From f3689e39bcd3662d0dd8a6f5bb591a97aa305395 Mon Sep 17 00:00:00 2001 From: David Harrigan Date: Wed, 22 Apr 2015 13:45:29 +0000 Subject: [PATCH 0001/2114] Issue #42: AMQConnection missing "/" for non-default virtual hosts. If the virtual host is not the default virtual host, then there needs to be a separator between the port and the name of the virtual host. -=david=- --- src/com/rabbitmq/client/impl/AMQConnection.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/com/rabbitmq/client/impl/AMQConnection.java b/src/com/rabbitmq/client/impl/AMQConnection.java index 229876dc8f..2da661e794 100644 --- a/src/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/com/rabbitmq/client/impl/AMQConnection.java @@ -862,7 +862,8 @@ public AMQCommand transformReply(AMQCommand command) { } @Override public String toString() { - return "amqp://" + this.username + "@" + getHostAddress() + ":" + getPort() + _virtualHost; + final String virtualHost = "/".equals(_virtualHost) ? _virtualHost : "/" + _virtualHost; + return "amqp://" + this.username + "@" + getHostAddress() + ":" + getPort() + virtualHost; } private String getHostAddress() { From 74066327ce15ba9f8e52aa6a5faf7f267dd4e3c4 Mon Sep 17 00:00:00 2001 From: David Pratt Date: Thu, 23 Apr 2015 11:56:31 -0500 Subject: [PATCH 0002/2114] Fix deadlock on close() with congested server. The RPC call for close() should not necessarily listen indefinitely, since it will block essentially forever if the server is congested. --- src/com/rabbitmq/client/impl/ChannelN.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/com/rabbitmq/client/impl/ChannelN.java b/src/com/rabbitmq/client/impl/ChannelN.java index 481dbf51bc..ac705da9c6 100644 --- a/src/com/rabbitmq/client/impl/ChannelN.java +++ b/src/com/rabbitmq/client/impl/ChannelN.java @@ -571,7 +571,9 @@ public AMQCommand transformReply(AMQCommand command) { // we wait for the reply. We ignore the result. // (It's NOT always close-ok.) notify = true; - k.getReply(-1); + // Should not wait indefinately, since if the server is congested + // the call will lock and never return. This stalls and kills the current thread. + k.getReply(10000); } catch (TimeoutException ise) { // Will never happen since we wait infinitely } catch (ShutdownSignalException sse) { From 3f2dc78dd388ba3a486b1f4f5c8f6af77c41f344 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Thu, 23 Apr 2015 20:30:34 +0300 Subject: [PATCH 0003/2114] Re-throw timeout exception unless aborting --- src/com/rabbitmq/client/impl/ChannelN.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/com/rabbitmq/client/impl/ChannelN.java b/src/com/rabbitmq/client/impl/ChannelN.java index ac705da9c6..5a0e047731 100644 --- a/src/com/rabbitmq/client/impl/ChannelN.java +++ b/src/com/rabbitmq/client/impl/ChannelN.java @@ -537,8 +537,7 @@ protected void close(int closeCode, boolean initiatedByApplication, Throwable cause, boolean abort) - throws IOException - { + throws IOException, TimeoutException { // First, notify all our dependents that we are shutting down. // This clears isOpen(), so no further work from the // application side will be accepted, and any inbound commands @@ -571,11 +570,11 @@ public AMQCommand transformReply(AMQCommand command) { // we wait for the reply. We ignore the result. // (It's NOT always close-ok.) notify = true; - // Should not wait indefinately, since if the server is congested - // the call will lock and never return. This stalls and kills the current thread. + // do not wait indefinitely k.getReply(10000); } catch (TimeoutException ise) { - // Will never happen since we wait infinitely + if (!abort) + throw ise; } catch (ShutdownSignalException sse) { if (!abort) throw sse; From 28025d3f67a149741d8c306166309f4b07c9df18 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 24 Apr 2015 15:33:28 +0300 Subject: [PATCH 0004/2114] Make sure TimeoutException is in the method signature --- src/com/rabbitmq/client/Channel.java | 4 +-- src/com/rabbitmq/client/impl/ChannelN.java | 32 ++++++++++++---------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/com/rabbitmq/client/Channel.java b/src/com/rabbitmq/client/Channel.java index 69fd4fcdbb..2040e81044 100644 --- a/src/com/rabbitmq/client/Channel.java +++ b/src/com/rabbitmq/client/Channel.java @@ -77,7 +77,7 @@ public interface Channel extends ShutdownNotifier { * * @throws java.io.IOException if an error is encountered */ - void close() throws IOException; + void close() throws IOException, TimeoutException; /** * Close this channel. @@ -86,7 +86,7 @@ public interface Channel extends ShutdownNotifier { * @param closeMessage a message indicating the reason for closing the connection * @throws java.io.IOException if an error is encountered */ - void close(int closeCode, String closeMessage) throws IOException; + void close(int closeCode, String closeMessage) throws IOException, TimeoutException; /** * Indicates whether the server has asked this client to stop diff --git a/src/com/rabbitmq/client/impl/ChannelN.java b/src/com/rabbitmq/client/impl/ChannelN.java index 5a0e047731..b00c1c403c 100644 --- a/src/com/rabbitmq/client/impl/ChannelN.java +++ b/src/com/rabbitmq/client/impl/ChannelN.java @@ -422,10 +422,10 @@ protected void processDelivery(Command command, Basic.Deliver method) { command.getContentBody()); } catch (Throwable ex) { getConnection().getExceptionHandler().handleConsumerException(this, - ex, - callback, - m.getConsumerTag(), - "handleDelivery"); + ex, + callback, + m.getConsumerTag(), + "handleDelivery"); } } @@ -433,11 +433,11 @@ private void callReturnListeners(Command command, Basic.Return basicReturn) { try { for (ReturnListener l : this.returnListeners) { l.handleReturn(basicReturn.getReplyCode(), - basicReturn.getReplyText(), - basicReturn.getExchange(), - basicReturn.getRoutingKey(), - (BasicProperties) command.getContentHeader(), - command.getContentBody()); + basicReturn.getReplyText(), + basicReturn.getExchange(), + basicReturn.getRoutingKey(), + (BasicProperties) command.getContentHeader(), + command.getContentBody()); } } catch (Throwable ex) { getConnection().getExceptionHandler().handleReturnListenerException(this, ex); @@ -493,15 +493,13 @@ private void asyncShutdown(Command command) throws IOException { /** Public API - {@inheritDoc} */ public void close() - throws IOException - { + throws IOException, TimeoutException { close(AMQP.REPLY_SUCCESS, "OK"); } /** Public API - {@inheritDoc} */ public void close(int closeCode, String closeMessage) - throws IOException - { + throws IOException, TimeoutException { close(closeCode, closeMessage, true, null, false); } @@ -517,8 +515,12 @@ public void abort(int closeCode, String closeMessage) throws IOException { try { - close(closeCode, closeMessage, true, null, true); - } catch (IOException _e) { /* ignored */ } + close(closeCode, closeMessage, true, null, true); + } catch (IOException _e) { + /* ignored */ + } catch (TimeoutException _e) { + /* ignored */ + } } /** From 992a32dc8a0178c5aef56e053dfe839630416e65 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 24 Apr 2015 15:33:28 +0300 Subject: [PATCH 0005/2114] Make sure TimeoutException is in the method signature --- src/com/rabbitmq/client/Channel.java | 4 +-- src/com/rabbitmq/client/impl/ChannelN.java | 32 ++++++++++++---------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/com/rabbitmq/client/Channel.java b/src/com/rabbitmq/client/Channel.java index 69fd4fcdbb..2040e81044 100644 --- a/src/com/rabbitmq/client/Channel.java +++ b/src/com/rabbitmq/client/Channel.java @@ -77,7 +77,7 @@ public interface Channel extends ShutdownNotifier { * * @throws java.io.IOException if an error is encountered */ - void close() throws IOException; + void close() throws IOException, TimeoutException; /** * Close this channel. @@ -86,7 +86,7 @@ public interface Channel extends ShutdownNotifier { * @param closeMessage a message indicating the reason for closing the connection * @throws java.io.IOException if an error is encountered */ - void close(int closeCode, String closeMessage) throws IOException; + void close(int closeCode, String closeMessage) throws IOException, TimeoutException; /** * Indicates whether the server has asked this client to stop diff --git a/src/com/rabbitmq/client/impl/ChannelN.java b/src/com/rabbitmq/client/impl/ChannelN.java index 5a0e047731..b00c1c403c 100644 --- a/src/com/rabbitmq/client/impl/ChannelN.java +++ b/src/com/rabbitmq/client/impl/ChannelN.java @@ -422,10 +422,10 @@ protected void processDelivery(Command command, Basic.Deliver method) { command.getContentBody()); } catch (Throwable ex) { getConnection().getExceptionHandler().handleConsumerException(this, - ex, - callback, - m.getConsumerTag(), - "handleDelivery"); + ex, + callback, + m.getConsumerTag(), + "handleDelivery"); } } @@ -433,11 +433,11 @@ private void callReturnListeners(Command command, Basic.Return basicReturn) { try { for (ReturnListener l : this.returnListeners) { l.handleReturn(basicReturn.getReplyCode(), - basicReturn.getReplyText(), - basicReturn.getExchange(), - basicReturn.getRoutingKey(), - (BasicProperties) command.getContentHeader(), - command.getContentBody()); + basicReturn.getReplyText(), + basicReturn.getExchange(), + basicReturn.getRoutingKey(), + (BasicProperties) command.getContentHeader(), + command.getContentBody()); } } catch (Throwable ex) { getConnection().getExceptionHandler().handleReturnListenerException(this, ex); @@ -493,15 +493,13 @@ private void asyncShutdown(Command command) throws IOException { /** Public API - {@inheritDoc} */ public void close() - throws IOException - { + throws IOException, TimeoutException { close(AMQP.REPLY_SUCCESS, "OK"); } /** Public API - {@inheritDoc} */ public void close(int closeCode, String closeMessage) - throws IOException - { + throws IOException, TimeoutException { close(closeCode, closeMessage, true, null, false); } @@ -517,8 +515,12 @@ public void abort(int closeCode, String closeMessage) throws IOException { try { - close(closeCode, closeMessage, true, null, true); - } catch (IOException _e) { /* ignored */ } + close(closeCode, closeMessage, true, null, true); + } catch (IOException _e) { + /* ignored */ + } catch (TimeoutException _e) { + /* ignored */ + } } /** From d393fdfab7d7229b0c4323f49b398aa2b9bd64f4 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 24 Apr 2015 17:25:47 +0300 Subject: [PATCH 0006/2114] Fixes rebuild from scratch --- .../rabbitmq/client/impl/DefaultExceptionHandler.java | 3 +++ .../client/impl/recovery/AutorecoveringChannel.java | 4 ++-- .../com/rabbitmq/client/test/functional/BasicGet.java | 3 ++- .../client/test/functional/ClusteredTestBase.java | 4 ++-- .../com/rabbitmq/client/test/functional/Confirm.java | 4 ++-- .../client/test/functional/ConnectionRecovery.java | 10 +++++----- .../client/test/functional/ExceptionMessages.java | 2 +- .../test/functional/HeadersExchangeValidation.java | 2 +- .../com/rabbitmq/client/test/functional/QosTests.java | 4 ++-- .../com/rabbitmq/client/test/server/Bug19219Test.java | 2 +- test/src/com/rabbitmq/examples/ConsumerMain.java | 7 ++++++- test/src/com/rabbitmq/examples/ProducerMain.java | 6 +++++- test/src/com/rabbitmq/examples/StressPersister.java | 2 +- test/src/com/rabbitmq/examples/TestMain.java | 2 +- .../com/rabbitmq/examples/perf/MulticastParams.java | 4 ++-- 15 files changed, 36 insertions(+), 23 deletions(-) diff --git a/src/com/rabbitmq/client/impl/DefaultExceptionHandler.java b/src/com/rabbitmq/client/impl/DefaultExceptionHandler.java index c07e7256fa..cef33fd384 100644 --- a/src/com/rabbitmq/client/impl/DefaultExceptionHandler.java +++ b/src/com/rabbitmq/client/impl/DefaultExceptionHandler.java @@ -18,6 +18,7 @@ import java.io.IOException; import java.net.ConnectException; +import java.util.concurrent.TimeoutException; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.AlreadyClosedException; @@ -106,6 +107,8 @@ protected void handleChannelKiller(Channel channel, Throwable exception, String channel.close(AMQP.REPLY_SUCCESS, "Closed due to exception from " + what); } catch (AlreadyClosedException ace) { // noop + } catch (TimeoutException ace) { + // noop } catch (IOException ioe) { // TODO: log the failure System.err.println("Failure during close of channel " + channel + " after " + exception diff --git a/src/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java b/src/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java index 5225f06921..6921f6f4fe 100644 --- a/src/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java +++ b/src/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java @@ -57,7 +57,7 @@ public Channel getDelegate() { return delegate; } - public void close() throws IOException { + public void close() throws IOException, TimeoutException { try { delegate.close(); } finally { @@ -65,7 +65,7 @@ public void close() throws IOException { } } - public void close(int closeCode, String closeMessage) throws IOException { + public void close(int closeCode, String closeMessage) throws IOException, TimeoutException { try { delegate.close(closeCode, closeMessage); } finally { diff --git a/test/src/com/rabbitmq/client/test/functional/BasicGet.java b/test/src/com/rabbitmq/client/test/functional/BasicGet.java index 9c7b5194e4..87c4961fdf 100644 --- a/test/src/com/rabbitmq/client/test/functional/BasicGet.java +++ b/test/src/com/rabbitmq/client/test/functional/BasicGet.java @@ -5,6 +5,7 @@ import com.rabbitmq.client.test.BrokerTestCase; import java.io.IOException; +import java.util.concurrent.TimeoutException; public class BasicGet extends BrokerTestCase { public void testBasicGetWithEnqueuedMessages() throws IOException, InterruptedException { @@ -28,7 +29,7 @@ public void testBasicGetWithEmptyQueue() throws IOException, InterruptedExceptio channel.queueDelete(q); } - public void testBasicGetWithClosedChannel() throws IOException, InterruptedException { + public void testBasicGetWithClosedChannel() throws IOException, InterruptedException, TimeoutException { assertTrue(channel.isOpen()); String q = channel.queueDeclare().getQueue(); diff --git a/test/src/com/rabbitmq/client/test/functional/ClusteredTestBase.java b/test/src/com/rabbitmq/client/test/functional/ClusteredTestBase.java index 4f16d182ef..16309f9092 100644 --- a/test/src/com/rabbitmq/client/test/functional/ClusteredTestBase.java +++ b/test/src/com/rabbitmq/client/test/functional/ClusteredTestBase.java @@ -97,8 +97,8 @@ private boolean clustered(Connection c1, Connection c2) throws IOException { } ch1.queueDelete(q); - ch1.close(); - ch2.close(); + ch1.abort(); + ch2.abort(); return true; } diff --git a/test/src/com/rabbitmq/client/test/functional/Confirm.java b/test/src/com/rabbitmq/client/test/functional/Confirm.java index 4e9f1a5025..41def19920 100644 --- a/test/src/com/rabbitmq/client/test/functional/Confirm.java +++ b/test/src/com/rabbitmq/client/test/functional/Confirm.java @@ -31,6 +31,7 @@ import java.util.Map; import java.util.SortedSet; import java.util.TreeSet; +import java.util.concurrent.TimeoutException; public class Confirm extends BrokerTestCase { @@ -242,8 +243,7 @@ public void testWaitForConfirmsWithoutConfirmSelected() } public void testWaitForConfirmsException() - throws IOException, InterruptedException - { + throws IOException, InterruptedException, TimeoutException { publishN("", "confirm-test", true, false); channel.close(); try { diff --git a/test/src/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/test/src/com/rabbitmq/client/test/functional/ConnectionRecovery.java index 5adc88c503..d45ad6cc0b 100644 --- a/test/src/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/test/src/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -276,7 +276,7 @@ public void queueRecovered(String oldName, String newName) { ch.exchangeDelete(x); } - public void testDeclarationOfManyAutoDeleteQueuesWithTransientConsumer() throws IOException { + public void testDeclarationOfManyAutoDeleteQueuesWithTransientConsumer() throws IOException, TimeoutException { Channel ch = connection.createChannel(); assertRecordedQueues(connection, 0); for(int i = 0; i < 5000; i++) { @@ -290,7 +290,7 @@ public void testDeclarationOfManyAutoDeleteQueuesWithTransientConsumer() throws ch.close(); } - public void testDeclarationOfManyAutoDeleteExchangesWithTransientQueuesThatAreUnbound() throws IOException { + public void testDeclarationOfManyAutoDeleteExchangesWithTransientQueuesThatAreUnbound() throws IOException, TimeoutException { Channel ch = connection.createChannel(); assertRecordedExchanges(connection, 0); for(int i = 0; i < 5000; i++) { @@ -306,7 +306,7 @@ public void testDeclarationOfManyAutoDeleteExchangesWithTransientQueuesThatAreUn ch.close(); } - public void testDeclarationOfManyAutoDeleteExchangesWithTransientQueuesThatAreDeleted() throws IOException { + public void testDeclarationOfManyAutoDeleteExchangesWithTransientQueuesThatAreDeleted() throws IOException, TimeoutException { Channel ch = connection.createChannel(); assertRecordedExchanges(connection, 0); for(int i = 0; i < 5000; i++) { @@ -320,7 +320,7 @@ public void testDeclarationOfManyAutoDeleteExchangesWithTransientQueuesThatAreDe ch.close(); } - public void testDeclarationOfManyAutoDeleteExchangesWithTransientExchangesThatAreUnbound() throws IOException { + public void testDeclarationOfManyAutoDeleteExchangesWithTransientExchangesThatAreUnbound() throws IOException, TimeoutException { Channel ch = connection.createChannel(); assertRecordedExchanges(connection, 0); for(int i = 0; i < 5000; i++) { @@ -337,7 +337,7 @@ public void testDeclarationOfManyAutoDeleteExchangesWithTransientExchangesThatAr ch.close(); } - public void testDeclarationOfManyAutoDeleteExchangesWithTransientExchangesThatAreDeleted() throws IOException { + public void testDeclarationOfManyAutoDeleteExchangesWithTransientExchangesThatAreDeleted() throws IOException, TimeoutException { Channel ch = connection.createChannel(); assertRecordedExchanges(connection, 0); for(int i = 0; i < 5000; i++) { diff --git a/test/src/com/rabbitmq/client/test/functional/ExceptionMessages.java b/test/src/com/rabbitmq/client/test/functional/ExceptionMessages.java index d7af4461af..f098743da7 100644 --- a/test/src/com/rabbitmq/client/test/functional/ExceptionMessages.java +++ b/test/src/com/rabbitmq/client/test/functional/ExceptionMessages.java @@ -28,7 +28,7 @@ public void testAlreadyClosedExceptionMessageWithCleanClose() throws IOException String uuid = UUID.randomUUID().toString(); try { - channel.close(); + channel.abort(); channel.queueDeclare(uuid, false, false, false, null); } catch (AlreadyClosedException ace) { assertTrue(ace.getMessage().startsWith("channel is already closed due to clean channel shutdown")); diff --git a/test/src/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java b/test/src/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java index 17724034aa..491fb4c37a 100644 --- a/test/src/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java +++ b/test/src/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java @@ -43,6 +43,6 @@ private void failBind(String queue, HashMap arguments) { private void succeedBind(String queue, HashMap arguments) throws IOException { Channel ch = connection.createChannel(); ch.queueBind(queue, "amq.headers", "", arguments); - ch.close(); + ch.abort(); } } diff --git a/test/src/com/rabbitmq/client/test/functional/QosTests.java b/test/src/com/rabbitmq/client/test/functional/QosTests.java index 7dfd1ca13b..2e5e65d47d 100644 --- a/test/src/com/rabbitmq/client/test/functional/QosTests.java +++ b/test/src/com/rabbitmq/client/test/functional/QosTests.java @@ -316,8 +316,8 @@ public void testLimitingMultipleChannels() ackDelivery(ch2, d2.remove(0), true); drain(c1, 1); drain(c2, 1); - ch1.close(); - ch2.close(); + ch1.abort(); + ch2.abort(); } public void testLimitInheritsUnackedCount() diff --git a/test/src/com/rabbitmq/client/test/server/Bug19219Test.java b/test/src/com/rabbitmq/client/test/server/Bug19219Test.java index b996fd867e..9d25fda6fd 100644 --- a/test/src/com/rabbitmq/client/test/server/Bug19219Test.java +++ b/test/src/com/rabbitmq/client/test/server/Bug19219Test.java @@ -112,7 +112,7 @@ public void run() { //notifications timing out. boolean success = false; try { - channel.close(); + channel.abort(); success = true; } catch (ShutdownSignalException e) { } finally { diff --git a/test/src/com/rabbitmq/examples/ConsumerMain.java b/test/src/com/rabbitmq/examples/ConsumerMain.java index 1ce702a61e..15ec65d656 100644 --- a/test/src/com/rabbitmq/examples/ConsumerMain.java +++ b/test/src/com/rabbitmq/examples/ConsumerMain.java @@ -22,6 +22,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintStream; +import java.util.concurrent.TimeoutException; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; @@ -93,10 +94,14 @@ public void run() { System.err.println("hit IOException in ConsumerMain: trace follows"); ex.printStackTrace(); throw new RuntimeException(ex); + } catch (TimeoutException ex) { + System.err.println("hit IOException in ConsumerMain: trace follows"); + ex.printStackTrace(); + throw new RuntimeException(ex); } } - private void runIt() throws IOException { + private void runIt() throws IOException, TimeoutException { Channel channel = _connection.createChannel(); String queueName = "test queue"; diff --git a/test/src/com/rabbitmq/examples/ProducerMain.java b/test/src/com/rabbitmq/examples/ProducerMain.java index a57dbe4995..c2dedb0df1 100644 --- a/test/src/com/rabbitmq/examples/ProducerMain.java +++ b/test/src/com/rabbitmq/examples/ProducerMain.java @@ -19,6 +19,7 @@ import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; +import java.util.concurrent.TimeoutException; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; @@ -128,9 +129,12 @@ public void run() { } catch (IOException ex) { throw new RuntimeException(ex); // wrap and re-throw } + catch (TimeoutException ex) { + throw new RuntimeException(ex); + } } - private void runIt() throws IOException { + private void runIt() throws IOException, TimeoutException { _channel = _connection.createChannel(); String queueName = "test queue"; diff --git a/test/src/com/rabbitmq/examples/StressPersister.java b/test/src/com/rabbitmq/examples/StressPersister.java index 4338b9e9bf..613b461699 100644 --- a/test/src/com/rabbitmq/examples/StressPersister.java +++ b/test/src/com/rabbitmq/examples/StressPersister.java @@ -204,7 +204,7 @@ public void publishOneInOneOutReceive(int backlogSize, int bodySize, int repeatC redeclare(q, chan); trace("Closing connection"); - chan.close(); + chan.abort(); conn.close(); trace("Sample results (timestamp in milliseconds since epoch; microseconds/roundtrip)"); diff --git a/test/src/com/rabbitmq/examples/TestMain.java b/test/src/com/rabbitmq/examples/TestMain.java index 8e9d7b272c..ad5668e3ac 100644 --- a/test/src/com/rabbitmq/examples/TestMain.java +++ b/test/src/com/rabbitmq/examples/TestMain.java @@ -270,7 +270,7 @@ public void run() throws IOException { sendLotsOfTrivialMessages(batchSize, queueName); expect(batchSize, drain(batchSize, queueName, true)); - _ch1.close(); + _ch1.abort(); log("Closing."); try { diff --git a/test/src/com/rabbitmq/examples/perf/MulticastParams.java b/test/src/com/rabbitmq/examples/perf/MulticastParams.java index ce87580953..ba15758c5c 100644 --- a/test/src/com/rabbitmq/examples/perf/MulticastParams.java +++ b/test/src/com/rabbitmq/examples/perf/MulticastParams.java @@ -217,7 +217,7 @@ public String configureQueue(Connection connection, String id) throws IOExceptio null).getQueue(); } channel.queueBind(qName, exchangeName, id); - channel.close(); + channel.abort(); return qName; } @@ -245,7 +245,7 @@ private static boolean exists(Connection connection, Checker checker) throws IOE try { Channel ch = connection.createChannel(); checker.check(ch); - ch.close(); + ch.abort(); return true; } catch (IOException e) { From 335c161e788a856c9a27d821077e37fb2924ffb6 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 24 Apr 2015 17:25:47 +0300 Subject: [PATCH 0007/2114] Fixes rebuild from scratch --- .../rabbitmq/client/impl/DefaultExceptionHandler.java | 3 +++ .../client/impl/recovery/AutorecoveringChannel.java | 4 ++-- .../com/rabbitmq/client/test/functional/BasicGet.java | 3 ++- .../client/test/functional/ClusteredTestBase.java | 4 ++-- .../com/rabbitmq/client/test/functional/Confirm.java | 4 ++-- .../client/test/functional/ConnectionRecovery.java | 10 +++++----- .../client/test/functional/ExceptionMessages.java | 2 +- .../test/functional/HeadersExchangeValidation.java | 2 +- .../com/rabbitmq/client/test/functional/QosTests.java | 4 ++-- .../com/rabbitmq/client/test/server/Bug19219Test.java | 2 +- test/src/com/rabbitmq/examples/ConsumerMain.java | 7 ++++++- test/src/com/rabbitmq/examples/ProducerMain.java | 6 +++++- test/src/com/rabbitmq/examples/StressPersister.java | 2 +- test/src/com/rabbitmq/examples/TestMain.java | 2 +- .../com/rabbitmq/examples/perf/MulticastParams.java | 4 ++-- 15 files changed, 36 insertions(+), 23 deletions(-) diff --git a/src/com/rabbitmq/client/impl/DefaultExceptionHandler.java b/src/com/rabbitmq/client/impl/DefaultExceptionHandler.java index c07e7256fa..cef33fd384 100644 --- a/src/com/rabbitmq/client/impl/DefaultExceptionHandler.java +++ b/src/com/rabbitmq/client/impl/DefaultExceptionHandler.java @@ -18,6 +18,7 @@ import java.io.IOException; import java.net.ConnectException; +import java.util.concurrent.TimeoutException; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.AlreadyClosedException; @@ -106,6 +107,8 @@ protected void handleChannelKiller(Channel channel, Throwable exception, String channel.close(AMQP.REPLY_SUCCESS, "Closed due to exception from " + what); } catch (AlreadyClosedException ace) { // noop + } catch (TimeoutException ace) { + // noop } catch (IOException ioe) { // TODO: log the failure System.err.println("Failure during close of channel " + channel + " after " + exception diff --git a/src/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java b/src/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java index 5225f06921..6921f6f4fe 100644 --- a/src/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java +++ b/src/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java @@ -57,7 +57,7 @@ public Channel getDelegate() { return delegate; } - public void close() throws IOException { + public void close() throws IOException, TimeoutException { try { delegate.close(); } finally { @@ -65,7 +65,7 @@ public void close() throws IOException { } } - public void close(int closeCode, String closeMessage) throws IOException { + public void close(int closeCode, String closeMessage) throws IOException, TimeoutException { try { delegate.close(closeCode, closeMessage); } finally { diff --git a/test/src/com/rabbitmq/client/test/functional/BasicGet.java b/test/src/com/rabbitmq/client/test/functional/BasicGet.java index 9c7b5194e4..87c4961fdf 100644 --- a/test/src/com/rabbitmq/client/test/functional/BasicGet.java +++ b/test/src/com/rabbitmq/client/test/functional/BasicGet.java @@ -5,6 +5,7 @@ import com.rabbitmq.client.test.BrokerTestCase; import java.io.IOException; +import java.util.concurrent.TimeoutException; public class BasicGet extends BrokerTestCase { public void testBasicGetWithEnqueuedMessages() throws IOException, InterruptedException { @@ -28,7 +29,7 @@ public void testBasicGetWithEmptyQueue() throws IOException, InterruptedExceptio channel.queueDelete(q); } - public void testBasicGetWithClosedChannel() throws IOException, InterruptedException { + public void testBasicGetWithClosedChannel() throws IOException, InterruptedException, TimeoutException { assertTrue(channel.isOpen()); String q = channel.queueDeclare().getQueue(); diff --git a/test/src/com/rabbitmq/client/test/functional/ClusteredTestBase.java b/test/src/com/rabbitmq/client/test/functional/ClusteredTestBase.java index 4f16d182ef..16309f9092 100644 --- a/test/src/com/rabbitmq/client/test/functional/ClusteredTestBase.java +++ b/test/src/com/rabbitmq/client/test/functional/ClusteredTestBase.java @@ -97,8 +97,8 @@ private boolean clustered(Connection c1, Connection c2) throws IOException { } ch1.queueDelete(q); - ch1.close(); - ch2.close(); + ch1.abort(); + ch2.abort(); return true; } diff --git a/test/src/com/rabbitmq/client/test/functional/Confirm.java b/test/src/com/rabbitmq/client/test/functional/Confirm.java index 4e9f1a5025..41def19920 100644 --- a/test/src/com/rabbitmq/client/test/functional/Confirm.java +++ b/test/src/com/rabbitmq/client/test/functional/Confirm.java @@ -31,6 +31,7 @@ import java.util.Map; import java.util.SortedSet; import java.util.TreeSet; +import java.util.concurrent.TimeoutException; public class Confirm extends BrokerTestCase { @@ -242,8 +243,7 @@ public void testWaitForConfirmsWithoutConfirmSelected() } public void testWaitForConfirmsException() - throws IOException, InterruptedException - { + throws IOException, InterruptedException, TimeoutException { publishN("", "confirm-test", true, false); channel.close(); try { diff --git a/test/src/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/test/src/com/rabbitmq/client/test/functional/ConnectionRecovery.java index 5adc88c503..d45ad6cc0b 100644 --- a/test/src/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/test/src/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -276,7 +276,7 @@ public void queueRecovered(String oldName, String newName) { ch.exchangeDelete(x); } - public void testDeclarationOfManyAutoDeleteQueuesWithTransientConsumer() throws IOException { + public void testDeclarationOfManyAutoDeleteQueuesWithTransientConsumer() throws IOException, TimeoutException { Channel ch = connection.createChannel(); assertRecordedQueues(connection, 0); for(int i = 0; i < 5000; i++) { @@ -290,7 +290,7 @@ public void testDeclarationOfManyAutoDeleteQueuesWithTransientConsumer() throws ch.close(); } - public void testDeclarationOfManyAutoDeleteExchangesWithTransientQueuesThatAreUnbound() throws IOException { + public void testDeclarationOfManyAutoDeleteExchangesWithTransientQueuesThatAreUnbound() throws IOException, TimeoutException { Channel ch = connection.createChannel(); assertRecordedExchanges(connection, 0); for(int i = 0; i < 5000; i++) { @@ -306,7 +306,7 @@ public void testDeclarationOfManyAutoDeleteExchangesWithTransientQueuesThatAreUn ch.close(); } - public void testDeclarationOfManyAutoDeleteExchangesWithTransientQueuesThatAreDeleted() throws IOException { + public void testDeclarationOfManyAutoDeleteExchangesWithTransientQueuesThatAreDeleted() throws IOException, TimeoutException { Channel ch = connection.createChannel(); assertRecordedExchanges(connection, 0); for(int i = 0; i < 5000; i++) { @@ -320,7 +320,7 @@ public void testDeclarationOfManyAutoDeleteExchangesWithTransientQueuesThatAreDe ch.close(); } - public void testDeclarationOfManyAutoDeleteExchangesWithTransientExchangesThatAreUnbound() throws IOException { + public void testDeclarationOfManyAutoDeleteExchangesWithTransientExchangesThatAreUnbound() throws IOException, TimeoutException { Channel ch = connection.createChannel(); assertRecordedExchanges(connection, 0); for(int i = 0; i < 5000; i++) { @@ -337,7 +337,7 @@ public void testDeclarationOfManyAutoDeleteExchangesWithTransientExchangesThatAr ch.close(); } - public void testDeclarationOfManyAutoDeleteExchangesWithTransientExchangesThatAreDeleted() throws IOException { + public void testDeclarationOfManyAutoDeleteExchangesWithTransientExchangesThatAreDeleted() throws IOException, TimeoutException { Channel ch = connection.createChannel(); assertRecordedExchanges(connection, 0); for(int i = 0; i < 5000; i++) { diff --git a/test/src/com/rabbitmq/client/test/functional/ExceptionMessages.java b/test/src/com/rabbitmq/client/test/functional/ExceptionMessages.java index d7af4461af..f098743da7 100644 --- a/test/src/com/rabbitmq/client/test/functional/ExceptionMessages.java +++ b/test/src/com/rabbitmq/client/test/functional/ExceptionMessages.java @@ -28,7 +28,7 @@ public void testAlreadyClosedExceptionMessageWithCleanClose() throws IOException String uuid = UUID.randomUUID().toString(); try { - channel.close(); + channel.abort(); channel.queueDeclare(uuid, false, false, false, null); } catch (AlreadyClosedException ace) { assertTrue(ace.getMessage().startsWith("channel is already closed due to clean channel shutdown")); diff --git a/test/src/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java b/test/src/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java index 17724034aa..491fb4c37a 100644 --- a/test/src/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java +++ b/test/src/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java @@ -43,6 +43,6 @@ private void failBind(String queue, HashMap arguments) { private void succeedBind(String queue, HashMap arguments) throws IOException { Channel ch = connection.createChannel(); ch.queueBind(queue, "amq.headers", "", arguments); - ch.close(); + ch.abort(); } } diff --git a/test/src/com/rabbitmq/client/test/functional/QosTests.java b/test/src/com/rabbitmq/client/test/functional/QosTests.java index 7dfd1ca13b..2e5e65d47d 100644 --- a/test/src/com/rabbitmq/client/test/functional/QosTests.java +++ b/test/src/com/rabbitmq/client/test/functional/QosTests.java @@ -316,8 +316,8 @@ public void testLimitingMultipleChannels() ackDelivery(ch2, d2.remove(0), true); drain(c1, 1); drain(c2, 1); - ch1.close(); - ch2.close(); + ch1.abort(); + ch2.abort(); } public void testLimitInheritsUnackedCount() diff --git a/test/src/com/rabbitmq/client/test/server/Bug19219Test.java b/test/src/com/rabbitmq/client/test/server/Bug19219Test.java index b996fd867e..9d25fda6fd 100644 --- a/test/src/com/rabbitmq/client/test/server/Bug19219Test.java +++ b/test/src/com/rabbitmq/client/test/server/Bug19219Test.java @@ -112,7 +112,7 @@ public void run() { //notifications timing out. boolean success = false; try { - channel.close(); + channel.abort(); success = true; } catch (ShutdownSignalException e) { } finally { diff --git a/test/src/com/rabbitmq/examples/ConsumerMain.java b/test/src/com/rabbitmq/examples/ConsumerMain.java index 1ce702a61e..15ec65d656 100644 --- a/test/src/com/rabbitmq/examples/ConsumerMain.java +++ b/test/src/com/rabbitmq/examples/ConsumerMain.java @@ -22,6 +22,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintStream; +import java.util.concurrent.TimeoutException; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; @@ -93,10 +94,14 @@ public void run() { System.err.println("hit IOException in ConsumerMain: trace follows"); ex.printStackTrace(); throw new RuntimeException(ex); + } catch (TimeoutException ex) { + System.err.println("hit IOException in ConsumerMain: trace follows"); + ex.printStackTrace(); + throw new RuntimeException(ex); } } - private void runIt() throws IOException { + private void runIt() throws IOException, TimeoutException { Channel channel = _connection.createChannel(); String queueName = "test queue"; diff --git a/test/src/com/rabbitmq/examples/ProducerMain.java b/test/src/com/rabbitmq/examples/ProducerMain.java index a57dbe4995..c2dedb0df1 100644 --- a/test/src/com/rabbitmq/examples/ProducerMain.java +++ b/test/src/com/rabbitmq/examples/ProducerMain.java @@ -19,6 +19,7 @@ import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; +import java.util.concurrent.TimeoutException; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; @@ -128,9 +129,12 @@ public void run() { } catch (IOException ex) { throw new RuntimeException(ex); // wrap and re-throw } + catch (TimeoutException ex) { + throw new RuntimeException(ex); + } } - private void runIt() throws IOException { + private void runIt() throws IOException, TimeoutException { _channel = _connection.createChannel(); String queueName = "test queue"; diff --git a/test/src/com/rabbitmq/examples/StressPersister.java b/test/src/com/rabbitmq/examples/StressPersister.java index 4338b9e9bf..613b461699 100644 --- a/test/src/com/rabbitmq/examples/StressPersister.java +++ b/test/src/com/rabbitmq/examples/StressPersister.java @@ -204,7 +204,7 @@ public void publishOneInOneOutReceive(int backlogSize, int bodySize, int repeatC redeclare(q, chan); trace("Closing connection"); - chan.close(); + chan.abort(); conn.close(); trace("Sample results (timestamp in milliseconds since epoch; microseconds/roundtrip)"); diff --git a/test/src/com/rabbitmq/examples/TestMain.java b/test/src/com/rabbitmq/examples/TestMain.java index 8e9d7b272c..ad5668e3ac 100644 --- a/test/src/com/rabbitmq/examples/TestMain.java +++ b/test/src/com/rabbitmq/examples/TestMain.java @@ -270,7 +270,7 @@ public void run() throws IOException { sendLotsOfTrivialMessages(batchSize, queueName); expect(batchSize, drain(batchSize, queueName, true)); - _ch1.close(); + _ch1.abort(); log("Closing."); try { diff --git a/test/src/com/rabbitmq/examples/perf/MulticastParams.java b/test/src/com/rabbitmq/examples/perf/MulticastParams.java index ce87580953..ba15758c5c 100644 --- a/test/src/com/rabbitmq/examples/perf/MulticastParams.java +++ b/test/src/com/rabbitmq/examples/perf/MulticastParams.java @@ -217,7 +217,7 @@ public String configureQueue(Connection connection, String id) throws IOExceptio null).getQueue(); } channel.queueBind(qName, exchangeName, id); - channel.close(); + channel.abort(); return qName; } @@ -245,7 +245,7 @@ private static boolean exists(Connection connection, Checker checker) throws IOE try { Channel ch = connection.createChannel(); checker.check(ch); - ch.close(); + ch.abort(); return true; } catch (IOException e) { From fd27f27c3867ae348f0712704f04733847707488 Mon Sep 17 00:00:00 2001 From: xuwei-k <6b656e6a69@gmail.com> Date: Sat, 25 Apr 2015 16:04:58 +0900 Subject: [PATCH 0008/2114] implements java.io.Closeable --- src/com/rabbitmq/client/Channel.java | 4 +++- src/com/rabbitmq/client/Connection.java | 4 +++- src/com/rabbitmq/client/RpcClient.java | 4 +++- src/com/rabbitmq/client/RpcServer.java | 4 +++- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/com/rabbitmq/client/Channel.java b/src/com/rabbitmq/client/Channel.java index 2040e81044..3fc4b0b640 100644 --- a/src/com/rabbitmq/client/Channel.java +++ b/src/com/rabbitmq/client/Channel.java @@ -16,6 +16,7 @@ package com.rabbitmq.client; +import java.io.Closeable; import java.io.IOException; import java.util.Map; import java.util.concurrent.TimeoutException; @@ -58,7 +59,7 @@ * */ -public interface Channel extends ShutdownNotifier { +public interface Channel extends ShutdownNotifier, Closeable { /** * Retrieve this channel's channel number. * @return the channel number @@ -77,6 +78,7 @@ public interface Channel extends ShutdownNotifier { * * @throws java.io.IOException if an error is encountered */ + @Override void close() throws IOException, TimeoutException; /** diff --git a/src/com/rabbitmq/client/Connection.java b/src/com/rabbitmq/client/Connection.java index 3abfaa2226..d39d70b410 100644 --- a/src/com/rabbitmq/client/Connection.java +++ b/src/com/rabbitmq/client/Connection.java @@ -16,6 +16,7 @@ package com.rabbitmq.client; +import java.io.Closeable; import java.io.IOException; import java.net.InetAddress; import java.util.Map; @@ -50,7 +51,7 @@ * Current implementations are thread-safe for code at the client API level, * and in fact thread-safe internally except for code within RPC calls. */ -public interface Connection extends ShutdownNotifier { // rename to AMQPConnection later, this is a temporary name +public interface Connection extends ShutdownNotifier, Closeable { // rename to AMQPConnection later, this is a temporary name /** * Retrieve the host. * @return the hostname of the peer we're connected to. @@ -123,6 +124,7 @@ public interface Connection extends ShutdownNotifier { // rename to AMQPConnecti * * @throws IOException if an I/O problem is encountered */ + @Override void close() throws IOException; /** diff --git a/src/com/rabbitmq/client/RpcClient.java b/src/com/rabbitmq/client/RpcClient.java index 48c944954d..fbedb37cbe 100644 --- a/src/com/rabbitmq/client/RpcClient.java +++ b/src/com/rabbitmq/client/RpcClient.java @@ -19,6 +19,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.Closeable; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.EOFException; @@ -41,7 +42,7 @@ * It simply provides a mechanism for sending a message to an exchange with a given routing key, * and waiting for a response. */ -public class RpcClient { +public class RpcClient extends Closeable { /** Channel we are communicating on */ private final Channel _channel; /** Exchange to send requests to */ @@ -113,6 +114,7 @@ public void checkConsumer() throws IOException { * Public API - cancels the consumer, thus deleting the temporary queue, and marks the RpcClient as closed. * @throws IOException if an error is encountered */ + @Override public void close() throws IOException { if (_consumer != null) { _channel.basicCancel(_consumer.getConsumerTag()); diff --git a/src/com/rabbitmq/client/RpcServer.java b/src/com/rabbitmq/client/RpcServer.java index 73ccceb4e8..d3e5dba663 100644 --- a/src/com/rabbitmq/client/RpcServer.java +++ b/src/com/rabbitmq/client/RpcServer.java @@ -17,13 +17,14 @@ package com.rabbitmq.client; +import java.io.Closeable; import java.io.IOException; /** * Class which manages a request queue for a simple RPC-style service. * The class is agnostic about the format of RPC arguments / return values. */ -public class RpcServer { +public class RpcServer extends Closeable { /** Channel we are communicating on */ private final Channel _channel; /** Queue to receive requests from */ @@ -66,6 +67,7 @@ public RpcServer(Channel channel, String queueName) * it was a temporary queue, and marks the RpcServer as closed. * @throws IOException if an error is encountered */ + @Override public void close() throws IOException { From 6d611d7973f9c9689667d1b1b0d8989e054b1824 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Sat, 25 Apr 2015 16:37:42 +0300 Subject: [PATCH 0009/2114] Revert "implements java.io.Closeable" This reverts commit fd27f27c3867ae348f0712704f04733847707488. It conflicts with a recently merged timeout exception change. --- src/com/rabbitmq/client/Channel.java | 4 +--- src/com/rabbitmq/client/Connection.java | 4 +--- src/com/rabbitmq/client/RpcClient.java | 4 +--- src/com/rabbitmq/client/RpcServer.java | 4 +--- 4 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/com/rabbitmq/client/Channel.java b/src/com/rabbitmq/client/Channel.java index 3fc4b0b640..2040e81044 100644 --- a/src/com/rabbitmq/client/Channel.java +++ b/src/com/rabbitmq/client/Channel.java @@ -16,7 +16,6 @@ package com.rabbitmq.client; -import java.io.Closeable; import java.io.IOException; import java.util.Map; import java.util.concurrent.TimeoutException; @@ -59,7 +58,7 @@ * */ -public interface Channel extends ShutdownNotifier, Closeable { +public interface Channel extends ShutdownNotifier { /** * Retrieve this channel's channel number. * @return the channel number @@ -78,7 +77,6 @@ public interface Channel extends ShutdownNotifier, Closeable { * * @throws java.io.IOException if an error is encountered */ - @Override void close() throws IOException, TimeoutException; /** diff --git a/src/com/rabbitmq/client/Connection.java b/src/com/rabbitmq/client/Connection.java index d39d70b410..3abfaa2226 100644 --- a/src/com/rabbitmq/client/Connection.java +++ b/src/com/rabbitmq/client/Connection.java @@ -16,7 +16,6 @@ package com.rabbitmq.client; -import java.io.Closeable; import java.io.IOException; import java.net.InetAddress; import java.util.Map; @@ -51,7 +50,7 @@ * Current implementations are thread-safe for code at the client API level, * and in fact thread-safe internally except for code within RPC calls. */ -public interface Connection extends ShutdownNotifier, Closeable { // rename to AMQPConnection later, this is a temporary name +public interface Connection extends ShutdownNotifier { // rename to AMQPConnection later, this is a temporary name /** * Retrieve the host. * @return the hostname of the peer we're connected to. @@ -124,7 +123,6 @@ public interface Connection extends ShutdownNotifier, Closeable { // rename to A * * @throws IOException if an I/O problem is encountered */ - @Override void close() throws IOException; /** diff --git a/src/com/rabbitmq/client/RpcClient.java b/src/com/rabbitmq/client/RpcClient.java index fbedb37cbe..48c944954d 100644 --- a/src/com/rabbitmq/client/RpcClient.java +++ b/src/com/rabbitmq/client/RpcClient.java @@ -19,7 +19,6 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; -import java.io.Closeable; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.EOFException; @@ -42,7 +41,7 @@ * It simply provides a mechanism for sending a message to an exchange with a given routing key, * and waiting for a response. */ -public class RpcClient extends Closeable { +public class RpcClient { /** Channel we are communicating on */ private final Channel _channel; /** Exchange to send requests to */ @@ -114,7 +113,6 @@ public void checkConsumer() throws IOException { * Public API - cancels the consumer, thus deleting the temporary queue, and marks the RpcClient as closed. * @throws IOException if an error is encountered */ - @Override public void close() throws IOException { if (_consumer != null) { _channel.basicCancel(_consumer.getConsumerTag()); diff --git a/src/com/rabbitmq/client/RpcServer.java b/src/com/rabbitmq/client/RpcServer.java index d3e5dba663..73ccceb4e8 100644 --- a/src/com/rabbitmq/client/RpcServer.java +++ b/src/com/rabbitmq/client/RpcServer.java @@ -17,14 +17,13 @@ package com.rabbitmq.client; -import java.io.Closeable; import java.io.IOException; /** * Class which manages a request queue for a simple RPC-style service. * The class is agnostic about the format of RPC arguments / return values. */ -public class RpcServer extends Closeable { +public class RpcServer { /** Channel we are communicating on */ private final Channel _channel; /** Queue to receive requests from */ @@ -67,7 +66,6 @@ public RpcServer(Channel channel, String queueName) * it was a temporary queue, and marks the RpcServer as closed. * @throws IOException if an error is encountered */ - @Override public void close() throws IOException { From cecc35e6b525bf906c21e33a2493aaf76a015003 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Mon, 27 Apr 2015 10:06:49 +0300 Subject: [PATCH 0010/2114] Introduce Channel#messageCount Uses a passive queue.declare and returns the number of messages ready to be delivered. This is one of the most common questions on our list, high time we introduce a convenience method. --- src/com/rabbitmq/client/Channel.java | 10 ++++++++++ src/com/rabbitmq/client/impl/ChannelN.java | 18 ++++++++++++------ .../impl/recovery/AutorecoveringChannel.java | 4 ++++ 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/com/rabbitmq/client/Channel.java b/src/com/rabbitmq/client/Channel.java index 2040e81044..6e8b921fa9 100644 --- a/src/com/rabbitmq/client/Channel.java +++ b/src/com/rabbitmq/client/Channel.java @@ -899,4 +899,14 @@ void basicNack(long deliveryTag, boolean multiple, boolean requeue) * @throws IOException Problem transmitting method. */ Command rpc(Method method) throws IOException; + + /** + * Returns the number of messages in a queue ready to be delivered + * to consumers. This method assumes the queue exists. If it doesn't, + * an exception will be closed with an exception. + * @param queue the name of the queue + * @return the number of messages in ready state + * @throws IOException Problem transmitting method. + */ + long messageCount(String queue) throws IOException; } diff --git a/src/com/rabbitmq/client/impl/ChannelN.java b/src/com/rabbitmq/client/impl/ChannelN.java index b00c1c403c..8f4348ae1a 100644 --- a/src/com/rabbitmq/client/impl/ChannelN.java +++ b/src/com/rabbitmq/client/impl/ChannelN.java @@ -649,12 +649,12 @@ public void basicPublish(String exchange, String routingKey, useProps = MessageProperties.MINIMAL_BASIC; } transmit(new AMQCommand(new Basic.Publish.Builder() - .exchange(exchange) - .routingKey(routingKey) - .mandatory(mandatory) - .immediate(immediate) - .build(), - useProps, body)); + .exchange(exchange) + .routingKey(routingKey) + .mandatory(mandatory) + .immediate(immediate) + .build(), + useProps, body)); } /** Public API - {@inheritDoc} */ @@ -883,6 +883,12 @@ public Queue.DeclareOk queueDeclarePassive(String queue) .getMethod(); } + /** Public API - {@inheritDoc} */ + public long messageCount(String queue) throws IOException { + Queue.DeclareOk ok = queueDeclarePassive(queue); + return ok.getMessageCount(); + } + /** Public API - {@inheritDoc} */ public Queue.DeleteOk queueDelete(String queue, boolean ifUnused, boolean ifEmpty) throws IOException diff --git a/src/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java b/src/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java index 6921f6f4fe..3ca65771f9 100644 --- a/src/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java +++ b/src/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java @@ -287,6 +287,10 @@ public AMQP.Queue.DeclareOk queueDeclarePassive(String queue) throws IOException return delegate.queueDeclarePassive(queue); } + public long messageCount(String queue) throws IOException { + return delegate.messageCount(queue); + } + public AMQP.Queue.DeleteOk queueDelete(String queue) throws IOException { return queueDelete(queue, false, false); } From 0405c61fee3954b53a2d55e79b5320b789c52748 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Mon, 27 Apr 2015 10:07:16 +0300 Subject: [PATCH 0011/2114] Commit test case for Channel#messageCount --- .../client/test/functional/MessageCount.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 test/src/com/rabbitmq/client/test/functional/MessageCount.java diff --git a/test/src/com/rabbitmq/client/test/functional/MessageCount.java b/test/src/com/rabbitmq/client/test/functional/MessageCount.java new file mode 100644 index 0000000000..beec343dee --- /dev/null +++ b/test/src/com/rabbitmq/client/test/functional/MessageCount.java @@ -0,0 +1,21 @@ +package com.rabbitmq.client.test.functional; + +import com.rabbitmq.client.test.BrokerTestCase; + +import java.io.IOException; + +public class MessageCount extends BrokerTestCase { + public void testMessageCount() throws IOException { + String q = generateQueueName(); + channel.queueDeclareNoWait(q, false, true, true, null); + assertEquals(0, channel.messageCount(q)); + + basicPublishVolatile(q); + assertEquals(1, channel.messageCount(q)); + basicPublishVolatile(q); + assertEquals(2, channel.messageCount(q)); + + channel.queuePurge(q); + assertEquals(0, channel.messageCount(q)); + } +} From eccba6e18f10f18823f89a6f0bc435d8f1be574e Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Mon, 27 Apr 2015 10:22:54 +0300 Subject: [PATCH 0012/2114] Introduce Channel#consumerCount --- src/com/rabbitmq/client/Channel.java | 10 ++++++++++ src/com/rabbitmq/client/impl/ChannelN.java | 6 ++++++ .../impl/recovery/AutorecoveringChannel.java | 4 ++++ .../client/test/functional/ConsumerCount.java | 20 +++++++++++++++++++ .../client/test/functional/MessageCount.java | 2 +- 5 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 test/src/com/rabbitmq/client/test/functional/ConsumerCount.java diff --git a/src/com/rabbitmq/client/Channel.java b/src/com/rabbitmq/client/Channel.java index 6e8b921fa9..e665b08d33 100644 --- a/src/com/rabbitmq/client/Channel.java +++ b/src/com/rabbitmq/client/Channel.java @@ -909,4 +909,14 @@ void basicNack(long deliveryTag, boolean multiple, boolean requeue) * @throws IOException Problem transmitting method. */ long messageCount(String queue) throws IOException; + + /** + * Returns the number of consumers on a queue. + * This method assumes the queue exists. If it doesn't, + * an exception will be closed with an exception. + * @param queue the name of the queue + * @return the number of consumers + * @throws IOException Problem transmitting method. + */ + long consumerCount(String queue) throws IOException; } diff --git a/src/com/rabbitmq/client/impl/ChannelN.java b/src/com/rabbitmq/client/impl/ChannelN.java index 8f4348ae1a..4e347f2349 100644 --- a/src/com/rabbitmq/client/impl/ChannelN.java +++ b/src/com/rabbitmq/client/impl/ChannelN.java @@ -889,6 +889,12 @@ public long messageCount(String queue) throws IOException { return ok.getMessageCount(); } + /** Public API - {@inheritDoc} */ + public long consumerCount(String queue) throws IOException { + Queue.DeclareOk ok = queueDeclarePassive(queue); + return ok.getConsumerCount(); + } + /** Public API - {@inheritDoc} */ public Queue.DeleteOk queueDelete(String queue, boolean ifUnused, boolean ifEmpty) throws IOException diff --git a/src/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java b/src/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java index 3ca65771f9..5cb5245e95 100644 --- a/src/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java +++ b/src/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java @@ -291,6 +291,10 @@ public long messageCount(String queue) throws IOException { return delegate.messageCount(queue); } + public long consumerCount(String queue) throws IOException { + return delegate.consumerCount(queue); + } + public AMQP.Queue.DeleteOk queueDelete(String queue) throws IOException { return queueDelete(queue, false, false); } diff --git a/test/src/com/rabbitmq/client/test/functional/ConsumerCount.java b/test/src/com/rabbitmq/client/test/functional/ConsumerCount.java new file mode 100644 index 0000000000..ea22dbcde5 --- /dev/null +++ b/test/src/com/rabbitmq/client/test/functional/ConsumerCount.java @@ -0,0 +1,20 @@ +package com.rabbitmq.client.test.functional; + +import com.rabbitmq.client.DefaultConsumer; +import com.rabbitmq.client.test.BrokerTestCase; + +import java.io.IOException; + +public class ConsumerCount extends BrokerTestCase { + public void testConsumerCount() throws IOException { + String q = generateQueueName(); + channel.queueDeclare(q, false, true, false, null); + assertEquals(0, channel.consumerCount(q)); + + String tag = channel.basicConsume(q, new DefaultConsumer(channel)); + assertEquals(1, channel.consumerCount(q)); + + channel.basicCancel(tag); + assertEquals(0, channel.consumerCount(q)); + } +} diff --git a/test/src/com/rabbitmq/client/test/functional/MessageCount.java b/test/src/com/rabbitmq/client/test/functional/MessageCount.java index beec343dee..80996a4b29 100644 --- a/test/src/com/rabbitmq/client/test/functional/MessageCount.java +++ b/test/src/com/rabbitmq/client/test/functional/MessageCount.java @@ -7,7 +7,7 @@ public class MessageCount extends BrokerTestCase { public void testMessageCount() throws IOException { String q = generateQueueName(); - channel.queueDeclareNoWait(q, false, true, true, null); + channel.queueDeclare(q, false, true, false, null); assertEquals(0, channel.messageCount(q)); basicPublishVolatile(q); From 36c27b9836088acd03a2770eb2c2212dc5934a5d Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 29 Apr 2015 15:15:30 +0300 Subject: [PATCH 0013/2114] Update version --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0aedfa732a..8215aaf3a0 100644 --- a/README.md +++ b/README.md @@ -14,14 +14,14 @@ Maven artifacts are [released to Maven Central](http://search.maven.org/#search% com.rabbitmq amqp-client - 3.4.4 + 3.5.1 ``` ### Gradle ``` groovy -compile 'com.rabbitmq:amqp-client:3.4.4' +compile 'com.rabbitmq:amqp-client:3.5.1' ``` From b29a9c9ffc7f9c8c8c1e14b27c5757ffcd8062ac Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Tue, 5 May 2015 14:56:54 +0300 Subject: [PATCH 0014/2114] More sensible handling of InterruptedExceptions --- src/com/rabbitmq/client/impl/AMQChannel.java | 2 +- src/com/rabbitmq/client/impl/AMQConnection.java | 4 +++- src/com/rabbitmq/client/impl/WorkPool.java | 2 +- src/com/rabbitmq/tools/Tracer.java | 4 ++-- src/com/rabbitmq/utility/SingleShotLinearTimer.java | 2 +- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/com/rabbitmq/client/impl/AMQChannel.java b/src/com/rabbitmq/client/impl/AMQChannel.java index 09a8f1fc57..945f7bb6ed 100644 --- a/src/com/rabbitmq/client/impl/AMQChannel.java +++ b/src/com/rabbitmq/client/impl/AMQChannel.java @@ -58,7 +58,7 @@ public abstract class AMQChannel extends ShutdownNotifierComponent { private RpcContinuation _activeRpc = null; /** Whether transmission of content-bearing methods should be blocked */ - public boolean _blockContent = false; + public volatile boolean _blockContent = false; /** * Construct a channel on the given connection, with the given channel number. diff --git a/src/com/rabbitmq/client/impl/AMQConnection.java b/src/com/rabbitmq/client/impl/AMQConnection.java index 2da661e794..5c257556a7 100644 --- a/src/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/com/rabbitmq/client/impl/AMQConnection.java @@ -682,7 +682,9 @@ public SocketCloseWait(ShutdownSignalException sse) { public void run() { try { - _appContinuation.uninterruptibleGet(); + _appContinuation.get(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); } finally { _running = false; _channel0.notifyOutstandingRpc(cause); diff --git a/src/com/rabbitmq/client/impl/WorkPool.java b/src/com/rabbitmq/client/impl/WorkPool.java index 2251fdea86..1c8adc3979 100644 --- a/src/com/rabbitmq/client/impl/WorkPool.java +++ b/src/com/rabbitmq/client/impl/WorkPool.java @@ -196,7 +196,7 @@ public boolean addWorkItem(K key, W item) { try { queue.put(item); } catch (InterruptedException e) { - // ok + Thread.currentThread().interrupt(); } synchronized (this) { diff --git a/src/com/rabbitmq/tools/Tracer.java b/src/com/rabbitmq/tools/Tracer.java index 3cc41a9808..4c99ff9308 100644 --- a/src/com/rabbitmq/tools/Tracer.java +++ b/src/com/rabbitmq/tools/Tracer.java @@ -216,8 +216,8 @@ public void run() { } } - private void waitAndLogException(BlockingCell bc) { - reportAndLogNonNullException(bc.uninterruptibleGet()); + private void waitAndLogException(BlockingCell bc) throws InterruptedException { + reportAndLogNonNullException(bc.get()); } private void reportAndLogNonNullException(Exception e) { diff --git a/src/com/rabbitmq/utility/SingleShotLinearTimer.java b/src/com/rabbitmq/utility/SingleShotLinearTimer.java index 71f130f21b..638ed84bee 100644 --- a/src/com/rabbitmq/utility/SingleShotLinearTimer.java +++ b/src/com/rabbitmq/utility/SingleShotLinearTimer.java @@ -80,7 +80,7 @@ public void run() { wait(_runTime - now); } } catch (InterruptedException e) { - // Don't care + Thread.currentThread().interrupt(); } } From 94f594e7c7173faf5354cc9f691fd1f274b31838 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Sun, 10 May 2015 01:21:20 +0300 Subject: [PATCH 0015/2114] Test for rabbitmq/rabbitmq-server#152 --- .../test/server/XDeathHeaderGrowth.java | 110 ++++++++++++++++-- 1 file changed, 102 insertions(+), 8 deletions(-) diff --git a/test/src/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java b/test/src/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java index 9a259672e8..f4492a0ac0 100644 --- a/test/src/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java +++ b/test/src/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java @@ -13,6 +13,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.UUID; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -56,22 +57,18 @@ public void testBoundedXDeathHeaderGrowth() throws IOException, InterruptedExcep declareTransientFanoutExchange(x3); final String q1 = "issues.rabbitmq-server-78.queue1"; - Map args1 = argumentsForDeadLetteringTo(x1); - declareTransientQueue(q1, args1); + declareTransientQueue(q1, argumentsForDeadLetteringTo(x1)); final String q2 = "issues.rabbitmq-server-78.queue2"; - Map args2 = argumentsForDeadLetteringTo(x2); - declareTransientQueue(q2, args2); + declareTransientQueue(q2, argumentsForDeadLetteringTo(x2)); this.channel.queueBind(q2, x1, ""); final String q3 = "issues.rabbitmq-server-78.queue3"; - Map args3 = argumentsForDeadLetteringTo(x3); - declareTransientQueue(q3, args3); + declareTransientQueue(q3, argumentsForDeadLetteringTo(x3)); this.channel.queueBind(q3, x2, ""); final String qz = "issues.rabbitmq-server-78.destination"; - Map args4 = argumentsForDeadLetteringTo(x3); - declareTransientQueue(qz, args4); + declareTransientQueue(qz, argumentsForDeadLetteringTo(x3)); this.channel.queueBind(qz, x3, ""); CountDownLatch latch = new CountDownLatch(10); @@ -95,6 +92,103 @@ public void testBoundedXDeathHeaderGrowth() throws IOException, InterruptedExcep } Collections.sort(cs); assertEquals(Arrays.asList(1L, 1L, 1L, 9L), cs); + + cleanUpExchanges(x1, x2, x3); + cleanUpQueues(q1, q2, q3, qz); + } + + private void cleanUpExchanges(String... xs) throws IOException { + for(String x : xs) { + this.channel.exchangeDelete(x); + } + } + private void cleanUpQueues(String... qs) throws IOException { + for(String q : qs) { + this.channel.queueDelete(q); + } + } + + @SuppressWarnings("unchecked") + public void testHandlingOfXDeathHeadersFromEarlierVersions() throws IOException, InterruptedException { + final String x1 = "issues.rabbitmq-server-152.fanout1"; + declareTransientFanoutExchange(x1); + final String x2 = "issues.rabbitmq-server-152.fanout2"; + declareTransientFanoutExchange(x2); + + final String q1 = "issues.rabbitmq-server-152.queue1"; + declareTransientQueue(q1, argumentsForDeadLetteringTo(x1)); + + final String q2 = "issues.rabbitmq-server-152.queue2"; + declareTransientQueue(q2, argumentsForDeadLetteringTo(x2)); + this.channel.queueBind(q2, x1, ""); + + final String qz = "issues.rabbitmq-server-152.destination"; + declareTransientQueue(qz, argumentsForDeadLetteringTo(x2)); + this.channel.queueBind(qz, x2, ""); + + CountDownLatch latch = new CountDownLatch(10); + RejectingConsumer cons = new RejectingConsumer(this.channel, latch); + this.channel.basicConsume(qz, cons); + + final AMQP.BasicProperties.Builder bldr = new AMQP.BasicProperties.Builder(); + AMQP.BasicProperties props = bldr.headers( + propsWithLegacyXDeathsInHeaders("issues.rabbitmq-server-152.queue97", + "issues.rabbitmq-server-152.queue97", + "issues.rabbitmq-server-152.queue97", + "issues.rabbitmq-server-152.queue98", + "issues.rabbitmq-server-152.queue99")).build(); + this.channel.basicPublish("", q1, props, "msg".getBytes()); + + assertTrue(latch.await(5, TimeUnit.SECONDS)); + List> events = (List>)cons.getHeaders().get("x-death"); + assertEquals(6, events.size()); + + List qs = new ArrayList(); + for (Map evt : events) { + qs.add(evt.get("queue").toString()); + } + Collections.sort(qs); + assertEquals(Arrays.asList(qz, q1, q2, + "issues.rabbitmq-server-152.queue97", + "issues.rabbitmq-server-152.queue98", + "issues.rabbitmq-server-152.queue99"), qs); + List cs = new ArrayList(); + for (Map evt : events) { + cs.add((Long)evt.get("count")); + } + Collections.sort(cs); + assertEquals(Arrays.asList(1L, 1L, 4L, 4L, 9L, 12L), cs); + + cleanUpExchanges(x1, x2); + cleanUpQueues(q1, q2, qz, + "issues.rabbitmq-server-152.queue97", + "issues.rabbitmq-server-152.queue98", + "issues.rabbitmq-server-152.queue99"); + } + + private Map propsWithLegacyXDeathsInHeaders(String... qs) { + Map m = new HashMap(); + List> xDeaths = new ArrayList>(); + for(String q : qs) { + xDeaths.add(newXDeath(q)); + xDeaths.add(newXDeath(q)); + xDeaths.add(newXDeath(q)); + xDeaths.add(newXDeath(q)); + } + + m.put("x-death", xDeaths); + return m; + } + + private Map newXDeath(String q) { + Map m = new HashMap(); + m.put("reason", "expired"); + m.put("queue", q); + m.put("exchange", "issues.rabbitmq-server-152.fanout0"); + m.put("routing-keys", Arrays.asList("routing-key-1", "routing-key-2")); + m.put("random", UUID.randomUUID().toString()); + + return m; } private Map argumentsForDeadLetteringTo(String dlx) { From bdc45330c86837e87e52427c276c77c1de942ce9 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 13 May 2015 15:03:59 +0300 Subject: [PATCH 0016/2114] Make it clearer that publishes can block when an alarm is in effect Fixes 30. --- src/com/rabbitmq/client/Channel.java | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/com/rabbitmq/client/Channel.java b/src/com/rabbitmq/client/Channel.java index 2040e81044..23aa907cae 100644 --- a/src/com/rabbitmq/client/Channel.java +++ b/src/com/rabbitmq/client/Channel.java @@ -245,8 +245,16 @@ public interface Channel extends ShutdownNotifier { void basicQos(int prefetchCount) throws IOException; /** - * Publish a message + * Publish a message. + * + * Publishing to a non-existent exchange will result in a channel-level + * protocol exception, which closes the channel. + * + * Invocations of Channel#basicPublish will eventually block if a + * resource-driven alarm is in effect. + * * @see com.rabbitmq.client.AMQP.Basic.Publish + * @see Resource-driven alarms. * @param exchange the exchange to publish the message to * @param routingKey the routing key * @param props other properties for the message - routing headers etc @@ -256,8 +264,13 @@ public interface Channel extends ShutdownNotifier { void basicPublish(String exchange, String routingKey, BasicProperties props, byte[] body) throws IOException; /** - * Publish a message + * Publish a message. + * + * Invocations of Channel#basicPublish will eventually block if a + * resource-driven alarm is in effect. + * * @see com.rabbitmq.client.AMQP.Basic.Publish + * @see Resource-driven alarms. * @param exchange the exchange to publish the message to * @param routingKey the routing key * @param mandatory true if the 'mandatory' flag is to be set @@ -269,8 +282,16 @@ void basicPublish(String exchange, String routingKey, boolean mandatory, BasicPr throws IOException; /** - * Publish a message + * Publish a message. + * + * Publishing to a non-existent exchange will result in a channel-level + * protocol exception, which closes the channel. + * + * Invocations of Channel#basicPublish will eventually block if a + * resource-driven alarm is in effect. + * * @see com.rabbitmq.client.AMQP.Basic.Publish + * @see Resource-driven alarms. * @param exchange the exchange to publish the message to * @param routingKey the routing key * @param mandatory true if the 'mandatory' flag is to be set From 0148557f1a3f54c009f277acb5c666a51f678489 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 13 May 2015 15:26:06 +0300 Subject: [PATCH 0017/2114] Revisit Channel documentation Adds sections that link to tutorials, API guide, and (briefly) cover concurrency considerations. Follow-up to #58, fixes #30. --- src/com/rabbitmq/client/Channel.java | 45 +++++++++++++--------------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/src/com/rabbitmq/client/Channel.java b/src/com/rabbitmq/client/Channel.java index 23aa907cae..ea8e88b364 100644 --- a/src/com/rabbitmq/client/Channel.java +++ b/src/com/rabbitmq/client/Channel.java @@ -28,36 +28,33 @@ import com.rabbitmq.client.AMQP.Confirm; /** - * Public API: Interface to an AMQ channel. See the spec for details. + * Interface to a channel. All non-deprecated methods of + * this interface are part of the public API. * - *

- * To open a channel, - *

- * {@link Connection} conn = ...;
- * {@link Channel} channel = conn.{@link Connection#createChannel createChannel}();
- * 
- *

- * Public API: - *

    - *
  • getChannelNumber - *
  • close - *
- *

+ *

Tutorials

+ * RabbitMQ tutorials demonstrate how + * key methods of this interface are used. * + *

User Guide

+ * See + * + *

Concurrency Considerations

*

- * {@link Channel} instances are safe for use by multiple - * threads. Requests into a {@link Channel} are serialized, with only one - * thread running commands at a time. - * As such, applications may prefer using a {@link Channel} per thread - * instead of sharing the same Channel across multiple threads. + * {@link Channel} instances must not be shared between + * threads. Applications + * should prefer using a {@link Channel} per thread + * instead of sharing the same {@link Channel} across + * multiple threads. While some operations on channels are safe to invoke + * concurrently, some are not and will result in incorrect frame interleaving + * on the wire. Sharing channels between threads will also interfere with + * Publisher Confirms. * - * An important caveat to this is that confirms are not handled - * properly when a {@link Channel} is shared between multiple threads. In that - * scenario, it is therefore important to ensure that the {@link Channel} - * instance is not accessed concurrently by multiple threads. + * As such, applications need to use a {@link Channel} per thread. + *

* + * @see RabbitMQ tutorials + * @see RabbitMQ Java Client User Guide */ - public interface Channel extends ShutdownNotifier { /** * Retrieve this channel's channel number. From 5cad8fad2bde15e92eb58364947dc72cce3a632e Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 13 May 2015 15:31:42 +0300 Subject: [PATCH 0018/2114] Safe this file for real --- src/com/rabbitmq/client/Channel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/rabbitmq/client/Channel.java b/src/com/rabbitmq/client/Channel.java index ea8e88b364..e19cd3f2e8 100644 --- a/src/com/rabbitmq/client/Channel.java +++ b/src/com/rabbitmq/client/Channel.java @@ -36,7 +36,7 @@ * key methods of this interface are used. * *

User Guide

- * See + * See Java Client User Guide. * *

Concurrency Considerations

*

From ee11f5cc7bbcdb362e43bdd4a0084e6160186124 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 13 May 2015 16:58:50 +0300 Subject: [PATCH 0019/2114] Improve docs around recovery listeners --- src/com/rabbitmq/client/Connection.java | 3 ++ .../rabbitmq/client/ConnectionFactory.java | 40 ++++++++++++++++--- src/com/rabbitmq/client/Recoverable.java | 7 ++++ 3 files changed, 44 insertions(+), 6 deletions(-) diff --git a/src/com/rabbitmq/client/Connection.java b/src/com/rabbitmq/client/Connection.java index 3abfaa2226..37c0758176 100644 --- a/src/com/rabbitmq/client/Connection.java +++ b/src/com/rabbitmq/client/Connection.java @@ -101,6 +101,9 @@ public interface Connection extends ShutdownNotifier { // rename to AMQPConnecti /** * Create a new channel, using an internally allocated channel number. + * If automatic connection recovery + * is enabled, the channel returned by this method will be {@link Recoverable}. + * * @return a new channel descriptor, or null if none is available * @throws IOException if an I/O problem is encountered */ diff --git a/src/com/rabbitmq/client/ConnectionFactory.java b/src/com/rabbitmq/client/ConnectionFactory.java index c80b33d0e9..976f8f60a0 100644 --- a/src/com/rabbitmq/client/ConnectionFactory.java +++ b/src/com/rabbitmq/client/ConnectionFactory.java @@ -530,16 +530,19 @@ public void useSslProtocol(SSLContext context) } /** - * Returns true if automatic connection recovery is enabled, false otherwise + * Returns true if automatic connection recovery + * is enabled, false otherwise * @return true if automatic connection recovery is enabled, false otherwise + * @see Automatic Recovery */ public boolean isAutomaticRecoveryEnabled() { return automaticRecovery; } /** - * Enables or disables automatic connection recovery + * Enables or disables automatic connection recovery. * @param automaticRecovery if true, enables connection recovery + * @see Automatic Recovery */ public void setAutomaticRecoveryEnabled(boolean automaticRecovery) { this.automaticRecovery = automaticRecovery; @@ -548,6 +551,7 @@ public void setAutomaticRecoveryEnabled(boolean automaticRecovery) { /** * Returns true if topology recovery is enabled, false otherwise * @return true if topology recovery is enabled, false otherwise + * @see Automatic Recovery */ @SuppressWarnings("unused") public boolean isTopologyRecoveryEnabled() { @@ -557,6 +561,7 @@ public boolean isTopologyRecoveryEnabled() { /** * Enables or disables topology recovery * @param topologyRecovery if true, enables topology recovery + * @see Automatic Recovery */ public void setTopologyRecoveryEnabled(boolean topologyRecovery) { this.topologyRecovery = topologyRecovery; @@ -567,7 +572,13 @@ protected FrameHandlerFactory createFrameHandlerFactory() throws IOException { } /** - * Create a new broker connection + * Create a new broker connection, picking the first available address from + * the list. + * + * If automatic connection recovery + * is enabled, the connection returned by this method will be {@link Recoverable}. Future + * reconnection attempts will pick a random accessible address from the provided list. + * * @param addrs an array of known broker addresses (hostname/port pairs) to try in order * @return an interface to the connection * @throws IOException if it encounters a problem @@ -577,11 +588,18 @@ public Connection newConnection(Address[] addrs) throws IOException { } /** - * Create a new broker connection + * Create a new broker connection, picking the first available address from + * the list. + * + * If automatic connection recovery + * is enabled, the connection returned by this method will be {@link Recoverable}. Future + * reconnection attempts will pick a random accessible address from the provided list. + * * @param executor thread execution service for consumers on the connection * @param addrs an array of known broker addresses (hostname/port pairs) to try in order * @return an interface to the connection * @throws java.io.IOException if it encounters a problem + * @see Automatic Recovery */ public Connection newConnection(ExecutorService executor, Address[] addrs) throws IOException @@ -617,7 +635,12 @@ public ConnectionParams params(ExecutorService executor) { } /** - * Create a new broker connection + * Create a new broker connection. + * + * If automatic connection recovery + * is enabled, the connection returned by this method will be {@link Recoverable}. Reconnection + * attempts will always use the address configured on {@link ConnectionFactory}. + * * @return an interface to the connection * @throws IOException if it encounters a problem */ @@ -628,7 +651,12 @@ public Connection newConnection() throws IOException { } /** - * Create a new broker connection + * Create a new broker connection. + * + * If automatic connection recovery + * is enabled, the connection returned by this method will be {@link Recoverable}. Reconnection + * attempts will always use the address configured on {@link ConnectionFactory}. + * * @param executor thread execution service for consumers on the connection * @return an interface to the connection * @throws IOException if it encounters a problem diff --git a/src/com/rabbitmq/client/Recoverable.java b/src/com/rabbitmq/client/Recoverable.java index f7efe8ea5f..e91166a3a9 100644 --- a/src/com/rabbitmq/client/Recoverable.java +++ b/src/com/rabbitmq/client/Recoverable.java @@ -3,6 +3,13 @@ /** * Provides a way to register (network, AMQP 0-9-1) connection recovery * callbacks. + * + * When connection recovery is enabled via {@link ConnectionFactory}, + * {@link ConnectionFactory#newConnection()} and {@link Connection#createChannel()} + * return {@link Recoverable} connections and channels. + * + * @see com.rabbitmq.client.impl.recovery.AutorecoveringConnection + * @see com.rabbitmq.client.impl.recovery.AutorecoveringChannel */ public interface Recoverable { /** From 6dc3bc6cb7a36fc3cb7ee3c6dedb560cb13794cf Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 13 May 2015 17:06:00 +0300 Subject: [PATCH 0020/2114] Deprecate methods related to the old flow control Fixes #59. --- src/com/rabbitmq/client/Channel.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/com/rabbitmq/client/Channel.java b/src/com/rabbitmq/client/Channel.java index e19cd3f2e8..0d24a6eb58 100644 --- a/src/com/rabbitmq/client/Channel.java +++ b/src/com/rabbitmq/client/Channel.java @@ -86,9 +86,9 @@ public interface Channel extends ShutdownNotifier { void close(int closeCode, String closeMessage) throws IOException, TimeoutException; /** - * Indicates whether the server has asked this client to stop - * sending content-bearing commands (such as basic.publish) by - * issueing a channel.flow{active=false}. + * Deprecated, superseded by TCP back pressure. + * @deprecated + * @see Resource-driven alarms */ boolean flowBlocked(); @@ -130,12 +130,18 @@ public interface Channel extends ShutdownNotifier { /** * Add a {@link FlowListener}. + * Deprecated, superseded by TCP back pressure. + * @deprecated + * @see Resource-driven alarms * @param listener the listener to add */ void addFlowListener(FlowListener listener); /** * Remove a {@link FlowListener}. + * Deprecated, superseded by TCP back pressure. + * @deprecated + * @see Resource-driven alarms * @param listener the listener to remove * @return true if the listener was found and removed, * false otherwise @@ -144,6 +150,9 @@ public interface Channel extends ShutdownNotifier { /** * Remove all {@link FlowListener}s. + * Deprecated, superseded by TCP back pressure. + * @deprecated + * @see Resource-driven alarms */ void clearFlowListeners(); From c4f037f245d976ed348f3bd00dc46ad0f54df1bd Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 13 May 2015 22:08:44 +0300 Subject: [PATCH 0021/2114] During handshake, await on continuations with a timeout --- .../rabbitmq/client/ConnectionFactory.java | 10 +++--- src/com/rabbitmq/client/impl/AMQChannel.java | 13 ++++++++ .../rabbitmq/client/impl/AMQConnection.java | 32 ++++++++++--------- 3 files changed, 35 insertions(+), 20 deletions(-) diff --git a/src/com/rabbitmq/client/ConnectionFactory.java b/src/com/rabbitmq/client/ConnectionFactory.java index 976f8f60a0..f5632dac4b 100644 --- a/src/com/rabbitmq/client/ConnectionFactory.java +++ b/src/com/rabbitmq/client/ConnectionFactory.java @@ -27,6 +27,7 @@ import java.net.URLDecoder; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeoutException; import javax.net.SocketFactory; import javax.net.ssl.SSLSocketFactory; @@ -583,7 +584,7 @@ protected FrameHandlerFactory createFrameHandlerFactory() throws IOException { * @return an interface to the connection * @throws IOException if it encounters a problem */ - public Connection newConnection(Address[] addrs) throws IOException { + public Connection newConnection(Address[] addrs) throws IOException, TimeoutException { return newConnection(this.sharedExecutor, addrs); } @@ -602,8 +603,7 @@ public Connection newConnection(Address[] addrs) throws IOException { * @see Automatic Recovery */ public Connection newConnection(ExecutorService executor, Address[] addrs) - throws IOException - { + throws IOException, TimeoutException { FrameHandlerFactory fhFactory = createFrameHandlerFactory(); ConnectionParams params = params(executor); @@ -644,7 +644,7 @@ public ConnectionParams params(ExecutorService executor) { * @return an interface to the connection * @throws IOException if it encounters a problem */ - public Connection newConnection() throws IOException { + public Connection newConnection() throws IOException, TimeoutException { return newConnection(this.sharedExecutor, new Address[] {new Address(getHost(), getPort())} ); @@ -661,7 +661,7 @@ public Connection newConnection() throws IOException { * @return an interface to the connection * @throws IOException if it encounters a problem */ - public Connection newConnection(ExecutorService executor) throws IOException { + public Connection newConnection(ExecutorService executor) throws IOException, TimeoutException { return newConnection(executor, new Address[] {new Address(getHost(), getPort())} ); diff --git a/src/com/rabbitmq/client/impl/AMQChannel.java b/src/com/rabbitmq/client/impl/AMQChannel.java index 945f7bb6ed..57249855a8 100644 --- a/src/com/rabbitmq/client/impl/AMQChannel.java +++ b/src/com/rabbitmq/client/impl/AMQChannel.java @@ -207,6 +207,11 @@ public AMQCommand rpc(Method m) return privateRpc(m); } + public AMQCommand rpc(Method m, int timeout) + throws IOException, ShutdownSignalException, TimeoutException { + return privateRpc(m, timeout); + } + private AMQCommand privateRpc(Method m) throws IOException, ShutdownSignalException { @@ -221,6 +226,14 @@ private AMQCommand privateRpc(Method m) return k.getReply(); } + private AMQCommand privateRpc(Method m, int timeout) + throws IOException, ShutdownSignalException, TimeoutException { + SimpleBlockingRpcContinuation k = new SimpleBlockingRpcContinuation(); + rpc(m, k); + + return k.getReply(timeout); + } + public void rpc(Method m, RpcContinuation k) throws IOException { diff --git a/src/com/rabbitmq/client/impl/AMQConnection.java b/src/com/rabbitmq/client/impl/AMQConnection.java index 5c257556a7..6d8348073e 100644 --- a/src/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/com/rabbitmq/client/impl/AMQConnection.java @@ -255,8 +255,7 @@ private void initializeHeartbeatSender() { * garbage collected when the connection object is no longer referenced. */ public void start() - throws IOException - { + throws IOException, TimeoutException { initializeConsumerWorkService(); initializeHeartbeatSender(); this._running = true; @@ -292,24 +291,24 @@ public void start() AMQP.Connection.Tune connTune = null; try { connStart = - (AMQP.Connection.Start) connStartBlocker.getReply().getMethod(); + (AMQP.Connection.Start) connStartBlocker.getReply(HANDSHAKE_TIMEOUT/2).getMethod(); _serverProperties = Collections.unmodifiableMap(connStart.getServerProperties()); Version serverVersion = - new Version(connStart.getVersionMajor(), - connStart.getVersionMinor()); + new Version(connStart.getVersionMajor(), + connStart.getVersionMinor()); if (!Version.checkVersion(clientVersion, serverVersion)) { throw new ProtocolVersionMismatchException(clientVersion, - serverVersion); + serverVersion); } String[] mechanisms = connStart.getMechanisms().toString().split(" "); SaslMechanism sm = this.saslConfig.getSaslMechanism(mechanisms); if (sm == null) { throw new IOException("No compatible authentication mechanism found - " + - "server offered [" + connStart.getMechanisms() + "]"); + "server offered [" + connStart.getMechanisms() + "]"); } LongString challenge = null; @@ -317,15 +316,15 @@ public void start() do { Method method = (challenge == null) - ? new AMQP.Connection.StartOk.Builder() - .clientProperties(_clientProperties) - .mechanism(sm.getName()) - .response(response) - .build() - : new AMQP.Connection.SecureOk.Builder().response(response).build(); + ? new AMQP.Connection.StartOk.Builder() + .clientProperties(_clientProperties) + .mechanism(sm.getName()) + .response(response) + .build() + : new AMQP.Connection.SecureOk.Builder().response(response).build(); try { - Method serverResponse = _channel0.rpc(method).getMethod(); + Method serverResponse = _channel0.rpc(method, HANDSHAKE_TIMEOUT/2).getMethod(); if (serverResponse instanceof AMQP.Connection.Tune) { connTune = (AMQP.Connection.Tune) serverResponse; } else { @@ -335,7 +334,7 @@ public void start() } catch (ShutdownSignalException e) { Method shutdownMethod = e.getReason(); if (shutdownMethod instanceof AMQP.Connection.Close) { - AMQP.Connection.Close shutdownClose = (AMQP.Connection.Close) shutdownMethod; + AMQP.Connection.Close shutdownClose = (AMQP.Connection.Close) shutdownMethod; if (shutdownClose.getReplyCode() == AMQP.ACCESS_REFUSED) { throw new AuthenticationFailureException(shutdownClose.getReplyText()); } @@ -343,6 +342,9 @@ public void start() throw new PossibleAuthenticationFailureException(e); } } while (connTune == null); + } catch (TimeoutException te) { + _frameHandler.close(); + throw te; } catch (ShutdownSignalException sse) { _frameHandler.close(); throw AMQChannel.wrap(sse); From e4bf2c5211d9861adf33658c1182650ce89e441e Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 13 May 2015 22:44:36 +0300 Subject: [PATCH 0022/2114] Compile from scratch --- .../client/impl/recovery/AutorecoveringConnection.java | 3 ++- .../impl/recovery/RecoveryAwareAMQConnectionFactory.java | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index 3a73b59b1e..f56f2eed2d 100644 --- a/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -27,6 +27,7 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeoutException; /** * Connection implementation that performs automatic recovery when @@ -79,7 +80,7 @@ public AutorecoveringConnection(ConnectionParams params, FrameHandlerFactory f, * @throws IOException * @see com.rabbitmq.client.ConnectionFactory#newConnection(java.util.concurrent.ExecutorService) */ - public void init() throws IOException { + public void init() throws IOException, TimeoutException { this.delegate = this.cf.newConnection(); this.addAutomaticRecoveryListener(); } diff --git a/src/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java b/src/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java index 58f747842e..6c5cb5541e 100644 --- a/src/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java +++ b/src/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java @@ -10,6 +10,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.concurrent.TimeoutException; public class RecoveryAwareAMQConnectionFactory { private final ConnectionParams params; @@ -26,8 +27,7 @@ public RecoveryAwareAMQConnectionFactory(ConnectionParams params, FrameHandlerFa * @return an interface to the connection * @throws java.io.IOException if it encounters a problem */ - RecoveryAwareAMQConnection newConnection() throws IOException - { + RecoveryAwareAMQConnection newConnection() throws IOException, TimeoutException { IOException lastException = null; for (Address addr : shuffle(addrs)) { try { From 2f49ce5be83601dfd19f8a28ec09d5628b677118 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 15 May 2015 14:46:30 +0300 Subject: [PATCH 0023/2114] Pick highest TLS version available Fall back to SSLv3 when we run on a really old or crippled JDK. --- .../rabbitmq/client/test/BrokerTestCase.java | 31 ++++++++++++++++--- .../test/ssl/BadVerifiedConnection.java | 8 ++--- .../client/test/ssl/UnverifiedConnection.java | 4 +-- .../client/test/ssl/VerifiedConnection.java | 7 +++-- 4 files changed, 36 insertions(+), 14 deletions(-) diff --git a/test/src/com/rabbitmq/client/test/BrokerTestCase.java b/test/src/com/rabbitmq/client/test/BrokerTestCase.java index 2521e1f19b..88030ed5ac 100644 --- a/test/src/com/rabbitmq/client/test/BrokerTestCase.java +++ b/test/src/com/rabbitmq/client/test/BrokerTestCase.java @@ -18,8 +18,11 @@ package com.rabbitmq.client.test; import java.io.IOException; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; import java.util.Map; import java.util.UUID; +import java.util.concurrent.TimeoutException; import junit.framework.TestCase; @@ -36,6 +39,8 @@ import com.rabbitmq.client.AMQP; import com.rabbitmq.tools.Host; +import javax.net.ssl.SSLContext; + public class BrokerTestCase extends TestCase { protected ConnectionFactory connectionFactory = newConnectionFactory(); @@ -47,7 +52,7 @@ protected ConnectionFactory newConnectionFactory() { protected Channel channel; protected void setUp() - throws IOException { + throws IOException, TimeoutException { openConnection(); openChannel(); @@ -55,7 +60,7 @@ protected void setUp() } protected void tearDown() - throws IOException { + throws IOException, TimeoutException { closeChannel(); closeConnection(); @@ -72,7 +77,7 @@ protected void tearDown() * connection and channel have been opened. */ protected void createResources() - throws IOException { + throws IOException, TimeoutException { } /** @@ -87,7 +92,7 @@ protected void releaseResources() } protected void restart() - throws IOException { + throws IOException, TimeoutException { tearDown(); bareRestart(); setUp(); @@ -99,7 +104,7 @@ protected void bareRestart() } public void openConnection() - throws IOException { + throws IOException, TimeoutException { if (connection == null) { connection = connectionFactory.newConnection(); } @@ -285,4 +290,20 @@ protected String generateQueueName() { protected String generateExchangeName() { return "exchange" + UUID.randomUUID().toString(); } + + protected SSLContext getSSLContext() throws NoSuchAlgorithmException { + SSLContext c = null; + + // pick the first protocol available, preferring TLSv1.2, then TLSv1, + // falling back to SSLv3 if running on an ancient/crippled JDK + for(String proto : Arrays.asList("TLSv1.2", "TLSv1", "SSLv3")) { + try { + c = SSLContext.getInstance(proto); + return c; + } catch (NoSuchAlgorithmException x) { + // keep trying + } + } + throw new NoSuchAlgorithmException(); + } } diff --git a/test/src/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java b/test/src/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java index d525d0de4b..c463a1d463 100644 --- a/test/src/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java +++ b/test/src/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java @@ -24,6 +24,7 @@ import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; +import java.util.concurrent.TimeoutException; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; @@ -38,8 +39,7 @@ */ public class BadVerifiedConnection extends UnverifiedConnection { public void openConnection() - throws IOException - { + throws IOException, TimeoutException { try { String keystorePath = System.getProperty("keystore.empty.path"); assertNotNull(keystorePath); @@ -64,7 +64,7 @@ public void openConnection() KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); kmf.init(ks, p12Password); - SSLContext c = SSLContext.getInstance("SSLv3"); + SSLContext c = getSSLContext(); c.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); connectionFactory = new ConnectionFactory(); @@ -85,7 +85,7 @@ public void openConnection() try { connection = connectionFactory.newConnection(); fail(); - } catch (SSLHandshakeException e) { + } catch (SSLHandshakeException ignored) { } catch (IOException e) { fail(); } diff --git a/test/src/com/rabbitmq/client/test/ssl/UnverifiedConnection.java b/test/src/com/rabbitmq/client/test/ssl/UnverifiedConnection.java index abb10a996b..f9378efe7d 100644 --- a/test/src/com/rabbitmq/client/test/ssl/UnverifiedConnection.java +++ b/test/src/com/rabbitmq/client/test/ssl/UnverifiedConnection.java @@ -19,6 +19,7 @@ import java.io.IOException; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; +import java.util.concurrent.TimeoutException; import com.rabbitmq.client.GetResponse; import com.rabbitmq.client.test.BrokerTestCase; @@ -29,8 +30,7 @@ */ public class UnverifiedConnection extends BrokerTestCase { public void openConnection() - throws IOException - { + throws IOException, TimeoutException { try { connectionFactory.useSslProtocol(); } catch (NoSuchAlgorithmException ex) { diff --git a/test/src/com/rabbitmq/client/test/ssl/VerifiedConnection.java b/test/src/com/rabbitmq/client/test/ssl/VerifiedConnection.java index ce4a4480e5..c48763f82c 100644 --- a/test/src/com/rabbitmq/client/test/ssl/VerifiedConnection.java +++ b/test/src/com/rabbitmq/client/test/ssl/VerifiedConnection.java @@ -24,6 +24,8 @@ import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; +import java.util.Arrays; +import java.util.concurrent.TimeoutException; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; @@ -38,8 +40,7 @@ public class VerifiedConnection extends UnverifiedConnection { public void openConnection() - throws IOException - { + throws IOException, TimeoutException { try { String keystorePath = System.getProperty("keystore.path"); assertNotNull(keystorePath); @@ -64,7 +65,7 @@ public void openConnection() KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); kmf.init(ks, p12Password); - SSLContext c = SSLContext.getInstance("SSLv3"); + SSLContext c = getSSLContext(); c.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); connectionFactory = new ConnectionFactory(); From 4dc9801f1bdf569bb30f488137b0cd70bdde3002 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 15 May 2015 14:47:51 +0300 Subject: [PATCH 0024/2114] Make tests compile from scratch Adapt to the recently introduced TimeoutException in the ConnectionFactory#newConnection signature. --- .../client/test/AMQConnectionTest.java | 8 +++++--- .../client/test/SharedThreadPoolTest.java | 3 ++- .../test/functional/AbstractRejectTest.java | 7 +++---- .../test/functional/AlternateExchange.java | 3 ++- .../test/functional/BindingLifecycle.java | 5 +++-- .../test/functional/BindingLifecycleBase.java | 9 +++++---- .../client/test/functional/CcRoutes.java | 5 +++-- .../test/functional/ClusteredTestBase.java | 3 ++- .../client/test/functional/Confirm.java | 2 +- .../test/functional/ConnectionOpen.java | 3 ++- .../test/functional/ConnectionRecovery.java | 17 ++++++++++------ .../test/functional/ExceptionHandling.java | 6 ++++-- .../functional/ExchangeDeleteIfUnused.java | 4 ++-- .../client/test/functional/FrameMax.java | 10 ++++------ .../client/test/functional/QosTests.java | 4 ++-- .../test/functional/QueueExclusivity.java | 3 ++- .../test/functional/QueueLifecycle.java | 3 ++- .../test/functional/RequeueOnClose.java | 12 +++++------ .../functional/RequeueOnConnectionClose.java | 4 ++-- .../test/functional/SaslMechanisms.java | 20 ++++++++++--------- .../client/test/functional/Transactions.java | 4 ++-- .../client/test/functional/UserIDHeader.java | 3 ++- .../client/test/performance/QosScaling.java | 3 ++- .../test/performance/StressManagement.java | 5 +++-- .../client/test/server/AbsentQueue.java | 5 +++-- .../client/test/server/BlockedConnection.java | 3 ++- .../client/test/server/Bug19219Test.java | 5 ++++- .../test/server/DurableBindingLifecycle.java | 13 ++++++------ .../test/server/ExclusiveQueueDurability.java | 3 ++- .../rabbitmq/client/test/server/Firehose.java | 3 ++- .../client/test/server/LoopbackUsers.java | 11 +++++----- .../client/test/server/MemoryAlarms.java | 5 +++-- .../client/test/server/Permissions.java | 13 +++++------- .../rabbitmq/examples/StressPersister.java | 8 +++++--- test/src/com/rabbitmq/examples/TestMain.java | 20 +++++++++---------- .../rabbitmq/examples/perf/MulticastSet.java | 5 +++-- .../examples/perf/SimpleScenario.java | 3 ++- 37 files changed, 136 insertions(+), 107 deletions(-) diff --git a/test/src/com/rabbitmq/client/test/AMQConnectionTest.java b/test/src/com/rabbitmq/client/test/AMQConnectionTest.java index a22b2495be..d229fba8d9 100644 --- a/test/src/com/rabbitmq/client/test/AMQConnectionTest.java +++ b/test/src/com/rabbitmq/client/test/AMQConnectionTest.java @@ -24,6 +24,7 @@ import java.util.Collections; import java.util.List; import java.util.concurrent.Executors; +import java.util.concurrent.TimeoutException; import com.rabbitmq.client.impl.ConnectionParams; import com.rabbitmq.client.TopologyRecoveryException; @@ -86,7 +87,7 @@ public static TestSuite suite() { /** Check the AMQConnection does send exactly 1 initial header, and deal correctly with * the frame handler throwing an exception when we try to read data */ - public void testConnectionSendsSingleHeaderAndTimesOut() { + public void testConnectionSendsSingleHeaderAndTimesOut() throws TimeoutException { IOException exception = new SocketTimeoutException(); _mockFrameHandler.setExceptionOnReadingFrames(exception); assertEquals(0, _mockFrameHandler.countHeadersSent()); @@ -127,10 +128,11 @@ public void testConnectionHangInNegotiation() { new AMQConnection(params, this._mockFrameHandler).start(); fail("Connection should have thrown exception"); } catch(IOException signal) { - // As expected + // expected + } catch(TimeoutException te) { + // also fine: continuation timed out first } assertEquals(1, this._mockFrameHandler.countHeadersSent()); - // _connection.close(0, CLOSE_MESSAGE); List exceptionList = exceptionHandler.getHandledExceptions(); assertEquals("Only one exception expected", 1, exceptionList.size()); assertEquals("Wrong type of exception returned.", SocketTimeoutException.class, exceptionList.get(0).getClass()); diff --git a/test/src/com/rabbitmq/client/test/SharedThreadPoolTest.java b/test/src/com/rabbitmq/client/test/SharedThreadPoolTest.java index ee828e1d42..48763e40f7 100644 --- a/test/src/com/rabbitmq/client/test/SharedThreadPoolTest.java +++ b/test/src/com/rabbitmq/client/test/SharedThreadPoolTest.java @@ -6,9 +6,10 @@ import java.io.IOException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.TimeoutException; public class SharedThreadPoolTest extends BrokerTestCase { - public void testWillShutDownExecutor() throws IOException { + public void testWillShutDownExecutor() throws IOException, TimeoutException { ConnectionFactory cf = new ConnectionFactory(); ExecutorService executor = Executors.newFixedThreadPool(8); cf.setSharedExecutor(executor); diff --git a/test/src/com/rabbitmq/client/test/functional/AbstractRejectTest.java b/test/src/com/rabbitmq/client/test/functional/AbstractRejectTest.java index f6c88eb10f..6922f8caf2 100644 --- a/test/src/com/rabbitmq/client/test/functional/AbstractRejectTest.java +++ b/test/src/com/rabbitmq/client/test/functional/AbstractRejectTest.java @@ -25,6 +25,7 @@ import java.io.IOException; import java.util.Arrays; +import java.util.concurrent.TimeoutException; abstract class AbstractRejectTest extends BrokerTestCase { @@ -32,8 +33,7 @@ abstract class AbstractRejectTest extends BrokerTestCase { @Override protected void setUp() - throws IOException - { + throws IOException, TimeoutException { super.setUp(); secondaryChannel = connection.createChannel(); @@ -41,8 +41,7 @@ protected void setUp() @Override protected void tearDown() - throws IOException - { + throws IOException, TimeoutException { if (secondaryChannel != null) { secondaryChannel.abort(); secondaryChannel = null; diff --git a/test/src/com/rabbitmq/client/test/functional/AlternateExchange.java b/test/src/com/rabbitmq/client/test/functional/AlternateExchange.java index 9a33e740d6..89e7919617 100644 --- a/test/src/com/rabbitmq/client/test/functional/AlternateExchange.java +++ b/test/src/com/rabbitmq/client/test/functional/AlternateExchange.java @@ -23,6 +23,7 @@ import com.rabbitmq.client.GetResponse; import java.io.IOException; +import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.Map; import java.util.HashMap; @@ -55,7 +56,7 @@ private static boolean[] expected(String key) { return expected; } - @Override protected void setUp() throws IOException { + @Override protected void setUp() throws IOException, TimeoutException { super.setUp(); channel.addReturnListener(new ReturnListener() { public void handleReturn(int replyCode, diff --git a/test/src/com/rabbitmq/client/test/functional/BindingLifecycle.java b/test/src/com/rabbitmq/client/test/functional/BindingLifecycle.java index eb02962f16..53ba458660 100644 --- a/test/src/com/rabbitmq/client/test/functional/BindingLifecycle.java +++ b/test/src/com/rabbitmq/client/test/functional/BindingLifecycle.java @@ -18,6 +18,7 @@ package com.rabbitmq.client.test.functional; import java.io.IOException; +import java.util.concurrent.TimeoutException; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.GetResponse; @@ -150,7 +151,7 @@ public void testExchangeIfUnused() throws IOException { * Because the exchange has been auto-deleted, the bind operation * should fail. */ - public void testExchangeAutoDelete() throws IOException { + public void testExchangeAutoDelete() throws IOException, TimeoutException { doAutoDelete(false, 1); } @@ -161,7 +162,7 @@ public void testExchangeAutoDelete() throws IOException { * The difference should be that the original exchange should not * get auto-deleted */ - public void testExchangeAutoDeleteManyBindings() throws IOException { + public void testExchangeAutoDeleteManyBindings() throws IOException, TimeoutException { doAutoDelete(false, 10); } diff --git a/test/src/com/rabbitmq/client/test/functional/BindingLifecycleBase.java b/test/src/com/rabbitmq/client/test/functional/BindingLifecycleBase.java index d16c1a59fb..9fffb5c403 100644 --- a/test/src/com/rabbitmq/client/test/functional/BindingLifecycleBase.java +++ b/test/src/com/rabbitmq/client/test/functional/BindingLifecycleBase.java @@ -21,6 +21,7 @@ import com.rabbitmq.client.GetResponse; import com.rabbitmq.client.QueueingConsumer; import java.io.IOException; +import java.util.concurrent.TimeoutException; /** * This tests whether bindings are created and nuked properly. @@ -57,7 +58,7 @@ protected void deleteExchangeAndQueue(Binding binding) throws IOException { channel.exchangeDelete(binding.x); } - protected void doAutoDelete(boolean durable, int queues) throws IOException { + protected void doAutoDelete(boolean durable, int queues) throws IOException, TimeoutException { String[] queueNames = null; Binding binding = Binding.randomBinding(); channel.exchangeDeclare(binding.x, "direct", durable, true, null); @@ -109,7 +110,7 @@ protected void doAutoDelete(boolean durable, int queues) throws IOException { } @Override - protected void restart() throws IOException { + protected void restart() throws IOException, TimeoutException { } protected void sendRoutable(Binding binding) throws IOException { @@ -171,7 +172,7 @@ protected Binding(String q, String x, String k) { * Main difference is restarting the broker to make sure that the * durable queues are blasted away. */ - public void testExchangeAutoDeleteDurable() throws IOException { + public void testExchangeAutoDeleteDurable() throws IOException, TimeoutException { doAutoDelete(true, 1); } @@ -179,7 +180,7 @@ public void testExchangeAutoDeleteDurable() throws IOException { * The same thing as testExchangeAutoDeleteManyBindings, but with * durable queues. */ - public void testExchangeAutoDeleteDurableManyBindings() throws IOException { + public void testExchangeAutoDeleteDurableManyBindings() throws IOException, TimeoutException { doAutoDelete(true, 10); } } diff --git a/test/src/com/rabbitmq/client/test/functional/CcRoutes.java b/test/src/com/rabbitmq/client/test/functional/CcRoutes.java index 6be0bf2ed2..72a7c8cab0 100644 --- a/test/src/com/rabbitmq/client/test/functional/CcRoutes.java +++ b/test/src/com/rabbitmq/client/test/functional/CcRoutes.java @@ -27,6 +27,7 @@ import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.concurrent.TimeoutException; public class CcRoutes extends BrokerTestCase { @@ -38,7 +39,7 @@ public class CcRoutes extends BrokerTestCase { protected List ccList; protected List bccList; - @Override protected void setUp() throws IOException { + @Override protected void setUp() throws IOException, TimeoutException { super.setUp(); propsBuilder = new BasicProperties.Builder(); headers = new HashMap(); @@ -46,7 +47,7 @@ public class CcRoutes extends BrokerTestCase { bccList = new ArrayList(); } - @Override protected void createResources() throws IOException { + @Override protected void createResources() throws IOException, TimeoutException { super.createResources(); for (String q : queues) { channel.queueDeclare(q, false, true, true, null); diff --git a/test/src/com/rabbitmq/client/test/functional/ClusteredTestBase.java b/test/src/com/rabbitmq/client/test/functional/ClusteredTestBase.java index 16309f9092..45d5038941 100644 --- a/test/src/com/rabbitmq/client/test/functional/ClusteredTestBase.java +++ b/test/src/com/rabbitmq/client/test/functional/ClusteredTestBase.java @@ -24,6 +24,7 @@ import com.rabbitmq.tools.Host; import java.io.IOException; +import java.util.concurrent.TimeoutException; /** * Base class for tests which would like a second, clustered node. @@ -52,7 +53,7 @@ public void openChannel() throws IOException { private static boolean nonClusteredWarningPrinted; @Override - public void openConnection() throws IOException { + public void openConnection() throws IOException, TimeoutException { super.openConnection(); if (clusteredConnection == null) { try { diff --git a/test/src/com/rabbitmq/client/test/functional/Confirm.java b/test/src/com/rabbitmq/client/test/functional/Confirm.java index 41def19920..e1fe0ecd6a 100644 --- a/test/src/com/rabbitmq/client/test/functional/Confirm.java +++ b/test/src/com/rabbitmq/client/test/functional/Confirm.java @@ -40,7 +40,7 @@ public class Confirm extends BrokerTestCase private static final String TTL_ARG = "x-message-ttl"; @Override - protected void setUp() throws IOException { + protected void setUp() throws IOException, TimeoutException { super.setUp(); channel.confirmSelect(); channel.queueDeclare("confirm-test", true, true, false, null); diff --git a/test/src/com/rabbitmq/client/test/functional/ConnectionOpen.java b/test/src/com/rabbitmq/client/test/functional/ConnectionOpen.java index 8cbb901bb1..df9808f0f4 100644 --- a/test/src/com/rabbitmq/client/test/functional/ConnectionOpen.java +++ b/test/src/com/rabbitmq/client/test/functional/ConnectionOpen.java @@ -20,6 +20,7 @@ import java.io.IOException; import java.io.DataInputStream; import java.net.Socket; +import java.util.concurrent.TimeoutException; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.MalformedFrameException; @@ -84,7 +85,7 @@ public void testCrazyProtocolHeader() throws IOException { } } - public void testFrameMaxLessThanFrameMinSize() throws IOException { + public void testFrameMaxLessThanFrameMinSize() throws IOException, TimeoutException { ConnectionFactory factory = new ConnectionFactory(); factory.setRequestedFrameMax(100); try { diff --git a/test/src/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/test/src/com/rabbitmq/client/test/functional/ConnectionRecovery.java index d45ad6cc0b..c310c81c1b 100644 --- a/test/src/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/test/src/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -35,7 +35,8 @@ public void testConnectionRecoveryWithServerRestart() throws IOException, Interr assertTrue(connection.isOpen()); } - public void testConnectionRecoveryWithMultipleAddresses() throws IOException, InterruptedException { + public void testConnectionRecoveryWithMultipleAddresses() + throws IOException, InterruptedException, TimeoutException { final Address[] addresses = {new Address("127.0.0.1"), new Address("127.0.0.1", 5672)}; AutorecoveringConnection c = newRecoveringConnection(addresses); try { @@ -48,7 +49,8 @@ public void testConnectionRecoveryWithMultipleAddresses() throws IOException, In } - public void testConnectionRecoveryWithDisabledTopologyRecovery() throws IOException, InterruptedException { + public void testConnectionRecoveryWithDisabledTopologyRecovery() + throws IOException, InterruptedException, TimeoutException { AutorecoveringConnection c = newRecoveringConnection(true); Channel ch = c.createChannel(); String q = "java-client.test.recovery.q2"; @@ -550,7 +552,7 @@ public void handleRecovery(Recoverable recoverable) { wait(latch); } - public void testBasicAckAfterChannelRecovery() throws IOException, InterruptedException { + public void testBasicAckAfterChannelRecovery() throws IOException, InterruptedException, TimeoutException { final AtomicInteger consumed = new AtomicInteger(0); int n = 5; final CountDownLatch latch = new CountDownLatch(n); @@ -697,16 +699,19 @@ protected ConnectionFactory newConnectionFactory() { return buildConnectionFactoryWithRecoveryEnabled(false); } - private AutorecoveringConnection newRecoveringConnection(boolean disableTopologyRecovery) throws IOException { + private AutorecoveringConnection newRecoveringConnection(boolean disableTopologyRecovery) + throws IOException, TimeoutException { ConnectionFactory cf = buildConnectionFactoryWithRecoveryEnabled(disableTopologyRecovery); return (AutorecoveringConnection) cf.newConnection(); } - private AutorecoveringConnection newRecoveringConnection(Address[] addresses) throws IOException { + private AutorecoveringConnection newRecoveringConnection(Address[] addresses) + throws IOException, TimeoutException { return newRecoveringConnection(false, addresses); } - private AutorecoveringConnection newRecoveringConnection(boolean disableTopologyRecovery, Address[] addresses) throws IOException { + private AutorecoveringConnection newRecoveringConnection(boolean disableTopologyRecovery, Address[] addresses) + throws IOException, TimeoutException { ConnectionFactory cf = buildConnectionFactoryWithRecoveryEnabled(disableTopologyRecovery); return (AutorecoveringConnection) cf.newConnection(addresses); } diff --git a/test/src/com/rabbitmq/client/test/functional/ExceptionHandling.java b/test/src/com/rabbitmq/client/test/functional/ExceptionHandling.java index d723415c79..5d23562e55 100644 --- a/test/src/com/rabbitmq/client/test/functional/ExceptionHandling.java +++ b/test/src/com/rabbitmq/client/test/functional/ExceptionHandling.java @@ -14,6 +14,7 @@ import java.io.IOException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; public class ExceptionHandling extends TestCase { private ConnectionFactory newConnectionFactory(ExceptionHandler eh) { @@ -22,7 +23,7 @@ private ConnectionFactory newConnectionFactory(ExceptionHandler eh) { return cf; } - public void testHandleConsumerException() throws IOException, InterruptedException { + public void testHandleConsumerException() throws IOException, InterruptedException, TimeoutException { final CountDownLatch latch = new CountDownLatch(1); final DefaultExceptionHandler eh = new DefaultExceptionHandler() { @Override @@ -38,7 +39,8 @@ public void handleConsumerException(Channel channel, Throwable exception, Consum String q = ch.queueDeclare().getQueue(); ch.basicConsume(q, new DefaultConsumer(ch) { @Override - public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { + public void handleDelivery(String consumerTag, Envelope envelope, + AMQP.BasicProperties properties, byte[] body) throws IOException { throw new RuntimeException("oops"); } }); diff --git a/test/src/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java b/test/src/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java index c361b2a2dd..2fdd2b552b 100644 --- a/test/src/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java +++ b/test/src/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java @@ -18,6 +18,7 @@ package com.rabbitmq.client.test.functional; import java.io.IOException; +import java.util.concurrent.TimeoutException; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.test.BrokerTestCase; @@ -29,8 +30,7 @@ public class ExchangeDeleteIfUnused extends BrokerTestCase { private final static String ROUTING_KEY = "something"; protected void createResources() - throws IOException - { + throws IOException, TimeoutException { super.createResources(); channel.exchangeDeclare(EXCHANGE_NAME, "direct"); String queueName = channel.queueDeclare().getQueue(); diff --git a/test/src/com/rabbitmq/client/test/functional/FrameMax.java b/test/src/com/rabbitmq/client/test/functional/FrameMax.java index b2e13d840f..f1b88a05ba 100644 --- a/test/src/com/rabbitmq/client/test/functional/FrameMax.java +++ b/test/src/com/rabbitmq/client/test/functional/FrameMax.java @@ -23,6 +23,7 @@ import java.io.IOException; import java.net.Socket; import java.util.concurrent.ExecutorService; +import java.util.concurrent.TimeoutException; import com.rabbitmq.client.Address; import com.rabbitmq.client.AMQP; @@ -72,8 +73,7 @@ public void testFrameSizes() /* server should reject frames larger than AMQP.FRAME_MIN_SIZE * during connection negotiation */ public void testRejectLargeFramesDuringConnectionNegotiation() - throws IOException - { + throws IOException, TimeoutException { ConnectionFactory cf = new ConnectionFactory(); cf.getClientProperties().put("too_long", LongStringHelper.asLongString(new byte[AMQP.FRAME_MIN_SIZE])); try { @@ -86,8 +86,7 @@ public void testRejectLargeFramesDuringConnectionNegotiation() /* server should reject frames larger than the negotiated frame * size */ public void testRejectExceedingFrameMax() - throws IOException - { + throws IOException, TimeoutException { closeChannel(); closeConnection(); ConnectionFactory cf = new GenerousConnectionFactory(); @@ -149,8 +148,7 @@ public GenerousAMQConnection(ConnectionFactory factory, private static class GenerousConnectionFactory extends ConnectionFactory { @Override public Connection newConnection(ExecutorService executor, Address[] addrs) - throws IOException - { + throws IOException, TimeoutException { IOException lastException = null; for (Address addr : addrs) { try { diff --git a/test/src/com/rabbitmq/client/test/functional/QosTests.java b/test/src/com/rabbitmq/client/test/functional/QosTests.java index 2e5e65d47d..6ee332d062 100644 --- a/test/src/com/rabbitmq/client/test/functional/QosTests.java +++ b/test/src/com/rabbitmq/client/test/functional/QosTests.java @@ -26,6 +26,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.concurrent.TimeoutException; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; @@ -38,8 +39,7 @@ public class QosTests extends BrokerTestCase { protected void setUp() - throws IOException - { + throws IOException, TimeoutException { openConnection(); openChannel(); } diff --git a/test/src/com/rabbitmq/client/test/functional/QueueExclusivity.java b/test/src/com/rabbitmq/client/test/functional/QueueExclusivity.java index 63e5ef7edc..2f0c07c00d 100644 --- a/test/src/com/rabbitmq/client/test/functional/QueueExclusivity.java +++ b/test/src/com/rabbitmq/client/test/functional/QueueExclusivity.java @@ -19,6 +19,7 @@ import java.io.IOException; import java.util.HashMap; +import java.util.concurrent.TimeoutException; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; @@ -35,7 +36,7 @@ public class QueueExclusivity extends BrokerTestCase { public Channel altChannel; final String q = "exclusiveQ"; - protected void createResources() throws IOException { + protected void createResources() throws IOException, TimeoutException { altConnection = connectionFactory.newConnection(); altChannel = altConnection.createChannel(); altChannel.queueDeclare(q, diff --git a/test/src/com/rabbitmq/client/test/functional/QueueLifecycle.java b/test/src/com/rabbitmq/client/test/functional/QueueLifecycle.java index 5e71c8fe8e..43613e64b1 100644 --- a/test/src/com/rabbitmq/client/test/functional/QueueLifecycle.java +++ b/test/src/com/rabbitmq/client/test/functional/QueueLifecycle.java @@ -21,6 +21,7 @@ import java.util.Arrays; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.TimeoutException; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.QueueingConsumer; @@ -147,7 +148,7 @@ public void testExclusiveNotAutoDelete() throws IOException { verifyQueueExists(name); } - public void testExclusiveGoesWithConnection() throws IOException { + public void testExclusiveGoesWithConnection() throws IOException, TimeoutException { String name = "exclusivequeue2"; channel.queueDeclare(name, false, true, false, null); // now it's there diff --git a/test/src/com/rabbitmq/client/test/functional/RequeueOnClose.java b/test/src/com/rabbitmq/client/test/functional/RequeueOnClose.java index 91f33d64af..6090c0f4bc 100644 --- a/test/src/com/rabbitmq/client/test/functional/RequeueOnClose.java +++ b/test/src/com/rabbitmq/client/test/functional/RequeueOnClose.java @@ -19,6 +19,7 @@ import com.rabbitmq.client.test.BrokerTestCase; import java.io.IOException; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeoutException; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; @@ -38,7 +39,7 @@ public abstract class RequeueOnClose private static final String Q = "RequeueOnClose"; private static final int MESSAGE_COUNT = 2000; - protected abstract void open() throws IOException; + protected abstract void open() throws IOException, TimeoutException; protected abstract void close() throws IOException; @@ -70,8 +71,7 @@ private GetResponse getMessage() } private void publishAndGet(int count, boolean doAck) - throws IOException, InterruptedException - { + throws IOException, InterruptedException, TimeoutException { openConnection(); for (int repeat = 0; repeat < count; repeat++) { open(); @@ -128,8 +128,7 @@ public void testRequeueingConsumer() throws Exception } private void publishLotsAndGet() - throws IOException, InterruptedException, ShutdownSignalException - { + throws IOException, InterruptedException, ShutdownSignalException, TimeoutException { openConnection(); open(); channel.queueDeclare(Q, false, false, false, null); @@ -211,8 +210,7 @@ public void testRequeueInFlightConsumerAckNoCancel() throws Exception private static final int MESSAGES_TO_CONSUME = 20; private void publishLotsAndConsumeSome(boolean ack, boolean cancelBeforeFinish) - throws IOException, InterruptedException, ShutdownSignalException - { + throws IOException, InterruptedException, ShutdownSignalException, TimeoutException { openConnection(); open(); channel.queueDeclare(Q, false, false, false, null); diff --git a/test/src/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java b/test/src/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java index 5d61fb0f2d..8b46908a35 100644 --- a/test/src/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java +++ b/test/src/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java @@ -18,12 +18,12 @@ package com.rabbitmq.client.test.functional; import java.io.IOException; +import java.util.concurrent.TimeoutException; public class RequeueOnConnectionClose extends RequeueOnClose { - protected void open() throws IOException - { + protected void open() throws IOException, TimeoutException { openConnection(); openChannel(); } diff --git a/test/src/com/rabbitmq/client/test/functional/SaslMechanisms.java b/test/src/com/rabbitmq/client/test/functional/SaslMechanisms.java index 3f9054352c..77cb0861c8 100644 --- a/test/src/com/rabbitmq/client/test/functional/SaslMechanisms.java +++ b/test/src/com/rabbitmq/client/test/functional/SaslMechanisms.java @@ -30,6 +30,7 @@ import java.io.IOException; import java.util.Arrays; import java.util.Map; +import java.util.concurrent.TimeoutException; public class SaslMechanisms extends BrokerTestCase { private String[] mechanisms; @@ -71,19 +72,19 @@ public SaslMechanism getSaslMechanism(String[] mechanisms) { // TODO test gibberish examples. ATM the server is not very robust. - public void testPlainLogin() throws IOException { + public void testPlainLogin() throws IOException, TimeoutException { loginOk("PLAIN", new byte[][] {"\0guest\0guest".getBytes()} ); loginBad("PLAIN", new byte[][] {"\0guest\0wrong".getBytes()} ); } - public void testAMQPlainLogin() throws IOException { + public void testAMQPlainLogin() throws IOException, TimeoutException { // guest / guest loginOk("AMQPLAIN", new byte[][] {{5,76,79,71,73,78,83,0,0,0,5,103,117,101,115,116,8,80,65,83,83,87,79,82,68,83,0,0,0,5,103,117,101,115,116}} ); // guest / wrong loginBad("AMQPLAIN", new byte[][] {{5,76,79,71,73,78,83,0,0,0,5,103,117,101,115,116,8,80,65,83,83,87,79,82,68,83,0,0,0,5,119,114,111,110,103}} ); } - public void testCRLogin() throws IOException { + public void testCRLogin() throws IOException, TimeoutException { // Make sure mechanisms is populated loginOk("PLAIN", new byte[][] {"\0guest\0guest".getBytes()} ); @@ -94,15 +95,15 @@ public void testCRLogin() throws IOException { } } - public void testConnectionCloseAuthFailureUsername() throws IOException { + public void testConnectionCloseAuthFailureUsername() throws IOException, TimeoutException { connectionCloseAuthFailure("incorrect-username", "incorrect-password"); } - public void testConnectionCloseAuthFailurePassword() throws IOException { + public void testConnectionCloseAuthFailurePassword() throws IOException, TimeoutException { connectionCloseAuthFailure(connectionFactory.getUsername(), "incorrect-password"); } - public void connectionCloseAuthFailure(String username, String password) throws IOException { + public void connectionCloseAuthFailure(String username, String password) throws IOException, TimeoutException { String failDetail = "for username " + username + " and password " + password; try { Connection conn = connectionWithoutCapabilities(username, password); @@ -117,7 +118,8 @@ public void connectionCloseAuthFailure(String username, String password) throws // start a connection without capabilities, causing authentication failures // to be reported by the broker by closing the connection - private Connection connectionWithoutCapabilities(String username, String password) throws IOException { + private Connection connectionWithoutCapabilities(String username, String password) + throws IOException, TimeoutException { ConnectionFactory customFactory = connectionFactory.clone(); customFactory.setUsername(username); customFactory.setPassword(password); @@ -127,14 +129,14 @@ private Connection connectionWithoutCapabilities(String username, String passwor return customFactory.newConnection(); } - private void loginOk(String name, byte[][] responses) throws IOException { + private void loginOk(String name, byte[][] responses) throws IOException, TimeoutException { ConnectionFactory factory = new ConnectionFactory(); factory.setSaslConfig(new Config(name, responses)); Connection connection = factory.newConnection(); connection.close(); } - private void loginBad(String name, byte[][] responses) throws IOException { + private void loginBad(String name, byte[][] responses) throws IOException, TimeoutException { try { loginOk(name, responses); fail("Login succeeded!"); diff --git a/test/src/com/rabbitmq/client/test/functional/Transactions.java b/test/src/com/rabbitmq/client/test/functional/Transactions.java index 5a352844c4..691cd168b2 100644 --- a/test/src/com/rabbitmq/client/test/functional/Transactions.java +++ b/test/src/com/rabbitmq/client/test/functional/Transactions.java @@ -20,6 +20,7 @@ import com.rabbitmq.client.AMQP; import com.rabbitmq.client.test.BrokerTestCase; import java.io.IOException; +import java.util.concurrent.TimeoutException; import com.rabbitmq.client.GetResponse; @@ -323,8 +324,7 @@ public void testRedeliverAckedUncommitted() } public void testCommitWithDeletedQueue() - throws IOException - { + throws IOException, TimeoutException { txSelect(); basicPublish(); releaseResources(); diff --git a/test/src/com/rabbitmq/client/test/functional/UserIDHeader.java b/test/src/com/rabbitmq/client/test/functional/UserIDHeader.java index 3dc05c0463..213f149940 100644 --- a/test/src/com/rabbitmq/client/test/functional/UserIDHeader.java +++ b/test/src/com/rabbitmq/client/test/functional/UserIDHeader.java @@ -22,6 +22,7 @@ import com.rabbitmq.tools.Host; import java.io.IOException; +import java.util.concurrent.TimeoutException; public class UserIDHeader extends BrokerTestCase { private static final AMQP.BasicProperties GOOD = new AMQP.BasicProperties.Builder().userId("guest").build(); @@ -42,7 +43,7 @@ public void testInvalidUserId() { } } - public void testImpersonatedUserId() throws IOException { + public void testImpersonatedUserId() throws IOException, TimeoutException { Host.rabbitmqctl("set_user_tags guest administrator impersonator"); connection = null; channel = null; diff --git a/test/src/com/rabbitmq/client/test/performance/QosScaling.java b/test/src/com/rabbitmq/client/test/performance/QosScaling.java index 9f959176ba..d3b820138b 100644 --- a/test/src/com/rabbitmq/client/test/performance/QosScaling.java +++ b/test/src/com/rabbitmq/client/test/performance/QosScaling.java @@ -29,6 +29,7 @@ import java.io.IOException; import java.util.List; import java.util.ArrayList; +import java.util.concurrent.TimeoutException; public class QosScaling { @@ -121,7 +122,7 @@ protected long drain(QueueingConsumer c) throws IOException { return finish - start; } - public long run() throws IOException { + public long run() throws IOException, TimeoutException { connectionFactory.setHost(params.host); connectionFactory.setPort(params.port); connection = connectionFactory.newConnection(); diff --git a/test/src/com/rabbitmq/client/test/performance/StressManagement.java b/test/src/com/rabbitmq/client/test/performance/StressManagement.java index a0656b073d..193464d28b 100644 --- a/test/src/com/rabbitmq/client/test/performance/StressManagement.java +++ b/test/src/com/rabbitmq/client/test/performance/StressManagement.java @@ -25,6 +25,7 @@ import org.apache.commons.cli.Option; import java.io.IOException; +import java.util.concurrent.TimeoutException; public class StressManagement { protected static class Parameters { @@ -69,7 +70,7 @@ public StressManagement(Parameters p) { params = p; } - public long run() throws IOException { + public long run() throws IOException, TimeoutException { connectionFactory.setHost(params.host); connectionFactory.setPort(params.port); connection = connectionFactory.newConnection(); @@ -97,7 +98,7 @@ public long run() throws IOException { try { Thread.sleep(10); } catch (InterruptedException e) { - + Thread.currentThread().interrupt(); } } } diff --git a/test/src/com/rabbitmq/client/test/server/AbsentQueue.java b/test/src/com/rabbitmq/client/test/server/AbsentQueue.java index 7941db0483..47e256201c 100644 --- a/test/src/com/rabbitmq/client/test/server/AbsentQueue.java +++ b/test/src/com/rabbitmq/client/test/server/AbsentQueue.java @@ -22,6 +22,7 @@ import com.rabbitmq.tools.Host; import java.io.IOException; +import java.util.concurrent.TimeoutException; /** * This tests whether 'absent' queues - durable queues whose home node @@ -31,13 +32,13 @@ public class AbsentQueue extends ClusteredTestBase { private static final String Q = "absent-queue"; - @Override protected void setUp() throws IOException { + @Override protected void setUp() throws IOException, TimeoutException { super.setUp(); if (clusteredConnection != null) stopSecondary(); } - @Override protected void tearDown() throws IOException { + @Override protected void tearDown() throws IOException, TimeoutException { if (clusteredConnection != null) startSecondary(); super.tearDown(); diff --git a/test/src/com/rabbitmq/client/test/server/BlockedConnection.java b/test/src/com/rabbitmq/client/test/server/BlockedConnection.java index 0085e6d9db..b0779f31b7 100644 --- a/test/src/com/rabbitmq/client/test/server/BlockedConnection.java +++ b/test/src/com/rabbitmq/client/test/server/BlockedConnection.java @@ -28,6 +28,7 @@ import java.io.IOException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; public class BlockedConnection extends BrokerTestCase { protected void releaseResources() throws IOException { @@ -57,7 +58,7 @@ public void testInitialBlock() throws Exception { assertTrue(latch.await(10, TimeUnit.SECONDS)); } - private Connection connection(final CountDownLatch latch) throws IOException { + private Connection connection(final CountDownLatch latch) throws IOException, TimeoutException { ConnectionFactory factory = new ConnectionFactory(); Connection connection = factory.newConnection(); connection.addBlockedListener(new BlockedListener() { diff --git a/test/src/com/rabbitmq/client/test/server/Bug19219Test.java b/test/src/com/rabbitmq/client/test/server/Bug19219Test.java index 9d25fda6fd..895096663e 100644 --- a/test/src/com/rabbitmq/client/test/server/Bug19219Test.java +++ b/test/src/com/rabbitmq/client/test/server/Bug19219Test.java @@ -19,6 +19,7 @@ import java.io.IOException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeoutException; import junit.framework.TestSuite; @@ -89,6 +90,8 @@ public void run() { startPublisher(); } catch (IOException e) { } catch (InterruptedException e) { + } catch (TimeoutException e) { + e.printStackTrace(); } } }; @@ -126,7 +129,7 @@ public void run() { } } - private void startPublisher() throws IOException, InterruptedException { + private void startPublisher() throws IOException, InterruptedException, TimeoutException { final Connection conn = connectionFactory.newConnection(); final Channel pubCh = conn.createChannel(); diff --git a/test/src/com/rabbitmq/client/test/server/DurableBindingLifecycle.java b/test/src/com/rabbitmq/client/test/server/DurableBindingLifecycle.java index c650775b7b..0944edccf8 100644 --- a/test/src/com/rabbitmq/client/test/server/DurableBindingLifecycle.java +++ b/test/src/com/rabbitmq/client/test/server/DurableBindingLifecycle.java @@ -24,6 +24,7 @@ import com.rabbitmq.tools.Host; import java.io.IOException; +import java.util.concurrent.TimeoutException; /** * This tests whether bindings are created and nuked properly. @@ -36,7 +37,7 @@ */ public class DurableBindingLifecycle extends BindingLifecycleBase { @Override - protected void restart() throws IOException { + protected void restart() throws IOException, TimeoutException { if (clusteredConnection != null) { clusteredConnection.abort(); clusteredConnection = null; @@ -49,7 +50,7 @@ protected void restart() throws IOException { restartPrimary(); } - private void restartPrimary() throws IOException { + private void restartPrimary() throws IOException, TimeoutException { tearDown(); bareRestart(); setUp(); @@ -58,7 +59,7 @@ private void restartPrimary() throws IOException { /** * Tests whether durable bindings are correctly recovered. */ - public void testDurableBindingRecovery() throws IOException { + public void testDurableBindingRecovery() throws IOException, TimeoutException { declareDurableTopicExchange(X); declareAndBindDurableQueue(Q, X, K); @@ -91,7 +92,7 @@ public void testDurableBindingRecovery() throws IOException { * main difference is that the broker has to be restarted to * verify that the durable routes have been turfed. */ - public void testDurableBindingsDeletion() throws IOException { + public void testDurableBindingsDeletion() throws IOException, TimeoutException { declareDurableTopicExchange(X); declareAndBindDurableQueue(Q, X, K); @@ -120,7 +121,7 @@ public void testDurableBindingsDeletion() throws IOException { * The idea is to create a durable queue, nuke the server and then * publish a message to it using the queue name as a routing key */ - public void testDefaultBindingRecovery() throws IOException { + public void testDefaultBindingRecovery() throws IOException, TimeoutException { declareDurableQueue(Q); restart(); @@ -138,7 +139,7 @@ public void testDefaultBindingRecovery() throws IOException { * queue and the durable queue is on a cluster node that restarts, * we do not lose the binding. See bug 24009. */ - public void testTransientExchangeDurableQueue() throws IOException { + public void testTransientExchangeDurableQueue() throws IOException, TimeoutException { // This test depends on the second node in the cluster to keep // the transient X alive if (clusteredConnection != null) { diff --git a/test/src/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java b/test/src/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java index 4eb20b338a..af3b954803 100644 --- a/test/src/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java +++ b/test/src/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java @@ -18,6 +18,7 @@ package com.rabbitmq.client.test.server; import java.io.IOException; +import java.util.concurrent.TimeoutException; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; @@ -48,7 +49,7 @@ public void testConnectionQueueSameNode() throws Exception { verifyQueueMissing(channel, "scenario1"); } - private void restartPrimaryAbruptly() throws IOException { + private void restartPrimaryAbruptly() throws IOException, TimeoutException { connection = null; channel = null; bareRestart(); diff --git a/test/src/com/rabbitmq/client/test/server/Firehose.java b/test/src/com/rabbitmq/client/test/server/Firehose.java index d7cd1c4dda..c6b3b0f869 100644 --- a/test/src/com/rabbitmq/client/test/server/Firehose.java +++ b/test/src/com/rabbitmq/client/test/server/Firehose.java @@ -7,13 +7,14 @@ import java.io.IOException; import java.util.List; import java.util.Map; +import java.util.concurrent.TimeoutException; public class Firehose extends BrokerTestCase { private String q; private String firehose; @Override - protected void createResources() throws IOException { + protected void createResources() throws IOException, TimeoutException { super.createResources(); channel.exchangeDeclare("test", "fanout", false, true, null); q = channel.queueDeclare().getQueue(); diff --git a/test/src/com/rabbitmq/client/test/server/LoopbackUsers.java b/test/src/com/rabbitmq/client/test/server/LoopbackUsers.java index 55ec3c62e0..2ded79cf77 100644 --- a/test/src/com/rabbitmq/client/test/server/LoopbackUsers.java +++ b/test/src/com/rabbitmq/client/test/server/LoopbackUsers.java @@ -11,6 +11,7 @@ import java.net.NetworkInterface; import java.net.SocketException; import java.util.Enumeration; +import java.util.concurrent.TimeoutException; public class LoopbackUsers extends TestCase { @Override @@ -24,7 +25,7 @@ protected void tearDown() throws IOException { Host.rabbitmqctl("delete_user test"); } - public void testLoopback() throws IOException { + public void testLoopback() throws IOException, TimeoutException { String addr = findRealIPAddress().getHostAddress(); assertGuestFail(addr); Host.rabbitmqctl("eval 'application:set_env(rabbit, loopback_users, []).'"); @@ -33,25 +34,25 @@ public void testLoopback() throws IOException { assertGuestFail(addr); } - private void assertGuestSucceed(String addr) throws IOException { + private void assertGuestSucceed(String addr) throws IOException, TimeoutException { succeedConnect("guest", addr); succeedConnect("guest", "localhost"); succeedConnect("test", addr); succeedConnect("test", "localhost"); } - private void assertGuestFail(String addr) throws IOException { + private void assertGuestFail(String addr) throws IOException, TimeoutException { failConnect("guest", addr); succeedConnect("guest", "localhost"); succeedConnect("test", addr); succeedConnect("test", "localhost"); } - private void succeedConnect(String name, String addr) throws IOException { + private void succeedConnect(String name, String addr) throws IOException, TimeoutException { getFactory(name, addr).newConnection().close(); } - private void failConnect(String name, String addr) throws IOException { + private void failConnect(String name, String addr) throws IOException, TimeoutException { try { getFactory(name, addr).newConnection(); fail(); diff --git a/test/src/com/rabbitmq/client/test/server/MemoryAlarms.java b/test/src/com/rabbitmq/client/test/server/MemoryAlarms.java index cc04174c2f..6822f65f7a 100644 --- a/test/src/com/rabbitmq/client/test/server/MemoryAlarms.java +++ b/test/src/com/rabbitmq/client/test/server/MemoryAlarms.java @@ -17,6 +17,7 @@ package com.rabbitmq.client.test.server; import java.io.IOException; +import java.util.concurrent.TimeoutException; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; @@ -32,7 +33,7 @@ public class MemoryAlarms extends BrokerTestCase { private Channel channel2; @Override - protected void setUp() throws IOException { + protected void setUp() throws IOException, TimeoutException { connectionFactory.setRequestedHeartbeat(1); super.setUp(); if (connection2 == null) { @@ -42,7 +43,7 @@ protected void setUp() throws IOException { } @Override - protected void tearDown() throws IOException { + protected void tearDown() throws IOException, TimeoutException { if (channel2 != null) { channel2.abort(); channel2 = null; diff --git a/test/src/com/rabbitmq/client/test/server/Permissions.java b/test/src/com/rabbitmq/client/test/server/Permissions.java index 5e32c36d22..ca7a4f568f 100644 --- a/test/src/com/rabbitmq/client/test/server/Permissions.java +++ b/test/src/com/rabbitmq/client/test/server/Permissions.java @@ -23,6 +23,7 @@ import java.io.IOException; import java.util.Map; import java.util.HashMap; +import java.util.concurrent.TimeoutException; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; @@ -47,16 +48,14 @@ public Permissions() } protected void setUp() - throws IOException - { + throws IOException, TimeoutException { deleteRestrictedAccount(); addRestrictedAccount(); super.setUp(); } protected void tearDown() - throws IOException - { + throws IOException, TimeoutException { super.tearDown(); deleteRestrictedAccount(); } @@ -82,8 +81,7 @@ protected void deleteRestrictedAccount() } protected void createResources() - throws IOException - { + throws IOException, TimeoutException { ConnectionFactory factory = new ConnectionFactory(); factory.setUsername("testadmin"); factory.setPassword("test"); @@ -117,8 +115,7 @@ protected void withNames(WithName action) action.with("none"); } - public void testAuth() - { + public void testAuth() throws TimeoutException { ConnectionFactory unAuthFactory = new ConnectionFactory(); unAuthFactory.setUsername("test"); unAuthFactory.setPassword("tset"); diff --git a/test/src/com/rabbitmq/examples/StressPersister.java b/test/src/com/rabbitmq/examples/StressPersister.java index 613b461699..0de1861410 100644 --- a/test/src/com/rabbitmq/examples/StressPersister.java +++ b/test/src/com/rabbitmq/examples/StressPersister.java @@ -23,6 +23,7 @@ import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.TimeoutException; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; @@ -116,11 +117,11 @@ public void configure(String[] args) connectionFactory.setUri(uri); } - public Connection newConnection() throws IOException { + public Connection newConnection() throws IOException, TimeoutException { return connectionFactory.newConnection(); } - public void run() throws IOException, InterruptedException { + public void run() throws IOException, InterruptedException, TimeoutException { topStartTime = System.currentTimeMillis(); String logFileName = String.format("stress-persister-b%08d-B%010d-c%08d-s%06d-%s.out", backlogSize, bodySize, repeatCount, sampleGranularity, commentText); @@ -147,7 +148,8 @@ public void redeclare(String q, Channel chan) throws IOException { // of indication back from the server that it's caught up with us } - public void publishOneInOneOutReceive(int backlogSize, int bodySize, int repeatCount, int sampleGranularity) throws IOException, InterruptedException { + public void publishOneInOneOutReceive(int backlogSize, int bodySize, int repeatCount, int sampleGranularity) + throws IOException, InterruptedException, TimeoutException { String q = "test"; BasicProperties props = MessageProperties.MINIMAL_PERSISTENT_BASIC; Connection conn = newConnection(); diff --git a/test/src/com/rabbitmq/examples/TestMain.java b/test/src/com/rabbitmq/examples/TestMain.java index ad5668e3ac..c80b0b271c 100644 --- a/test/src/com/rabbitmq/examples/TestMain.java +++ b/test/src/com/rabbitmq/examples/TestMain.java @@ -22,6 +22,7 @@ import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.net.URISyntaxException; +import java.util.concurrent.TimeoutException; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Address; @@ -115,8 +116,7 @@ public FrameHandlerFactory createFrameHandlerFactory() } public static void runConnectionNegotiationTest(final String uri) - throws IOException, URISyntaxException, NoSuchAlgorithmException, KeyManagementException - { + throws IOException, URISyntaxException, NoSuchAlgorithmException, KeyManagementException, TimeoutException { Connection conn; @@ -124,7 +124,7 @@ public static void runConnectionNegotiationTest(final String uri) conn = new TestConnectionFactory(0, 1, uri).newConnection(); conn.close(); throw new RuntimeException("expected socket close"); - } catch (IOException e) {} + } catch (IOException ignored) {} ConnectionFactory factory; factory = new ConnectionFactory(); @@ -135,7 +135,7 @@ public static void runConnectionNegotiationTest(final String uri) conn = factory.newConnection(); conn.close(); throw new RuntimeException("expected socket close"); - } catch (IOException e) {} + } catch (IOException ignored) {} factory = new ConnectionFactory(); factory.setRequestedChannelMax(10); @@ -174,8 +174,7 @@ private static void checkNegotiatedMaxValue(String name, } public static void runConnectionShutdownTests(final String uri) - throws IOException, URISyntaxException, NoSuchAlgorithmException, KeyManagementException - { + throws IOException, URISyntaxException, NoSuchAlgorithmException, KeyManagementException, TimeoutException { Connection conn; Channel ch; // Test what happens when a connection is shut down w/o first @@ -189,7 +188,7 @@ public static void runConnectionShutdownTests(final String uri) try { ch.exchangeDeclare("mumble", "invalid"); throw new RuntimeException("expected shutdown"); - } catch (IOException e) { + } catch (IOException ignored) { } // Test what happens when we just kill the connection conn = new ConnectionFactory(){{setUri(uri);}}.newConnection(); @@ -198,8 +197,7 @@ public static void runConnectionShutdownTests(final String uri) } public static void runProducerConsumerTest(String uri, int commitEvery) - throws IOException, URISyntaxException, NoSuchAlgorithmException, KeyManagementException - { + throws IOException, URISyntaxException, NoSuchAlgorithmException, KeyManagementException, TimeoutException { ConnectionFactory cfconnp = new ConnectionFactory(); cfconnp.setUri(uri); Connection connp = cfconnp.newConnection(); @@ -215,7 +213,9 @@ public static void runProducerConsumerTest(String uri, int commitEvery) public static void sleep(int ms) { try { Thread.sleep(ms); - } catch (InterruptedException _e) { } // ignore + } catch (InterruptedException _e) { + Thread.currentThread().interrupt(); + } } private final Connection _connection; diff --git a/test/src/com/rabbitmq/examples/perf/MulticastSet.java b/test/src/com/rabbitmq/examples/perf/MulticastSet.java index 13a8fd2d15..4a7338192f 100644 --- a/test/src/com/rabbitmq/examples/perf/MulticastSet.java +++ b/test/src/com/rabbitmq/examples/perf/MulticastSet.java @@ -22,6 +22,7 @@ import java.io.IOException; import java.util.UUID; +import java.util.concurrent.TimeoutException; public class MulticastSet { private final String id; @@ -41,11 +42,11 @@ public MulticastSet(Stats stats, ConnectionFactory factory, this.params = params; } - public void run() throws IOException, InterruptedException { + public void run() throws IOException, InterruptedException, TimeoutException { run(false); } - public void run(boolean announceStartup) throws IOException, InterruptedException { + public void run(boolean announceStartup) throws IOException, InterruptedException, TimeoutException { Thread[] consumerThreads = new Thread[params.getConsumerCount()]; Connection[] consumerConnections = new Connection[consumerThreads.length]; for (int i = 0; i < consumerConnections.length; i++) { diff --git a/test/src/com/rabbitmq/examples/perf/SimpleScenario.java b/test/src/com/rabbitmq/examples/perf/SimpleScenario.java index 70d4145e48..31e09cf79f 100644 --- a/test/src/com/rabbitmq/examples/perf/SimpleScenario.java +++ b/test/src/com/rabbitmq/examples/perf/SimpleScenario.java @@ -19,6 +19,7 @@ import com.rabbitmq.client.ConnectionFactory; import java.io.IOException; +import java.util.concurrent.TimeoutException; public class SimpleScenario implements Scenario { private final String name; @@ -38,7 +39,7 @@ public SimpleScenario(String name, ConnectionFactory factory, long interval, Mul this.interval = interval; } - public void run() throws IOException, InterruptedException { + public void run() throws IOException, InterruptedException, TimeoutException { this.stats = new SimpleScenarioStats(interval); for (MulticastParams p : params) { MulticastSet set = new MulticastSet(stats, factory, p); From 5786af24595a1383da24db9c1a23da3affabb94d Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 15 May 2015 14:53:02 +0300 Subject: [PATCH 0025/2114] Silence deprecation warnings in Channel implementations --- src/com/rabbitmq/client/impl/ChannelN.java | 8 ++++++++ .../client/impl/recovery/AutorecoveringChannel.java | 10 ++++++++++ 2 files changed, 18 insertions(+) diff --git a/src/com/rabbitmq/client/impl/ChannelN.java b/src/com/rabbitmq/client/impl/ChannelN.java index b00c1c403c..b1720cf368 100644 --- a/src/com/rabbitmq/client/impl/ChannelN.java +++ b/src/com/rabbitmq/client/impl/ChannelN.java @@ -137,14 +137,20 @@ public void clearReturnListeners() { returnListeners.clear(); } + @SuppressWarnings("deprecation") + @Deprecated public void addFlowListener(FlowListener listener) { flowListeners.add(listener); } + @SuppressWarnings("deprecation") + @Deprecated public boolean removeFlowListener(FlowListener listener) { return flowListeners.remove(listener); } + @SuppressWarnings("deprecation") + @Deprecated public void clearFlowListeners() { flowListeners.clear(); } @@ -1166,6 +1172,8 @@ public Confirm.SelectOk confirmSelect() } /** Public API - {@inheritDoc} */ + @SuppressWarnings("deprecation") + @Deprecated public boolean flowBlocked() { return _blockContent; } diff --git a/src/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java b/src/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java index 6921f6f4fe..be24390477 100644 --- a/src/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java +++ b/src/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java @@ -73,6 +73,8 @@ public void close(int closeCode, String closeMessage) throws IOException, Timeou } } + @SuppressWarnings("deprecation") + @Deprecated public boolean flowBlocked() { return delegate.flowBlocked(); } @@ -100,16 +102,22 @@ public void clearReturnListeners() { delegate.clearReturnListeners(); } + @SuppressWarnings("deprecation") + @Deprecated public void addFlowListener(FlowListener listener) { this.flowListeners.add(listener); delegate.addFlowListener(listener); } + @SuppressWarnings("deprecation") + @Deprecated public boolean removeFlowListener(FlowListener listener) { this.flowListeners.remove(listener); return delegate.removeFlowListener(listener); } + @SuppressWarnings("deprecation") + @Deprecated public void clearFlowListeners() { this.flowListeners.clear(); delegate.clearFlowListeners(); @@ -497,6 +505,8 @@ private void recoverConfirmListeners() { } } + @Deprecated + @SuppressWarnings("deprecation") private void recoverFlowListeners() { for(FlowListener fl : this.flowListeners) { this.delegate.addFlowListener(fl); From 4f29b1a7613cc301ea94aa3bb136a28076c1cad6 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 15 May 2015 15:16:09 +0300 Subject: [PATCH 0026/2114] Ignore .properties files used by JUnit 3 at runtime --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index b552f873b8..401cc09653 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ /ebin/ /out/ /tmp/ +junit*.properties \ No newline at end of file From c1a66b08e202ffde1a3940ba52e6ebe181a22cd3 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Sun, 24 May 2015 05:25:16 +0300 Subject: [PATCH 0027/2114] (c) year --- LICENSE-MPL-RabbitMQ | 2 +- codegen.py | 4 ++-- src/com/rabbitmq/client/Address.java | 2 +- src/com/rabbitmq/client/AlreadyClosedException.java | 2 +- src/com/rabbitmq/client/AuthenticationFailureException.java | 2 +- src/com/rabbitmq/client/BasicProperties.java | 2 +- src/com/rabbitmq/client/BlockedListener.java | 2 +- src/com/rabbitmq/client/Channel.java | 2 +- src/com/rabbitmq/client/Command.java | 2 +- src/com/rabbitmq/client/ConfirmListener.java | 2 +- src/com/rabbitmq/client/Connection.java | 2 +- src/com/rabbitmq/client/ConnectionFactory.java | 2 +- src/com/rabbitmq/client/Consumer.java | 2 +- src/com/rabbitmq/client/ConsumerCancelledException.java | 2 +- src/com/rabbitmq/client/ContentHeader.java | 2 +- src/com/rabbitmq/client/DefaultConsumer.java | 2 +- src/com/rabbitmq/client/DefaultSaslConfig.java | 2 +- src/com/rabbitmq/client/Envelope.java | 2 +- src/com/rabbitmq/client/ExceptionHandler.java | 2 +- src/com/rabbitmq/client/FlowListener.java | 2 +- src/com/rabbitmq/client/GetResponse.java | 2 +- src/com/rabbitmq/client/JDKSaslConfig.java | 2 +- src/com/rabbitmq/client/LongString.java | 2 +- src/com/rabbitmq/client/MalformedFrameException.java | 2 +- src/com/rabbitmq/client/MapRpcServer.java | 2 +- src/com/rabbitmq/client/MessageProperties.java | 2 +- src/com/rabbitmq/client/Method.java | 2 +- src/com/rabbitmq/client/MissedHeartbeatException.java | 2 +- src/com/rabbitmq/client/NullTrustManager.java | 2 +- .../client/PossibleAuthenticationFailureException.java | 2 +- src/com/rabbitmq/client/ProtocolVersionMismatchException.java | 2 +- src/com/rabbitmq/client/QueueingConsumer.java | 2 +- src/com/rabbitmq/client/ReturnListener.java | 2 +- src/com/rabbitmq/client/RpcClient.java | 2 +- src/com/rabbitmq/client/RpcServer.java | 2 +- src/com/rabbitmq/client/SaslConfig.java | 2 +- src/com/rabbitmq/client/SaslMechanism.java | 2 +- src/com/rabbitmq/client/ShutdownListener.java | 2 +- src/com/rabbitmq/client/ShutdownNotifier.java | 2 +- src/com/rabbitmq/client/ShutdownSignalException.java | 2 +- src/com/rabbitmq/client/StringRpcServer.java | 2 +- src/com/rabbitmq/client/UnexpectedFrameError.java | 2 +- src/com/rabbitmq/client/UnexpectedMethodError.java | 2 +- src/com/rabbitmq/client/UnknownClassOrMethodId.java | 2 +- src/com/rabbitmq/client/impl/AMQBasicProperties.java | 2 +- src/com/rabbitmq/client/impl/AMQChannel.java | 2 +- src/com/rabbitmq/client/impl/AMQCommand.java | 2 +- src/com/rabbitmq/client/impl/AMQConnection.java | 4 ++-- src/com/rabbitmq/client/impl/AMQContentHeader.java | 2 +- src/com/rabbitmq/client/impl/CRDemoMechanism.java | 2 +- src/com/rabbitmq/client/impl/ChannelManager.java | 2 +- src/com/rabbitmq/client/impl/ChannelN.java | 2 +- src/com/rabbitmq/client/impl/ClientVersion.java.in | 2 +- src/com/rabbitmq/client/impl/CommandAssembler.java | 2 +- src/com/rabbitmq/client/impl/ConsumerDispatcher.java | 2 +- src/com/rabbitmq/client/impl/ConsumerWorkService.java | 2 +- src/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java | 2 +- src/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java | 2 +- src/com/rabbitmq/client/impl/DefaultExceptionHandler.java | 2 +- src/com/rabbitmq/client/impl/ExternalMechanism.java | 2 +- src/com/rabbitmq/client/impl/Frame.java | 2 +- src/com/rabbitmq/client/impl/FrameHandler.java | 2 +- src/com/rabbitmq/client/impl/HeartbeatSender.java | 2 +- src/com/rabbitmq/client/impl/LongStringHelper.java | 2 +- src/com/rabbitmq/client/impl/Method.java | 2 +- src/com/rabbitmq/client/impl/MethodArgumentReader.java | 2 +- src/com/rabbitmq/client/impl/MethodArgumentWriter.java | 2 +- src/com/rabbitmq/client/impl/PlainMechanism.java | 2 +- src/com/rabbitmq/client/impl/ShutdownNotifierComponent.java | 2 +- src/com/rabbitmq/client/impl/SocketFrameHandler.java | 2 +- src/com/rabbitmq/client/impl/TruncatedInputStream.java | 2 +- src/com/rabbitmq/client/impl/UnknownChannelException.java | 2 +- src/com/rabbitmq/client/impl/ValueReader.java | 2 +- src/com/rabbitmq/client/impl/ValueWriter.java | 2 +- src/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java | 2 +- src/com/rabbitmq/client/impl/Version.java | 2 +- src/com/rabbitmq/tools/Tracer.java | 2 +- src/com/rabbitmq/tools/json/JSONReader.java | 2 +- src/com/rabbitmq/tools/json/JSONSerializable.java | 2 +- src/com/rabbitmq/tools/json/JSONUtil.java | 2 +- src/com/rabbitmq/tools/json/JSONWriter.java | 2 +- src/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java | 2 +- src/com/rabbitmq/tools/jsonrpc/JsonRpcException.java | 2 +- src/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java | 2 +- src/com/rabbitmq/tools/jsonrpc/ParameterDescription.java | 2 +- src/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java | 2 +- src/com/rabbitmq/tools/jsonrpc/ServiceDescription.java | 2 +- src/com/rabbitmq/utility/BlockingCell.java | 2 +- src/com/rabbitmq/utility/BlockingValueOrException.java | 2 +- src/com/rabbitmq/utility/IntAllocator.java | 2 +- src/com/rabbitmq/utility/SensibleClone.java | 2 +- src/com/rabbitmq/utility/SingleShotLinearTimer.java | 2 +- src/com/rabbitmq/utility/Utility.java | 2 +- src/com/rabbitmq/utility/ValueOrException.java | 2 +- test/src/com/rabbitmq/client/test/AMQBuilderApiTest.java | 2 +- test/src/com/rabbitmq/client/test/AMQConnectionTest.java | 2 +- test/src/com/rabbitmq/client/test/AmqpUriTest.java | 2 +- test/src/com/rabbitmq/client/test/BlockingCellTest.java | 2 +- test/src/com/rabbitmq/client/test/BrokenFramesTest.java | 2 +- test/src/com/rabbitmq/client/test/BrokerTestCase.java | 2 +- test/src/com/rabbitmq/client/test/Bug20004Test.java | 2 +- .../rabbitmq/client/test/ChannelNumberAllocationTests.java | 2 +- test/src/com/rabbitmq/client/test/ClientTests.java | 2 +- test/src/com/rabbitmq/client/test/ClonePropertiesTest.java | 2 +- test/src/com/rabbitmq/client/test/CloseInMainLoop.java | 2 +- test/src/com/rabbitmq/client/test/ConfirmBase.java | 2 +- test/src/com/rabbitmq/client/test/JSONReadWriteTest.java | 2 +- test/src/com/rabbitmq/client/test/MultiThreadedChannel.java | 2 +- .../rabbitmq/client/test/QueueingConsumerShutdownTests.java | 2 +- test/src/com/rabbitmq/client/test/TableTest.java | 2 +- .../com/rabbitmq/client/test/TruncatedInputStreamTest.java | 2 +- test/src/com/rabbitmq/client/test/ValueOrExceptionTest.java | 2 +- .../rabbitmq/client/test/functional/AbstractRejectTest.java | 2 +- .../rabbitmq/client/test/functional/AlternateExchange.java | 2 +- .../com/rabbitmq/client/test/functional/BindingLifecycle.java | 2 +- .../rabbitmq/client/test/functional/BindingLifecycleBase.java | 2 +- test/src/com/rabbitmq/client/test/functional/CcRoutes.java | 2 +- .../rabbitmq/client/test/functional/ClusteredTestBase.java | 2 +- test/src/com/rabbitmq/client/test/functional/Confirm.java | 2 +- .../com/rabbitmq/client/test/functional/ConnectionOpen.java | 2 +- .../client/test/functional/ConsumerCancelNotification.java | 2 +- .../com/rabbitmq/client/test/functional/DefaultExchange.java | 2 +- .../com/rabbitmq/client/test/functional/DoubleDeletion.java | 2 +- .../rabbitmq/client/test/functional/DurableOnTransient.java | 2 +- .../com/rabbitmq/client/test/functional/ExchangeDeclare.java | 2 +- .../client/test/functional/ExchangeDeleteIfUnused.java | 2 +- .../client/test/functional/ExchangeEquivalenceBase.java | 2 +- .../client/test/functional/ExchangeExchangeBindings.java | 2 +- .../test/functional/ExchangeExchangeBindingsAutoDelete.java | 2 +- test/src/com/rabbitmq/client/test/functional/FrameMax.java | 2 +- .../com/rabbitmq/client/test/functional/FunctionalTests.java | 2 +- test/src/com/rabbitmq/client/test/functional/Heartbeat.java | 2 +- .../com/rabbitmq/client/test/functional/InternalExchange.java | 2 +- test/src/com/rabbitmq/client/test/functional/InvalidAcks.java | 2 +- .../com/rabbitmq/client/test/functional/InvalidAcksBase.java | 2 +- .../com/rabbitmq/client/test/functional/InvalidAcksTx.java | 2 +- test/src/com/rabbitmq/client/test/functional/Nack.java | 2 +- .../rabbitmq/client/test/functional/NoRequeueOnCancel.java | 2 +- .../com/rabbitmq/client/test/functional/PerMessageTTL.java | 2 +- test/src/com/rabbitmq/client/test/functional/PerQueueTTL.java | 2 +- test/src/com/rabbitmq/client/test/functional/Policies.java | 2 +- test/src/com/rabbitmq/client/test/functional/QosTests.java | 2 +- .../com/rabbitmq/client/test/functional/QueueExclusivity.java | 2 +- test/src/com/rabbitmq/client/test/functional/QueueLease.java | 2 +- .../com/rabbitmq/client/test/functional/QueueLifecycle.java | 2 +- .../com/rabbitmq/client/test/functional/QueueSizeLimit.java | 2 +- test/src/com/rabbitmq/client/test/functional/Recover.java | 2 +- test/src/com/rabbitmq/client/test/functional/Reject.java | 2 +- .../client/test/functional/RequeueOnChannelClose.java | 2 +- .../com/rabbitmq/client/test/functional/RequeueOnClose.java | 2 +- .../client/test/functional/RequeueOnConnectionClose.java | 2 +- test/src/com/rabbitmq/client/test/functional/Routing.java | 2 +- .../com/rabbitmq/client/test/functional/SaslMechanisms.java | 2 +- test/src/com/rabbitmq/client/test/functional/Tables.java | 2 +- .../src/com/rabbitmq/client/test/functional/Transactions.java | 2 +- .../client/test/functional/UnbindAutoDeleteExchange.java | 2 +- .../com/rabbitmq/client/test/functional/UnexpectedFrames.java | 2 +- .../src/com/rabbitmq/client/test/functional/UserIDHeader.java | 2 +- test/src/com/rabbitmq/client/test/performance/CLIHelper.java | 2 +- test/src/com/rabbitmq/client/test/performance/QosScaling.java | 2 +- .../com/rabbitmq/client/test/performance/ScalabilityTest.java | 2 +- .../rabbitmq/client/test/performance/StressManagement.java | 2 +- test/src/com/rabbitmq/client/test/server/AbsentQueue.java | 2 +- .../client/test/server/AlternateExchangeEquivalence.java | 2 +- .../com/rabbitmq/client/test/server/BlockedConnection.java | 2 +- test/src/com/rabbitmq/client/test/server/Bug19219Test.java | 2 +- .../rabbitmq/client/test/server/DurableBindingLifecycle.java | 2 +- .../client/test/server/EffectVisibilityCrossNodeTest.java | 2 +- .../rabbitmq/client/test/server/ExclusiveQueueDurability.java | 2 +- test/src/com/rabbitmq/client/test/server/HATests.java | 2 +- test/src/com/rabbitmq/client/test/server/MemoryAlarms.java | 2 +- test/src/com/rabbitmq/client/test/server/MessageRecovery.java | 2 +- test/src/com/rabbitmq/client/test/server/Permissions.java | 2 +- test/src/com/rabbitmq/client/test/server/ServerTests.java | 2 +- .../com/rabbitmq/client/test/ssl/BadVerifiedConnection.java | 2 +- test/src/com/rabbitmq/client/test/ssl/SSLTests.java | 2 +- .../com/rabbitmq/client/test/ssl/UnverifiedConnection.java | 2 +- test/src/com/rabbitmq/client/test/ssl/VerifiedConnection.java | 2 +- test/src/com/rabbitmq/examples/BufferPerformanceMetrics.java | 2 +- .../src/com/rabbitmq/examples/ChannelCreationPerformance.java | 2 +- test/src/com/rabbitmq/examples/ConfirmDontLoseMessages.java | 2 +- test/src/com/rabbitmq/examples/ConsumerMain.java | 2 +- test/src/com/rabbitmq/examples/FileConsumer.java | 2 +- test/src/com/rabbitmq/examples/FileProducer.java | 2 +- test/src/com/rabbitmq/examples/HelloClient.java | 2 +- test/src/com/rabbitmq/examples/HelloJsonClient.java | 2 +- test/src/com/rabbitmq/examples/HelloJsonServer.java | 2 +- test/src/com/rabbitmq/examples/HelloJsonService.java | 2 +- test/src/com/rabbitmq/examples/HelloServer.java | 2 +- test/src/com/rabbitmq/examples/LogTail.java | 2 +- test/src/com/rabbitmq/examples/MulticastMain.java | 2 +- test/src/com/rabbitmq/examples/PerQueueTTLGetter.java | 2 +- test/src/com/rabbitmq/examples/PerQueueTTLPublisher.java | 2 +- test/src/com/rabbitmq/examples/PerfTest.java | 2 +- test/src/com/rabbitmq/examples/PerfTestMulti.java | 2 +- test/src/com/rabbitmq/examples/ProducerMain.java | 2 +- test/src/com/rabbitmq/examples/SendString.java | 2 +- test/src/com/rabbitmq/examples/SimpleConsumer.java | 2 +- test/src/com/rabbitmq/examples/SimpleProducer.java | 2 +- test/src/com/rabbitmq/examples/SimpleTopicConsumer.java | 2 +- test/src/com/rabbitmq/examples/SimpleTopicProducer.java | 2 +- test/src/com/rabbitmq/examples/SpammyTopicProducer.java | 2 +- test/src/com/rabbitmq/examples/StressPersister.java | 2 +- test/src/com/rabbitmq/examples/TestMain.java | 2 +- test/src/com/rabbitmq/examples/TracerConcurrencyTest.java | 2 +- test/src/com/rabbitmq/examples/perf/Broker.java | 2 +- test/src/com/rabbitmq/examples/perf/BrokerValue.java | 2 +- test/src/com/rabbitmq/examples/perf/BrokerVariable.java | 2 +- test/src/com/rabbitmq/examples/perf/Consumer.java | 2 +- test/src/com/rabbitmq/examples/perf/MulticastParams.java | 2 +- test/src/com/rabbitmq/examples/perf/MulticastSet.java | 2 +- test/src/com/rabbitmq/examples/perf/MulticastValue.java | 2 +- test/src/com/rabbitmq/examples/perf/MulticastVariable.java | 2 +- test/src/com/rabbitmq/examples/perf/Producer.java | 2 +- .../src/com/rabbitmq/examples/perf/RateVsLatencyScenario.java | 2 +- test/src/com/rabbitmq/examples/perf/Scenario.java | 2 +- test/src/com/rabbitmq/examples/perf/ScenarioStats.java | 2 +- test/src/com/rabbitmq/examples/perf/SimpleScenario.java | 2 +- test/src/com/rabbitmq/examples/perf/SimpleScenarioStats.java | 2 +- test/src/com/rabbitmq/examples/perf/Stats.java | 2 +- test/src/com/rabbitmq/examples/perf/Variable.java | 2 +- test/src/com/rabbitmq/examples/perf/VariableValue.java | 2 +- test/src/com/rabbitmq/examples/perf/VaryingScenario.java | 2 +- test/src/com/rabbitmq/examples/perf/VaryingScenarioStats.java | 2 +- test/src/com/rabbitmq/tools/Host.java | 2 +- test/src/com/rabbitmq/utility/IntAllocatorTests.java | 2 +- 226 files changed, 228 insertions(+), 228 deletions(-) diff --git a/LICENSE-MPL-RabbitMQ b/LICENSE-MPL-RabbitMQ index b0325a0e49..096b2c4eaa 100644 --- a/LICENSE-MPL-RabbitMQ +++ b/LICENSE-MPL-RabbitMQ @@ -447,7 +447,7 @@ EXHIBIT A -Mozilla Public License. The Original Code is RabbitMQ. The Initial Developer of the Original Code is GoPivotal, Inc. - Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. + Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. Alternatively, the contents of this file may be used under the terms of the GNU General Public License version 2 (the "GPL2"), or diff --git a/codegen.py b/codegen.py index 24e2e52364..fe7db666dd 100644 --- a/codegen.py +++ b/codegen.py @@ -11,7 +11,7 @@ ## The Original Code is RabbitMQ. ## ## The Initial Developer of the Original Code is GoPivotal, Inc. -## Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +## Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. ## from __future__ import nested_scopes @@ -143,7 +143,7 @@ def printFileHeader(): // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // """ diff --git a/src/com/rabbitmq/client/Address.java b/src/com/rabbitmq/client/Address.java index 40df18801d..6c7283f8c1 100644 --- a/src/com/rabbitmq/client/Address.java +++ b/src/com/rabbitmq/client/Address.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/AlreadyClosedException.java b/src/com/rabbitmq/client/AlreadyClosedException.java index f5ff58bdfd..e587001c50 100644 --- a/src/com/rabbitmq/client/AlreadyClosedException.java +++ b/src/com/rabbitmq/client/AlreadyClosedException.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/AuthenticationFailureException.java b/src/com/rabbitmq/client/AuthenticationFailureException.java index e2dbe64de0..ceb5e85a62 100644 --- a/src/com/rabbitmq/client/AuthenticationFailureException.java +++ b/src/com/rabbitmq/client/AuthenticationFailureException.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2013-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2013-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/BasicProperties.java b/src/com/rabbitmq/client/BasicProperties.java index a1b7346382..021b17d087 100644 --- a/src/com/rabbitmq/client/BasicProperties.java +++ b/src/com/rabbitmq/client/BasicProperties.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/BlockedListener.java b/src/com/rabbitmq/client/BlockedListener.java index bf7728c3d2..ca002185b7 100644 --- a/src/com/rabbitmq/client/BlockedListener.java +++ b/src/com/rabbitmq/client/BlockedListener.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/Channel.java b/src/com/rabbitmq/client/Channel.java index ac63fe5a34..824518f0f0 100644 --- a/src/com/rabbitmq/client/Channel.java +++ b/src/com/rabbitmq/client/Channel.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/Command.java b/src/com/rabbitmq/client/Command.java index 4938f15521..b5007b542d 100644 --- a/src/com/rabbitmq/client/Command.java +++ b/src/com/rabbitmq/client/Command.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/ConfirmListener.java b/src/com/rabbitmq/client/ConfirmListener.java index 7109de0b76..e6f113b16c 100644 --- a/src/com/rabbitmq/client/ConfirmListener.java +++ b/src/com/rabbitmq/client/ConfirmListener.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/Connection.java b/src/com/rabbitmq/client/Connection.java index 37c0758176..b216cacb04 100644 --- a/src/com/rabbitmq/client/Connection.java +++ b/src/com/rabbitmq/client/Connection.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/ConnectionFactory.java b/src/com/rabbitmq/client/ConnectionFactory.java index f5632dac4b..e4163c6916 100644 --- a/src/com/rabbitmq/client/ConnectionFactory.java +++ b/src/com/rabbitmq/client/ConnectionFactory.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/Consumer.java b/src/com/rabbitmq/client/Consumer.java index d1c43f2c70..8279088163 100644 --- a/src/com/rabbitmq/client/Consumer.java +++ b/src/com/rabbitmq/client/Consumer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/ConsumerCancelledException.java b/src/com/rabbitmq/client/ConsumerCancelledException.java index a322f73fcc..a711cb2b9b 100644 --- a/src/com/rabbitmq/client/ConsumerCancelledException.java +++ b/src/com/rabbitmq/client/ConsumerCancelledException.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/ContentHeader.java b/src/com/rabbitmq/client/ContentHeader.java index b8d1ae4b6e..b8cb340c26 100644 --- a/src/com/rabbitmq/client/ContentHeader.java +++ b/src/com/rabbitmq/client/ContentHeader.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/DefaultConsumer.java b/src/com/rabbitmq/client/DefaultConsumer.java index f526d379eb..7026d8107b 100644 --- a/src/com/rabbitmq/client/DefaultConsumer.java +++ b/src/com/rabbitmq/client/DefaultConsumer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/DefaultSaslConfig.java b/src/com/rabbitmq/client/DefaultSaslConfig.java index 9888f69432..b86b1c2e73 100644 --- a/src/com/rabbitmq/client/DefaultSaslConfig.java +++ b/src/com/rabbitmq/client/DefaultSaslConfig.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/Envelope.java b/src/com/rabbitmq/client/Envelope.java index eb5d797556..56269734b0 100644 --- a/src/com/rabbitmq/client/Envelope.java +++ b/src/com/rabbitmq/client/Envelope.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/ExceptionHandler.java b/src/com/rabbitmq/client/ExceptionHandler.java index f304a1ae84..8160ca1b5e 100644 --- a/src/com/rabbitmq/client/ExceptionHandler.java +++ b/src/com/rabbitmq/client/ExceptionHandler.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/FlowListener.java b/src/com/rabbitmq/client/FlowListener.java index df09664844..b6b1ba8594 100644 --- a/src/com/rabbitmq/client/FlowListener.java +++ b/src/com/rabbitmq/client/FlowListener.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/GetResponse.java b/src/com/rabbitmq/client/GetResponse.java index 3c77cec022..1d06d2774a 100644 --- a/src/com/rabbitmq/client/GetResponse.java +++ b/src/com/rabbitmq/client/GetResponse.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/JDKSaslConfig.java b/src/com/rabbitmq/client/JDKSaslConfig.java index 8e57795044..f19d45c970 100644 --- a/src/com/rabbitmq/client/JDKSaslConfig.java +++ b/src/com/rabbitmq/client/JDKSaslConfig.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/LongString.java b/src/com/rabbitmq/client/LongString.java index 28d5a24385..b503281750 100644 --- a/src/com/rabbitmq/client/LongString.java +++ b/src/com/rabbitmq/client/LongString.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/MalformedFrameException.java b/src/com/rabbitmq/client/MalformedFrameException.java index 12700140ab..cde6fed01a 100644 --- a/src/com/rabbitmq/client/MalformedFrameException.java +++ b/src/com/rabbitmq/client/MalformedFrameException.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/MapRpcServer.java b/src/com/rabbitmq/client/MapRpcServer.java index 426332b690..b150a5c09e 100644 --- a/src/com/rabbitmq/client/MapRpcServer.java +++ b/src/com/rabbitmq/client/MapRpcServer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/MessageProperties.java b/src/com/rabbitmq/client/MessageProperties.java index 0b30657101..2624b8c734 100644 --- a/src/com/rabbitmq/client/MessageProperties.java +++ b/src/com/rabbitmq/client/MessageProperties.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/Method.java b/src/com/rabbitmq/client/Method.java index dfafe9a596..c5b62f7dc4 100644 --- a/src/com/rabbitmq/client/Method.java +++ b/src/com/rabbitmq/client/Method.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/MissedHeartbeatException.java b/src/com/rabbitmq/client/MissedHeartbeatException.java index 34afccf9d2..1808cde295 100644 --- a/src/com/rabbitmq/client/MissedHeartbeatException.java +++ b/src/com/rabbitmq/client/MissedHeartbeatException.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/NullTrustManager.java b/src/com/rabbitmq/client/NullTrustManager.java index 8aef053bf3..7ac9a213dd 100644 --- a/src/com/rabbitmq/client/NullTrustManager.java +++ b/src/com/rabbitmq/client/NullTrustManager.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/PossibleAuthenticationFailureException.java b/src/com/rabbitmq/client/PossibleAuthenticationFailureException.java index 33b9dcdb69..a5858dd64c 100644 --- a/src/com/rabbitmq/client/PossibleAuthenticationFailureException.java +++ b/src/com/rabbitmq/client/PossibleAuthenticationFailureException.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/ProtocolVersionMismatchException.java b/src/com/rabbitmq/client/ProtocolVersionMismatchException.java index f247ad68d2..fd187b833f 100644 --- a/src/com/rabbitmq/client/ProtocolVersionMismatchException.java +++ b/src/com/rabbitmq/client/ProtocolVersionMismatchException.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/QueueingConsumer.java b/src/com/rabbitmq/client/QueueingConsumer.java index d4e9b1fc4e..c2cdd346a2 100644 --- a/src/com/rabbitmq/client/QueueingConsumer.java +++ b/src/com/rabbitmq/client/QueueingConsumer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/ReturnListener.java b/src/com/rabbitmq/client/ReturnListener.java index b634a2c5c9..64017ee12f 100644 --- a/src/com/rabbitmq/client/ReturnListener.java +++ b/src/com/rabbitmq/client/ReturnListener.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/RpcClient.java b/src/com/rabbitmq/client/RpcClient.java index 48c944954d..10e8ea2c62 100644 --- a/src/com/rabbitmq/client/RpcClient.java +++ b/src/com/rabbitmq/client/RpcClient.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/RpcServer.java b/src/com/rabbitmq/client/RpcServer.java index 73ccceb4e8..f900b7877c 100644 --- a/src/com/rabbitmq/client/RpcServer.java +++ b/src/com/rabbitmq/client/RpcServer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/SaslConfig.java b/src/com/rabbitmq/client/SaslConfig.java index 87420cbd0e..382df58ae2 100644 --- a/src/com/rabbitmq/client/SaslConfig.java +++ b/src/com/rabbitmq/client/SaslConfig.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/SaslMechanism.java b/src/com/rabbitmq/client/SaslMechanism.java index 59b2538c83..c869d38eda 100644 --- a/src/com/rabbitmq/client/SaslMechanism.java +++ b/src/com/rabbitmq/client/SaslMechanism.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/ShutdownListener.java b/src/com/rabbitmq/client/ShutdownListener.java index 0bfd890315..72b99a194b 100644 --- a/src/com/rabbitmq/client/ShutdownListener.java +++ b/src/com/rabbitmq/client/ShutdownListener.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/ShutdownNotifier.java b/src/com/rabbitmq/client/ShutdownNotifier.java index e2ce0b8838..a8471b7827 100644 --- a/src/com/rabbitmq/client/ShutdownNotifier.java +++ b/src/com/rabbitmq/client/ShutdownNotifier.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/ShutdownSignalException.java b/src/com/rabbitmq/client/ShutdownSignalException.java index c90df1ea2e..5787e67322 100644 --- a/src/com/rabbitmq/client/ShutdownSignalException.java +++ b/src/com/rabbitmq/client/ShutdownSignalException.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/StringRpcServer.java b/src/com/rabbitmq/client/StringRpcServer.java index 9ea120c6ab..0c7b2e01d7 100644 --- a/src/com/rabbitmq/client/StringRpcServer.java +++ b/src/com/rabbitmq/client/StringRpcServer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/UnexpectedFrameError.java b/src/com/rabbitmq/client/UnexpectedFrameError.java index 08df6d4d11..a86cda5cb3 100644 --- a/src/com/rabbitmq/client/UnexpectedFrameError.java +++ b/src/com/rabbitmq/client/UnexpectedFrameError.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/UnexpectedMethodError.java b/src/com/rabbitmq/client/UnexpectedMethodError.java index a474d2bde3..38cff48085 100644 --- a/src/com/rabbitmq/client/UnexpectedMethodError.java +++ b/src/com/rabbitmq/client/UnexpectedMethodError.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/UnknownClassOrMethodId.java b/src/com/rabbitmq/client/UnknownClassOrMethodId.java index 058d3f6b89..ffc4629ca5 100644 --- a/src/com/rabbitmq/client/UnknownClassOrMethodId.java +++ b/src/com/rabbitmq/client/UnknownClassOrMethodId.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/impl/AMQBasicProperties.java b/src/com/rabbitmq/client/impl/AMQBasicProperties.java index 53acbe3e13..32a390256b 100644 --- a/src/com/rabbitmq/client/impl/AMQBasicProperties.java +++ b/src/com/rabbitmq/client/impl/AMQBasicProperties.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/AMQChannel.java b/src/com/rabbitmq/client/impl/AMQChannel.java index 57249855a8..3f7c091ba5 100644 --- a/src/com/rabbitmq/client/impl/AMQChannel.java +++ b/src/com/rabbitmq/client/impl/AMQChannel.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/impl/AMQCommand.java b/src/com/rabbitmq/client/impl/AMQCommand.java index 88aecee324..d682b9abff 100644 --- a/src/com/rabbitmq/client/impl/AMQCommand.java +++ b/src/com/rabbitmq/client/impl/AMQCommand.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/AMQConnection.java b/src/com/rabbitmq/client/impl/AMQConnection.java index 6d8348073e..d2fd4524b0 100644 --- a/src/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/com/rabbitmq/client/impl/AMQConnection.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; @@ -52,7 +52,7 @@ import com.rabbitmq.utility.BlockingCell; final class Copyright { - final static String COPYRIGHT="Copyright (C) 2007-2014 GoPivotal, Inc."; + final static String COPYRIGHT="Copyright (C) 2007-2015 Pivotal Software, Inc."; final static String LICENSE="Licensed under the MPL. See http://www.rabbitmq.com/"; } diff --git a/src/com/rabbitmq/client/impl/AMQContentHeader.java b/src/com/rabbitmq/client/impl/AMQContentHeader.java index 8a16bb7899..58eb8fe0b9 100644 --- a/src/com/rabbitmq/client/impl/AMQContentHeader.java +++ b/src/com/rabbitmq/client/impl/AMQContentHeader.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/CRDemoMechanism.java b/src/com/rabbitmq/client/impl/CRDemoMechanism.java index 45fb70053c..90e3dac51c 100644 --- a/src/com/rabbitmq/client/impl/CRDemoMechanism.java +++ b/src/com/rabbitmq/client/impl/CRDemoMechanism.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/ChannelManager.java b/src/com/rabbitmq/client/impl/ChannelManager.java index 85e30a4e20..e77afcf7ae 100644 --- a/src/com/rabbitmq/client/impl/ChannelManager.java +++ b/src/com/rabbitmq/client/impl/ChannelManager.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/ChannelN.java b/src/com/rabbitmq/client/impl/ChannelN.java index 6b5a087718..fdc868d7b2 100644 --- a/src/com/rabbitmq/client/impl/ChannelN.java +++ b/src/com/rabbitmq/client/impl/ChannelN.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/ClientVersion.java.in b/src/com/rabbitmq/client/impl/ClientVersion.java.in index 8eb0a13fe3..0aaaa5b6f0 100644 --- a/src/com/rabbitmq/client/impl/ClientVersion.java.in +++ b/src/com/rabbitmq/client/impl/ClientVersion.java.in @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/CommandAssembler.java b/src/com/rabbitmq/client/impl/CommandAssembler.java index de74152249..16bf8242c7 100644 --- a/src/com/rabbitmq/client/impl/CommandAssembler.java +++ b/src/com/rabbitmq/client/impl/CommandAssembler.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/ConsumerDispatcher.java b/src/com/rabbitmq/client/impl/ConsumerDispatcher.java index 64c7f7eb79..f5bf62b6e1 100644 --- a/src/com/rabbitmq/client/impl/ConsumerDispatcher.java +++ b/src/com/rabbitmq/client/impl/ConsumerDispatcher.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2011-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2011-2015 Pivotal Software, Inc. All rights reserved. package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/ConsumerWorkService.java b/src/com/rabbitmq/client/impl/ConsumerWorkService.java index 83dc8fd25b..a38c63e0c2 100644 --- a/src/com/rabbitmq/client/impl/ConsumerWorkService.java +++ b/src/com/rabbitmq/client/impl/ConsumerWorkService.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2011-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2011-2015 Pivotal Software, Inc. All rights reserved. package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java b/src/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java index c3f69baa26..b66d01e862 100644 --- a/src/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java +++ b/src/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java b/src/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java index e869b48dfb..fcf4b0d7b6 100644 --- a/src/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java +++ b/src/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/impl/DefaultExceptionHandler.java b/src/com/rabbitmq/client/impl/DefaultExceptionHandler.java index cef33fd384..63b31c1784 100644 --- a/src/com/rabbitmq/client/impl/DefaultExceptionHandler.java +++ b/src/com/rabbitmq/client/impl/DefaultExceptionHandler.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/ExternalMechanism.java b/src/com/rabbitmq/client/impl/ExternalMechanism.java index fce3ab1df5..698eccf483 100644 --- a/src/com/rabbitmq/client/impl/ExternalMechanism.java +++ b/src/com/rabbitmq/client/impl/ExternalMechanism.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/Frame.java b/src/com/rabbitmq/client/impl/Frame.java index 5b3fc491ef..8c83640929 100644 --- a/src/com/rabbitmq/client/impl/Frame.java +++ b/src/com/rabbitmq/client/impl/Frame.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/FrameHandler.java b/src/com/rabbitmq/client/impl/FrameHandler.java index 47602f638e..705d67629d 100644 --- a/src/com/rabbitmq/client/impl/FrameHandler.java +++ b/src/com/rabbitmq/client/impl/FrameHandler.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/HeartbeatSender.java b/src/com/rabbitmq/client/impl/HeartbeatSender.java index bbd0c7c196..893597d0a5 100644 --- a/src/com/rabbitmq/client/impl/HeartbeatSender.java +++ b/src/com/rabbitmq/client/impl/HeartbeatSender.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/impl/LongStringHelper.java b/src/com/rabbitmq/client/impl/LongStringHelper.java index 8d18b70ecd..bf7d609660 100644 --- a/src/com/rabbitmq/client/impl/LongStringHelper.java +++ b/src/com/rabbitmq/client/impl/LongStringHelper.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/impl/Method.java b/src/com/rabbitmq/client/impl/Method.java index 0a7ce83808..db6ba559b4 100644 --- a/src/com/rabbitmq/client/impl/Method.java +++ b/src/com/rabbitmq/client/impl/Method.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/impl/MethodArgumentReader.java b/src/com/rabbitmq/client/impl/MethodArgumentReader.java index c7c1973212..85fbf95675 100644 --- a/src/com/rabbitmq/client/impl/MethodArgumentReader.java +++ b/src/com/rabbitmq/client/impl/MethodArgumentReader.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/impl/MethodArgumentWriter.java b/src/com/rabbitmq/client/impl/MethodArgumentWriter.java index 2143ea9b16..f52e605818 100644 --- a/src/com/rabbitmq/client/impl/MethodArgumentWriter.java +++ b/src/com/rabbitmq/client/impl/MethodArgumentWriter.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/impl/PlainMechanism.java b/src/com/rabbitmq/client/impl/PlainMechanism.java index b134dd5c0f..7eb0fa9cf0 100644 --- a/src/com/rabbitmq/client/impl/PlainMechanism.java +++ b/src/com/rabbitmq/client/impl/PlainMechanism.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/ShutdownNotifierComponent.java b/src/com/rabbitmq/client/impl/ShutdownNotifierComponent.java index e48edf5ef5..5e11fad487 100644 --- a/src/com/rabbitmq/client/impl/ShutdownNotifierComponent.java +++ b/src/com/rabbitmq/client/impl/ShutdownNotifierComponent.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/impl/SocketFrameHandler.java b/src/com/rabbitmq/client/impl/SocketFrameHandler.java index 004cc2b32d..565497e6ae 100644 --- a/src/com/rabbitmq/client/impl/SocketFrameHandler.java +++ b/src/com/rabbitmq/client/impl/SocketFrameHandler.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/TruncatedInputStream.java b/src/com/rabbitmq/client/impl/TruncatedInputStream.java index 767ffa235d..52dade475c 100644 --- a/src/com/rabbitmq/client/impl/TruncatedInputStream.java +++ b/src/com/rabbitmq/client/impl/TruncatedInputStream.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/impl/UnknownChannelException.java b/src/com/rabbitmq/client/impl/UnknownChannelException.java index 4a0de7eb3f..d7730f559a 100644 --- a/src/com/rabbitmq/client/impl/UnknownChannelException.java +++ b/src/com/rabbitmq/client/impl/UnknownChannelException.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/impl/ValueReader.java b/src/com/rabbitmq/client/impl/ValueReader.java index 7f171a63eb..d8bfbcb05b 100644 --- a/src/com/rabbitmq/client/impl/ValueReader.java +++ b/src/com/rabbitmq/client/impl/ValueReader.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/impl/ValueWriter.java b/src/com/rabbitmq/client/impl/ValueWriter.java index 05e3e0a723..f5eb70a41d 100644 --- a/src/com/rabbitmq/client/impl/ValueWriter.java +++ b/src/com/rabbitmq/client/impl/ValueWriter.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java b/src/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java index 7520e20abc..b7a2ed408f 100644 --- a/src/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java +++ b/src/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java @@ -1,5 +1,5 @@ /* - * Modifications Copyright 2014 GoPivotal, Inc and licenced as per + * Modifications Copyright 2015 Pivotal Software, Inc and licenced as per * the rest of the RabbitMQ Java client. */ diff --git a/src/com/rabbitmq/client/impl/Version.java b/src/com/rabbitmq/client/impl/Version.java index 3735e678ed..8f28027a44 100644 --- a/src/com/rabbitmq/client/impl/Version.java +++ b/src/com/rabbitmq/client/impl/Version.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/tools/Tracer.java b/src/com/rabbitmq/tools/Tracer.java index 4c99ff9308..cf04a16390 100644 --- a/src/com/rabbitmq/tools/Tracer.java +++ b/src/com/rabbitmq/tools/Tracer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.tools; diff --git a/src/com/rabbitmq/tools/json/JSONReader.java b/src/com/rabbitmq/tools/json/JSONReader.java index 57ddcbd3b9..349fa3a739 100644 --- a/src/com/rabbitmq/tools/json/JSONReader.java +++ b/src/com/rabbitmq/tools/json/JSONReader.java @@ -1,6 +1,6 @@ /* Copyright (c) 2006-2007 Frank Carver - Copyright (c) 2007-2014 GoPivotal, Inc. All Rights Reserved + Copyright (c) 2007-2015 Pivotal Software, Inc. All Rights Reserved Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/src/com/rabbitmq/tools/json/JSONSerializable.java b/src/com/rabbitmq/tools/json/JSONSerializable.java index ad9f32a304..6c219ad093 100644 --- a/src/com/rabbitmq/tools/json/JSONSerializable.java +++ b/src/com/rabbitmq/tools/json/JSONSerializable.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/tools/json/JSONUtil.java b/src/com/rabbitmq/tools/json/JSONUtil.java index 7076dd6b5a..2c71c6263d 100644 --- a/src/com/rabbitmq/tools/json/JSONUtil.java +++ b/src/com/rabbitmq/tools/json/JSONUtil.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/tools/json/JSONWriter.java b/src/com/rabbitmq/tools/json/JSONWriter.java index 7df0913ac5..e6a3ebd845 100644 --- a/src/com/rabbitmq/tools/json/JSONWriter.java +++ b/src/com/rabbitmq/tools/json/JSONWriter.java @@ -1,6 +1,6 @@ /* Copyright (c) 2006-2007 Frank Carver - Copyright (c) 2007-2014 GoPivotal, Inc. All Rights Reserved + Copyright (c) 2007-2015 Pivotal Software, Inc. All Rights Reserved Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/src/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java b/src/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java index de8ba54ff0..5579a5acbf 100644 --- a/src/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java +++ b/src/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.tools.jsonrpc; diff --git a/src/com/rabbitmq/tools/jsonrpc/JsonRpcException.java b/src/com/rabbitmq/tools/jsonrpc/JsonRpcException.java index 0da710896c..c21315ae6a 100644 --- a/src/com/rabbitmq/tools/jsonrpc/JsonRpcException.java +++ b/src/com/rabbitmq/tools/jsonrpc/JsonRpcException.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java b/src/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java index ac0d6a2d99..72725bbdfc 100644 --- a/src/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java +++ b/src/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/tools/jsonrpc/ParameterDescription.java b/src/com/rabbitmq/tools/jsonrpc/ParameterDescription.java index 407a978691..7ae45f06c3 100644 --- a/src/com/rabbitmq/tools/jsonrpc/ParameterDescription.java +++ b/src/com/rabbitmq/tools/jsonrpc/ParameterDescription.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java b/src/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java index 842396397a..1d1419e3b4 100644 --- a/src/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java +++ b/src/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/tools/jsonrpc/ServiceDescription.java b/src/com/rabbitmq/tools/jsonrpc/ServiceDescription.java index 332526d984..0b8143b7e7 100644 --- a/src/com/rabbitmq/tools/jsonrpc/ServiceDescription.java +++ b/src/com/rabbitmq/tools/jsonrpc/ServiceDescription.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/utility/BlockingCell.java b/src/com/rabbitmq/utility/BlockingCell.java index 74f545e81e..a278811df6 100644 --- a/src/com/rabbitmq/utility/BlockingCell.java +++ b/src/com/rabbitmq/utility/BlockingCell.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/utility/BlockingValueOrException.java b/src/com/rabbitmq/utility/BlockingValueOrException.java index 12d299bc83..0d761255e5 100644 --- a/src/com/rabbitmq/utility/BlockingValueOrException.java +++ b/src/com/rabbitmq/utility/BlockingValueOrException.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.utility; diff --git a/src/com/rabbitmq/utility/IntAllocator.java b/src/com/rabbitmq/utility/IntAllocator.java index 85a32130d8..160e730259 100644 --- a/src/com/rabbitmq/utility/IntAllocator.java +++ b/src/com/rabbitmq/utility/IntAllocator.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.utility; diff --git a/src/com/rabbitmq/utility/SensibleClone.java b/src/com/rabbitmq/utility/SensibleClone.java index a21868b0de..25ad1a40c1 100644 --- a/src/com/rabbitmq/utility/SensibleClone.java +++ b/src/com/rabbitmq/utility/SensibleClone.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.utility; diff --git a/src/com/rabbitmq/utility/SingleShotLinearTimer.java b/src/com/rabbitmq/utility/SingleShotLinearTimer.java index 638ed84bee..8b4cbd11f8 100644 --- a/src/com/rabbitmq/utility/SingleShotLinearTimer.java +++ b/src/com/rabbitmq/utility/SingleShotLinearTimer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/utility/Utility.java b/src/com/rabbitmq/utility/Utility.java index c85dcdd081..a11470bd4d 100644 --- a/src/com/rabbitmq/utility/Utility.java +++ b/src/com/rabbitmq/utility/Utility.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.utility; diff --git a/src/com/rabbitmq/utility/ValueOrException.java b/src/com/rabbitmq/utility/ValueOrException.java index 4a9e549448..a69a2fa57e 100644 --- a/src/com/rabbitmq/utility/ValueOrException.java +++ b/src/com/rabbitmq/utility/ValueOrException.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.utility; diff --git a/test/src/com/rabbitmq/client/test/AMQBuilderApiTest.java b/test/src/com/rabbitmq/client/test/AMQBuilderApiTest.java index 20381a13f3..a9754038f3 100644 --- a/test/src/com/rabbitmq/client/test/AMQBuilderApiTest.java +++ b/test/src/com/rabbitmq/client/test/AMQBuilderApiTest.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // // package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/AMQConnectionTest.java b/test/src/com/rabbitmq/client/test/AMQConnectionTest.java index d229fba8d9..27821bda9f 100644 --- a/test/src/com/rabbitmq/client/test/AMQConnectionTest.java +++ b/test/src/com/rabbitmq/client/test/AMQConnectionTest.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/AmqpUriTest.java b/test/src/com/rabbitmq/client/test/AmqpUriTest.java index a477de02c9..2b38d7aefa 100644 --- a/test/src/com/rabbitmq/client/test/AmqpUriTest.java +++ b/test/src/com/rabbitmq/client/test/AmqpUriTest.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2011-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2011-2015 Pivotal Software, Inc. All rights reserved. // // package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/BlockingCellTest.java b/test/src/com/rabbitmq/client/test/BlockingCellTest.java index 267f6dd06f..0fe8be87d3 100644 --- a/test/src/com/rabbitmq/client/test/BlockingCellTest.java +++ b/test/src/com/rabbitmq/client/test/BlockingCellTest.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/BrokenFramesTest.java b/test/src/com/rabbitmq/client/test/BrokenFramesTest.java index 7e57ffec7b..b11830c18a 100644 --- a/test/src/com/rabbitmq/client/test/BrokenFramesTest.java +++ b/test/src/com/rabbitmq/client/test/BrokenFramesTest.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/BrokerTestCase.java b/test/src/com/rabbitmq/client/test/BrokerTestCase.java index 88030ed5ac..656c59893f 100644 --- a/test/src/com/rabbitmq/client/test/BrokerTestCase.java +++ b/test/src/com/rabbitmq/client/test/BrokerTestCase.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/Bug20004Test.java b/test/src/com/rabbitmq/client/test/Bug20004Test.java index 45947150e6..60470d43d9 100644 --- a/test/src/com/rabbitmq/client/test/Bug20004Test.java +++ b/test/src/com/rabbitmq/client/test/Bug20004Test.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/ChannelNumberAllocationTests.java b/test/src/com/rabbitmq/client/test/ChannelNumberAllocationTests.java index 13d00eb361..73aa26f86f 100644 --- a/test/src/com/rabbitmq/client/test/ChannelNumberAllocationTests.java +++ b/test/src/com/rabbitmq/client/test/ChannelNumberAllocationTests.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/ClientTests.java b/test/src/com/rabbitmq/client/test/ClientTests.java index d618da89f1..7df48df58a 100644 --- a/test/src/com/rabbitmq/client/test/ClientTests.java +++ b/test/src/com/rabbitmq/client/test/ClientTests.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/ClonePropertiesTest.java b/test/src/com/rabbitmq/client/test/ClonePropertiesTest.java index 186ad84ea1..5e7ea4a6db 100644 --- a/test/src/com/rabbitmq/client/test/ClonePropertiesTest.java +++ b/test/src/com/rabbitmq/client/test/ClonePropertiesTest.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/CloseInMainLoop.java b/test/src/com/rabbitmq/client/test/CloseInMainLoop.java index c94fc488d5..eca14245bc 100644 --- a/test/src/com/rabbitmq/client/test/CloseInMainLoop.java +++ b/test/src/com/rabbitmq/client/test/CloseInMainLoop.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/ConfirmBase.java b/test/src/com/rabbitmq/client/test/ConfirmBase.java index 576005aeb3..584d03d79c 100644 --- a/test/src/com/rabbitmq/client/test/ConfirmBase.java +++ b/test/src/com/rabbitmq/client/test/ConfirmBase.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2011-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2011-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/JSONReadWriteTest.java b/test/src/com/rabbitmq/client/test/JSONReadWriteTest.java index 4b1a9d6aa5..8b681bd322 100644 --- a/test/src/com/rabbitmq/client/test/JSONReadWriteTest.java +++ b/test/src/com/rabbitmq/client/test/JSONReadWriteTest.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/MultiThreadedChannel.java b/test/src/com/rabbitmq/client/test/MultiThreadedChannel.java index b1a08c4e71..12d01b3153 100644 --- a/test/src/com/rabbitmq/client/test/MultiThreadedChannel.java +++ b/test/src/com/rabbitmq/client/test/MultiThreadedChannel.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/QueueingConsumerShutdownTests.java b/test/src/com/rabbitmq/client/test/QueueingConsumerShutdownTests.java index abd4be91ff..39bb7fa0a5 100644 --- a/test/src/com/rabbitmq/client/test/QueueingConsumerShutdownTests.java +++ b/test/src/com/rabbitmq/client/test/QueueingConsumerShutdownTests.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/TableTest.java b/test/src/com/rabbitmq/client/test/TableTest.java index 9a40188295..4a38ba6262 100644 --- a/test/src/com/rabbitmq/client/test/TableTest.java +++ b/test/src/com/rabbitmq/client/test/TableTest.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/TruncatedInputStreamTest.java b/test/src/com/rabbitmq/client/test/TruncatedInputStreamTest.java index 72cf4f3b71..dbef4d4b22 100644 --- a/test/src/com/rabbitmq/client/test/TruncatedInputStreamTest.java +++ b/test/src/com/rabbitmq/client/test/TruncatedInputStreamTest.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/ValueOrExceptionTest.java b/test/src/com/rabbitmq/client/test/ValueOrExceptionTest.java index e8a54103f1..7fad3dc0fb 100644 --- a/test/src/com/rabbitmq/client/test/ValueOrExceptionTest.java +++ b/test/src/com/rabbitmq/client/test/ValueOrExceptionTest.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/functional/AbstractRejectTest.java b/test/src/com/rabbitmq/client/test/functional/AbstractRejectTest.java index 6922f8caf2..5d60af44d0 100644 --- a/test/src/com/rabbitmq/client/test/functional/AbstractRejectTest.java +++ b/test/src/com/rabbitmq/client/test/functional/AbstractRejectTest.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/AlternateExchange.java b/test/src/com/rabbitmq/client/test/functional/AlternateExchange.java index 89e7919617..5b908c9541 100644 --- a/test/src/com/rabbitmq/client/test/functional/AlternateExchange.java +++ b/test/src/com/rabbitmq/client/test/functional/AlternateExchange.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/BindingLifecycle.java b/test/src/com/rabbitmq/client/test/functional/BindingLifecycle.java index 53ba458660..15af445c7e 100644 --- a/test/src/com/rabbitmq/client/test/functional/BindingLifecycle.java +++ b/test/src/com/rabbitmq/client/test/functional/BindingLifecycle.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/BindingLifecycleBase.java b/test/src/com/rabbitmq/client/test/functional/BindingLifecycleBase.java index 9fffb5c403..f850648bc5 100644 --- a/test/src/com/rabbitmq/client/test/functional/BindingLifecycleBase.java +++ b/test/src/com/rabbitmq/client/test/functional/BindingLifecycleBase.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/CcRoutes.java b/test/src/com/rabbitmq/client/test/functional/CcRoutes.java index 72a7c8cab0..40d7137d02 100644 --- a/test/src/com/rabbitmq/client/test/functional/CcRoutes.java +++ b/test/src/com/rabbitmq/client/test/functional/CcRoutes.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/ClusteredTestBase.java b/test/src/com/rabbitmq/client/test/functional/ClusteredTestBase.java index 45d5038941..a56c43cf25 100644 --- a/test/src/com/rabbitmq/client/test/functional/ClusteredTestBase.java +++ b/test/src/com/rabbitmq/client/test/functional/ClusteredTestBase.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/Confirm.java b/test/src/com/rabbitmq/client/test/functional/Confirm.java index e1fe0ecd6a..d6464aa5fc 100644 --- a/test/src/com/rabbitmq/client/test/functional/Confirm.java +++ b/test/src/com/rabbitmq/client/test/functional/Confirm.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/ConnectionOpen.java b/test/src/com/rabbitmq/client/test/functional/ConnectionOpen.java index df9808f0f4..a4564bf68e 100644 --- a/test/src/com/rabbitmq/client/test/functional/ConnectionOpen.java +++ b/test/src/com/rabbitmq/client/test/functional/ConnectionOpen.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java b/test/src/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java index 7a43ba94d2..9c7eb9455e 100644 --- a/test/src/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java +++ b/test/src/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/DefaultExchange.java b/test/src/com/rabbitmq/client/test/functional/DefaultExchange.java index bb94450b62..985ac148d1 100644 --- a/test/src/com/rabbitmq/client/test/functional/DefaultExchange.java +++ b/test/src/com/rabbitmq/client/test/functional/DefaultExchange.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/DoubleDeletion.java b/test/src/com/rabbitmq/client/test/functional/DoubleDeletion.java index 7ba5e3837e..04f125c86b 100644 --- a/test/src/com/rabbitmq/client/test/functional/DoubleDeletion.java +++ b/test/src/com/rabbitmq/client/test/functional/DoubleDeletion.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/DurableOnTransient.java b/test/src/com/rabbitmq/client/test/functional/DurableOnTransient.java index 48c359ccc7..d5bba6ac9a 100644 --- a/test/src/com/rabbitmq/client/test/functional/DurableOnTransient.java +++ b/test/src/com/rabbitmq/client/test/functional/DurableOnTransient.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/ExchangeDeclare.java b/test/src/com/rabbitmq/client/test/functional/ExchangeDeclare.java index ae84ca804e..5600f88b4b 100644 --- a/test/src/com/rabbitmq/client/test/functional/ExchangeDeclare.java +++ b/test/src/com/rabbitmq/client/test/functional/ExchangeDeclare.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java b/test/src/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java index 2fdd2b552b..43ae1492e2 100644 --- a/test/src/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java +++ b/test/src/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java b/test/src/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java index dae6c6c38a..2d294d6506 100644 --- a/test/src/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java +++ b/test/src/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java b/test/src/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java index b6206bb785..aac119ab08 100644 --- a/test/src/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java +++ b/test/src/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java b/test/src/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java index 36cd989d45..d723ea630e 100644 --- a/test/src/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java +++ b/test/src/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/FrameMax.java b/test/src/com/rabbitmq/client/test/functional/FrameMax.java index f1b88a05ba..be7a0d00d3 100644 --- a/test/src/com/rabbitmq/client/test/functional/FrameMax.java +++ b/test/src/com/rabbitmq/client/test/functional/FrameMax.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/FunctionalTests.java b/test/src/com/rabbitmq/client/test/functional/FunctionalTests.java index 86d4d49752..ab1a3b9303 100644 --- a/test/src/com/rabbitmq/client/test/functional/FunctionalTests.java +++ b/test/src/com/rabbitmq/client/test/functional/FunctionalTests.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/Heartbeat.java b/test/src/com/rabbitmq/client/test/functional/Heartbeat.java index 7de1c85ec2..dfb4ef5091 100644 --- a/test/src/com/rabbitmq/client/test/functional/Heartbeat.java +++ b/test/src/com/rabbitmq/client/test/functional/Heartbeat.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/InternalExchange.java b/test/src/com/rabbitmq/client/test/functional/InternalExchange.java index 295ec83415..351b00b1d8 100644 --- a/test/src/com/rabbitmq/client/test/functional/InternalExchange.java +++ b/test/src/com/rabbitmq/client/test/functional/InternalExchange.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/InvalidAcks.java b/test/src/com/rabbitmq/client/test/functional/InvalidAcks.java index 117451877d..4051e79998 100644 --- a/test/src/com/rabbitmq/client/test/functional/InvalidAcks.java +++ b/test/src/com/rabbitmq/client/test/functional/InvalidAcks.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/InvalidAcksBase.java b/test/src/com/rabbitmq/client/test/functional/InvalidAcksBase.java index fcd7f6cb76..f71ccf1694 100644 --- a/test/src/com/rabbitmq/client/test/functional/InvalidAcksBase.java +++ b/test/src/com/rabbitmq/client/test/functional/InvalidAcksBase.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/InvalidAcksTx.java b/test/src/com/rabbitmq/client/test/functional/InvalidAcksTx.java index e6ef6524ae..6c82b33d0d 100644 --- a/test/src/com/rabbitmq/client/test/functional/InvalidAcksTx.java +++ b/test/src/com/rabbitmq/client/test/functional/InvalidAcksTx.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/Nack.java b/test/src/com/rabbitmq/client/test/functional/Nack.java index 4cc01ff5a8..f2e197187c 100644 --- a/test/src/com/rabbitmq/client/test/functional/Nack.java +++ b/test/src/com/rabbitmq/client/test/functional/Nack.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java b/test/src/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java index cda8ade377..3096c9fc57 100644 --- a/test/src/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java +++ b/test/src/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/PerMessageTTL.java b/test/src/com/rabbitmq/client/test/functional/PerMessageTTL.java index df1f812582..53be989130 100644 --- a/test/src/com/rabbitmq/client/test/functional/PerMessageTTL.java +++ b/test/src/com/rabbitmq/client/test/functional/PerMessageTTL.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/PerQueueTTL.java b/test/src/com/rabbitmq/client/test/functional/PerQueueTTL.java index e6cd19cb47..46c74277b8 100644 --- a/test/src/com/rabbitmq/client/test/functional/PerQueueTTL.java +++ b/test/src/com/rabbitmq/client/test/functional/PerQueueTTL.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/Policies.java b/test/src/com/rabbitmq/client/test/functional/Policies.java index f3c8e1fc83..c450f4e70b 100644 --- a/test/src/com/rabbitmq/client/test/functional/Policies.java +++ b/test/src/com/rabbitmq/client/test/functional/Policies.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/QosTests.java b/test/src/com/rabbitmq/client/test/functional/QosTests.java index 6ee332d062..6b0ce04877 100644 --- a/test/src/com/rabbitmq/client/test/functional/QosTests.java +++ b/test/src/com/rabbitmq/client/test/functional/QosTests.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/QueueExclusivity.java b/test/src/com/rabbitmq/client/test/functional/QueueExclusivity.java index 2f0c07c00d..bcc40305d1 100644 --- a/test/src/com/rabbitmq/client/test/functional/QueueExclusivity.java +++ b/test/src/com/rabbitmq/client/test/functional/QueueExclusivity.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/QueueLease.java b/test/src/com/rabbitmq/client/test/functional/QueueLease.java index 055da31ead..50a4e223e0 100644 --- a/test/src/com/rabbitmq/client/test/functional/QueueLease.java +++ b/test/src/com/rabbitmq/client/test/functional/QueueLease.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/QueueLifecycle.java b/test/src/com/rabbitmq/client/test/functional/QueueLifecycle.java index 43613e64b1..0a00022cb4 100644 --- a/test/src/com/rabbitmq/client/test/functional/QueueLifecycle.java +++ b/test/src/com/rabbitmq/client/test/functional/QueueLifecycle.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/QueueSizeLimit.java b/test/src/com/rabbitmq/client/test/functional/QueueSizeLimit.java index 5b62a022cc..96d858e867 100644 --- a/test/src/com/rabbitmq/client/test/functional/QueueSizeLimit.java +++ b/test/src/com/rabbitmq/client/test/functional/QueueSizeLimit.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/Recover.java b/test/src/com/rabbitmq/client/test/functional/Recover.java index 24d6b7d76a..c9442354c4 100644 --- a/test/src/com/rabbitmq/client/test/functional/Recover.java +++ b/test/src/com/rabbitmq/client/test/functional/Recover.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/Reject.java b/test/src/com/rabbitmq/client/test/functional/Reject.java index 6108841b0a..3c479a53f1 100644 --- a/test/src/com/rabbitmq/client/test/functional/Reject.java +++ b/test/src/com/rabbitmq/client/test/functional/Reject.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java b/test/src/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java index 7554d5b8a0..522a6db719 100644 --- a/test/src/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java +++ b/test/src/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/RequeueOnClose.java b/test/src/com/rabbitmq/client/test/functional/RequeueOnClose.java index 6090c0f4bc..cc9beeec9e 100644 --- a/test/src/com/rabbitmq/client/test/functional/RequeueOnClose.java +++ b/test/src/com/rabbitmq/client/test/functional/RequeueOnClose.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java b/test/src/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java index 8b46908a35..26d2ff7347 100644 --- a/test/src/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java +++ b/test/src/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/Routing.java b/test/src/com/rabbitmq/client/test/functional/Routing.java index a45122cf6c..8c1c440f28 100644 --- a/test/src/com/rabbitmq/client/test/functional/Routing.java +++ b/test/src/com/rabbitmq/client/test/functional/Routing.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/SaslMechanisms.java b/test/src/com/rabbitmq/client/test/functional/SaslMechanisms.java index 77cb0861c8..b8b510ed0c 100644 --- a/test/src/com/rabbitmq/client/test/functional/SaslMechanisms.java +++ b/test/src/com/rabbitmq/client/test/functional/SaslMechanisms.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/Tables.java b/test/src/com/rabbitmq/client/test/functional/Tables.java index 5e5e3351df..1b0239d48b 100644 --- a/test/src/com/rabbitmq/client/test/functional/Tables.java +++ b/test/src/com/rabbitmq/client/test/functional/Tables.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/Transactions.java b/test/src/com/rabbitmq/client/test/functional/Transactions.java index 691cd168b2..40fdedb44a 100644 --- a/test/src/com/rabbitmq/client/test/functional/Transactions.java +++ b/test/src/com/rabbitmq/client/test/functional/Transactions.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java b/test/src/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java index 620fd01a25..31bde6ce15 100644 --- a/test/src/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java +++ b/test/src/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/UnexpectedFrames.java b/test/src/com/rabbitmq/client/test/functional/UnexpectedFrames.java index f5b2c613a1..c69d4b2a07 100644 --- a/test/src/com/rabbitmq/client/test/functional/UnexpectedFrames.java +++ b/test/src/com/rabbitmq/client/test/functional/UnexpectedFrames.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/UserIDHeader.java b/test/src/com/rabbitmq/client/test/functional/UserIDHeader.java index 213f149940..0ca80c8985 100644 --- a/test/src/com/rabbitmq/client/test/functional/UserIDHeader.java +++ b/test/src/com/rabbitmq/client/test/functional/UserIDHeader.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/performance/CLIHelper.java b/test/src/com/rabbitmq/client/test/performance/CLIHelper.java index 39e1f9de68..04d3887f31 100644 --- a/test/src/com/rabbitmq/client/test/performance/CLIHelper.java +++ b/test/src/com/rabbitmq/client/test/performance/CLIHelper.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/performance/QosScaling.java b/test/src/com/rabbitmq/client/test/performance/QosScaling.java index d3b820138b..09839d9e94 100644 --- a/test/src/com/rabbitmq/client/test/performance/QosScaling.java +++ b/test/src/com/rabbitmq/client/test/performance/QosScaling.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/performance/ScalabilityTest.java b/test/src/com/rabbitmq/client/test/performance/ScalabilityTest.java index 96003f88eb..d38e073ec2 100644 --- a/test/src/com/rabbitmq/client/test/performance/ScalabilityTest.java +++ b/test/src/com/rabbitmq/client/test/performance/ScalabilityTest.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/performance/StressManagement.java b/test/src/com/rabbitmq/client/test/performance/StressManagement.java index 193464d28b..595b1d1adb 100644 --- a/test/src/com/rabbitmq/client/test/performance/StressManagement.java +++ b/test/src/com/rabbitmq/client/test/performance/StressManagement.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.performance; diff --git a/test/src/com/rabbitmq/client/test/server/AbsentQueue.java b/test/src/com/rabbitmq/client/test/server/AbsentQueue.java index 47e256201c..d62d5acb2b 100644 --- a/test/src/com/rabbitmq/client/test/server/AbsentQueue.java +++ b/test/src/com/rabbitmq/client/test/server/AbsentQueue.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java b/test/src/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java index 683e067ebc..586dad58b6 100644 --- a/test/src/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java +++ b/test/src/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/server/BlockedConnection.java b/test/src/com/rabbitmq/client/test/server/BlockedConnection.java index b0779f31b7..23239725fa 100644 --- a/test/src/com/rabbitmq/client/test/server/BlockedConnection.java +++ b/test/src/com/rabbitmq/client/test/server/BlockedConnection.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/server/Bug19219Test.java b/test/src/com/rabbitmq/client/test/server/Bug19219Test.java index 895096663e..a01fa96dbe 100644 --- a/test/src/com/rabbitmq/client/test/server/Bug19219Test.java +++ b/test/src/com/rabbitmq/client/test/server/Bug19219Test.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.server; diff --git a/test/src/com/rabbitmq/client/test/server/DurableBindingLifecycle.java b/test/src/com/rabbitmq/client/test/server/DurableBindingLifecycle.java index 0944edccf8..27e262f537 100644 --- a/test/src/com/rabbitmq/client/test/server/DurableBindingLifecycle.java +++ b/test/src/com/rabbitmq/client/test/server/DurableBindingLifecycle.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java b/test/src/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java index 630d06af84..9bb659e207 100644 --- a/test/src/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java +++ b/test/src/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.server; diff --git a/test/src/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java b/test/src/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java index af3b954803..d6108c5db5 100644 --- a/test/src/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java +++ b/test/src/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/server/HATests.java b/test/src/com/rabbitmq/client/test/server/HATests.java index 80d970bdad..3a2f7ea038 100644 --- a/test/src/com/rabbitmq/client/test/server/HATests.java +++ b/test/src/com/rabbitmq/client/test/server/HATests.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.server; diff --git a/test/src/com/rabbitmq/client/test/server/MemoryAlarms.java b/test/src/com/rabbitmq/client/test/server/MemoryAlarms.java index 6822f65f7a..12dd19a424 100644 --- a/test/src/com/rabbitmq/client/test/server/MemoryAlarms.java +++ b/test/src/com/rabbitmq/client/test/server/MemoryAlarms.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.server; diff --git a/test/src/com/rabbitmq/client/test/server/MessageRecovery.java b/test/src/com/rabbitmq/client/test/server/MessageRecovery.java index 100058370a..45c33c242c 100644 --- a/test/src/com/rabbitmq/client/test/server/MessageRecovery.java +++ b/test/src/com/rabbitmq/client/test/server/MessageRecovery.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. package com.rabbitmq.client.test.server; diff --git a/test/src/com/rabbitmq/client/test/server/Permissions.java b/test/src/com/rabbitmq/client/test/server/Permissions.java index ca7a4f568f..0993499751 100644 --- a/test/src/com/rabbitmq/client/test/server/Permissions.java +++ b/test/src/com/rabbitmq/client/test/server/Permissions.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/server/ServerTests.java b/test/src/com/rabbitmq/client/test/server/ServerTests.java index 30b923bfa9..bc86b366ab 100644 --- a/test/src/com/rabbitmq/client/test/server/ServerTests.java +++ b/test/src/com/rabbitmq/client/test/server/ServerTests.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java b/test/src/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java index c463a1d463..9354a7084e 100644 --- a/test/src/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java +++ b/test/src/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.ssl; diff --git a/test/src/com/rabbitmq/client/test/ssl/SSLTests.java b/test/src/com/rabbitmq/client/test/ssl/SSLTests.java index 9df495670a..4263bd241c 100644 --- a/test/src/com/rabbitmq/client/test/ssl/SSLTests.java +++ b/test/src/com/rabbitmq/client/test/ssl/SSLTests.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/ssl/UnverifiedConnection.java b/test/src/com/rabbitmq/client/test/ssl/UnverifiedConnection.java index f9378efe7d..785f8cae15 100644 --- a/test/src/com/rabbitmq/client/test/ssl/UnverifiedConnection.java +++ b/test/src/com/rabbitmq/client/test/ssl/UnverifiedConnection.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.ssl; diff --git a/test/src/com/rabbitmq/client/test/ssl/VerifiedConnection.java b/test/src/com/rabbitmq/client/test/ssl/VerifiedConnection.java index c48763f82c..8a6ef3d617 100644 --- a/test/src/com/rabbitmq/client/test/ssl/VerifiedConnection.java +++ b/test/src/com/rabbitmq/client/test/ssl/VerifiedConnection.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.ssl; diff --git a/test/src/com/rabbitmq/examples/BufferPerformanceMetrics.java b/test/src/com/rabbitmq/examples/BufferPerformanceMetrics.java index 61accc0533..919bd9c107 100644 --- a/test/src/com/rabbitmq/examples/BufferPerformanceMetrics.java +++ b/test/src/com/rabbitmq/examples/BufferPerformanceMetrics.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/ChannelCreationPerformance.java b/test/src/com/rabbitmq/examples/ChannelCreationPerformance.java index 32dcf624f0..ca34ba1a2e 100644 --- a/test/src/com/rabbitmq/examples/ChannelCreationPerformance.java +++ b/test/src/com/rabbitmq/examples/ChannelCreationPerformance.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/ConfirmDontLoseMessages.java b/test/src/com/rabbitmq/examples/ConfirmDontLoseMessages.java index 61c37d70af..996a498264 100644 --- a/test/src/com/rabbitmq/examples/ConfirmDontLoseMessages.java +++ b/test/src/com/rabbitmq/examples/ConfirmDontLoseMessages.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/examples/ConsumerMain.java b/test/src/com/rabbitmq/examples/ConsumerMain.java index 15ec65d656..aaadf0dd49 100644 --- a/test/src/com/rabbitmq/examples/ConsumerMain.java +++ b/test/src/com/rabbitmq/examples/ConsumerMain.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/examples/FileConsumer.java b/test/src/com/rabbitmq/examples/FileConsumer.java index 2a3602b48a..613961a2cb 100644 --- a/test/src/com/rabbitmq/examples/FileConsumer.java +++ b/test/src/com/rabbitmq/examples/FileConsumer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/examples/FileProducer.java b/test/src/com/rabbitmq/examples/FileProducer.java index fe6bb9eb00..fb051a43c0 100644 --- a/test/src/com/rabbitmq/examples/FileProducer.java +++ b/test/src/com/rabbitmq/examples/FileProducer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/examples/HelloClient.java b/test/src/com/rabbitmq/examples/HelloClient.java index e21b597d9e..9eba3c0f15 100644 --- a/test/src/com/rabbitmq/examples/HelloClient.java +++ b/test/src/com/rabbitmq/examples/HelloClient.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/HelloJsonClient.java b/test/src/com/rabbitmq/examples/HelloJsonClient.java index dbed068004..8917cc51b8 100644 --- a/test/src/com/rabbitmq/examples/HelloJsonClient.java +++ b/test/src/com/rabbitmq/examples/HelloJsonClient.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/HelloJsonServer.java b/test/src/com/rabbitmq/examples/HelloJsonServer.java index 19329a40ab..d8628739d6 100644 --- a/test/src/com/rabbitmq/examples/HelloJsonServer.java +++ b/test/src/com/rabbitmq/examples/HelloJsonServer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/HelloJsonService.java b/test/src/com/rabbitmq/examples/HelloJsonService.java index 77d45ff084..51b0d7924a 100644 --- a/test/src/com/rabbitmq/examples/HelloJsonService.java +++ b/test/src/com/rabbitmq/examples/HelloJsonService.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/examples/HelloServer.java b/test/src/com/rabbitmq/examples/HelloServer.java index 703132e375..2117230aaf 100644 --- a/test/src/com/rabbitmq/examples/HelloServer.java +++ b/test/src/com/rabbitmq/examples/HelloServer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/examples/LogTail.java b/test/src/com/rabbitmq/examples/LogTail.java index b2d39a220b..16e693fba0 100644 --- a/test/src/com/rabbitmq/examples/LogTail.java +++ b/test/src/com/rabbitmq/examples/LogTail.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/MulticastMain.java b/test/src/com/rabbitmq/examples/MulticastMain.java index d33621116c..2c9b3b43c6 100644 --- a/test/src/com/rabbitmq/examples/MulticastMain.java +++ b/test/src/com/rabbitmq/examples/MulticastMain.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/PerQueueTTLGetter.java b/test/src/com/rabbitmq/examples/PerQueueTTLGetter.java index 8705ae0c4a..63d9434727 100644 --- a/test/src/com/rabbitmq/examples/PerQueueTTLGetter.java +++ b/test/src/com/rabbitmq/examples/PerQueueTTLGetter.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/PerQueueTTLPublisher.java b/test/src/com/rabbitmq/examples/PerQueueTTLPublisher.java index 533abdd0e2..c66161f4d2 100644 --- a/test/src/com/rabbitmq/examples/PerQueueTTLPublisher.java +++ b/test/src/com/rabbitmq/examples/PerQueueTTLPublisher.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/PerfTest.java b/test/src/com/rabbitmq/examples/PerfTest.java index 6381e6ecdf..e7caf63038 100644 --- a/test/src/com/rabbitmq/examples/PerfTest.java +++ b/test/src/com/rabbitmq/examples/PerfTest.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/PerfTestMulti.java b/test/src/com/rabbitmq/examples/PerfTestMulti.java index cf6f86cdda..0edbfe9820 100644 --- a/test/src/com/rabbitmq/examples/PerfTestMulti.java +++ b/test/src/com/rabbitmq/examples/PerfTestMulti.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/ProducerMain.java b/test/src/com/rabbitmq/examples/ProducerMain.java index c2dedb0df1..66613f03f5 100644 --- a/test/src/com/rabbitmq/examples/ProducerMain.java +++ b/test/src/com/rabbitmq/examples/ProducerMain.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/SendString.java b/test/src/com/rabbitmq/examples/SendString.java index be6cde2ae8..3b1b9c1db0 100644 --- a/test/src/com/rabbitmq/examples/SendString.java +++ b/test/src/com/rabbitmq/examples/SendString.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/SimpleConsumer.java b/test/src/com/rabbitmq/examples/SimpleConsumer.java index 51154f3abe..2d0ab97740 100644 --- a/test/src/com/rabbitmq/examples/SimpleConsumer.java +++ b/test/src/com/rabbitmq/examples/SimpleConsumer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/SimpleProducer.java b/test/src/com/rabbitmq/examples/SimpleProducer.java index eb85dbdbfa..70b54e9025 100644 --- a/test/src/com/rabbitmq/examples/SimpleProducer.java +++ b/test/src/com/rabbitmq/examples/SimpleProducer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/SimpleTopicConsumer.java b/test/src/com/rabbitmq/examples/SimpleTopicConsumer.java index c0a8f22200..a50e0956a6 100644 --- a/test/src/com/rabbitmq/examples/SimpleTopicConsumer.java +++ b/test/src/com/rabbitmq/examples/SimpleTopicConsumer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/SimpleTopicProducer.java b/test/src/com/rabbitmq/examples/SimpleTopicProducer.java index 4257e2a91d..335934f3c7 100644 --- a/test/src/com/rabbitmq/examples/SimpleTopicProducer.java +++ b/test/src/com/rabbitmq/examples/SimpleTopicProducer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/SpammyTopicProducer.java b/test/src/com/rabbitmq/examples/SpammyTopicProducer.java index 4e49935c0f..a3d7915d33 100644 --- a/test/src/com/rabbitmq/examples/SpammyTopicProducer.java +++ b/test/src/com/rabbitmq/examples/SpammyTopicProducer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/StressPersister.java b/test/src/com/rabbitmq/examples/StressPersister.java index 0de1861410..48fcc23adb 100644 --- a/test/src/com/rabbitmq/examples/StressPersister.java +++ b/test/src/com/rabbitmq/examples/StressPersister.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/TestMain.java b/test/src/com/rabbitmq/examples/TestMain.java index c80b0b271c..0ef4cdb2aa 100644 --- a/test/src/com/rabbitmq/examples/TestMain.java +++ b/test/src/com/rabbitmq/examples/TestMain.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/examples/TracerConcurrencyTest.java b/test/src/com/rabbitmq/examples/TracerConcurrencyTest.java index 64df3c1829..01eb9f55aa 100644 --- a/test/src/com/rabbitmq/examples/TracerConcurrencyTest.java +++ b/test/src/com/rabbitmq/examples/TracerConcurrencyTest.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/perf/Broker.java b/test/src/com/rabbitmq/examples/perf/Broker.java index c4d77e4d24..eabc659fb4 100644 --- a/test/src/com/rabbitmq/examples/perf/Broker.java +++ b/test/src/com/rabbitmq/examples/perf/Broker.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/BrokerValue.java b/test/src/com/rabbitmq/examples/perf/BrokerValue.java index 53b9fbe402..0631b9b8ac 100644 --- a/test/src/com/rabbitmq/examples/perf/BrokerValue.java +++ b/test/src/com/rabbitmq/examples/perf/BrokerValue.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/BrokerVariable.java b/test/src/com/rabbitmq/examples/perf/BrokerVariable.java index b4b7566fdd..17335ee033 100644 --- a/test/src/com/rabbitmq/examples/perf/BrokerVariable.java +++ b/test/src/com/rabbitmq/examples/perf/BrokerVariable.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/Consumer.java b/test/src/com/rabbitmq/examples/perf/Consumer.java index 6ef9327814..cdecad8dd7 100644 --- a/test/src/com/rabbitmq/examples/perf/Consumer.java +++ b/test/src/com/rabbitmq/examples/perf/Consumer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/MulticastParams.java b/test/src/com/rabbitmq/examples/perf/MulticastParams.java index ba15758c5c..b54f142895 100644 --- a/test/src/com/rabbitmq/examples/perf/MulticastParams.java +++ b/test/src/com/rabbitmq/examples/perf/MulticastParams.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/MulticastSet.java b/test/src/com/rabbitmq/examples/perf/MulticastSet.java index 4a7338192f..293bed2cbf 100644 --- a/test/src/com/rabbitmq/examples/perf/MulticastSet.java +++ b/test/src/com/rabbitmq/examples/perf/MulticastSet.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/MulticastValue.java b/test/src/com/rabbitmq/examples/perf/MulticastValue.java index 001f158abd..ca5ad0e558 100644 --- a/test/src/com/rabbitmq/examples/perf/MulticastValue.java +++ b/test/src/com/rabbitmq/examples/perf/MulticastValue.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/MulticastVariable.java b/test/src/com/rabbitmq/examples/perf/MulticastVariable.java index 5308c34abe..5a1368442c 100644 --- a/test/src/com/rabbitmq/examples/perf/MulticastVariable.java +++ b/test/src/com/rabbitmq/examples/perf/MulticastVariable.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/Producer.java b/test/src/com/rabbitmq/examples/perf/Producer.java index 628c23321b..26a9c19404 100644 --- a/test/src/com/rabbitmq/examples/perf/Producer.java +++ b/test/src/com/rabbitmq/examples/perf/Producer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/RateVsLatencyScenario.java b/test/src/com/rabbitmq/examples/perf/RateVsLatencyScenario.java index 4692d54fbf..32ba0fafd2 100644 --- a/test/src/com/rabbitmq/examples/perf/RateVsLatencyScenario.java +++ b/test/src/com/rabbitmq/examples/perf/RateVsLatencyScenario.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/Scenario.java b/test/src/com/rabbitmq/examples/perf/Scenario.java index 63c841d510..f680ccb71c 100644 --- a/test/src/com/rabbitmq/examples/perf/Scenario.java +++ b/test/src/com/rabbitmq/examples/perf/Scenario.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/ScenarioStats.java b/test/src/com/rabbitmq/examples/perf/ScenarioStats.java index d18126ca3d..e8fc10b223 100644 --- a/test/src/com/rabbitmq/examples/perf/ScenarioStats.java +++ b/test/src/com/rabbitmq/examples/perf/ScenarioStats.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/SimpleScenario.java b/test/src/com/rabbitmq/examples/perf/SimpleScenario.java index 31e09cf79f..7b7d83d98b 100644 --- a/test/src/com/rabbitmq/examples/perf/SimpleScenario.java +++ b/test/src/com/rabbitmq/examples/perf/SimpleScenario.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/SimpleScenarioStats.java b/test/src/com/rabbitmq/examples/perf/SimpleScenarioStats.java index 0a6e9c5b9c..80f3ee03ba 100644 --- a/test/src/com/rabbitmq/examples/perf/SimpleScenarioStats.java +++ b/test/src/com/rabbitmq/examples/perf/SimpleScenarioStats.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/Stats.java b/test/src/com/rabbitmq/examples/perf/Stats.java index ea7547824e..8ddf8664ce 100644 --- a/test/src/com/rabbitmq/examples/perf/Stats.java +++ b/test/src/com/rabbitmq/examples/perf/Stats.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/Variable.java b/test/src/com/rabbitmq/examples/perf/Variable.java index 771c607ec9..1157ca691a 100644 --- a/test/src/com/rabbitmq/examples/perf/Variable.java +++ b/test/src/com/rabbitmq/examples/perf/Variable.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/VariableValue.java b/test/src/com/rabbitmq/examples/perf/VariableValue.java index d76bfa5a72..edb27131c7 100644 --- a/test/src/com/rabbitmq/examples/perf/VariableValue.java +++ b/test/src/com/rabbitmq/examples/perf/VariableValue.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/VaryingScenario.java b/test/src/com/rabbitmq/examples/perf/VaryingScenario.java index 1eafa38bf1..9a9512d67e 100644 --- a/test/src/com/rabbitmq/examples/perf/VaryingScenario.java +++ b/test/src/com/rabbitmq/examples/perf/VaryingScenario.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/VaryingScenarioStats.java b/test/src/com/rabbitmq/examples/perf/VaryingScenarioStats.java index f7f97e0abe..49be18b106 100644 --- a/test/src/com/rabbitmq/examples/perf/VaryingScenarioStats.java +++ b/test/src/com/rabbitmq/examples/perf/VaryingScenarioStats.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/tools/Host.java b/test/src/com/rabbitmq/tools/Host.java index ef8bb41084..83f2bfb6f1 100644 --- a/test/src/com/rabbitmq/tools/Host.java +++ b/test/src/com/rabbitmq/tools/Host.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/utility/IntAllocatorTests.java b/test/src/com/rabbitmq/utility/IntAllocatorTests.java index 5caf10cd29..77fe5ab3c4 100644 --- a/test/src/com/rabbitmq/utility/IntAllocatorTests.java +++ b/test/src/com/rabbitmq/utility/IntAllocatorTests.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2011-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2011-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.utility; From d95bc836fbcb1e4dc4266914d8bf770df065f258 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Sun, 24 May 2015 05:25:16 +0300 Subject: [PATCH 0028/2114] (c) year --- LICENSE-MPL-RabbitMQ | 2 +- codegen.py | 4 ++-- src/com/rabbitmq/client/Address.java | 2 +- src/com/rabbitmq/client/AlreadyClosedException.java | 2 +- src/com/rabbitmq/client/AuthenticationFailureException.java | 2 +- src/com/rabbitmq/client/BasicProperties.java | 2 +- src/com/rabbitmq/client/BlockedListener.java | 2 +- src/com/rabbitmq/client/Channel.java | 2 +- src/com/rabbitmq/client/Command.java | 2 +- src/com/rabbitmq/client/ConfirmListener.java | 2 +- src/com/rabbitmq/client/Connection.java | 2 +- src/com/rabbitmq/client/ConnectionFactory.java | 2 +- src/com/rabbitmq/client/Consumer.java | 2 +- src/com/rabbitmq/client/ConsumerCancelledException.java | 2 +- src/com/rabbitmq/client/ContentHeader.java | 2 +- src/com/rabbitmq/client/DefaultConsumer.java | 2 +- src/com/rabbitmq/client/DefaultSaslConfig.java | 2 +- src/com/rabbitmq/client/Envelope.java | 2 +- src/com/rabbitmq/client/ExceptionHandler.java | 2 +- src/com/rabbitmq/client/FlowListener.java | 2 +- src/com/rabbitmq/client/GetResponse.java | 2 +- src/com/rabbitmq/client/JDKSaslConfig.java | 2 +- src/com/rabbitmq/client/LongString.java | 2 +- src/com/rabbitmq/client/MalformedFrameException.java | 2 +- src/com/rabbitmq/client/MapRpcServer.java | 2 +- src/com/rabbitmq/client/MessageProperties.java | 2 +- src/com/rabbitmq/client/Method.java | 2 +- src/com/rabbitmq/client/MissedHeartbeatException.java | 2 +- src/com/rabbitmq/client/NullTrustManager.java | 2 +- .../client/PossibleAuthenticationFailureException.java | 2 +- src/com/rabbitmq/client/ProtocolVersionMismatchException.java | 2 +- src/com/rabbitmq/client/QueueingConsumer.java | 2 +- src/com/rabbitmq/client/ReturnListener.java | 2 +- src/com/rabbitmq/client/RpcClient.java | 2 +- src/com/rabbitmq/client/RpcServer.java | 2 +- src/com/rabbitmq/client/SaslConfig.java | 2 +- src/com/rabbitmq/client/SaslMechanism.java | 2 +- src/com/rabbitmq/client/ShutdownListener.java | 2 +- src/com/rabbitmq/client/ShutdownNotifier.java | 2 +- src/com/rabbitmq/client/ShutdownSignalException.java | 2 +- src/com/rabbitmq/client/StringRpcServer.java | 2 +- src/com/rabbitmq/client/UnexpectedFrameError.java | 2 +- src/com/rabbitmq/client/UnexpectedMethodError.java | 2 +- src/com/rabbitmq/client/UnknownClassOrMethodId.java | 2 +- src/com/rabbitmq/client/impl/AMQBasicProperties.java | 2 +- src/com/rabbitmq/client/impl/AMQChannel.java | 2 +- src/com/rabbitmq/client/impl/AMQCommand.java | 2 +- src/com/rabbitmq/client/impl/AMQConnection.java | 4 ++-- src/com/rabbitmq/client/impl/AMQContentHeader.java | 2 +- src/com/rabbitmq/client/impl/CRDemoMechanism.java | 2 +- src/com/rabbitmq/client/impl/ChannelManager.java | 2 +- src/com/rabbitmq/client/impl/ChannelN.java | 2 +- src/com/rabbitmq/client/impl/ClientVersion.java.in | 2 +- src/com/rabbitmq/client/impl/CommandAssembler.java | 2 +- src/com/rabbitmq/client/impl/ConsumerDispatcher.java | 2 +- src/com/rabbitmq/client/impl/ConsumerWorkService.java | 2 +- src/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java | 2 +- src/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java | 2 +- src/com/rabbitmq/client/impl/DefaultExceptionHandler.java | 2 +- src/com/rabbitmq/client/impl/ExternalMechanism.java | 2 +- src/com/rabbitmq/client/impl/Frame.java | 2 +- src/com/rabbitmq/client/impl/FrameHandler.java | 2 +- src/com/rabbitmq/client/impl/HeartbeatSender.java | 2 +- src/com/rabbitmq/client/impl/LongStringHelper.java | 2 +- src/com/rabbitmq/client/impl/Method.java | 2 +- src/com/rabbitmq/client/impl/MethodArgumentReader.java | 2 +- src/com/rabbitmq/client/impl/MethodArgumentWriter.java | 2 +- src/com/rabbitmq/client/impl/PlainMechanism.java | 2 +- src/com/rabbitmq/client/impl/ShutdownNotifierComponent.java | 2 +- src/com/rabbitmq/client/impl/SocketFrameHandler.java | 2 +- src/com/rabbitmq/client/impl/TruncatedInputStream.java | 2 +- src/com/rabbitmq/client/impl/UnknownChannelException.java | 2 +- src/com/rabbitmq/client/impl/ValueReader.java | 2 +- src/com/rabbitmq/client/impl/ValueWriter.java | 2 +- src/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java | 2 +- src/com/rabbitmq/client/impl/Version.java | 2 +- src/com/rabbitmq/tools/Tracer.java | 2 +- src/com/rabbitmq/tools/json/JSONReader.java | 2 +- src/com/rabbitmq/tools/json/JSONSerializable.java | 2 +- src/com/rabbitmq/tools/json/JSONUtil.java | 2 +- src/com/rabbitmq/tools/json/JSONWriter.java | 2 +- src/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java | 2 +- src/com/rabbitmq/tools/jsonrpc/JsonRpcException.java | 2 +- src/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java | 2 +- src/com/rabbitmq/tools/jsonrpc/ParameterDescription.java | 2 +- src/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java | 2 +- src/com/rabbitmq/tools/jsonrpc/ServiceDescription.java | 2 +- src/com/rabbitmq/utility/BlockingCell.java | 2 +- src/com/rabbitmq/utility/BlockingValueOrException.java | 2 +- src/com/rabbitmq/utility/IntAllocator.java | 2 +- src/com/rabbitmq/utility/SensibleClone.java | 2 +- src/com/rabbitmq/utility/SingleShotLinearTimer.java | 2 +- src/com/rabbitmq/utility/Utility.java | 2 +- src/com/rabbitmq/utility/ValueOrException.java | 2 +- test/src/com/rabbitmq/client/test/AMQBuilderApiTest.java | 2 +- test/src/com/rabbitmq/client/test/AMQConnectionTest.java | 2 +- test/src/com/rabbitmq/client/test/AmqpUriTest.java | 2 +- test/src/com/rabbitmq/client/test/BlockingCellTest.java | 2 +- test/src/com/rabbitmq/client/test/BrokenFramesTest.java | 2 +- test/src/com/rabbitmq/client/test/BrokerTestCase.java | 2 +- test/src/com/rabbitmq/client/test/Bug20004Test.java | 2 +- .../rabbitmq/client/test/ChannelNumberAllocationTests.java | 2 +- test/src/com/rabbitmq/client/test/ClientTests.java | 2 +- test/src/com/rabbitmq/client/test/ClonePropertiesTest.java | 2 +- test/src/com/rabbitmq/client/test/CloseInMainLoop.java | 2 +- test/src/com/rabbitmq/client/test/ConfirmBase.java | 2 +- test/src/com/rabbitmq/client/test/JSONReadWriteTest.java | 2 +- test/src/com/rabbitmq/client/test/MultiThreadedChannel.java | 2 +- .../rabbitmq/client/test/QueueingConsumerShutdownTests.java | 2 +- test/src/com/rabbitmq/client/test/TableTest.java | 2 +- .../com/rabbitmq/client/test/TruncatedInputStreamTest.java | 2 +- test/src/com/rabbitmq/client/test/ValueOrExceptionTest.java | 2 +- .../rabbitmq/client/test/functional/AbstractRejectTest.java | 2 +- .../rabbitmq/client/test/functional/AlternateExchange.java | 2 +- .../com/rabbitmq/client/test/functional/BindingLifecycle.java | 2 +- .../rabbitmq/client/test/functional/BindingLifecycleBase.java | 2 +- test/src/com/rabbitmq/client/test/functional/CcRoutes.java | 2 +- .../rabbitmq/client/test/functional/ClusteredTestBase.java | 2 +- test/src/com/rabbitmq/client/test/functional/Confirm.java | 2 +- .../com/rabbitmq/client/test/functional/ConnectionOpen.java | 2 +- .../client/test/functional/ConsumerCancelNotification.java | 2 +- .../com/rabbitmq/client/test/functional/DefaultExchange.java | 2 +- .../com/rabbitmq/client/test/functional/DoubleDeletion.java | 2 +- .../rabbitmq/client/test/functional/DurableOnTransient.java | 2 +- .../com/rabbitmq/client/test/functional/ExchangeDeclare.java | 2 +- .../client/test/functional/ExchangeDeleteIfUnused.java | 2 +- .../client/test/functional/ExchangeEquivalenceBase.java | 2 +- .../client/test/functional/ExchangeExchangeBindings.java | 2 +- .../test/functional/ExchangeExchangeBindingsAutoDelete.java | 2 +- test/src/com/rabbitmq/client/test/functional/FrameMax.java | 2 +- .../com/rabbitmq/client/test/functional/FunctionalTests.java | 2 +- test/src/com/rabbitmq/client/test/functional/Heartbeat.java | 2 +- .../com/rabbitmq/client/test/functional/InternalExchange.java | 2 +- test/src/com/rabbitmq/client/test/functional/InvalidAcks.java | 2 +- .../com/rabbitmq/client/test/functional/InvalidAcksBase.java | 2 +- .../com/rabbitmq/client/test/functional/InvalidAcksTx.java | 2 +- test/src/com/rabbitmq/client/test/functional/Nack.java | 2 +- .../rabbitmq/client/test/functional/NoRequeueOnCancel.java | 2 +- .../com/rabbitmq/client/test/functional/PerMessageTTL.java | 2 +- test/src/com/rabbitmq/client/test/functional/PerQueueTTL.java | 2 +- test/src/com/rabbitmq/client/test/functional/Policies.java | 2 +- test/src/com/rabbitmq/client/test/functional/QosTests.java | 2 +- .../com/rabbitmq/client/test/functional/QueueExclusivity.java | 2 +- test/src/com/rabbitmq/client/test/functional/QueueLease.java | 2 +- .../com/rabbitmq/client/test/functional/QueueLifecycle.java | 2 +- .../com/rabbitmq/client/test/functional/QueueSizeLimit.java | 2 +- test/src/com/rabbitmq/client/test/functional/Recover.java | 2 +- test/src/com/rabbitmq/client/test/functional/Reject.java | 2 +- .../client/test/functional/RequeueOnChannelClose.java | 2 +- .../com/rabbitmq/client/test/functional/RequeueOnClose.java | 2 +- .../client/test/functional/RequeueOnConnectionClose.java | 2 +- test/src/com/rabbitmq/client/test/functional/Routing.java | 2 +- .../com/rabbitmq/client/test/functional/SaslMechanisms.java | 2 +- test/src/com/rabbitmq/client/test/functional/Tables.java | 2 +- .../src/com/rabbitmq/client/test/functional/Transactions.java | 2 +- .../client/test/functional/UnbindAutoDeleteExchange.java | 2 +- .../com/rabbitmq/client/test/functional/UnexpectedFrames.java | 2 +- .../src/com/rabbitmq/client/test/functional/UserIDHeader.java | 2 +- test/src/com/rabbitmq/client/test/performance/CLIHelper.java | 2 +- test/src/com/rabbitmq/client/test/performance/QosScaling.java | 2 +- .../com/rabbitmq/client/test/performance/ScalabilityTest.java | 2 +- .../rabbitmq/client/test/performance/StressManagement.java | 2 +- test/src/com/rabbitmq/client/test/server/AbsentQueue.java | 2 +- .../client/test/server/AlternateExchangeEquivalence.java | 2 +- .../com/rabbitmq/client/test/server/BlockedConnection.java | 2 +- test/src/com/rabbitmq/client/test/server/Bug19219Test.java | 2 +- .../rabbitmq/client/test/server/DurableBindingLifecycle.java | 2 +- .../client/test/server/EffectVisibilityCrossNodeTest.java | 2 +- .../rabbitmq/client/test/server/ExclusiveQueueDurability.java | 2 +- test/src/com/rabbitmq/client/test/server/HATests.java | 2 +- test/src/com/rabbitmq/client/test/server/MemoryAlarms.java | 2 +- test/src/com/rabbitmq/client/test/server/MessageRecovery.java | 2 +- test/src/com/rabbitmq/client/test/server/Permissions.java | 2 +- test/src/com/rabbitmq/client/test/server/ServerTests.java | 2 +- .../com/rabbitmq/client/test/ssl/BadVerifiedConnection.java | 2 +- test/src/com/rabbitmq/client/test/ssl/SSLTests.java | 2 +- .../com/rabbitmq/client/test/ssl/UnverifiedConnection.java | 2 +- test/src/com/rabbitmq/client/test/ssl/VerifiedConnection.java | 2 +- test/src/com/rabbitmq/examples/BufferPerformanceMetrics.java | 2 +- .../src/com/rabbitmq/examples/ChannelCreationPerformance.java | 2 +- test/src/com/rabbitmq/examples/ConfirmDontLoseMessages.java | 2 +- test/src/com/rabbitmq/examples/ConsumerMain.java | 2 +- test/src/com/rabbitmq/examples/FileConsumer.java | 2 +- test/src/com/rabbitmq/examples/FileProducer.java | 2 +- test/src/com/rabbitmq/examples/HelloClient.java | 2 +- test/src/com/rabbitmq/examples/HelloJsonClient.java | 2 +- test/src/com/rabbitmq/examples/HelloJsonServer.java | 2 +- test/src/com/rabbitmq/examples/HelloJsonService.java | 2 +- test/src/com/rabbitmq/examples/HelloServer.java | 2 +- test/src/com/rabbitmq/examples/LogTail.java | 2 +- test/src/com/rabbitmq/examples/MulticastMain.java | 2 +- test/src/com/rabbitmq/examples/PerQueueTTLGetter.java | 2 +- test/src/com/rabbitmq/examples/PerQueueTTLPublisher.java | 2 +- test/src/com/rabbitmq/examples/PerfTest.java | 2 +- test/src/com/rabbitmq/examples/PerfTestMulti.java | 2 +- test/src/com/rabbitmq/examples/ProducerMain.java | 2 +- test/src/com/rabbitmq/examples/SendString.java | 2 +- test/src/com/rabbitmq/examples/SimpleConsumer.java | 2 +- test/src/com/rabbitmq/examples/SimpleProducer.java | 2 +- test/src/com/rabbitmq/examples/SimpleTopicConsumer.java | 2 +- test/src/com/rabbitmq/examples/SimpleTopicProducer.java | 2 +- test/src/com/rabbitmq/examples/SpammyTopicProducer.java | 2 +- test/src/com/rabbitmq/examples/StressPersister.java | 2 +- test/src/com/rabbitmq/examples/TestMain.java | 2 +- test/src/com/rabbitmq/examples/TracerConcurrencyTest.java | 2 +- test/src/com/rabbitmq/examples/perf/Broker.java | 2 +- test/src/com/rabbitmq/examples/perf/BrokerValue.java | 2 +- test/src/com/rabbitmq/examples/perf/BrokerVariable.java | 2 +- test/src/com/rabbitmq/examples/perf/Consumer.java | 2 +- test/src/com/rabbitmq/examples/perf/MulticastParams.java | 2 +- test/src/com/rabbitmq/examples/perf/MulticastSet.java | 2 +- test/src/com/rabbitmq/examples/perf/MulticastValue.java | 2 +- test/src/com/rabbitmq/examples/perf/MulticastVariable.java | 2 +- test/src/com/rabbitmq/examples/perf/Producer.java | 2 +- .../src/com/rabbitmq/examples/perf/RateVsLatencyScenario.java | 2 +- test/src/com/rabbitmq/examples/perf/Scenario.java | 2 +- test/src/com/rabbitmq/examples/perf/ScenarioStats.java | 2 +- test/src/com/rabbitmq/examples/perf/SimpleScenario.java | 2 +- test/src/com/rabbitmq/examples/perf/SimpleScenarioStats.java | 2 +- test/src/com/rabbitmq/examples/perf/Stats.java | 2 +- test/src/com/rabbitmq/examples/perf/Variable.java | 2 +- test/src/com/rabbitmq/examples/perf/VariableValue.java | 2 +- test/src/com/rabbitmq/examples/perf/VaryingScenario.java | 2 +- test/src/com/rabbitmq/examples/perf/VaryingScenarioStats.java | 2 +- test/src/com/rabbitmq/tools/Host.java | 2 +- test/src/com/rabbitmq/utility/IntAllocatorTests.java | 2 +- 226 files changed, 228 insertions(+), 228 deletions(-) diff --git a/LICENSE-MPL-RabbitMQ b/LICENSE-MPL-RabbitMQ index b0325a0e49..096b2c4eaa 100644 --- a/LICENSE-MPL-RabbitMQ +++ b/LICENSE-MPL-RabbitMQ @@ -447,7 +447,7 @@ EXHIBIT A -Mozilla Public License. The Original Code is RabbitMQ. The Initial Developer of the Original Code is GoPivotal, Inc. - Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. + Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. Alternatively, the contents of this file may be used under the terms of the GNU General Public License version 2 (the "GPL2"), or diff --git a/codegen.py b/codegen.py index 24e2e52364..fe7db666dd 100644 --- a/codegen.py +++ b/codegen.py @@ -11,7 +11,7 @@ ## The Original Code is RabbitMQ. ## ## The Initial Developer of the Original Code is GoPivotal, Inc. -## Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +## Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. ## from __future__ import nested_scopes @@ -143,7 +143,7 @@ def printFileHeader(): // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // """ diff --git a/src/com/rabbitmq/client/Address.java b/src/com/rabbitmq/client/Address.java index 40df18801d..6c7283f8c1 100644 --- a/src/com/rabbitmq/client/Address.java +++ b/src/com/rabbitmq/client/Address.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/AlreadyClosedException.java b/src/com/rabbitmq/client/AlreadyClosedException.java index f5ff58bdfd..e587001c50 100644 --- a/src/com/rabbitmq/client/AlreadyClosedException.java +++ b/src/com/rabbitmq/client/AlreadyClosedException.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/AuthenticationFailureException.java b/src/com/rabbitmq/client/AuthenticationFailureException.java index e2dbe64de0..ceb5e85a62 100644 --- a/src/com/rabbitmq/client/AuthenticationFailureException.java +++ b/src/com/rabbitmq/client/AuthenticationFailureException.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2013-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2013-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/BasicProperties.java b/src/com/rabbitmq/client/BasicProperties.java index a1b7346382..021b17d087 100644 --- a/src/com/rabbitmq/client/BasicProperties.java +++ b/src/com/rabbitmq/client/BasicProperties.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/BlockedListener.java b/src/com/rabbitmq/client/BlockedListener.java index bf7728c3d2..ca002185b7 100644 --- a/src/com/rabbitmq/client/BlockedListener.java +++ b/src/com/rabbitmq/client/BlockedListener.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/Channel.java b/src/com/rabbitmq/client/Channel.java index 0d24a6eb58..30affe72f2 100644 --- a/src/com/rabbitmq/client/Channel.java +++ b/src/com/rabbitmq/client/Channel.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/Command.java b/src/com/rabbitmq/client/Command.java index 4938f15521..b5007b542d 100644 --- a/src/com/rabbitmq/client/Command.java +++ b/src/com/rabbitmq/client/Command.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/ConfirmListener.java b/src/com/rabbitmq/client/ConfirmListener.java index 7109de0b76..e6f113b16c 100644 --- a/src/com/rabbitmq/client/ConfirmListener.java +++ b/src/com/rabbitmq/client/ConfirmListener.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/Connection.java b/src/com/rabbitmq/client/Connection.java index 37c0758176..b216cacb04 100644 --- a/src/com/rabbitmq/client/Connection.java +++ b/src/com/rabbitmq/client/Connection.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/ConnectionFactory.java b/src/com/rabbitmq/client/ConnectionFactory.java index f5632dac4b..e4163c6916 100644 --- a/src/com/rabbitmq/client/ConnectionFactory.java +++ b/src/com/rabbitmq/client/ConnectionFactory.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/Consumer.java b/src/com/rabbitmq/client/Consumer.java index d1c43f2c70..8279088163 100644 --- a/src/com/rabbitmq/client/Consumer.java +++ b/src/com/rabbitmq/client/Consumer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/ConsumerCancelledException.java b/src/com/rabbitmq/client/ConsumerCancelledException.java index a322f73fcc..a711cb2b9b 100644 --- a/src/com/rabbitmq/client/ConsumerCancelledException.java +++ b/src/com/rabbitmq/client/ConsumerCancelledException.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/ContentHeader.java b/src/com/rabbitmq/client/ContentHeader.java index b8d1ae4b6e..b8cb340c26 100644 --- a/src/com/rabbitmq/client/ContentHeader.java +++ b/src/com/rabbitmq/client/ContentHeader.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/DefaultConsumer.java b/src/com/rabbitmq/client/DefaultConsumer.java index f526d379eb..7026d8107b 100644 --- a/src/com/rabbitmq/client/DefaultConsumer.java +++ b/src/com/rabbitmq/client/DefaultConsumer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/DefaultSaslConfig.java b/src/com/rabbitmq/client/DefaultSaslConfig.java index 9888f69432..b86b1c2e73 100644 --- a/src/com/rabbitmq/client/DefaultSaslConfig.java +++ b/src/com/rabbitmq/client/DefaultSaslConfig.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/Envelope.java b/src/com/rabbitmq/client/Envelope.java index eb5d797556..56269734b0 100644 --- a/src/com/rabbitmq/client/Envelope.java +++ b/src/com/rabbitmq/client/Envelope.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/ExceptionHandler.java b/src/com/rabbitmq/client/ExceptionHandler.java index f304a1ae84..8160ca1b5e 100644 --- a/src/com/rabbitmq/client/ExceptionHandler.java +++ b/src/com/rabbitmq/client/ExceptionHandler.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/FlowListener.java b/src/com/rabbitmq/client/FlowListener.java index df09664844..b6b1ba8594 100644 --- a/src/com/rabbitmq/client/FlowListener.java +++ b/src/com/rabbitmq/client/FlowListener.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/GetResponse.java b/src/com/rabbitmq/client/GetResponse.java index 3c77cec022..1d06d2774a 100644 --- a/src/com/rabbitmq/client/GetResponse.java +++ b/src/com/rabbitmq/client/GetResponse.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/JDKSaslConfig.java b/src/com/rabbitmq/client/JDKSaslConfig.java index 8e57795044..f19d45c970 100644 --- a/src/com/rabbitmq/client/JDKSaslConfig.java +++ b/src/com/rabbitmq/client/JDKSaslConfig.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/LongString.java b/src/com/rabbitmq/client/LongString.java index 28d5a24385..b503281750 100644 --- a/src/com/rabbitmq/client/LongString.java +++ b/src/com/rabbitmq/client/LongString.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/MalformedFrameException.java b/src/com/rabbitmq/client/MalformedFrameException.java index 12700140ab..cde6fed01a 100644 --- a/src/com/rabbitmq/client/MalformedFrameException.java +++ b/src/com/rabbitmq/client/MalformedFrameException.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/MapRpcServer.java b/src/com/rabbitmq/client/MapRpcServer.java index 426332b690..b150a5c09e 100644 --- a/src/com/rabbitmq/client/MapRpcServer.java +++ b/src/com/rabbitmq/client/MapRpcServer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/MessageProperties.java b/src/com/rabbitmq/client/MessageProperties.java index 0b30657101..2624b8c734 100644 --- a/src/com/rabbitmq/client/MessageProperties.java +++ b/src/com/rabbitmq/client/MessageProperties.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/Method.java b/src/com/rabbitmq/client/Method.java index dfafe9a596..c5b62f7dc4 100644 --- a/src/com/rabbitmq/client/Method.java +++ b/src/com/rabbitmq/client/Method.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/MissedHeartbeatException.java b/src/com/rabbitmq/client/MissedHeartbeatException.java index 34afccf9d2..1808cde295 100644 --- a/src/com/rabbitmq/client/MissedHeartbeatException.java +++ b/src/com/rabbitmq/client/MissedHeartbeatException.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/NullTrustManager.java b/src/com/rabbitmq/client/NullTrustManager.java index 8aef053bf3..7ac9a213dd 100644 --- a/src/com/rabbitmq/client/NullTrustManager.java +++ b/src/com/rabbitmq/client/NullTrustManager.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/PossibleAuthenticationFailureException.java b/src/com/rabbitmq/client/PossibleAuthenticationFailureException.java index 33b9dcdb69..a5858dd64c 100644 --- a/src/com/rabbitmq/client/PossibleAuthenticationFailureException.java +++ b/src/com/rabbitmq/client/PossibleAuthenticationFailureException.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/ProtocolVersionMismatchException.java b/src/com/rabbitmq/client/ProtocolVersionMismatchException.java index f247ad68d2..fd187b833f 100644 --- a/src/com/rabbitmq/client/ProtocolVersionMismatchException.java +++ b/src/com/rabbitmq/client/ProtocolVersionMismatchException.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/QueueingConsumer.java b/src/com/rabbitmq/client/QueueingConsumer.java index d4e9b1fc4e..c2cdd346a2 100644 --- a/src/com/rabbitmq/client/QueueingConsumer.java +++ b/src/com/rabbitmq/client/QueueingConsumer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/ReturnListener.java b/src/com/rabbitmq/client/ReturnListener.java index b634a2c5c9..64017ee12f 100644 --- a/src/com/rabbitmq/client/ReturnListener.java +++ b/src/com/rabbitmq/client/ReturnListener.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/RpcClient.java b/src/com/rabbitmq/client/RpcClient.java index 48c944954d..10e8ea2c62 100644 --- a/src/com/rabbitmq/client/RpcClient.java +++ b/src/com/rabbitmq/client/RpcClient.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/RpcServer.java b/src/com/rabbitmq/client/RpcServer.java index 73ccceb4e8..f900b7877c 100644 --- a/src/com/rabbitmq/client/RpcServer.java +++ b/src/com/rabbitmq/client/RpcServer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/SaslConfig.java b/src/com/rabbitmq/client/SaslConfig.java index 87420cbd0e..382df58ae2 100644 --- a/src/com/rabbitmq/client/SaslConfig.java +++ b/src/com/rabbitmq/client/SaslConfig.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/SaslMechanism.java b/src/com/rabbitmq/client/SaslMechanism.java index 59b2538c83..c869d38eda 100644 --- a/src/com/rabbitmq/client/SaslMechanism.java +++ b/src/com/rabbitmq/client/SaslMechanism.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/ShutdownListener.java b/src/com/rabbitmq/client/ShutdownListener.java index 0bfd890315..72b99a194b 100644 --- a/src/com/rabbitmq/client/ShutdownListener.java +++ b/src/com/rabbitmq/client/ShutdownListener.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/ShutdownNotifier.java b/src/com/rabbitmq/client/ShutdownNotifier.java index e2ce0b8838..a8471b7827 100644 --- a/src/com/rabbitmq/client/ShutdownNotifier.java +++ b/src/com/rabbitmq/client/ShutdownNotifier.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/ShutdownSignalException.java b/src/com/rabbitmq/client/ShutdownSignalException.java index c90df1ea2e..5787e67322 100644 --- a/src/com/rabbitmq/client/ShutdownSignalException.java +++ b/src/com/rabbitmq/client/ShutdownSignalException.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/StringRpcServer.java b/src/com/rabbitmq/client/StringRpcServer.java index 9ea120c6ab..0c7b2e01d7 100644 --- a/src/com/rabbitmq/client/StringRpcServer.java +++ b/src/com/rabbitmq/client/StringRpcServer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/UnexpectedFrameError.java b/src/com/rabbitmq/client/UnexpectedFrameError.java index 08df6d4d11..a86cda5cb3 100644 --- a/src/com/rabbitmq/client/UnexpectedFrameError.java +++ b/src/com/rabbitmq/client/UnexpectedFrameError.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/UnexpectedMethodError.java b/src/com/rabbitmq/client/UnexpectedMethodError.java index a474d2bde3..38cff48085 100644 --- a/src/com/rabbitmq/client/UnexpectedMethodError.java +++ b/src/com/rabbitmq/client/UnexpectedMethodError.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/UnknownClassOrMethodId.java b/src/com/rabbitmq/client/UnknownClassOrMethodId.java index 058d3f6b89..ffc4629ca5 100644 --- a/src/com/rabbitmq/client/UnknownClassOrMethodId.java +++ b/src/com/rabbitmq/client/UnknownClassOrMethodId.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/impl/AMQBasicProperties.java b/src/com/rabbitmq/client/impl/AMQBasicProperties.java index 53acbe3e13..32a390256b 100644 --- a/src/com/rabbitmq/client/impl/AMQBasicProperties.java +++ b/src/com/rabbitmq/client/impl/AMQBasicProperties.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/AMQChannel.java b/src/com/rabbitmq/client/impl/AMQChannel.java index 57249855a8..3f7c091ba5 100644 --- a/src/com/rabbitmq/client/impl/AMQChannel.java +++ b/src/com/rabbitmq/client/impl/AMQChannel.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/impl/AMQCommand.java b/src/com/rabbitmq/client/impl/AMQCommand.java index 88aecee324..d682b9abff 100644 --- a/src/com/rabbitmq/client/impl/AMQCommand.java +++ b/src/com/rabbitmq/client/impl/AMQCommand.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/AMQConnection.java b/src/com/rabbitmq/client/impl/AMQConnection.java index 6d8348073e..d2fd4524b0 100644 --- a/src/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/com/rabbitmq/client/impl/AMQConnection.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; @@ -52,7 +52,7 @@ import com.rabbitmq.utility.BlockingCell; final class Copyright { - final static String COPYRIGHT="Copyright (C) 2007-2014 GoPivotal, Inc."; + final static String COPYRIGHT="Copyright (C) 2007-2015 Pivotal Software, Inc."; final static String LICENSE="Licensed under the MPL. See http://www.rabbitmq.com/"; } diff --git a/src/com/rabbitmq/client/impl/AMQContentHeader.java b/src/com/rabbitmq/client/impl/AMQContentHeader.java index 8a16bb7899..58eb8fe0b9 100644 --- a/src/com/rabbitmq/client/impl/AMQContentHeader.java +++ b/src/com/rabbitmq/client/impl/AMQContentHeader.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/CRDemoMechanism.java b/src/com/rabbitmq/client/impl/CRDemoMechanism.java index 45fb70053c..90e3dac51c 100644 --- a/src/com/rabbitmq/client/impl/CRDemoMechanism.java +++ b/src/com/rabbitmq/client/impl/CRDemoMechanism.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/ChannelManager.java b/src/com/rabbitmq/client/impl/ChannelManager.java index 85e30a4e20..e77afcf7ae 100644 --- a/src/com/rabbitmq/client/impl/ChannelManager.java +++ b/src/com/rabbitmq/client/impl/ChannelManager.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/ChannelN.java b/src/com/rabbitmq/client/impl/ChannelN.java index b1720cf368..9711941929 100644 --- a/src/com/rabbitmq/client/impl/ChannelN.java +++ b/src/com/rabbitmq/client/impl/ChannelN.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/ClientVersion.java.in b/src/com/rabbitmq/client/impl/ClientVersion.java.in index 8eb0a13fe3..0aaaa5b6f0 100644 --- a/src/com/rabbitmq/client/impl/ClientVersion.java.in +++ b/src/com/rabbitmq/client/impl/ClientVersion.java.in @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/CommandAssembler.java b/src/com/rabbitmq/client/impl/CommandAssembler.java index de74152249..16bf8242c7 100644 --- a/src/com/rabbitmq/client/impl/CommandAssembler.java +++ b/src/com/rabbitmq/client/impl/CommandAssembler.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/ConsumerDispatcher.java b/src/com/rabbitmq/client/impl/ConsumerDispatcher.java index 64c7f7eb79..f5bf62b6e1 100644 --- a/src/com/rabbitmq/client/impl/ConsumerDispatcher.java +++ b/src/com/rabbitmq/client/impl/ConsumerDispatcher.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2011-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2011-2015 Pivotal Software, Inc. All rights reserved. package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/ConsumerWorkService.java b/src/com/rabbitmq/client/impl/ConsumerWorkService.java index 83dc8fd25b..a38c63e0c2 100644 --- a/src/com/rabbitmq/client/impl/ConsumerWorkService.java +++ b/src/com/rabbitmq/client/impl/ConsumerWorkService.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2011-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2011-2015 Pivotal Software, Inc. All rights reserved. package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java b/src/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java index c3f69baa26..b66d01e862 100644 --- a/src/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java +++ b/src/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java b/src/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java index e869b48dfb..fcf4b0d7b6 100644 --- a/src/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java +++ b/src/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/impl/DefaultExceptionHandler.java b/src/com/rabbitmq/client/impl/DefaultExceptionHandler.java index cef33fd384..63b31c1784 100644 --- a/src/com/rabbitmq/client/impl/DefaultExceptionHandler.java +++ b/src/com/rabbitmq/client/impl/DefaultExceptionHandler.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/ExternalMechanism.java b/src/com/rabbitmq/client/impl/ExternalMechanism.java index fce3ab1df5..698eccf483 100644 --- a/src/com/rabbitmq/client/impl/ExternalMechanism.java +++ b/src/com/rabbitmq/client/impl/ExternalMechanism.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/Frame.java b/src/com/rabbitmq/client/impl/Frame.java index 5b3fc491ef..8c83640929 100644 --- a/src/com/rabbitmq/client/impl/Frame.java +++ b/src/com/rabbitmq/client/impl/Frame.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/FrameHandler.java b/src/com/rabbitmq/client/impl/FrameHandler.java index 47602f638e..705d67629d 100644 --- a/src/com/rabbitmq/client/impl/FrameHandler.java +++ b/src/com/rabbitmq/client/impl/FrameHandler.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/HeartbeatSender.java b/src/com/rabbitmq/client/impl/HeartbeatSender.java index bbd0c7c196..893597d0a5 100644 --- a/src/com/rabbitmq/client/impl/HeartbeatSender.java +++ b/src/com/rabbitmq/client/impl/HeartbeatSender.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/impl/LongStringHelper.java b/src/com/rabbitmq/client/impl/LongStringHelper.java index 8d18b70ecd..bf7d609660 100644 --- a/src/com/rabbitmq/client/impl/LongStringHelper.java +++ b/src/com/rabbitmq/client/impl/LongStringHelper.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/impl/Method.java b/src/com/rabbitmq/client/impl/Method.java index 0a7ce83808..db6ba559b4 100644 --- a/src/com/rabbitmq/client/impl/Method.java +++ b/src/com/rabbitmq/client/impl/Method.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/impl/MethodArgumentReader.java b/src/com/rabbitmq/client/impl/MethodArgumentReader.java index c7c1973212..85fbf95675 100644 --- a/src/com/rabbitmq/client/impl/MethodArgumentReader.java +++ b/src/com/rabbitmq/client/impl/MethodArgumentReader.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/impl/MethodArgumentWriter.java b/src/com/rabbitmq/client/impl/MethodArgumentWriter.java index 2143ea9b16..f52e605818 100644 --- a/src/com/rabbitmq/client/impl/MethodArgumentWriter.java +++ b/src/com/rabbitmq/client/impl/MethodArgumentWriter.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/impl/PlainMechanism.java b/src/com/rabbitmq/client/impl/PlainMechanism.java index b134dd5c0f..7eb0fa9cf0 100644 --- a/src/com/rabbitmq/client/impl/PlainMechanism.java +++ b/src/com/rabbitmq/client/impl/PlainMechanism.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/ShutdownNotifierComponent.java b/src/com/rabbitmq/client/impl/ShutdownNotifierComponent.java index e48edf5ef5..5e11fad487 100644 --- a/src/com/rabbitmq/client/impl/ShutdownNotifierComponent.java +++ b/src/com/rabbitmq/client/impl/ShutdownNotifierComponent.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/impl/SocketFrameHandler.java b/src/com/rabbitmq/client/impl/SocketFrameHandler.java index 004cc2b32d..565497e6ae 100644 --- a/src/com/rabbitmq/client/impl/SocketFrameHandler.java +++ b/src/com/rabbitmq/client/impl/SocketFrameHandler.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/TruncatedInputStream.java b/src/com/rabbitmq/client/impl/TruncatedInputStream.java index 767ffa235d..52dade475c 100644 --- a/src/com/rabbitmq/client/impl/TruncatedInputStream.java +++ b/src/com/rabbitmq/client/impl/TruncatedInputStream.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/impl/UnknownChannelException.java b/src/com/rabbitmq/client/impl/UnknownChannelException.java index 4a0de7eb3f..d7730f559a 100644 --- a/src/com/rabbitmq/client/impl/UnknownChannelException.java +++ b/src/com/rabbitmq/client/impl/UnknownChannelException.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/impl/ValueReader.java b/src/com/rabbitmq/client/impl/ValueReader.java index 7f171a63eb..d8bfbcb05b 100644 --- a/src/com/rabbitmq/client/impl/ValueReader.java +++ b/src/com/rabbitmq/client/impl/ValueReader.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/impl/ValueWriter.java b/src/com/rabbitmq/client/impl/ValueWriter.java index 05e3e0a723..f5eb70a41d 100644 --- a/src/com/rabbitmq/client/impl/ValueWriter.java +++ b/src/com/rabbitmq/client/impl/ValueWriter.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java b/src/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java index 7520e20abc..b7a2ed408f 100644 --- a/src/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java +++ b/src/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java @@ -1,5 +1,5 @@ /* - * Modifications Copyright 2014 GoPivotal, Inc and licenced as per + * Modifications Copyright 2015 Pivotal Software, Inc and licenced as per * the rest of the RabbitMQ Java client. */ diff --git a/src/com/rabbitmq/client/impl/Version.java b/src/com/rabbitmq/client/impl/Version.java index 3735e678ed..8f28027a44 100644 --- a/src/com/rabbitmq/client/impl/Version.java +++ b/src/com/rabbitmq/client/impl/Version.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/tools/Tracer.java b/src/com/rabbitmq/tools/Tracer.java index 4c99ff9308..cf04a16390 100644 --- a/src/com/rabbitmq/tools/Tracer.java +++ b/src/com/rabbitmq/tools/Tracer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.tools; diff --git a/src/com/rabbitmq/tools/json/JSONReader.java b/src/com/rabbitmq/tools/json/JSONReader.java index 57ddcbd3b9..349fa3a739 100644 --- a/src/com/rabbitmq/tools/json/JSONReader.java +++ b/src/com/rabbitmq/tools/json/JSONReader.java @@ -1,6 +1,6 @@ /* Copyright (c) 2006-2007 Frank Carver - Copyright (c) 2007-2014 GoPivotal, Inc. All Rights Reserved + Copyright (c) 2007-2015 Pivotal Software, Inc. All Rights Reserved Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/src/com/rabbitmq/tools/json/JSONSerializable.java b/src/com/rabbitmq/tools/json/JSONSerializable.java index ad9f32a304..6c219ad093 100644 --- a/src/com/rabbitmq/tools/json/JSONSerializable.java +++ b/src/com/rabbitmq/tools/json/JSONSerializable.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/tools/json/JSONUtil.java b/src/com/rabbitmq/tools/json/JSONUtil.java index 7076dd6b5a..2c71c6263d 100644 --- a/src/com/rabbitmq/tools/json/JSONUtil.java +++ b/src/com/rabbitmq/tools/json/JSONUtil.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/tools/json/JSONWriter.java b/src/com/rabbitmq/tools/json/JSONWriter.java index 7df0913ac5..e6a3ebd845 100644 --- a/src/com/rabbitmq/tools/json/JSONWriter.java +++ b/src/com/rabbitmq/tools/json/JSONWriter.java @@ -1,6 +1,6 @@ /* Copyright (c) 2006-2007 Frank Carver - Copyright (c) 2007-2014 GoPivotal, Inc. All Rights Reserved + Copyright (c) 2007-2015 Pivotal Software, Inc. All Rights Reserved Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/src/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java b/src/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java index de8ba54ff0..5579a5acbf 100644 --- a/src/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java +++ b/src/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.tools.jsonrpc; diff --git a/src/com/rabbitmq/tools/jsonrpc/JsonRpcException.java b/src/com/rabbitmq/tools/jsonrpc/JsonRpcException.java index 0da710896c..c21315ae6a 100644 --- a/src/com/rabbitmq/tools/jsonrpc/JsonRpcException.java +++ b/src/com/rabbitmq/tools/jsonrpc/JsonRpcException.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java b/src/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java index ac0d6a2d99..72725bbdfc 100644 --- a/src/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java +++ b/src/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/tools/jsonrpc/ParameterDescription.java b/src/com/rabbitmq/tools/jsonrpc/ParameterDescription.java index 407a978691..7ae45f06c3 100644 --- a/src/com/rabbitmq/tools/jsonrpc/ParameterDescription.java +++ b/src/com/rabbitmq/tools/jsonrpc/ParameterDescription.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java b/src/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java index 842396397a..1d1419e3b4 100644 --- a/src/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java +++ b/src/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/tools/jsonrpc/ServiceDescription.java b/src/com/rabbitmq/tools/jsonrpc/ServiceDescription.java index 332526d984..0b8143b7e7 100644 --- a/src/com/rabbitmq/tools/jsonrpc/ServiceDescription.java +++ b/src/com/rabbitmq/tools/jsonrpc/ServiceDescription.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/utility/BlockingCell.java b/src/com/rabbitmq/utility/BlockingCell.java index 74f545e81e..a278811df6 100644 --- a/src/com/rabbitmq/utility/BlockingCell.java +++ b/src/com/rabbitmq/utility/BlockingCell.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/utility/BlockingValueOrException.java b/src/com/rabbitmq/utility/BlockingValueOrException.java index 12d299bc83..0d761255e5 100644 --- a/src/com/rabbitmq/utility/BlockingValueOrException.java +++ b/src/com/rabbitmq/utility/BlockingValueOrException.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.utility; diff --git a/src/com/rabbitmq/utility/IntAllocator.java b/src/com/rabbitmq/utility/IntAllocator.java index 85a32130d8..160e730259 100644 --- a/src/com/rabbitmq/utility/IntAllocator.java +++ b/src/com/rabbitmq/utility/IntAllocator.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.utility; diff --git a/src/com/rabbitmq/utility/SensibleClone.java b/src/com/rabbitmq/utility/SensibleClone.java index a21868b0de..25ad1a40c1 100644 --- a/src/com/rabbitmq/utility/SensibleClone.java +++ b/src/com/rabbitmq/utility/SensibleClone.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.utility; diff --git a/src/com/rabbitmq/utility/SingleShotLinearTimer.java b/src/com/rabbitmq/utility/SingleShotLinearTimer.java index 638ed84bee..8b4cbd11f8 100644 --- a/src/com/rabbitmq/utility/SingleShotLinearTimer.java +++ b/src/com/rabbitmq/utility/SingleShotLinearTimer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/utility/Utility.java b/src/com/rabbitmq/utility/Utility.java index c85dcdd081..a11470bd4d 100644 --- a/src/com/rabbitmq/utility/Utility.java +++ b/src/com/rabbitmq/utility/Utility.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.utility; diff --git a/src/com/rabbitmq/utility/ValueOrException.java b/src/com/rabbitmq/utility/ValueOrException.java index 4a9e549448..a69a2fa57e 100644 --- a/src/com/rabbitmq/utility/ValueOrException.java +++ b/src/com/rabbitmq/utility/ValueOrException.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.utility; diff --git a/test/src/com/rabbitmq/client/test/AMQBuilderApiTest.java b/test/src/com/rabbitmq/client/test/AMQBuilderApiTest.java index 20381a13f3..a9754038f3 100644 --- a/test/src/com/rabbitmq/client/test/AMQBuilderApiTest.java +++ b/test/src/com/rabbitmq/client/test/AMQBuilderApiTest.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // // package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/AMQConnectionTest.java b/test/src/com/rabbitmq/client/test/AMQConnectionTest.java index d229fba8d9..27821bda9f 100644 --- a/test/src/com/rabbitmq/client/test/AMQConnectionTest.java +++ b/test/src/com/rabbitmq/client/test/AMQConnectionTest.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/AmqpUriTest.java b/test/src/com/rabbitmq/client/test/AmqpUriTest.java index a477de02c9..2b38d7aefa 100644 --- a/test/src/com/rabbitmq/client/test/AmqpUriTest.java +++ b/test/src/com/rabbitmq/client/test/AmqpUriTest.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2011-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2011-2015 Pivotal Software, Inc. All rights reserved. // // package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/BlockingCellTest.java b/test/src/com/rabbitmq/client/test/BlockingCellTest.java index 267f6dd06f..0fe8be87d3 100644 --- a/test/src/com/rabbitmq/client/test/BlockingCellTest.java +++ b/test/src/com/rabbitmq/client/test/BlockingCellTest.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/BrokenFramesTest.java b/test/src/com/rabbitmq/client/test/BrokenFramesTest.java index 7e57ffec7b..b11830c18a 100644 --- a/test/src/com/rabbitmq/client/test/BrokenFramesTest.java +++ b/test/src/com/rabbitmq/client/test/BrokenFramesTest.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/BrokerTestCase.java b/test/src/com/rabbitmq/client/test/BrokerTestCase.java index 88030ed5ac..656c59893f 100644 --- a/test/src/com/rabbitmq/client/test/BrokerTestCase.java +++ b/test/src/com/rabbitmq/client/test/BrokerTestCase.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/Bug20004Test.java b/test/src/com/rabbitmq/client/test/Bug20004Test.java index 45947150e6..60470d43d9 100644 --- a/test/src/com/rabbitmq/client/test/Bug20004Test.java +++ b/test/src/com/rabbitmq/client/test/Bug20004Test.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/ChannelNumberAllocationTests.java b/test/src/com/rabbitmq/client/test/ChannelNumberAllocationTests.java index 13d00eb361..73aa26f86f 100644 --- a/test/src/com/rabbitmq/client/test/ChannelNumberAllocationTests.java +++ b/test/src/com/rabbitmq/client/test/ChannelNumberAllocationTests.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/ClientTests.java b/test/src/com/rabbitmq/client/test/ClientTests.java index d618da89f1..7df48df58a 100644 --- a/test/src/com/rabbitmq/client/test/ClientTests.java +++ b/test/src/com/rabbitmq/client/test/ClientTests.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/ClonePropertiesTest.java b/test/src/com/rabbitmq/client/test/ClonePropertiesTest.java index 186ad84ea1..5e7ea4a6db 100644 --- a/test/src/com/rabbitmq/client/test/ClonePropertiesTest.java +++ b/test/src/com/rabbitmq/client/test/ClonePropertiesTest.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/CloseInMainLoop.java b/test/src/com/rabbitmq/client/test/CloseInMainLoop.java index c94fc488d5..eca14245bc 100644 --- a/test/src/com/rabbitmq/client/test/CloseInMainLoop.java +++ b/test/src/com/rabbitmq/client/test/CloseInMainLoop.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/ConfirmBase.java b/test/src/com/rabbitmq/client/test/ConfirmBase.java index 576005aeb3..584d03d79c 100644 --- a/test/src/com/rabbitmq/client/test/ConfirmBase.java +++ b/test/src/com/rabbitmq/client/test/ConfirmBase.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2011-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2011-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/JSONReadWriteTest.java b/test/src/com/rabbitmq/client/test/JSONReadWriteTest.java index 4b1a9d6aa5..8b681bd322 100644 --- a/test/src/com/rabbitmq/client/test/JSONReadWriteTest.java +++ b/test/src/com/rabbitmq/client/test/JSONReadWriteTest.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/MultiThreadedChannel.java b/test/src/com/rabbitmq/client/test/MultiThreadedChannel.java index b1a08c4e71..12d01b3153 100644 --- a/test/src/com/rabbitmq/client/test/MultiThreadedChannel.java +++ b/test/src/com/rabbitmq/client/test/MultiThreadedChannel.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/QueueingConsumerShutdownTests.java b/test/src/com/rabbitmq/client/test/QueueingConsumerShutdownTests.java index abd4be91ff..39bb7fa0a5 100644 --- a/test/src/com/rabbitmq/client/test/QueueingConsumerShutdownTests.java +++ b/test/src/com/rabbitmq/client/test/QueueingConsumerShutdownTests.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/TableTest.java b/test/src/com/rabbitmq/client/test/TableTest.java index 9a40188295..4a38ba6262 100644 --- a/test/src/com/rabbitmq/client/test/TableTest.java +++ b/test/src/com/rabbitmq/client/test/TableTest.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/TruncatedInputStreamTest.java b/test/src/com/rabbitmq/client/test/TruncatedInputStreamTest.java index 72cf4f3b71..dbef4d4b22 100644 --- a/test/src/com/rabbitmq/client/test/TruncatedInputStreamTest.java +++ b/test/src/com/rabbitmq/client/test/TruncatedInputStreamTest.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/ValueOrExceptionTest.java b/test/src/com/rabbitmq/client/test/ValueOrExceptionTest.java index e8a54103f1..7fad3dc0fb 100644 --- a/test/src/com/rabbitmq/client/test/ValueOrExceptionTest.java +++ b/test/src/com/rabbitmq/client/test/ValueOrExceptionTest.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/functional/AbstractRejectTest.java b/test/src/com/rabbitmq/client/test/functional/AbstractRejectTest.java index 6922f8caf2..5d60af44d0 100644 --- a/test/src/com/rabbitmq/client/test/functional/AbstractRejectTest.java +++ b/test/src/com/rabbitmq/client/test/functional/AbstractRejectTest.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/AlternateExchange.java b/test/src/com/rabbitmq/client/test/functional/AlternateExchange.java index 89e7919617..5b908c9541 100644 --- a/test/src/com/rabbitmq/client/test/functional/AlternateExchange.java +++ b/test/src/com/rabbitmq/client/test/functional/AlternateExchange.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/BindingLifecycle.java b/test/src/com/rabbitmq/client/test/functional/BindingLifecycle.java index 53ba458660..15af445c7e 100644 --- a/test/src/com/rabbitmq/client/test/functional/BindingLifecycle.java +++ b/test/src/com/rabbitmq/client/test/functional/BindingLifecycle.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/BindingLifecycleBase.java b/test/src/com/rabbitmq/client/test/functional/BindingLifecycleBase.java index 9fffb5c403..f850648bc5 100644 --- a/test/src/com/rabbitmq/client/test/functional/BindingLifecycleBase.java +++ b/test/src/com/rabbitmq/client/test/functional/BindingLifecycleBase.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/CcRoutes.java b/test/src/com/rabbitmq/client/test/functional/CcRoutes.java index 72a7c8cab0..40d7137d02 100644 --- a/test/src/com/rabbitmq/client/test/functional/CcRoutes.java +++ b/test/src/com/rabbitmq/client/test/functional/CcRoutes.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/ClusteredTestBase.java b/test/src/com/rabbitmq/client/test/functional/ClusteredTestBase.java index 45d5038941..a56c43cf25 100644 --- a/test/src/com/rabbitmq/client/test/functional/ClusteredTestBase.java +++ b/test/src/com/rabbitmq/client/test/functional/ClusteredTestBase.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/Confirm.java b/test/src/com/rabbitmq/client/test/functional/Confirm.java index e1fe0ecd6a..d6464aa5fc 100644 --- a/test/src/com/rabbitmq/client/test/functional/Confirm.java +++ b/test/src/com/rabbitmq/client/test/functional/Confirm.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/ConnectionOpen.java b/test/src/com/rabbitmq/client/test/functional/ConnectionOpen.java index df9808f0f4..a4564bf68e 100644 --- a/test/src/com/rabbitmq/client/test/functional/ConnectionOpen.java +++ b/test/src/com/rabbitmq/client/test/functional/ConnectionOpen.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java b/test/src/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java index 7a43ba94d2..9c7eb9455e 100644 --- a/test/src/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java +++ b/test/src/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/DefaultExchange.java b/test/src/com/rabbitmq/client/test/functional/DefaultExchange.java index bb94450b62..985ac148d1 100644 --- a/test/src/com/rabbitmq/client/test/functional/DefaultExchange.java +++ b/test/src/com/rabbitmq/client/test/functional/DefaultExchange.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/DoubleDeletion.java b/test/src/com/rabbitmq/client/test/functional/DoubleDeletion.java index 7ba5e3837e..04f125c86b 100644 --- a/test/src/com/rabbitmq/client/test/functional/DoubleDeletion.java +++ b/test/src/com/rabbitmq/client/test/functional/DoubleDeletion.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/DurableOnTransient.java b/test/src/com/rabbitmq/client/test/functional/DurableOnTransient.java index 48c359ccc7..d5bba6ac9a 100644 --- a/test/src/com/rabbitmq/client/test/functional/DurableOnTransient.java +++ b/test/src/com/rabbitmq/client/test/functional/DurableOnTransient.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/ExchangeDeclare.java b/test/src/com/rabbitmq/client/test/functional/ExchangeDeclare.java index ae84ca804e..5600f88b4b 100644 --- a/test/src/com/rabbitmq/client/test/functional/ExchangeDeclare.java +++ b/test/src/com/rabbitmq/client/test/functional/ExchangeDeclare.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java b/test/src/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java index 2fdd2b552b..43ae1492e2 100644 --- a/test/src/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java +++ b/test/src/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java b/test/src/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java index dae6c6c38a..2d294d6506 100644 --- a/test/src/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java +++ b/test/src/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java b/test/src/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java index b6206bb785..aac119ab08 100644 --- a/test/src/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java +++ b/test/src/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java b/test/src/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java index 36cd989d45..d723ea630e 100644 --- a/test/src/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java +++ b/test/src/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/FrameMax.java b/test/src/com/rabbitmq/client/test/functional/FrameMax.java index f1b88a05ba..be7a0d00d3 100644 --- a/test/src/com/rabbitmq/client/test/functional/FrameMax.java +++ b/test/src/com/rabbitmq/client/test/functional/FrameMax.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/FunctionalTests.java b/test/src/com/rabbitmq/client/test/functional/FunctionalTests.java index 86d4d49752..ab1a3b9303 100644 --- a/test/src/com/rabbitmq/client/test/functional/FunctionalTests.java +++ b/test/src/com/rabbitmq/client/test/functional/FunctionalTests.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/Heartbeat.java b/test/src/com/rabbitmq/client/test/functional/Heartbeat.java index 7de1c85ec2..dfb4ef5091 100644 --- a/test/src/com/rabbitmq/client/test/functional/Heartbeat.java +++ b/test/src/com/rabbitmq/client/test/functional/Heartbeat.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/InternalExchange.java b/test/src/com/rabbitmq/client/test/functional/InternalExchange.java index 295ec83415..351b00b1d8 100644 --- a/test/src/com/rabbitmq/client/test/functional/InternalExchange.java +++ b/test/src/com/rabbitmq/client/test/functional/InternalExchange.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/InvalidAcks.java b/test/src/com/rabbitmq/client/test/functional/InvalidAcks.java index 117451877d..4051e79998 100644 --- a/test/src/com/rabbitmq/client/test/functional/InvalidAcks.java +++ b/test/src/com/rabbitmq/client/test/functional/InvalidAcks.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/InvalidAcksBase.java b/test/src/com/rabbitmq/client/test/functional/InvalidAcksBase.java index fcd7f6cb76..f71ccf1694 100644 --- a/test/src/com/rabbitmq/client/test/functional/InvalidAcksBase.java +++ b/test/src/com/rabbitmq/client/test/functional/InvalidAcksBase.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/InvalidAcksTx.java b/test/src/com/rabbitmq/client/test/functional/InvalidAcksTx.java index e6ef6524ae..6c82b33d0d 100644 --- a/test/src/com/rabbitmq/client/test/functional/InvalidAcksTx.java +++ b/test/src/com/rabbitmq/client/test/functional/InvalidAcksTx.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/Nack.java b/test/src/com/rabbitmq/client/test/functional/Nack.java index 4cc01ff5a8..f2e197187c 100644 --- a/test/src/com/rabbitmq/client/test/functional/Nack.java +++ b/test/src/com/rabbitmq/client/test/functional/Nack.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java b/test/src/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java index cda8ade377..3096c9fc57 100644 --- a/test/src/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java +++ b/test/src/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/PerMessageTTL.java b/test/src/com/rabbitmq/client/test/functional/PerMessageTTL.java index df1f812582..53be989130 100644 --- a/test/src/com/rabbitmq/client/test/functional/PerMessageTTL.java +++ b/test/src/com/rabbitmq/client/test/functional/PerMessageTTL.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/PerQueueTTL.java b/test/src/com/rabbitmq/client/test/functional/PerQueueTTL.java index e6cd19cb47..46c74277b8 100644 --- a/test/src/com/rabbitmq/client/test/functional/PerQueueTTL.java +++ b/test/src/com/rabbitmq/client/test/functional/PerQueueTTL.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/Policies.java b/test/src/com/rabbitmq/client/test/functional/Policies.java index f3c8e1fc83..c450f4e70b 100644 --- a/test/src/com/rabbitmq/client/test/functional/Policies.java +++ b/test/src/com/rabbitmq/client/test/functional/Policies.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/QosTests.java b/test/src/com/rabbitmq/client/test/functional/QosTests.java index 6ee332d062..6b0ce04877 100644 --- a/test/src/com/rabbitmq/client/test/functional/QosTests.java +++ b/test/src/com/rabbitmq/client/test/functional/QosTests.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/QueueExclusivity.java b/test/src/com/rabbitmq/client/test/functional/QueueExclusivity.java index 2f0c07c00d..bcc40305d1 100644 --- a/test/src/com/rabbitmq/client/test/functional/QueueExclusivity.java +++ b/test/src/com/rabbitmq/client/test/functional/QueueExclusivity.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/QueueLease.java b/test/src/com/rabbitmq/client/test/functional/QueueLease.java index 055da31ead..50a4e223e0 100644 --- a/test/src/com/rabbitmq/client/test/functional/QueueLease.java +++ b/test/src/com/rabbitmq/client/test/functional/QueueLease.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/QueueLifecycle.java b/test/src/com/rabbitmq/client/test/functional/QueueLifecycle.java index 43613e64b1..0a00022cb4 100644 --- a/test/src/com/rabbitmq/client/test/functional/QueueLifecycle.java +++ b/test/src/com/rabbitmq/client/test/functional/QueueLifecycle.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/QueueSizeLimit.java b/test/src/com/rabbitmq/client/test/functional/QueueSizeLimit.java index 5b62a022cc..96d858e867 100644 --- a/test/src/com/rabbitmq/client/test/functional/QueueSizeLimit.java +++ b/test/src/com/rabbitmq/client/test/functional/QueueSizeLimit.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/Recover.java b/test/src/com/rabbitmq/client/test/functional/Recover.java index 24d6b7d76a..c9442354c4 100644 --- a/test/src/com/rabbitmq/client/test/functional/Recover.java +++ b/test/src/com/rabbitmq/client/test/functional/Recover.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/Reject.java b/test/src/com/rabbitmq/client/test/functional/Reject.java index 6108841b0a..3c479a53f1 100644 --- a/test/src/com/rabbitmq/client/test/functional/Reject.java +++ b/test/src/com/rabbitmq/client/test/functional/Reject.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java b/test/src/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java index 7554d5b8a0..522a6db719 100644 --- a/test/src/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java +++ b/test/src/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/RequeueOnClose.java b/test/src/com/rabbitmq/client/test/functional/RequeueOnClose.java index 6090c0f4bc..cc9beeec9e 100644 --- a/test/src/com/rabbitmq/client/test/functional/RequeueOnClose.java +++ b/test/src/com/rabbitmq/client/test/functional/RequeueOnClose.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java b/test/src/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java index 8b46908a35..26d2ff7347 100644 --- a/test/src/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java +++ b/test/src/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/Routing.java b/test/src/com/rabbitmq/client/test/functional/Routing.java index a45122cf6c..8c1c440f28 100644 --- a/test/src/com/rabbitmq/client/test/functional/Routing.java +++ b/test/src/com/rabbitmq/client/test/functional/Routing.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/SaslMechanisms.java b/test/src/com/rabbitmq/client/test/functional/SaslMechanisms.java index 77cb0861c8..b8b510ed0c 100644 --- a/test/src/com/rabbitmq/client/test/functional/SaslMechanisms.java +++ b/test/src/com/rabbitmq/client/test/functional/SaslMechanisms.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/Tables.java b/test/src/com/rabbitmq/client/test/functional/Tables.java index 5e5e3351df..1b0239d48b 100644 --- a/test/src/com/rabbitmq/client/test/functional/Tables.java +++ b/test/src/com/rabbitmq/client/test/functional/Tables.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/Transactions.java b/test/src/com/rabbitmq/client/test/functional/Transactions.java index 691cd168b2..40fdedb44a 100644 --- a/test/src/com/rabbitmq/client/test/functional/Transactions.java +++ b/test/src/com/rabbitmq/client/test/functional/Transactions.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java b/test/src/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java index 620fd01a25..31bde6ce15 100644 --- a/test/src/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java +++ b/test/src/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/UnexpectedFrames.java b/test/src/com/rabbitmq/client/test/functional/UnexpectedFrames.java index f5b2c613a1..c69d4b2a07 100644 --- a/test/src/com/rabbitmq/client/test/functional/UnexpectedFrames.java +++ b/test/src/com/rabbitmq/client/test/functional/UnexpectedFrames.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/UserIDHeader.java b/test/src/com/rabbitmq/client/test/functional/UserIDHeader.java index 213f149940..0ca80c8985 100644 --- a/test/src/com/rabbitmq/client/test/functional/UserIDHeader.java +++ b/test/src/com/rabbitmq/client/test/functional/UserIDHeader.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/performance/CLIHelper.java b/test/src/com/rabbitmq/client/test/performance/CLIHelper.java index 39e1f9de68..04d3887f31 100644 --- a/test/src/com/rabbitmq/client/test/performance/CLIHelper.java +++ b/test/src/com/rabbitmq/client/test/performance/CLIHelper.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/performance/QosScaling.java b/test/src/com/rabbitmq/client/test/performance/QosScaling.java index d3b820138b..09839d9e94 100644 --- a/test/src/com/rabbitmq/client/test/performance/QosScaling.java +++ b/test/src/com/rabbitmq/client/test/performance/QosScaling.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/performance/ScalabilityTest.java b/test/src/com/rabbitmq/client/test/performance/ScalabilityTest.java index 96003f88eb..d38e073ec2 100644 --- a/test/src/com/rabbitmq/client/test/performance/ScalabilityTest.java +++ b/test/src/com/rabbitmq/client/test/performance/ScalabilityTest.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/performance/StressManagement.java b/test/src/com/rabbitmq/client/test/performance/StressManagement.java index 193464d28b..595b1d1adb 100644 --- a/test/src/com/rabbitmq/client/test/performance/StressManagement.java +++ b/test/src/com/rabbitmq/client/test/performance/StressManagement.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.performance; diff --git a/test/src/com/rabbitmq/client/test/server/AbsentQueue.java b/test/src/com/rabbitmq/client/test/server/AbsentQueue.java index 47e256201c..d62d5acb2b 100644 --- a/test/src/com/rabbitmq/client/test/server/AbsentQueue.java +++ b/test/src/com/rabbitmq/client/test/server/AbsentQueue.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java b/test/src/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java index 683e067ebc..586dad58b6 100644 --- a/test/src/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java +++ b/test/src/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/server/BlockedConnection.java b/test/src/com/rabbitmq/client/test/server/BlockedConnection.java index b0779f31b7..23239725fa 100644 --- a/test/src/com/rabbitmq/client/test/server/BlockedConnection.java +++ b/test/src/com/rabbitmq/client/test/server/BlockedConnection.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/server/Bug19219Test.java b/test/src/com/rabbitmq/client/test/server/Bug19219Test.java index 895096663e..a01fa96dbe 100644 --- a/test/src/com/rabbitmq/client/test/server/Bug19219Test.java +++ b/test/src/com/rabbitmq/client/test/server/Bug19219Test.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.server; diff --git a/test/src/com/rabbitmq/client/test/server/DurableBindingLifecycle.java b/test/src/com/rabbitmq/client/test/server/DurableBindingLifecycle.java index 0944edccf8..27e262f537 100644 --- a/test/src/com/rabbitmq/client/test/server/DurableBindingLifecycle.java +++ b/test/src/com/rabbitmq/client/test/server/DurableBindingLifecycle.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java b/test/src/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java index 630d06af84..9bb659e207 100644 --- a/test/src/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java +++ b/test/src/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.server; diff --git a/test/src/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java b/test/src/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java index af3b954803..d6108c5db5 100644 --- a/test/src/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java +++ b/test/src/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/server/HATests.java b/test/src/com/rabbitmq/client/test/server/HATests.java index 80d970bdad..3a2f7ea038 100644 --- a/test/src/com/rabbitmq/client/test/server/HATests.java +++ b/test/src/com/rabbitmq/client/test/server/HATests.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.server; diff --git a/test/src/com/rabbitmq/client/test/server/MemoryAlarms.java b/test/src/com/rabbitmq/client/test/server/MemoryAlarms.java index 6822f65f7a..12dd19a424 100644 --- a/test/src/com/rabbitmq/client/test/server/MemoryAlarms.java +++ b/test/src/com/rabbitmq/client/test/server/MemoryAlarms.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.server; diff --git a/test/src/com/rabbitmq/client/test/server/MessageRecovery.java b/test/src/com/rabbitmq/client/test/server/MessageRecovery.java index 100058370a..45c33c242c 100644 --- a/test/src/com/rabbitmq/client/test/server/MessageRecovery.java +++ b/test/src/com/rabbitmq/client/test/server/MessageRecovery.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. package com.rabbitmq.client.test.server; diff --git a/test/src/com/rabbitmq/client/test/server/Permissions.java b/test/src/com/rabbitmq/client/test/server/Permissions.java index ca7a4f568f..0993499751 100644 --- a/test/src/com/rabbitmq/client/test/server/Permissions.java +++ b/test/src/com/rabbitmq/client/test/server/Permissions.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/server/ServerTests.java b/test/src/com/rabbitmq/client/test/server/ServerTests.java index 30b923bfa9..bc86b366ab 100644 --- a/test/src/com/rabbitmq/client/test/server/ServerTests.java +++ b/test/src/com/rabbitmq/client/test/server/ServerTests.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java b/test/src/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java index c463a1d463..9354a7084e 100644 --- a/test/src/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java +++ b/test/src/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.ssl; diff --git a/test/src/com/rabbitmq/client/test/ssl/SSLTests.java b/test/src/com/rabbitmq/client/test/ssl/SSLTests.java index 9df495670a..4263bd241c 100644 --- a/test/src/com/rabbitmq/client/test/ssl/SSLTests.java +++ b/test/src/com/rabbitmq/client/test/ssl/SSLTests.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/ssl/UnverifiedConnection.java b/test/src/com/rabbitmq/client/test/ssl/UnverifiedConnection.java index f9378efe7d..785f8cae15 100644 --- a/test/src/com/rabbitmq/client/test/ssl/UnverifiedConnection.java +++ b/test/src/com/rabbitmq/client/test/ssl/UnverifiedConnection.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.ssl; diff --git a/test/src/com/rabbitmq/client/test/ssl/VerifiedConnection.java b/test/src/com/rabbitmq/client/test/ssl/VerifiedConnection.java index c48763f82c..8a6ef3d617 100644 --- a/test/src/com/rabbitmq/client/test/ssl/VerifiedConnection.java +++ b/test/src/com/rabbitmq/client/test/ssl/VerifiedConnection.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.ssl; diff --git a/test/src/com/rabbitmq/examples/BufferPerformanceMetrics.java b/test/src/com/rabbitmq/examples/BufferPerformanceMetrics.java index 61accc0533..919bd9c107 100644 --- a/test/src/com/rabbitmq/examples/BufferPerformanceMetrics.java +++ b/test/src/com/rabbitmq/examples/BufferPerformanceMetrics.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/ChannelCreationPerformance.java b/test/src/com/rabbitmq/examples/ChannelCreationPerformance.java index 32dcf624f0..ca34ba1a2e 100644 --- a/test/src/com/rabbitmq/examples/ChannelCreationPerformance.java +++ b/test/src/com/rabbitmq/examples/ChannelCreationPerformance.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/ConfirmDontLoseMessages.java b/test/src/com/rabbitmq/examples/ConfirmDontLoseMessages.java index 61c37d70af..996a498264 100644 --- a/test/src/com/rabbitmq/examples/ConfirmDontLoseMessages.java +++ b/test/src/com/rabbitmq/examples/ConfirmDontLoseMessages.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/examples/ConsumerMain.java b/test/src/com/rabbitmq/examples/ConsumerMain.java index 15ec65d656..aaadf0dd49 100644 --- a/test/src/com/rabbitmq/examples/ConsumerMain.java +++ b/test/src/com/rabbitmq/examples/ConsumerMain.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/examples/FileConsumer.java b/test/src/com/rabbitmq/examples/FileConsumer.java index 2a3602b48a..613961a2cb 100644 --- a/test/src/com/rabbitmq/examples/FileConsumer.java +++ b/test/src/com/rabbitmq/examples/FileConsumer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/examples/FileProducer.java b/test/src/com/rabbitmq/examples/FileProducer.java index fe6bb9eb00..fb051a43c0 100644 --- a/test/src/com/rabbitmq/examples/FileProducer.java +++ b/test/src/com/rabbitmq/examples/FileProducer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/examples/HelloClient.java b/test/src/com/rabbitmq/examples/HelloClient.java index e21b597d9e..9eba3c0f15 100644 --- a/test/src/com/rabbitmq/examples/HelloClient.java +++ b/test/src/com/rabbitmq/examples/HelloClient.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/HelloJsonClient.java b/test/src/com/rabbitmq/examples/HelloJsonClient.java index dbed068004..8917cc51b8 100644 --- a/test/src/com/rabbitmq/examples/HelloJsonClient.java +++ b/test/src/com/rabbitmq/examples/HelloJsonClient.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/HelloJsonServer.java b/test/src/com/rabbitmq/examples/HelloJsonServer.java index 19329a40ab..d8628739d6 100644 --- a/test/src/com/rabbitmq/examples/HelloJsonServer.java +++ b/test/src/com/rabbitmq/examples/HelloJsonServer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/HelloJsonService.java b/test/src/com/rabbitmq/examples/HelloJsonService.java index 77d45ff084..51b0d7924a 100644 --- a/test/src/com/rabbitmq/examples/HelloJsonService.java +++ b/test/src/com/rabbitmq/examples/HelloJsonService.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/examples/HelloServer.java b/test/src/com/rabbitmq/examples/HelloServer.java index 703132e375..2117230aaf 100644 --- a/test/src/com/rabbitmq/examples/HelloServer.java +++ b/test/src/com/rabbitmq/examples/HelloServer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/examples/LogTail.java b/test/src/com/rabbitmq/examples/LogTail.java index b2d39a220b..16e693fba0 100644 --- a/test/src/com/rabbitmq/examples/LogTail.java +++ b/test/src/com/rabbitmq/examples/LogTail.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/MulticastMain.java b/test/src/com/rabbitmq/examples/MulticastMain.java index d33621116c..2c9b3b43c6 100644 --- a/test/src/com/rabbitmq/examples/MulticastMain.java +++ b/test/src/com/rabbitmq/examples/MulticastMain.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/PerQueueTTLGetter.java b/test/src/com/rabbitmq/examples/PerQueueTTLGetter.java index 8705ae0c4a..63d9434727 100644 --- a/test/src/com/rabbitmq/examples/PerQueueTTLGetter.java +++ b/test/src/com/rabbitmq/examples/PerQueueTTLGetter.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/PerQueueTTLPublisher.java b/test/src/com/rabbitmq/examples/PerQueueTTLPublisher.java index 533abdd0e2..c66161f4d2 100644 --- a/test/src/com/rabbitmq/examples/PerQueueTTLPublisher.java +++ b/test/src/com/rabbitmq/examples/PerQueueTTLPublisher.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/PerfTest.java b/test/src/com/rabbitmq/examples/PerfTest.java index 6381e6ecdf..e7caf63038 100644 --- a/test/src/com/rabbitmq/examples/PerfTest.java +++ b/test/src/com/rabbitmq/examples/PerfTest.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/PerfTestMulti.java b/test/src/com/rabbitmq/examples/PerfTestMulti.java index cf6f86cdda..0edbfe9820 100644 --- a/test/src/com/rabbitmq/examples/PerfTestMulti.java +++ b/test/src/com/rabbitmq/examples/PerfTestMulti.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/ProducerMain.java b/test/src/com/rabbitmq/examples/ProducerMain.java index c2dedb0df1..66613f03f5 100644 --- a/test/src/com/rabbitmq/examples/ProducerMain.java +++ b/test/src/com/rabbitmq/examples/ProducerMain.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/SendString.java b/test/src/com/rabbitmq/examples/SendString.java index be6cde2ae8..3b1b9c1db0 100644 --- a/test/src/com/rabbitmq/examples/SendString.java +++ b/test/src/com/rabbitmq/examples/SendString.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/SimpleConsumer.java b/test/src/com/rabbitmq/examples/SimpleConsumer.java index 51154f3abe..2d0ab97740 100644 --- a/test/src/com/rabbitmq/examples/SimpleConsumer.java +++ b/test/src/com/rabbitmq/examples/SimpleConsumer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/SimpleProducer.java b/test/src/com/rabbitmq/examples/SimpleProducer.java index eb85dbdbfa..70b54e9025 100644 --- a/test/src/com/rabbitmq/examples/SimpleProducer.java +++ b/test/src/com/rabbitmq/examples/SimpleProducer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/SimpleTopicConsumer.java b/test/src/com/rabbitmq/examples/SimpleTopicConsumer.java index c0a8f22200..a50e0956a6 100644 --- a/test/src/com/rabbitmq/examples/SimpleTopicConsumer.java +++ b/test/src/com/rabbitmq/examples/SimpleTopicConsumer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/SimpleTopicProducer.java b/test/src/com/rabbitmq/examples/SimpleTopicProducer.java index 4257e2a91d..335934f3c7 100644 --- a/test/src/com/rabbitmq/examples/SimpleTopicProducer.java +++ b/test/src/com/rabbitmq/examples/SimpleTopicProducer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/SpammyTopicProducer.java b/test/src/com/rabbitmq/examples/SpammyTopicProducer.java index 4e49935c0f..a3d7915d33 100644 --- a/test/src/com/rabbitmq/examples/SpammyTopicProducer.java +++ b/test/src/com/rabbitmq/examples/SpammyTopicProducer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/StressPersister.java b/test/src/com/rabbitmq/examples/StressPersister.java index 0de1861410..48fcc23adb 100644 --- a/test/src/com/rabbitmq/examples/StressPersister.java +++ b/test/src/com/rabbitmq/examples/StressPersister.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/TestMain.java b/test/src/com/rabbitmq/examples/TestMain.java index c80b0b271c..0ef4cdb2aa 100644 --- a/test/src/com/rabbitmq/examples/TestMain.java +++ b/test/src/com/rabbitmq/examples/TestMain.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/examples/TracerConcurrencyTest.java b/test/src/com/rabbitmq/examples/TracerConcurrencyTest.java index 64df3c1829..01eb9f55aa 100644 --- a/test/src/com/rabbitmq/examples/TracerConcurrencyTest.java +++ b/test/src/com/rabbitmq/examples/TracerConcurrencyTest.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/perf/Broker.java b/test/src/com/rabbitmq/examples/perf/Broker.java index c4d77e4d24..eabc659fb4 100644 --- a/test/src/com/rabbitmq/examples/perf/Broker.java +++ b/test/src/com/rabbitmq/examples/perf/Broker.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/BrokerValue.java b/test/src/com/rabbitmq/examples/perf/BrokerValue.java index 53b9fbe402..0631b9b8ac 100644 --- a/test/src/com/rabbitmq/examples/perf/BrokerValue.java +++ b/test/src/com/rabbitmq/examples/perf/BrokerValue.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/BrokerVariable.java b/test/src/com/rabbitmq/examples/perf/BrokerVariable.java index b4b7566fdd..17335ee033 100644 --- a/test/src/com/rabbitmq/examples/perf/BrokerVariable.java +++ b/test/src/com/rabbitmq/examples/perf/BrokerVariable.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/Consumer.java b/test/src/com/rabbitmq/examples/perf/Consumer.java index 6ef9327814..cdecad8dd7 100644 --- a/test/src/com/rabbitmq/examples/perf/Consumer.java +++ b/test/src/com/rabbitmq/examples/perf/Consumer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/MulticastParams.java b/test/src/com/rabbitmq/examples/perf/MulticastParams.java index ba15758c5c..b54f142895 100644 --- a/test/src/com/rabbitmq/examples/perf/MulticastParams.java +++ b/test/src/com/rabbitmq/examples/perf/MulticastParams.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/MulticastSet.java b/test/src/com/rabbitmq/examples/perf/MulticastSet.java index 4a7338192f..293bed2cbf 100644 --- a/test/src/com/rabbitmq/examples/perf/MulticastSet.java +++ b/test/src/com/rabbitmq/examples/perf/MulticastSet.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/MulticastValue.java b/test/src/com/rabbitmq/examples/perf/MulticastValue.java index 001f158abd..ca5ad0e558 100644 --- a/test/src/com/rabbitmq/examples/perf/MulticastValue.java +++ b/test/src/com/rabbitmq/examples/perf/MulticastValue.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/MulticastVariable.java b/test/src/com/rabbitmq/examples/perf/MulticastVariable.java index 5308c34abe..5a1368442c 100644 --- a/test/src/com/rabbitmq/examples/perf/MulticastVariable.java +++ b/test/src/com/rabbitmq/examples/perf/MulticastVariable.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/Producer.java b/test/src/com/rabbitmq/examples/perf/Producer.java index 628c23321b..26a9c19404 100644 --- a/test/src/com/rabbitmq/examples/perf/Producer.java +++ b/test/src/com/rabbitmq/examples/perf/Producer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/RateVsLatencyScenario.java b/test/src/com/rabbitmq/examples/perf/RateVsLatencyScenario.java index 4692d54fbf..32ba0fafd2 100644 --- a/test/src/com/rabbitmq/examples/perf/RateVsLatencyScenario.java +++ b/test/src/com/rabbitmq/examples/perf/RateVsLatencyScenario.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/Scenario.java b/test/src/com/rabbitmq/examples/perf/Scenario.java index 63c841d510..f680ccb71c 100644 --- a/test/src/com/rabbitmq/examples/perf/Scenario.java +++ b/test/src/com/rabbitmq/examples/perf/Scenario.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/ScenarioStats.java b/test/src/com/rabbitmq/examples/perf/ScenarioStats.java index d18126ca3d..e8fc10b223 100644 --- a/test/src/com/rabbitmq/examples/perf/ScenarioStats.java +++ b/test/src/com/rabbitmq/examples/perf/ScenarioStats.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/SimpleScenario.java b/test/src/com/rabbitmq/examples/perf/SimpleScenario.java index 31e09cf79f..7b7d83d98b 100644 --- a/test/src/com/rabbitmq/examples/perf/SimpleScenario.java +++ b/test/src/com/rabbitmq/examples/perf/SimpleScenario.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/SimpleScenarioStats.java b/test/src/com/rabbitmq/examples/perf/SimpleScenarioStats.java index 0a6e9c5b9c..80f3ee03ba 100644 --- a/test/src/com/rabbitmq/examples/perf/SimpleScenarioStats.java +++ b/test/src/com/rabbitmq/examples/perf/SimpleScenarioStats.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/Stats.java b/test/src/com/rabbitmq/examples/perf/Stats.java index ea7547824e..8ddf8664ce 100644 --- a/test/src/com/rabbitmq/examples/perf/Stats.java +++ b/test/src/com/rabbitmq/examples/perf/Stats.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/Variable.java b/test/src/com/rabbitmq/examples/perf/Variable.java index 771c607ec9..1157ca691a 100644 --- a/test/src/com/rabbitmq/examples/perf/Variable.java +++ b/test/src/com/rabbitmq/examples/perf/Variable.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/VariableValue.java b/test/src/com/rabbitmq/examples/perf/VariableValue.java index d76bfa5a72..edb27131c7 100644 --- a/test/src/com/rabbitmq/examples/perf/VariableValue.java +++ b/test/src/com/rabbitmq/examples/perf/VariableValue.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/VaryingScenario.java b/test/src/com/rabbitmq/examples/perf/VaryingScenario.java index 1eafa38bf1..9a9512d67e 100644 --- a/test/src/com/rabbitmq/examples/perf/VaryingScenario.java +++ b/test/src/com/rabbitmq/examples/perf/VaryingScenario.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/VaryingScenarioStats.java b/test/src/com/rabbitmq/examples/perf/VaryingScenarioStats.java index f7f97e0abe..49be18b106 100644 --- a/test/src/com/rabbitmq/examples/perf/VaryingScenarioStats.java +++ b/test/src/com/rabbitmq/examples/perf/VaryingScenarioStats.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/tools/Host.java b/test/src/com/rabbitmq/tools/Host.java index ef8bb41084..83f2bfb6f1 100644 --- a/test/src/com/rabbitmq/tools/Host.java +++ b/test/src/com/rabbitmq/tools/Host.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/utility/IntAllocatorTests.java b/test/src/com/rabbitmq/utility/IntAllocatorTests.java index 5caf10cd29..77fe5ab3c4 100644 --- a/test/src/com/rabbitmq/utility/IntAllocatorTests.java +++ b/test/src/com/rabbitmq/utility/IntAllocatorTests.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2011-2014 GoPivotal, Inc. All rights reserved. +// Copyright (c) 2011-2015 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.utility; From 3291399a46aeccc83f5045555bb8981c8f3f5877 Mon Sep 17 00:00:00 2001 From: Zack Date: Wed, 24 Jun 2015 14:19:47 -0600 Subject: [PATCH 0029/2114] Remove WorkPool memory leak --- src/com/rabbitmq/client/impl/WorkPool.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/com/rabbitmq/client/impl/WorkPool.java b/src/com/rabbitmq/client/impl/WorkPool.java index 1c8adc3979..0377f52912 100644 --- a/src/com/rabbitmq/client/impl/WorkPool.java +++ b/src/com/rabbitmq/client/impl/WorkPool.java @@ -123,6 +123,7 @@ public void unregisterKey(K key) { this.pool.remove(key); this.ready.remove(key); this.inProgress.remove(key); + this.unlimited.remove(key); } } @@ -134,6 +135,7 @@ public void unregisterAllKeys() { this.pool.clear(); this.ready.clear(); this.inProgress.clear(); + this.unlimited.clear(); } } From 57f1ead604f786e9570427adb137e6b0f4ff42c2 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Mon, 29 Jun 2015 01:16:51 +0300 Subject: [PATCH 0030/2114] Throw IllegalArgumentError early if queue name length exceeds 255 chars Fixes #72. --- src/com/rabbitmq/client/impl/ChannelN.java | 17 ++++++++++++++++- .../client/test/functional/QueueLifecycle.java | 10 ++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/com/rabbitmq/client/impl/ChannelN.java b/src/com/rabbitmq/client/impl/ChannelN.java index 9711941929..84723f6282 100644 --- a/src/com/rabbitmq/client/impl/ChannelN.java +++ b/src/com/rabbitmq/client/impl/ChannelN.java @@ -840,6 +840,7 @@ public Queue.DeclareOk queueDeclare(String queue, boolean durable, boolean exclu boolean autoDelete, Map arguments) throws IOException { + validateQueueNameLength(queue); return (Queue.DeclareOk) exnWrappingRpc(new Queue.Declare.Builder() .queue(queue) @@ -864,6 +865,7 @@ public void queueDeclareNoWait(String queue, boolean exclusive, boolean autoDelete, Map arguments) throws IOException { + validateQueueNameLength(queue); transmit(new AMQCommand(new Queue.Declare.Builder() .queue(queue) .durable(durable) @@ -879,6 +881,7 @@ public void queueDeclareNoWait(String queue, public Queue.DeclareOk queueDeclarePassive(String queue) throws IOException { + validateQueueNameLength(queue); return (Queue.DeclareOk) exnWrappingRpc(new Queue.Declare.Builder() .queue(queue) @@ -893,6 +896,7 @@ public Queue.DeclareOk queueDeclarePassive(String queue) public Queue.DeleteOk queueDelete(String queue, boolean ifUnused, boolean ifEmpty) throws IOException { + validateQueueNameLength(queue); return (Queue.DeleteOk) exnWrappingRpc(new Queue.Delete.Builder() .queue(queue) @@ -904,6 +908,7 @@ public Queue.DeleteOk queueDelete(String queue, boolean ifUnused, boolean ifEmpt @Override public void queueDeleteNoWait(String queue, boolean ifUnused, boolean ifEmpty) throws IOException { + validateQueueNameLength(queue); transmit(new AMQCommand(new Queue.Delete.Builder() .queue(queue) .ifUnused(ifUnused) @@ -924,6 +929,7 @@ public Queue.BindOk queueBind(String queue, String exchange, String routingKey, Map arguments) throws IOException { + validateQueueNameLength(queue); return (Queue.BindOk) exnWrappingRpc(new Queue.Bind.Builder() .queue(queue) @@ -938,7 +944,6 @@ public Queue.BindOk queueBind(String queue, String exchange, public Queue.BindOk queueBind(String queue, String exchange, String routingKey) throws IOException { - return queueBind(queue, exchange, routingKey, null); } @@ -947,6 +952,7 @@ public void queueBindNoWait(String queue, String exchange, String routingKey, Map arguments) throws IOException { + validateQueueNameLength(queue); transmit(new AMQCommand(new Queue.Bind.Builder() .queue(queue) .exchange(exchange) @@ -960,6 +966,7 @@ public Queue.UnbindOk queueUnbind(String queue, String exchange, String routingK Map arguments) throws IOException { + validateQueueNameLength(queue); return (Queue.UnbindOk) exnWrappingRpc(new Queue.Unbind.Builder() .queue(queue) @@ -974,6 +981,7 @@ public Queue.UnbindOk queueUnbind(String queue, String exchange, String routingK public Queue.PurgeOk queuePurge(String queue) throws IOException { + validateQueueNameLength(queue); return (Queue.PurgeOk) exnWrappingRpc(new Queue.Purge.Builder() .queue(queue) @@ -992,6 +1000,7 @@ public Queue.UnbindOk queueUnbind(String queue, String exchange, String routingK public GetResponse basicGet(String queue, boolean autoAck) throws IOException { + validateQueueNameLength(queue); AMQCommand replyCommand = exnWrappingRpc(new Basic.Get.Builder() .queue(queue) .noAck(autoAck) @@ -1218,4 +1227,10 @@ private void handleAckNack(long seqNo, boolean multiple, boolean nack) { unconfirmedSet.notifyAll(); } } + + private void validateQueueNameLength(String queue) { + if(queue.length() > 255) { + throw new IllegalArgumentException("queue name must be no more than 255 characters long"); + } + } } diff --git a/test/src/com/rabbitmq/client/test/functional/QueueLifecycle.java b/test/src/com/rabbitmq/client/test/functional/QueueLifecycle.java index 0a00022cb4..3616cd8133 100644 --- a/test/src/com/rabbitmq/client/test/functional/QueueLifecycle.java +++ b/test/src/com/rabbitmq/client/test/functional/QueueLifecycle.java @@ -167,4 +167,14 @@ public void testArgumentArrays() throws IOException { channel.queueDeclare(queueName, true, true, false, args); verifyQueue(queueName, true, true, false, args); } + + public void testQueueNamesLongerThan255Characters() throws IOException { + String q = new String(new byte[300]).replace('\u0000', 'x'); + try { + channel.queueDeclare(q, false, false, false, null); + fail("queueDeclare should have failed"); + } catch (IllegalArgumentException ignored) { + // expected + } + } } From 76d85ccdbdb97d2bc6e73bf81fa98b1bd5935cf7 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Sat, 4 Jul 2015 00:56:47 +0300 Subject: [PATCH 0031/2114] Demonstrate that DefaultExceptionHnalder#handleConsumerException closes the channel --- .../rabbitmq/client/test/functional/ExceptionHandling.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/src/com/rabbitmq/client/test/functional/ExceptionHandling.java b/test/src/com/rabbitmq/client/test/functional/ExceptionHandling.java index 5d23562e55..1ed485e178 100644 --- a/test/src/com/rabbitmq/client/test/functional/ExceptionHandling.java +++ b/test/src/com/rabbitmq/client/test/functional/ExceptionHandling.java @@ -28,6 +28,7 @@ public void testHandleConsumerException() throws IOException, InterruptedExcepti final DefaultExceptionHandler eh = new DefaultExceptionHandler() { @Override public void handleConsumerException(Channel channel, Throwable exception, Consumer consumer, String consumerTag, String methodName) { + super.handleConsumerException(channel, exception, consumer, consumerTag, methodName); latch.countDown(); } }; @@ -41,11 +42,12 @@ public void handleConsumerException(Channel channel, Throwable exception, Consum @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { - throw new RuntimeException("oops"); + throw new RuntimeException("exception expected here, don't freak out"); } }); ch.basicPublish("", q, null, "".getBytes()); wait(latch); + assertFalse(ch.isOpen()); } public void testNullExceptionHandler() { From d909f8b0c7536d33a15c2973525fcdb1e4dff891 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Sat, 4 Jul 2015 01:53:55 +0300 Subject: [PATCH 0032/2114] Split DefaultExceptionHandler into strict and forgiving versions Currently DefaultExceptionHandler will close the channel when an unhandled consumer or listener exception occurs. Not everybody agrees this is a great idea. This commit introduces a forgiving version and keeps DefaultExceptionHandler strict. For 3.6.0 we will make DefaultExceptionHandler forgiving. --- .../client/impl/DefaultExceptionHandler.java | 118 +--------------- .../impl/ForgivingExceptionHandler.java | 130 ++++++++++++++++++ .../client/impl/StrictExceptionHandler.java | 85 ++++++++++++ .../test/functional/ExceptionHandling.java | 27 +++- 4 files changed, 242 insertions(+), 118 deletions(-) create mode 100644 src/com/rabbitmq/client/impl/ForgivingExceptionHandler.java create mode 100644 src/com/rabbitmq/client/impl/StrictExceptionHandler.java diff --git a/src/com/rabbitmq/client/impl/DefaultExceptionHandler.java b/src/com/rabbitmq/client/impl/DefaultExceptionHandler.java index 63b31c1784..82ac3ff175 100644 --- a/src/com/rabbitmq/client/impl/DefaultExceptionHandler.java +++ b/src/com/rabbitmq/client/impl/DefaultExceptionHandler.java @@ -16,123 +16,11 @@ package com.rabbitmq.client.impl; -import java.io.IOException; -import java.net.ConnectException; -import java.util.concurrent.TimeoutException; - -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.AlreadyClosedException; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.Consumer; import com.rabbitmq.client.ExceptionHandler; -import com.rabbitmq.client.TopologyRecoveryException; /** - * Default implementation of {@link com.rabbitmq.client.ExceptionHandler} used by {@link AMQConnection}. + * Default implementation of {@link com.rabbitmq.client.ExceptionHandler} + * used by {@link AMQConnection}. */ -public class DefaultExceptionHandler implements ExceptionHandler { - public void handleUnexpectedConnectionDriverException(Connection conn, Throwable exception) { - // TODO: Log this somewhere, just in case we have a bug like - // 16272 where exceptions aren't being propagated properly - // again. - - //System.err.println("DefaultExceptionHandler:"); - //exception.printStackTrace(); - } - - public void handleReturnListenerException(Channel channel, Throwable exception) { - handleChannelKiller(channel, exception, "ReturnListener.handleReturn"); - } - - public void handleFlowListenerException(Channel channel, Throwable exception) { - handleChannelKiller(channel, exception, "FlowListener.handleFlow"); - } - - public void handleConfirmListenerException(Channel channel, Throwable exception) { - handleChannelKiller(channel, exception, "ConfirmListener.handle{N,A}ck"); - } - - public void handleBlockedListenerException(Connection connection, Throwable exception) { - handleConnectionKiller(connection, exception, "BlockedListener"); - } - - public void handleConsumerException(Channel channel, Throwable exception, - Consumer consumer, String consumerTag, - String methodName) - { - handleChannelKiller(channel, exception, "Consumer " + consumer - + " (" + consumerTag + ")" - + " method " + methodName - + " for channel " + channel); - } - - /** - * @since 3.3.0 - */ - public void handleConnectionRecoveryException(Connection conn, Throwable exception) { - // ignore java.net.ConnectException as those are - // expected during recovery and will only produce noisy - // traces - if (exception instanceof ConnectException) { - // no-op - } else { - System.err.println("Caught an exception during connection recovery!"); - exception.printStackTrace(System.err); - } - } - - /** - * @since 3.3.0 - */ - public void handleChannelRecoveryException(Channel ch, Throwable exception) { - System.err.println("Caught an exception when recovering channel " + ch.getChannelNumber()); - exception.printStackTrace(System.err); - } - - /** - * @since 3.3.0 - */ - public void handleTopologyRecoveryException(Connection conn, Channel ch, TopologyRecoveryException exception) { - System.err.println("Caught an exception when recovering topology " + exception.getMessage()); - exception.printStackTrace(System.err); - } - - protected void handleChannelKiller(Channel channel, Throwable exception, String what) { - // TODO: log the exception - System.err.println("DefaultExceptionHandler: " + what + " threw an exception for channel " - + channel + ":"); - exception.printStackTrace(); - try { - channel.close(AMQP.REPLY_SUCCESS, "Closed due to exception from " + what); - } catch (AlreadyClosedException ace) { - // noop - } catch (TimeoutException ace) { - // noop - } catch (IOException ioe) { - // TODO: log the failure - System.err.println("Failure during close of channel " + channel + " after " + exception - + ":"); - ioe.printStackTrace(); - channel.getConnection().abort(AMQP.INTERNAL_ERROR, "Internal error closing channel for " + what); - } - } - - protected void handleConnectionKiller(Connection connection, Throwable exception, String what) { - // TODO: log the exception - System.err.println("DefaultExceptionHandler: " + what + " threw an exception for connection " - + connection + ":"); - exception.printStackTrace(); - try { - connection.close(AMQP.REPLY_SUCCESS, "Closed due to exception from " + what); - } catch (AlreadyClosedException ace) { - // noop - } catch (IOException ioe) { - // TODO: log the failure - System.err.println("Failure during close of connection " + connection + " after " + exception - + ":"); - ioe.printStackTrace(); - connection.abort(AMQP.INTERNAL_ERROR, "Internal error closing connection for " + what); - } - } +public class DefaultExceptionHandler extends StrictExceptionHandler implements ExceptionHandler { } diff --git a/src/com/rabbitmq/client/impl/ForgivingExceptionHandler.java b/src/com/rabbitmq/client/impl/ForgivingExceptionHandler.java new file mode 100644 index 0000000000..a7365d835b --- /dev/null +++ b/src/com/rabbitmq/client/impl/ForgivingExceptionHandler.java @@ -0,0 +1,130 @@ +// The contents of this file are subject to the Mozilla Public License +// Version 1.1 (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.mozilla.org/MPL/ +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and +// limitations under the License. +// +// The Original Code is RabbitMQ. +// +// The Initial Developer of the Original Code is GoPivotal, Inc. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// + +package com.rabbitmq.client.impl; + +import java.io.IOException; +import java.net.ConnectException; +import java.util.concurrent.TimeoutException; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.AlreadyClosedException; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.Consumer; +import com.rabbitmq.client.ExceptionHandler; +import com.rabbitmq.client.TopologyRecoveryException; + +/** + * An implementation of {@link com.rabbitmq.client.ExceptionHandler} that does not + * close channels on unhandled consumer and listener exception. + * + * Used by {@link AMQConnection}. + * + * @see ExceptionHandler + * @see com.rabbitmq.client.ConnectionFactory#setExceptionHandler(com.rabbitmq.client.ExceptionHandler) + */ +public class ForgivingExceptionHandler implements ExceptionHandler { + public void handleUnexpectedConnectionDriverException(Connection conn, Throwable exception) { + // TODO: Log this somewhere, just in case we have a bug like + // 16272 where exceptions aren't being propagated properly + // again. + + //System.err.println("DefaultExceptionHandler:"); + //exception.printStackTrace(); + } + + public void handleReturnListenerException(Channel channel, Throwable exception) { + handleChannelKiller(channel, exception, "ReturnListener.handleReturn"); + } + + public void handleFlowListenerException(Channel channel, Throwable exception) { + handleChannelKiller(channel, exception, "FlowListener.handleFlow"); + } + + public void handleConfirmListenerException(Channel channel, Throwable exception) { + handleChannelKiller(channel, exception, "ConfirmListener.handle{N,A}ck"); + } + + public void handleBlockedListenerException(Connection connection, Throwable exception) { + handleConnectionKiller(connection, exception, "BlockedListener"); + } + + public void handleConsumerException(Channel channel, Throwable exception, + Consumer consumer, String consumerTag, + String methodName) + { + handleChannelKiller(channel, exception, "Consumer " + consumer + + " (" + consumerTag + ")" + + " method " + methodName + + " for channel " + channel); + } + + /** + * @since 3.3.0 + */ + public void handleConnectionRecoveryException(Connection conn, Throwable exception) { + // ignore java.net.ConnectException as those are + // expected during recovery and will only produce noisy + // traces + if (exception instanceof ConnectException) { + // no-op + } else { + System.err.println("Caught an exception during connection recovery!"); + exception.printStackTrace(System.err); + } + } + + /** + * @since 3.3.0 + */ + public void handleChannelRecoveryException(Channel ch, Throwable exception) { + System.err.println("Caught an exception when recovering channel " + ch.getChannelNumber()); + exception.printStackTrace(System.err); + } + + /** + * @since 3.3.0 + */ + public void handleTopologyRecoveryException(Connection conn, Channel ch, TopologyRecoveryException exception) { + System.err.println("Caught an exception when recovering topology " + exception.getMessage()); + exception.printStackTrace(System.err); + } + + protected void handleChannelKiller(Channel channel, Throwable exception, String what) { + System.err.println(this.getClass().getName() + ": " + what + " threw an exception for channel " + + channel + ":"); + exception.printStackTrace(); + } + + protected void handleConnectionKiller(Connection connection, Throwable exception, String what) { + // TODO: log the exception + System.err.println("DefaultExceptionHandler: " + what + " threw an exception for connection " + + connection + ":"); + exception.printStackTrace(); + try { + connection.close(AMQP.REPLY_SUCCESS, "Closed due to exception from " + what); + } catch (AlreadyClosedException ace) { + // noop + } catch (IOException ioe) { + // TODO: log the failure + System.err.println("Failure during close of connection " + connection + " after " + exception + + ":"); + ioe.printStackTrace(); + connection.abort(AMQP.INTERNAL_ERROR, "Internal error closing connection for " + what); + } + } +} diff --git a/src/com/rabbitmq/client/impl/StrictExceptionHandler.java b/src/com/rabbitmq/client/impl/StrictExceptionHandler.java new file mode 100644 index 0000000000..4d879ffac9 --- /dev/null +++ b/src/com/rabbitmq/client/impl/StrictExceptionHandler.java @@ -0,0 +1,85 @@ +// The contents of this file are subject to the Mozilla Public License +// Version 1.1 (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.mozilla.org/MPL/ +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and +// limitations under the License. +// +// The Original Code is RabbitMQ. +// +// The Initial Developer of the Original Code is GoPivotal, Inc. +// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// + +package com.rabbitmq.client.impl; + +import java.io.IOException; +import java.net.ConnectException; +import java.util.concurrent.TimeoutException; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.AlreadyClosedException; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.Consumer; +import com.rabbitmq.client.ExceptionHandler; +import com.rabbitmq.client.TopologyRecoveryException; + +/** + * An implementation of {@link com.rabbitmq.client.ExceptionHandler} that does not + * close channels on unhandled consumer exception. + * + * Used by {@link AMQConnection}. + * + * @see ExceptionHandler + * @see com.rabbitmq.client.ConnectionFactory#setExceptionHandler(ExceptionHandler) + */ +public class StrictExceptionHandler extends ForgivingExceptionHandler implements ExceptionHandler { + public void handleReturnListenerException(Channel channel, Throwable exception) { + handleChannelKiller(channel, exception, "ReturnListener.handleReturn"); + } + + public void handleFlowListenerException(Channel channel, Throwable exception) { + handleChannelKiller(channel, exception, "FlowListener.handleFlow"); + } + + public void handleConfirmListenerException(Channel channel, Throwable exception) { + handleChannelKiller(channel, exception, "ConfirmListener.handle{N,A}ck"); + } + + public void handleBlockedListenerException(Connection connection, Throwable exception) { + handleConnectionKiller(connection, exception, "BlockedListener"); + } + + public void handleConsumerException(Channel channel, Throwable exception, + Consumer consumer, String consumerTag, + String methodName) + { + handleChannelKiller(channel, exception, "Consumer " + consumer + + " (" + consumerTag + ")" + + " method " + methodName + + " for channel " + channel); + } + + protected void handleChannelKiller(Channel channel, Throwable exception, String what) { + System.err.println(this.getClass().getName() + ": " + what + " threw an exception for channel " + + channel + ":"); + exception.printStackTrace(); + try { + channel.close(AMQP.REPLY_SUCCESS, "Closed due to exception from " + what); + } catch (AlreadyClosedException ace) { + // noop + } catch (TimeoutException ace) { + // noop + } catch (IOException ioe) { + // TODO: log the failure + System.err.println("Failure during close of channel " + channel + " after " + exception + + ":"); + ioe.printStackTrace(); + channel.getConnection().abort(AMQP.INTERNAL_ERROR, "Internal error closing channel for " + what); + } + } +} diff --git a/test/src/com/rabbitmq/client/test/functional/ExceptionHandling.java b/test/src/com/rabbitmq/client/test/functional/ExceptionHandling.java index 1ed485e178..fd9c27485f 100644 --- a/test/src/com/rabbitmq/client/test/functional/ExceptionHandling.java +++ b/test/src/com/rabbitmq/client/test/functional/ExceptionHandling.java @@ -9,6 +9,7 @@ import com.rabbitmq.client.Envelope; import com.rabbitmq.client.ExceptionHandler; import com.rabbitmq.client.impl.DefaultExceptionHandler; +import com.rabbitmq.client.impl.ForgivingExceptionHandler; import junit.framework.TestCase; import java.io.IOException; @@ -23,15 +24,34 @@ private ConnectionFactory newConnectionFactory(ExceptionHandler eh) { return cf; } - public void testHandleConsumerException() throws IOException, InterruptedException, TimeoutException { + public void testDefaultConsumerHandleConsumerException() throws IOException, InterruptedException, TimeoutException { final CountDownLatch latch = new CountDownLatch(1); - final DefaultExceptionHandler eh = new DefaultExceptionHandler() { + final ExceptionHandler eh = new DefaultExceptionHandler() { @Override public void handleConsumerException(Channel channel, Throwable exception, Consumer consumer, String consumerTag, String methodName) { super.handleConsumerException(channel, exception, consumer, consumerTag, methodName); latch.countDown(); } }; + + testConsumerHandleConsumerException(eh, latch, true); + } + + public void testForgivingConsumerHandleConsumerException() throws IOException, InterruptedException, TimeoutException { + final CountDownLatch latch = new CountDownLatch(1); + final ExceptionHandler eh = new ForgivingExceptionHandler() { + @Override + public void handleConsumerException(Channel channel, Throwable exception, Consumer consumer, String consumerTag, String methodName) { + super.handleConsumerException(channel, exception, consumer, consumerTag, methodName); + latch.countDown(); + } + }; + + testConsumerHandleConsumerException(eh, latch, false); + } + + protected void testConsumerHandleConsumerException(ExceptionHandler eh, CountDownLatch latch, boolean expectChannelClose) + throws InterruptedException, TimeoutException, IOException { ConnectionFactory cf = newConnectionFactory(eh); assertEquals(cf.getExceptionHandler(), eh); Connection conn = cf.newConnection(); @@ -47,7 +67,8 @@ public void handleDelivery(String consumerTag, Envelope envelope, }); ch.basicPublish("", q, null, "".getBytes()); wait(latch); - assertFalse(ch.isOpen()); + + assertEquals(!expectChannelClose, ch.isOpen()); } public void testNullExceptionHandler() { From 7d4f61470077e93e5d851e77bcf4ab1e07bd0d64 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Sat, 4 Jul 2015 01:56:39 +0300 Subject: [PATCH 0033/2114] Typo --- src/com/rabbitmq/client/impl/StrictExceptionHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/rabbitmq/client/impl/StrictExceptionHandler.java b/src/com/rabbitmq/client/impl/StrictExceptionHandler.java index 4d879ffac9..50d6b78f12 100644 --- a/src/com/rabbitmq/client/impl/StrictExceptionHandler.java +++ b/src/com/rabbitmq/client/impl/StrictExceptionHandler.java @@ -29,7 +29,7 @@ import com.rabbitmq.client.TopologyRecoveryException; /** - * An implementation of {@link com.rabbitmq.client.ExceptionHandler} that does not + * An implementation of {@link com.rabbitmq.client.ExceptionHandler} that does * close channels on unhandled consumer exception. * * Used by {@link AMQConnection}. From 6cd0fda33902c72e8700a08c153cb1378e172594 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Sun, 5 Jul 2015 20:04:36 +0300 Subject: [PATCH 0034/2114] Add a case with negative header value --- test/src/com/rabbitmq/client/test/TableTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/src/com/rabbitmq/client/test/TableTest.java b/test/src/com/rabbitmq/client/test/TableTest.java index 4a38ba6262..4c976b9a19 100644 --- a/test/src/com/rabbitmq/client/test/TableTest.java +++ b/test/src/com/rabbitmq/client/test/TableTest.java @@ -92,5 +92,7 @@ public void testLoop() table.put("d", LongStringHelper.asLongString("d")); assertEquals(table, unmarshal(marshal(table))); + table.put("e", -126); + assertEquals(table, unmarshal(marshal(table))); } } From f18c1ad8959bcb29c70e33121b5d9d2f5246615f Mon Sep 17 00:00:00 2001 From: Daniel Hakim Date: Tue, 21 Jul 2015 20:26:05 -0400 Subject: [PATCH 0035/2114] Stops Recovery When Client Closes Adds a boolean flag, manuallyClosed to keep track of whether or not the AutoRecoveringConnection has been told to close by the application. If flag is set before recovery attempt, autorecovery fails out. If flag is set mid recovery attempt, creates the new connection, then immediately aborts it. --- .../recovery/AutorecoveringConnection.java | 80 +++++++++++++++---- 1 file changed, 64 insertions(+), 16 deletions(-) diff --git a/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index f56f2eed2d..2dddb86ad5 100644 --- a/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -67,7 +67,14 @@ public class AutorecoveringConnection implements Connection, Recoverable, Networ private final Map consumers = new ConcurrentHashMap(); private final List consumerRecoveryListeners = new ArrayList(); private final List queueRecoveryListeners = new ArrayList(); - + + // Used to block connection recovery attempts after close() is invoked. + private volatile boolean manuallyClosed = false; + + // This lock guards the manuallyClosed flag and the delegate connection. Guarding these two ensures that a new connection can never + // be created after application code has initiated shutdown. + private Object recoveryLock = new Object(); + public AutorecoveringConnection(ConnectionParams params, FrameHandlerFactory f, Address[] addrs) { this.cf = new RecoveryAwareAMQConnectionFactory(params, f, addrs); this.params = params; @@ -181,6 +188,9 @@ public boolean isOpen() { * @see com.rabbitmq.client.Connection#close() */ public void close() throws IOException { + synchronized(recoveryLock) { + this.manuallyClosed = true; + } delegate.close(); } @@ -188,6 +198,9 @@ public void close() throws IOException { * @see Connection#close(int) */ public void close(int timeout) throws IOException { + synchronized(recoveryLock) { + this.manuallyClosed = true; + } delegate.close(timeout); } @@ -195,6 +208,9 @@ public void close(int timeout) throws IOException { * @see Connection#close(int, String, int) */ public void close(int closeCode, String closeMessage, int timeout) throws IOException { + synchronized(recoveryLock) { + this.manuallyClosed = true; + } delegate.close(closeCode, closeMessage, timeout); } @@ -202,6 +218,9 @@ public void close(int closeCode, String closeMessage, int timeout) throws IOExce * @see com.rabbitmq.client.Connection#abort() */ public void abort() { + synchronized(recoveryLock) { + this.manuallyClosed = true; + } delegate.abort(); } @@ -209,6 +228,9 @@ public void abort() { * @see Connection#abort(int, String, int) */ public void abort(int closeCode, String closeMessage, int timeout) { + synchronized(recoveryLock) { + this.manuallyClosed = true; + } delegate.abort(closeCode, closeMessage, timeout); } @@ -216,6 +238,9 @@ public void abort(int closeCode, String closeMessage, int timeout) { * @see Connection#abort(int, String) */ public void abort(int closeCode, String closeMessage) { + synchronized(recoveryLock) { + this.manuallyClosed = true; + } delegate.abort(closeCode, closeMessage); } @@ -223,6 +248,9 @@ public void abort(int closeCode, String closeMessage) { * @see Connection#abort(int) */ public void abort(int timeout) { + synchronized(recoveryLock) { + this.manuallyClosed = true; + } delegate.abort(timeout); } @@ -261,7 +289,10 @@ public void clearBlockedListeners() { * @see com.rabbitmq.client.Connection#close(int, String) */ public void close(int closeCode, String closeMessage) throws IOException { - delegate.close(closeCode, closeMessage); + synchronized(recoveryLock) { + this.manuallyClosed = true; + } + delegate.close(closeCode, closeMessage); } /** @@ -404,16 +435,18 @@ public void removeConsumerRecoveryListener(ConsumerRecoveryListener listener) { synchronized private void beginAutomaticRecovery() throws InterruptedException, IOException, TopologyRecoveryException { Thread.sleep(this.params.getNetworkRecoveryInterval()); - this.recoverConnection(); - this.recoverShutdownListeners(); - this.recoverBlockedListeners(); - this.recoverChannels(); - if(this.params.isTopologyRecoveryEnabled()) { - this.recoverEntities(); - this.recoverConsumers(); - } + if (!this.recoverConnection()) + return; + + this.recoverShutdownListeners(); + this.recoverBlockedListeners(); + this.recoverChannels(); + if(this.params.isTopologyRecoveryEnabled()) { + this.recoverEntities(); + this.recoverConsumers(); + } - this.notifyRecoveryListeners(); + this.notifyRecoveryListeners(); } private void recoverShutdownListeners() { @@ -428,18 +461,33 @@ private void recoverBlockedListeners() { } } - private void recoverConnection() throws IOException, InterruptedException { - boolean recovering = true; - while (recovering) { + // Returns true if the connection was recovered, + // false if application initiated shutdown while attempting recovery. + private boolean recoverConnection() throws IOException, InterruptedException { + while (!manuallyClosed) + { try { - this.delegate = this.cf.newConnection(); - recovering = false; + RecoveryAwareAMQConnection newConn = this.cf.newConnection(); + synchronized(recoveryLock) { + if (!manuallyClosed) { + // This is the standard case. + this.delegate = newConn; + return true; + } + } + // This is the once in a blue moon case. + // Application code just called close as the connection + // was being re-established. So we attempt to close the newly created connection. + newConn.abort(); + return false; } catch (Exception e) { // TODO: exponential back-off Thread.sleep(this.params.getNetworkRecoveryInterval()); this.getExceptionHandler().handleConnectionRecoveryException(this, e); } } + + return false; } private void recoverChannels() { From 997aefc4aada919eb4f5847fff7b4d7411583e64 Mon Sep 17 00:00:00 2001 From: "Gavin M. Roy" Date: Fri, 21 Aug 2015 21:36:22 -0400 Subject: [PATCH 0036/2114] Add travis-ci configuration --- .travis.yml | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000000..4b4c6bb4dc --- /dev/null +++ b/.travis.yml @@ -0,0 +1,29 @@ +sudo: false +language: erlang +addons: + apt: + packages: + - xsltproc +services: + - rabbitmq +otp_release: + - "R16B03-1" +install: + - if [ ! -d "$HOME/rabbitmq-public-umbrella/.git" ]; then git clone https://github.com/rabbitmq/rabbitmq-public-umbrella.git $HOME/rabbitmq-public-umbrella; fi + - cd $HOME/rabbitmq-public-umbrella + - make co + - make up +before_script: + - IFS="/" read -a PARTS <<< "$TRAVIS_REPO_SLUG" + - export TEST_DIR=$HOME/rabbitmq-public-umbrella/${PARTS[1]} + - rm -rf ${TEST_DIR} + - cp -r ${TRAVIS_BUILD_DIR} ${TEST_DIR} + - cd ${TEST_DIR} +script: ant test-client +before_cache: + - rm -rf ${TEST_DIR} + - cd $HOME +cache: + apt: true + directories: + - $HOME/rabbitmq-public-umbrella From c7008faaf3427fdbabf6824b0d1d1f36174a777b Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Tue, 25 Aug 2015 17:36:23 +0300 Subject: [PATCH 0037/2114] Make handshake timeout configurable Fixes #81. --- .../rabbitmq/client/ConnectionFactory.java | 45 +++++++++++++++---- .../rabbitmq/client/impl/AMQConnection.java | 10 ++--- .../client/impl/ConnectionParams.java | 13 +++++- 3 files changed, 53 insertions(+), 15 deletions(-) diff --git a/src/com/rabbitmq/client/ConnectionFactory.java b/src/com/rabbitmq/client/ConnectionFactory.java index e4163c6916..364d55dcbb 100644 --- a/src/com/rabbitmq/client/ConnectionFactory.java +++ b/src/com/rabbitmq/client/ConnectionFactory.java @@ -70,9 +70,14 @@ public class ConnectionFactory implements Cloneable { public static final int DEFAULT_AMQP_PORT = AMQP.PROTOCOL.PORT; /** The default ssl port */ public static final int DEFAULT_AMQP_OVER_SSL_PORT = 5671; - /** The default connection timeout; + /** The default TCP connection timeout; * zero means wait indefinitely */ public static final int DEFAULT_CONNECTION_TIMEOUT = 0; + /** + * The default AMQP 0-9-1 connection handshake timeout. See DEFAULT_CONNECTION_TIMEOUT + * for TCP (socket) connection timeout. + */ + public static final int DEFAULT_HANDSHAKE_TIMEOUT = 10000; /** The default shutdown timeout; * zero means wait indefinitely */ public static final int DEFAULT_SHUTDOWN_TIMEOUT = 10000; @@ -89,6 +94,7 @@ public class ConnectionFactory implements Cloneable { private int requestedFrameMax = DEFAULT_FRAME_MAX; private int requestedHeartbeat = DEFAULT_HEARTBEAT; private int connectionTimeout = DEFAULT_CONNECTION_TIMEOUT; + private int handshakeTimeout = DEFAULT_HANDSHAKE_TIMEOUT; private int shutdownTimeout = DEFAULT_SHUTDOWN_TIMEOUT; private Map _clientProperties = AMQConnection.defaultClientProperties(); private SocketFactory factory = SocketFactory.getDefault(); @@ -308,21 +314,41 @@ public int getRequestedHeartbeat() { } /** - * Set the connection timeout. - * @param connectionTimeout connection establishment timeout in milliseconds; zero for infinite + * Set the TCP connection timeout. + * @param connectionTimeout connection TCP establishment timeout in milliseconds; zero for infinite */ public void setConnectionTimeout(int connectionTimeout) { this.connectionTimeout = connectionTimeout; } /** - * Retrieve the connection timeout. - * @return the connection timeout, in milliseconds; zero for infinite + * Retrieve the TCP connection timeout. + * @return the TCP connection timeout, in milliseconds; zero for infinite */ public int getConnectionTimeout() { return this.connectionTimeout; } + /** + * Retrieve the AMQP 0-9-1 protocol handshake timeout. + * @return the AMQP0-9-1 protocol handshake timeout, in milliseconds + */ + public int getHandshakeTimeout() { + return handshakeTimeout; + } + + /** + * Set the AMQP0-9-1 protocol handshake timeout. + * @param handshakeTimeout the AMQP0-9-1 protocol handshake timeout, in milliseconds + */ + public void setHandshakeTimeout(int handshakeTimeout) { + if(handshakeTimeout < connectionTimeout) { + this.handshakeTimeout = handshakeTimeout; + } else { + throw new IllegalArgumentException("handshake timeout cannot be lower than TCP connection timeout"); + } + } + /** * Set the shutdown timeout. This is the amount of time that Consumer implementations have to * continue working through deliveries (and other Consumer callbacks) after the connection @@ -629,9 +655,12 @@ public Connection newConnection(ExecutorService executor, Address[] addrs) } public ConnectionParams params(ExecutorService executor) { - return new ConnectionParams(username, password, executor, virtualHost, getClientProperties(), - requestedFrameMax, requestedChannelMax, requestedHeartbeat, shutdownTimeout, saslConfig, - networkRecoveryInterval, topologyRecovery, exceptionHandler, threadFactory); + // TODO: switch to use setters for all fields + ConnectionParams result = new ConnectionParams(username, password, executor, virtualHost, getClientProperties(), + requestedFrameMax, requestedChannelMax, requestedHeartbeat, shutdownTimeout, saslConfig, + networkRecoveryInterval, topologyRecovery, exceptionHandler, threadFactory); + result.setHandshakeTimeout(handshakeTimeout); + return result; } /** diff --git a/src/com/rabbitmq/client/impl/AMQConnection.java b/src/com/rabbitmq/client/impl/AMQConnection.java index d2fd4524b0..484dddba99 100644 --- a/src/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/com/rabbitmq/client/impl/AMQConnection.java @@ -63,8 +63,6 @@ final class Copyright { * for an example. */ public class AMQConnection extends ShutdownNotifierComponent implements Connection, NetworkConnection { - /** Timeout used while waiting for AMQP handshaking to complete (milliseconds) */ - public static final int HANDSHAKE_TIMEOUT = 10000; private final ExecutorService executor; private Thread mainLoopThread; private ThreadFactory threadFactory = Executors.defaultThreadFactory(); @@ -139,6 +137,7 @@ public static final Map defaultClientProperties() { private final int requestedHeartbeat; private final int requestedChannelMax; private final int requestedFrameMax; + private final int handshakeTimeout; private final int shutdownTimeout; private final String username; private final String password; @@ -218,6 +217,7 @@ public AMQConnection(ConnectionParams params, FrameHandler frameHandler) this.requestedFrameMax = params.getRequestedFrameMax(); this.requestedChannelMax = params.getRequestedChannelMax(); this.requestedHeartbeat = params.getRequestedHeartbeat(); + this.handshakeTimeout = params.getHandshakeTimeout(); this.shutdownTimeout = params.getShutdownTimeout(); this.saslConfig = params.getSaslConfig(); this.executor = params.getExecutor(); @@ -273,7 +273,7 @@ public void start() try { // The following two lines are akin to AMQChannel's // transmit() method for this pseudo-RPC. - _frameHandler.setTimeout(HANDSHAKE_TIMEOUT); + _frameHandler.setTimeout(handshakeTimeout); _frameHandler.sendHeader(); } catch (IOException ioe) { _frameHandler.close(); @@ -291,7 +291,7 @@ public void start() AMQP.Connection.Tune connTune = null; try { connStart = - (AMQP.Connection.Start) connStartBlocker.getReply(HANDSHAKE_TIMEOUT/2).getMethod(); + (AMQP.Connection.Start) connStartBlocker.getReply(handshakeTimeout/2).getMethod(); _serverProperties = Collections.unmodifiableMap(connStart.getServerProperties()); @@ -324,7 +324,7 @@ public void start() : new AMQP.Connection.SecureOk.Builder().response(response).build(); try { - Method serverResponse = _channel0.rpc(method, HANDSHAKE_TIMEOUT/2).getMethod(); + Method serverResponse = _channel0.rpc(method, handshakeTimeout/2).getMethod(); if (serverResponse instanceof AMQP.Connection.Tune) { connTune = (AMQP.Connection.Tune) serverResponse; } else { diff --git a/src/com/rabbitmq/client/impl/ConnectionParams.java b/src/com/rabbitmq/client/impl/ConnectionParams.java index 6a28df4087..2dfeba745f 100644 --- a/src/com/rabbitmq/client/impl/ConnectionParams.java +++ b/src/com/rabbitmq/client/impl/ConnectionParams.java @@ -16,6 +16,7 @@ public class ConnectionParams { private final int requestedFrameMax; private final int requestedChannelMax; private final int requestedHeartbeat; + private int handshakeTimeout; private final int shutdownTimeout; private final SaslConfig saslConfig; private final long networkRecoveryInterval; @@ -36,8 +37,8 @@ public class ConnectionParams { * @param saslConfig sasl configuration hook * @param networkRecoveryInterval interval used when recovering from network failure * @param topologyRecovery should topology (queues, exchanges, bindings, consumers) recovery be performed? - * @param threadFactory - * @param exceptionHandler + * @param threadFactory factory that instantiates threads used by the client + * @param exceptionHandler handles unhandled consumer exceptions */ public ConnectionParams(String username, String password, ExecutorService executor, String virtualHost, Map clientProperties, @@ -92,6 +93,14 @@ public int getRequestedHeartbeat() { return requestedHeartbeat; } + public int getHandshakeTimeout() { + return handshakeTimeout; + } + + public void setHandshakeTimeout(int timeout) { + this.handshakeTimeout = timeout; + } + public int getShutdownTimeout() { return shutdownTimeout; } From 4b94c5d4c6d7aea863abf05a8338b71651d4242a Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Tue, 25 Aug 2015 17:46:54 +0300 Subject: [PATCH 0038/2114] Run more tests on Travis --- .travis.yml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4b4c6bb4dc..444fb35b4a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,18 +8,16 @@ services: - rabbitmq otp_release: - "R16B03-1" + - "17.5" + - "18.0" install: - if [ ! -d "$HOME/rabbitmq-public-umbrella/.git" ]; then git clone https://github.com/rabbitmq/rabbitmq-public-umbrella.git $HOME/rabbitmq-public-umbrella; fi - cd $HOME/rabbitmq-public-umbrella - make co - make up before_script: - - IFS="/" read -a PARTS <<< "$TRAVIS_REPO_SLUG" - - export TEST_DIR=$HOME/rabbitmq-public-umbrella/${PARTS[1]} - - rm -rf ${TEST_DIR} - - cp -r ${TRAVIS_BUILD_DIR} ${TEST_DIR} - - cd ${TEST_DIR} -script: ant test-client + - cd $HOME/rabbitmq-public-umbrella/rabbitmq-test +script: make lite before_cache: - rm -rf ${TEST_DIR} - cd $HOME From 5fbda0db3b04767b923d5824353b3b405d08ac82 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Tue, 25 Aug 2015 17:51:37 +0300 Subject: [PATCH 0039/2114] Disable Travis CI for now --- .travis.yml | 27 --------------------------- 1 file changed, 27 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 444fb35b4a..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,27 +0,0 @@ -sudo: false -language: erlang -addons: - apt: - packages: - - xsltproc -services: - - rabbitmq -otp_release: - - "R16B03-1" - - "17.5" - - "18.0" -install: - - if [ ! -d "$HOME/rabbitmq-public-umbrella/.git" ]; then git clone https://github.com/rabbitmq/rabbitmq-public-umbrella.git $HOME/rabbitmq-public-umbrella; fi - - cd $HOME/rabbitmq-public-umbrella - - make co - - make up -before_script: - - cd $HOME/rabbitmq-public-umbrella/rabbitmq-test -script: make lite -before_cache: - - rm -rf ${TEST_DIR} - - cd $HOME -cache: - apt: true - directories: - - $HOME/rabbitmq-public-umbrella From 49d291103ebcf4df80cafa8c4d0c1c594301f398 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 26 Aug 2015 02:14:25 +0300 Subject: [PATCH 0040/2114] Improve argument validation based on user feedback --- .../rabbitmq/client/ConnectionFactory.java | 26 ++++++++---- .../client/test/AMQConnectionTest.java | 41 +++++++++++++++++++ 2 files changed, 59 insertions(+), 8 deletions(-) diff --git a/src/com/rabbitmq/client/ConnectionFactory.java b/src/com/rabbitmq/client/ConnectionFactory.java index 364d55dcbb..8573d3e137 100644 --- a/src/com/rabbitmq/client/ConnectionFactory.java +++ b/src/com/rabbitmq/client/ConnectionFactory.java @@ -315,10 +315,17 @@ public int getRequestedHeartbeat() { /** * Set the TCP connection timeout. - * @param connectionTimeout connection TCP establishment timeout in milliseconds; zero for infinite + * @param timeout connection TCP establishment timeout in milliseconds; zero for infinite */ - public void setConnectionTimeout(int connectionTimeout) { - this.connectionTimeout = connectionTimeout; + public void setConnectionTimeout(int timeout) { + if(timeout < 0) { + throw new IllegalArgumentException("TCP connection timeout cannot be negative"); + } + if(timeout > handshakeTimeout) { + throw new IllegalArgumentException("TCP connection timeout cannot be greater than handshake timeout"); + } else { + this.connectionTimeout = timeout; + } } /** @@ -339,13 +346,16 @@ public int getHandshakeTimeout() { /** * Set the AMQP0-9-1 protocol handshake timeout. - * @param handshakeTimeout the AMQP0-9-1 protocol handshake timeout, in milliseconds + * @param timeout the AMQP0-9-1 protocol handshake timeout, in milliseconds */ - public void setHandshakeTimeout(int handshakeTimeout) { - if(handshakeTimeout < connectionTimeout) { - this.handshakeTimeout = handshakeTimeout; - } else { + public void setHandshakeTimeout(int timeout) { + if(timeout < 0) { + throw new IllegalArgumentException("handshake timeout cannot be negative"); + } + if(connectionTimeout != 0 && timeout < connectionTimeout) { throw new IllegalArgumentException("handshake timeout cannot be lower than TCP connection timeout"); + } else { + this.handshakeTimeout = timeout; } } diff --git a/test/src/com/rabbitmq/client/test/AMQConnectionTest.java b/test/src/com/rabbitmq/client/test/AMQConnectionTest.java index 27821bda9f..d610ce4519 100644 --- a/test/src/com/rabbitmq/client/test/AMQConnectionTest.java +++ b/test/src/com/rabbitmq/client/test/AMQConnectionTest.java @@ -84,6 +84,47 @@ public static TestSuite suite() { super.tearDown(); } + public void testNegativeTCPConnectionTimeout() { + ConnectionFactory cf = new ConnectionFactory(); + try { + cf.setConnectionTimeout(-10); + fail("expected an exception"); + } catch (IllegalArgumentException _ignored) { + // expected + } + } + + public void testNegativeProtocolHandshakeTimeout() { + ConnectionFactory cf = new ConnectionFactory(); + try { + cf.setHandshakeTimeout(-10); + fail("expected an exception"); + } catch (IllegalArgumentException _ignored) { + // expected + } + } + + public void testTCPConnectionTimeoutGreaterThanHandShakeTimeout() { + ConnectionFactory cf = new ConnectionFactory(); + try { + cf.setHandshakeTimeout(3000); + cf.setConnectionTimeout(5000); + fail("expected an exception"); + } catch (IllegalArgumentException _ignored) { + // expected + } + } + + public void testProtocolHandshakeTimeoutGreaterThanTCPConnectionTimeout() { + ConnectionFactory cf = new ConnectionFactory(); + + cf.setConnectionTimeout(5000); + cf.setHandshakeTimeout(7000); + + cf.setConnectionTimeout(0); + cf.setHandshakeTimeout(7000); + } + /** Check the AMQConnection does send exactly 1 initial header, and deal correctly with * the frame handler throwing an exception when we try to read data */ From 3576480f2d2f1031a658fe770149cd0a150401c4 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Thu, 27 Aug 2015 00:51:54 +0300 Subject: [PATCH 0041/2114] Introduce LongString#toString Fixes #84, references #83. --- src/com/rabbitmq/client/LongString.java | 6 +++++ .../com/rabbitmq/client/test/ClientTests.java | 1 + .../rabbitmq/client/test/LongStringTest.java | 25 +++++++++++++++++++ 3 files changed, 32 insertions(+) create mode 100644 test/src/com/rabbitmq/client/test/LongStringTest.java diff --git a/src/com/rabbitmq/client/LongString.java b/src/com/rabbitmq/client/LongString.java index b503281750..05030dc5c7 100644 --- a/src/com/rabbitmq/client/LongString.java +++ b/src/com/rabbitmq/client/LongString.java @@ -53,4 +53,10 @@ public interface LongString * @return the array of bytes containing the content of the {@link LongString} */ public byte [] getBytes(); + + /** + * Get the content as a String. Uses UTF-8 as encoding. + * @return he content of the {@link LongString} as a string + */ + public String toString(); } diff --git a/test/src/com/rabbitmq/client/test/ClientTests.java b/test/src/com/rabbitmq/client/test/ClientTests.java index 7df48df58a..6f3274b8a8 100644 --- a/test/src/com/rabbitmq/client/test/ClientTests.java +++ b/test/src/com/rabbitmq/client/test/ClientTests.java @@ -24,6 +24,7 @@ public class ClientTests extends TestCase { public static TestSuite suite() { TestSuite suite = new TestSuite("client"); suite.addTest(TableTest.suite()); + suite.addTest(LongStringTest.suite()); suite.addTest(BlockingCellTest.suite()); suite.addTest(TruncatedInputStreamTest.suite()); suite.addTest(AMQConnectionTest.suite()); diff --git a/test/src/com/rabbitmq/client/test/LongStringTest.java b/test/src/com/rabbitmq/client/test/LongStringTest.java new file mode 100644 index 0000000000..61955ed541 --- /dev/null +++ b/test/src/com/rabbitmq/client/test/LongStringTest.java @@ -0,0 +1,25 @@ +package com.rabbitmq.client.test; + +import com.rabbitmq.client.LongString; +import com.rabbitmq.client.impl.LongStringHelper; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +import java.io.UnsupportedEncodingException; + +public class LongStringTest extends TestCase { +public static TestSuite suite() + { + TestSuite suite = new TestSuite("longString"); + suite.addTestSuite(LongStringTest.class); + return suite; + } + + public void testToString() throws UnsupportedEncodingException { + String s = "abcdef"; + LongString ls = LongStringHelper.asLongString(s); + + assertTrue(ls.toString().equals(s)); + assertTrue(ls.toString().equals(new String(ls.getBytes(), "UTF-8"))); + } +} From 57ecae54dd0f78b742c8d66e49ae09aaaecb702a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Wed, 2 Sep 2015 13:24:45 +0200 Subject: [PATCH 0042/2114] Makefile: Allow to override `ant` location and add flags --- Makefile | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index bf5df82554..653e5a3c2c 100644 --- a/Makefile +++ b/Makefile @@ -13,11 +13,14 @@ AMQP_CODEGEN_DIR=$(shell fgrep sibling.codegen.dir build.properties | sed -e 's: MAVEN_RSYNC_DESTINATION=maven@195.224.125.254:/home/maven/rabbitmq-java-client/ +ANT ?= ant +ANT_FLAGS ?= + all: - ant build + $(ANT) $(ANT_FLAGS) build clean: - ant clean + $(ANT) $(ANT_FLAGS) clean distclean: clean make -C $(AMQP_CODEGEN_DIR) clean @@ -27,17 +30,17 @@ dist: distclean srcdist dist_all maven-bundle dist_all: dist1.5 javadoc-archive jar: - ant jar + $(ANT) $(ANT_FLAGS) jar maven-bundle: - ant -Dimpl.version=$(VERSION) maven-bundle + $(ANT) $(ANT_FLAGS) -Dimpl.version=$(VERSION) maven-bundle dist1.5: - ant -Ddist.out=build/$(PACKAGE_NAME)-bin-$(VERSION) -Dimpl.version=$(VERSION) dist + $(ANT) $(ANT_FLAGS) -Ddist.out=build/$(PACKAGE_NAME)-bin-$(VERSION) -Dimpl.version=$(VERSION) dist $(MAKE) post-dist TARBALL_NAME=$(PACKAGE_NAME)-bin-$(VERSION) javadoc-archive: - ant javadoc + $(ANT) $(ANT_FLAGS) javadoc cp -Rp build/doc/api build/$(JAVADOC_ARCHIVE) (cd build; tar -zcf $(JAVADOC_ARCHIVE).tar.gz $(JAVADOC_ARCHIVE)) (cd build; zip -q -r $(JAVADOC_ARCHIVE).zip $(JAVADOC_ARCHIVE)) From 6ff390a65af2426e4a1a6bf9ff8e7a41a3776121 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Wed, 2 Sep 2015 14:38:40 +0200 Subject: [PATCH 0043/2114] Allow to override the path to rabbitmqctl and rabbitmq-test --- test/src/com/rabbitmq/tools/Host.java | 32 ++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/test/src/com/rabbitmq/tools/Host.java b/test/src/com/rabbitmq/tools/Host.java index 83f2bfb6f1..36e8e620ce 100644 --- a/test/src/com/rabbitmq/tools/Host.java +++ b/test/src/com/rabbitmq/tools/Host.java @@ -93,15 +93,15 @@ private static Process executeCommandProcess(String command) throws IOException } public static Process rabbitmqctl(String command) throws IOException { - return executeCommand("../rabbitmq-server/scripts/rabbitmqctl " + command); + return executeCommand(rabbitmqctlCommand() + " " + command); } public static Process rabbitmqctlIgnoreErrors(String command) throws IOException { - return executeCommandIgnoringErrors("../rabbitmq-server/scripts/rabbitmqctl " + command); + return executeCommandIgnoringErrors(rabbitmqctlCommand() + " " + command); } public static Process invokeMakeTarget(String command) throws IOException { - return executeCommand("cd ../rabbitmq-test; " + makeCommand() + " " + command); + return executeCommand("cd " + rabbitmqTestDir() + "; " + makeCommand() + " " + command); } private static String makeCommand() @@ -118,6 +118,32 @@ private static String makeCommand() return makecmd; } + private static String rabbitmqctlCommand() + { + // Get the rabbitmqctl(1) executable to use from the environment. + String cmd = System.getenv("RABBITMQCTL"); + + // Default to "make" if the environment variable is unset. + if (cmd == null) { + cmd = "../rabbitmq-server/scripts/rabbitmqctl"; + } + + return cmd; + } + + private static String rabbitmqTestDir() + { + // Get the rabbitmq-test directory to use from the environment. + String dir = System.getenv("RABBITMQ_TEST_DIR"); + + // Default to "make" if the environment variable is unset. + if (dir == null) { + dir = "../rabbitmq-test"; + } + + return dir; + } + public static void closeConnection(String pid) throws IOException { rabbitmqctl("close_connection '" + pid + "' 'Closed via rabbitmqctl'"); } From 1c30510684b2f2450d5c327f24619cb5d1a765fc Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 18 Sep 2015 15:55:04 +0300 Subject: [PATCH 0044/2114] Squash warnings in AMQConnection --- .../rabbitmq/client/impl/AMQConnection.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/com/rabbitmq/client/impl/AMQConnection.java b/src/com/rabbitmq/client/impl/AMQConnection.java index 484dddba99..afe65dad80 100644 --- a/src/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/com/rabbitmq/client/impl/AMQConnection.java @@ -75,7 +75,7 @@ public class AMQConnection extends ShutdownNotifierComponent implements Connecti * @return a map of client properties * @see Connection#getClientProperties */ - public static final Map defaultClientProperties() { + public static Map defaultClientProperties() { Map props = new HashMap(); props.put("product", LongStringHelper.asLongString("RabbitMQ")); props.put("version", LongStringHelper.asLongString(ClientVersion.VERSION)); @@ -166,7 +166,7 @@ public final void disconnectChannel(ChannelN channel) { cm.releaseChannelNumber(channel); } - private final void ensureIsOpen() + private void ensureIsOpen() throws AlreadyClosedException { if (!isOpen()) { @@ -287,7 +287,7 @@ public void start() mainLoopThread.start(); // after this point clear-up of MainLoop is triggered by closing the frameHandler. - AMQP.Connection.Start connStart = null; + AMQP.Connection.Start connStart; AMQP.Connection.Tune connTune = null; try { connStart = @@ -390,8 +390,6 @@ public void start() // We can now respond to errors having finished tailoring the connection this._inConnectionNegotiation = false; - - return; } protected ChannelManager instantiateChannelManager(int channelMax, ThreadFactory threadFactory) { @@ -408,7 +406,7 @@ protected int negotiateChannelMax(int requestedChannelMax, int serverMax) { /** * Private API - check required preconditions and protocol invariants */ - private static final void checkPreconditions() { + private static void checkPreconditions() { AMQCommand.checkPreconditions(); } @@ -451,8 +449,9 @@ public void setHeartbeat(int heartbeat) { * Makes it possible to override thread factory that is used * to instantiate connection network I/O loop. Only necessary * in the environments with restricted - * @param threadFactory + * @param threadFactory thread factory to use */ + @SuppressWarnings("unused") public void setThreadFactory(ThreadFactory threadFactory) { this.threadFactory = threadFactory; } @@ -460,6 +459,7 @@ public void setThreadFactory(ThreadFactory threadFactory) { /** * @return Thread factory used by this connection. */ + @SuppressWarnings("unused") public ThreadFactory getThreadFactory() { return threadFactory; } @@ -516,7 +516,7 @@ public void flush() throws IOException { _frameHandler.flush(); } - private static final int negotiatedMaxValue(int clientValue, int serverValue) { + private static int negotiatedMaxValue(int clientValue, int serverValue) { return (clientValue == 0 || serverValue == 0) ? Math.max(clientValue, serverValue) : Math.min(clientValue, serverValue); @@ -646,7 +646,7 @@ public boolean processControlCommand(Command c) throws IOException // Already shutting down, so just send back a CloseOk. try { _channel0.quiescingTransmit(new AMQP.Connection.CloseOk.Builder().build()); - } catch (IOException _e) { } // ignore + } catch (IOException ignored) { } // ignore return true; } else if (method instanceof AMQP.Connection.CloseOk) { // It's our final "RPC". Time to shut down. @@ -666,7 +666,7 @@ public void handleConnectionClose(Command closeCommand) { ShutdownSignalException sse = shutdown(closeCommand.getMethod(), false, null, _inConnectionNegotiation); try { _channel0.quiescingTransmit(new AMQP.Connection.CloseOk.Builder().build()); - } catch (IOException _e) { } // ignore + } catch (IOException ignored) { } // ignore _brokerInitiatedShutdown = true; SocketCloseWait scw = new SocketCloseWait(sse); final String name = "AMQP Connection Closing Monitor " + @@ -793,7 +793,7 @@ public void abort(int closeCode, String closeMessage, int timeout) { try { close(closeCode, closeMessage, true, null, timeout, true); - } catch (IOException _e) { } // ignore + } catch (IOException ignored) { } // ignore } /** From a603ebeb938a50cbc35da2aeb459dfed963bc86b Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 18 Sep 2015 15:55:28 +0300 Subject: [PATCH 0045/2114] Squash warnings in AMQChannel --- src/com/rabbitmq/client/impl/AMQChannel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/rabbitmq/client/impl/AMQChannel.java b/src/com/rabbitmq/client/impl/AMQChannel.java index 3f7c091ba5..9b9526bc7e 100644 --- a/src/com/rabbitmq/client/impl/AMQChannel.java +++ b/src/com/rabbitmq/client/impl/AMQChannel.java @@ -323,7 +323,7 @@ public void quiescingTransmit(AMQCommand c) throws IOException { while (_blockContent) { try { _channelMutex.wait(); - } catch (InterruptedException e) {} + } catch (InterruptedException ignored) {} // This is to catch a situation when the thread wakes up during // shutdown. Currently, no command that has content is allowed From 907ddfbdba5f20eaf148879a0721ff5df4d7e92d Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 18 Sep 2015 17:03:25 +0300 Subject: [PATCH 0046/2114] Refactor ConnectionParams to setters Before we introduce another field. --- .../rabbitmq/client/ConnectionFactory.java | 19 ++- .../client/impl/ConnectionParams.java | 126 ++++++++++-------- 2 files changed, 89 insertions(+), 56 deletions(-) diff --git a/src/com/rabbitmq/client/ConnectionFactory.java b/src/com/rabbitmq/client/ConnectionFactory.java index 8573d3e137..f5a6668703 100644 --- a/src/com/rabbitmq/client/ConnectionFactory.java +++ b/src/com/rabbitmq/client/ConnectionFactory.java @@ -665,10 +665,21 @@ public Connection newConnection(ExecutorService executor, Address[] addrs) } public ConnectionParams params(ExecutorService executor) { - // TODO: switch to use setters for all fields - ConnectionParams result = new ConnectionParams(username, password, executor, virtualHost, getClientProperties(), - requestedFrameMax, requestedChannelMax, requestedHeartbeat, shutdownTimeout, saslConfig, - networkRecoveryInterval, topologyRecovery, exceptionHandler, threadFactory); + ConnectionParams result = new ConnectionParams(); + + result.setUsername(username); + result.setPassword(password); + result.setExecutor(executor); + result.setVirtualHost(virtualHost); + result.setClientProperties(getClientProperties()); + result.setRequestedFrameMax(requestedFrameMax); + result.setRequestedChannelMax(requestedChannelMax); + result.setShutdownTimeout(shutdownTimeout); + result.setSaslConfig(saslConfig); + result.setNetworkRecoveryInterval(networkRecoveryInterval); + result.setTopologyRecovery(topologyRecovery); + result.setExceptionHandler(exceptionHandler); + result.setThreadFactory(threadFactory); result.setHandshakeTimeout(handshakeTimeout); return result; } diff --git a/src/com/rabbitmq/client/impl/ConnectionParams.java b/src/com/rabbitmq/client/impl/ConnectionParams.java index 2dfeba745f..d487f19fcd 100644 --- a/src/com/rabbitmq/client/impl/ConnectionParams.java +++ b/src/com/rabbitmq/client/impl/ConnectionParams.java @@ -8,58 +8,24 @@ import java.util.concurrent.ThreadFactory; public class ConnectionParams { - private final String username; - private final String password; - private final ExecutorService executor; - private final String virtualHost; - private final Map clientProperties; - private final int requestedFrameMax; - private final int requestedChannelMax; - private final int requestedHeartbeat; + private String username; + private String password; + private ExecutorService executor; + private String virtualHost; + private Map clientProperties; + private int requestedFrameMax; + private int requestedChannelMax; + private int requestedHeartbeat; private int handshakeTimeout; - private final int shutdownTimeout; - private final SaslConfig saslConfig; - private final long networkRecoveryInterval; - private final boolean topologyRecovery; - - private final ExceptionHandler exceptionHandler; - private final ThreadFactory threadFactory; - - /** - * @param username name used to establish connection - * @param password for username - * @param executor thread pool service for consumer threads for channels on this connection - * @param virtualHost virtual host of this connection - * @param clientProperties client info used in negotiating with the server - * @param requestedFrameMax max size of frame offered - * @param requestedChannelMax max number of channels offered - * @param requestedHeartbeat heart-beat in seconds offered - * @param saslConfig sasl configuration hook - * @param networkRecoveryInterval interval used when recovering from network failure - * @param topologyRecovery should topology (queues, exchanges, bindings, consumers) recovery be performed? - * @param threadFactory factory that instantiates threads used by the client - * @param exceptionHandler handles unhandled consumer exceptions - */ - public ConnectionParams(String username, String password, ExecutorService executor, - String virtualHost, Map clientProperties, - int requestedFrameMax, int requestedChannelMax, int requestedHeartbeat, - int shutdownTimeout, SaslConfig saslConfig, long networkRecoveryInterval, - boolean topologyRecovery, ExceptionHandler exceptionHandler, ThreadFactory threadFactory) { - this.username = username; - this.password = password; - this.executor = executor; - this.virtualHost = virtualHost; - this.clientProperties = clientProperties; - this.requestedFrameMax = requestedFrameMax; - this.requestedChannelMax = requestedChannelMax; - this.requestedHeartbeat = requestedHeartbeat; - this.shutdownTimeout = shutdownTimeout; - this.saslConfig = saslConfig; - this.networkRecoveryInterval = networkRecoveryInterval; - this.topologyRecovery = topologyRecovery; - this.exceptionHandler = exceptionHandler; - this.threadFactory = threadFactory; - } + private int shutdownTimeout; + private SaslConfig saslConfig; + private long networkRecoveryInterval; + private boolean topologyRecovery; + + private ExceptionHandler exceptionHandler; + private ThreadFactory threadFactory; + + public ConnectionParams() {} public String getUsername() { return username; @@ -121,7 +87,63 @@ public boolean isTopologyRecoveryEnabled() { return topologyRecovery; } - public ThreadFactory getThreadFactory() { + public ThreadFactory getThreadFactory() { return threadFactory; } + + public void setUsername(String username) { + this.username = username; + } + + public void setPassword(String password) { + this.password = password; + } + + public void setExecutor(ExecutorService executor) { + this.executor = executor; + } + + public void setVirtualHost(String virtualHost) { + this.virtualHost = virtualHost; + } + + public void setClientProperties(Map clientProperties) { + this.clientProperties = clientProperties; + } + + public void setRequestedFrameMax(int requestedFrameMax) { + this.requestedFrameMax = requestedFrameMax; + } + + public void setRequestedChannelMax(int requestedChannelMax) { + this.requestedChannelMax = requestedChannelMax; + } + + public void setRequestedHeartbeat(int requestedHeartbeat) { + this.requestedHeartbeat = requestedHeartbeat; + } + + public void setShutdownTimeout(int shutdownTimeout) { + this.shutdownTimeout = shutdownTimeout; + } + + public void setSaslConfig(SaslConfig saslConfig) { + this.saslConfig = saslConfig; + } + + public void setNetworkRecoveryInterval(long networkRecoveryInterval) { + this.networkRecoveryInterval = networkRecoveryInterval; + } + + public void setTopologyRecovery(boolean topologyRecovery) { + this.topologyRecovery = topologyRecovery; + } + + public void setExceptionHandler(ExceptionHandler exceptionHandler) { + this.exceptionHandler = exceptionHandler; + } + + public void setThreadFactory(ThreadFactory threadFactory) { + this.threadFactory = threadFactory; + } } From 2f60a8b15dce0aa059acf9866f48af7b96fd1475 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 18 Sep 2015 17:05:22 +0300 Subject: [PATCH 0047/2114] Set requested heartbeat, too --- src/com/rabbitmq/client/ConnectionFactory.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/com/rabbitmq/client/ConnectionFactory.java b/src/com/rabbitmq/client/ConnectionFactory.java index f5a6668703..392882e892 100644 --- a/src/com/rabbitmq/client/ConnectionFactory.java +++ b/src/com/rabbitmq/client/ConnectionFactory.java @@ -681,6 +681,7 @@ public ConnectionParams params(ExecutorService executor) { result.setExceptionHandler(exceptionHandler); result.setThreadFactory(threadFactory); result.setHandshakeTimeout(handshakeTimeout); + result.setRequestedHeartbeat(requestedHeartbeat); return result; } From f6b969e0b4664d00e62e6aea22703f24468808b3 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 18 Sep 2015 17:11:42 +0300 Subject: [PATCH 0048/2114] More specific ConnectionParams field name --- src/com/rabbitmq/client/ConnectionFactory.java | 4 ++-- src/com/rabbitmq/client/impl/AMQConnection.java | 2 +- src/com/rabbitmq/client/impl/ConnectionParams.java | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/com/rabbitmq/client/ConnectionFactory.java b/src/com/rabbitmq/client/ConnectionFactory.java index 392882e892..6653982676 100644 --- a/src/com/rabbitmq/client/ConnectionFactory.java +++ b/src/com/rabbitmq/client/ConnectionFactory.java @@ -664,12 +664,12 @@ public Connection newConnection(ExecutorService executor, Address[] addrs) } } - public ConnectionParams params(ExecutorService executor) { + public ConnectionParams params(ExecutorService consumerWorkServiceExecutor) { ConnectionParams result = new ConnectionParams(); result.setUsername(username); result.setPassword(password); - result.setExecutor(executor); + result.setConsumerWorkServiceExecutor(consumerWorkServiceExecutor); result.setVirtualHost(virtualHost); result.setClientProperties(getClientProperties()); result.setRequestedFrameMax(requestedFrameMax); diff --git a/src/com/rabbitmq/client/impl/AMQConnection.java b/src/com/rabbitmq/client/impl/AMQConnection.java index afe65dad80..365c4506f8 100644 --- a/src/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/com/rabbitmq/client/impl/AMQConnection.java @@ -220,7 +220,7 @@ public AMQConnection(ConnectionParams params, FrameHandler frameHandler) this.handshakeTimeout = params.getHandshakeTimeout(); this.shutdownTimeout = params.getShutdownTimeout(); this.saslConfig = params.getSaslConfig(); - this.executor = params.getExecutor(); + this.executor = params.getConsumerWorkServiceExecutor(); this.threadFactory = params.getThreadFactory(); this._channelManager = null; diff --git a/src/com/rabbitmq/client/impl/ConnectionParams.java b/src/com/rabbitmq/client/impl/ConnectionParams.java index d487f19fcd..d42679b906 100644 --- a/src/com/rabbitmq/client/impl/ConnectionParams.java +++ b/src/com/rabbitmq/client/impl/ConnectionParams.java @@ -10,7 +10,7 @@ public class ConnectionParams { private String username; private String password; - private ExecutorService executor; + private ExecutorService consumerWorkServiceExecutor; private String virtualHost; private Map clientProperties; private int requestedFrameMax; @@ -35,8 +35,8 @@ public String getPassword() { return password; } - public ExecutorService getExecutor() { - return executor; + public ExecutorService getConsumerWorkServiceExecutor() { + return consumerWorkServiceExecutor; } public String getVirtualHost() { @@ -99,8 +99,8 @@ public void setPassword(String password) { this.password = password; } - public void setExecutor(ExecutorService executor) { - this.executor = executor; + public void setConsumerWorkServiceExecutor(ExecutorService consumerWorkServiceExecutor) { + this.consumerWorkServiceExecutor = consumerWorkServiceExecutor; } public void setVirtualHost(String virtualHost) { From 22ddfedea874ec2c6b99d96e60fcd8046b78d8d0 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 18 Sep 2015 18:57:27 +0300 Subject: [PATCH 0049/2114] Use an executor for shutdown monitors Fixes #87. --- .../rabbitmq/client/ConnectionFactory.java | 38 ++++++++++++++++++- .../rabbitmq/client/impl/AMQConnection.java | 23 ++++++----- .../client/impl/ConnectionParams.java | 9 +++++ 3 files changed, 59 insertions(+), 11 deletions(-) diff --git a/src/com/rabbitmq/client/ConnectionFactory.java b/src/com/rabbitmq/client/ConnectionFactory.java index 6653982676..b74556ca52 100644 --- a/src/com/rabbitmq/client/ConnectionFactory.java +++ b/src/com/rabbitmq/client/ConnectionFactory.java @@ -101,6 +101,9 @@ public class ConnectionFactory implements Cloneable { private SaslConfig saslConfig = DefaultSaslConfig.PLAIN; private ExecutorService sharedExecutor; private ThreadFactory threadFactory = Executors.defaultThreadFactory(); + // minimises the number of threads rapid closure of many + // connections uses, see rabbitmq/rabbitmq-java-client#86 + private ExecutorService shutdownExecutor; private SocketConfigurator socketConf = new DefaultSocketConfigurator(); private ExceptionHandler exceptionHandler = new DefaultExceptionHandler(); @@ -469,18 +472,34 @@ public void setSocketConfigurator(SocketConfigurator socketConfigurator) { } /** - * Set the executor to use by default for newly created connections. + * Set the executor to use for consumer operation dispatch + * by default for newly created connections. * All connections that use this executor share it. * * It's developer's responsibility to shut down the executor * when it is no longer needed. * - * @param executor + * @param executor executor service to be used for + * consumer operation */ public void setSharedExecutor(ExecutorService executor) { this.sharedExecutor = executor; } + /** + * Set the executor to use for connection shutdown. + * All connections that use this executor share it. + * + * It's developer's responsibility to shut down the executor + * when it is no longer needed. + * + * @param executor executor service to be used for + * connection shutdown + */ + public void setShutdownExecutor(ExecutorService executor) { + this.shutdownExecutor = executor; + } + /** * Retrieve the thread factory used to instantiate new threads. * @see ThreadFactory @@ -640,6 +659,8 @@ public Connection newConnection(Address[] addrs) throws IOException, TimeoutExce */ public Connection newConnection(ExecutorService executor, Address[] addrs) throws IOException, TimeoutException { + // make sure we respect the provided thread factory + maybeInitializeShutdownExecutor(); FrameHandlerFactory fhFactory = createFrameHandlerFactory(); ConnectionParams params = params(executor); @@ -682,6 +703,7 @@ public ConnectionParams params(ExecutorService consumerWorkServiceExecutor) { result.setThreadFactory(threadFactory); result.setHandshakeTimeout(handshakeTimeout); result.setRequestedHeartbeat(requestedHeartbeat); + result.setShutdownExecutor(shutdownExecutor); return result; } @@ -718,6 +740,18 @@ public Connection newConnection(ExecutorService executor) throws IOException, Ti ); } + /** + * Lazily initializes shutdown executor service. This is necessary + * to make sure the default executor uses the thread factory that + * may be user-provided and crucially important in certain environments, + * e.g. Google App Engine or JEE application servers. + */ + protected void maybeInitializeShutdownExecutor() { + if(shutdownExecutor == null) { + shutdownExecutor = Executors.newFixedThreadPool(4, threadFactory); + } + } + @Override public ConnectionFactory clone(){ try { return (ConnectionFactory)super.clone(); diff --git a/src/com/rabbitmq/client/impl/AMQConnection.java b/src/com/rabbitmq/client/impl/AMQConnection.java index 365c4506f8..0fc0224d98 100644 --- a/src/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/com/rabbitmq/client/impl/AMQConnection.java @@ -63,7 +63,8 @@ final class Copyright { * for an example. */ public class AMQConnection extends ShutdownNotifierComponent implements Connection, NetworkConnection { - private final ExecutorService executor; + private final ExecutorService consumerWorkServiceExecutor; + private final ExecutorService shutdownExecutor; private Thread mainLoopThread; private ThreadFactory threadFactory = Executors.defaultThreadFactory(); @@ -220,7 +221,8 @@ public AMQConnection(ConnectionParams params, FrameHandler frameHandler) this.handshakeTimeout = params.getHandshakeTimeout(); this.shutdownTimeout = params.getShutdownTimeout(); this.saslConfig = params.getSaslConfig(); - this.executor = params.getConsumerWorkServiceExecutor(); + this.consumerWorkServiceExecutor = params.getConsumerWorkServiceExecutor(); + this.shutdownExecutor = params.getShutdownExecutor(); this.threadFactory = params.getThreadFactory(); this._channelManager = null; @@ -231,7 +233,7 @@ public AMQConnection(ConnectionParams params, FrameHandler frameHandler) } private void initializeConsumerWorkService() { - this._workService = new ConsumerWorkService(executor, threadFactory, shutdownTimeout); + this._workService = new ConsumerWorkService(consumerWorkServiceExecutor, threadFactory, shutdownTimeout); } private void initializeHeartbeatSender() { @@ -478,7 +480,7 @@ public ExceptionHandler getExceptionHandler() { /** Public API * - * @return true if this work service instance uses its own executor (as opposed to a shared one) + * @return true if this work service instance uses its own consumerWorkServiceExecutor (as opposed to a shared one) */ public boolean willShutDownConsumerExecutor() { return this._workService.usesPrivateExecutor(); @@ -669,12 +671,12 @@ public void handleConnectionClose(Command closeCommand) { } catch (IOException ignored) { } // ignore _brokerInitiatedShutdown = true; SocketCloseWait scw = new SocketCloseWait(sse); - final String name = "AMQP Connection Closing Monitor " + - getHostAddress() + ":" + getPort(); - Thread waiter = Environment.newThread(threadFactory, scw, name); - waiter.start(); + shutdownExecutor.execute(scw); } + // same as ConnectionFactory.DEFAULT_SHUTDOWN_TIMEOUT + private static long SOCKET_CLOSE_TIMEOUT = 10000; + private class SocketCloseWait implements Runnable { private final ShutdownSignalException cause; @@ -684,9 +686,12 @@ public SocketCloseWait(ShutdownSignalException sse) { public void run() { try { - _appContinuation.get(); + // TODO: use a sensible timeout here + _appContinuation.get(SOCKET_CLOSE_TIMEOUT); } catch (InterruptedException e) { Thread.currentThread().interrupt(); + } catch (TimeoutException ignored) { + // this releases the thread } finally { _running = false; _channel0.notifyOutstandingRpc(cause); diff --git a/src/com/rabbitmq/client/impl/ConnectionParams.java b/src/com/rabbitmq/client/impl/ConnectionParams.java index d42679b906..a7eacd0391 100644 --- a/src/com/rabbitmq/client/impl/ConnectionParams.java +++ b/src/com/rabbitmq/client/impl/ConnectionParams.java @@ -11,6 +11,7 @@ public class ConnectionParams { private String username; private String password; private ExecutorService consumerWorkServiceExecutor; + private ExecutorService shutdownExecutor; private String virtualHost; private Map clientProperties; private int requestedFrameMax; @@ -146,4 +147,12 @@ public void setExceptionHandler(ExceptionHandler exceptionHandler) { public void setThreadFactory(ThreadFactory threadFactory) { this.threadFactory = threadFactory; } + + public ExecutorService getShutdownExecutor() { + return shutdownExecutor; + } + + public void setShutdownExecutor(ExecutorService shutdownExecutor) { + this.shutdownExecutor = shutdownExecutor; + } } From 0d097de0ffca259e2db5b238de0c332924393f0c Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Mon, 21 Sep 2015 16:17:11 +0300 Subject: [PATCH 0050/2114] Upgrade JUnit to 4.x --- lib/hamcrest-core.jar | Bin 0 -> 45024 bytes lib/junit.jar | Bin 121070 -> 314932 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 lib/hamcrest-core.jar diff --git a/lib/hamcrest-core.jar b/lib/hamcrest-core.jar new file mode 100644 index 0000000000000000000000000000000000000000..9d5fe16e3dd37ebe79a36f61f5d0e1a69a653a8a GIT binary patch literal 45024 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 UgpPtD2z>DYYp}SJr5?)v0beu;=l}o! literal 0 HcmV?d00001 diff --git a/lib/junit.jar b/lib/junit.jar index 674d71e89ea154dbe2e3cd032821c22b39e8fd68..3a7fc266c3e32283a2b21fe12166ebdcc33a1da1 100644 GIT binary patch literal 314932 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

&R7;REBZd0NaNVcN6Eoy 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

?@Ib4$R$ZbA6MIsF(ZEk4Ii=sfRBa)&Yo zdo*%+J~Z_4Ve2DlO3H=gri+l&z1J@juzqxm_xwRViQht_&1OavHJXt$3rIeBbnQ$= z6{7tuh8?B5NvT#b3&5vtz!ok*tj9nWQy>b2deChCqnt1&-?N3oU%RV;C=`rq2Ep0` z$9|7Z2fL1tZQlQu3vZLdQ?AdgU_}db4R#CPuX)T1T=XAo-N7Mkcd68Vys&*6L@pI= z*@hY++4Sa(UH8u_x#*i0Cow&F!B^KqU*D%Ax8KFrr)5h*&yr-ypzZW8wc&f$@rh)4 z!9Cdi7W@8o)klls+xdFV>Koblp>m8_G9?$uctSXx+snV@u@q;`tNH8|ydk31MnDW}cEG?&A>isZNL$3fLBa#iwuXx_Vb5QSoS zc1*L^MR%Gynit@tW2j=}4jgmYyDCao)m8jr4>(2v^k~|32Cr)lIXA>F%C;ahnSt9x z1GaRvG`-Xkk+z8kqSX!{MH%#>P=`Rk>2!-3qSK{mioBN_rFQ1|9+9Q( ztI6RR*Le7!y%9!zI8u}a2GcLz&vLLUhCEBh)8L}1t@g?e>Lwh`8TkOkt+zDmDG7A* z*!h7IDGs5jSEo9E!zC2GH5p8bM)Y>1M2ewL?T{E_PAf7|g|#3+Brny}2BWoW8nDnLxaQgd$|Krm|VgXR>c}%6|I(d4bwx(t9Qj4_-|)l8&$?59gZ#XM!LL zhnyFj&qCOTLMNq_(lCm*u0&d>b{gKLH`kcZc2nf6%6s|veBOKp!3+kTvA6sJ9(qoFmReBVj9$vK&>HQspEPRH07 zdd{(FsPScw7($NHWhHJ?2?{FDNO-#B))CNkUaa+srxL^|v_e&cuJ5kFSN%qhNjl_YH(V{ISF4U#Yfz+gz5TSG+I9hWsM(Bk5fN#dx(2?FM(Eb*tGz2Jb{J zY8Ai7a6iHpFThsiz+3L~3ZLFncL=vHhE$GTYFx`LF=7_pq4R|==h`&^J$9a%O>-T0 zEJRwIV6*?SINx8XX$7%D^XuO7XM(@`{q0LZA{tg8xpbt6l>@)TlQ@Q6i=2>y-#vHdPcQcoi<56xTBo~U;b0!Wj@=!MKa zlLa>@J_NedkI-7@$HRz57>PWh5_-h^q_|Xm*Vye(>E!a;uyM$G;NUgFLfU95^gD$j zIB(fSpgAh82AUT>o<~~Vfo6&*!dS!o0n#V~tTw_g%AOs9|5DQbRaH)@WnP*98K)CE z5D@qO->Uk1kegP&&_-Rs^POpAoV@ghEF=_K2H)?5q18)NQ`8o*WeP7wq?NR0xrVJo()6J30FGQ@z;1i0FcT|@LbAaW;7tOF6 z<@1v0&+u?m2l-MNUUz^)Ox!*eCau$85B-uFj_;F|_ZI7a<5aPOf;9Xr`T-;#JQq#? z{nFr{$GE7yW}?(UJ8Wb?0$W(4@tbK_4u>lAswk8*iz8=AmD|wFRhOwoWJH2WYd@UI zJlQ$ab7YH4Lf~V!o?IK$<)-q4{2}X99LY(QH*ZnmxhOHQo@`V3v84^WZkb|}O1=hmX|@5pp` zmSmO)wYh>Q$rzC*;hoVd0@!9U!^G~|t<@Ac)Ec1@+Y*yrQpyum%aV<{b6s=}xopuQ zaGO_xp=`<-EHYiYMo%C=*k$#S?#ksK#+xm(572mCPNDIMUu$UW$bWL2$s|~7?hyv% zn}46?@*Sz**3)gQ+gz?CZWDnrFS?i&ZlsIDF?kQ(*yqe=Im5@qG+5Op+HV{gP=%R7 zK;3h5XlJhsdFP+r>-&J`yF47EZ*(27gcn!YZo|1xeROt!Qsy8c0uvp;$4!j~dMzqh z1rL=`=9{snfqFgwjwm0JgX*f+?n8r`*)KzeH`3^HM$R3bA;ldIf_+v+w}s*#Wx!-Z zi^;B+Rn6l~S8Yiaig=$*cT!^_VG&c47lqzhj9j%`i`7WhUXHFTCbsJrI~4k%@tGje zEA}zzO@dszk4>N#e=DtnQBOz|CJM#g{%zzoKUk7)b0`WVmGlGpC%S|5fbG{SS+|U+ zuBdm)EzU!TkHKp~7e9eHk}oW%zWw37Q~B24!WbVCf0 z4yDXRiY;W&ppNd}kEC13t=9)TFKMYr$#8UaCCEr?w613bQs2&I?0({VUhYdZxKc!x zy`T}!OjB{K&7JVy0R9&NNj!wqD+ZUwrROl4L0w`gWZm8bH&!&>y<;Mzc`VJP(=RQ_ zHYz!z>OBzdv-C;z3fCdV(PYmJg3{w|8U7@DT3sSC)i|QL5>=uOcQ zO*X7*V&4*k(Zdq6d+!6I)Xw>ALSK6FKCK$R1%GazQ$=a$YxP1s-@; zr4I;ee1N_`e!GsKDvlId6JHL*8#i+5LJ5&z1G(d$Ec{L1LeLogLN5TZJKA8HPYYU4sQ7@mm9`*) zR%d53TNs88hSO%O;0c@!eR@*@Ie_eb-}Vu40jqBklW3%2=k-|PiS@i-2dO)W)jJIZ zLhL;-``J^A?=l^>dBk}YK<35d-Jnm>KU>p7U6l#*UkP8^?C0v1^Zl_vQQfjTqZYld zkx}0eSPyfE96Q+0z9RxL*sz_oI^ckG#d>C9BDJDHyPY=3dssU8=T%)XNQ}bCPnhB> z_Ua{!gjdWW2leCtv#gGI_?D=9V~$d7mNGQL6k8UZHIq>M{u56+TxQfG*l878e@J^X zeJe}YT@h?dstcCA@8@iBdEUTmtB)iUgoK@0uFeWW^mId!3=9zB4w=vu339QM( z?8uRyo`Hx9&t12v#~rC*qh!x8r`%K*QDaEm#ug09mQ>K~(qfQ` z^sIPC`B6T`d{lBKmcGs*TPflvK$GxNRbJznD|2D`h#({B)QDegzA-ydxH@FS2h+v# zdQs6fWsqtDnovsZYI;S4*CDpI%BpH`%VfoLM1K)BhTLm}(B&^nRL;>;txQX-usC&v zsxHMfjCE5V8tv|p&AN|NR(MfTZE%!x9LYcaB?sxMwN~=`5!PTJG!wi*n+>>d*^FMHs{u6ipyZ!&WMF~;h{)=() z6&hAX2+ap=96b_faR4Ctfku-PgUiDJMvoz~N&JotlKYjv`6k)q^YI!o$5}pcTNyKT z&j>&#t8n#b2Hbt{1;@r$iw`UX9!^|@tXjW@^}JEK*nXZ)y%lmqD0IX%k?u&>s6y@uZU_`!T$2F z_dp*OL7gEDK{$fYy?CaZa~arIY|zJy3XUFV-l14Spq1 zdclTI07=)ezQE)fYmmKZqXX+o;jJ53J2U%l-lC zD$m;JG#>l0g?T>_S_K5%{G3XbZK~|9D>ymTd6j%Gu8N zLTPNv8Lmy$?NT`dvB0XomP@q3Z0yl1D;zhCLvOZHmDM)Q2WNn00|FbpzPtbh3QqTQ zdG_13w*~vvHB~sf8B)JBoPGTeWR+EBcIf}%dc~2vWT#}`G>`iWH zn?|gG=peNc_Hw)t*}R?8-fRO6Y<}<=H=0oYA)Z6^bivhPRa;hvZsx|()OLxYMwx+_ zn|1dc=x-i06&I-tTcmCL2Nm z`heaztiHHHeR%>uKp+@3%Ep~jdmXO1lk4DibFFu8(KsSh@Ob2_9$m?W3iKgwK*=Qc zD73I6-s+HC^^o9nk#yrF$R8w;KLo9b8^6GkB2H!1*1_44tybA%bBeBTwG1hSRJ(5E zTo!eTSdmf6srFo1c2NJMeHZ-}?jYlcTSzheBejcSGsXbPxOX0xLA#`IwA-WN0XP&3 zD<1md9D-5x89XB8FJBJ~D!JY;or=d{!n{+z|Ei+DCanBJS1@|OO1cbyTl^17{(rr% z01LB!#VwfrvyxQ*_5l=*52?qb2iZp>wL+$cf~Fk8Q5XHD1UCGQPh*lfh1SNcVl5`0 ze~2YjWDeg_zHKr(1sR=`cCV04{!W&p9GEV-UpI6M(4|8;`sfh%p+blesi?R2r7s{EVc! z=Dak0T8c$JPoBe6c2%Kpw9jOrsXJ)yNTt|o9O6C=NQ<%wYPbolI6dmUwGthUHJhdu zOReQ9O=zQs9^10h7|5BGCfHnvxtmPKk#?=H!c(G?KA{*$0VWD^aS8P;-Duhb(IwOj z&0&x!O{(=mhf`YyqkZckdNP$cUFnXCgmrul)j8H^v+j&j zM%duQOkkAK=_Z@*bS-&XA zPhP9ctd2?G#Kn7?f;N;gNw)+xF=i2FKyFBw#N$m7`5ksaPv0GEjH}DVHv)%LG2U4c zj<5$(hFNXt|3lh426x_WYr?TQwrxAZI<=>! z>h~$1QvX|PUF$*;nA^!KIdB&-mNi4BOJEwInOKMlyPV(#ZI$6@eHY=W^9h^-JI#oV z>nm8K(6JEn1*j+uJ19*|XM;-U0?MpUw859)Bk=8Wgp&sWD){~bikwFuau;|-J4Lq> za~^ndh-pI0V+@=KuaN{2yV zMhoHZvO(Ng#AV>|}WFn<)vVL=&j+tmHd&C4S!09nn>uL)lk@I{P$GEL#(oTlcj zc8nWHXA%|PwMOBR?F7C9ehSN06m^#CP?1@ANf2=?k9%!!_9!L-|5Kf>!hK!QN4;cK zDUSKi^wBt3eP>67)X*NLQ|-&7mB_DDG-c5K{NVje|lpAHcq z2i0ktQvQ6o2QN#Oh~TRrm*n5D=`)8gkzR_#6097SZ*KZ}MvvWW?grkD505@)qvvApCS4U62>_JYhf&Ifp*IEt#-U zUn6=?i7x~29(1gjsRYXaykucAIzN*%A3d`{A&uR^1j-KWElN1^gqm@phQxZ}Yik~K zspAQQq!CWDiB$sRFmkm-Z(@3{@;c)}n~f#~*Bn){coK4zF)fr#Xm3YmwF#r3GO}5y zhGDGp=w%sx_sV>0$dC1dZ$N~NE}T`xP{m+&1*U6YqAo5eH8G3Og!F_>#Mf@=LJxxa ztdqo|Gr0kTTg?EyGDr#-0a9R3ZMCG#z!l-VzHw%GR#`D*FYNd)HKd&$I<~ zGwvz0Jpk)B^{Nj48gR`PU38^zYW4|S}MzuN4Y94a8s+#agO-lTh}T?+Q^yN~7jIQ=Iys{j2c{o@EF%5h74=cHyvh8pM1 zJS(Y&5F$3%&h!eWBS}LLAGTz$ma--jSS_F9w7d7bv;6S(;T6xgqmsf`J)iVG(P%3^;f5xkn($yC-8TRSlp>8ryJCxM8_6vb+Yr5 znH}}z*EySqBvX*OTe_H!cxGRkwe=X8hL_>YZE+u*7j57|7M7gOt?lF*OX%O(I1l18 zq*RnPYL);!e@dx+XIqMnAxPbGijAep714YL-9x}Q1wtrn4L~dsClw;5bMpw%$n@#i z*^O0ALEzBKqP_%&3ctRg79dm-;JxMK!xn_D`us!eKe%4NiLSqkj!ko)sZ%iG!xy>< zg_DtZ(j`lv=(kY4<feerfn_i>T%|jmmX5sxW&X#`_>&^!5tzLg= z@1Xx*hK&Cd31_NU{$;x5Wd)(OOiKp})$~wUSSkf{;U`}UlZTuuFEAY^zgBipw@&&a zUF+~N2<^`c+dB$}K1Dv$CxG!gjMwznHhAV~YkFV+JaPT_{^qyw-5b|YhWq5o!IBE^ z2heZq18Ijnfu9})dEiWTE&0Edg*bVXXQF?i+_g}tWS6LRb0;eDD#iBYg>fYzdlYTk zgISK%#20C7HndJ*Y>u_&l~k)>k1f4SlAzy{i4;DXVw zhZ(uqWdOmiVd%5Fk3$CaT17qYJIsZeUE>n0SlxB84bQPwOF9{KP|mQlV%3XVHaQl0wC6 zt}ZAX%e}6w0Ntb+dM_HLux+L|iC!V`5XmSJO!SRlPcmj#@6ul`%0L2rl#(#!+fZ5N zHfzG@!R5ch@!n?UXY^6a&vwdYo>@rSV4ezrS z%d6%W;k#~bZ(Ow(Fa=SKcobfkwL}UU<^-lB{$?qpPaXTu=nvgngnt0ktExm1!qnrD z&uI1SxM0p$HmlSOnsx zz#tt#Q6CbEE4ZQDgk8B54?iBl-0`mVHx9l=#w;+Y=#dah8UWt-M27J=^MaEQ>sgY@ zow4H2S{Gb}si9+I`IQ4)ZSp|}rdB~4)JI?se$o}K(eGqK&^%IS;lmgR2c*VZWE-W7 zW>TD;#}4q4{p+E+ljGxGjJ*EB@^(B*u!p{%nU!xO;^%)*vHc&gynnninF?Cw^S_X} z!?C-Fc+{S~|ALIxw@ z_@nobApWQQW$O_x=^roeFUa3maQe(PY`ww}08fM#!Yz0^zTLuG2`@WYw$`HYiBUm} zbSDd@;zQCHG&T3icYM6bLVSV0?pkL@FQBL$+5~)StYO7|8|E-yB*r7G0RJ4tFolz( zyvuDEy)vhF5D8<+f{B=jvmN1w%*2gXLYkF64CN%$M?o2J-$R#U^p-=WocnAcn|}Sa zDV5n)Fs4r;V;m`*jPo>3oOC;ian5HbtXj&fmn%6aNYgC}{1ARw8>T|b<%iCP^Gi|Qc9=ZOQQtg^{V5Fit@mF&{oM+Fx?xMvNo^Fp-U1Nfyw zKfF&$+ZQYsTN8nzjaC~*)!0pI&&BrXyS;~`toF>PWU8!mA-?m95$>!)g~hOF14D@H zVdw99*4Ri&#AbWO)tlH%HNk134{<3lXs8C|<2|)lJ_K>( zN_jrsSn-tpf#lq ztpOZe>|p2lZE4p{l4NkRYiZY3&Iq@4g3uQct7^`*ya6YN?hbSyi|!j}>|1gmgE)sUf-;TXQ>AEC7!W5aFxMxz7@oBjz*TP`G08`nlFU)^ zROd8pVN0G$50Z{$FoFk)cx0f}BSI1#I?QP+$fP8n5$aZ2YOr3I-9Ix%rG`AFm<}C4 zVr)L#&uV}cCt+7o%XXL!H#vpF;pkbLm!5};3LRuE_4Pl8H^~IEPso8 zKzr0E#j{kzD!t2Lj|x~0ksTQVqB28&#?^nGkP>AsVK2sujoIoK{(g}tS{L3}EFG$u z`$$!!)Wy76Aez@opDZ5!4!*xZD({mKW((Qqm@{q2F+Hv&0Hp!tzlcEA;oun06Bk?x zt=LHF>;uoEI5N?eSyc9`Y3cYyMPkHGQXx+nP_h#TC8U)7Xy9b{Lni#7_RzdQz67e5 z53+u=-)PL*bH#Rz0smC(0Cg}gnVzuR+Spa>4_DxjY#(k-j(5pvvo zJ6Oc?)d5Fw8tLxKPeZ8a$Un3iw&h657Qud9hZIaQ851AWLIT}MJnPnm=P9+53EEoO z=8wgp1DK0?nL$!5vVF>GdUag>bS5sSQ>D*&L3BG~)al7#`CDO%9zuO8H(YBc39hr4 zT|w35&p|=fyBhCZ2f&w)o=$7;Vt@40M|u`8m=M@3YQNSj-nvRc)`*EPyZo=ro^iEv z8is91F9e$~VjJ#@Q-ZGcKy}}J!|=YjG}`mm`YM$&DWet=5IZv03MjmLOZ0TSSd^5{ zt@w>-DrV21UZuM#m|l@vCf`ceA?rzG;BSPB!ZTfj`5o7L`dVb>g>2;m!+YjhSP zEDF7kBDmS9f5w@JIotb(q3+=_i{DN# z+4!y&k*(6I_mSz!cKv>YYnVhy)0RY8>FLrYR;d=)X-qvR8km8OsFHYNl+aV4WG{Rq zX-Bu3Cyl$LoFN{r<>?yit`n8?nVp+098(Rj7ZfOn#Ku;C(2THF z5h{earABBo=SB|@^8$>Xh|2D%u5k0dB^oHa*be9rt`-dKk?dnNSr(Jw=rMRMA3Jd> z+wsZ1)9t;F%H0GP?2)w*Ikmo+0*AW^)VYLJFm$d&{Gkft$p&T85O|?rz?_})9K;<0 zO@{@EyOdz~o%Jp4owBKlPp4s`ZP1{CG5=xL;F%<8@q*eyuwn{V^uy@0qlPD3B}0S6 znX6fbysiMcriOP{eivf`DIV2t*BQ^&v|Dm;30=61{>Y!1hKLu&R8(c=JB#rE0Cg(n zj*Mh@u{=7MZE}(tHG}H$q);v<+nAHd&5v3t@J~%!-JiRHXONFU4-~Y5tvpEcR-2ac z#z4>0 zP|C%-%n`JW&aW@)o_ybkr-oaijhlgzf#L%2wq^{PTm``rh$+Vuv|7v{(4^~(g*jk@ zlzNIA>;!OO87%kbfIe!CG0GHXZYaPG8peZ_*$$&`+;*HJU`45ASU-)4V(x}SatSnX zCcn>BR2>ooLJx;H25pDBt<`U`a)6}fnnN>6;s*Z;*Y}d&5m!qq#N72wJ*W`(Ddtdq zG|jjD+D%i~$9NZZR$EvWA{6d~4{nxYed?E%`0?#FE;TS4D`bmQygw%!+~qn~%N?bU zyI=6!duVs23g9|nQK>Ih@fGk6aUX^WU2=Pw&)R9~#%9e+-nh;7(7 zeMTGL1_BiZP!x_J&_a~7+$1d|MH5rcfYF8&F9?}DMaUhVpzD5t?U42MefV#ed^0jO zG71;O@YhwWS{G3S?DIGLit9lBJ-Hv2{jGhFz_2A>UUQNx>`@Ib+VwB{>f?e{(W|jDD$)2-eE%tT_ z+0F)pu_2p9K>O>GO zI(}|8X0T@%D}bYG1-ryE;cOM$mG<(F_Hx%GmV3;s3w?2ls@zOwjkvr|dSy#fq#r{! zWg=R=ck3L8*?5#CZEkpdZjXV;SLG?`{NCJ)EsbUHt3uf< zn%@n;|B&eLcLVVE1m+*rWnk=>bnh?ZpedVjXTE{4UQtc>(7{2L!G6(DQcAEgEM)=i zB!WKZRA~h5i9on*0Sp-_5UI45loQ^smrwhmi=m@6&hNFV0yYG1!dcdh!L!F8^1qd< zbm!dGzZ9?HZ`O~L)y?EPk^koaCU9srj*Pz$hQ~b~Ktzm0ujYZxo5U4a&ZAact;*G>eqWztgFr0)00=1cctVm%Z%sIyQf|KE749~t5TXc#<6_AD>u^%PCL8yr6>i5fwpa4U8%2Xb!0Fs%VR>u;u& zrmlY(nEka}SZ}9UeBUr7#CJcS{2%lJ-{VU|JFD+xTRsa5ssBm{_+O2i9kG<5gNe1l z-yNN@u7%_OQsyd~f8&?vUea+!0+_T1i}!k38q_<4fME+s+JfXEFvx&%-D`C} zh-|IhhXnHj=*AKQd86Z(&g28s%0!($s9N!6oz?LmJ^JAVel!-!00bF8TQnW zb?~dX-kU5X6n5L;@K>|>q!!(OsLRgUV6)NBOa0#NCohKODl$=!yf2Bk`Q87f1O{;A%m3Nm4*xx=sZEX_D4?XF@S1KF=J!tWg&R!OfDx^4GQ- z%c3ZzNlXoY$RR+nhf20lqY0yIAt~J9Mhz9E%44cVAxyZD*<*FwAZ3pq!0Cg3^J8Qd)0cU2z&= zlA6Mbs4=Fr*1&8^i7P532k-HQ>|KLaBu18ANXd-AD9UD$Yq*Wf;}y{??=@52lxz4l z|I&0642YqBqxwFsL4nuGX}vPPpH-zW z4LtIdBghAe2{&HC)LD3Q@vslaDE+!PyA9c}FShEKKgwUd$X(M_Yc}PadZ9OqE~uRw zNRGYP>`Y$&1%mwR(o$81Cjf^50C*t!2AclgF0FsOIuq)UE{Y4^Ap?v|bdtF6bvuGd z2!sK|=(6*O5Qw6Fs`!fVat%(B+P&TTQW=u)6{u&lO|+I;c}u`ciF`h;pdlD8 z0yvq`_F`xcX)j*7vuxJu2w&rammh&8-S&*n9b8^=s9q!8$^H;~RDmvlbffLnm@X6{ z;;veu#RmK4vmRPT-b5ka-Qn%CrD+#Zzw=EU^A^+f2mUFDFpf4wH{AYHFz9pa`)3P0 ziHmA~r`a|cn3uXwHYfugFWYrE&^u#@-8*H7&K?_>7uBCXNLsk8*KhbqyKsJALcre4 z*JQxn%07Or>rIvYv#JHfL#J}&TBamygKH`xh_SR(rX-6(dYwsre`ru!j|l@$sCGjq z+oU?3nAMVx6BD@|wQiiKl$#e%#mp#vAOro#&!`dA6<&ZioKi2|))?gryrKI3)ytaC zJg90}?Ytt02B>x|W0%`R2`Q&8bLd(b#I>+y12i<+D+L?I>f&Qnwe0dyWCSa-+DfD# zSVb`PYZH?~F4X4MHgLk#LqQ3RG@30|O-WeBS#CB3(_^OP9YsfQ`ONb&orqV`Yf#74 zYbokTYkk9YRD4olmwkmg?%V>e^bnS3Y(^ zn#Rk|D9m4mI&4#nW3oo5gUkiq^cxvdCLak=jmTrx9Ry&D4G!!{1Y0%NsIz-c#o}8x zkfKbEnas1uwKEwRsylXw2!(~lLEkkCR;G;KIg5%ABm~jvI`&sI8DwVdaY(P?ZqCw3 z2T@6Dth#-YR%vdZvzq+QByQQ?Eu$`v%;KdnkYePUs9R^yAjzb%6dzSw)~cS)E=*H> zrkSy7c$|bW!%nr5Bqm&wC${E+&i1&=C?o$$n!_T@^Y5K(HhLl&TLG~v@=p&X5z<)F zkkK%cs1)Fv_Z*d^-OQMWKEw+Q{b|IGVWJo1anP~y;B6l20KzW>c^1NAXVY-9{;dwJ zFAtg!tG6q}9$-m4Y46ulCQB4`cnpKutQ{|%vy(K}2b_!NDJ5Rr1DG!4@0i(KT+OAg zHxqDz9doLyPqjox;F1liKavR4TS>G#y`eUD03wTtARY!*a9ac#%34_AJVQ>jzmpF$ z!?eSk9Z|t{f~jN1MG{~~)^Y(EpuxToqcOlHq0OHnhBG|X#9WF^+uF^r>`R`d!C)%< zytD~KzO@N&Di%zF6Z!Rl1u}$XMS^|^+t+8KO=r##O}=N{pdc0mUYG)5cz5|zg+5Qe z#O_<1MqSi&YD62HxyC11s7Z{3VlOL+|93G0II&uNdvIt0co+i5MfrKWC zluSxEVR_7St%9VoV-5CcwTt&$9Qy4F5V3&ZmJs^2%>rDV&OY4OvEFG!Zdk^ZICVWC ztxY?zWPWrkvL9GmI#`lZ3YBQOi+i7HMy<`Xz&>OC zpu4_JX|JUu)`e+ZLZ~1mJ3x9Vj91AL;h(bXdnUO~K$%#gCy6da~Y9UPA&?1ha8;U-EE(%CzPRkQ~8Fo8#j zf*;%bJr4O|Xnc*mLhWiF0w;E3W=qKIYZPKp8YwO7hGOEW>ZY9VIebwX!4IPd>X8() zqB40^8}zJRVwPKny-HJd>@9=A;p(`u9A=eCJ=&_Y#Qc4=n6UW>IZ%E50^`I+meRn{ zT#K{d*|H3hepU7B`vwUkvB8G<9d55-cxTvmO{8y~u~a}{HO5^iiHZSd?vZTpQn89dSN^ol8sZ5=!E zFTm@uelQd1$R2+ubg1;6m^cU9?Ys!^PE~Gh1`a=6nY#wG5mma; zr}pAj4F$4H%Lka&V$CF8ss_per{B8Cb}oAVm>KlI9^Q^>v$(SSt8#LuNL#@hI5=S|Tj4)=av|$=orHo zeuQIr|DBQ1_9udlP{-13WQ`+7>QFB~I7Sv9EJrPZm-x9La{90g!KVL2 zh^d#e%loCxOX4Q}AH8q?95h4rD?0|uyJ!>+jhkTZ461sxA9L|csXVlirc&DpUXm9A zrWb$#Q-q1Y>_)sr2Rq|h;5y4^t`ZE+zy~rUy_kAjftZk&u9zzZ4(-E-uEVJA|MkJ$ zU>gfwL+7=03*0cLBI8-YBhN9(&3}tGIX>+yI(ZM^nas)sx&X(KjoF`P@dNCnMo7!r zQxgX1vlD3dlYsPNS(P9o&r`~PAn#3n*>nGb!Oa1KlNCrR6%5iZ3!*j=gIldnAfHYH zRaYWyK$^|@DSGeL8o_1n&4Dbvui(?;hwl=o7qQIBp{ghfjE!xpA-u!54s;Q?4I^WtO7R6FR;ro-%gy1QVHH+pxnH2yBeTW?Lz98%?asm3G)mEVCLahNO`KY?V3UrENu?>Rw08>(ceE z3^B2JIGb++C5|R@KXq*uUcP zmcIW5+c^GC-mijR!&h!b@%P7R55iKz=&-K%IIRpJTrr^@U~uf)ZcS{m)mWjoq&l_1oZeE5}i-lJ=+}W zTul54y2FX8I>5Wyx&-tJbYGS(llx$Iof-vB@m99|06^usbigVoXNjeEN&n33mW)q6 z+;qO4$n3w>?Rp`PKhwfAW_eHY(Eb#$(`(XK6#woi~%AfSA+0b?*>I|u$u<)x_A zS@&2g^g{MB>Jjg(XJ?suS)!#dny_{Fom`g#Vs`tS-D(dvnD-YGU(hMr_y0&D#! zP=g{In2bu?sXY{RRNtGUvO()jJS9}W9k$NQBg8t_oo!Bj^aq)N!Oa%yWJrth=muGUzE9$O+hoJEy;`|K4W!^io>12Df>y?um!JDmkyF0rF ziU{nM{``*Zi8-wN*lws(&pUo4zE7IIP zC^}k{3OG8>?t<%cLDm;V1{g)eZAzhr>VX7x1HAy+JKBFEd4CZ-Rw7P8ZoW~x(r;?+ zemEu( zq9e8M)sCBW3C)RusaWBlS+^;JsG&8`8Dz;eW)F8KlbEODw&2$Yk06?3(j5hB*{yQC z_)s(v5Nhd-({D!;?+PbSPUyl=fbD%mbxBF{mMniP1XZ{!pfR(Rvzug7>1O$6-?9U`_=Bxxhg@I zkTzAiI#znyZ|SVWl&_jXZC$ZWH+huI#nNUDY5^k*2sM;Ifd!e(7Nuf*S07Cv) zLTrg**c{wipX;J?Y5@4L2PwH76gUE6r8nB^0K}BSLa#ZOf{Fh8)TF4FcXC^Ui>|kc zKcrGW(i|P;cK4}dob50Hz-^Fr6hhU+dL zZ^m2cVWYJDFIHsM;4DsreIEJ^3hZ*q?=e}>_0G1|2q%4F8G2Gfv4f@=d=bw=83*Eb zGZdRkh$!|3z>8)MBFumgaZaJ z^vK2oYW60C7(d&q_b019QFEp%h(&4qxjE){Hs%YP*o_{A`@p^CZS-=J0E;OyP5)?t|tHazN!ZJ!0FA{6d z(IN6`|gr_JbznYF7R_?yn)_WB-ZH=o4 z4M=n6R&KIiDjX*XpZYbMnxj9$e63LbF~TBKEvb!)-Z5aS)H$GlLNWA%r7BX;@x_M{ zE_Eiw0#_264uWy1228TI<^n?1%MsRrdAxyT)v$p35N+UCJc3jyEC4{q(Mqcdg!;6r}jodycP!*QQgW(PG4zBwVM;lhNb}q6X=X_N_&F1x*~TkT79Mnr zo$6*bEGa9gVq_Yug#kMIH00QsRp$8ho>o>7Ym~(wZY@dzbP&`xnJ>B<_Os*MuDrbo zQp0p8qcifSV0f(Z)LxwBRn^avk(u9CVp_r?-F>ABcw%aqetGDln+6i5!Q3-kqsqz3 zO3?*wq&4R4RI#&?=EHLNRoHE9U~6J~59w`rk?^Op(_QBkf;5F?gOi*l0Mpmd_ZkYt z8ar!Jp~ZmT5D;S1wku@%4B-x`_Ubh44%Tx~K>7`hwl@5YCFE9*b7|ud&?1yacw-+I#=Q70( z{AJAbkC;kbZLd%?p?C4#YJ_}-u5BBOCHedle*MKixic|4Z7i{}2Q8#K&F3Rm^n}0X z{BkoVOdSyD#GbjWbbi&7fSitG0UjLA=XbgSTKigARhMX< z%!q#vctFX+y&1g_wUc#=KW6#6?UsBf^btK+6k63R@!W8-I97~t@+lWq3ofNVW7TcE zcT%cVQL8<%vpH6`xx2XnO$z3w8+y2;nE7C)KA|b9@EbDURzzCgdI|iTTyndOYB!r& zwfHzI13*T@Q`^b3e`4q`DFCx%J@8=2Iy)g`v^WT3sl$XTVmWUT8$lA&(>WS7vJjJb z*``JaE4(I}04f+98z`pP98L zZ{PGLDIC|TD#XOc^2?CP~`q=?JiTzu!(&|ufTsxd)Nihdkw5Huit6_`z z%AKlnE}-BDzjFp6|AFP+iO%!&q@Iflk^s9kq{C)U=($%4ZO6N}*OR7FB38y6#;B4fuM`j#<%1v*L$D+RG7Q0faN||cJB5Muu4;JS!mXR~s z%EOGY=N`x{T`oQdkZppa{eBW57*90asv9{DUgr0Ke$hQ$S>J_2EX-H4u=`QEnU zajoj&-a~)LBud#ySvPfR`o4HdtdDj-HfhC}g+!kWku_8}Xhz^MFWjFizk&1%R8>qY z8uz%$3qhgn)N_2xx|mQBqL(7sj9@B=s40Han;hhJ^7d;m@B`$NT9FBCApTpaJYrPS zj9x@CW`v-pc8g-!Q{c{*dcm^9^9BW64z5@;r@NJijbpNMM1Ex>rr0`?CSK;|j4-#D zQ{QqDbuE^6>e1IS^>>udQ~MIjvTGF>rUj@!dyX$4l&>!hqNJ)a!1oCvZvxA~AN!M7VyDGdn}XifgBQfQ zd1Ru&T9q&|zfG-E%uFy6S72&G;y3wGl?Dk@ZC1wh8XjjDRs*rfaj1qLB$v%_cwS2K z>b!oe{Lq8kW$HDOV7D;U_Lshao59;y%=pD491_tQs7ezpL@MhDMlx4|8zPw(WI#1Y zWT^VnceP#>+ZD0=_ypQ-t|XtRHm$1~?@xe=;V@ls7$7J`wjZIKD&>d=QlJ47DDhr5 zDqD^QHu!DmDPV*Pb`1&m22=Soo)#OOcuu1SU5b^;^FHIYCzVvObg$G3tqV z+xqTPs_}rWnxSuYnRE9L*Bcpp zr{BXK*qwQZfhSaNo38dsx^! z{sfTQCBX$zfTEzG*F2^9H_zgjVrx`o^=ge?SZ(|GX^;J)=B{UBX|Qu{pmS{G9{tkk zVT*%E+G+DL_Xx=)J-*p!w|j^T{&9wSncWx5_^ALXD+}4i#Wi|yO{>BQyqtMl*5j~} zDG~I}Aj#@vz#}-kb)^S7$a4v(V+j~N12|=<*`heG?0%$BX_BJpNWwZFw7u}Pw*u8Q zY}TF^!J}It?j%-4km$_Fd_NKKv%O+7o`>?$xpMK^rJ2RzBKNF0%(L?hB2j&ONe-#i z19l-66LrbJ&A|Rk3=d^CE(q~RJSY+K7yMSPVJI=MrS;B<-o4<+} zKQPbN%5*ppGX6$=ukc)!sGXF!M@9brZ{+N2QeWhO?_obT?6-3H|7LEcU}LCnYGkVa zH(BHFq5nVTX9LQXDo7&eo#_G8#NqOOq792pl*B$2&$G&Ys)D8q@Gl;3w37>vmmVZi2r%rb4y%pCu#US|nI);Ce9!VY^th}weAFZUm-(6*U1EUX)K}`OZ zXWc4&=J9)Tffs^@Qz{^W(5DQ8F3L~oAzB$P8!k%;$EWOL=8F1_`$O*Chpf(((iTeMXyUA#1lFxttI0=nxsrmCz#ERom7jF z+;W%hi5DMx6$RHugXhj_#z<9YMyuZ8C1w}Hp3Ul5(&8euLJI|`rc9RX!Q* zXSKOWjXYR(Qz-LPfRp~N3M1$xawx{JG}pCji7HW&x$?ob++>frSu*S~#GhLZ7Dize zqU+Fmp*R{9L25ynOZ8n6V9=(e0puZU)NOh~ddDcr5s)cpC=M*dtyA|wSE4U`Q{z-E zUdXHKr-^Bomz~HB?Ylyuo1tM)t@%>S8CAX1DPFpx*Y=>3i_Ff<+eK1SG9!wdX1fck z%39ED2lQ>lbowAzF5q7uGnS4QP`5)Zb5~QC`mL5Km&%0$&S*Oc*FT~(!%?X^(}H(S zMfvQePO}mO*|48nQT)Ufc2QMjDwhnL2cKl^r~-*9M6c< ziuVuu3n-{=-#5XhVhnP2sCgD_5R#FhFN*bN9mCexDU+D@YbyAD2eQ=Bn5;WSs?3Uo zW~srM;-CvI>k0PWkI21Zo$Wkl2Bc$AxKY`m;dt3<$@u) z4ebKH^a+B*;IV~f1E9L@Cf`e9A=!VJzrJ7STf&nOLY-={3pV^g(>S9gq?S|+&31;J*0^h z-E?+=82E3M4l!#J*u6Dcl@nBbOMTJ(su5NNYa&oVQ~$tw-GZHpn$$!ngA&o)Br&cc zzlX`Kgp)4|IuK*S4drwSzmYaDO4Cb6mRsB2+F{@T4mJ%5+}L1bgVbEFd8gk@UrC}@ z$X*Izt>Mat$6u<=@&s#WrhemAp+{n_i4KJsYKWOe7Id#UjAeL`#4iSTTXkO0vaE*l z1E>rkW5`&fgYXWc=Yv31*IPz0CK#FnESR>PMhYyaVD1Zz)h&;X1IyOS?JMh5lW?_E z%HN;xQtm}u-kX?vj6twTfV4){bd_#ci*UP@he5k=+M463sFUMT`Pn@}xp{ztLV;(v zfpz^yQd7iS6(_Q7vXj(h4V6-}dBO$XIi|VZ(uI~&B!hKM6RURf8LT_f#Kq|ge7hb> zdz7LUoEV$bDn?vpE@-sL81==de82u`uahBJnqb{Z&S*{iV(11|IJpFYubcAzW0Oje$r^ zE4P-wHC*u)g}$<2mWuY4vt3*PM-9^1b9#2Z`aW5aRg3Cq-wrI#A2d%!D7{?m(w zA*En*(%7cUcI+#a7BsOKt=|BvVaar1ris;gZ$Vy z{^k-TYRTYoO+nKtcfaFDKl_(Wn~7jQb|MV2^?mh*v)!b$meapuJ6i-9pKC-58I5;%)tjU?4)e`%i z-L7aDuIn3kK!L(3CE?$5L!`J2T-i%{L6zQ1m*~*yh^?du-Zp%XF>Xz8WzdtpRNKp0zJBRz9Hcs?>JqWPYUHQh z^mCZq`>yIhj<1T8%e2Q3=Buu}13k8~cZr%e0&r8$o<{$u2`~&RKs{A7q{D+(&udYB z37XASa2_qr@h0J*UMim?<_&x^4RWsCwv4!vcCmEApmOjkEU}VxY87TBzM@i1zDiZ3)>~RiBa4C$JslEY1(XA!f6|oW~FVb z(zb2euH=)pZQHg{Y1_7|Qj_mN_c`4&^G$#M?kj%Yv3JCdwf0`izb@*wzK@t1Gt{5_ zB#m|$f9))If2@f3ux;X2FZB%$_?*V~KD63NK zogZ2B(1elf#20F+A-(<#J~N4nie)+qPFT=-b^pn4ggLtG-j=-2S26I3N6CeZt3@mmTD>YX)kJru(*XndCw}UZh`mJ@$ z_~C@pcC+>VxYVUX$elG?BX!6}dGmEq&84FJeq@{f6JkdP7yPy?sE80h7AY2>6(yclL8;LbwHj19RHuw_ZVuzZM2f4i_cn^n>gS{sy z7c4HNc4EfJK}n?%-d3|bk6$<4Og{#b>lkjc9({95z7g9l$3|&Ar`JKr{@ktcPNzk|Sg1k)41@sQn_^2kes5tUuvkfjq)cP`JMVl07d`E8 zQSx>&$L+IX>5=VV>+}cm&3(fp9n&IN4FTi-RS*Vc^@(ny)opA$L2xU>wlmE-^8w;N zD2z9EBscZgVsQ}=Bbw&N4P6R*{e@En=)>(#mDr-SAbm$QL?^e&Xh;``zha7;mbtGe zL~f4@+eYRQ{h1$)lm@#z>i{?Q3Fo_gpSIB*x9L zufNN%bWqwdA9Nr#&>jz##hfHoyrw#1k)t6Zf5R)nsxe95bZ2F7kB@@O;ZV3sxXpuY zW0r`g3^yo8?*SUaNXJ5TG!I|UagOx9qyNw2?=PY)O4j)@@atYU{36@b{~wOO|II`- z$v+KJ#Y}8X91WaJ{?>f`UtChF6xSs|8IgFEyk?so6|0u0q4?Z^F>Vzo#k+FRkgI%R zSR3P5<78A{wfLaJy-1_nf4W*O=(j)BlF#|)5 zxu@3m6Z3wQXu7+%1P<`~J3q`iv6$-$>g&cZ^9f~e;tIrtKXNe?!*GWoL6AeDl43Ui z_(xP6e#Z8Sx9AbKP?*)QA|Q>=vUkUAzLY@>z}#*6Ex`hvUpSe^Kki>V=KjX8;_TK- zer>$h*T%E|zij+}7+?Ln=8%VKC+-;WF|JNzrEgBA&thG zX@?4(Zz4G=qOTu;N#?f#NJPLO@8ncxnvb2U>o&jcHc;k%YcvxV9fA%nv~mcQqAQ8~ z)uS26l!~_;h>V_yb3)aTaj|1Hmc^?B;iEKm(uiKJ5e5}{>x~hr=R{-}k0!bCLO3yX zlNkmYj!2msd6ae>Df3voFf|kC64cmK;gmUw85!Xb)^jtVq5+AGsrk%v%H0poG?le` z70a}C-!24-I;vD+5Fy9IbK zEK+QmfL>P&)>qJS0bDy!7fg!%_(lk3U$~EK(+WRD=M(vV=H*{c0NPlw2FI_h3I0+o z75P7JkI`4Unf=|F>?`4{U5rhH{$qvYA1h8jZ2vLVUZnix7omXkA*)2Y&JO#Z8{9L%P{AHO zDOZgA($9q5e{WUf15n;PwFi^|YJYd^v<_`Pn@$iH&e*RNH`%odZhdDsB!Gz_dOj<( z0mr+#T=Rjrtg>-xu}#Y!Idy2+ZPnSQAXE*^d1$4MZoAA#o@Mjda?$SN{XSlk^S$Cb zx)t1+2+e?Vrybz;?a`kuJ^1P&!A9E5}~t3o!NZA@xz?B_Pks0W>Pt8RGGE$|J@7GNBKtdX!3J2{=K zL?fbI#-RX?WgUrRG96YQw1NFSe)Q5QpZj1|OiUH!5{1|(+$@y?lTb%qHjWZ8wrC&i z?3h7hu6Ur&yxKzsq<0 zOHfPL{+FQsJLZ=azix@chy?h#n$fz|`fJr@eqKaq6qrg93VwwHOo*_y5Q7q+ONFyb zF{)XxnEa<|twI3Q$B$3>MEtzCOh{r>SDd*ZO|HlEczH1<2WV?wCX$k;#(-25oZix1 zV}KfvCX{ftr+oBkIyl3@BDz-n&4bPfaN5i??t)o8Km&B&4jtO{d!D8tDXzLUtZ zh|Op`FYu2t*L_z5zMn2&C9}(L6@6Ve z0$+Ky=MkzPu+$F@Uz#DTP$1i7%$~tF_~w+j3rwH@-}We_%x9;Q`zI>X(oZ@hzXf=P zCSe%J?w67O6h_T1U%l{>Bhv1D4#YW@SwtR3e5xJ zO-%gMl}JUL;w`?bnW-7y>t-8g563IKKI#Nx@l7Y72ot@tbk_vF2Gi74R#69c+#g5;fBlIt9kx3*ODkXs*Y z35%TamFD?!Z}Uz2ZvjkJnnrsn=FUnI#kXfNK$`@d(0%cr*_%7?3e>jCx#j)`j}ry2 zg84I~yzZJmqOJXkvs;BTKb1FiK73VI7T5z$erZ*C9-qSV2xRTf^J=~ytpT}DS^=uO z^fCF~dj1v-&D4KIL;rt^hKRqSVVH7d`XA8{7Opz`w`d^3pZ!NP=*fRYgI=k(msj{1 zqGLHQ6JEF~NUjE16!4a3qz9K?YryL$YJD~YGT%=|^=Wz70L)cn#{GYx2mWePVK5dj z7XNBfQTu9B`SJgB-~G!)_m58xQ48y@3BkWdMVE$^v$7ichpcIQnzXH-G$9e9zMo%0 zS`e^w97-=Bwt4mj4iU8K(!@~$AZuED-y2lkq*>LZNv&d)E9YHkX<3#`f|R#HwXh`C zw76zjfo|2I{ZaYVUwFQCyw&E!%<=Pia z&ut%rs^^dg1gX=Cp?5e|!+GO!b-jOtg8=9Fb2OL?myYbr*A{=L4KmF$G$X|0B@|RF z^Q9Q}kV8GdZg*YQI|NclmS_Ckt<58dv*)R zeMEiEDAH!oUjd_&V{+bz4tE5)cvxd8rj7Hom+~ry>IYCs+9UY}&t)$&$do(@rmTzA zCdfSZQ`zgH02LMtBv+GhgMfosDS1Abl7o!??BL?!ABIX%Pmn4D);RS`t@Y02Cyu6% z#@_hGi{w#1zZDVYQxVR6h9&UgrgDiYa%_TDE;Lz72jC)Jl-WJS+GM1av&|-MEdwVX zF_taVm6Y(Hc;G7j;vpd)O_DMI=noxraVaoOnR?rN7(q+BsQRl@yu8q6#>Ez~2s@?c zAdBHmWcc!3JWHNIBcr+160*Q9losj&zf>oGXl3a{1|%t|w4{MwzNjnNBLcc@$~f#^ z^d0M&5Cok0G%=^l_c$wQpa+hrEkj~5~cCA%(ei>Ta6 z0$Z|}>5#)kDI9f(CVCId&s*%xllyd5Daa{-mG;|}Bf?cf%+EFbgE3sU5XK*k?Lw{9 zox(KDq;HJakAJrNk1J^z7tW)Vj_>NGzyx;`#SMjRnNw|av5I)#cYTW)QqoQYJ!cL`KQAj?XJuWXW_W(f z1Od&$OV!>Yy7;Bu@B91dxT-=pKd_rkgm0GPz?p{JUxcp_A zi7?yFv7LbqvWonpv}CAqy)^Y#=;7$6_Pm5NhfP|oLU1d zg-z+dui(OqltRe2EkxE*f49ztqVNq_ zPM_D`P_47UQ=yNZj$V0mr0Ol%hpwKtBWc_IBSe!^;&&lehQfiv&M{2(!2QAOrX`1W zSAgD53J9BALCBaM<%v*DfZjehq;J7ai~Fp93fddOH1!LwZgIVPcdW|HK*xHlB9e&o zkN6D!9dt({S$j$jKP_B$l|F)7a&Q8no`B_>_5l8UdXVn2lK24j8#VCb8}@IH#Q{D0 zwEpe5xjvR8Xi~u@^$>IPSsGg#TH$u}fCx^OYS6yiWbp-Bo%Tcmpx;}5tDF}1_1SaK z^Kans=I0TlkOy2t_Hoz|7RY~`EgC^K8_ft*YK}H=*qqGRj+ifa-bi^h>yxfos5;SP zbg6fe-L>&fphz)YJ+du)oiN$SeJs96{x*fpwg%BNt9O!q{J70Qw?G5);l2rH$m1@V z2Fu|}I5{g8Tr$o-4Rzv|SGK!`^ZMus1{PacBl9G3M2I#M+C+z_e(Bp9eXXJnvuVU3 z(yiUeS)U!`*HJ2x*i|vn#okOz%xN7Iv8y76FwYgci60~rZXqf%dk|Q@4psE+dK2TQ z^OO(p(?4y1F6^Ct1oT3hEBhs}bTe5=KSr3dr!bsNIFK)kYg*;a^2N&w_*DIbGej!d zr#Nw37d7}bQ z5c%RgPAVBcAI806MQjj5uT!;%_sdRfN;|el_u04-;iZh&xW%sX$=Sa4d%3PB-?vwB ztao{CeA7j2Uly*l$*Gj9~=cSKqi zyUu9)7rM@6%A8d*m^Ld7!W!9-R-IDt3C^AHvCHG;b;o+f*rA2j9AQfOI7J(z*BHRf z#~1)=#_7W9$)$}KgWx%&6|cy>@N+?ZVp;ftJlxguZRQRQ*sBxFd0Vp?U?hAJ8NP|1 zL8LcGoQbA4XxTF_O9r;bQFQogkz#ov6(&1CmYSsncO$pPNCG0)0W=|s=0M1Af{bk2 zqU9PtCOF1BHkid2C!R@6am9jr2{W(8i8$O1!5X+r=@Vc>?QY8OeNtFLmd(K>+;DzR?a15Z zIAScdB<2ArVfvkI$u=K-gf)Dn$T(g=&c~LUam<{U%nRH(=8h#p^nGa}PG$ zS1G@(QONF+Wps|NKbHxAZ5hpO8Jqr$P4;qrD^6k@7#F+~5EeD&GJ3>{?gsJY#^$_h zjr;D)r0XuQWluE?4 z8~}UZz#!iPy+FSUEiojMYaQL~6qtCK5<9OArz@8V_D;4Ph#c~gI11&Jj4YTdik2(8 zB2ORwVJF)9LTQKT(7=PGzs1q1Q}EDqQj#vs|B)rlQg~XR(W_%0j*jfW-isH+xkeF``ETF7O!}g8nHhcwTgQT|ti%WL@ z$dgllXj5)~#~qaQwA!H5BOom$es_yoQq=4TqsVyJv^gT3K6%XYM7q~JYX2mD_mxm| z+Ye+SezCqD(nS0G7u4*pGL>-NmisS>LH;jjM(}@HrvCf;|j2=HTM%O)iQVQP8B2rTc0sLtWQk#JwYNy`bK&W~lw!s16xRe1Xi3S-` z$T$Y5RF4<`GDGqgga!uFC2IHupT)ucU&TWI1#S4}JK_t#wlFqu{wI-_rK z)*=A_CPre>WK|ymn<>+@0524kO#BwW8XC2%?M*KPhBAP#^Y*u?-R{xP__y=*Vq7PJBV zmdyZ*>00b?WtaBOtu787@pr-?PJc8y=+u!z!mZ=DreHNN?IB2>YUq>x5S!NM823>g zN1i(#7@kx=a5Qk?TJsDlo@Dopomwj@UPf*wB2IP}SI;|7rmXC&f_H1KfjlQq3EjA& z`l3=rfJOnXAXZW7nChxNuARrT`RY?s(O_jE@CwO(iViWq&kXz2un)n$F4Az5c}VN-Tk&dYIGf3-Ayhoe4ds`MdeZv{@ z!5lKFuDfLDd|rnearmehjopmYQKlYI$IR-jObuVs&_<}`-PTW1@wjdnkJvDJe43C2lCyJhF0^8n)JE*J=@8RhGr<@9by+Wy3CY`4n;}+Dn zG4PXQ&urt+evh;mM#X8svWU#ZW$!8dQ)>d3D|}M2UF$-h=a!gvyW2!uNrZCIKu82l z&YC}{U9(8}ETTTmv?7_gxMqf7Hd9FMSJ*jVZ0O^dupkKA(Th)>$of_pC)r>~I=%S4 zLg@ax$q6a9u@yZ^t~lspP<44wfuM40C34Al0CV_-YOclV+~#`ZjjJI~L1MB>a&d?G zRO8nEt|`_p398z7X$RRME!yhlxu&Y^QMTqM@skyp#OgqRT7u`V>m=;XVH!d~ka~?e z9<-lqnCz$u>^ktacpO=_u30bquQUflJHoT_v) z$J?D0x)4X?6I6Q|g=lA=-S0bud`#p%fre=b+!z_H%i0nclE5>}0gZHWbsfi_L--!n zKo^Q$HSbbY$2ABI^6uKjMwayub|4mN{Cfn-q-*o!m$A?0O4`_;jymcDc<1kurEYfm z(?XqhkZ*{Y*cJ;je46BV$7P@Yq6_uc!5s>oBlJJxKK>g_O!AMF{}1kCOC9-|G<9uI zeC|atu&>3&OA$fCHKPmjwdNt1EdJ%I2Wpse9eo^SuL{xW$lJ`c`; zwYplLy_^UF4i(FWT5d(EAZ1`Z4>d}qWKD6eeC<%|7IO2A8`ja|Qrz!Z77#skQ7L!d zuEyzDOD^6ihItgWpE$T~t*=uT>Op9lvdfK6GHRnI)?d`eP{c2I$R6yC z(4niy>tu`PsM>+7J6oR=D&zGpjX~cXMMcW$Npuaxnto&Jj2My3FawtSh|wgQlRpID zlJRh5^DZJG*t#=Ps17#U=&pL@ORgX-6MC>^gL|Y=>?SY+8=Sj1^V}qg@E+Du4K%;L z0}MM~Dg@Mduf~r@3bR51P5Haf*_P^kNh;0*P#S}Ih1c;3*#)XFo&{m!VaW-t3VYgwVfhYcx z0r_{FALfLdnqYS+g+6g3EGVgY>t2PUpm&E#wSnVMVaV}%{k0nPmM^7Bme5WIw9$bI zy-l_1*|EgvowD7c$Cw(#*ATy5vAqOmQYc$2~x=_i$F9%=U-qcB*$uD zgpxSEMxG#eJj})=3BwB-OW&d?L4GfU9fxK*M6P$v6nMui7GHD5Y(`g%p7{2C9PA3< z3J>f2ZFIr_^*;9X0T`e7^}o0_DPZs|(SB8q$X}J?|HU2Xe^ZV89nXx4`y~s)h%{2t z+8U5wN+L>+jVR1H<9<`f$S918@-~`(-lwENCdFRFx=9zOcE1DqB0sDF-49$4B4NhW z^V`kz&)@xlO-6HFo!>Sj2F2}3ohP*<3s12E71f3{TPIQK8-O_N zw2@S<(kDgTY0(XmlI<~ZxNVPU0yhcgWf2$?%PuH87uGm-3uh?<137tb6Lx^P7TUzt z9{FRv3XECEW)Si12-euuddiz0fvTKW$X{xWtS1wsrA913>*+J=crx8zNH+a)=Q*MD z^h({u?O=uq#)43k`0&^=!{v4MKTY7u8+5Ndp+%$nKKh@`A}W~mrLwJtBl1-Yt{M-xN>Gp{<~FNSk`S>pt7t+gGJY!pG$u<{@zEN{ zYERXVty=ROZuSgf=$*rs@|JYJ(!cEKDZZPs3xH4_JzT72aX*i+Z+AJFJ=HA#>;$n# z-NqI-=YcYQg?G+{4>g!# zv;3q6mcP1@?5ApbA?~j{kA-h$fTWUSnMoVcq6z-?lmmhU5x0k z0YN{!FMhb-J^l0L*Pzi|$$s3ae~Cvzsq|Z^X-92m^SNZr z3hLeHU1gUlrQ4FtwBx1edYyO2uB%}vz4*PR$?~6BDz0QL`eeL{#d5Z{CeiiHw$Dzo zjPac4TT?$824+l9;C+rv1-FJ>Vw-K(aP*EtL|F&(`Rb13?I+{dpY)S=7FQF$ljg>E zb|{M%;}7?vkW!~yf7t%XzFdNK3-9c;H@kldQ~{^UCKJpVjEgyoVa~lkoVYIrr}Nof zJ`qn5t)oM#qr_~Yi!aMwOfo&78M@ud-mt@eJXG(=FU!I!Z3dA7O+1O}8#XPtTvQfI z7&G4P?#UCB(H<;~u8~%*HQ2-EV_@{J08#o}uDWQx*K+2{WUR%_tiGC=sNr zeo<-jAh)RT%x@)(JhbWM$fG_s z8+XM&XoNX&Ij!+@ku+M>?s3gL*}6}N_@NX2y<`*Iu&UT7VavKl_H_L!ft<%C=p;Z%kq)5M=CCu6|N-|n3sX$)Bn2j{#6);Kmbe7HM_$wJrHwUc~!^|U(bnUp~ zQ=gwdyyp28{$!`k8cHCzRzx^WW!}?XKWEu-{(1fR@rNDg^@cErLYmW9DAYi-nvW7v z3ZWS{6KQXBY>^dw8GRBk6UzD9M+l*YsuimrVZ(Be%Ucqm1>L(H+2A+wu#Ln$7N<8` z5bcXLRL)42s5fxU*scq>p7ITVr%fe>USdoynLy8CP|ZQCZ@KWGhWbSms^jJtQg^T& z^-FZXHPuVDfRm!r!&oJ&TmL9WJ83RLda*4jbGprWb8q{8Lzy&P)$v#>vw89**em?J zJp$~5NJzE$a-*;)GdXH?Xm?&EYg%jkzDNJK#F(ogSH==^81nPE`P68kO9ed}8It&& z-(3it62X*=+{qHB4e>x$a-Oy1M5IMBQP2A?&w;?WWZdedOe15Ig7*0lAs@D%E5<9J zM;rS7>XFCK(HQ1nhmWd+GSXJXj0qFw(Q&M(1FKH$mn+}@G@7OwFPa^&xqxR<21cJz z?k<~|IZvc6$%svmC}!utZOW3sO5H8$Bq5-z$nP=(oAlpD^k%DY$?NYs(*OE(z}sZi z=JjXd@o@z48L!xH$r2JIFQ5)=oxxH%Jw2g;;@N)4Mhd{H?e4DVc88%9SzJODNTKS` zNA!!OA=-->te$N7nkHhq+tPuWHmqvNP6dd0bgcpw@A+a1Qg8N(RZ}53Wza#OxbhIr z>|UAu;el~e_S7^z;9@>Sk4Y&Q6${&pMG7CvIz|FB;CoX3`Q&$wqzjm(vFq zrF35XbtZ2UPh)Ub;fen8Ggb&XtyK%t!lOGBi7271kCXBMqarACaSbkbqJkg?2XtV1 z@l{0$3VACjA{%ru-Mc3>7(FTTkVa+6mdh-!=c}UK2CoS2*Ul`T4Xj^Bm5EayL=kR` zf?kEv=oq*4Fz~2UC@U3vBoHc@$pgTdinp1#-7y_hTZ4#TPoMOx>bXuu>CB_FLKB$m z+8_JLNlhft1m!QtzLk44q9^&ECGMp!(7xq+W-o2wEjLe^MMkif2Sb_H_+-h}J83Om9uG|^aO*Lw=f_%%Wdt*|hDRm{W5>>}(w8$!>W~Pn5%LYaM z76~;*>}qRDX2r=vRAx{dWhKg0VnTe7I$nHCo)BN#~X=BU35}eUJH}S4K$L(vn%^l9;hA=l4} zN^rTtaZ=q*)fQ=)bnC{In(yT~OPLF3IYu-l3K}>#WzFhq>jgzkmc3s#uS5gM=#1JX zT70nYt^<&>OiS@>3yN(MAk!ZVmD7sCz0M^|=4CD=DE^P45^`L-Y}j1>b8F#2W7cFsi@G>)mZuK_WCIHnHUc8?-4RKt zM*AyMp9qYjIWR=9jF!Jgz==b-C^mRet}i_O)}~0o0GtbWF!pdyOAgAOfw#@=SIs*| zy(niGvkWoCyKb}Yd9T0=&wCN(nu7N}lJNPcyif{v^NA}1Jw!;;Uu}XS1t&ug4nUWC zgw5eXCuq|JVh=<_e;nj-hhg`?d4#f&7ZRug-rbWG*>XXI{DMOt($ilYu0M&f-ID1+TWHr5!h@pTu<%CFzj1_+kOfZjkCm{_v?k_Cm z7gXnhypEqQVQMjvfQaM~v$J+g@LqtsL3-C2pd)BRRXjue0MbfcI|ivHC+=YnS?;$V z5ljs|^@R708nUGgY=gM@r(gS8@NcnC7#g&l#!+iDh_dP(N(XeWAPtbBJfOodki=9( zQWApHZnv#HTzlY7Axe(L!}IHtyT@zHs|(%1sg6=uq+Wh0!4XjXxGk~@A)sX)AcreA z`LPi!!6up{WDJ2Q*d0_FS$nmVjr;_9R{VFyX^cY2Z>7d%w}O}GokRpfd^cG9Gg{k2 z)v$=QUKAg(r$c`0PTlvqSi@=x^tOWNEvX+ZQvIFil!ctj%#AL@_cv(MbQn|d;Ajcw z=V`{MAMd0bQp-z2@0m|mWGA-SE-D@xN{~Y3#P{fbwv6}=GLRx0%tC|9H}F#l+jvL7 z9Tr`*;hE^(S=u?=W;QrpRmiV-C)>Q-K$je@RyS|-{^FOGmpuwz{6|1U@I??}df za0C;wU(+^~ySpIy|Ktd4d8DMFECu)e;s{u(X%VnYe_heU>D})@z9NiW`0lSbfw?VN;qCMV z^3SOft}6+Bw?VVlI!tLk+G2Dw9iH=)qh&@HU&47Op@#L>o{j;DnMyo564cVf{^Os2 zL--+-yA~CxV$`mb*S_3{gb421eLBjy<2n`}rdO%)8t8awbtsc|;%rB6$AwXX&McQvJhxp|2xCx-Z-vU>`{PxU*R5pB}-hjnKwgNqA4ag18) zd&TrnE6D2?M}UeXZa?_N5r8R*J9Q6gIQE91roqdRKZKLx`?m{Z02`--ZLs2dUr;W%!~y{tDnJA?6xii z`C`#lpMkKSpNY*BHtKwOv>y*Tn`R1I zNi(V^itK1T;jh%6`&-Usc3E0!jtLmd_tErEDq&LO*fFfMw_2@|q!`9^_+M74W!RrbAK#0n5j{#v7_OiyjpZ&AlfsR(P^RU%HB_rf z(c188!A5?g3SuYIUHYv^$g{lckYsRNnd)|#OG#OTf|E7=JLc5nC81Q8wu*RUN!fSUhO$TmLQE+o=qKCa zvEEa=kG+-#;*~dA9hh}Irs8(p7JGF#EFqIU9sEjKg!%OWR^95w&5ymX^ua_e7NDA= zY<##yb{g1cDL|WO?XiRSo)xoZv=V0R@>JjW1AIjHP~!h&WfG**8gIaqeqB!iM5WJ65_yJ;uoxJv^1s!?+L97oa)faV2J)wn=!m>GVET?}&#>>g;@z=PJs?rw&LDaLl*v!cp+JkXr@(!#E z(1G?2`R%LY`%|1(96Y4V{hJ5w2-GTu0^E9;{2K$SQ)Ie$+y#n3h`2gAQ3!O6dVOL- z5rjCgBbtg3R)M>}=9wOj#Gr#82eGmPo(i$@!V`48EFk&uzmRiz@}H5HUm553bx@-H zTjnXcSpP%0KUnT>X0Sd^>6KyF1zEwEG>Yx&TF|--v6!54I2FGbalNcv59={T^%`y< zUkV0wVCQi;7?=^aMi}(A337mJ?aAzk8PGULA98e*FnDGG&|Q^`-a2Jb#F=JMkDfy{ zo>eJ;>q-}0kIRd6hIElAmhoi8cVs4`X|{YVL9+sBRN|3O@tn-rAvR3mr@K_SW6It9 z&G?FTV}eArOK(eebf)`D?vd973$6}w=VObHS}6UUGey;?McrX~=mDK^Lk)*r=#;9y zj^zn9^m_Eujq{oRv+KFjY5P}14&MhFa#kr8uw`Dz+k&*-{OLI` zRY3?y>4m|{#9~O>1JpnPT+Hdhd4Z4iB&0cCzSyDLu|~`{k>mI z_R(?6%1auMPewOtuGuLk0dLJbtoBcZl4}Ta8lRZmSFU$Lfh28;>)li+`TlAec2Y3eujNsl6w8oP1DV^x)p)J81?d)%6tck` zWt#L<0-2FEI-Jc_liNtqg7oBL0mb<^K+cu2r-)2O+Srl^GZ`)}`q{OryCjT)kWra7 z)4Ev>G8Z;0lc5E3I_oqebDOYgL0z6iG+(8!JEhcde5$nOS`267W9v-bAB`-8?lp64 zkckGv?Tuw6%iZ5ugJd zBZ`UAN9_llh4-PYYZf_P`*G7*(~o*}XB?O24&{$#`rr7RTrkE>y&U|cUP2H=J#Cw?pacVW$B9hXou8H>gD{|Th?=^JSO(A8a?uBOM71t6!gT~m;~dt; zPK>IH2?pKiV;j?Ld@VaNEo-@GoJ|QX7do|G{Z#Ir-#DR+m;DULQ)~%S!nj|$c z3E(h$Ao59jamTlr;asqsS!Ka!%Xc1TIRVkMo3nn`LaK zcHjdynl)xhf~R8*l&I|a!9Gh1@t*M!`243cplyM)7Jc63&tR_HDf7V{@Et|Jq)zCX zHqWeWah-m$P3^cqsKv^7Iib`^Z`^|I46k#|kIhE;Wo>|}=<#{_`V3DxMnHK$nn{^< ze%7MvVKUhsV-%oF%gns}XrAJZpTt4v-U?WVdKm;898&TK!eurXjx$iz!2&&{-D6d4 zUIZ?MsnVb|(tvgV9ZrqOTE8`X*AifbS#8o9z3U0U!E9!*HffDBz!^Z;%E^FlUj(^W zpmS}D(78IAv!&Y0hPsVvPyObMP8FN3J<8% zzm9R>I~{5X>Ro(ScUPt)XFD#J>*Bu=wC}s!i-t_jfT3b2mNS8g?D9^;IpEzL} z&cUDqR6L}wNt_DMT8a;oipWJIk~yCJ9p9k2(6{G1b95K}twA74%CVI*cs!1L%;R@< zZhi3UXqOmP4h`mYgIU8M{?FpfDC8?rIVFxcsjV+>P`-*WA&ei-DX>RI;&h0o52WER z@1v*jF2%-=q5>5J+BtsaIw1-v81^2QO}A^>j2D>^ZH);E_qjC+Rv>AJ{QSQDUgnlg z2b_1x?3+TnM`vUewB{}Fc6FMON}J|)_?Ncno&0w+9>lNDf{s8++?nIM3<3qWxKb)C zx=U6&)-0MY9w0JBN;A5Fic!2#Lo6Wf@RrMlgJhAbFx@u#7kxT+qSzAaefGT7+3bF1 z)U7T4T_I$-HP}9^jo{u|eO>Suye#mSB?a12+_gmPVMS@sM=)<|$RKnKZKXnqWGgoF z42X1X9u5a6?I&<&!Wp6y!nr%CAj6kKJis{PTJ3rLQ2dhBJn+aBT#3|cz+9Cn0E5f& z^qgE6;dx|qv8OqOjS#URdja~W(Rp#puWl`y80{U$!#bfrYmu$+{=aGNS;P*13m0D=%fPK4E2XMXFeA_op^*#bz0 zbx1}-#Nms9ldiva{)6ZW_fUw8!PY;Z7zcXe%8|Tw^7b z>?@aJ?7R&HxUGDLf�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 TY(h;@!?}i$7z!3V8^-w`q)kqw literal 121070 zcmbrk1CV6hwk_Oc+qP}nwr$(4E_d0sZC7>Kwr$&d{hf2}dG~%1??n9fPwdQyHFD?7 zHTIlyry!qDw;?Jv$h_V2Ugsdo?{2v(d5AZ+tzr&FKJ4{AE zRzg%nNtsqg^j>CSTw02Tb{0m8hH`3Rx`vK%D>l%>QxnzcUK;Unggx zWv6BMN5uc6{_k^)_g_G|f6lRhp`DAfu!VuOof$C$t&z2Xlar6Ujue&vG7p*nXI~-i5u%&4#^6t_YK&C*e^HIJaGnC=x3uT zj^~L_FF&tP>Ze+fQn@*K3pwpmWsgmT#4{q2fRoCmYk%;fU#XCE@VjZxHq3EduCXM{ zHYpt0nPc)^I(il47Zt+e@gSB!&Lr;Q3 zQ?aqSIKKhUlZb)*0VkVCd5 ztmc=Psm2>G`k+`OZz;v8>jL=O87@2*1jL$kR$~ftP#yqu9)R8yX44c13ANCto}IQD z@N(>~!FS=`p-&a`rMf4`eDTMls*zrfxq1)Rhp=;f-h6-iZS& z`&i%&)$c;*#?`_W(gQgS!W!|c{m8vn3x1{-HgncNIgy3qgxJrYLWRiZtuWL@CXx5i z%TOCq1b|dB4rtAxF8AuFwX$_uDcIE?KC~|GRx969W2gdRFy1F0RuI#(&W5tk3@1GK z6Ns&SwSNe{YU+M;@D8GjGobsNM&Zb%uBZmI#G2|C61?L@5v;iawvf>l&1JmgU5ZCB zq^dR3Y!naj$hnu!yc+y)u6e^UhAFlCxy49`EH=tjtZtHDq&6T4HXX)ymK`*9Dj7u% zZFP`ltit-sWpcCUDAG|>)k#V&tXuz>tw6Rzj)jP2ozH}vF0e9tYmv!odzMg6%p$X1@Iy&<6 zeeU@7`~G^`u5p`<#PuetbQyZ={Ha zpxyv~pguYVgZY}sAcPL737oz^#~Q{8Q)P}8M!N#b(QKvOtf5$|h(CedmC@4z>IHHHG~OMQS0hZIZ83iYIC#zf;@!TWD9Re&&x>Yvt;l)gltCO*Kllj6d>i~ zltwl8+*w*k-)R@o#N8!vyaABT+&ys_OF<$Y%N#`B{n#%H~m|IY+8?;D^u+ zF|(S0OThCqOOHT+oHAUP%@u+f+XKhYhU&u=ii(SLVo7}^Af_XhY__(QKBzjR--u(h zKa)W*nM@UWaSeHWvsYCv=4;jZbR4rGVH6N$_YhpopS&?vm&F-;f5e^F&z%tOktzG=4$|!KrfnB zJRFyny(EJ6qlgGAnUr*H#qJy`rbX`0-1#&Jrt|G07%|puWh0@;l}^8WGat%}me(_T zmP7>u-SPQ`TqP-O@h9eLDQcz|^9&tG-C293=7G;lG-|G6X)5>0Yozb=0~Y$nO%4_-3pR*;C}8N9U~?u$ePMia6|8Xt|a zad*05Lc)(>VakYlAuluzPnnKfBR;Uyfw-MyRP?B|hG!}Y7PJbY$1q2&sZfr57)HD- z;6?KhZ)A%C*`h?27|r;!W>8eukxXn%qI$c~aM3pFWCS6kZH3qV^5lZx3P9$~y>bP0 zY3mw-O!I0(k^JZ-XP8+^T)D=G{mWLJ!4P3)RS`2Bt@&AZm|qE-F3u%LEW{NnI>TGe z&VDdHC7x#|a$<1IEiOwp&L~2PO2hV?o|PeHe!XRsQ=-!jWqW{=??9gVTX`m11d|JB z?}0Abdq;y`vAB?veKSIn4I`&{J=AwwoOz*ZjT+LVo)7XUbkiAB?TCp-lKko8K3nT@ zC*gM0V9rIox{E5)y44(Zljr4THJ(rHnqnNA#jN)&Ayy5oaVJZQAwLXwELA=|G5B(k_+|@+;+)VNHiXc8#Q^;bxW0~v-@&+U=;HG+ zxJ0Nt2Qgub*_e$;@O*^PwJDja^r~%? z3D<(@IiZl#o%1Ma~64me)K%3wrv8g-5gTeyIIsrX-suAd=m~^O5N??^>Iy6lo zAA(%UL^yzGR-v!t5L2|i+Epm+sPwsFvObN`l~x?sPwIfJAdeI!LtZMw zi6PX_V-B8&Dg${&ZFoMJ&g25_RC0KdhL~P$o^;Nz&2ni?*o>GLVrmUxfTPJ=IUM52 zYok(IWXNJ|EbX(gIFAOSHuxJ-vp|YAerluB2&*|KOa{DI9NeZgCiOuYL)gjLWPqS< zGa9z;QW;)zLB?;!Ax1Mf#vpA z5OPC;3sLRBa83zpxYxW0Lm1`<)a7^P1+-;6d3fEdjBuaI6tfqjBNWm`UQT3V`yXIJ zD=}aw*1CqTFGYB4?vsmXqnk!exiS4#Rb{>B8QL?S{p}kr+I7uSFIVqAH(K4a)q8!-D8N4lo4P z$b_=w=1@Hk?H=o_8(RRIOhYi!crd!>^vb*tQuQjgt>7CDVhQV~S5wbCzvvRhNwZaSfRUWOQp`y9&}$bc%53L+D(D>t3-M}`%FR_qbK;D;C_ zJZeB_Mpr_%-CUVPp5=BeMh`GRG#|sm%_45%qc4?Y zsdlrnvsva8gDnb$X5tj!HKf+ew8;|W#tAYBIvcG{x)eB#yq0;P4{@w;-ms-9UMmBl zQCKh>J_t{x6q`#GxJoVES>W<#>%00Y76-eM+)i^1ICQwh?%OG>8pRuZHsNFJ1=p{at?J8Ng=j<@)(zPkF zedM!0k{C>;CX>9U$|{Q^k?ZYa{k)@T;zrF37f|w4`~6U+`zu5?xfpfFE^C9>Tazq` z4gEZ@PWBDTo!7rdHqI*YJIeb#^w}0>*!csMb#Q-o5~Oi!pqa}&V^7+voXZzz-4b$T zR;OpGq7*0jnQs<1g+Z79S>_=z=Xp!`TZMTjBi%&t>)oU*wEGJX_H!Z@$NHn=mOhUJ z{Q>`{zq}jW?w=#Q!f;e zmnS6s7k{&V#Ik6jRb(E*yz0d4G=T5;h?Y1@ZD4~=m;srZD?^64KecY8h9IdND>h+y zk?7GaHqXGxVz8Jqr1yc8xl6K)<5?uqSP|iLmB^RX7<2q#3aKBgB^7<2Kq(LKJW!iD zm-s3oM-~crmODlb@By`QU)DZtUAVK}uog(?@+3Kkw=+-=d~dvq_g%ifv@-d@k1T~hMS0~v7UjQdWqC(CGe;9ACqV2|?_yD}EzFHI+4S}e_I zISx^V%auuG$RLYm9OkvzOz4-XEfr8!5 z^$yGSSpz$Z;U(bcD9x1)JBtcnJh3s?TpA6pcoam^PUXGc~lC zakP$l^N&!i`?gr_`Mjmc8*Avpt=bpIl-tOGol8Q^FyS3!WIw$~!at?g>+T@4CPQ61 z{n3ovaV-GN@GA=YZ`4Fv>rK~4)Ckh5x4Di}tw6Zc(%>< z${2!K?WV;l_EG#k@y8qUW8K5~g0t-%c5MfnRDmA$joH*_+ho&3WT&_<;qTeQjTky1 z+fUzOuE}M|FN}i$mk>`)aSQdy94Mog?b9g%q(-M7ZtOf8Dc8FrAT#C@h& zEeSVb_OMUaYwv9Z#8elYaM4Qp0!(UZTTt=qs9@pnwgw3O1c#f)Z6@Bb`1)ak$gS_0|*K_(ud!GXK1y3ImUANCJhJhe z01}pi0z=%wZ8*iQ(ahkre8~8EUOV5Izu>)vi0N*b-kK6~KrE<66mQik`J{QQ=MEH5 zpU}s-W^+gL=nDv}-7zRm=>#%a_7J@#h*;=XDr|PM4QBl8VDRW`Oeb>=ytspPyI61i zM!GTHMlHd0AAkSWW@iVWvYqr0E{wm=I*<9A{ ze@ZybAEWpGt*deWrmK}roSYT^VY&V{E0PZAj}@sl-fTtj_^D9{r>wq3EF2aqjtPAF z?hKPvycxBrv1cX$e!BzqqOdn*P8i2Hdf+?3VK(*qFS}|)A4V!@)D)BQGQum1@>`Mg zjT=S?BZUnI-k_A?Drg&VH_A`bZj7I61pdf6g`%r7A@AuKs4Bm<9FZpNEH`DQ1dEcw zuGY8d9c(@5V^F9ROR>WLmMdJLBPi{#8=Q(o@Cm;?K4{`jaxyRi08Inh(>`{*08A)I zP$l?|*k;+po8pXS2(>~1Uy}uaO35u84@uvOr{(m`A?LViHS!_)ic(*mo9r4R5EY9NEKG1P}4 z)`X@tT*MlH9s};tyrFr|&<1fgzkp_}60zq*yGh37n65zO$+VR6^Iv395%326IZ8;tc+Pg@2-W!gZ z);Mpm1pUV6mKsGdsVYyHap9+xMm)~E5e$_ow~ZGjOE9N*`We|c2Y2ajPt7FX6#Met z8cpkL#UB0+5jD7u({X*d6u1TIdQODRvqJj|3_~^5bn6aiR0HviQN_UxdI+TmZr1?j z(>-XEQul7dMDFb?(nvD|Ts!2XGq4CJF!P4J3IMviF&b&DB3QyO)qccYh)jMj@umom z#ZgoYwIB+;7k&2z;6;L4vh*Hkmw~S-4I}A%pS^6CA(PO&93i=Zn~^cT4=E^-9{TCr ztY_B?di81r4KU_65#SI*o~Pqew3Wh&aky%Nd;E-LP&Qc`sFjLtt@V0%MCzggE(c6P zD&d1NS^FG6${~2RDu|rZneQl!O#^(Z6~c@O&a|QEqkeL%@)?UoaqKqLSx|I@L;Q3_ z+=iMkEj8+*cvsKNy!Y%!JoEHJu{{1pN||nb2pY@8PdhcW%w{x%#7Tz;+nl=;2%9-n zt1f1h$Ky|QA%JPv4VbEZM%~%kFtyhyDB6Ao2%$yCRw)#;UhtZIn54A~ZJ!!Cm}Q1f z;uW^T zaeTVu!YU(~xWhdfTUiED(aWSyti(DWU`Q_F1!^o#)`jZyf%Q)20t!`VL~)k1U%!fo zk??XF1F$?pGMg7dEVr!s!XSlb%o6EMpmOLCL_M|_0WHtVM8H7<-lQr_TB#Oq3i9Gi zvgFJ(WN$h=Zbe|$7U}>~R-Pnb<3o?B9lYIv)-XM@3nDl<@)rxlu&e_$TxMhd(-7tLqk~^jI7WLbQ zdIMWN*$yk}Ek#(SqL$Iex!%z^8r{2m!OcOme=+TzF5!&+5J3K>8BdBOoY5t>-pjnc zY3$Z49<+V%%l!uEgWSPvEeKrqX@kpan$7I$efS(paYZmKZ$=KVOxw2r@w8dEk~SV6 zes-uDWQczISm^4FyVY@;(`Qx%RT0|6NfK2JS|oR)pgP`QXH*@cUUP(A`bw$~m$8s? zkyWT2_bCVnN{Mx@7Nb5JdccD5B&>9ht4n{x!yx6|23KM;25$aLa|l}Gx+alD(81}m zEsVC`9N!cA9OZgBXt=%llzV$?v9n+W2#TX!Wk`UJ>j#1)tbchwZR=`XQgKk>lkfIsRaP+?f2n%*>!C<^C#0G?>$vl0z&30Bv%A zHT@D82QlqGU4rdDc8UMc^qKzEBouY5kp49NmS3Bu9g|CqOPU3XtjWwGYBwVCz!0cV zy`P2c;m}fP5>o>FUE;u*(IT# z+R}!^*RF6}-=>iTNj^)j6IrO_(7!9+cA5nh9c}kq;^u8kfl4b{+CCFb81M>XCa%QQ5aceRnpC6k0eEujMnoghSV;-rf}<88C)zj&QFm0h^u!u z&YHB*WnQ;LOrIx6`lATa%O4RlG4_?OKXcmNAaK*8ywRU#V^D)KF})%GSh_<2q!>_ux{(uZzw6Dy|z+SB5YVuaP>!}M_^ zzsqiX%`i-h)ZAr|*K`kZOBSQy%%SHoOdV8lA!4o596~bP5ox8AoMMf`YUv~Tfnrs3 z-RjhNz1+jYXVnL_@bwRkpjV)2UjK*vn*S~P z%>QElU#ri{1Gb1QQKC`XO-bD51Gcz#_~iLv0r1M0qwmI9OArpIu4Y7ErTGDPJAr&X zcqCgGKmh~)Tzq!A^6~ZX76i3YCzN(mtdhp3l`aoJN=w}?TVkwU;DI-2B=RIYf&64+ zw{$Z$=Qak1svb||e=20{l{Hr`#G+(~FT)Li(3?n;q-0sLgZ|PFjJ4CXbRvy{#ON+V zZxTt>`iiWbBQ$m^P?8v-u4(i}zG?EO?s~n69XA3m2r?A1@JP*WG4Uo`(-}&}R3LAs zL7>ul&d{)mp?@FMOX6Iof@E8&i~JV8ZQ~}Pu5S@YxL)0OrGi_!r< zdWAj$A22=oE|DZ>E?|Z|?5ZD%xX$mUj@ZFlF>IlV7bY#e#jM})xuaSAZ9mbUP0$4r zX@BX|Jk@lrj3-}Ny=8DQWFQG^qW8s-FQMn}${G_uvZ85uc@Y zU7%Hof^YvLi*>XAb@cBOcD|eWx~&KQIjX->x=wa}@7Etv3;(yIvi!@7QPPt8lhR+s zRkS*)o(S*)15%4NP}I8R<_L-55E2EyNPKQ=v_f1nOqQI@6uu*Ccrz9Z|LiJwDTp*H zPFnhrA#FO9cJ000Hu3d!e~-4O-b)qICQHnH+KOj#z~RN6cuh#)&ZfrLgFc7zJmTW5 z)|lB61#2e>ciT+8@IV%=t3a0X_iDo_^hDeN00wj# zLcc4q3H})BQC;kSindWIcd1DBK@HDU!o~x5g>z%d&T?Jh4qM{Ziw_C=2R!)LU=Iyw z!C=uHVpLX5bg_DZj$C6HX($(|?f#V?6Yd6PtpzbJ8qMm`=2nwD|Ew_X_`)pGBEz5x zDAR$XSShH|6~z1R^jXZS4Er1Y6jB|GU`u{fTo_Ao27N%eAr3i8mYc+K@NX3cqa0d6 zio`mDJ&bH7`f4)IEr0S}O?a1#1)WD=#e&z$a&%BDH4Kz(7$IE6BL+|H1yD_m$3Am8 zK_3Q9Qqs}plSbL*C*$dl{p8%pzOQ^kc>>>a`>{Os2;94||i5Iox_`G|!QT zTJ{y&Cx@DtBszLTy|}RFTl*cqOr2{Zr$Q!?Z^oHn#At;9xGEN|9W2YTc~sq4O=voo z4OU7{v|eSoPE(m)-(T-M zLZEhaQY+XcnrZyrY-NyB#)e(Rn&YjrxBNkK>e3?g2ya?99_-0^x3L7)9kfb-97$`y z*Fpt^n@Ydpq#tjBYAtD%=gb>??Owq`gS@{bGoUP#M_z~qON|6=t_cL4_(xm|;)so( z(t+?mxT)|Xj(NEc?$iZ-$zM>=$jy)EMNSXc_pLb6K@J+@8=9PpFj-w9l*4^2p49%% zw>R>MyY)cU8$-yO+DexB>OGp$Gil2Xl@X+sb>UMHeJj;Gu8}8#&sg=8PLe+nv%nsU z8N;O8is)*f4)`8L-TWnvn3g+fH4^YV+G73O#{lQ0`ht3sXqD3dRIO9;2sOC$1+(PK zF1?y}F+Oox>2&1OxQXUI8W%b+BzPE9FnFZ7tp5J1>YL@OHc+cXA#EQOlXZQ_YPgzf z3U-TqNgIxQ`yW~l*x{um;{Q*(^`ea5ghw|sP}*Yl_|b+fN7R&uvpHOk*^mqcgefp ztz^aI?~LK(eXKQv5L*=6ovSdz%o7+p8NKv>HZOJjF%M25R_BI*hOVed?f#etlV_1m zM~=*!5YmnZ5)7M490%sLWpg}3xOF#L`&l^N>QQBO+H(EI5$g39CgU2tX9!>Z&9V12WID>hRL6<>qrRuer$ZZ~$RAIk<>O(e)`hOOdHQ zX~By|0MyGLGl(pI8-Hsc0DqCcRceZZs70fGdCYc6rxTxAZ=wNmG5?wp@ zKqqn@Vw7!)fw1zzP5?F}Q~H)bydzV<40V*#SPsS;R2e6Hd2e2^2q%t%SaJu`xM6%n zy;NjB(w76<=JsrT;;68{4Z*@w|7g|kWD`6T*o1S$IrJsl+8!(qLi6|I! zO}S>c2`k&iyuR4!w}|xK*TiJa7>YES=A6Pl!a3K1Bmd_{CPfikiGV+B{^zY||3Tz) z{EJP6@qe-@i-RLp@mNJ;tKAq7y(8)EA0}uZuW-tnB`RZKrcb)R-=IxF`|*QM^0x$3 zcxgtaQ-YVQtnJp8o~}X3Pp#LZ&yq%yFK=q?2e1Bwr-Ls%^cug^5;n)pVt^`Iop7pp#^emCiC zyX$uMofRH5lP;Mps!4gPg$!O(`f~$JC*VEeq;G17Es^+=IBr!^ms6_U5Cw#f5DM51 z!g1pe8R%PNckv%gsde@&W7ZLI=n+et-=0#Gf4Uyq0kCXm)WPf$XhUmI6%|9$L{l}cc{(t(f z|Kupi6T(}0@$s9(&6F`=ln6pXy$_SdFcr8jKMW$Az+bch-++PqEVeUfc2qhu4W3_1 zYk|_G%nGGZxhh$87BU^f8d-#jwrXv%Xi4$X(8{K1sY)|t`+4KpREqTJ`xt2B`HJUx zqk-;uk}2ogn2*D}_$|QVg2N||zjA0B?;L8OlDVJ`#V0Qo!vTp&rg4eTv)Htb&(ai- zJ@u|VS>%I7f{ZRonK|06iV3={)1o49X<#R6!0KmA{Lp906)~!lv=qeSEu<2oz$t%EKkoh z>_jy?l0^x3#hIl}WWF9v;rR=c_@5MhU?rskQ7P=cE8p1E5eQe&=j|L&1tH!KzvavP zjHNhH6`3rq?Ph{MlRYC9N`=9ih;~{IW&72c!nVlPoY_>_WMYD9Hr_|DJK z>@adsUS6mbDKUDCb5@3hern2}5B=(C2Ai9%ku9oXf<2c86~M?PDvC)Ji#aCxZqAx> zEw^T-(Oc0uk{*yjeNO9C506=dWf#`ZzKIVp){Tck%gl3B!jQHO1|ZDcTgkQt5$An5 z^gZ{}Ar1bKu|+uHych}EQ6XEt7JaT7`%DA1N~%*?PD;SQlBMla7@Wd#D7`=H3m?2( zn+gl_)R-5=O^!tYwAhUmdJ=7aXd>0?8g3~jVrsiE(K7L6EkwF8bA z@M(zi%pIUUjv8jIKd>jsqs`pN4yvWC=o`Eh(98~rlydH07^|wLw-^}hw9_Y^!NYR(>L0W7rh<* zRi?7qy|P^u=sJK0KA3OYzAn{4veMRG*E*W(W#P$d>T5mSv-PCTlu(e&6Z=MFI`OiQ?R(DZsf$(YkrHB*a zWPuPKw0lq!*D$?SYBX?jZ;kH*J9=Nmo33HA$q5gXVwWAv!j2^T=KfW(!!6#>B@_;= z5L`wz*3a}Yx&h9yY%By0S-sQG4~{pbtg*@*dD4!-ag=M44a)lpP7ZY3oc8-GEb$Z+ z52DU657AJkUE*LDE3LQ9w)*K#T4(FgTmuazq45mDSY?O;QyxU4JU-2Q%|D)h4g=gv zM4Q@^m(wB`TC-TuDUYNPyoKAz@Wq2B9CLEh+vYC<@nV zpHlf|UetAP;;V+}hmZF6bCEi7w%X%*8ZK!%n>@@iW zf1~NC(Q6a79VyvD4YJtGQNGC;2HsmyjGCFMo_qQo5n&Ad(!ihQEWV9Ml56F@KE+D zga&~;XIShP;Zz;xkM($HSVK&}>z@)33MlPAE5HTHns8yIT$*T^qKY*w*#cqj>?g(* zG|l80qLS@bb1s15drpsp5%s%J7|s+K(_-%OFs3~2cLqS(-;+mOD9NT-^}UA%RYG+27@9L(m+=-G;m02a^~1!3c|0E0`kNZz{a3BNPy=5`obfgNLm34UxIo zZd7&?%1IT^MnQiO3jAAk>0K=OoWa(2VH_-eErt2UWNlh|dCf1=kCKerU`AQ0NiN!Z z36PEN^3d#{vd`Lep2_7)Tsd=G% zfh^C22Nb)(?!5MqUhLESirM|KOZCy$(OW^%Fnw1)I?8E z&#H#>_c{SFw4?)27>pw}jK`FZW>2+hj{T@+Qcfy=qRdIRn1R0Q4N;c4tM^HES>>gA zuiq>3c45(;vNk;X_Cv(#T!}6ErnF@?0#(ZI-IM5zsvJiDl5Z62BOld`eqDYGl)6`V$ zA~x4q$a2n^u}io)IEcw0JVJAjQF3Iw9@|DaNk#vpI)B+|G>J`~aVrUa?4!ueAEi(q zZ-vB^+-X0J8v4mGfKP`Kc9==317WShxOduSt9}S7No$qwh+tLfa^}q7pqwo0SBM3x zm~NB;tp0kTpvp1ff8aR+b2e}Sz4$8`hjVaV6N=7LNo`;u<6fr1syYUyqfYAd0o#T4 z%@if^j#CV7Pc=YnU#sl8cZ|wOFGzy@ROJ`~BsP@_A2$Q?dbJkjhPov_8Uui4MFRnH zn37QSbWh<^=Gl}gbj;nTxfd=U7ER$fo!GQTS%Ky*TDfb7wi zw&bJz4RlIgYp}T+xJ*kY653FKs}P}~DFNu2ZLtXC4ACV`%|=;2pF2hV0mIgXgPUQK zfN>FqkD#RBSn*e0wX&MWBFfpiw31WBq%DJp$N3@)2xVopNNUB&vlvx=8JA^DJ1#=0 z;h$Y`a4IKWhB0r^#N5Dk=SE3+wsXsOmR#DS0hP5%nPQujSRiq!k9lzxg0hAKv0MFBuCx1=XTy8K7DGF}49;1%c!pa{g|SHyg#f0PWZ#yTEKb*V zu7+pYK2itZ2bE+iO|R=&SdWIMgbNU)e?kf#a4psl4Dg#15igXL=*`d+d(J|FjDI3z z)eNbcs*F7aGq`(ee5&^70h}>MtAPwVojunk;&I2I zc@_AWY8Nxo;K^*Bh&#J-QkN=vj_}!nJMJ$sRL3kEa{~Lo{*&~~A)ZIJd6?pRHbnfX1bo4+&zT`|$IKs6Gv0w4-?{w2WAJnaAK)AaS_gK@GlnEDP zEQoYJKAM$+XWWSIB2;{Ra=@l0&*WM+UC4g!$jI44shPgK^>Tp?>EDyJ{wM65y8YCW z1oWeM25?w~Z?4-w3$eK-GAdK-EGkh)mLE~`kRCcoqP(g~JXqq#{D4jbSst;23U9e} zsEqIUK#01+6)aI!C(Q37rm-aQM&5yq&A$&KfwMGFN**1~B<1zV;fDQhK`=^(S4t00 zu{qTWV2kDLfZ6V#Kyu(JgKlcrWU-JM2bZ@#(6?x7O}lVQq{{LB%-3QJUp*L?R9@|= z&`L$%2%6y`JADH@qdMm>86VsbH%yKFOMr_A9?5@jW|tC(_%iQ1nM zOW)Khz^rKbTFQZ059}QN1ybno_f6tGytx;G<~xEg8&R^205v;a-439=C+~$HmGu|l zq(-nv(xe6e%^qepO#1Mg0(a=KH|Q+dm8&MILq40>D6>3pZ59ARvO>>&wOg zdPaUgC+laBW%C}N&8;3 z^`J^TuZ6&6E85$MtnZXIoB%pIW}p?N>=v>ei_4YhYa6I^Q@rTe=nr`b+GW3P=4M#< z+4m1zpPrmKzr+k))q+zb71?hUy}aoK>^E&38NJeAbhJ9HtO?zwWEhkk!KUDdg+uL1 z+uhkSTv~O0 zWl2GzLB@Xel$5S8$Z;e=<#{w0C?6V3NsKR;ar(EPNI#;@a3VB>CYEti=4^Dv<*4W$ z*uvQz0+s)$c>N%JCI@oLP2W;3xKZ}sX^X*Ygi8J-pCuN?8)JPX)k}J^QUUIEWzU=v zOpOp4Lje2AeG@NL)JqBiBtson#z@xjY+KnUua*W>XCDFxrGf(UXNd z!-&ty-W9)ijAU*@`xWbsiE@jeJTY&kE68PGtEpzWq8oy1g*~8)t z7;gYHop+dOx9`!2SZ0rcCu4T&&G?GG)&oTz^6Fb%B%>{s;X&YoqS+o4Q!*ZVWZUy0 zqb;`{SMSH2VNjDyOV+PisAMIBniG5&-2Ot{7(Ojn@j@-!Rz{kHra5S~`{GT(0yT^* zE~3dk#808AtIj({Ne9(1Hr{5~=#4p1jsvJIW%TNt4*i@lbY2=h9ker*Z}e&n4xNNt zQ-XRmGoV*#m9V6YGE+{vPGVY-ZkUoE!iXnj*=Hc6fnW zDlKx8mTMKJEqoFQ%ZcS}?+XD>?~4~Y%FLyf%h|zu?0ILn6e`1mDn3k-0xo+6H0I43@!`Knjb-rAd}a z_9dznEUalPWyP-mi@b%}`!pPwN8WAJEo{qc`HY|vO=JrgU9Fr};{S)ScZ#yKOSV8O z?MmCW?MmCWZQHhOJ1cG5wkvI$H~;QFr|-F=`ycn=+xv0v^{rU3W<<=G0Whi)utGc0 zV^CV3q_d~?n-FPqM+kopd$z!sgtbw!Vs+s3kvubbx; zJAZE&HEI`~1}_Y0DbmuZHv0Sw<+>F1l6+QFn)s}Vj3;Y8B z(oakMkn-MXX}qlTt}dCWfH1t`$~+BM%meQsYX+u`w58JVL*fs6bNTx9g49vjIy_(I zf(Z8Mo9Hx+{TOny6|sx1P^3fSMv|q&2z6Lt-oAh+Z|-441#aQER&5C`A6-rpst4j} zHNY#;UQm*v?J@Q4>1Bh}OCjG;JDk&1F~U}qqZ6#51MSQ6Fca9PH`i63f-9~391uE9 zJ;%woxyz}uNz!I()Qu7!lzeSIUQ7k9oI-|Au}df-YNX=+ z{p@+3-5-HOvfdCdU}ch*`akE$yod`fw}ncc;f(j}9&&lKV8%|0PW4ogBVBoMaFawf zrOSr*PDe=`HTOINPEVZkUXF4V;D#4zgN=(q{y4muaq&W~v;SD-0$t^j7P&)gh|MWX zcqTXBEh)nW*G?` zTaeP@wW_nrG80LvD;HZ@MC!O9et*-_#Kxd_?OUWCA+>? zJ7pd~2%Gs`!lY$m!J$JG#`wv`)YlaO^qGYp{EoEi`9NBwMBEKiGiy~Rmczq@H%H2W zHksDQwa-?!s{Q-Bdq!!7`^jlOvlWPj8anAm!C%~9~gFtq;O_g zOk(2V>XCGLew{d3N<2y{`x+jZN|HAq&B(<*cx|{InRQx))PI-Yg1~cfPpoeg25Z!c zN&Ir{0YSWd@CnxXPQ0HV{ghuvDe%Ap;p8E05AS-PROY$T6w}sMjd}R$dzWRL0~`0g z31A-kc07BJ^f_b})G;FD_`t^iyuSyw$Ui)-qGuWL_l%$Lws~-B@6P{63cssd@5xYya-Z7`0(<9wj&JS4Ps1`fuF6H7FGFX z^0M17E|6n}-=-k~c2A0&+R za#!9=xxg%D+VqJ=xeRw1CQDR$_Xhw@$$C3Qk6lhXBu>?A9Q1?(diL&3JI2K=K7UXy z?;HEF#8QQ-2M15gk2cQ!=w|HFp< z$p*+uT$TUka0Y)(_5DJV3Jnc~1dtPeD)39OSfndSBC=(5%_Ji?MA)5_@Oc=^%V_;rD+YinH*g{wSbw807vZCWI-cP0=)YY z2jVv%=_R&SGn35^Nbcvj`mkRxbS88%%^AT=9!tGUDQ(qzqxHebAz50E`Hgg*#$4oc zId!z{wm1gU_d2Pj7BcZtvD9YL(W_R8XR6ERGNBx;?2Onm_Kp&-+-V7W_+XCpSa2}& z7&muGZS5;wrCWHSIQy2KVPtgibhfG|WejIZ$r0lOHNf=IYV4ptIGkfaIvg|~78I+m8;}ZEm6kuX=3@LSb!2QR~tJdEwF3dZ8q=9}SJ3GpGJ>K!F6DzV(Q?_Fe@}k1uYjxK14<3@;2l|eR61%Zqfs=tku2$_lTN`PQzugUgqpAp!4Wm zq0N#SDB8X=@elBgISH|ftR|yu?04p=<{eHoRgoi#C^So+2YJ9Z^zJW(Q29+TYU7 zeiYdc{Inip@5E0S63b*@KcYwI)u9s?G3nB~ZykM`D5zzQWIcJ4s_Q=%j0>y})&w_T z89~?V2_(leVA8*r-X)-+XDR7si&JN&D0)J)T(Z4Dj6YcHGf{2~&cOBg(k#-+WG-ys z$aBw8%eBjvzP=}DO>yO!D%0FlG_Xk&Bi%Ex&6wuf=(Q|-^_|rN%2A-W*^QW`Y)p2| z0#smVooV%&3YMi?=G-r^(Z~<#i%#z1p_J^d@+*RPZH`Skpl!&9*Ft+;xO&e z`6+7uVUTjP>OY`!w8$=RL3#E71bQ*--cDPhEo@kvIOcjk2O{&QFqjEh;>cKvsu|r&j|+UPpwmcj<3@(uWRtQB6}zfzWAp<;=lw?hUUnHSQmxsKg=4797j z3%Yxc4qfLikQL5Z!W ztft;F-xpxx>W+4_^g@MGfN_M56cBATm#Wvub*6?U48h`q32D@%b%th?{>Df}pU`uc zx*5^^7g&k(OW892CYl-jEft&aKV3BPMz%(Jjz)%mneV@Nfr?sxbqa9LFEv$4_$AAS zS5=m-pcLjlkA~dli6sal;1NAHS(O;swXdIp-2%NMl5{-}M8Kw#F~=Xbe+}^FZLM1S z%I+8$UruB>T(Ud3_Cz6UUobgKcKhg?5| zK8L!$-)ty|CkFn9qJO2jtpvqs(G*FdZ3?rz%aD14gf$cOO=-)%v<2K9ogx3H2x6@~ zvsS-cdi4bvay1pjyxcuKQP>rlMSm?*!5;@0(NKJvJ;*+8aNXFv-<9a^N$Zui77A6z zidG$#%1T}mjZE-w8Tck5_2|OmDI6T62xi7;96I#qCNDHY9czP^;pPr~KM!w-(bY6j zy(8rD)ZfLYOrJchsProjeHT=B~c)&`n=)EjYjKnDIaSI8vQ zvE3=~b7vONa>M5B;m#`8yrMGd?Vo{%XM^+2!q?Ra11{ zulUOp?H%Ir?I(s@1B4K;*Q$NcyF~0JFTdks_*1K!)Hh1$C9{{&wKTHSA)Ems0B_RJ zN;S>;9jhpO%EF@2*gmcm0R1PRV`+S6C9#Do;Hn5i=T-#d0=mZWCQteVG3^h5++*O@ zqo11No|Q&C1#Y3RLFokd-~fJfG7TM@<02dn(}Bk3YZU?U+hJTQ6SfE==_lc@{irI7 z@|;tn1uf*q6#qjR&zTdg*0&|rCy>Oc#zTRa^@mV3ks2*&rwQ-9T-OEJu*ZaoGnwbudUS#Hg&>8-e0 zCYPWJq>~7hT_c?t6D=YJu7-Q~kJMa4h@cK*dyYiw2sPehOJ=FyF}QE1L|>d4Ch;-c zbqYTkMP2x&0A$Y?sN9vwIEuruI;%cq6yE}HOMME+LSWpLPr8B33o8@!fijSo=gc>T zP;!-BLdTBtFPR-m(~>@27QmKUGWr3{%c?*-GbDP%K`VD~)*wZ}D*R{_siY9DF|dPa z(WhlOsR!%kDJJ#phth2esnI`rk#Q>9%nC$xG+O8xScMORg$vZC8#Ce^9fB^Gk!iDt zX^SQ#V7;nb8oJ0HDt14J?dTC<6&L4y{_?`?_$O`f-zEnAw_cdwznPeVk)xCC{{)L( za_fH?78A)9zzyj|3EgJh0OIp_c*5>CW1$`)2Yqf4oJ6*yqq0{7tWw3h0dU3{poMoLUL8r!JCL z!BaA#783$%^0b56?A>BQ=<}H_2J26wf#1I&+Aq|AjG0gFA&NTh3y6@`v%0`wkx_{i zx!F|73VhSSP@5y01xpI_2>l}#)c*Yp6VOe@jm zy&d4k;#imiUllLK)_NiH+#GnpDgs+2Pxs`J$|zc*YAB9i_1@ZL_Q#8BLB>{@OxycI1eN{gBjuYL#A?SbiO?ZE6IRD~{$8THD(;*FY z&l^vI7inl5f6h2TLpoB++VxA#TC>E)Lh@Te+npGJGSn5?V>K=Bf)d5L{=k8>I~TkF zF(W2e<>C2!ze_Rr`n=mi9dixk(YvFH0_09iQ5P126B)f0C3%%Sb=>s_&+2;sIvEx} zR&6Ciq>uqxI)`U*-;@003v+OTub5WmUgIWVd%G#C)Q3QZ{h16wxrZ13d+rXgEP6nU z3?jxksXtP=>(^9E#w+v zSMK@3MaQa{k$e@mI@bM35MH|=K%WD|a24W_V&aiWd!u>++qE~Q5-on+ z@?`mlL21!4CP%4|H^#nF8jNfVrz|(Ec9p7iSo?`M`4qhD&VJ1M9Q+8aQSYx5z1*VH ze5|orOx_kv?TB_l@0g(yb%VWecq487Rn2YP6D67PhmvKscE!9Y)c||r4Og)Fhg_f6 z`csVs)If^i2g@hmUsj`wtQ>dzZ8ea8>u&ztVeoI^Z9WGFBl~}$y{r@sSH(r-;boGP zG%OMTAOW&J@o+>ck-2mB^r;huOm@&SdAf6Rk3{ScKnd(@sCeoX{2E2!De66;>arB# zwER`0iX9DW{6(l2LhIf-Z*x42GM!wFuph5F9yytk(vP7!cXS@cSx%p4%}ZTXnx9t{ zHnQ+l`MlujHJlldCh8&bhoOzz(idh{G9^`tLn8b$8=Hqb^~`!CAsVbtS52V0)Ch`g z^wF$qz{t!@)~JeDbzoILl4Q&H2KP~!NHJv8xmV-7DH|uxWmNqs3LbsaR;-J6-`D9; zOq>Vj{ZWJ;eqaKl7r!@ACk4Iv2OlFzQ6+?vhOpj`J_{Ig;gglRZMAU!ayX#~FqSLA z+YU{V&ghRf39iVk1K?ywn;y6*#G3`%4Ce9f_CLIS!$oA$_#-$Wi1DIK`KHfDc@Oc6 z43NR1hB2v5fk%Ce8E~AT93DwlJf$xYm%{E zUY0$jeAu}UwAAmEEku~l`>aR%StDRRVy_f0ls&eW)Blv2&ruUVy?Q|7cd8a2lnLvy z#ltK{K=q!bd8ZTXDxpX1&|LZTYT`iwX3KE}jJgEwQ;m1WBs@Y{5fSkZwrDrVSU*=3pJO*=)l3w|AW*f;NNQCD z_04u)Lg3>>_s>d;=s(~+02f#`@07o`6_2Lx0640;I%8wXx32Fn$38Spv!9)PrzoDT zAPIQ0_AuuJHsi1{b`iW_UB-AA;~H6DA=Jyp-HrPIUU@qEz*buLXz!%(%-`>UcyymG z8{^r$H5{K-pcD9g*FfB(g0w|w&^5RbnY#HfU!-2~-#)<+dE7RZi7q6iFhH*7*INKX z&KE+{;+A``zPr_aZy%RL;I#OQ9rk`C0(AwHnN_UX6tiPcen6Wwznq|oY6u}Me0**B zwh3+*J-LGV1U=BFfrNZS?H^AYrv|}X_2V0xC;%xFO;L|pIyva{$16ew>F;*CN1EDz z&qwJj>kZ81#ur0SaK_NqkMxj&5v9W{|KNehnS(H3A7Z#9#PXAlJl9bEAbLr+XR;A5 z1k^&GWJw`KAr@her zD5X-U$YVN*m`Vi?B`K|3;OXxMH-B0QZv883SsXw~&yi}%f@SwslFF=0@H1IL(X;D? z03=;wsLUIhH$7d$eu0U&8T=-cMSsjXP!f}j1wSoA_THIXr(j@1pE}RjJkC&JCb0Qe zP=L-J@HVgw=xtc>A(qxzQ5Slz^=JlA4ie#uRZ^l+?V>daF@x(xq-6DxB+bm4wjm>5 zPHOo%UC87=`O4%DlS zwAjnxU7TOdT%ybILV6hSrc$?X$BvAbz=n#(8xSL1rdt%ctx&D@g-)FDOZjJ36{uTrbUJdEJ4mJ7s*?#7- zg1@zgP?0qz1z+_@I-gRhr{P7 zEAWm0K8;MovyXslAKG0={28wDhzu9w5enNn5Q4S)#yk*`_Kc6i_Z}Pk%naA19s3+A z;W>cstt#gxG4jqHFKR_;B8elu8mtFJh+l)0@7n|iOAX6v)F$g?~w~QDdrqSddOj#^oX53J?3??^T{tu6K{zr|I|sgk?|rIg{$x6ZHTQ%BU`kGW+`Djn zH0(UWUWKZ;l?F$cw|sxNH~l!3z)}1&e4pe+R^I!i#-aa)Rm+@oR3L>~b_&?J0ksnb zF{aeTA#D>muOZjO%-MuXx!$m(p7Fm({aK@aTHAXKgK^>mvI%kAsY{w@U zJGewQMaAvlB^wZ$+fw6Tg{F6jOFD(pCz_V}{U8OT?9k7gr_?`J{TIHRQjL?Tokj=> zyVpg01GqX2joE@)c(7(*clK&egiz|jX$)JL_vh~!IiAyn+z-N~o#q7Q=N^Rshk4du z)o?&60RVGZ-?fhYb*&m_)XGh%u1PWNnXAIBtACaa*YKGMCB9Wtb5Z{e%2WI=l>h&N zvhPH)u%4Nvk)e>i{r@BzqGY6G`o0T?0#HHzxnv|bQjq|Wk2~-J`jMF!w5eODs%QGV z@m3YxR>qb<`v$?2-_L&! zok;(~`xdaVvemOUbNJ^Ace4Li;yy}YQU+55=_{%ew`LWPK6STdiZrhYAR|5z7%US3 zGKxGL=sfmd)03$5V#Rr`rQiA6kD1bP5Yb(}9tAwc1_`mJ1`}(L$5tayjRtznKyy zjY=(kh3iu2$`Xe8Uo5<>gW!e%N256{=3bloDU-R5x81zn3Q&TAi*7q{)o0jjJX) z4+H|b1naay++%9rkeA(v!e!}834!aTKC zqVcQrkkBFJOH(hYl4yu;N7=D$4EP0Gg&WFQm(ILd+&iuj z(Kv)g=T98Ltj$LFQ4?0zc3GlK8?XbU`Ks6wDMQu?`r4U{r_DA`S_nZC2eE2*^3<%Z zlMwoCcbPf4VnF0R-W2n6;Kt|cOs!_th)ydxV48bSsrW`e6&55SVwsBJX0aPWfcLz_ zV5BLKvl=W4k%8K?7e;WlM5DR{UChskr@F4G2^&P--?YQ$L~!IB3v!t77Hf@n=$XX5DSA*8w)5UZOdT^nAUeyqGf_ijpXl#3N2Ce^#fN!@ zO8Obw>3}Vn?6h`v-yz3nrYu8J>7Va+rhCLF4gq<~*vKz-^LzIER1`TJ&(@QFHuZza zjk<;3DNBHs1ae1$G>#{DKwfzMOwKJCaYMD-u^>OBp~ zU1aMWlZ}DjseQPDhu!r3MEfi38^#d39?_~auGjQ-Va4dzx|x@Es)cGYH2`DHqDkC6 zI;sTZlI%Xi3}Ogf_)@k4#aJ;wC+I>56LMrvM}7mg(>|MH|0sfNEz21;eP>Xrz6V|X zcUOS_A6&t=aJ8e6fuo+j<-eSOloaPr|8I{A1Rjn;lC0>gew@v(A;t7KZma~SR!6hD zO2y?H!tgV1MvUZ6`_OAE=Lm`i1r0vFgNBhbT3Or4;9JeB%1)g<4TS>`eyFuWLT==i zh{bFw2b>4LoCCc#XA(Bh^+C4HK8@TaaCEwkS7Y8$%}e=0(ke;YB*=4o9!A!pa51Trx&NART*e zGi?abI0t<@b9zFc`ru;HSSpH11H;(m>t16`S#vux>99s)G(sR1TW>Qt`*ICqX$nFh zQc-zWLzoN#AVeT2AaJ@`I))mC8hW}PX3n5LbHQctMKk@NzSr}uK5nw|kox`aTmE)^ z{}#CT_Z|9wYp_YmX9}1~NMD<9qN>UACmATBa`aqlrd2WGMX>5r7-ZB)uQjI#EJQVi zcJ%-aO^uCR>bM2b-p8c{(Ts}2uosb1=oOCv-nTLK@0*)O5MrjodUfqj8xGz_ncLh) znx8LE&Af7c*w2c(cZM_xO$K5T8B0f!78ER%CKou=6(M-QEGSnvBgRhSKlAu?z1YX$ zC_pF@fD$1VhDjUMsEtk2z6UE<6)_@e0V;XSGo7K7hBifk1A9!^X$dhSf$)`5@Pn%m z`Z5DL-8c&4j!4CvEY+|Wv-ukHGYT_NQZHxInU>6{`2|0lr_G!Mo0^eDKSd%Qrw68u zuSmSAkv8!FFzcP9SK%(#v-hKzhBqZW{JET$=s#`8XChmHOqx-qDbQzZBAcia%Vl@x zooRwcjtUjsyx5<*M@PVbK$S5!-XkdGuVCT zf@8_(XsJ^O*3FXZ2C5(v;3br+keZMk#I{WXxJbP*#2Y6py_9g8bERvnY!eVRIcKkz#1EE-86^0mnVl07$Q&=*j^KD5=b{H8*nSJPLFGa@L+TbSW z3LKoNn2d7}ZIO?SS;{vQ+6vc@Oe{_kL>UYYL#~FBF%xX+da|_?S!v8As%ai$NMmUX zjS3XrXGod$ei7uE)PtyF0WO|* z6!BZDb_#+3J8a_k_!^vEkO9@1*DctD@sdqdBNr6ny*IP5g_2xBAfp;`gWB2&4Yx01 z^bwm+nF~wvrX!hBvoek)J#)6??=Wl`-Okc&rC^J@&Y}z{?HXxKW4Q|$Pl+FQnz_X- z&`geGA<(sC;e+&Y?9<}?CjQa*eyB8P0;A$Vj_OHy;Uc?EV_k5Gq5@EP-~dCbsv8SF zY-)!EYgg2^RyxelMLg#YTb7~>fLm4oJqI2qY-Tsdw{~pqA$n^8v}fSIvAVD4%wdra z>~m9Fjy1aKZwiPbEUPV+eLzF|`&!GA+X-yl8fEni+Tg0KGlQ1SZ zIz#BiPWKnVXjzyutFUVm?z><%0GN*yB+ghE~te=M-0@9FKPQk=IuH;E!@QdyUuw zuACj6AvcW?w=m~|=;;cs1dE0D$n+e>7g|>tpD?fI@U`W#FJ}2?(D~=&u}vu?3>H2{tb6OKd_}6Z<;j$ zt<^p?d)lwvwjX@(tdsrVZoBTyZDTD*JC#S-rcW<~Iz-mac=5Jxk8hu4=X@rMx?60l zQFEJLk5N7EQ1wDK~%d76hQEjq+r36IBk19)&7G^L@$i zp4D+6V1T==#v7;-X;!TV2fFvcqzZ}RQ=b=cjXD_H6Xj96Cnlykk1{=`C(f^UdA<7r z%q$t9ah1l~lE_onAb1%k_9T;4DxIWgm833#432r`c+At{m1&Hd>_xb2UUu}3$wINb z@#@g~$}z_Q{h(F_=GiEJdyU;GNU)AUf1EPsL7TTClq@s}WsxPL&C$ECsAzho^tPL0 z*@DVYbyehIi~rDeq%alI;8cfG+zHUBbVu_q*FMZxOu%BT2b_kJkLplfTa?uD*@m*4DnJYd34;S%btp|(`)t((9U5El-5$PDE7_@Oc-$UmcqK2~;$~B%PG&nF zGW#R{n25A-UO}5jS9EaUuwUajWiFVO46VOKH&xd(4foEVJgkR&ryKYQxYsLKJLS+b zG{H#7+Ui_)hH@++igfPx z)r5(KPN)EfXq<8X5fCjIYz%K9+~EtoGT zOr7*=hw5jkw8n>jlpcMV=Gy7MLG#kzg64nMtp6|8k~I6CDD^#`^`FH@rxKdHyJZQhQa z&M>XG^hHyX8)-CODNYk$g?Z+fHByk5YK_DA0_DmcDXJ2^C32dHuQVfB@=9(!$@K&2 z+NWvKChB=@KWGkfn~GbT9c+Pm##&;nLfW}G=qO>MBV8Qk52Pq{V zsuXsm9Y!O{jD{(%1kk>|Tv4nqxAKC(@$*Ax_?A(|J3!JWHtU$!2XohXsRkwdU_+qDV5b0%ZvYjiepZaOd#(?o#v_QfThvZNGDH9XWj(~I8H05UUH!YysCZN?1sH04tfqF^>PS9s1QMvFs;Eiq zuk6^0mM*Sn>r;89C?ftm1h&2kh=cT&49SyVOa$Yv^T$RI6thj|VnRdMODwmF&7PyS zysJe;ObSz%U|iD3uad1kqWZFtZB+5KRF=6Cy8ezMzCtXwV+^&{tH-lqkY1i!ud=ah zZ~=7vfDlQ)r@?03V&e=yc8D&udppbe=1IFu@-93TO|QNkfk^TJvb*_Ex8Rlf)%0^Z z;S~ho+38UFM;LvA!*%`X+_^y!XdZ({R*i&4%`aUEmsNz+h;28j0oCx?Uw;t)iZKi( z2z3I#_cQ#PukqjS9lY;d|L4Hq|7-XE+|z$reU!3=0-_3Z>KWOg!B1Zk_4qCekZEyA(fk;QAC1Y6)QyqW9Q0q?YWY~&Or8mo2q?z zmMRwWdH5DO&cJRiNw2P%7{1N5l5ft`jY_7Yvgjw!-9YlSgg?)em5Q%~((zzq*Nd$+D!5J`g<5cfBn^^|+T>695QUk%OI~CfN362*;PLP`=AWR}bai8i> zEinn{Cej3mj4lavb`|PJ6^J@CNo6!|sj5g=hDS3x=Ac#lYcAvtdbXi6Zx@h)@|tD~ zk?d!vAM$cX;>P`-TThWxS_-X*i`hoYz7R^ta;?+J5ZEkp$}XbvNl8QdveXaZO51|| zkhA=G2->4ndL_^B1mtJnoG?%E@W=+W>-6M&qa!8iHje?s z0d{bq4oj?*yOiEx)ju8h3?ZllF|yn&A;_?BW3(ylvfwrDo;2TFEi*;1ngvleC7%IB^;;4)mE*S{Z6M3DQUz?tBQWh}Bg=cZ9_Vk) zoaw6yOk_o^`N@I)PMsVUOMRS5HjLjP%`C-sUb;@b2vXQqFdY8ibffL!*X3J4i}z3k zAJe+9JgUYfhkrk*e-2UZc4Ee002fCK23=Fkv^}AAJE@M7^Ni)dzGuxFF^NH|0{pckJcMk6C4}oH^t= zuAwP7@CRzEOIVs$8iLC4oRUO7=<l^e|JXwpoM7d4Kp{`6zp`x234Q%Dvno2P@~zBm^*Ar zG-|SZOq>$E+R$gOVYnddA1tV>t6MfV`x=$|8@}tNz1ZH|+a#Y?Q0b~M{X#MOeIZuo zdHFt-Nk$~^pL1^REO&w}N+>rxceyLrM__Gl27Y%&()m6Ibj#FfP{PJHlUk*j)|*0Q zPugPiQM|~ekm6D}uS7#v#}PH<*9qe9Apfj5?T;S4ll`{{>i=}8dBsXe z0MWw*Z<|%DJF8SYRH*aPfHZn5(rP2|LHf&fG~DA@RL)wV#BYZ4O2{JpW8MRs+Mob3 zP{yj*mfKcZhfhZregyV6Ig2$+*=}zv)UP9A!m5DKYC~F)%HjR5um)rl}TA0Bekroo`V@heu=bo=aCeW+XnjaMF;lcdt-J^7Po^&G)|@;H9h z!3W9G8EF3xYMcO^F7zIVA)OdmV`B2r=nj8+bPM?WP<}RedmmYf5ANZvg%Jd0l~1hE3dkzeic(~2nb6H0tIx{5`0Q^RUW5Fuhrl@jiuB#i z;{m3jgFv&Xqj~)tKSuJgVXA%9|vn3{H z4ql)Hmx%`O=XIMm`Wu*4ZeHsH3%l?9vJ?NHBGx3!OYN>TZwyUxlMScWZrQ={2TY`l zG=&t2O5Q(w5cX8E^%6Y8fC3?`2)L{X1*D&8THzz9$men^M^=+P=A*bhcB4C^+>D@I)`y}|QU zrw#5QJYPtFqKQYOi4sCI<{}TIn3yW?S`ytj4vl?%tz;I=30lp+LWeZ^c;aDQoz zHJRlS7+I_r7GFW2<^Fo?U9chxLcuSj@FnurxiuVf1uKmurkZ=$H5AZ3`5$M({!3 z5F{Y*`npl9-^nyB^%4(m6oHSQe+r6ObYlo-pDW=S|8n8=u%>z{@2bKC`nvL+^wD_ji)A`?dekbIm0eKC9v=jTXSPy1m02v z13qnVA7z(Sp}o3R`US`AEKK^`B7B5K9>WFG&y+q`gMu9!`PA4n%dnFZBjMq2Rfe@L zE}Rs{hBOXiLuIES0}bNA7C43LP`huET8p391%+K5%>Z|(I9wz&X)+PQ9~ikfZTJ|g zsT^U`S)!&;1`V@a!Dn*iYlOpY zVgH%NWRb{8;f3=QimKhBtb_R$xoDpRLpy9UqZgp4UL%ik>0>HB0&5F4XF4m*=S;BX zx~9I#N`27&*#W%r8K#_JRKcWmvoJ+GW09d}1;Jpdt05e_H_kFMwm7xp!Ia7{T1J48 zn(6$w8?3B2$fK8rdo4pMBv$`oy`oHzFO^;ls<6!f52N`vQ%DYj!LoDa&%}e?Ag~pn znI{!cBiMu@SC5ny0Ws@nF`@P4n_MuRe(j(9%A|Zrmuu?W%LR)J(IMkk;?1T zq`^G1`-BFgcjW%uld&5uxhY`3gT}~g03lR(j>l%gykH@=b z8^ahqVIs=RYwkCtG({nkux3dULM|Tm;v{x|=DNYw{Gx~$2{dR@TOLT0I^L&syRJ)| zpDjB{%4Alk=S^N)OiZs6zNo%dg4OPoSy^@(^;c#@TWg@eL5ji6P>Ta8PWgc5O}V{+ zT1|`!j|Wa$9+D&pqvCdQpD5rx2ya?LC~|W#0)yA*rc;0?a@%a60Xrc7noII>V`^Ou zwFo}Zv)O&xz4gJf)P_ghn)BC$`E5f+NCJP{W4zZtN`8{`q@?}5t z+Zf+fg@Q@z0v2ns*eaIk>wC%+{HbM3dd1(4+RMW zCUX}zVZemav;Z2d0TVyXK7cN_&HZ)iD)ysbfY;^gN*$y3UF@7`x%Wm%gCB!_Jdr=K zgv{1OWpIaZ_y@hCR7Q_%k#5LyTE+K6K+E6g*k$J< zPCoKZcLceSv&!;3lUrbjbr>z5^R5M;@veEGv>)W72&S^oa&2?lP@O{P>R;)mH0J}# zCNs0WMfey+^tnVEBr%rP?9_83P3owSu$xlWb&q<19= zXDF15aZ{FMaM@qh*G{<9-ib=uZU0_M@r2SDtNnFvHNnK1%O|R77p=Ld<(8Jf5_Edn zA6^(<(^-%P!IKuZc&dq$1Qr;FSCEFQ4s@65N7XoK?6USp2cN%mkJMMa`wEQ9?6x)P z0O(-3h&5dflC%*nzBUB)6eMHR7%@A&1_{1m>->b?Q*@4n7vuPZBl{vn3liDLfO`sNV(Z0f`MLp!Oh{;(lSb8gd&J2~Q z4In%3SAUSaC8}z^CJI{oVvy>EoCL2mNX$>jO>LEYOxFAfw^{0rS_8Mm(yvVg4b$V&b4Vy3lFfjLnZn36J&s#w0oN9chUq1? zT=@R}iF8>42CATRfc7T4~|dL&vO-9-H&RHIdk zgR|s_q1eAbN$|DdXWR3plteyBRlog}=vGvYLI{HfcHA1G;*>wM%Fg4Tely*`y`|#)EmFKhjk7|X5 zMYyUM8_GSH{=O%G-_-lur>8%vYC9L`!Y_Lu*=Wn3E(N_f3kJQ0Xrk9rEH)WQsZ3jM zNVSZ1US(%xI|#HsXN`uvt7FTxFHTX5nr~a2ZESyLdP^%ARrj4fB@$aPdPQy?L32D& zZA_(Rt{48=zi-O{_~;3ANamjL9WjgAqJb#rEUbF~`zW&6=Y#oGTywaWp6EXNs(ch? z1M9smzV|BQ_j)|=c%#Fq7VQ&g-tGi2_{n>t>Z012nFCW8Il;QI&(TF-^`tnGXXlk^ciQG^Pt(nSO;%(AzfoAuKCLe1w>EcJs{14*~pzHJR^^hRq!|}m#tFcS7kerPJ=GT%_q)Tzx|oeio3$N zC1ixs?aQ2>7urZ_;I<;9qc62g_+343W4{~r~|e+^6iH~C8SYgos9=I1+c{FniKOgM!v4-eSzo?J{XP%H0u zQ5J-5pD>zXaeCU+(Ay0g6?c+`i@=Tw{#y)?tzdx1u;cO9a(-&!?k{z0V_9Tr=S znwxW-y4IsX50dJO%~ht$T?%s<1@lHi{@WWuMWUw!y1jEf2U1i>v#E8FDpPa6_VjNa zEy7PY-4tM*k3nV`Avuje`0rQqVgWeKKpX*y!ra`{8~CZ(bWMJ_)#F?+y{5E)H@Lg~ z1mQ2jv1DkhdS6-{-#a&rGFjh>+z+dgfitTx7%8h*8Q#-EJzjWcOuexm7My)k;0dft z>)tzEgt=G8>QI1~`PG)10MnxwrCe27HY{CVG6srJpL&z-ultK>VY5_twQ(Yb8YI-g zG&fU?k@WJxXaeF#eD=XK5^n1;1UIs(9;Hu!kv3crsrd(@mA{~!?sN&6y2Ovf@zjiY zQV93)kRKGY2_t3K7*C~XW&$B*WFp{a$KD7ZUN% z#lX$2?z16dX!80VDH6jCm$}GXZAn!+HvttbS2N`BTp0fO zi?qljwalhM*qIv}wk`Zpki_mb*}t2iqlqY>D6Kkh2&5O;d5 z+ZHZ!vBCNk_#vR|T*gwEQ39-rPX%H6q;w5WQd>-M*0=JRPp;$vnIP71h;L>j;}(pF zAmZjlDT|>ZQ}az})(JMIeKwK9(1ymTYxyzpzt_7F$TT;&5;PVxp_PiZ(eh6j=|M%4 zN+1&j&t`DYX%UlL=D+9hg56v!@{+&$C?0%`K3W}_)EJJ3-nRO+D&4HMj3{Viw!V&; zHw~8Lh)7i9uj#JMXeUD;4}OUlhRL)9XjE2h@#3BPdi)I=2_Gg`i?5>;eY*?jJ4AGf zi{pF%LD6{?9n^5U$P$9IX^BBq3x^CEjIS9wbxbLcq=F^H3@@hxsF~%^1xm?h$$WMJ zAy->G7x1TZpo8Q}5IX;j=ZaY8WX^_2tVujfBXt3K$Zz1(KoJWv+P-etHg%CThNPU* zhr21y8dApk^ptFzm^OEAY<>XA;@`{*vxJfl_T$#EJ2>UyLd?B8riP0PmN*Jpy zJ!J}>{lb&e%7YO4Ak;W)!T17wQ4XN)exy@gZFu;0Sy{sS!#+m6uB1^=Fc=8j-P8{8 zBSmHFUKqKko{SPSx!x4lZq>7oAZM2{L3j?~Akb5M90jaVt`NP6D1DhF9~%OP$1rNKNCs-IrU+`Anh zWG#_MQ-AS|e1U((C)c?d^!1);U}@=Rqn&+Ft98Xm$_sw|28QZSp}cntf&<|xptJP3 zDQd|^hq1<8pY8SRDQV9;{TJ1VlUL>VH-4SR5`NuZT)RWhGW z#G}bCf}iTIjx6Z@9}Mc*PK5; z%&k>rjNBPqUs>kGdf>Frid%Z$^y<4b=rkKmGTuYZH@|9i?uJI=?+wJfjqf_uV)S_-^#6h z=m&N3H{TLK^Fs^TblY_bp)u+#i0ab9X9X)isjQbA6nEvL2emhvJhEIVa%oXDuc?yn zxK=hyTum^g>(X&oH@8^(XyTbSRM8ORx@Rf|3=lhT{{%q2jw0W7-T>uTqkJaRn}a60 z@X)eK{J_1lh1}KKLrD`sBGHp)apl}$#%&(WG{T|kr<@e|{849j4Q;n6VUPnTObn&f z(+=zreJgc9W;UNbNx7knmnp`WVK&Pbh{u~$^lnJh&jGQ6r8~W&d0$pWgrlxEkWCDXHR{W4y zrMiAGsBMfxaHILSo5#{%Fxoh)cNe)siC~ig3@BR&8R*6YZa>c`ZoS=1S|s*6b?@3( z_7*!H!RGN{3G%owTx<}3aG!An<9d$$1TUtZnNaArDbsLTeF6a5z?394uY4Lind4S| z_M=1hO2#(p3`6H5B?PXmU41*<6lNz2*}3+?Z#ZIfRgLDDkM>+#6R`Pt>Yg%O_Rr6^ za;=&kd{EH`+le$73&Z&>E8n*1t_>?+=ySLxTA`jMneeeQoWS#bN#OIC2C-Tv{cv}YdPm#5iwUt7#_PobAdYctsowv&__SyvjsvDeRrs-F>l zGen}jFVcA_QRHz?nZw7lhg^E7afURDq$AP4s0d-?f4E0J_V~caUo(BaQAd}iLm88=3b+o4NRNxjNsYQN}fE8Q@GjmoP);F;S=VU5QJN&mm`+8 zW%T1JkaebH-bejCyLyk%V0+b0va&+}wi2ih+n0d;Nkss!oeF22#C9Bi$DKP>oE?#WQ=J%U~le}DSLJ9q@;l{|N= z_+q~LARH?!u&VQV4z`9Zvgo990dzsF5QJ$07eIm5IrFO{^yUbJvna3FE`b z*X?IdT`&~T`#IQCy9w?(|LZYV23GGd8PKVz%Lx?T1i=h7{(@HEZ>?hfI|eohYk*VB zzR)MHZ*pD6;G4hsz4Q6Fv%N&T#W(%uet^CGJide@w8vZC+?|6C6{~slJUcIRKL)*n zRT0byKWoMB#X;t^vZ3kS;O-HtCQRHc@a_rYea=QKO|V2>gnxO?$d^B=6v^;PrQ~8I z2a9HrGnM0;61}sALxE2F$n-Lde+Az7;>_(PRV4a5*gG!gh;o&#C>l2=k6klAM0`azV}QbyidJW|ek!C7B%3@eKfan^NBI}oV?uB(Z$SC0iT^8(K$vDEab|RWj-_i4x@Jh{q)fe zQ#Wf_XVt2(YVdQ}z!XWMaR27XbHu;ZHO8E{g*AAH0qdz>wu`0No&!FW}{^M?Bn z!SqDQxWB){G@#i6eLpFRht3-N;9Qiq(&v>6=$+RuBlxX@-@|W~3Ot|FqWM4&O6=T> zdF!-!$iPpFbF5uR1%-Aj(qCZ;>#4|YeuLMpIYYiPJ$loLXd&^*vbj~cg!d-cG8(>Zv;NE_W+#28p6%Bnuie*7i`G%@u+Y*4tGoF2(l#K$uDBObIjY_m_hJOz` zc(}t%120h9Xm``sm^teQz*DZ_!AP2Tf~HfGQNXKAN*(5!p)mk0c#gblw&Yhwhv1!g z&O1o?Cc%amXoxewEsn=KsBj`_ExKO+E17m}nw~T{4*5<@8A9t#YcEQ1KMvt-I4eg_ z^94ph29>Juy74*wVDOe5%-E&=A^%A4Hjxu62vu^~)l@>h#Zti~FvYaPHt8T-8)%yF zvyAXPt#`o>8N|bA<-zCpnP+LyL+owo!pNiyajgeg{KIL+hgpdMkMVfq(Q>Lfvj%v= z$?f*1SsgX7p~)*_UPI!ZQ_@Xn0NR`z&N8O`5zS?UNP8OsW=q`dSNLb&Tw8*uo7$)@ zTJ9ybkwJE|;OAJ7M?B;tgXpW__yl$Ts!8oGm!4>6Mg#4atK^bTXjWhRBL_1u4l}qp zb%Y{y^7^0Bfkd-8vryz)2v5aG$}6b~z4kI$Bc|w+h32&zej`hMWi5#m2~|JKt}G8} z$bX|uxq0y&tMNs?70fu|%Xot~c(mC)(^6^Aeg&x=J!Z!6m zy(RW?|65`cOv6}i6O1%nw)N>1%I&QsHtW)13CJfiG)Hi%gTe+R+EG_lD0gVhLFl=Fdl;?l z6wB2_Q3Lwyer9H711*{^r)H+Uq>sW^$_S3! zP6W4PVUDTxom_%>)?j7WDkZfN7&c@F9qE(~S(am-f4OoCwH*(LH4KXA;?N>?R&yH5n z*?S1ZRpwEx`B0wODbEEK>pjbS`gCq)&!kuQ2J@xX0nbcjmEMJT>4?Zk?q>$I~uo??A&Ulo!`E|U z$1(7+Pg`cgX*>i^GFY&oZkn8RWv<{@-LhpC%h2!~V+6`$kQ*i0{Lsxm(#20EQCuUo zW2w-9jfX|q>a|v78{Nq=!lkQ z7+x+VQB-D0aITwaS&oJKg#~rqOGhtEWY8_ELShgcLbn^?u-985sL`5yW4GBCx!ZA( z!q6`_r$&=-nI{`Vhk=xvx(3$>p<|9thSAsUt{5|E;Z$7;IY7ieAh{; ztl^}B=n_z&Z{fIS-{-+GDIg28zM}j+U)$MhaG#-Cs})n{A>X@BRac{W=|vG0{=_^y zJVb$py@_0kdd&%Kt8Y|f3v<_0M#qa{E86nmv*T~7z{26-O=@ogZw=Rp@3Xi;u8z{w zQktO4I!M8AVLF;Vdo7P1OZ^rhX{=~8207zk_i;`23aODK{Ch8GObzMxhQUn2IdbiL zC2g5xJMZvo-0m(__=h`X=(D1b;~4NNX}X?<$#evx7o<1bE_a;^pe!YWdzCSZ7T%Vn zb{Bh(Wxb9!LOAzqw&nBz48pcS<3WO?Dak?EeYqD;4xhU#UqDyv_9x8q+BdjeYbe_b zi*3!Q^0$5j_0uC)$Y08?vq4-RBiG-(Dg~xP&&^OFjOOpTs&=rXX!H-=nt^s7NPn*X z>^Wa5{C3fG@okHdYPHo$e9aZx8F@C9Z3c0f?M58BM#^wX7+@7YlFY~XMG8O%H20$W zSHK*)K}^Mp%lM=(o=E6|UUf0>r@teVv_bMh?0Wxw6tM+oR}uxT`k9BtP&sp#S0n+y z25c1``#fiT1R-L?_4bV6nM8FCZK6Bon~evm<|rw#n1YiZ`d!>zU?mXjP{4eAZq zT)%Z5&;wz=BOEAFaRY9C_c0#gW5G@W42$Em9fUO5g$LxzSp(@U{B{(T0{ya~hXv^z zZrSd#;F(zb*cgGEK_)iD;Y;uPHrqsICppMG{>D3C@CvM>h7f(GYPY@o@@Wax?i*8w z%%Jg0?=NhB#}0)-R6C@5yWoY@Y2421gYieJ#%?@&(32&;B+j82&!iW-j*;6Fts5Kz z;>%w66W63uRxCL)=@Q~bOfyRlcx^cw_RJ-a&Yog?g268!1KR$RwlhfC zg=uW%mskT#V*RUs8r2Nj7}M{sGh)*9eQ2M#Mdu6zwUnXV=+lJE5&d07!S<_T2lZ(* z_4=E$e5+G=0S@sM+^Rj=I~x8xsHz|Q2z#CY)*U~iz@9&ISREaxY6r91MSpbbqSPl> zM`(75(hdc8j%rb)$a;Ki_uDf;lX2VQ;&u7rbgJlEQPk!yUz;Pb*F=y?F66o{4vsMx z48x=Er8tTXFCHZznVjVD9O(NL1Yl2cQ=_F4?Cvdx7;eTVEzGfo{q3M9CCPT7r;Zhr z1WEc*R+Rfm3xQq{X*h==D5VyDY~qsR>1F{^z`5+Lx2TE}*jW3{io}d>in<@?e-gJP zrpF}!zLb|wzRECvO7WfCaZZ~oVZ z#4iKDzdHQ>GI6Ahi0VJ~ef{`4SNz??fAiY}3?06RZc3(x&i^Vj8A@>?c7M^+DMBXE z6KAG=06zjIM2tlEO=pi0z&jsk?ENNt`^G)e5;MJ|w|UXI{`m0R#=WH*L9H8OK;G12 zAXWzyL?de`w6^82bT3sdN+Bh5H)L2<<3ehv3w-fK+vnp}!Bs`H z3@@^viz0~++t!ruuD@gh)-IQAtKS6X9}bB;X*m6ZzyA5P{&L9ZKOFLxZpXi$xrDW@ zfvJ`8|8SBDR8&_+R7U!U3MCo{R(tQswn3krrMMKBi`WkWv5m(fNMvDfRJjxVQ=5!_=X0 zk(8XA>GT~Z8n37S<)N8N_&(>M8-+S9#}zWUju^g~@aDI_sv4No&YZt44+afG zMG+t`H9-&8JB-#7LUD&3h{CH5bsmDr5|xC=5){CvzCx`ExnBuAs!9JdEQycc++cjC z?s$d1nlk9!?_4(EE>&?Zwg};eKu8ix^n8HND$}{IZuh~ zuyV<(n}?=N@2DF%u;n4mF|$%tJw?+LxlzUV*J$!W)Sz+$QHSoenH8L!5sX)+T0KQ5 zDYk}YmxUQ@7J~JWIN#G2d{5hWI?HI;@coQLhN~v9^H!1#{a`RvVf3H6lKZ zvAfAJS08Yae}>tW^!neHrBfv)(&z zi3NKZZdkzHnGsgaA z;SAAWN=@H>;)tzAyg~z9nCnZZaWt(v1;ZOd9Ffy0J3_+b6wXD5Ty@zqNkdw)=mCTx zS{ExqN%y0|wmbP1RfhD9_?D}#vcq%MLLEIx&SL`@x1QNOO@_882TRx5iFC>e@2WY6 zn)+sM4;R;qe~|d<(caZDK<5%Mr&k*CI~p@@j@ALv6xP%}w(dqgeumw#Yce90TBzNH6JYiCL9uzAAg9*QX(XPBWnJn`?}&3wy&bR_Xdgc}JaVa+Qwn zPJI5)9ux_Vs@iXV>UdPqi}Y20iFay#=|%k&1L-n@|CaZV|Ctmltc|UyjZKa0A06sz zBoy>x^qwaAzX3t(tbHrO=%U2ac?Jxi^!|9$MFY;)Ir0Ytg?R&&`$YfnFa6X(fg}Ae z&^6H6(whPx`@Rnj8WjkYheeNriGpQu0GDLPN~^1j817RS9}={k4`|u3BTA2firUgd z&fk{9GWjT;Rvtyz46SxwQ3-qL3uBxJRbn%Z3|{CXZpvZNBkVV^~vM{Q7d zqc^Z@s#Sm4%7|tVFcx0&AfNf8%*6_O@uR4^o!UtAWQH<%Rh>!lea&vSkhe{Xz_mG< zIP}7Hok^0$!}@;QTE4QH8irHlQG24_O+6RTpXtw3+MuGWdi&**zQ2j({xfq>{L^c4 zh8BP2jz8Pw|Hvi(kGdKe|EJt?(5K`Y3!M|c7@3Tk3BKid!U96GV4{pbbp=6enOy5C zOZnDNV=QdQpkKPe_fXKST)293L_RE_pX?jU-kq#xFR#%wn=*s&QRolEu1E$}al)}8 zYd;Aho=HOnPzlCCTw}na9|)$q(X6DOKrezgFxsnw5x0%mPN3AizmeNgKt-YgkV&DR zG}#a5-0#NH=H{F7_;*h|_=#j3F7n4}TFt@r_8BK*HoM*DM{}~oY96-JKZ&$ItX*^cum?!DU#-u zInz3XA2k_#e@mNFV3UQ~IdF1RG1QBSfnb#5YN-)jZLlYxCYB7BmeX8mm*M&yWdv^q zNhb^B-oEwcc~-O`qmyYCMhFC{cy#yz%DF~e#F^M7NHf>0Ff?%`^u9$`-aI9cieNhB zFM9`(My0$3e)QZQFr*|dn9j5V%iG`>odMtS`yo*OtskZ}HW7(@P> zc>T35*#Q1LTDZ`lOHV7nRs433XqC3FWoFDsce^-QN%U^jWY^bCuL7YbMF`srWyInWddWOe=wHVomaU=lCF4_j#&&gg>5eOV zZG6WXNm(dGhdC-mAA6^pt$|F_B#KDgb{~lc%`?V%&-c-3_V+pxlY}qwc0DVi?x7cY zqPfQaIIcEKKUhU^*UQ%M9yp2@UA3@$;7Jmt7N{|2|&YTk2X^{5`%R>BAX3O?>pC!z2kB2f1KXBhmizBPGkI|sury;Nsio3A_5zpfLO zQtS{tJV+VIeHG7Oeu06BI=O)t0F=P^cq%|M)w;0(F#+q58{<8IE~K`IRG$4EzUW2= z_g);^dg0)@vQCb=Ehi^xrw_HR@a;@~{(oqr|6k$5iVBB+T=ro5|m!67VJ2mKBJgnf?{ zM(b`K1HiP2==y*&a1B_3<@)3HKysa>Ud_RYH+CPt;6tT#_@ zeDMl6;r1*nSD~@c8FbVAqV-YJ`}6t!n<=A>cuoUqtJBgQ;bP;P(c&%t=pr6a(c@U? zvV(;4lE=(uJxFd)gOA&y(G#byL*oLX4D&DSav!KUETjzhl#`{ZM&!tsq~Deg*y1@$ z*C0i+44&#M!csrh8UcOn4g*f8d_8z7F<+Y44d%|xNDdGJn`X~qLl2u*&g12j+p5Q| zQ{duO@2-iUXTPhC)(RzIa)GIKu2eZjH7}Frgvh}h(%nwNA+TW>h0Cb-AS3{>+ zac0XJAzOUJVC-8+bF%pq{JV957=aF?Eb131wh&NmQU>?GPw0{dBPF@OBhH3a@Ju}Z zrsQK=5N9S``HsGcb0N3rS5VOPR+_ILlx$GGA#3JlaQQ}k=bZn&wF>na@HCdnnkk#7 za+t-JPrb*Q%?M5;Yeg1-vJL?FMwEAGe!FzqOb%j1;vKOLcXyIC%j}F24>#NP+rH{Z z1(t9er4kq!FY!x|o`u0l+cm-NS^gWez4IKbj5eg~B4T^q1;4lb6Th2$Fmj_6(MMl7 z=B11U?I$D(GHoPX+x5p)P6e8EY_&Wim%b{Eae*LyCAUSh%#P~brXs;DdT0IG_X_~S zOz~+R;M0W1V^^@uYmlrPtL9oCW2|v|O5G5{h#Ehza@)n|_=zLc$U)|AWQ|CYuXbBC z@&&U#>04-G|zvZSmH*dzSDipf`b_%-2v{P(8>oPVq-_lx7BxG>INS0 z)GbSjz@9xu!xdM?K;`m*HRQksBRAP8I&65KT>NbC{6k3sq3RihAu-G#We_An_O1fDxFXJ%7_$A%xi9E`^VzUM0>cZJ)wS(<(|56?8G?4K&l&Rsn)^~4l$AerlO8Ov z7q+MP;b3#5yU#|aSoj#C3G!JQZX>2i#ITS|#tOq(Bc@f3z-Xhu!|p_7h!jKZ!ZW1k zKoeM%6y3Xf^l^%Ln*B#S z5;n-44*g0u0RLw&{;$)-pD@N(Bk`XVqQ4zSmH*&yB7a<-p=+riAfN+=grrC?BSq5V ziQ$>xfg`~|tJsQY=?obVPvr5Kmm^m;I%<IW{RXwG?K|jOf!xqSV}|liuG^AV5$T9NsBnFlx?VE;gMAYaOSOWOaN6 zA1?}0U`bNLh$@mSqZhO;URGU94|z-rRp^s=(IG{0WLl@0+EF&0?5?75pR{L?@w} zOC=5+(Ut4PBExH~MnG3jwO&6XK?z)NEu7Fm$zjg%M-S(L>$QM$Caf?5t@(mRI=wyyjTCNwpZaVPuaqMCRgbd3 zVL7tLaFmTiicZc#Sc#ObLl2a*5w8l`#Su(3eLP4}h%yY8WQfCsVS0}ZZw|HTLlB}a z!eFp|z1HFMa5#ujPTlgz8n_o$v?<8iRR|`Lu+An3#n_K)D+Ux*8Us$*?UL_!SWrpv zZz-Yi$NCYWQ)Xx~hP(-wbm{?zH5fganUb>ggAs)f{vO>UOc6Y%S>f`1*Yc?|^V^WAP2ggCFZ&38f-{dqGc5(tR_CQRB_bw@z)M{{sO5kHgN-E3h$=jY6UE< z{dulV`M&)sL=~z%5`!X8Nh(arfi-;|qWN%{?5Lb?w{6-qyKf8RH`m|1aPpNP|T78KAJZb^WT_}W`qDs?ud_%3qrp91X&zM1B8}7#*mw_sU)-vDo!JJ1Fv7ZrWxsQ74;`ac1#VunzsGhD@3iNe9Y7auY*DJb4*_qOig`+A&xEP+N`)h&S*!an!DgfL^40jQU%)DX#4*wAl2 z5&7#3Ce{y!1n$Apx;Kzj`>I3gA#-x;T8$x1=^3j<-z0yaaSxVV(}$^EH7*9`5wZta zWJFT(x@102B>34E!&oiIUz;!2odzSqB^Dms{>i|SUfEO!fCe2;A*qQB zKUO;q(Vx(~Z+4@f0$l8W(C`GljQFEdc<7)%L4J@^zfp0wKXW__!>B@U{eF8Q`JiIg ziiM}Ut!lpEt;051Ez(`)l@hmRnXY9ckeq}Mg@s=QrR`rUN?fM{g^Wr)j;tRgw;uwY zI?>VEucxh3w>35Nov3^>OVLIq>+PgGq;i|L0W7{fQzD!bak}y3q8wZA{Z-aiEw+DV zBPyO-o(Rlu$L}w+@1vetIyCH;)Iq-HwB{_CfQx^A+o193hr}osFEH2m~PI%v?CtLx|jS&UXil8 z1YNx!rMPVWgjRHZsF3OxeJLyT;Mf!(ox5BKnzS!oa&n zCoXJGXq)ZCIo}6w9$9d>pjTX44ZE1B^Gn${f;*a)tTevYxZmA`6*lZCJ4t}%vUYsFvJpQYIIo3=NL z3bqX^VAVRh#vHQ~q6aU*>-dUS8E$0lTZVo+S9}MslzvlR=x6k>3E<*wJR-4)SOnB&!*>%~MYkZH>}MGnDV-I^o3%V)5E>x#H%2CIyGqN3Hn) z+Yk!_Ysn{DEGa_#xh?8k3TGBSOdUx8>Dms$h-`E~XPh0f~Rog{{ z?aD4p?CoO5x@nG>CfUV)`)kYHnmklGUsDLlbr-#vk1t$nct_*4fv=Og@5MMnQ%K!o ze2V|Dl(!TMX%qK*mmI>@k%6@gQoo1Yd3VC!1+{41h!MVDr0?Jk-~gD!QH61#f4VJ% z-cUn-^rDx(Y=9k4KAJWrSmF;S7uP9;g|73g`4I6ng{)u$Gy7 zkT0eUCigNC$r6|k=JO>nh$};HM_|KJ&w8`%<9UezhTl=|^wP*fO{8guf7*p!-lb9h zT5pgy4MkD5qyhV^6OH)^*TT$uLyP|ceM3`xb#QyhIe=MPd>YOSkLA|(SiphLN>ctB zbGn_!Xm9b7c+T40F7}T|10ZG!L7w%y(Oj$%(HHE<#*xB;+KjO>4MCcYJBzX^Y25ep zJdO;CykITp%4{!|gk<;N*@1+!dmc`qcfPE{o5>mE33N}=M0?-Ov@m^_Fe{ldzK^qw zy2oA}A>?Ev4225RJkSws@%oGg)D?q*5{0gtD9q)E@xN^2FwvndpuUKV;kyF$va@ z#F*tbYa!AfH)=DN%?%Dyg*z}^ji_`yD3;FJ?VhT)b-!_lG2-aEyJWa<4D5b_ZwO@> z7_aq)cgwFmLosm-5^lSix%gse6$B-_sBnzG)5P;vZ+Uc#7~No0?XYhObxd?Vf}md$ z$9jijXb;p=a(BN=c*43(40r-9ldQ{6ZwNVN#FZ-%Qp-c1xV-$trH+h`PonJO;Ej3#E1d|WMeQEe4|R4?S4Ih(ut{Bu<4*oA^OqbfH`@ON?%@3s-1#4B!heaJ zO9_FL{!8RMZ>FPTj^Iy)^TW4{jJdtIH-i6`I;YHGVF&z@I+vywfEV$kBlIr_DuPwf zG!-?9>NM9fwK9{{6E*V6V*0zpxj$SOup1tyMHrL>6eSd1*HF(;*GLzL9$gKfC@~1k zpSWGW{rzdo*MBenTK_wAMesjaC+BGOcfn0dnQkfnFW`;}3}scVv6Ak32O4$+)Wr;n z2rZ77$DPT%-4xHjROfn^;|ahk!4?<6yrFnGb!^Q2m5Xb0Lw5@%8EVm$kYQgjG9m9q zPPV)yR#u53w-tJTcH)`h5rVpTW9J8|xnZvk8qqO_Ch?>f7L6VV3Oy9AxGDwpd>CpZ z?KiP#Hf>tie8aQ&mD#cvoCH!WvRd7g)@d(^yfO(Z+@96MtXWpiR{ZQ^uGqH8Lg@RYy6vixw! zTdijbtwJ!Dh(D+~!ExRIK1gkysK9op#}3^Yths(~aBuB?j|Tw3kK*g&cL5_f!zYp` zs;@wpB&ZDBC@5bb{nbkRG^;8Fb}+1HCwfGapmZKL)o!{FM>~>`)SK!6~ctvLmwB5H~-~)Jg}qepJ_7?Wx+$*8qDj z2^#N`*!-2q0DjcS&Od7jr@N}@uU{@S`I`&>2{z;ZXUEz*e|4xhn$qyGzvs6gxCg2I-Qh?v7z(A)+EB4 z57!gmn{1&oF|R-wVDEd1{RF3d_Q!{-0Lgvzn8S}Gnk>H4Tb&1NWreTe|l<4OCM z#M(tT1-t;?qhG$1cF+KSl#HV$9j$Li+zQZZu57JU>6{1^BJ6GexP8@(TfA_?M#gob z3`^_6fd&RL{eHUMmUGX_0DHzbGrl*R^AG&y+T{n?J_UGJiPtMy)h@J=06B5fXZH4^ zp*;l$f&nEpThhEHk%UU&@eZcpO;>jf&t%D@fY;4hiHV&(J|}P{r>Eb@Z#Av;DsEo5 z5UwgjE}Ds21EqJh7XKe-?;PFfmUWF*Y}>Z&q+;8)Rk3Z`wv&oev2ELSQZaANIo+dg z_j%v`?svyX{(Z)8?6vk@m~+h~O{X99{oL@LhehCqcrsq@Lut|BIj9XslIW?6x#k@o z(VS9|*$u?)n)6xZT!tN0Zwh^jkoU)h!$Xkek~w$o{BmpGcvPPf_GqV4)+DtlujpD< zpJ;TT8+D}81G~n#(H<((qncNhydl_`jG=cZmicmJILlBq$0R2&$D$lu>0cKF4(VJq z=F75W|ArL(-&vROACN+}wa`0BcVsVxEgLbjDYn+I+BMNeyngad?vNO-A9MYQ2 zx#;W^%q2Bw$9w)++MYrzWU7JWQanRJn5PLI?kW_2q7Vl7NM1@m$?Z+A- z#X&Li$=Xm z+4cc6uV%`;u&?4uTcxUNj56KFosiOb92ZZZ_>$1Gif+~Hj@+3vuo2_fH*0Am+t>N| zmSNZ1CJSTe-Qv?dy#g67(qX|&k{D&t4FswC$K!vM10U%2Wyk3MYR7-+=lu`2^e-z0 zsXl9BEurwh0W)Eau?|ODgCvxO?fI%14et)JM*(1=iEbl<)5@GV#)6t-GYEG zlKgZ#+xy-n62)?-3>Qz9KN12&l{P ztn1!u_Ap}|g3aW$1w~E+G3ztZV?W#lmZPZ(3viItH~CIe%XoRRrjOFlLE3;VG(F{1 zEkbj}@!J=Z{Y?&iTRd6(ipz)J8VNRL=k6%2wWCUdE3VTQnu<-WB2rPb#;oQROWl&U z&on^6iYA@D*!pnQN8zeWC{=)z1A|hk#XI52<#my*uuPZF7J_Z#lA=zGvZ*Sg*^2Nb z>A==xPD>3{2t;F#l?*0yOExUbQ+jBvEa!bNfU4ESv#D_oqEVG`j@G36q^OkQIDI!A zK|ggVHzSvHBGV?+Q16s=ZrDhN+f#-{3=54?Fo6jFJ74M z@^uBOZ`Zlf9B_C}RK8&oG~X+gvr#0((K{H$?tp74CP5k|6AY+Iy3$7P-eZE&lm866 z!>YYtd?Yl!q!HCzA$+$H6_~XRRaR3K>ap_!MLqt>P;^vpoC(-QdqU;25pV+RPC1+T?uVt7J@_c*| z$+&7td=+-8Lh0VmkdSsP@8zzc$}o25Xsyc=$TaH!`WsMVmcemJY}wqyn7)b@>3uz- z*}Sx8jpUgQLn@OazOne=5V>8k&&!^8q3D;J$d@?$m%0wh{%PA-#czW4C0#c>(L}8@ zCPf?4z{l5$qfqf`6KJL^JHaR4uD4jJ_@wb=8F0M26yARM;Rkp#Z5LK0I*O*7MU9B;4D&{VDsYul7a2I(mH%X1r+_jO&qEoV)DylU_k_B(9*)M0qGx&mLheCf{X6T(#d z>Ad?Ib|;YYX8HUp*}>je3dR`wLnd{NKbkQS#${~W*iA0nj%nSIPk0J*JHBW#rNc@Z zYl%{OFGA=sLrn8vh(}&6mb;B5>~AbG1Yh>cTlfo6$4NK?lyoTVrO3XYL-H(sy{zQ zq3QZC!6+rzH+rtRV^6BsPmA^>{2WZ5_HpIT0f9;yx&A{nYk)NakaKDRM*03r!0IrT zaKk8e)$fwj<5`nxngDD%zMROKy)-0uQh~NKyG?lyi0)(t!q~Li=mWuPQ0P?po`i3M zgrvb-5-pa5Z-=YFJi_foz7)R{1xyG%TSGmPuNMJtcQ|+<*(Gm){KRtee-5bTj<{f# zQtj~Ow|;*2D(v(|xC)zJqTTHg^U^~&>NpZ8?Bv(%4>1PDiF*O$)tQkal*pQw15^<7 z&Ux%aBOI+0A%>SPSDFt!EgL=x*!=A&bg!f&OOl^_eJvEAG4?6!>5h<-BC<+kkrbsz ze7pkg{yhM9I@gq_Ww(hIu~4EiP}CT(ORn2cwvMx^9ol&Z@a$e$<-%^0#gC@a5QsG| zF6Dr}dVp2pB6nWK(Gac1N18owqdk(vF!l5MHzaJ)z06gkJvpZ zikD%me%o8;8n@e*edtl}?u{isi$H-9N_U8j_~z+e+A|`~DIq0hZ!Pj1-kQgc?Ab}; zyid_J-A9ZDe4FbH68?y~0_o)aI=C1>TQ zc}4KmlcKBhuJAc8g0~F>U$!geluq{|q7J*83jiP8?!i%Cms;-?VtkynaQjQ(5^l!x z(OAxC*%CKX-*UvBjvAL|{lU+N*^8VTG>e7p8Xb>!7@s4q@fw|)onCJ0j>o?U_L&#I zAnU$n2q^ze1^GYIIQ+jQ>4LUSHeZAoIei;rtAE6Q6>~={Rg4Zp^<-w;mFNU^J8QC& zU7_R+b|~{zcInV&kud6#+Py_dlzzgg)zEJ1ZB z>y;FRCi`u+Od!6e5r9h%retGHSYAJgbErnkl9MZz1a;G^pANQ}Fsllsvj()P@jXXYRh zfp{U(I(wmjvZaPn{7$;8`s8Ma=o>GQ8(s;OBo8J z$YoSJch1Gzk{wE|s$B`K0)lTWzLe+0orZ}7p-xhe=A}-_eGMEo7_HXOM;9mUd$Rm$ zg@!z)mdCw~l#iE-+rm-bR|z2?) zd4G=+b3`eG4$!#^)4X58_A*}Uo$zUM;gYo@%qhlIg)i4T)j(@u&4M4yDU_Bx`5sBI zNn&9FO-3bhAJ#xnhmW;1XV_{SZmX(hEt?+Mw0QhdwzfC;p#k_-#GhuJ){H;g|&0t3{9>M;yz5Q|6!qyPYOa z;)j1Y+qMjfsoms8;S{a)Ed37kfE#K`v? z92JnO0#x<30;3xf?IRgCs3>SRDx0aMbQi0rt>dKnbK0(L_-{Dl-55;zvi4G~&z)cE z)M^culWk0dIyWkIdF4eqC}<}wT-p2qBraV@956Tc#5N@Z0)_G|UAu_9VvV)M$Y7XQ z%q?Aq5qx63Q{(d02Q9mT;r56GK4#)GyYU>1@J!#Am~KWYi*}GEA7tZC3)5sQpBjjs zpq-@BCW)P-gDs!1dFkdmw--s8nd!Hs)I+=aCwl?&a|;YkLaS|H;%Dggs3>s<3>!#f zltD5mFN{O`Q=SVw3R3biR&^Gk0(vm^ebiZo?i{o87BDqxNXMw%5M{#v9~wZV=@o)Z zSK7dLSmm!kz=Q*-pngWIG_)4qA0~+R3^^FtxzY6YCLrz#8?35}D)$@~@z&;3T0Eg< ztKLX^dVDQsR`GhG#i6#wkfB`0DDSo+8NS*BqwEYp>(4_;&#P?ZQ?P@eV@z*-cU2D@ zziWuglWe2BP$ROpnJn=3&wLoS$b6@#PUYLqyG*g+GI3YE+m*-u!ZxC z8*5m_#VEoKnj7kZ_{sKdRQFj+fqgLqZHApUM*8Vv85R1<1KQFXz6fDf@Yj zs0)Bc3h8U#POxt#4t{sf%^(){Z}#&WCDo+`meOotY>dZiTil^=bnuXz0Y8gs>t1}- z4*SL)U5(^#2$W9lM+o=T-zXFddNR;^lf-nZuD&l zwqU~TVR8#Jh(5ogJMY?kWOvgdBlJ2PcSF5-$C-BZZ&i5ubPSff>$=`_?&Z9_ zLwQ`=o)7rc%9aT?D}=nW3tO@b6}6!%-VJw%b)2<2FM(Iic8j zAhdFkwzdmPIrBtGA*iI3gsxPBv{!|;wPjPs*`pXjw?r3e#YDCEsq*zxJxss#ai5E% z+X-RT^>K`|2#sIrL)YOGM7oSFEB6zPM-7NrEXh+fg}$PPUvVN^!8V~@e|Pv<<@?A2 z#-@sP4FJ0d$UBd{uA$i7hy4b^Es&?tUBW((dcAU}SFh5I)|WNWLx`*Ee87tcwB8TR zE+Z;(JdEVHEY3+J;Snrm6#0lTD8I@pmJwps*fJpei%z9g7+QB=33wp0mH|Q`0 z+AtqtbUiYxbLbqI$(b`PiD71o*n?qa(a2;_h>wWOU@#fvCLXVQ2?N%@!j}4g(&mc{ zelL**7&&ihgiI$5I~-Qx+k2aov43L<&ORvA6%^f?B!i(FjfjePqyb4pcY^B}*fvmP z(Mv-$twhlgkZMXIkWipZSPc4m)(8ZOq_VzHz^oAp3eC>E-56j?y&LZ6Mqw`|;)!D* zh|pWPpGx@6=3f3NmDqhn{-UU0RZ{f5(@}};89}3bKcx13+@c*gjDGZb9x+>^_f^oi z{XOZLG|W^7wMOF34DE`zODGVSQ*(qr=&Tq6UC}rUiM$8oTC}cWc%>bh1H>o3P4^Y= zkM;v##mEvP__uG*aR06M%=fqaL&(@f|7$(e-v<4NzsP@vmcllU_HGKsHeYiJ|0L^X zDQ$gixr6^eUFBkzB@a@eQsReS^H&m%lIxYMtu3AjjOV?x_NZ)W>9D*6+wR&==={DL zaI^BY72Kl=9~Ehjq>YJyT5d`x04?$7H&`=PO3{tFxR63#?(btczq7cE3eGV-acDkpJehdhm2>^mcH(SQ4 z=!dZVa&gKvYrnO2f}z)f2CuX`W~-Byl~gjJZ8<}FA*k-1+m@Se_kMcf%087rZJ8V+ z1&1LAoJ3^r!m`BCC{+v$=E$I6nM-M=_C`iQNLd)v3H2RlxQdb^u|d$n?_{&*xiban zR~n2B(u`{i>qjH%^s>_}^jil*MD4j*$UZPzyb18qcgG#GjbM`SZnZp^wa-vPl&UD*i4Rw!$n*%8Z*LW*lK!UuKr% z*h7AP>dau`%Q78CB)ra~XQPjhrq1<$T@Giue2@pjXlx2CY6(ZY)aS6t6WRoMp);!z zBSWyHa*Rh#8lrq>fELK^$7C^A81G|$B;qDDM_2{V-liD*YdS)$TMu3TtC6PnUkR(< z|1Z5+$zI>k_zwh2+Scfw*>;xFn!=Ym^CSQx?gmQ=w1jH`OR@ zkz(lSuP9x}_}0B4`gEh=HAo~-mfZrqVRn7LSkV>?k1&3Y9lw)$Jee!;czB(v+1ehm zu4EWLSC!H(yfEBYuR1;<=`2u&uFXFY8Q7K7nkKFJy*C4shXTh+Q#I_+O0zghVguZR z4*JkYbkQFrONVO3Pn+K}Fg4wtFeh!pB;+v5p^eZQH~BlCT(jPhs|3jp1k{Hx%@o{- zT!tS$j~)=5sUar@LV%!Ih&3(6rb=IEx;PhNg629eAWz!FLz#p6hovGFy4E2L8Vga4 zdTT>RpYQTq*qqkoCkXz-C@tC;DBpgu8Zxw9{sF4FS>ceoehztpCe-I%K`t6kyaS$K zf=%)h1ke~GFoc<)Pah7>Fzm7sIeKrdBd!VfiWd8cadI#=RxjaUeYCT)JQGT!KC_fU zBvZe$V}$8waqhgcNzA%iSRR*MoWWuolV72dHi<>AG)hNm7;OaT5_K?a1YUB?Q@*|{ z;xgoHogKou{xOebCe|-?-fdE4VVq2Z>mVY6bwe>Nh4Fy|>*h7M-qbLc+PYCrj8zc z=Xx$k5h9~$(9G8qu~e$sNp}w)R`D=}xzL4w7b@ZHKkiEEgv!(1uR-R~BDJF}YaEz-~x{t@GpYeH7K25@Yj#r^G9TQoqcX^S5}oW*FZUuf^t`gqVTDwQ$XP)`~uVZcUl!Pv_4=j43e~wR{M%< zdpoqdOWhq&@mmIeTw6Wt$8E1$JNI1Mu;4pYo@qrX+oJr(cNT69j~G@rPWb^X6j|N5 z*1OB4n0hHM8Owx3aS|@!WhC@G7V&xGMFO;6I*F$!CKc8M)9pgA zd0T(Pn$+6TAM{^LW1N56+4!HeF7^NC+xb`Bo26u_I41|s(+r|00H2tm3?SbRXrbh( z&@U>Pr^dgk!T*jp3gS;-7e9YGb)9n@i7IM>-NmsNW51qJ2vEp*8nS+Lxl(WXc=#GK zr3*g*!flGaS((~e!Ku8VRdZ~SUSp2ZH(}N)U+b3M)Kv0;b7=>WLfh$oYU6e1ohn7~OO#UO-4L=s$_*f@&P z@I843I4F;&B*U|_uCezbzscZ7Z~;d}B?igF;s7tZl|7qd2tnLyTO#?-y2*{i#`{^u zU*hNPh(x%2$`!2^uGvcX1dIOQt?1F%+jMy$`ny*GuqawpZ~11H#@2Oq)qa)E&Zt;FYzm}e9PBvEg{QDVzsCyh3E;eB zxt?taKJ)K`305)fD+eXOkXdLmomgygU8vJ76~3IOAQAQ$EH!U$rI!i|e!d!2G$di5 zP&C{yVZRCaiFi4UWFN#NsM;a^h^p4Zvz}syRt8Vu8uQ2!0#(}HoJ21jQ~=D_x)YCH zA&lqP!av6h%@m-Hfng*LI?Ho?X|pd)$oE~Q;X%-%ys@?0%V$1imKsZ|9)&u52~RYe z0GHVFS{wX5JU=o9W8Yu7b}aK2k>6W2I07(q(@P~Zj*)q2=WgiON)G#UBS1TZpHcjI%@ND`${e9bAJZ#@wPCLG3G}!dA)NxA6X>YfZ=?4Z z%+W{C#1X7xj4PDRcJGPxg*RVQ>s(Lo`B<+(aAi;qreK#`qfeM&$fD&uBQjxX0n;XY zqb*j1&kl5!Stg+cBeTR`XMmbCZUB41GG$Xh>(48p|G4EHFeFkO)!8?Ql%lMTE zg~yVc1{!xM?iRN%Vg(5IEwBbONEBvbV4%VcnQV=m20ts4F+XVB@y}Wg|_& z6RO=dj@NkJEua}p0q&bY63B0qf`QCo+Y~|QCC?ZJe1AgBI8`dVu3tBr;;V!8zcUwz z|8}GQkv4u2L;etl_$SI7C9f%q`L$zIWEy3iQoyoG0ay^3{^B%4JYz7>RWg)x;F`A^ z0$M%9h^~~cLcBs8?+?&^FU^nlxUV=vYSOrCER9Ka$_Fp57tIPPQKVKS4sDa1Cp5{0 zFbNOrj%g7`m~80r0!&9WRmKDSt z5_=qqT1XH@<#DAZ$>>QMf395 z7!4McDOFHLuc(MwyMIX=vf60L)T)!^QoM@@$oN#9$yx-3oQzWi&Q-~U@I5tMPzU-R zx(mCn;ZUKp3>2L;PZmro z$Li;#^iF6&$l9qki2&6pGTY=K2B6;)HzNjNmMQgu)z&39zDa|dc$FV@sqMmPd_yWF z-DzVpj$3;`qJAu%nPu2^%*z9Vww0R&PbzzfWbE~rmWu0AeMUL*b>}o=6a@zAiahwA ze@>i2vE!D+e*u&S{}rI*{6E?FA141JjS@7rvigtWK-p3eOBvl8wpqGKb5&rD6@(f* z8J@Q6!JiZbMPqed4w+t~-KG~pyLDu+r@J?Gw27~BW>(9wBu-1k$k zH2o=#D>u5SFVdsi@1?D-cR!o)T`oT^F8+yIrp;{SHQ37WI`b7jswIDonRpMR3B#V- zHxlzT%ep2K?Gp=lz&)R)*3Cb+}l7|S2(12zB!vyKULTr7Tmz2br-V-UwlA=PIs zaUxq@5vi!at%{1me%U0Zl9-_c)dgTjz`IR`HWbQJ-EJfo0$trf{>llm0T$w|SSBOM zl<|tJ7x^a|r|ZZMPg69q+d4a+#4?3wC@+!Lh_4prqRCz`DIf-Gv$}QCG1*{>ia|b3 z0{WBPC|V0~-7J2R$pYDBLI{UVRT9ukAk~d~E3w(K^eh8A^a%w%NjK?tncXx@G0*d9 z2;^1fLBAplR)-pdY_3`K4xG?o>i* z+1V{nPBV#A!~!b~J@Sm4-9-7i!#WxP!i0rcs(e;& zz`BA#d~wUA-uD!T;bW^C&B~}NAxCg6n+oX!Vj$a{Cdx@171hfW=lLtgDAHl@umR&kAd6L)7A$ePsJn5v!fTBAQfGjJyM; zoZ+shCpN=gTir+DxrCi&DwPM#3wD^Dh{vig(T28a_rvE{#t$q~li+I#8!XFt6(H_? z>7AK|)*!|%DjXH(+`7ZOV+keQw~Iv+k|Qsn(lULFThoSfn$DvDB|+r%R9rleq)Kk$ zOJYN$wsmQWOi>UGL>4N3N~%1pot?PRQO1%{-8~QbY$cW8)HUTeGKk`OeV;6NEa#9~ zUIVfHTlNhC)=q4R#VPyU(+Gp!1Fnv)MBGx@&RzkB1<>@)z4vl+jdH)q?P(6f zG=td1WTzsD-4Q!NQYRlK-ojQYljkvA>;2kRQdc{&qR94!&|h&@Oh=XxHu?HzyZb_l}Hf(7;-LLjYQr#@)+|mr{tA8N_^Id`ph^;%nSCP5VYK z{zT!QwTmxn2spPsv5io&Ny&Kru1U|akiExx+7h7+TYJTTSF8~>YhLT>%h=R=2Z!&r zhH}|tzJ_y2eI7W#-3@i=jnF_RGz;Cd(b=Rs3G(N(Txz4rX^s& z`x{sNHH6F!0chkXt7c)100a6Wvxsvy9tSR8H|O|zvK0jv9Nb?VK1;JVA5Fx-AsRCK zh<|TBUb=L>($M*QI$X&r<)U?gpKFY-nviDeFkC!WV&E-GQ=MV%se6nvtN6nM#tD0= z$7r_l;B~RLnT;F!m%=Zrd)my3ncjw!12-hbFdGyz0m2X=?gyLVcHyJFf>4nYojNXF3AP_fB{^l{n-&H z4-Z4)j!XnLBewWkWDt&48pl9exK=z@zP0Ivg}I;zReG6X8gs3G*l-DT5cYf)UP!EN zjp(OzSaprjZl5EL5Lh3d>1i?(UN5ho3Eb4!sL&vZnGfNP-vyi@9VbY7I3Tutay3^I zK`kse@LZ%{H=sP8`9zYze9$Gm0sHX&+>hR$sZMjXqDh5G34L;g9 z&=|=qHp}9DEbI8NA$Gv`fcK8I-a}(oppA=Ia5w717(^ySu4A<2$?CYFG z`ov>4`lu^tR&ZeRyQKJ0G{1JFq6~gh^QLiUq~JJkilYmrNqa+H&`81b2eZ6LFOdV`%@&7VzJ|2!BSh9uPgaG5k*AW zo$)~V9)+qdqYCz8I;8_{L?x4q+&NacA0lRUcPKF@C47Dur8W%O3?UjF1amUYCH^1> zxS7u;V={R^eimDus|YJBa?>brcKHDCa*Opr%QFC|ojQKzZUkCnu;~wiNONu~Ib-)g zVgId^LZ7A)Qf*N`1>F4Z%Q}N6SaXcov}R)-K}8zF!rw1uVxwh<-`L945ys(5MD0H4 ze%LLF>C9RS!W13mPlRzS)l&b$2&5nr&qMmXk$!b*sZZT|dxuwd$6S$1(4-^LC`Mw< zZojB)dMd5L&uPL&Ca->kE_EWym&$|*DNZDe4P%WM+uhuAN{5_A?jz-sN(!j1Rb|V{t16jm z3&;8gdb*Q4|MQr@^NDYr#gI^~S^Mx*7CE+dlAF<6@+%O^R(-|Tb}$2dm9nQpzKC@q z%I_nZ&29;rL2SCd1G0l}f$g#cpRQ-WF?QW)n0cFTF0yTz<~qW~9(%Y#owtUfPcF9* zIwDm3l+QZ@oI9JghBi-*flv^vQQ!`ziBc%-+4rq+(sTx9uw{muv5v{w0B$*gHrS&C+W}+@;QQDk7&M~xxXD&Iv<|v?WY0)r2p;hi?Z&t5 zM0zpE8t?a9C554}W3wI5vCN>}Ms@X?JC?{qJytJwPriNh-l^Hbs@fbuG%9?Xwhj&O z#G=j1zRchVc(g;8Jlepmyy6aYo=wl2GZDJR&L$h>RpK9__K|=b&zmH3R6+nQZ*>qu z*@df6qeXJm=&{U>gQHuHfa2|zu9jHJdaNb?J%ei=?pSGHp6E*_H0QH@xZHCr*}*fT zYVTUVjb9F{P0&^mX$|^1QU@<;s?#qc@xZDrJRRzCO)J~X$a1ygg)#)zaxjO!|Aijx zk-hCj)s8D9{&I3FA89Miqs}46_=?QD>lh!Z!(veM3ljc`{>Rs>zu^IMsKB2upgc#A z0CnHlQlI&HC=V_U0$|90%I043+6U79t$eao4(XQgDiGQXJ#p1I*osq0AYjU zs~06H1W{-qge!$A$6=0d2h$hwx3A9Y!@2|#;UIz(0zkRq17gHdn@OwnBE<~{{!ox7 zlbkVa&VI0qBBatAqf^T7nCK@@2uKW~ zq}ezB7&D<1-k+tu{Ruv1!espQIX8_$V??5FepJY3lRWGF(4pDbWVi~_x8`QP_PGU$gpf98lm=Rxn zI{jxL8DSj6PGP=GexWd;R@#?ktN#3!1pXm<@o9Npx-?_;aAI1kd8!FgoMip5)&`4K z{fGpnRlOWs)U=gA0=ggdf+7)1#vM5oIk$0fY2wfE?_vC>#1b0B@(;O-J3pcc>GenH zmGXNhdZ{yl5+kV?4{UalCzQg!ym((9A$h`N^y_oK8^p#;xKEjv1=q|OX{r>zrzuYB zFe=V-!X|RFj7N~0FZ{|yt-R4G0M`Nwq$~?U-^soxG$SC{3zrgh{oq;M^5KCNyzQT`{-PxeS+w}BsyYFdBD6rY%`y>0MzjFp7`SLiO|LSpn9|ZWz z$>nXsvhw8aPzqUygP3q=i4Y*_Y>EWqZ2?^N&YnL|FN$;HJc(vba75CXjAg zQXQKldmF?L2Zx4ikd!f}PL$BevvthKYgmj+`~d$U!bUkaxZM8rntS}$qxjcY$v@fF ze;tLb<-g8g-vnMSb$FcqY>hhj6Pk>6^W}OcU{@AZ1QgT+6bBUl+XxqZ*~AH(5qEAk zqok?I>a7<<@gwnbv)d-`FFk>viH4;$*SXek4{dL?a7HztukZr~F4UZqqx$vpl)wJ} z6^{P1L;m--LC)UR)ZW;^K|uc>(nwD6nqO!u^3dlTRMFZ+5Gv&~q_CfjYThPGPb#^e znqm}0F6Xh+1ubH&xHPBODq^UDoU_S5pN}9uS*4o?4`yN@mS|3#K zufFa^<2An84Sv05K1f^qmaDE>A<#(uhiT3x86t<*jZ~Hqdb^(_fn?~*wAwnWLhb{x z%o;qw^To|mPDb=)1R&C)m`LixxlG8QT9;yypdZCYrPp;cr{zM{XF^Sa8^O_l;h4`U z=;emOR_=X7QwP=Kx#O{qzt$gs@xbYRJYrA|N-KPkxGhnF(4d_GAiw zNn#qidbL(&*oe@_%EJoDqbnoPA%16+{sdkZ;`wj`s8UE zR3p?IoAKH!qlYg0lw$$4QbW>1sW_gQ%y0K&zMq+a~l6F{{z{Qq#pF&-#T`1|gXfh#G8EI7Htk zh-5<v-YNQ2)yo!_(cd=#$G9im5XdLh-cw$>o1=WaYv`Y zK9>%I3|N&tOwnue364m;J2WYeexpv%$}6j$B~QOA)zI%05o#T6_9fHjb#j+zQxbGT zjnDr4v-KMjhTW_4^{62KSEv>DZ<*5OUcq@P6a+Q0tcIGbj%Jr zGZxGbbp@v7Dw*{ANZ-5?vH3-?0G?74U396zff!@n`?8M^dusLrw)Z!_@)8G<0cTum zUh>w}jkJ}GU*4}%y0-9rEb}0=+}6$1UB@_TRVHhcDxPz;9>ELo5a532ioesIxg$}p zln)%bjKtgGzDwaZTCY>s^3r}OZ-9uvB&jpQy%~&{KaT;9EYKM8gu_TsMhhpllVTAJ}tr73d=yQkbDH(fj@u z&+H2f7J6bWQ>u-dc+inFF6whCQ2J-+a|jXkpH;7ixwDGsZ{gQAm$!#}OpiLKu5Cq~^39>?mon z;j+Gk=&GvMekn1RQgNHs&{x`x4TAM<+=vgaOlLVAC%Z!lNyfHJW)()2{}Xrr^BZN) zlDyOm;}ujSOHtRwDA}x&ae=}6WO1E)CtHb=rEC-Tn7RCL$dg#qsiDlRBe$O{2qsePF)ShcB5XGJjqVA4mIv;%+RYvuk zjeKvQH>2jgGhRk{bJcX>s1{}?zqs3xruSMxwka!+VU9uxs?;-9_1TXe2G+_Qez8v; zCo1-#+KNT*&=;{hoj$mB7ae-K2l?ir5e?{F20G6H^EM~-y2L0^52lXl)UqRNG#Flo zQ`%da5*xx#xSyWz;_!YYZQK=I&s}*uQZfC54NGEOLZsY-1%?m8-&h8Yz{I>Ro#uzt&TdSX+nqw^er%jAfe^#;%vBkzW>VpDcplW$BtAH@AUY z44wz`iry|%;V+?d;aM%xi6q`~trSYp?by?!%Rw8E2|JLWJ32^hY(cmshop=}j&M)k z@}Osga$gLirH?z^U=k2z+sf948*Lw5d}A2d{0D%32v zVe)Q5oEJJj&BzraAV=}{hj7cWqBZH|^xIhZLU!b6o~H4p@s!<77fT4!{dT;w9WK|O ze?LC6*)IXO&eH2 z3@4*XtGD>^wOWv-q3J5z+vN{25ek-kgxT+Lo-O^U*jy;v%l(UD%(jP78q;SgAVzugc!xidjM?d;64yLjoW0JK$e+$ znnPo-U(a#u&Kd7@$rm1R8D9JD6SY&Ss5!DZ9z2^^xne+?03)=<)H-V$I~4D8QoVXt zKe17=^#<&yO}yx^7d3~11#LOUO+D>OBjL#Znp&@H%V|ydf_EVPEhGBRl!N?l@A&^@ z?!R92q(2*^$RD6cpaMe9p)J135SGYG{*p}Lh^#`IL%rmJZr}h`kOjzj3SWP{$@lFE@;Cxf?Dz#j*rf^hvK39>ast*3PT#>B zjnY zZZOC!h&N5Gxgbo-nO}jea-_Tw{k+Pl^r&wN&h=BWw-`WLb*jjeOvynhO^o5G9KcXP zJc^>2bhBf?H*5Y&MP1h*FFs)<6AdaQ3BrUZy`+?pA&*puHq$Cu?zJ<~;A=P-X{$=c zG;Y>~fRwR4p9{5`pN2nkHcDFvnfqxMN89#(O`L>yYb=`owz1w?e;0p_IY)?F1B&t1{LL2L- zKh7DG$q{sx`or%ujLU8y0_-7(Vw-5}_BG2>*?Vi1aD4a`I((-_2PkprP~Wmfv3R1# z#Io^ns9?7Zgv{N{UUNI~-9TkEx8LE?4?m}gpb!RqTWW;S6MxPaRZ*6C3riMB@0iTv zv1t+qwBJ)a#J6Kn0{%GNSSdk+GgMQ03Jo0WtsBM|btPVdnrli9kDB2NxVI+=j9A`p z3e@k@>t?AapS?&cbVE)NK<_igeELPRN4b$b>nPiVWGU3VXpwE$QFTLK&5w}St_UF6 zcF^>lmMj;tq-2=Qe0(GFtcf6x*1c@nQXW^_tk-?8%}typ>4&Crr`rAQd0`~S%-pa8(77CnN>lK1WPhhvz7Om`^W4(7B#HE43+U`!w^899>Wq1>?Bn zjMGYn8k5?-r*V)@8cd0GmvcHFj^U^HTQU@$o{^?{Ki;FI3DOXpoa?7nD zSoU1xJ;3g*yK;F021%@Nj+_-i+kA@65j39GMbvWBhb+Oh#!PWA<)_SbLN?y)L+zU< zgG8uSvB5N^Wzf_zGQqR5fm9Lp9|@ihJ~?57UVF{eYo!m#u21&@!!#mB$JRIKe31Ka4CdXMU(ahpX)0beEq<(zk zz4DCh%+_?K-Va=npjcJ;2JG+bHOy}4kK3k(^HVO8G@0SK0Ej`T9$ePOShLL?{V39M48OOcR-Q3pNbVl}nr;lz zx-pw?=B_z+G#R=MgvkwYHlZMh5_gnoY8rS|&VU1QagySLTYLAl$J3{9yU+mG$=H}{ zkW*rzQOzz(3A64HR`x1dC`p|rMZd+=_64kJBiwJvU2-^FqKg|868SWTpNM!Iu;IFR zdq^e3yc2Pm_hJ$}*Hgde+~c>ssC*?Ix{Elr72w$MJHJL0iC_`5iEU8M4kEU$tr2c# zUd=r$gl7^xj)k8l-MnM)ur*;pLh4Wdq#$pYagI`dB^!GGwnpVYBhcT$xj!P%SDqng z`!xvV>iAdeQI76_1>i>xnri%D5g?g4w(8;bRmj(f!++7QVX+)1ZDVp}4FbECGYA>A zwz)l6zsg>Ey%F+-;0)A1jjYRWp-5mSY0_G5Wcod>*0}~6IxT&m3`rwRsPdW!M*;)h zk-%JQlC$-bmSQNdhyCRw`d9lk&DfOg4)r<$C&XHi(&~ZMlM%Yx)%&BmQ2Ea>Y7-u! z2DY>@xOTa8i1$wsMIR-+Jb%hJrSd?`)9=5q%#s7AZ?P}_#3+k4`GK3i!tCLHt^M); z$3Xmb3^rft$PE7oz)F^X6#qPe5m0A(wZm=O6$WkKMNb0!a*#>sA~3Puc&EsyDH}$3 z@IG;awxpTSDFbmTs$5e9|0pzy-eC0%X;CO}|++z`*cLyf8(RRz=?rwaGOCKW0RQ{fM?m}DT9Xsy~A4eMOkRb_z~W?Vy=8Gdbjz(%(hP8_Txx_-h9gZ`T+MZZun z+HXy$uvEo37ecqiH~2hFt|wysYu$7ZRhDoxS1M!N;D$=aTi3#C!lE>Wkc`-U-A|>C z6UBq96jQz624b(R-z?Y@?qNhB97y%UpCoI})1a43cOZ;fs#jFKVaQc!@h?_zH^cov z+&0ooQ$Ou`m_LgUqRCv#iwo%bEqk2_buEmrr!a@b;~@l8tooT*qmN+Z=*;$M=x!_O z%&16+HRw&0`O4K5WO@+z@qxzUs(0~g=dzV{iQ3RkQN>@AwLM~Bh9Ob}lbd$(00Xpu$CiPPBuv7H#T1o@dP z$lj?I7_gjCiSV5@!E=_(_y{fJEnh=0M(u4f9LChI82%EpAzf35Zt;bv>~i+q1)G*9c%8{zhe7GTg%nswl?akSHSRv zwEXXFt-m)Q|8c|rbZz>7vdU00w)#70U0W&g^miL&O50yFadNUXoTnt6cKJMK_pT?+X2}r z;!qt?Ns&9FIko#ven;2Hks=aQ$*!dJ7L`i4(U*b3Q1#jUm}<{irxtBF~*f7RZ8o ztqb;K;l*a)gfJ_ZB!@dNLmkKJ!HghIh=j+|Hsmo6(O13qSJcF7zM zE34;_n{_0WyBnFeX;nr0TubCz`8R9@ATg`awJ%C+rfM}|a55c-%xB9#%E@r$p8rHN zFcnnsV!uj=UtcEv|7+fVJY7z)TQ-RD@Pl0d=e^D-LNwESALjCYBF!Ch4Xl3f zhqQMH6SQ5j04q`HN@rHuwr$(CZQHhO+qP}nwvEaA_wAm=JaZS_i*NNUPrQK>5hrjz zJ^F5O*iuC;8=0{M>va*y%acd_8cC)NyNL3`hWCiIppcC@h%CbDzl*%|fs8A%e&5vy zsW5&FIuyrd-LUX%zE$P&mKgphalw9oql=2DUl3h^tn_(er@P=x?I}FV8?yA|lW#Ej z8q^6DN#Z^on{w;k*j%>e#d&DpHpz`96|mlqIipq_=C zW!iW4+A}hK1|8ehkQ_X^z;+`=?6aKp-C$B5#2oGncNZTUCM?`~jk+UTa;Cnm+4Dv! zn`d91D0>tDy*YtJatlPmWPMsw{EoBCC&Gf{3?{C6CRMw#v~%ox1^w46*VhK6X!$XN z+y8?Z{9BR6QBL!p2-d8r(Nhf2@G+X$G$%x?Uiiq;p}EW`35m_{ctqfWsUM z>lKI3vw}*2L3WhpZ2|kf=Y>Q)WwJ~h;r2H%(HRO?w4<3y4A&9Z^Mpw8Bv7B4#=>rZ z%&C{;L`WnS*j{5&8*@OU60JeI@XgvhJyC-CdM7Nv)lYKqXIH<=5B@AbtpedICG*+U zsq77*)N)|nH|=3TVx2|WO)0N|{DO!aHqw!@-Z7GH18Wrd^)Z9sYg3V>Nz2>ws{Mt9p^Qw z9H;RPYubPseg7wcLegTE7)Q4lZv0~1XYwY%_rwEWl^7PpYZblZ)z{FqsVgMp?)J2x z@;G$2YZojLjIhSlU=?_Al_9Yy_+yI4O>+yE?SM;AmZuC3~Lw9}D>WKUe_$fBE^qAH}I3O(IU_O2zfM z3w3gF50U()6G9Ta7(X5eGLHx$bh`m18{m_%nvAWzh{t_x)6XAD@~GD5dLbI9+l_L61;e)bT!C5dNS zo_ho7x3zKxRQz(XnYdGEA#nY+QolWDT=hsadma%j&et~5Ml+gy8QLFrPzNVTx(IeF zb}R+2hhCT#jz}aIqCXetF9469f>%&JmVCU+ujy1R*g3f((Kru#nRY@Z50h@IA3H24 zwa;E7%sj(4-W%o|0N5VR(i1vbIXFln3L1VPZLcX`$BpP1%cxF)D~!XG^lc1?>$nKs z{>Qa!0_#-!)so*}+_LE%DcqM%=A9S-6i{Ir* znavrD73xboFe4v7&KwkMi|YJ3@CVb*{{yBB|Ance?0>O<&d%pV>9Yluo^{Zp0h1t4_=Vi!Ar1dc1R~)lQCv)P(jRBJPi1m@Uwicr5qscR zMAeBDd);XY`%AoQCKhbhk;vJ8o~-StE zG*rPZCx`_aEP29M64ke|6(e!-5;&D9WW%8-CcL29L0vl z#7~t`F9`r0PP=3Y2Rjevp<)96jS9?B_7=+XXB?}kM)HO&o&tJ7*)lEh7%6xNn^z;H z0BMXs7Cen&6F_<-g;tA&s?S4l|CYA?<*&+-M_|7Fl;zfVWVXxdi%Yn2q`!K_)%K7s=#INo5x(+Qsm8$vzyRlfHpXFX5X=#E6qPnV&EjCxD6w9!dCsEu` z-ag9+p@57z4p-Z4)1gRRoI8ybHy`%gvG%+CC=kz^e{`K+22~v_cn{{? zmqV4GUaibd74~b4cL__0)1yOml2?fWXp0JWF6Hb6glR#Up74MFLL^`qpv5U9=(icQ zd%4VM8tn}0GDVQ8J3wpe%ymy%SP$-ug9)0~q$gr4ZR$<9YWc~8LG-lnFhxUhhaoZC ziVTksHfQu)B5|wGLH^=7rt0o`%M+4&W6G0B>8J4~HXWo+8tuFIqb&zb$tShy*XE;0 z?ox)nKXFq@w^Dg%h2u`r=mBR9V|ME;zEF-g5!x%*$nt|2D^BP<)wFQ*7wW^OgjQH( zhW9)rGZ@6ir^+Dd%R13^jMF4?LGv%!LmY$D`rJFLx2q4?#JV6VGS^JjU0($fZZ6uO zhLchGvZ2QhyKhA7cR~l^K*A6<&kOg%!yM{h{*M4*(6Pl|u z|8<`lD$r}jEs-14`UqW=H5<-fl&bG_*p3JkPEB58Gh+4b zCW*F8^{&!5;z1=3yoZ1Pwruq!@0LNHyE8)=@7BwTfHW?88RT+(!60{zE0?Y%O1$j? z5&Pqjp;0UhgdX4lTj|?w8Ozfx<+UC_YPclO7`oX%hfFK5M+Jg}t{>(PJ}9Wx8hjrX zY&bYv2A@-M(JzaYQ?+m#e}{=hw!LqB7#tHOA+njzgoN+{$7CkZOUAf@TM8(GsJ_lT!YF@xHGuJCijVTc! zCRoENb+Qm50OVewF|ZNGG1(+_POqOsD7k>{G686AoQsbsc`ec5>+A0)!&o5nh_HWD z$XQ}4{ZjFWbXYpXxX_0!FDRz#|6HumgOQ}7+3qsdHCUd65aV*6KXpo2ml$+1S?SO4 zNj6_!Bu;W#Xe0L-;Lv(;iTbT(YAj<=yG4JI$Mm+1egr<^Y2}2Fc+57eKBfR*87Xh4 zQC7ZFJQZ8b9;_8Ayue*#7VnmPrFH`v-&;=40j@MX^P&itJ$p*u`>G`-ov6@jBcUH; zH75QjV-^|nAqi4kU>7!IP4QKI541lujm~x_Hry-c+BIMoic~0B=LP;R#1S}q`}2Py zL+$?|GO+wRGRXZvtq7iDW0BX(1=0YV3z*=P$`UR)siHN}Dhx^C{CHP1hf)}b2 zS>lL&-Qr{HM<;sKx!Dq8&tZx3`I#v!;j5a4!FMA@HIt{a;Li?kYr@AB+X5WuT?oNT z?F!BNg_iix>X|4cjCF8~`v(%5j=)!&&c}~$Wu?oax)8S;Fj@M}Ar8&HIZ~GDz{T|! zZJt$}#Rj=_zwmU4!U9lf1zw!4~jTKzS=LUMCjw$D#-< zP6`QEC@&c};q0bsNByP!oh7RMwt$=HXQZX9N3f@NmWK$Rj91+Hyu!X$&xAFqsI2@y;>6IRepB3KQ;$Byh|$Q!S1WAef1{2EXf_>j?MmGOEd?DB zrNamvuoea0{zb~g;X7S3q}{G#T=`|>%u28ND*jVemzT7j#an~?%ttfaesL(=2Z zY$yy~1@fLOLE%jO0UNo&)|(Bu?RKL>Y~tLo4-JPr$5qD8)rA!JR!dtvt_KD14J>S) zf~l(^7M-eeMF?@BBGp)FN#fvr(ehS#P)*|3{#8Qqf)Ik=`q)Bihl~>HV+Q|uEUcCq z4VB>h2nasQML;B=Mz5NF!^k47@gB#Dd+(h6Go~FB#pLUWz<5MIHoOw7?a})O^vX3& zw-!gkpX2-Jm?J(=bIpj_Ey~=fKd|2a5OMB%LxC_q4?FYc`~N56{$mT_-vmseyr%V> z%+Eq54SO3Nx|gMWx^_v=hRz8F#JwH?5rM#8RW!maj5Abnr^-`P!Y>L0!TrEwt(W|W zYtj}f*$5_9&f`zFtm8}9_s`+vY7sr4Xp|(-Tys!E)`m?llVq3xsI0&$@(&M1ApI2V zo92!Sn`UjVHFPlYnHYnSL9N6|_ox|~ej6f|I>Ro$noH9b#~_E}OmvLUo~DvKU3n~U zRZ0nJ(ln^jqGvH00!YDmpQwl^#3{5Hnsgz+d#Kf>%P`_y+n-~#Vz8wa?#Rv(SLvZ>|WkH>0Ynt&wEh zgc1@*l?)aqB_LxkB%SG*8!N5N=lt_XU~-y*zn&u>c`+jY7GPoeiI2P`%-TvKE;s>p zjFAbomiWv;H8W)cmkJ(M@GU>+B#vEkgG&ChXTYVI$s*Lk*q2!=8|q11?2gY75o#|0 z&Ou!ESB3xYpAHT}9cMfoU$+OV7~xU9SdFr;f8t5=5l8~fdUi2g1=joh6VD??W10Zoe#t)3`Ac5)sg~( zko%3^ecpLltAK}jg`&>JM;Z4SuEtxRpU=b60W?2%OUD(r@zh zrSfuo!8{f7tqvsm*QPnwE5quFaRpFJs>&?%ml4s}z%{i5+d?_?!!KLJ1F|lcla%4I zC=lGvgHmr;+AhVVVfTmwsWI}2pe>FKWyS_ZUYr}Qk&r?dTCw255p zLuAx-?U=7UaP4b5Tn^B8nQKC^2MPtN+9%R&F$@bbkH-;uEjETYv zg?ctGEg%^54O%TaTMrlvS8Q&Xr`&xjGE3&yIyDwakaqLu+*2CB(#2g}gZw+2zzC5N zjTipAiFeS3*;2S78xtq}xHYO>MFH>{E<}@N?ns1HjX0utsc_1N9&f$rI$zU^hB*A&w2=ilkcKlwP!>#8Ywp;(y`b63| ziY6tCweRK_hjwaOMCOKxCmOi0V2(D7*6TiaVjtw}k3V8r%$Hy9b;?_q`k-{m1crXl z4dm)1Dl`x^k*mp|moCHEGV>&$mPn&7OnXINPW@M2i7ntx%Z&iM z@Gwy-0M?o>ffgB;r!WjR0>R9(@bLMgfxMo7_L9D7OA2B3Iz*z?ZH9t9Jm9s@bW*ZO z1>wt{+wh5fQtA*cxA#ly{ag9xv`oEV7=RHtQY^t-%26?xJ<6Y3=xcC-&UigdK9`sy zRlMg!dhK`Owkwr@lXUW@w>}ipn%;5}|K_pgE2sWi2$ z%pAsW*qrBrFeTjoM9M^#h{1o6BUS$~1^$mN>%WPwe`Bk!$E>^^smzh>B)$> zcwr4Vz?5V^vyDY;xKn*o7Jl5~H3}Xl`m){%w^JyvVeK><(VWK{_Sg5_!Q3Od=-H^q z?xk@=3;d;2@~B#1mQ!+t0&?bVI#7pL*f%xPi-s<1r=cS*BeWGQRM=@UPyuwix&{Un zYI5kj3NZUn*b|8hjUbXHhLJC0G92BqM`9?baQf2lR@n>8b)@N*K_9XkNKmbjlTN>| zTZy-GOw;deYs{3#lBEo z0v0mwVvg&9MOoS|9IHV_f@I>uv{7`1b;1ndT`&tx4+Ad(7`7|4OMNnnJyvR`v^l1P z@vm}wXHGE~0tl{W_7aCd)u*7BV#qYC@O?tdKdXFc@5f?rutu&bZ;138k*hdfl#(|!%xnRaNNlC4Rgq<6ZY*JtzgyuHRM$& z$fMid@7SpuY#Cy54m5(|=5S7hdulByv`@vf<1@yE6`2OMK^um!!Cfp#M*bhwcR{+e zEyP7E7dIsEa7?FIs57RgNRz%KM!H>yofsgcPNeHaYffa-Bg#uyw073Cg5h-DTa{BJ zhCeAUWzI4ia`7JLrSLM(EOjWUNohyaPQ{Ewk?rNRagU{YS zg+o5zB~i!^s`dYSRR2v{dAUwzw?Vs)sqqvO`UcFQ5!c=5oJYqaWoTF9!vNo zPb@B`h&X>*OAfO@4>+>aaG9uqIBS829uutH_uR*y?~i|MEp#(;Z4k&xH+4uB6-hRe zz#d#n5^l&J5mESWgSKsxVH(M=0_Ls?6*#S37WSLfUPuQ}` zs{@lX&sLHZoO@)-gqkfHP~rbn6Qk@cMmG72N*KoY?CSuIGU%n~jxZI%8}H`ee;{8! zlrk+pv~_GBburwsq|(5fCXbjVvWaG3t!<)tQs+1a(Urbizv}O+dydO?Al^05X`0|5 zE%)`-!F2~9fe=;1n9%Sa^+A4CvBV0wKP9(WwxMLmBQU&ifC>0uwg~|Ks{EN~X8L_U zc#93Tk&4i)=axy zTYJl^=V;c()=aVRD?WhKz5ITuOX4Ic@N@IM>ghN>JsV_Pu@PRF{R+?O|RAkk@ z;kDN2EX8MxaM-MtJ)4rd4Eu|5%CeaHG4qyvk&0eVguAnpShj=;{Ko4BZ(Or$F1_9M zVFnJdFPRg^EfGvHhs|ae;@FyyXZ^%#_{=efcTi+6z01NO48X9Cp*;kvirqR#3m2z( zdoG>%`m6_^A@6^AT%_svlz+X=>i<2e|E}pBV>Hcw6rh5(5iFH2n}pI;;!Wm(sq=7E zsmZ|$1=UDI)Xi?ZG>VM|Ci<=_=CYASKo9b`ak$A2CIm*!OrPxVS6=BOm93n;&X3f@EJ6fDI{_J%BAnf zn4WF+ITap0Rc?Rp1 zWY-Yfwc~C#S7rch3H;D^?oQo}Ht9AMW!klgErgF2J5*)WZE-?9JV5BENhz8#DX@J5 z2K75^50Vx4qOSXU^SgdBv)>JQmOoP_M4nS3F_x>T@}2SmR)mdsRfEqIrO=k7o5Z~9 zpm=}3q8!s4V3RWhx-``Sa$9A+#+m!?*OHL3{KnQqIbTe{Pw zSuQ+}aQ{MnTkyyXM3}i)ny6d8uJ~+Af_>`vz9tP^3s@HS!+kv5UAUURLP^O#;V4K?R4!qh z9`$%;3K)9I0WrODtigozBX^&8{t_KKG6XaS)vH+DSkGn$J1zvd<1US`d6Uc}9+3I6 zK9U!qQ{eLE&-qqfL=N`hPCmfttbLJ=oT*^vPmyCn zGlKxF|9(ZALmYZ-B7^ORoSq?9dHcv8>=u+!W%ET@hc_`MqH%N?4l>EXy|5lG9`G{0 zk~Yq{6ma(ra%5Q>uF0=5dKmK4v}XoctI>q2E39fQbh6~<*Q9K?YUw{$n^!DhMF!B= zvIJ2=zdD;EH*f!#ElED&$tgEKLuaa}R##m1OOAYWOt-)xB(<|K!v4i+xxaksf}Z6k z;BEY9vV|Jv2%^`^Wb(nw3ug8EqR`_>$U>X4p)XIcVTHgy3DAp(9!t$=&Q8s2)}o9A zM-&v2>`2q}>~ae}geOK5;D~bL=z8rW8u+!D-eiEyfA%6$GL7k6x|thH5k=EWp~=C> zn!y)F;IKCXpEg`+o(xOX-|%Zh$%ksP7NSB>g-|%jIMk1oYE)w_sXT7B^ASW)zwTG({gYt^v)G5b<59^(at*wPNhC6)I4or1-6ucB<0C7#*Wx%9x27<${6 zogCu@^r!4HJtag_Lg$endTehh3S#)HVcn3fM-e<&Y%m6V_vdT=Y!4E44&1c#w6kB( zu^K#o(;T=o6LPsv?>Qbkk62*Kqkp&2KiOR-A?%njd?wEs20DOiLc`}tR7-Xp{zzYd zV~61&M_n|O>eDb*upK_u*Ym1A=(qWWw!yPwvXm}wBVhs`8-;uEDW@+8aR1H{$zkuH zjPbGj#bnZ!RHZMoyzfqf_(wovBj5hl0=ZQ|y3647j-|>CfYX()Q^0)>bhy*%juik) zFbt+#qi_(_M~2n@bo0JF%!f+P?phwZ1z~IaCT=)L5yAkI^SiUdntX=?a~^_DRXA`? zg|Cb{j=zv_=Q*l0_TcK_vwmoO7cT4?+WCO>Izt8zeo5QM_leBVjEYk2`$h+qXD-kR zKTJ&*bjkw`=K$&!tZ8^K7D)MwUt1NAGfsfa4T+}F9R34}6Db-8s@o^<_$8bh{DUyy zI^Y*o@>d=2iLqREUa@M)bdLZa(+LT6N+$gLIbY|dZwNQC0H6MB{R295@HFdDJmVlg zb&qvmOd?x>5eSSjzqc?o@|^YQb5HVo0c)T8NgL~fugD`r3EKjC5;ll5+cZkk0 z87+S%V0cw=rp=c&O7>6*-U0A+}aKPoIv0Kc#HMo28_cPbU0? zjr$wa4Cj&`7@wwV4YRDIEgynE)HRpCwd1>TKA~qKG&b;Mj7UYM$P-8jaCu%$ z;GI+sj9)I(C_^y5npE^Mll8&-e4(!|FOZmlGHC>JNg)Cl7qF-vLh$4f?OD*E_bW~H z4Gr?4PcYogAh>B(Wh|`Tpp3+!{^FxZm*Vqtrk-;ZM26hzA+`XT@FJ1+z`D8h;r@~k zxO?CgkATycq*Y6>{S(*bjc9qoqII$3-mR;l6JAe3~70xl6O9L z7H+5~cNiWgwoU1dILa8h#RikUSU)?(2uUVFc78CFBF!F-?0&S_%229<6i*@elCxt5 zD4S{?g{*$1BB~ z0dpwM=-;q&SgOZC07u0+4K<`4vvNu^*%e8XePPN9`Z zhKgbdI5vj?EL9$S#BAm8PIs=!`(vMY20~E))6$f$1|Vn6^Geo+NF8vDq-zGC1wdUo zGWjjX;G9+q;IHF~V38Fz|mn#@{47r{<19b>^D z5Nu`B)NSNdqj?7P^rA7O4MW9ck3z)<42xP)7>6K-k*c=PE^flG`SjE;CxrnKuOe;E zItkhVXj90gZ-#%>Y;z+k*Q9Btme!@YN56!sj~7(dGk+HswWw*}i(oa)l2`S^5H*Uh zqi+xK5I{Wt-tT~`rJ}@O$>snQ42Nn`*ZWKFUf(iUS}lJru+Hi}Fb#l0wgeCD+z9Nh z7IUw*=cLfN$8-zH+XZ!$-bbr`CfYsTDDn3`!6d5ic7Kg=-F;zdpMLY#Gq-9#G%~r0 zp67&86f2f5TQSG*n?{$^d#h*B3i;2dQCsuLks#H8mEKMR3{b2OzrhaSdAN8`8J#kC8=+T7qbup|BYs$wE?vy=3 zObIDK3TC!y>8CVMZO4m&(X02sD|F7Rtz3#D=DqmEJDb0qzz&pU-aMEonX}R-X~2 znE^Q9X6&RjaPViV4>xk|A*H$3Jp_@sd@&nyV+(noZ;iiKr+ z5svGYM3Lm!0#F?zF|Ib`blxIv$LEiq0bxBaN z)VrBZ2@PpG4AMJIqx_1nc_OAaMjQGgY5hI!Mq-OF2FGG;n~n^oL!kpO@J+^W6kF`S zjD)dNjmB#2Fr0<4_P@;B+qqm)Ww=OeCq4vNLz5+ih+-r6W^{1&q8l8q970p|#!7p9 zxrty}i6J@cf=G>t$fnn%T>5zIl#L1y46P;J2qZOIGydR?La-!ZW#)}mS-yo>f`#%P z(FLi_+mBGh<5CgmP0=Psc5UXNG9a`@3TUa;HEkti9*K-FmN(jvl(-#HYR^7bNDY0V zY2q;M(R*YS!?GNkyh9Q1pxV-zi>e<0+T-=QS7!(xOC4#d0MQxStr7;2SnVyg&NpG0 zzG^t(e+$9Q(3y2f>(STTc+oH$g{w>84xoHX;M#AFr=XRU*lR8koHt>UzM6CZpR|m% zQBI!Rb!sQgd|0s~=4dL3A#Oia7D90_gLVxgbsmwYyp3{6zRk3nMNAuenQ9maf9moW z&KrID5l{`i4!gcxai%28x8-os+QT89g;GD=K2u=61C-YqaXa!Qy(i|qrwg!hHnT%e z(e4flP53*0O+O}1N3Yf#@i;Or;o7QXqTZiBQ-f_Jd3_4O263y;#Z`vgVH-OeKIhjq zm!LdSelfvX`Gy`(v@LKu9H33~mB|2=hv(s)Gklfknoj}d3D44m+Z@2MJh>t7$%+qn zq$eBQ(VyUa2DDZA0(RXL-0}NP$~Bq3Za(gL1>e)-%s=+B_erIg@cnYO6T_I#GE=uD z)crCSz+}`ZGXb6mIHa z6XuymYuDP${ME74$Abp1jbck> za=zFmle*y}?nRUe9?K~Axjaee0h2T}kKGM-E{{PI$XPqI6Q{2MF>2(-J4`9SD5=DJ z7yq1h@-+>>^^wHsrOs&52Ud0)v7p6pMlR0!(yK4&cJg;Xj{j`i6_!$Dw9J~$g+A{v zL*ONF_mcHr0TQEfNzJ5Oxx3*DJ5r1@FsnhWhIgYv+>}E|A16Jpxw7^(^6$hlPbcjKeC~aqs;L_%aW8<;@#(|vOC|qwWE0C5h(WfHkF`Ae$I|)_ zYG;Ocxl9_w<2M%;dn2k+qIq8p8;-G&MMkOg_(d8g(}yw-E7Sr$YiOruhu?HIE|Q8p zSotNCms1fry0cc^%E{|-vPwc2%b$c-y}(DF#-yQ!8!&H&7X8x9<4 zVDck#m*N1vPmcgp7Mx}Zc{;t#i@jAmdL9yb<9f8eqV9+d;6v-?Qad)}3?WwQ74~(h z4^Oun?8-um(8`Gj(ZgTN@@=}_B^cEtYx@h9AQ>a2MW>bLdug;)_s3@B=yNGjSi;A{ zs%#MP>vPpmc+<$6Tdp|L`Jv%^4_q5(3&jCjf@lA7tFdY3u2ZY zdOj~27Wima6(AAgRLB!0qt*O8E0)B5LGF7cC}WbCC`Dz^Ei1w%_1ei(DuVj55Sfg? z>*fl3jyu8oW78ZB$?BK!FNlq_u3tg%alfny*V``|f@Oqrm^GFz-RK=x@%Et}3j)3^ z$(30)pQH=ugNn}P(gc@-7`&9hrROBy*Ayt7$rp642fsyn`MYAwb! z`97tF3tKWQ5_z@o8RUbV(-+4ReGl+dLp>f~psQ!C%2{6$(K)H9WJ5X^l_%4yqz z!YE}g93}M)ct&QKXg-rs`#s+h3RvqV(%0RLlHpxYaNh^>nD$>aQd?|+wE-1Lc=y5t)z@g zpGw_P4|`&?Y-@!#rHX+3*)0nnwae-)Nu$-t=F1%4pUKak|X0~*$m zG7vT|7BU4a?4N;ey%N7Vg(Dxyn?lbQt>)qML(D%3hkmytY+mifGdt8CJ@Gl`|zSS&wd z)cPX6@Fc0(oPycX8Pk@rzQblCT*)FQv@x-vdS+ps3tBlK#Cl{Vde)Nv)a>lnv@XWL z^qtGwoVtf+JJo;_VIOW@cyAiut~tm)IRALk6$(r4peo{Of-GTc7A*P_R7Nb5UMQCF zdLIk6M93}&iN{jVzF{JiUGrS;y{2+#bN4P2J->tNx4B4 z$|W=>)YfGRO4aLjnUdq44a}0IJ1C-hM8TKHPq0?|Lwn8>O*_UQWWUBW(Z#EQV77e# zGen_Z(M4*JV9FTg0LssXde;D&&zX^mhTu@#pJGyaY~e-(DYv_Ikg02Oz*ggT0GYJ> zC#VQT9&!OtA5Ba&b34Fj(8I!qOG%!q{f@9o9F1O%?TVC#14K?=8V1H8kV2mc*fIfq z0|@#;C$0R1&7gWHLjg?=?dfeJjz0?FD+0)3?D&>Q>&Ss%lYg(&|4IBf2(Y#leTmtp zIB*CrehD?amz}S|kfPC5z)YiQ6ub7Cxw&;TL+Y@|?GJ1m_u??R5x}ByNW*AAH zsI^6st5|6rPYaB|*r}?+{#d%VnCv%|Y0Ht|&QSDE@rD?>v3EZi-JrafN;lBXi z$9k9#89%Fk5&BR_v{t91hj5=$mlG^e)h*~YRar?vQ#C~_KJCzs_7aXR7mh9iv7XgN zGsV>XB{1;j8GGjtUp!qHI1xe3w0^b^E@FM>Sr3Gu*Z{}n;xB-KjtW&QTWUdnt!whnOvAwRjA6Y zF9n>oRS;FA;#_>;WIlZ6m|@FC-g)NR`(E0!grgkF7QZnkB<+ApRCt*8MFMK*Xv~H_ z%SUp5ShL=p#@p+TbpF*+0qlK$0{c;S!KmQ>2+YygFy`9~RsNFB$OE5qMz-f*0*|bH zL^LA{1`%gNQC8f~kkMb->pKtT!QtFu%gxwG=3{DVRk9(DP7kggb_nX1V2HM3;tppC z*bl`b?T`G@jbFM5;EBPs*i-M~6J=J3qRm*G9knTbnd+nLGvUMfFMFG6f^Lkm%NX@&`RR-84)GPu{!nJqPiIKfsj4oB({VK*C@XMIkI zLsbASTb303ew+guZ z<^0b%f|KeWtShAF=$I0bp}HHRzp6Ccw#EvMIcDs+a(qO2RncrSZnu0VKKzjeJ~+tY}hoWs>x6I3@B#(pm(`ZJ{Xx#+?wkzbZ; z5^=oYRGmSILKrqS#d7X^4`)lWYxqRwm1ya9Odn(b7j|{bOLkpG)lNmD0u}ZVg{4EA zfkEj{2odtST1aJC0SGpEZ~vQQqHS$&RulMq+7VQUQdSe{{87Tij;Z}aLxGR-*}$GI z$r`@SzAVawK27kjE<-dfk_$-I-ZEHuw{K0hze~0-ix)udgDdcR^3Jn%QT|CHqEoc( z3T46L9*Hf3N*WL29*QkR&Eg!3Eyh;L=6>L|?sITduqqwSnuXIkI*+Zf{^I_DVG-XB zDIJbprPyQmrLC>qp$|)7DjOqJSA5@yL}p?K^n$g|&%jaMcLe7vB*PIU>@(BCJEh5_ zJ873msJKNU3%ZeiSej9&{XlC4v4?Cg?k#T3(0z25c*gb{u;hjU8CAei!xrV#cAyG1 z)s}~bhQ=1P*Nsl;%dD0yQhd~IxqA8AVB?>g)ekMQs_VbZ3<`ENR7lLYYS&23YqxAv zS0x*jmt7%3p_|a$`#JQ$`xM2|xy;!*KwN=f-1(Cau3a3K& z%+97(SIEyTuBn(_lVf2mA;W_`MH4gcNCdBrVT!3$>okL&dtR1`Fd?9rF6)@56Te!5 zVbEZs{W^z-pTo5o`{J@dtlbCemE)QrK)yW`?blLXI;+_KjUNpzBUUBlW&?8A>+a04Aq`Skt0;WWUR&2ie3vHhbTqT$X#=Mn-oaK?mF``v*xs_xvMLaG*s(!2?56dYJ1m zV7cuR_ICi-u&*BQDNDU^N8z*aRXbg>U*u+dUeZusq&3KZ=}%V$h4c@7D0*@j_UlB} zha_0?%vASqvSAVkkmHmo@^tlRSu`N7pabqG0<$$m7xR*i!WKgS%}q$N#s}9Bt6-eK z9)Bdw9rdbSArkrTHlw~PF=O)8?%xkjf&f^POi{N-ZoA2-h!qrv3axph4rfgzIoLq+ z?P=IB1EvplRc%#M>oD1z5hoRJn0!_uZvxUy>P!mlYEcES1j7et8&JAze`hh~aSryF zZ_1gZR`{U+!&kW4MOAxnX!Efg>p@4UDhpY7A_S?on`=Q z5yZUdD&dP|{8UDhb9le=-cu3c(Bx-5U|aU9u*qGH83>j61a(~nPt zdfr{p*(b~r@4Fm4j(WNvK8(JPP1I&_y~27OK933u9ilJG^_F~moR{QGP+Y}FC#M44 zjV{R!DIQSL?(!`T45SbHZ+fT{qJErO(~+qG)D2)VsBMHgxG+l!-^qj)=ytWB zquax%T;x~cN#V|BBO;b<2#CQZO`i&+Z)XLQ6nMD<7*#*4|39R?Q?ThmR##O}VJtBI%&uepQeA2wVOD)s=iD2{k zb}97ww@R(wGZJ=>JO}30;}vv=?nQOM$_Xq|k1Kr{@qj$hXXBCy_Gxsv1H2+mib8TggUlqt&bqjc{R_PsslGW%`axcaD-?A zIG&_ExqHpn!_nr0^$3-(NvAbd4mlHWzE2?d<4>~D&*j0-w8G`DWun!`nXBE1p;uv!-=s>UE?{8FjlQyPNu2Dy!$M9C#qM-~D z8(bD$dp^$L`4dpY$j`n6|R)~ z<^$HTnF;4dK`)S02i2lL?a$`PN#Y8ErmoQdt5Tq8f@l2N9 ziU63~ocQdVb4eb`M?cNY^VMs^E5;ZItBf-$1(h@tn`s!cR=#%!EJ_m66`HT|`ix$i zW0aDGlyYJ}A@0L2adsrcEl3Utzi^Z-9Uf)4oUw+|#WsCmeEg*NTM#A;?moW`} zNmvS*KC!*UVGg5ZVx??wVrhj~KPV6@Y|vCHWpAUm%PCu8;Yor(Vhx05d(%Ibx{G8n z0fljqU!Id^wy9R%pvy^WQcfx}`aIhyXkA6QN48{XydrZ-S4>jhZJ2a!q3$+B6~yk- zf>TQ01c~*7pc{_M+R%b)9Q!>UjJT@1Y+4h1^h*P*hNK4ux1bfFCOxa{3$qo19bwCQ zA*Slj9Y7?|8PSB^HV3tecX1l<>0E1GnGSaBY;c@`SwO(+s2!7BRB@^OAMsM=$;p=> zPIMjgRP)L!K8Y@kBf&~aJUr#-WD1|swCX(YwolD6mXoh~jyW^_^8BYBY_5W|bc($* zHc!*_V!yZ~bfck+77o4YGqVk$_?S)TrnOP3WOOB?A)ZA_aB=U0Ixdz7Y?V2~&MGRK zY7P)eiAA%kJ}t$5hbgA2@wA7`fdU5?c0(`fbbso^cEpgiqgq$aZ1PXU=3{2Hf3PPxt^oeM>a zY_Rm-1S(>H(m_1o^@A;MJjIE2PGWWUK^ZDqG@{RTi?DHFd5|KlP!lx81a5GVK@5^f zl%^zc--b*XiK1tVuv+6{3)uN9=2M4~sEc-*T5|Yr3rgspdaVd$S`vdLV8UZ<8=#0$ zcGA0;;4oq7Sc}1H<>ffVdK+$$Ma7%rhT9pQ@6c*os8%?$gvEGOH~z#M;t3tZYsJbqxAn!@M6{Y9yt*&V zL3HMu+jO^8>+^B{+Ey*YIa7(&b&$g?9ez8ZCIPGN*3adg6dYQ#VUQ*@Bt;&>J6mEj z{gIMW9I83~gcncn|(2e5l^k;d|>)#+U50p;g; z#uCL|Rb&_Gz3)I!srGN?b zsGn!&$9m(;ZYyzd7|6xNhxvrFJ2^v|l!UhVp5eys0OxV`6Op}c#aur#ofmupm(3!0 zI#!7r-r4ij0(LyjP6ewjq`%`x!>g8Atqi5<3yngI_cR*kcfdWeUFyalOA=t`nM0qd zC<}dGFhNLt_s2rmJKIiVwK!iH+WO*+d%}B7Rc(xh9jo5{&O5JSxYKk)BsiYN3rOEB zcb;Wiz@0y+T#3%^ceE+;Kftz~a4}a$T~lmnsB$)?&H)LcQ$-47lDQ7?+l*k49XyvT zT70x&j_QGEA*qVMbW7F43P0Q=_anEBMQ#ZlTJ`t4H}(q$()6*m4F&f9){_L?Xq{Ts zLynlP!Jwol+Y^?{F4-f(8f52Hki;hz;bNTi>^GAeG=Sh5}3r@{njqhBYO>ti6Yjr+#AtC+t-@e zBo_t%kS;r6^=vm)?bjN5kT)>iC{gr?G#5SqcoeecopWyR0m^fsd!rG2fn^JR)+56` zpi9uV+&K@b;(D!CDzrUBYOM=2K+RZWCO<-BJu(TqBD|O%o_Uk8M{518!|T9D>+BbE zbu77sdl6@5bE!I?y#zI3Ii)?IFTYgwNR| z%U60{x8RBNBYRoZqGDWI)W(P=Bc<^M%%HR0Hp!qZ3*yBs-$-U?&c=j#Q`d5W-;xfo znAT#KWPb!}plU=@HMOxOacWF`#Re;pzYHtB@#Z80GI~Z58*`b1IjX{McwXu$ybZWta%~{0EXK9RYDsgB@G6O`7k~2~l zhT3#=W8zc|Qie`?qR{QEOEQCZM19T3(L^CVX>0vwbXAccEc%Vk;(pTs;Wi`Z?g^ZE z%C%jeowwq~!al8h>=t(KIqKGR#I^05rL!)hw!>wzCgT)xuer~KYn$cMoGn~>k7dRC z{cqB$)%tG$f68CK+O_{lAN>Ed7x~XR@4viy|7)MuDW+4ppAIQ7Iz2AwYocmnj zj`GOLLEx;$CX3qktiEun$qVwTu@rs94F?mFJKz-%Ec7Z@qi($Tw&<3)uwt}nTdn1f z>oHEWbcGWmNl=ikz0R~X3mXhd@S|hq#nyiN`JKzfTry3p0@g9uZ-k4 zo{-`e7I7Rb1zMTyJ_ONaoYt03s;tY(Lh_?Wi4MMMni`pQM3l?+pT`!~?-XCm!f5%t zU#dI6JUeW?jyvSWK*y?3ntPTzWu%%}?ILX7{|4pXHSXa8{47WRYeD*dR$CMNx8Mu~ zBTFL#N1OkHZ2ci;{2QOd8fuN$TqM@$&0HytvzE|ynXU_8NCCzV`2$a~tU3+2v|LSX zc#%ERL1+N^FRo>#7##e1;I4P3!`15h`EztOnE|2<`1pS4EKM!xS_BEls>!)~hTYj+ zUMIFM7^HzyMVw@++?^d=l2`ykE^^!10I}!95OK9avBUi0Qtd85A9SCTOOBO?gtKF{ z_MM;Xr5DT9-%RPi`h1YrxSBR+Y_m?8l8Yk&l7!`@cY5=b>Ri8ddV&chxjw+$t;HZ- zNf=Pgi*kOF6=PNzr6rZXr^gDlTNZH2pb=qts^6vR9$9)@*X|8CvZdUuZO-Z$J z6b<_Th=aVlv@Z&T@*5p7ZRqBLC}Iy9rxQmS*=tKrk$sCECZI7HY5%D_!&<@ZPXBfU z@SlA}1vlbZgJX{E8MfiOZVZ#X9f=v$v^`@C9t%C<8Wo^p`YhljMOahqf14lY8ueTx z{KWU47vTRdG5(LH-b-#=obU&cWt3;7Zy|}beT@$pX&O$+4=;oikn@M=UHrH#(X2eT zJ?{m8;hq!dtcU937q57S(&(Q7RoM-Zp8)4;Z+~^;`8$0erC2mJGVr?>KPYK{peCeY z2qC4hk=wYz0p?S?QTmIXmG4x{?xDh>`?@73x{%~(%#pBxMTR*k6$UX8i0a}Z0It;0_yShazsB+JH5p+Or!7`{Kx1Le6Slv!Jh2>ZpU$G<^G3S3L8<6 zoYG^cVw7Du2&0T6=Q*@t61lz6i(5=T+v~(!!5R%RtnHXVOvR}z0!!BUZw+W&RgwF@ z{@sp$l&$<;^;u6O+lMvp$Gn6 z0VUursh%Ql6JJ1KEbG%ok3#a5o6i6%N?m}~=I6(R!=P%(z~u<9COU-{7%>4PEttco z?9d}&)>10Z6*d0$XI@;cXu))bOI&Pmz}gm-e7?v?W1lac;WGv|C<_FOy{fIQ9#1q> z5?DBP>42L1ChBb9GAx?LSwI)+Lx<>@``mm6H>iw|6H6eaq|qE>w)7PSDh9Tk z2jG9nSelF&q|<&Pz5f3v(*MzNd&!QA1JNUK*ESlQn>Kbes-tR|3KfUb01G9Q;UTe7 zJ7II?3J;;D7NB$sKF|W=?)1UlODPdChZ!oWJtDXiT!5Upi1bEMIUOv>rSNQ$#3uy}|lEBs9b*zH% zwYs4n183@lGPJ}-xP$uE@aEj(@zo+ddt+2JY}(LzO@E8E&;-Sb8-VRYt)@W@njN2M z4nTY3z_F-=t8-`V8rq-Jy?=U>xxqDJ zPcX1`DK5t%&>Te`vs2O0=_NmOV+a)CIPE2|B@Nvj$T(;O4ew+H zdN8Sn4}+ON&*SuCT0|dfDrL!(JViDrj5IOCr8e$+xERMSo#7hO3@b|SPgu+xlGHKE z&ReAB#((!4+{Sojdha!#cshP&l57g-Frw9%f`CX`oCmVk`By9#I}Oo2e_|Q`kFjL> z=UZ3M#!27ONWjv}z~Wzq^hQ5~>Hk1wcj)YHCfvcL2)R^JD3M#0 zYO?UJVwwP>Mrf@r<9!9`@R^q`2=V6ND$ze9lxh*(?ro*sW-yvWeI8#|Z<86|R)c{i z3*|LrZMjzR zy5`(vwZa$+(DTZ@8^YIPKau$klC|0-e)DS#1HM-lJLc?Ld%~NMPTygghd~@$=d^+) zM048hxu*-*r4UCWT>wnH5wr6eS~Vl1ge&r6g4lOXA&++nkBSvz!=kHB1|`^NXQ5oD zZ~-ePXbmP7A!!IheebH$jiPg&T8m?zCzy4vH-Lpyb)=6b?vwZNMW#aBcsOG}jtW*X z7=c&PuEmf6ovU65xg)Zb2;=j_ujxm0# z@h2^C{?W#U;h)n&!pQBv3bX%LQpjn^{HPMSfi!rQtjNt9a}=#g0h_FG-;@pJDp<_K z%fSPl;jImUQR_HGU(}@3(;sqqb9l>6GXe6!d%aRxb&e<4UB18GKS9MhgoJh`56KkQ zqK7Fu(8#;RYOQ6n*WBR}yJrkBmX#{V3&^1HWm^)K=aLOB=a~c7j!UDl*%yj3kwj0c z!p5(GSg285Ms!C5fu{Qj3+hC7 zLiwty{=BiYaTJ%3Prq}uYvMK-brTaB-KoveGl0P0xY}&-j!!+9&SgNA_WxG9*r1S> z)J?3SH7%+o+0p)i49z6QG9$XWM)`$1A%TR2GZ)s52Dvx)Nm8DSr)07v_Ea2zG-)Q( zP~)u_>E-@Onn8=mWATzV#(sT|#zKqv`^;`Qos{+B`?0}M(@*L0tA^+v^hLVgvnY)} z$sxJ^IfL}Y*`oWVrRf{7_1gJ}Jo`70r%;y6^bn0hrRtOtS2{h`G+M_R?7@>wjh%lc zC(QDbbZr3Rcs)yI=55Leu{ON|pi#J6q*gdXBEr+oe~~+o=o0xVf06<2ACrOZpOZmW z&tA{c(#TT5MbFmu|2ZH2%UWUHx^y8i$vpg!Sbxw8k}Bucp9?{N$;@=1pkTY%$+UUZ zI^B!!Lyai!-`)y%%sexUkbvaAB$*yR_6iQu8SOeUJU;wb60Rh&S3yxmeEYtG-9NFkVoK`_{-NKA%~5d_R(XmuQMErm1OzK)a5hv_xT30ql$lj@?5k9LClqFoOUc%UM zoj^|wyQK=a&0Eq0b*nO%ePosQB>nOQ zzq*4L!+4epA)8Mz%ts?Hrt=c^9B6|dnjCu&ndqLONJJOj3l!%k)FkuaqiGW-EBN|G zM4};5oC=Ik>jHTheMB9)O|Sgc#UWMg*Rcc>tZS0S%o<-CKpaDWXOImOw8@i1BAs?n ztP!m~B6klZ>wP~g$qq#pK2(kPkb!^yH)3W#4Hrz}=OV-YN5l;MKPT$Hx^n>|OG|kp zYeOUZ|DCBn%vJ?VB_wYeB1?p%q~D^24an4khCePvm1}=ySsJa#sK+#@yB_N{diLT5 zE{Z^Oyh9kH_F20h1Ttq6X3>XXz3)WWd0brFAnEc)4WF+z9kPxye#)1-XWs5lU*(7$ z4d2{H_to3`Eym&wb(g#QvHRnMa?5Uc%o$ja!?yaejy&@+V?HoV)nu7Nh-frb@$7Q6l7M6H_lN)uzA8o&uXH^-OfrPa7AY^ciDIy9XVr|R`3T;!IpKC!HZ zKA49Q(Ne!~nwR* z$L?3xy8diyr=s=QLI9!VCV|e!kB>3Om{@gYu00vTqB1m_?n!A%?;;HSS$AtZ#qAea zFL#w#@0w(2Rg}#+2U7#tlPT0t;f(a;(<5o>HFgT8nl1WEX5W9?H&%vhO$DC967DMF z?n2?5S&3)qdzD{iAA<*>kh7VXg}XDIfM(j1LYd}@>(U_a0>Us!(|lGK#{&*Ue7cz2 zS>ng-$W^BMOkWv`BU_CpC1wB7YG$9+3%d3y;H64_h;-x{^e*y-sJc^{v`C?$qWi+j zEQ7|%kGo3<{g~2f6g~{{S$p&upmn6;?B2lXQE+MUqS?=#i^Wp-fHMZY#Bge(q@>um z5cF`#e7LEik#i1NhllBK)r%q*smYPK-g6!s)ZlP7Y)3}^7DvP@KNhVfKs@Iq@ zX*^&)l!7Ch-TMOVC9JsH?I|a_b>NqFZZQ7CFxZtH773$4mMYY0=98%M#tmy`wmF%ID(UI(c~SkJ`4<=WyJH) z?t$~=^`P&89+tZ0NNqwZX1X_QY1JiKw)vjK?3t=$bec--d|wy$b?uA0Y?GHA&9ff7 z)_TKHyBR3Gh;QFzI*b7Z%sZjllSO7t*uC@~HXrKVv)?4I)1@lcd!2aY;2Q@N(idFT zxjik6hOHs%2a;!MXhw>KkwYzpPEjnjHhI?`1C^-V24}U4s2+1Y{ZSfHlG0iwSnqam6=D^9LKiORjZJ4~^%YhX%sbZk zPlS85$CcAA;A?)4)t5k*eyD%X5~JOJ4H-xC5nDB&X~~IKvc7r$?X|Sd*aVuSvyo-> zrzb8|2VLY4nq(65Il+lVqjMpY*(Fz@{@{U(VW}PT2)kClVeaDJ`*#taqWc!j_&; zRC3Y)kJ?wRCR~vvaOSTv2I=^P8f3>qL(q?QT#*oMjF$&#v?9D%#&ULdCFkqT5Ayo3 zRt3>SQzttQu@Q1fVWv=8K%J_nj(s8jHW+h=Bd%s=F(a*R=fl6a-c@OU<5urGUc(rH z-J)5O5fMHBDVlhTc_Yj{o9L%hn_$$I6n5RdN*qf(dC_mA$vL}lEQ4-3q*NAE4w9JA zvWUUN80rUXK@cwH0bQkJ_6$~r^5P9fEtHsOf7e+;9ie=|DC>JTKKkfxuhf03C=>7O z&Vv@>`c;n$n$RX7>+_`B)x(*WDC(#&+LBmT@<9`1I$+{L7UAFGiy~i{1P9(Ed=!ux zrY*h`y6&%yyd&JUtd_?bke&dIeQNxG31$$Ob(ZvcIw*sUzcB>%ST6yxRe*WQFQSV9 zrk`pZaoA^JeG|-=S@8_3c?_fBl+`|jV9e234k(}pMG@ee2w|rv>wLopg7EtfkEwjT z9{5R?Z$mnRfwguCJ%7rXnS?pk5Oe_(;C4iVE(mtsx}7FBxq|8xDn#F5@(Db8#Lplu z=M<@Z*ZGIjrYi|$b8gZb>@ z{O_wr)GeA7MW_{;;vc%)Rl|lJ=~j}sneCQ{&k3Hcim_vl_~YAYv3k9D-n8WETV^^` zOFzq_t@ZHgr%e1+N~*r`F2HfIbP-B36JWS(_)sz5NJEnW_^BA8sB5lvC*43wK=7TI ztC!h9(^|eV!{kd|=@*<&f!b@dnG?b@hqV5HGxKu7%(1c9C+Ukq;TIe%s}FMk@BV87 zetk@$V$<(0%~{+5fx>4&Uk@%bHy2|(DuLW>- z9kDXj8@q3YS76qmJC}nF%jpVkVV(QwZs*$h@?zA0Li!|8%H$wh@fzZ~gws!~`&2rd z{{4x-haqlll=1h1osKvt>qv!>qE;jvL6mt6TSf`U2EqW+z7!?t^<+E?CkDsOqyTKp zQAY6HdcBO<$V8;t`O$*PyZ{YUQMTY7#2a!?X{YaIzaU~Z+!~V4XM*i+$bGZJ_At*@ z&4V^0faN%&=wn7#WjAj-vqDXjzT`evZ8ysaV*frZ`GX}o*6|l8)WS#AZ*J|GhVR5e zwQHzd+&))&8@KK<)v-GVaxQ6|VF~wmAAbyetVT8}nYdO5tUx`1UDRv7R27WeTqRF?%c+`jsbXT^hm|`EERFvb4z)zmeE1f~kIanaTF~6#VT`R6zsix% zM7OV6peUYvv;k_1LUXwguK~dUG%UhuC zFG|vm5NM4UadziTUfWlU<~G$R#aWhY{p#uu(xg!dFe>iw4TLeWmQd{&+TgBATD}aY zI1^tj+>@QB)I1)lrKeofFQUe+9*ikBYTnZl5Qs>l@gkTkC{H!k^Vz@MCiGC_k&rNp z%yIw}SnJr+e3~`y&}1YZPq&eIUNuX%HXeE8;pfz2Ni%Z)w<28X@Z4PT}r{% zGOqzW#2a5uQ3gH0zEq z&g(I5o)%PKEjREBi6~+~z-jGia|yy0!ys}a7P;$+4uK@os0n8lsw5cbrN)RwX3OV4 zvXRqzZ{;BqY#m6{20U^4kA%5odS$2vToR-+|OSQ zg{xnUTR}Xtr7BLWnOI!QD!C6`LI^yYtB`kG=*sPly>?Pgw~2lVSAaAkUoy(fmKa89VG=n^ev~2E-g)U>QQ+p6Dl8(~Tjz}!otH+3OffsV&#;k;uG|*}gk5Uv9 zKuOO#RI`j+GO@b_S9BCIfs0gj_(C`>(_!(atXo00N*TJULR77#bVU%Bx*3gEbp|YV z201gSNj}Gg6*QS$+x{_yEt z9)iK+;kJh9_QfOr7=K2`vX7Dxybjl!-qJq+17)iM1qvs^YJD8V&l5~HvCU?=5e)wU zfZ&Rj?}{WA!<%I&^zHUEH;os$O_-e70PYm_eoNEi;la8k5P81tar>TN%J}%j(}8<< z@CwJnH(;+$?FZ@A4oBI8j@QTNUE?1OTIbrrxOT(FqdeX1O4qv_@5w#7OvU3?W;ppd!$4J@a)m0r62LWOf) zY+qc*R(X~+SmFH@`7LIVH9JjO|I+dO+TiVtAAbBXef)SouI8D@;wiV?oixZAes}fM zaVLG(9-ie++8t#8-PjSjZ){!}i_sp&(Vq0ymbDMy35RW|SE`vPY+(tm0LvsDQ#)KN8rcl&T_o*z~my^KMrf>0(0FowE%&4luN4Y2^61fNTi z1IG+7c#~DV2+Wm`*7M^g&kV4KROv|j3Hn0kFhZz0t=t8Jn|thyB=v$uV}jcaNoor% zz4!a+s(ClQ=EMYs+bT}mnYHtr&FjKDBkvQ3u+OB0VNfS2mNAl6|2ORplSVY@je{pj zcP~15e|#N;%qWMaG=Zfst%)Zxfkf4an){DWn|WzLCAFtg*^9F9f=5A`&EY_+^3qLY z7L`TlfyWbmRf63{$(TIsq`1^-KNyHKUXECy>rsu!GYCu3v}?!m`#XeOC;WB1LkLA( zDIBX+ft-#e;$vv^WVXar@MXt0u>sTJ63|_YdXI!*55EA2tLhE%^e94;j$ z8n=6tJ>zRXsNKh#-3qShu5|RN>YWD1iP`Jhb2hD8`P;}{K%OL`9}qe*RK_A7+U@lh z#c^jB>sUu8Tj!Y%k&q*JXpVi{v&_9^^U`$j<(L>7U($Ut+IcG9=IsS%*eRQzRd!d+ z&`;)6gcAp!wI1Rox!&Y%7mzF~z>SI35KF+PM8j+}$7a~7yDJ`GbBjo1t9%VX_UajC zaji0vIE@diB87IFJX{`NM?a9mZV4@O@s4*%7Zzmf(BDtWUprx|^Wrxhpt>JmYS&R4 za>ymF^fYTHC z>RB6E{%>#GK*i60jm5ZO5m5Hj#d9ia8-$=)a08i?Er^9Q@)}Eh2}0#c#94RwQIfTc zT?9(^ucz3&n;#9{RM-f6YxDP~zvQBhtq2z4iY5X&ue0Q*Pn5#? z(H0bLZVZ<3yV%xt(eV)LM`$TV!d_5}FgT1eg{+t&(NbZbnaibEXX@IuHqMEe9z|`X zGn_8oZPqbZ0Y0)U72Z*d2pUi0nDA|-sq_)}`8opeGvM^(N_b>Wq%Ym#my;T-=$Y}g zf?fs*>P$OVO`^!TP?Vg8qUjyA#vlXV8vFx%PX->)%yO!je9EWOI*J~<-tkgFywC^j za)J%{xPF1PO_RI0!mPduaWY1Aof)2x5u_2XBB|7K^Szj=n7}1hV|98&-G5&&9DBao z-isP~ZLY|T(*TNK)K_uhyN+vId@)9S#0 z&PYKz8!NXvE+&)qCs1zdgCJrnXo_~m${?mfE(;q9h84lI(1pnandu2hufnb)m82_G zg{H?0Nfn$|Wr3=`p3waAT6*{+v)op-Nf^X09r@a7x~OXQ@@>3u8#|osTYJxFwGDoB zm)Z!Am=}QTT@lZy?2}I11)oMGgZ3|PhR$FJWVB%a=Uae$L%BhMq?J?&vfbZ21;Z?3D0gTSI2hkXc(IHmp&e7%v$mY z7QvJP;(6&5gtRS4Ws-nN!1OW&bZWzTgb`_+To<*Al2djNmoQ?ig>wB0xQIiox6^QC zfhs-9w!RfVD-4X86~T=rM9;)H#^SrxT>KJ8PLL&XEnz1SbV25TgkBoJJ$iNP0ozGS z@1X~xI&R8(1+qt>@_Rx{H<3yZmJ?{A@B0-Lg+M@>QQO?oxZ?f&H)m6IVG)Uut)w z`_Fa?XfN)}LR*dq(wl;wBlELFXn(f;DKh^Ei-~l|D9+<_V0tP(6fU6*>S{+95P~;d z>hmsB^?tOWezd;%fI5P2egk=7_n^rKq-hZKNAoLTQl<<6j);2KB)N8Hm(iLdN3dxL z9M`X!*&9EIdxG1XP+BOxI6|Y|8`okcNlGAvSG3*DSRNuVia81a+yJGyO3Sa%KO}_J z$5;mAOYwvlN5mS_ejvcK7|y*|Q>G)iDhwBe_Hv0Xj(?(tnD)r*t} z5`o&?;34Pw^FD6MDoCRCqYR=o*b|p28TzQS7uh~N4r@HMd@CDlL@(7eV--z~+560G zm2!G%Lo=R<`UTT|rH8ZoE1L8HtTVZSpKF=;-l6wn+7?0FnM=masIlNWo!D~W6 z3AomxP_CGaA|6+My|6rEXBIauoYK3S*_^gS23zN8Sh;^li6P#z-X5}1dy8kP4nF5* z!VXHK)M81{4if~6*J=*MnXI`W*Ir9{R%#FA=4bj|&%$-XS6@@@jYQTxv-JJ4JZ?_M zagkjTi01qRqdzRf%EgY}BQs#iL5|)<;~p{jVv~Mpw1X>q*(14C6?*5a)w-Qp;yJDM!UB%yy#8DE*5nkDY5%Y z*f!)TSWnhGmY3bnIkZL#-%tg7Z8+c@qxTJ@_y+X1XU?{=ZK7|Ne=`~4*BN$J<^9it z1$VZ+%MFhTfR9sR`EQ>`fKQgUa#(UmhUM%V`24_>+vpeI?6@TE4WFQCu`xEQuAXGe zWt^e6FgLRZ`^oAT3(aF4gk~6t7nEF|e?!9q>TFqKf1Kmz2jn~if zPpBvA7@AJhD!h*ZK8h;So#+Ax2oDm*SDnWfUQ=Di8Kd3bpO3(eD}KD_ZAJA#M*)}Y zlPP27yKK#ws>%*8CFZu9KtpgT%Cu$4cPP90SKd~=j8>(Lo>L7pqT40LoEtkyppQ_G zr!9l*0u~Lxe=K1bsAPuYl1k6r(v=EXUJ3bylg8%=jl<5NEb_whk+1Gl(XN(GTxkWY zYMzkn0OWao{IB=NWXTZAsP=L{X$hLlJTe^bG3*^?&Pgw}g zRuE@1S7rE>Fs6(fHO%ujIsW$0FtEqeD&(r6i%^u}2w^FV^+mnVdzbpAO|6XPw@l4c zSz%@>WMffzzaVDfIxsDeD|$JCl7u+iZ}R*e!CrQJn*o?tMs|p8Rcac05!A5nz-Ylp zdRXzvez~K29I9;N+|GoOk`M9LVsxEot#F{# z&J{;vD00lY^DE0UVmTLdjN}rbc1Y5gG76HaT5A)ZAtfnxn?u*^APjlZt(Nt{-IPs) zc+@R;=|LZ(u2j>!5MdY?63bsy z`XC9|XU|Xx`G$_AwvyLTW--=vT+yb7{T+zJR$%VFM6mj#w3uV*GSXDKQ4$?UIW0j} zzx!%ggyx<#9opL;si;YUr;k34p}*T7$c6Ce4)mCLcp#Nl)PlIrf&AMgQ#s7IBEvTvspK^m9MD0EX^&($dvG*#GF$ywfM;Si&M!O% z#;P2t64YkCBy)0jrBN|}2o3(YoBGno|Kt>P#KdHxwb+OZLrMGC#tj)JFe_|LqCVp)<|oam;+5dBVXF;u&sgv&KT zV_e)&YVw&A-M^AnkA;K9MPL^V*aPDgN5GzDiUo+G0 zOQG6g&XFOazBf_)MiZ;0(aL>#Ky*zM7#x| zdMoN@bF^3`!a>j&Bk)> zNz}RdxH|z(yM|50Ci0zdC{LV>@&c`_r6=gTF*v z#X62_B)9;pe>)%FV6b1vggkP=@C@kbd9l%D^oPDPM9IBf#?xcxo93MifVtaZeX{vx zI&uUoo4G)lz~uuV7bBC|qZ3~aos6137o_)!jWs4^NewXIjO|+Llvv}~(8#_X-m-<- zrEMW1SZi$!1|r%}kPr(Y#)-y~5}r9Che;ZR)eG81ZB6rn29l5$(eKJ*#j`f?(a)on zRr19WKuBMkiPaKZ*M<1?lKr}l0V7%kTwp*C)CTT_fUEeWr@s`)Cd1NK#_2OJ&GZ1P zE+BJul}E4GP903?vwz0zT>Td}2LqT2VzI~tRBHsq&Z%8fTfN)gg?QP+b^8!voLQE( z#^%gmc(~z^Y-m9@qV42 zM^y3t=<8b`H}_jY@4RB&6;+~9*H)rQ1lfSs`hdGV)DQJuyV#^JhGC2_sgJLycKKM0 zx!m7Aa68y;I4}Pe%5Yb&%M$+n^{et{?(jcLJMjP8M&n!7G9FjgI___qgOit;W)B>@D zUQ)4z?)~)-(zOIN!9RXswEqBk{ma%|rcnvt4jk;?*4B2`^}f}9tu%T3{eGelFyo5} zv6MN2*%sd!9JMFc#JGs40&Z*kAU07jh40$>Hwyf@U>fjPFQoV2FQn)`-^r%p z#`RBft%9rHvGDhNbw%?Yb9sHWu|)GQ+d*i=R2ZDn4qa#A!5RUmKn3+-^kjjr=oSsm zr`s0kVg}@(LQjX$PWRL18S_nwJtjOyp&W+6gaaR|!Pd$Kr39G_y#h^?OoF6(oq?LH zQ+H%>IKJmW0^bQI3Y^6qAvfou;L1&cgd5F3p0_HDxWlCXH8$tm+g-#Y1tfGK(9107F(6n#gP2U;p&a4U5Fs#5-q+wcG$1$6cZM9f8f$C>2Yw4O-qrx>@R9u0k9<3d@4-7 zmFhiiSWp{{xn0R=dLXx}NstN&OSLZ@*-%gG{f!H!C@wFrFym;_wLrJ1twOLu6|c4! zr>evsw3qi}G)jDHAQ#c;8p%Z74Iqak!Z=<+SHdTzg;y8*DM{3d%3HkV4?!Qq+Uh(e z6g`{eks#vaA*-MU0DVPb&c|r!u0O8Txt1U{J)rj5)IMp|YoQ^|Ql+z}0-iC|oAP{g|FaH6i3?sa3V%-{3PpXmo%cMvK~SQwq;`{h|WCDG96Awi^K_GZ{Mz z(t$gCed7U==}p541m?twQ8Zt2Y^-%@Hh=iCzZbbNT45(~eE`8hX!L2K zDY*lrsZR!Vd5}_bl2yL-7(8GCa+~Rre366G@Yk;;T{9QlPCJ}3-lDIak-nc)DV=s) zGc_tU*zzLXZ@Oc>(%VlaaIrhoy`DSYZu4nV{LWk?(9D^KQk;!m|EQ9@QYV=;H@%8A z6A(MnGG8x-k^t)#2jpf{Bh~Y6i8!0G<5>Jvv;Q$sb+Ehq)j3UNn}Mf&ttzMO62pAB zI>#D-9A??B#Tx)xqJOARPeJ1ykVP}D1@pDpcgeTWP=S2*JhTg5spF*J=GQjMtwp5; zc={~hh#Vz)J#7y3B~CVe6?}QwIt}5XHs2c-MaOOwu?6KQ#zPn2^K5nz!Gk$&C&u%9 z9pClc?6b!SIIR8hzC;T6s}W=VvV1`D%`E~C4lN4Kmd|N*$gAyp65vyY5E0Y%(CpWh zZ3(44z`DY2nkWEhd%o3Wsi_D+wDX|3zD;hGfkeq)!VEN+ZhuoL!!8mQACkNU!GWt< zm+p@a%dO+Z!4H7UhIo=-tA=)LrxpI|Ym*I}9ZS@2o{->LM2}iX?hl@U^VA!?6{F*K zx`<(;fx#2-sIddnj28U8tA2XPnSAprZv>sfB8=IHYCEljB>5MP;}=S>?Z0QQ-yq#! zkomjOi2J#ZBGCc7{H|OJLo+x!Iz0-6o4Xbxk)7yiv^}R$+C6KE4-{E) zw%F57!}7I?2Nc>A{wW_xehxa`wF#+G6QLto>|W(2<<|VX`?i0-a0`ZkK3x7TR|*K> zM8Dxg&$Tno?aPgJM{I-MT6qTJEHlP$4?dsRL0(^P4^uw4Vsd*U^XBMym?;@*x=vt* zAKM8lW62VGZuk`J|K7uXc-Rp-%$sf&uRkQ6lwd4 zv$8$1l|Nh`0A_<72?jI;? zo5r^0KRhw9J*zhMBm8Wo#8dueql@Ne*JES&*b`3PXmz*t5P){hrDv}4wY@FKT4iaO zetAW-W%`i&YT;+frs@X?Meb=Ko;NcDdfF4*^=dm9+^V^fI-ibPzFd@=_dKsta?A9+ zID@|;ga2CKnqr?9F5~FXCzJ7b-B6$Ra!$hncO)Ajew>MNM}4cqsbG`7fP@J6T+>eYWe zc5~gmfS|DFVBQzpQ!BWPUvX^x+rvCuAR}SZ^JAC-bN>0<7azAX~s5|h3+ii392Xgt<%ys>73)rz2 zM6oj~>ZoQr0TQ9Vg$X>_xH`ZP0tl!(!WAZ<1%n^I2GUROD) zpCAw29~J_+8NeS}4ZF*6F$+%tPhJ&=)GkJXucX*wkh!FUrL432&b`j=(vRFvZkv1q zzugs8O}_7zTwXW2>V5x)^3e2_8sa9S2w;*>89T}qFzK;V67*9 z@dY&Ho_U%RQPN~al7L0(+c}Lcp*b~cI-PSgE#VgZFX+_|hiN8q=a8$5id1UB-X@CV zoY+X4EKG7+7xrlB2sZK$X#2t}tw=`Vx<$ld&Q3KSWuDwTd3dlJ3Oy7fNn%hC0F@S2 z8qOYn=>BfI+?P(lxIgg$1Xeqj5y6ue#N-zz70+6HT>U~;7CFSjFdqWF!C^Hopb>HB zTcOaM>`SF%YP5sC0jbfBjwdI>tdz@lt7@%weWpASLqQt;jlWm#<~$ zC>kzwgt%$r`G*5`L9d=ZQg0tAw;${sbJv%N4$D+!OBTJv+seQS4sxrYs8sA{}}t?}+xp<6_AQPB{lyjJcIfm4=J+4mj?SM0y9 zdWL);WOM+gM_-spKA;_atLp>8E{@HiL5!qK`e02UDe?Rm6+BO`txYn?sDb#s%5n>< z-vraelU3$CY=%X~7BKg%&97YwQYU0;le$9Byfue>rf$1%<*1bPog~rw%O4W?u1*>= zclQpIgC9Ncf2K;P4z|=dmsBN0a?Cf(KyYeE-p|nKku}H5#)!*Wy2nU+uO3^6F38o1 z`Sx56#x*d%wyAHZz$1}lS1hfYC}Q8(swequ^q*y4c~3=)-$r1&!~pR_xOnch=C&^q~;p<2qyFsxuLu{ScA$Ad|bYNA@QD6Y_fT z@lNvk4L#rYD%aDY$!U@vapkO14E4Tuw@(lc zSWiXqTvE2f`<|s-+jesqf;OE%dsZm_&;j+XAc6Dm=vjWSwSF>q2x)}+^GiA#t?(>4 zNL?F#LEUk)^b!n*Dlukt!uv?=!3C@Mw~2GF*`ftQlr`NYb%*e%w3mI?F5q)6je9`n zpc}=t8@Y?~F#6eH%P&GIZ=>JMtog+*se1L~5Y+IJwpipui(jUH^inM)v&Ak?Hi_>T zZ@8=C+iS{O{v2Kh(!<}qUOP^DfV%wxbKJ?5?+E5c?+>|O;F%2#YpJ(~$h2GWF*GOW zCx|rh*1;XVr{;_Z1?u=a%kO*U9ufN@a0!pm9^w@)GXHUA?v&sg+1}n>%I1OW@=94o z)>y=VAr53+jqKu7Z2i|KQQMAc`U4F(qs zdMTRI&nEK5m@zMHx`6d(mg@bkk}GD?^K$lZnjaY>iaHINNo)^AqSfcmCO2t|6unZs zO(e(cCKN|E+9lEN^pr@d#pXJRQ{ZR)q)MO5!P(PC&XuO0nbX%iAy41Jb#+W8WpV+`FkE zV)6cunpU%v_0O-jdG}~vJybVrBq-OoDScd4>$x$!{zzHMy<4_NTW=mqi8505Jx#J5 zuKXG|V}JtD{sVW)_1Qjef79C~NdfwPU1EM|Dm9Er&MNmagFNrX5O;EHE1x)}Vnw#P zI#Oe1Iy!cAh+0aqzw}ffEs4Omg>i1s#(94c&DzV2pKtsSwz^)zvPvQ{ty1km@woBu z@n@RD!O786EBIG=E6OVmY&dkjqh!$XNN;E~A+ua07;T=UXT}|i2;yNj!IjB5Sj7_D zM=@8r;T$|IJg!;S;*ILqM74`bWBFBhR7uhvu>UWIa z>+JRS?imHw{F2$A&x&@zGEVEs6C_+Dl4xJYnudVUiukDvCd!SBz zazRkbmh?)z$vUpdx(P>yWgUOTQ(ax~Z%>O8VRDHd zZo<}TNQK6`i!Rfyo@ajdLQ*NxFJd{*km^P=d)=bi;kxgEJ=}ELWarBRVQZ|F0mcwb z$43PfeFGZ;>^~NM{QP!6jH0mr3`j}_j_j3`(4!|M=rEZyqzcI1eG1f9E{RJAY)uUko7NQ2L}d;X|$q3W}4uA}=GPr!aMu9Bl~syoUfMNJN}_-_n|RKWojf3sW$gXe^weQvh(*hj)}TzFlf}Xq+>{R zOSWccXvp*0JZ$Xs;G+yFD$8`Cl?W162bS!VJ3@bvO_%&XnYx3B8OZJ!q`Q zJi$V~AXsivSJQ$0V@~6F4?XS@iC=55DH^(MDfX5}p}%JIfSoWj+~Tw19hdVFm2x77 zT(oi8yYCiOpSCN8*_t=O62$rnsYTBXnF(JFyE7>ryqz@tDlD?OnVVP2!X2_H9~Uhiu9l@g z8YU?eA8USYCf5nx7%O#j_Fm6J(i*&(7^MaIg5%8$l78;BybTirfrXXJGkm(9>_23Uk80+B`jVIO2*1tS zaF8(%G3>o8w11@A?wl5nbzrJ0iL`v!Su4W#K?;{yjEA(PUpH0-r(HY65S6x0=wC%e z?ByO6D;Z+zD($;Q$#D1`vsblQ0Y&cC*$%p^LXd%aH`( zn8D(%!mWCF-eyFOgX6dz&RG51j`$CWjMIeA4Liil9md=|n~T-#vv2bqb-L(KR+~Zp z?LB!+=CF;ngW2gjlT^3gR)=yje0xt{RhHW=@t8Vvz_!>sKDF=rSNqm!cd{|6sXE^U z=Nd_wj*tu1>vc0#5vt1v*D@>Dqo3VfyqPs#GpO+_IqyxT;9HN%5zXfT&yqVYwS9Td z*&``D|BdN7Pg={8u>Yv>?c=kJ6uPSJ>2kqa5O4EkSq(p1qDW%>aw<*uaZQWHt|;*? z;u+@xt78$tz1KHcd|H%n87T^NO*5n0qAypg+*%X8&N}f!2LdzXNC*pjP0RUN3{Fo+ z)%WGuI*-x$ksGG>jhO}R_smD$ZAh=>RemE38(h6l@x-a`yO#eaLW>hQYj|`st&^V< z`=X-~3I-{LP8@aA>-Z$LHetP(T%dHkud#)Xv$R%|rGA>0{iVFzOFoY@f3g;@{E2Cj z6#aI|c*4!-mBdp4$z8BV`!{3d@c5Y5wfH8vW`-a~9QqwAy`sMe4v8K!v$QxqzCA-j z9SKpDybz0XjxM)f^qY@GDdh?QdsM}>DEiVPk4{?B9Kz0BK3+?@T4qCh*5a7Z_EYrUZlGh})DeVeR^o0-_7sahvR zE~KQ!C`C!xxt~fqvrk&gl+B>?J}~tb=tI^W z=0DgIXTz*lpv0Htn?=h+%L2-}1ll{xwq*{hP=APaNL#GY82Ik}nM4dO-frXe2G`|_ zS0YsG7WHwc%2%K-VwEdw9=<##B>Dh))J<}rhjfwY6yro&qt|u( zl`5%BW8-M^R7;Ms6P1GJ7NCuLw%dalyf&^Ox}HNmC-!^ zK1^_Fg z&?@1XPxLPspRG1uX$l+5s*b1Jimn)X8N|L^k~vWGNc>WPsLGMhE@2)2(T?}S&THW$ zS#KV5K7GKc5IvI>Fac*UAIZ|oPvD=;eoHeb(Y&EJM%P%Au(&02{rI&=Mvu*uhKOeZ zY_cqjLR>>r*t>zdHD}Z8|(T@<5zgm7_r1Le+fxX5!b+DmOUp z=zYRTn|72hKkQB1;z7Vk^Gem^w7@cs>0J#0?RagCmDiNhRQ*$rXeO%9F*DTL4*%fT zFQ<5~ViB(^o^5Jy;%0gup1N9UgQ;HK?O4Ydw%q$O2bXkHueYpmx7w2Bn1nhkt~xg9 z6gAln%73EFW(knnZq5ISCu_>K>ZLldKUC({TFrpZ_Ql$4G51_isCcX=t`Wy;UUofE z;^4HA@657FYp?VDUH1VGhrtJq@UVlzt)Wl^zd0P9 zAKMV|T97Ot-N%gvCZOK;Di$yB+okeY|9uMWYAKwZY-OL`@V+ICy*!p$^xon2ZFP39 z+&jT_H$J2n2`AU<+6fLw7tV7LeolMQVDZgH>?RSZMW#-8VT4PR!gs628;)D&1HRkV z!AV|9pD5FJadQ1s&-~#VUj&srEQr$Vn6p7UG0AXwx7KWKm4$)3jLq1+(619)maex( zm#f4s5h#;g9pt7okUW&@@+!~qE-#`hDDSG#!GqoguSjTFU5KEQm&{JkhIQ4MtA2KL z;|hPQ&zrm9meduwIP4i$I@QoA#z(NtC=@e&TjnbV{yZT(v#lm$O4l@y${>)_?B>hN zV*-~ZiRNqH+!s4@-L6X*u4m**M!*Px5)=+Q*H%>b9EEu z*PHsyZ+?p)UHBgKA>v+&X@p=^C4(=;tM?4Kw9`GL3q2xE$3z0%rKR6Ur>+ipexoM& z%6D~CXOU(8=nabXEB5RIp=F$96f5PUCdPwx^fa%HH_wmMAr}b?+D@;`gR?g*z>b{@ z>bQ86IAGfjD35DUmkEJ0{VrrUTk^=qbIOhx>i9-PXA*%_PQ~4p!KtLYY zL5cjIe+wsg`djUsyr!y(vi2qZb1FMu?1HvF3BK0-U63!n1D=1aR_?6RhE|98PZbc5)V&DH%73P=V7y7O7FV8}@@tfe$$q4XY zGQk-f$YU@66&CQ9U#9-m#`0GjT@gw!h@GR=pPv%^lHwoCr}7=t6~F>^!M4DjWo)qD zhXbO+23&g+H9!aID6UDI)Qh0f8-Swz#{o||z*sv`8jeH94(su5EaRLN0syMU2MRzhTxHww5K;du&$nPVy(8aL~D1iF{Gvxv^F`$U^7)ZAh z^>2=j&E)4uYK4WsIRZ6cLpW;tdDCEL31ZeUhs61e5fDs#mtY&mvBI!4pJ|qXbunNS z>|$jBov|qS`z%3pgB5AMo(Kl4d%IYfOjudJPpjL-+UBXz1RP3WG*shXWx>i4#cVHp z=e3GZjB=5&V`Yh9W+|284+jF){ardvb6{nOV`gb7GpODIEM!ol>R8Q%l_i0hRT5Fu zW&l{iyI4UySXq*oS#-8S4p%|&cuL{m0EgO9_(2wh*(WfQEX`vTkz;HL=vRPBJIcK3 zAJUEiM&29&y9z}{lQwcYEVf`uT?_ki84x8wFae|QC?_@kn~GV|u$u{^Ho$gJ;BTms zzCDkDsqAhJbwYqq5h<)91P;YajZXeJ(SvLe&?B+#kP`A!~GWtXNmtx4n;ZPSWmOB&fn?eKR z>I5GU5jzUIB{mXhUlj<<4r-z7;)2b7qXQQ$%7N|jLAr*_^8S@LtKD2hM|&rT3k?1X z?COHWZ!G3d2_O@`I`CosM+8q9w!5KVBtw8hnjzq%NX%B`vU>A15mc@OA379Vu-$GP zcJIS~`@t{+xH1DsGf_J%m_23=_R#PV>8TL{cIyXrLsjuI95V~q6j&`5PW9kQFHlVf zG%uUO?4*AYWxdX@X9V zy?B@#v>=i##2rXy52Ry8p(XfWrtR6Gj#GHl@Pbs<8ua$4*@?-mJ#d(1`|6T#dKk~nndW20X>@mL;DV0+6OfM^MOECpXgEbX2poO^g0Mz1 z6&=Buh{%)6cVlmrDD%}RZhVUaI6`1WCKRmx12inu-Q3RA0&2nU-dE+VAC+p)uk1;0#S{N^>q4c|Qi65%6I~ku9Pejic@80yYn^p`68uuBry_>(|ym zO>$sES`=Jp1xDO%7e>0s8H>zrWV($Dv_l=yq^i*|2#A9P#N}sV@t-YW5Zp-q9rW<0 zz{~`-C63jiaew+82;!fSw^!>n!N1N%0abzT;xM78Y~6~9i9L9cnk!~_&K&}pH-Qfe z3QeUA0}XU9*gJb9ueLXA@j2j}+{Mdm$H3dug2-w9?0fy>4ZyPoJXF6c>ph+Vk;mwVwbOdXN9l({OR zV$d`5fFTWa)JW^z1BY2vyhp7ACkb$HzLTOmNa`RuOwrL5xkK;gaS51ddi7>B5TKP`Zml)J0!u7a~rtF6fhhc3fb^8 zI{CM?Kx83@Fic4g(nH`plqp7_39f^Nl|mt&n*R^t?-wAAvHREW=r+mT_e8oCxqdR2?7f;_SKVhJ>BY9W4q6 z`niK>LY-si;NhYP1tJvT3fF)+V3_wHS$Q?-)d|3(2>}mvgcLY{&O#1lXa891Km2;c zTB?l?$Y%y}Qq;u)27>>EyW8uK(q@m!n0Vwp}$moW<1vI-DUeeV|eUNj7Am`LHwO%L)_0^HIr z9E5T&oDgQ))%U|smjK+>E}S*>UN|g6+bI9+f3fpi?u6hBReVPO=h zY(3M5&*1=~Mxl+I(8FJurz$OITsnEyEm zcv_|33x{Ea6p5pdZD`B_(iQEJj*(?A9EL?wB<{Fdm?|GYA=i^or8~m57Y@TZDH7*7 z(d-YrA14)jP;p@#d*LuFl_GH!A5N!n1L=@!`%Ead`^32i4vX8}rf1d)2DF}CGziZg zG%Q{hClS_!bQ9#2P^hv=oY;eg#p&)*byy;OxOf+hQeY1n7N5()o8t%qw31!41;IUN zSX}P)zB><)%OSD5XiXrc#~Q9!JdWyROd?V?!R(^L7{`CNi_m`m4cOJwpghEe-?@9l;M6v7A z33U9h%^A^L&VUH zu=6khRG+Q~nI8rt{1qFs8Fu~*j~PX1VUU&Y=Aj)(uv0wbzKfk3=$TM(su_Q9*ni1~ zPTRRr40Vn-nu|vJm*MT!6S=c&=T0K97P6x#72~4qGrOR^A50u@aNNK@8{iubrC@Bp F`9DH82$KK+ From 0892e598f6df0c9c9cc61c4202e62897b283d4ce Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Mon, 21 Sep 2015 16:18:48 +0300 Subject: [PATCH 0051/2114] Depend on JUnit 4.12.0 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 07d328aa98..51b5e606b7 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ VERSION jar RabbitMQ Java Client - RabbitMQ AMQP Java Client + RabbitMQ Java client http://www.rabbitmq.com @@ -61,7 +61,7 @@ junit junit - 3.8.2 + 4.12.0 test From 16e53ebce3bdb036d7ab091ccb3e5c1766ac5ee5 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Mon, 21 Sep 2015 16:20:48 +0300 Subject: [PATCH 0052/2114] It's 4.12, not 4.12.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 51b5e606b7..5db8422d17 100644 --- a/pom.xml +++ b/pom.xml @@ -61,7 +61,7 @@ junit junit - 4.12.0 + 4.12 test From 474121e0e9a1e2df1f6adacabc1d3e37ee9084cd Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Tue, 22 Sep 2015 13:55:36 +0300 Subject: [PATCH 0053/2114] Remove timeout validation, fixes #92 --- src/com/rabbitmq/client/ConnectionFactory.java | 15 +++------------ .../rabbitmq/client/test/AMQConnectionTest.java | 9 ++------- 2 files changed, 5 insertions(+), 19 deletions(-) diff --git a/src/com/rabbitmq/client/ConnectionFactory.java b/src/com/rabbitmq/client/ConnectionFactory.java index 8573d3e137..e8f7af75d6 100644 --- a/src/com/rabbitmq/client/ConnectionFactory.java +++ b/src/com/rabbitmq/client/ConnectionFactory.java @@ -321,11 +321,7 @@ public void setConnectionTimeout(int timeout) { if(timeout < 0) { throw new IllegalArgumentException("TCP connection timeout cannot be negative"); } - if(timeout > handshakeTimeout) { - throw new IllegalArgumentException("TCP connection timeout cannot be greater than handshake timeout"); - } else { - this.connectionTimeout = timeout; - } + this.connectionTimeout = timeout; } /** @@ -352,11 +348,7 @@ public void setHandshakeTimeout(int timeout) { if(timeout < 0) { throw new IllegalArgumentException("handshake timeout cannot be negative"); } - if(connectionTimeout != 0 && timeout < connectionTimeout) { - throw new IllegalArgumentException("handshake timeout cannot be lower than TCP connection timeout"); - } else { - this.handshakeTimeout = timeout; - } + this.handshakeTimeout = timeout; } /** @@ -561,8 +553,7 @@ public void useSslProtocol(String protocol, TrustManager trustManager) * * @param context An initialized SSLContext */ - public void useSslProtocol(SSLContext context) - { + public void useSslProtocol(SSLContext context) { setSocketFactory(context.getSocketFactory()); } diff --git a/test/src/com/rabbitmq/client/test/AMQConnectionTest.java b/test/src/com/rabbitmq/client/test/AMQConnectionTest.java index d610ce4519..e73c534e1a 100644 --- a/test/src/com/rabbitmq/client/test/AMQConnectionTest.java +++ b/test/src/com/rabbitmq/client/test/AMQConnectionTest.java @@ -106,13 +106,8 @@ public void testNegativeProtocolHandshakeTimeout() { public void testTCPConnectionTimeoutGreaterThanHandShakeTimeout() { ConnectionFactory cf = new ConnectionFactory(); - try { - cf.setHandshakeTimeout(3000); - cf.setConnectionTimeout(5000); - fail("expected an exception"); - } catch (IllegalArgumentException _ignored) { - // expected - } + cf.setHandshakeTimeout(3000); + cf.setConnectionTimeout(5000); } public void testProtocolHandshakeTimeoutGreaterThanTCPConnectionTimeout() { From 36b87927e97b8d98a85b15b16de3fe58cf52b8b2 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Tue, 22 Sep 2015 16:15:56 +0300 Subject: [PATCH 0054/2114] Make shutdown executor optional, fixes #91 References #81, #82. --- src/com/rabbitmq/client/ConnectionFactory.java | 13 ------------- src/com/rabbitmq/client/impl/AMQConnection.java | 13 ++++++++++++- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/com/rabbitmq/client/ConnectionFactory.java b/src/com/rabbitmq/client/ConnectionFactory.java index d86e380076..93541ac6df 100644 --- a/src/com/rabbitmq/client/ConnectionFactory.java +++ b/src/com/rabbitmq/client/ConnectionFactory.java @@ -651,7 +651,6 @@ public Connection newConnection(Address[] addrs) throws IOException, TimeoutExce public Connection newConnection(ExecutorService executor, Address[] addrs) throws IOException, TimeoutException { // make sure we respect the provided thread factory - maybeInitializeShutdownExecutor(); FrameHandlerFactory fhFactory = createFrameHandlerFactory(); ConnectionParams params = params(executor); @@ -731,18 +730,6 @@ public Connection newConnection(ExecutorService executor) throws IOException, Ti ); } - /** - * Lazily initializes shutdown executor service. This is necessary - * to make sure the default executor uses the thread factory that - * may be user-provided and crucially important in certain environments, - * e.g. Google App Engine or JEE application servers. - */ - protected void maybeInitializeShutdownExecutor() { - if(shutdownExecutor == null) { - shutdownExecutor = Executors.newFixedThreadPool(4, threadFactory); - } - } - @Override public ConnectionFactory clone(){ try { return (ConnectionFactory)super.clone(); diff --git a/src/com/rabbitmq/client/impl/AMQConnection.java b/src/com/rabbitmq/client/impl/AMQConnection.java index 0fc0224d98..b1b326250f 100644 --- a/src/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/com/rabbitmq/client/impl/AMQConnection.java @@ -671,7 +671,18 @@ public void handleConnectionClose(Command closeCommand) { } catch (IOException ignored) { } // ignore _brokerInitiatedShutdown = true; SocketCloseWait scw = new SocketCloseWait(sse); - shutdownExecutor.execute(scw); + + // if shutdown executor is configured, use it. Otherwise + // execut socket close monitor the old fashioned way. + // see rabbitmq/rabbitmq-java-client#91 + if(shutdownExecutor != null) { + shutdownExecutor.execute(scw); + } else { + final String name = "RabbitMQ connection shutdown monitor " + + getHostAddress() + ":" + getPort(); + Thread waiter = Environment.newThread(threadFactory, scw, name); + waiter.start(); + } } // same as ConnectionFactory.DEFAULT_SHUTDOWN_TIMEOUT From 1fdb294f8b9bcea56c554e16dedc77065132cfb1 Mon Sep 17 00:00:00 2001 From: Yann ROBERT Date: Tue, 22 Sep 2015 18:40:23 +0200 Subject: [PATCH 0055/2114] Allow to set an optional Executor to be used to send heartbeats --- .../rabbitmq/client/ConnectionFactory.java | 20 +++++++++++++++---- .../rabbitmq/client/impl/AMQConnection.java | 10 ++++------ .../client/impl/ConnectionParams.java | 10 ++++++++++ .../rabbitmq/client/impl/HeartbeatSender.java | 13 +++++++----- 4 files changed, 38 insertions(+), 15 deletions(-) diff --git a/src/com/rabbitmq/client/ConnectionFactory.java b/src/com/rabbitmq/client/ConnectionFactory.java index 93541ac6df..beeedd1e7a 100644 --- a/src/com/rabbitmq/client/ConnectionFactory.java +++ b/src/com/rabbitmq/client/ConnectionFactory.java @@ -20,14 +20,11 @@ import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.util.Map; -import java.util.concurrent.ExecutorService; +import java.util.concurrent.*; import java.net.URI; import java.net.URISyntaxException; import java.net.URLDecoder; -import java.util.concurrent.Executors; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.TimeoutException; import javax.net.SocketFactory; import javax.net.ssl.SSLSocketFactory; @@ -104,6 +101,7 @@ public class ConnectionFactory implements Cloneable { // minimises the number of threads rapid closure of many // connections uses, see rabbitmq/rabbitmq-java-client#86 private ExecutorService shutdownExecutor; + private ScheduledExecutorService heartbeatExecutor; private SocketConfigurator socketConf = new DefaultSocketConfigurator(); private ExceptionHandler exceptionHandler = new DefaultExceptionHandler(); @@ -492,6 +490,19 @@ public void setShutdownExecutor(ExecutorService executor) { this.shutdownExecutor = executor; } + /** + * Set the executor to use to send the heartbeat + * All connections that use this executor share it. + * + * It's developer's responsibility to shut down the executor + * when it is no longer needed. + * + * @param executor executor service to be used to send heartbeat + */ + public void setHeartbeatExecutor(ScheduledExecutorService executor) { + this.heartbeatExecutor = executor; + } + /** * Retrieve the thread factory used to instantiate new threads. * @see ThreadFactory @@ -694,6 +705,7 @@ public ConnectionParams params(ExecutorService consumerWorkServiceExecutor) { result.setHandshakeTimeout(handshakeTimeout); result.setRequestedHeartbeat(requestedHeartbeat); result.setShutdownExecutor(shutdownExecutor); + result.setHeartbeatExecutor(heartbeatExecutor); return result; } diff --git a/src/com/rabbitmq/client/impl/AMQConnection.java b/src/com/rabbitmq/client/impl/AMQConnection.java index b1b326250f..c094667dd8 100644 --- a/src/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/com/rabbitmq/client/impl/AMQConnection.java @@ -25,11 +25,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.TimeoutException; +import java.util.concurrent.*; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.AuthenticationFailureException; @@ -64,6 +60,7 @@ final class Copyright { */ public class AMQConnection extends ShutdownNotifierComponent implements Connection, NetworkConnection { private final ExecutorService consumerWorkServiceExecutor; + private final ScheduledExecutorService heartbeatExecutor; private final ExecutorService shutdownExecutor; private Thread mainLoopThread; private ThreadFactory threadFactory = Executors.defaultThreadFactory(); @@ -222,6 +219,7 @@ public AMQConnection(ConnectionParams params, FrameHandler frameHandler) this.shutdownTimeout = params.getShutdownTimeout(); this.saslConfig = params.getSaslConfig(); this.consumerWorkServiceExecutor = params.getConsumerWorkServiceExecutor(); + this.heartbeatExecutor = params.getHeartbeatExecutor(); this.shutdownExecutor = params.getShutdownExecutor(); this.threadFactory = params.getThreadFactory(); @@ -237,7 +235,7 @@ private void initializeConsumerWorkService() { } private void initializeHeartbeatSender() { - this._heartbeatSender = new HeartbeatSender(_frameHandler, threadFactory); + this._heartbeatSender = new HeartbeatSender(_frameHandler, heartbeatExecutor, threadFactory); } /** diff --git a/src/com/rabbitmq/client/impl/ConnectionParams.java b/src/com/rabbitmq/client/impl/ConnectionParams.java index a7eacd0391..9114d81a95 100644 --- a/src/com/rabbitmq/client/impl/ConnectionParams.java +++ b/src/com/rabbitmq/client/impl/ConnectionParams.java @@ -5,12 +5,14 @@ import java.util.Map; import java.util.concurrent.ExecutorService; +import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadFactory; public class ConnectionParams { private String username; private String password; private ExecutorService consumerWorkServiceExecutor; + private ScheduledExecutorService heartbeatExecutor; private ExecutorService shutdownExecutor; private String virtualHost; private Map clientProperties; @@ -155,4 +157,12 @@ public ExecutorService getShutdownExecutor() { public void setShutdownExecutor(ExecutorService shutdownExecutor) { this.shutdownExecutor = shutdownExecutor; } + + public ScheduledExecutorService getHeartbeatExecutor() { + return heartbeatExecutor; + } + + public void setHeartbeatExecutor(ScheduledExecutorService heartbeatExecutor) { + this.heartbeatExecutor = heartbeatExecutor; + } } diff --git a/src/com/rabbitmq/client/impl/HeartbeatSender.java b/src/com/rabbitmq/client/impl/HeartbeatSender.java index 893597d0a5..00ba30eb6e 100644 --- a/src/com/rabbitmq/client/impl/HeartbeatSender.java +++ b/src/com/rabbitmq/client/impl/HeartbeatSender.java @@ -43,6 +43,7 @@ final class HeartbeatSender { private final ThreadFactory threadFactory; private ScheduledExecutorService executor; + private final boolean privateExecutor; private ScheduledFuture future; @@ -50,8 +51,10 @@ final class HeartbeatSender { private volatile long lastActivityTime; - HeartbeatSender(FrameHandler frameHandler, ThreadFactory threadFactory) { + HeartbeatSender(FrameHandler frameHandler, ScheduledExecutorService heartbeatExecutor, ThreadFactory threadFactory) { this.frameHandler = frameHandler; + this.privateExecutor = (heartbeatExecutor == null); + this.executor = heartbeatExecutor; this.threadFactory = threadFactory; } @@ -106,14 +109,14 @@ public void shutdown() { this.future = null; } - if (this.executor != null) { + if (this.privateExecutor) { // to be safe, we shouldn't call shutdown holding the // monitor. executorToShutdown = this.executor; - - this.shutdown = true; - this.executor = null; } + + this.executor = null; + this.shutdown = true; } if(executorToShutdown != null) { executorToShutdown.shutdown(); From f3b926087699df9328d747cf434a3076b35a4d3f Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Tue, 22 Sep 2015 20:04:34 +0300 Subject: [PATCH 0056/2114] Minor JavaDoc correction --- src/com/rabbitmq/client/ConnectionFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/rabbitmq/client/ConnectionFactory.java b/src/com/rabbitmq/client/ConnectionFactory.java index beeedd1e7a..ca135c9cf7 100644 --- a/src/com/rabbitmq/client/ConnectionFactory.java +++ b/src/com/rabbitmq/client/ConnectionFactory.java @@ -491,7 +491,7 @@ public void setShutdownExecutor(ExecutorService executor) { } /** - * Set the executor to use to send the heartbeat + * Set the executor to use to send heartbeat frames. * All connections that use this executor share it. * * It's developer's responsibility to shut down the executor From 30a9603a9fb9aaf02b518670e4b1c19e1ac8953c Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 23 Sep 2015 00:25:30 +0300 Subject: [PATCH 0057/2114] Allow channel manager to use an executor for shutdown monitoring Fixes #94. --- .../rabbitmq/client/impl/AMQConnection.java | 4 +++- .../rabbitmq/client/impl/ChannelManager.java | 21 +++++++++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/com/rabbitmq/client/impl/AMQConnection.java b/src/com/rabbitmq/client/impl/AMQConnection.java index c094667dd8..fc0127edff 100644 --- a/src/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/com/rabbitmq/client/impl/AMQConnection.java @@ -393,7 +393,9 @@ public void start() } protected ChannelManager instantiateChannelManager(int channelMax, ThreadFactory threadFactory) { - return new ChannelManager(this._workService, channelMax, threadFactory); + ChannelManager result = new ChannelManager(this._workService, channelMax, threadFactory); + result.setShutdownExecutor(this.shutdownExecutor); + return result; } /** diff --git a/src/com/rabbitmq/client/impl/ChannelManager.java b/src/com/rabbitmq/client/impl/ChannelManager.java index e77afcf7ae..42d03821ec 100644 --- a/src/com/rabbitmq/client/impl/ChannelManager.java +++ b/src/com/rabbitmq/client/impl/ChannelManager.java @@ -22,6 +22,7 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; @@ -45,6 +46,7 @@ public class ChannelManager { /** Maximum channel number available on this connection. */ private final int _channelMax; + private ExecutorService shutdownExecutor; private final ThreadFactory threadFactory; public int getChannelMax(){ @@ -117,8 +119,15 @@ public void run() { ssWorkService.shutdown(); } }; - Thread shutdownThread = Environment.newThread(threadFactory, target, "ConsumerWorkService shutdown monitor", true); - shutdownThread.start(); + if(this.shutdownExecutor != null) { + shutdownExecutor.submit(target); + } else { + Thread shutdownThread = Environment.newThread(threadFactory, + target, + "ConsumerWorkService shutdown monitor", + true); + shutdownThread.start(); + } } public ChannelN createChannel(AMQConnection connection) throws IOException { @@ -199,4 +208,12 @@ else if (existing != channel) { channelNumberAllocator.free(channelNumber); } } + + public ExecutorService getShutdownExecutor() { + return shutdownExecutor; + } + + public void setShutdownExecutor(ExecutorService shutdownExecutor) { + this.shutdownExecutor = shutdownExecutor; + } } From f24b66f1e91506d1e841d37e3ad85dafe3004b3e Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 23 Sep 2015 12:38:26 +0300 Subject: [PATCH 0058/2114] Squash warnings in AutorecoveringConnection --- .../client/impl/recovery/AutorecoveringConnection.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index 2dddb86ad5..76d3b3c066 100644 --- a/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -16,7 +16,6 @@ import com.rabbitmq.client.impl.NetworkConnection; import java.io.IOException; -import java.net.ConnectException; import java.net.InetAddress; import java.util.ArrayList; import java.util.Collection; @@ -73,7 +72,7 @@ public class AutorecoveringConnection implements Connection, Recoverable, Networ // This lock guards the manuallyClosed flag and the delegate connection. Guarding these two ensures that a new connection can never // be created after application code has initiated shutdown. - private Object recoveryLock = new Object(); + private final Object recoveryLock = new Object(); public AutorecoveringConnection(ConnectionParams params, FrameHandlerFactory f, Address[] addrs) { this.cf = new RecoveryAwareAMQConnectionFactory(params, f, addrs); @@ -410,6 +409,7 @@ public void addQueueRecoveryListener(QueueRecoveryListener listener) { * @see com.rabbitmq.client.impl.recovery.AutorecoveringConnection#addQueueRecoveryListener * @param listener listener to be removed */ + @SuppressWarnings("unused") public void removeQueueRecoveryListener(QueueRecoveryListener listener) { this.queueRecoveryListeners.remove(listener); } @@ -429,6 +429,7 @@ public void addConsumerRecoveryListener(ConsumerRecoveryListener listener) { * @see com.rabbitmq.client.impl.recovery.AutorecoveringConnection#addConsumerRecoveryListener(ConsumerRecoveryListener) * @param listener listener to be removed */ + @SuppressWarnings("unused") public void removeConsumerRecoveryListener(ConsumerRecoveryListener listener) { this.consumerRecoveryListeners.remove(listener); } From ef8f8438ad45f551b8211efa27a7c8f32b5e71e5 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 23 Sep 2015 14:13:47 +0300 Subject: [PATCH 0059/2114] Ignore debug/* --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 401cc09653..7feeba8f39 100644 --- a/.gitignore +++ b/.gitignore @@ -12,8 +12,9 @@ /.idea/ /build/ /cover/ +/debug/ /dist/ /ebin/ /out/ /tmp/ -junit*.properties \ No newline at end of file +junit*.properties From ffb25593153f587ecb3339f00a54e43c81f39ee3 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 23 Sep 2015 23:54:06 +0300 Subject: [PATCH 0060/2114] Make sure missed [server] heartbeats trigger connection recovery Fixes #57. --- .../client/impl/recovery/AutorecoveringConnection.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index 76d3b3c066..82d452df44 100644 --- a/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -5,6 +5,7 @@ import com.rabbitmq.client.BlockedListener; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; +import com.rabbitmq.client.MissedHeartbeatException; import com.rabbitmq.client.Recoverable; import com.rabbitmq.client.RecoveryListener; import com.rabbitmq.client.ShutdownListener; @@ -378,7 +379,7 @@ private void addAutomaticRecoveryListener() { ShutdownListener automaticRecoveryListener = new ShutdownListener() { public void shutdownCompleted(ShutdownSignalException cause) { try { - if (!cause.isInitiatedByApplication()) { + if (shouldTriggerConnectionRecovery(cause)) { c.beginAutomaticRecovery(); } } catch (Exception e) { @@ -394,6 +395,10 @@ public void shutdownCompleted(ShutdownSignalException cause) { } } + protected boolean shouldTriggerConnectionRecovery(ShutdownSignalException cause) { + return !cause.isInitiatedByApplication() || (cause.getCause() instanceof MissedHeartbeatException); + } + /** * Not part of the public API. Mean to be used by JVM RabbitMQ clients that build on * top of the Java client and need to be notified when server-named queue name changes From f22acbb69dce9f52465c57a1520b07f66e909008 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 23 Sep 2015 14:13:47 +0300 Subject: [PATCH 0061/2114] Ignore debug/* --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 401cc09653..7feeba8f39 100644 --- a/.gitignore +++ b/.gitignore @@ -12,8 +12,9 @@ /.idea/ /build/ /cover/ +/debug/ /dist/ /ebin/ /out/ /tmp/ -junit*.properties \ No newline at end of file +junit*.properties From 3edd47a1f58f826c8f20b240504c461dd7380c72 Mon Sep 17 00:00:00 2001 From: Yann ROBERT Date: Thu, 24 Sep 2015 15:04:18 +0200 Subject: [PATCH 0062/2114] Better use Executor#execute than ExecutorService#submit see https://github.com/rabbitmq/rabbitmq-java-client/commit/30a9603a9fb9aaf02b518670e4b1c19e1ac8953c#commitcomment-13395844 --- src/com/rabbitmq/client/impl/ChannelManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/rabbitmq/client/impl/ChannelManager.java b/src/com/rabbitmq/client/impl/ChannelManager.java index 42d03821ec..73a59d885e 100644 --- a/src/com/rabbitmq/client/impl/ChannelManager.java +++ b/src/com/rabbitmq/client/impl/ChannelManager.java @@ -120,7 +120,7 @@ public void run() { } }; if(this.shutdownExecutor != null) { - shutdownExecutor.submit(target); + shutdownExecutor.execute(target); } else { Thread shutdownThread = Environment.newThread(threadFactory, target, From 208432c62fc94bbb3a834311e01bea2602de227e Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Tue, 6 Oct 2015 21:46:29 +0300 Subject: [PATCH 0063/2114] Update dependency info to 3.5.5 --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8215aaf3a0..fb712fa298 100644 --- a/README.md +++ b/README.md @@ -14,14 +14,14 @@ Maven artifacts are [released to Maven Central](http://search.maven.org/#search% com.rabbitmq amqp-client - 3.5.1 + 3.5.5 ``` ### Gradle ``` groovy -compile 'com.rabbitmq:amqp-client:3.5.1' +compile 'com.rabbitmq:amqp-client:3.5.5' ``` From 88acf071023577f3d936cf2d30d261fa000f1f86 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 7 Oct 2015 17:04:12 +0100 Subject: [PATCH 0064/2114] Disable Maven repo close and promotion as it currently fails --- Makefile | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/Makefile b/Makefile index bf5df82554..b9723d4cd9 100644 --- a/Makefile +++ b/Makefile @@ -80,15 +80,6 @@ stage-and-promote-maven-bundle: amqp-client-$(VERSION).pom \ amqp-client-$(VERSION).jar \ amqp-client-$(VERSION)-javadoc.jar \ - amqp-client-$(VERSION)-sources.jar && \ - mvn org.sonatype.plugins:nexus-maven-plugin:$(MAVEN_NEXUS_VERSION):staging-close \ - org.sonatype.plugins:nexus-maven-plugin:$(MAVEN_NEXUS_VERSION):staging-promote \ - -Dnexus.url=http://oss.sonatype.org \ - -Dnexus.username=$$NEXUS_USERNAME \ - -Dnexus.password=$$NEXUS_PASSWORD \ - -Dnexus.promote.autoSelectOverride=true \ - -DtargetRepositoryId=releases \ - -B \ - -Dnexus.description="Public release of $$VERSION" \ + amqp-client-$(VERSION)-sources.jar \ ) From 6b893f6b429ecab87888adc10a7f8762a0046ca6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Fri, 16 Oct 2015 14:46:54 +0200 Subject: [PATCH 0065/2114] Detect UMBRELLA_AVAILABLE --- build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.xml b/build.xml index d1cee7636c..c859a43d78 100644 --- a/build.xml +++ b/build.xml @@ -120,7 +120,7 @@ - + From e7431c9c9ff16c846100b41c83ba2a988ea00f58 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Mon, 19 Oct 2015 19:01:37 +0300 Subject: [PATCH 0066/2114] Clean up exchanges, too, since the tests declare them --- .../rabbitmq/client/test/functional/AlternateExchange.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/src/com/rabbitmq/client/test/functional/AlternateExchange.java b/test/src/com/rabbitmq/client/test/functional/AlternateExchange.java index 5b908c9541..15bf090949 100644 --- a/test/src/com/rabbitmq/client/test/functional/AlternateExchange.java +++ b/test/src/com/rabbitmq/client/test/functional/AlternateExchange.java @@ -78,8 +78,10 @@ public void handleReturn(int replyCode, } @Override protected void releaseResources() throws IOException { - for (String q : resources) { - channel.queueDelete(q); + for (String r : resources) { + channel.queueDelete(r); + // declared by setupRouting + channel.exchangeDelete(r); } } From cd13e7abc438f6196da00020e44f492f24c5688c Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Mon, 19 Oct 2015 19:19:46 +0300 Subject: [PATCH 0067/2114] Clean resources before start, too Also use distinctive names. --- .../client/test/functional/DurableOnTransient.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/test/src/com/rabbitmq/client/test/functional/DurableOnTransient.java b/test/src/com/rabbitmq/client/test/functional/DurableOnTransient.java index d5bba6ac9a..3c38746d10 100644 --- a/test/src/com/rabbitmq/client/test/functional/DurableOnTransient.java +++ b/test/src/com/rabbitmq/client/test/functional/DurableOnTransient.java @@ -24,8 +24,8 @@ public class DurableOnTransient extends ClusteredTestBase { - protected static final String Q = "DurableQueue"; - protected static final String X = "TransientExchange"; + protected static final String Q = "SemiDurableBindings.DurableQueue"; + protected static final String X = "SemiDurableBindings.TransientExchange"; private GetResponse basicGet() throws IOException @@ -42,8 +42,11 @@ private void basicPublish() } protected void createResources() throws IOException { - // Transient exchange + channel.exchangeDelete(X); + // transient exchange channel.exchangeDeclare(X, "direct", false); + + channel.queueDelete(Q); // durable queue channel.queueDeclare(Q, true, false, false, null); } From 1c7ef6f432b57eeb7256c663aabe967d750a6c0a Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Mon, 19 Oct 2015 19:42:15 +0300 Subject: [PATCH 0068/2114] Be more proactive about cleaning up exchanges declared here --- .../com/rabbitmq/client/test/functional/AlternateExchange.java | 1 + 1 file changed, 1 insertion(+) diff --git a/test/src/com/rabbitmq/client/test/functional/AlternateExchange.java b/test/src/com/rabbitmq/client/test/functional/AlternateExchange.java index 15bf090949..a28ded58e0 100644 --- a/test/src/com/rabbitmq/client/test/functional/AlternateExchange.java +++ b/test/src/com/rabbitmq/client/test/functional/AlternateExchange.java @@ -98,6 +98,7 @@ public void handleReturn(int replyCode, protected void setupRouting(String name, String ae) throws IOException { Map args = new HashMap(); if (ae != null) args.put("alternate-exchange", ae); + channel.exchangeDelete(name); channel.exchangeDeclare(name, "direct", false, false, args); channel.queueBind(name, name, name); } From f6f3c23639f6945e3c569502a7260aa52ed4bc7b Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Mon, 19 Oct 2015 19:01:37 +0300 Subject: [PATCH 0069/2114] Clean up exchanges, too, since the tests declare them --- .../rabbitmq/client/test/functional/AlternateExchange.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/src/com/rabbitmq/client/test/functional/AlternateExchange.java b/test/src/com/rabbitmq/client/test/functional/AlternateExchange.java index 5b908c9541..15bf090949 100644 --- a/test/src/com/rabbitmq/client/test/functional/AlternateExchange.java +++ b/test/src/com/rabbitmq/client/test/functional/AlternateExchange.java @@ -78,8 +78,10 @@ public void handleReturn(int replyCode, } @Override protected void releaseResources() throws IOException { - for (String q : resources) { - channel.queueDelete(q); + for (String r : resources) { + channel.queueDelete(r); + // declared by setupRouting + channel.exchangeDelete(r); } } From 88ef19e6eef2879349f600fdde627f3aea28ef66 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Mon, 19 Oct 2015 19:19:46 +0300 Subject: [PATCH 0070/2114] Clean resources before start, too Also use distinctive names. --- .../client/test/functional/DurableOnTransient.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/test/src/com/rabbitmq/client/test/functional/DurableOnTransient.java b/test/src/com/rabbitmq/client/test/functional/DurableOnTransient.java index d5bba6ac9a..3c38746d10 100644 --- a/test/src/com/rabbitmq/client/test/functional/DurableOnTransient.java +++ b/test/src/com/rabbitmq/client/test/functional/DurableOnTransient.java @@ -24,8 +24,8 @@ public class DurableOnTransient extends ClusteredTestBase { - protected static final String Q = "DurableQueue"; - protected static final String X = "TransientExchange"; + protected static final String Q = "SemiDurableBindings.DurableQueue"; + protected static final String X = "SemiDurableBindings.TransientExchange"; private GetResponse basicGet() throws IOException @@ -42,8 +42,11 @@ private void basicPublish() } protected void createResources() throws IOException { - // Transient exchange + channel.exchangeDelete(X); + // transient exchange channel.exchangeDeclare(X, "direct", false); + + channel.queueDelete(Q); // durable queue channel.queueDeclare(Q, true, false, false, null); } From a26ae4b20846a91a6d4fa9f4e5a926d7017a2920 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Mon, 19 Oct 2015 19:42:15 +0300 Subject: [PATCH 0071/2114] Be more proactive about cleaning up exchanges declared here --- .../com/rabbitmq/client/test/functional/AlternateExchange.java | 1 + 1 file changed, 1 insertion(+) diff --git a/test/src/com/rabbitmq/client/test/functional/AlternateExchange.java b/test/src/com/rabbitmq/client/test/functional/AlternateExchange.java index 15bf090949..a28ded58e0 100644 --- a/test/src/com/rabbitmq/client/test/functional/AlternateExchange.java +++ b/test/src/com/rabbitmq/client/test/functional/AlternateExchange.java @@ -98,6 +98,7 @@ public void handleReturn(int replyCode, protected void setupRouting(String name, String ae) throws IOException { Map args = new HashMap(); if (ae != null) args.put("alternate-exchange", ae); + channel.exchangeDelete(name); channel.exchangeDeclare(name, "direct", false, false, args); channel.queueBind(name, name, name); } From 8e69b7073dfe3ed59af877e8eb5bdd48cd57e85d Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Tue, 20 Oct 2015 11:11:34 +0300 Subject: [PATCH 0072/2114] Makes semi-durable bindings test idempotent (fo realz) --- .../com/rabbitmq/client/test/functional/DurableOnTransient.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/src/com/rabbitmq/client/test/functional/DurableOnTransient.java b/test/src/com/rabbitmq/client/test/functional/DurableOnTransient.java index 3c38746d10..088781e904 100644 --- a/test/src/com/rabbitmq/client/test/functional/DurableOnTransient.java +++ b/test/src/com/rabbitmq/client/test/functional/DurableOnTransient.java @@ -66,7 +66,9 @@ public void testBindDurableToTransient() public void testSemiDurableBindingRemoval() throws IOException { if (clusteredConnection != null) { + deleteExchange("x"); declareTransientTopicExchange("x"); + clusteredChannel.queueDelete("q"); clusteredChannel.queueDeclare("q", true, false, false, null); channel.queueBind("q", "x", "k"); From 912921a8c3eff34b945cfe23f02319eeb86a488a Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Tue, 20 Oct 2015 11:11:34 +0300 Subject: [PATCH 0073/2114] Makes semi-durable bindings test idempotent (fo realz) --- .../com/rabbitmq/client/test/functional/DurableOnTransient.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/src/com/rabbitmq/client/test/functional/DurableOnTransient.java b/test/src/com/rabbitmq/client/test/functional/DurableOnTransient.java index 3c38746d10..088781e904 100644 --- a/test/src/com/rabbitmq/client/test/functional/DurableOnTransient.java +++ b/test/src/com/rabbitmq/client/test/functional/DurableOnTransient.java @@ -66,7 +66,9 @@ public void testBindDurableToTransient() public void testSemiDurableBindingRemoval() throws IOException { if (clusteredConnection != null) { + deleteExchange("x"); declareTransientTopicExchange("x"); + clusteredChannel.queueDelete("q"); clusteredChannel.queueDeclare("q", true, false, false, null); channel.queueBind("q", "x", "k"); From a16c0e4e201ad7096ba232c13f7daa3a7258e69e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Thu, 22 Oct 2015 19:04:50 +0200 Subject: [PATCH 0074/2114] Revert "Detect UMBRELLA_AVAILABLE" This reverts commit 6b893f6b429ecab87888adc10a7f8762a0046ca6. --- build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.xml b/build.xml index c859a43d78..d1cee7636c 100644 --- a/build.xml +++ b/build.xml @@ -120,7 +120,7 @@ - + From 0ebe51f93bad44c52893e3e283c42d0426713795 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Fri, 16 Oct 2015 14:46:54 +0200 Subject: [PATCH 0075/2114] Detect UMBRELLA_AVAILABLE --- build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.xml b/build.xml index d1cee7636c..c859a43d78 100644 --- a/build.xml +++ b/build.xml @@ -120,7 +120,7 @@ - + From 0d1b2bd0e84b8f77b2f62d4ee90983458baef02d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Fri, 23 Oct 2015 16:02:08 +0200 Subject: [PATCH 0076/2114] Use Java properties instead of environment variables Those properties' default values assume an erlang.mk file layout. As this is true almost always, one can still run "ant $target" to run the testsuite. rabbitmq-test will set those properties to point to the configured paths. --- build.properties | 4 +++- build.xml | 22 +++++++++++++++++-- codegen.py | 2 +- test/src/com/rabbitmq/tools/Host.java | 31 +++------------------------ 4 files changed, 27 insertions(+), 32 deletions(-) diff --git a/build.properties b/build.properties index b113e0e832..6d48519aff 100644 --- a/build.properties +++ b/build.properties @@ -12,7 +12,9 @@ javac.out=${build.out}/classes javadoc.out=build/doc/api lib.out=${build.out}/lib python.bin=python -sibling.codegen.dir=../rabbitmq-codegen/ +sibling.codegen.dir=../rabbitmq_codegen +sibling.rabbitmq_test.dir=../rabbitmq_test +rabbitmqctl.bin=../rabbit/scripts/rabbitmqctl spec.version=0.9.1 src.generated=${build.out}/gensrc standard.javac.source=1.6 diff --git a/build.xml b/build.xml index c859a43d78..0b5cc50339 100644 --- a/build.xml +++ b/build.xml @@ -4,6 +4,7 @@ + @@ -111,7 +112,6 @@ - @@ -124,7 +124,6 @@ - @@ -183,6 +182,10 @@ + + + + @@ -334,6 +337,10 @@ failureproperty="test.failure" fork="yes"> + + + + @@ -354,6 +361,9 @@ failureproperty="test.failure" fork="yes"> + + + @@ -367,6 +377,10 @@ failureproperty="test.failure" fork="yes"> + + + + + + + + diff --git a/codegen.py b/codegen.py index fe7db666dd..1ff058d537 100644 --- a/codegen.py +++ b/codegen.py @@ -18,7 +18,7 @@ import re import sys -sys.path.append("../rabbitmq-codegen") # in case we're next to an experimental revision +sys.path.append("../rabbitmq_codegen") # in case we're next to an experimental revision sys.path.append("codegen") # in case we're building from a distribution package from amqp_codegen import * diff --git a/test/src/com/rabbitmq/tools/Host.java b/test/src/com/rabbitmq/tools/Host.java index 36e8e620ce..61d89c1366 100644 --- a/test/src/com/rabbitmq/tools/Host.java +++ b/test/src/com/rabbitmq/tools/Host.java @@ -106,42 +106,17 @@ public static Process invokeMakeTarget(String command) throws IOException { private static String makeCommand() { - // Get the make(1) executable to use from the environment: - // make(1) provides the path to itself in $MAKE. - String makecmd = System.getenv("MAKE"); - - // Default to "make" if the environment variable is unset. - if (makecmd == null) { - makecmd = "make"; - } - - return makecmd; + return System.getProperty("make.bin"); } private static String rabbitmqctlCommand() { - // Get the rabbitmqctl(1) executable to use from the environment. - String cmd = System.getenv("RABBITMQCTL"); - - // Default to "make" if the environment variable is unset. - if (cmd == null) { - cmd = "../rabbitmq-server/scripts/rabbitmqctl"; - } - - return cmd; + return System.getProperty("rabbitmqctl.bin"); } private static String rabbitmqTestDir() { - // Get the rabbitmq-test directory to use from the environment. - String dir = System.getenv("RABBITMQ_TEST_DIR"); - - // Default to "make" if the environment variable is unset. - if (dir == null) { - dir = "../rabbitmq-test"; - } - - return dir; + return System.getProperty("sibling.rabbitmq_test.dir"); } public static void closeConnection(String pid) throws IOException { From ef5dd87047a94f2252dd7811139ca66b08beb3dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Fri, 6 Nov 2015 11:08:53 +0100 Subject: [PATCH 0077/2114] Makefile: Use $(MAKE) instead of hardcoding `make` --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ad551a22c7..81b339ae37 100644 --- a/Makefile +++ b/Makefile @@ -23,7 +23,7 @@ clean: $(ANT) $(ANT_FLAGS) clean distclean: clean - make -C $(AMQP_CODEGEN_DIR) clean + $(MAKE) -C $(AMQP_CODEGEN_DIR) clean dist: distclean srcdist dist_all maven-bundle From e9bac89869309842c46d483a953400e9bc53eedf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Fri, 6 Nov 2015 11:18:18 +0100 Subject: [PATCH 0078/2114] make srcdist: Allow the caller to provide build-java.html by its own mean --- Makefile | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 81b339ae37..d31154f983 100644 --- a/Makefile +++ b/Makefile @@ -63,8 +63,14 @@ srcdist: distclean if [ -f README.in ]; then \ cp README.in build/$(SRC_ARCHIVE)/README; \ - elinks -dump -no-references -no-numbering $(WEB_URL)build-java-client.html \ - >> build/$(SRC_ARCHIVE)/README; \ + if [ -f build-java-client.txt ]; then \ + cat build-java-client.txt \ + >> build/$(SRC_ARCHIVE)/README; \ + else \ + elinks -dump -no-references -no-numbering \ + $(WEB_URL)build-java-client.html \ + >> build/$(SRC_ARCHIVE)/README; \ + fi; \ fi (cd build; tar -zcf $(SRC_ARCHIVE).tar.gz $(SRC_ARCHIVE)) (cd build; zip -q -r $(SRC_ARCHIVE).zip $(SRC_ARCHIVE)) From 4e062b0ea2c8e1a99f78abb6c8d1e5ea09262eac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Fri, 6 Nov 2015 15:47:49 +0000 Subject: [PATCH 0079/2114] Use $(BUILD_DOC) to set the path to build-java-client.txt --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index d31154f983..629245a07e 100644 --- a/Makefile +++ b/Makefile @@ -63,8 +63,8 @@ srcdist: distclean if [ -f README.in ]; then \ cp README.in build/$(SRC_ARCHIVE)/README; \ - if [ -f build-java-client.txt ]; then \ - cat build-java-client.txt \ + if [ -f "$(BUILD_DOC)" ]; then \ + cat "$(BUILD_DOC)" \ >> build/$(SRC_ARCHIVE)/README; \ else \ elinks -dump -no-references -no-numbering \ From 473a928a12d9f9cfe6c92562d43af09c7d1284ef Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Thu, 19 Nov 2015 18:57:23 +0300 Subject: [PATCH 0080/2114] Shorter (and to the point) bundle.name --- build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.properties b/build.properties index 6d48519aff..21ba4ff08a 100644 --- a/build.properties +++ b/build.properties @@ -1,7 +1,7 @@ alt.javac.source=1.6 alt.javac.target=1.6 build.out=build -bundle.name=RabbitMQ Java AMQP client library +bundle.name=RabbitMQ client library bundle.out=${build.out}/bundle bundle.symbolicName=com.rabbitmq.client bundlor.home=bundlor From 0c6bf3fefc682185f2e8ee9ee088dbbfab47efe7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Thu, 19 Nov 2015 17:49:36 +0100 Subject: [PATCH 0081/2114] In the testsuite, pass $RABBITMQCTL to sub-makes explicitely --- test/src/com/rabbitmq/tools/Host.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/src/com/rabbitmq/tools/Host.java b/test/src/com/rabbitmq/tools/Host.java index 61d89c1366..7944a3cbd9 100644 --- a/test/src/com/rabbitmq/tools/Host.java +++ b/test/src/com/rabbitmq/tools/Host.java @@ -20,6 +20,7 @@ import com.rabbitmq.client.impl.NetworkConnection; import java.io.BufferedReader; +import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -101,7 +102,11 @@ public static Process rabbitmqctlIgnoreErrors(String command) throws IOException } public static Process invokeMakeTarget(String command) throws IOException { - return executeCommand("cd " + rabbitmqTestDir() + "; " + makeCommand() + " " + command); + File rabbitmqctl = new File(rabbitmqctlCommand()); + return executeCommand(makeCommand() + + " -C \'" + rabbitmqTestDir() + "\'" + + " RABBITMQCTL=\'" + rabbitmqctl.getAbsolutePath() + "\'" + + " " + command); } private static String makeCommand() From 98ad4d7c7e0bcb44a74ebef23545adf1e65009fc Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 20 Nov 2015 02:47:58 +0300 Subject: [PATCH 0082/2114] Remove outdated comment (from 2010) --- .../src/com/rabbitmq/client/test/functional/SaslMechanisms.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/src/com/rabbitmq/client/test/functional/SaslMechanisms.java b/test/src/com/rabbitmq/client/test/functional/SaslMechanisms.java index b8b510ed0c..d9b83d24d3 100644 --- a/test/src/com/rabbitmq/client/test/functional/SaslMechanisms.java +++ b/test/src/com/rabbitmq/client/test/functional/SaslMechanisms.java @@ -70,8 +70,6 @@ public SaslMechanism getSaslMechanism(String[] mechanisms) { } } - // TODO test gibberish examples. ATM the server is not very robust. - public void testPlainLogin() throws IOException, TimeoutException { loginOk("PLAIN", new byte[][] {"\0guest\0guest".getBytes()} ); loginBad("PLAIN", new byte[][] {"\0guest\0wrong".getBytes()} ); From cec545424fdbab73d20c0f57cdce9489dd5e8bfb Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 20 Nov 2015 03:48:52 +0300 Subject: [PATCH 0083/2114] Fixes #105 --- .../rabbitmq/client/impl/recovery/AutorecoveringChannel.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java b/src/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java index be24390477..53dca98056 100644 --- a/src/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java +++ b/src/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java @@ -378,7 +378,9 @@ public String basicConsume(String queue, boolean autoAck, String consumerTag, bo public void basicCancel(String consumerTag) throws IOException { RecordedConsumer c = this.deleteRecordedConsumer(consumerTag); - this.maybeDeleteRecordedAutoDeleteQueue(c.getQueue()); + if(c != null) { + this.maybeDeleteRecordedAutoDeleteQueue(c.getQueue()); + } delegate.basicCancel(consumerTag); } From c5fa8eb74231172c0ba635a1a26efa801a157aa1 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 2 Dec 2015 11:05:42 +0300 Subject: [PATCH 0084/2114] Clarify some PerfTest option descriptions Per feedback from folks at Pivotal. --- test/src/com/rabbitmq/examples/PerfTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/src/com/rabbitmq/examples/PerfTest.java b/test/src/com/rabbitmq/examples/PerfTest.java index e7caf63038..19254d9600 100644 --- a/test/src/com/rabbitmq/examples/PerfTest.java +++ b/test/src/com/rabbitmq/examples/PerfTest.java @@ -136,13 +136,13 @@ private static void usage(Options options) { private static Options getOptions() { Options options = new Options(); options.addOption(new Option("?", "help", false,"show usage")); - options.addOption(new Option("h", "uri", true, "AMQP URI")); + options.addOption(new Option("h", "uri", true, "connection URI")); options.addOption(new Option("t", "type", true, "exchange type")); options.addOption(new Option("e", "exchange", true, "exchange name")); options.addOption(new Option("u", "queue", true, "queue name")); options.addOption(new Option("k", "routingKey", true, "routing key")); options.addOption(new Option("K", "randomRoutingKey", false,"use random routing key per message")); - options.addOption(new Option("i", "interval", true, "sampling interval")); + options.addOption(new Option("i", "interval", true, "sampling interval in seconds")); options.addOption(new Option("r", "rate", true, "producer rate limit")); options.addOption(new Option("R", "consumerRate", true, "consumer rate limit")); options.addOption(new Option("x", "producers", true, "producer count")); @@ -154,8 +154,8 @@ private static Options getOptions() { options.addOption(new Option("A", "multiAckEvery", true, "multi ack every")); options.addOption(new Option("q", "qos", true, "consumer prefetch count")); options.addOption(new Option("Q", "globalQos", true, "channel prefetch count")); - options.addOption(new Option("s", "size", true, "message size")); - options.addOption(new Option("z", "time", true, "time limit")); + options.addOption(new Option("s", "size", true, "message size in bytes")); + options.addOption(new Option("z", "time", true, "run duration in seconds (unlimited by default)")); options.addOption(new Option("C", "pmessages", true, "producer message count")); options.addOption(new Option("D", "cmessages", true, "consumer message count")); Option flag = new Option("f", "flag", true, "message flag"); From cf5fbb5fe658959d06e61de4ca5b0ddfb884426b Mon Sep 17 00:00:00 2001 From: Gabriele Santomaggio Date: Thu, 3 Dec 2015 17:25:14 +0100 Subject: [PATCH 0085/2114] modified heartbeat to 60 seconds --- src/com/rabbitmq/client/ConnectionFactory.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/com/rabbitmq/client/ConnectionFactory.java b/src/com/rabbitmq/client/ConnectionFactory.java index e8f7af75d6..8bc16876cf 100644 --- a/src/com/rabbitmq/client/ConnectionFactory.java +++ b/src/com/rabbitmq/client/ConnectionFactory.java @@ -60,8 +60,8 @@ public class ConnectionFactory implements Cloneable { * zero means no limit */ public static final int DEFAULT_FRAME_MAX = 0; /** Default heart-beat interval; - * zero means no heart-beats */ - public static final int DEFAULT_HEARTBEAT = 0; + * 60 seconds */ + public static final int DEFAULT_HEARTBEAT = 60; /** The default host */ public static final String DEFAULT_HOST = "localhost"; /** 'Use the default port' port */ From fadb7461a7f4fe0fdb2d68deee46d9340f42391d Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Sat, 5 Dec 2015 14:15:37 +0300 Subject: [PATCH 0086/2114] Default (TCP) connection timeout is now 60s --- src/com/rabbitmq/client/ConnectionFactory.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/com/rabbitmq/client/ConnectionFactory.java b/src/com/rabbitmq/client/ConnectionFactory.java index 8bc16876cf..0654ee6360 100644 --- a/src/com/rabbitmq/client/ConnectionFactory.java +++ b/src/com/rabbitmq/client/ConnectionFactory.java @@ -70,9 +70,8 @@ public class ConnectionFactory implements Cloneable { public static final int DEFAULT_AMQP_PORT = AMQP.PROTOCOL.PORT; /** The default ssl port */ public static final int DEFAULT_AMQP_OVER_SSL_PORT = 5671; - /** The default TCP connection timeout; - * zero means wait indefinitely */ - public static final int DEFAULT_CONNECTION_TIMEOUT = 0; + /** The default TCP connection timeout: 60 seconds */ + public static final int DEFAULT_CONNECTION_TIMEOUT = 60000; /** * The default AMQP 0-9-1 connection handshake timeout. See DEFAULT_CONNECTION_TIMEOUT * for TCP (socket) connection timeout. From fbd0d9e270539b59ef79795337c20d0b77509f3e Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Sun, 13 Dec 2015 02:22:10 +0300 Subject: [PATCH 0087/2114] Basic priority queue test References rabbitmq/rabbitmq-server#448. --- .../client/test/server/PriorityQueues.java | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 test/src/com/rabbitmq/client/test/server/PriorityQueues.java diff --git a/test/src/com/rabbitmq/client/test/server/PriorityQueues.java b/test/src/com/rabbitmq/client/test/server/PriorityQueues.java new file mode 100644 index 0000000000..3aec1357f6 --- /dev/null +++ b/test/src/com/rabbitmq/client/test/server/PriorityQueues.java @@ -0,0 +1,68 @@ +package com.rabbitmq.client.test.server; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.DefaultConsumer; +import com.rabbitmq.client.Envelope; +import com.rabbitmq.client.test.BrokerTestCase; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class PriorityQueues extends BrokerTestCase { + public void testPrioritisingBasics() throws IOException, TimeoutException, InterruptedException { + String q = "with-3-priorities"; + int n = 3; + channel.queueDeclare(q, true, false, false, argsWithPriorities(n)); + publishWithPriorities(q, n); + + List xs = prioritiesOfEnqueuedMessages(q, n); + assertEquals(Integer.valueOf(3), xs.get(0)); + assertEquals(Integer.valueOf(2), xs.get(1)); + assertEquals(Integer.valueOf(1), xs.get(2)); + + channel.queueDelete(q); + } + + private List prioritiesOfEnqueuedMessages(String q, int n) throws InterruptedException, IOException { + final List xs = new ArrayList(); + final CountDownLatch latch = new CountDownLatch(n); + + channel.basicConsume(q, true, new DefaultConsumer(channel) { + @Override + public void handleDelivery(String consumerTag, Envelope envelope, + AMQP.BasicProperties properties, byte[] body) throws IOException { + xs.add(properties.getPriority()); + latch.countDown(); + } + }); + + latch.await(5, TimeUnit.SECONDS); + return xs; + } + + private void publishWithPriorities(String q, int n) throws IOException, TimeoutException, InterruptedException { + channel.confirmSelect(); + for (int i = 1; i <= n; i++) { + channel.basicPublish("", q, propsWithPriority(i), "msg".getBytes("UTF-8")); + } + channel.waitForConfirms(500); + } + + private AMQP.BasicProperties propsWithPriority(int n) { + return (new AMQP.BasicProperties.Builder()) + .priority(n) + .build(); + } + + private Map argsWithPriorities(int n) { + Map m = new HashMap(); + m.put("x-max-priority", n); + return m; + } +} From 1523251b7f233fb24adb968be18b156a840bbfb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Fri, 18 Dec 2015 15:27:03 +0100 Subject: [PATCH 0088/2114] Make codegen.py work with Python 3 References rabbitmq/rabbitmq-common#36. --- codegen.py | 428 +++++++++++++++++++++++++++-------------------------- 1 file changed, 215 insertions(+), 213 deletions(-) diff --git a/codegen.py b/codegen.py index 1ff058d537..1f9e59a618 100644 --- a/codegen.py +++ b/codegen.py @@ -15,6 +15,8 @@ ## from __future__ import nested_scopes +from __future__ import print_function + import re import sys @@ -127,7 +129,7 @@ def nullCheckedFields(spec, m): #--------------------------------------------------------------------------- def printFileHeader(): - print """// NOTE: This -*- java -*- source code is autogenerated from the AMQP + print("""// NOTE: This -*- java -*- source code is autogenerated from the AMQP // specification! // // The contents of this file are subject to the Mozilla Public License @@ -145,233 +147,233 @@ def printFileHeader(): // The Initial Developer of the Original Code is GoPivotal, Inc. // Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. // -""" +""") def genJavaApi(spec): def printHeader(): printFileHeader() - print "package com.rabbitmq.client;" - print - print "import java.io.DataInputStream;" - print "import java.io.IOException;" - print "import java.util.Collections;" - print "import java.util.HashMap;" - print "import java.util.Map;" - print "import java.util.Date;" - print - print "import com.rabbitmq.client.impl.ContentHeaderPropertyWriter;" - print "import com.rabbitmq.client.impl.ContentHeaderPropertyReader;" - print "import com.rabbitmq.client.impl.LongStringHelper;" + print("package com.rabbitmq.client;") + print() + print("import java.io.DataInputStream;") + print("import java.io.IOException;") + print("import java.util.Collections;") + print("import java.util.HashMap;") + print("import java.util.Map;") + print("import java.util.Date;") + print() + print("import com.rabbitmq.client.impl.ContentHeaderPropertyWriter;") + print("import com.rabbitmq.client.impl.ContentHeaderPropertyReader;") + print("import com.rabbitmq.client.impl.LongStringHelper;") def printProtocolClass(): - print - print " public static class PROTOCOL {" - print " public static final int MAJOR = %i;" % spec.major - print " public static final int MINOR = %i;" % spec.minor - print " public static final int REVISION = %i;" % spec.revision - print " public static final int PORT = %i;" % spec.port - print " }" + print() + print(" public static class PROTOCOL {") + print(" public static final int MAJOR = %i;" % spec.major) + print(" public static final int MINOR = %i;" % spec.minor) + print(" public static final int REVISION = %i;" % spec.revision) + print(" public static final int PORT = %i;" % spec.port) + print(" }") def printConstants(): - print - for (c,v,cls) in spec.constants: print " public static final int %s = %i;" % (java_constant_name(c), v) + print() + for (c,v,cls) in spec.constants: print(" public static final int %s = %i;" % (java_constant_name(c), v)) def builder(c,m): def ctorCall(c,m): ctor_call = "com.rabbitmq.client.impl.AMQImpl.%s.%s" % (java_class_name(c.name),java_class_name(m.name)) ctor_arg_list = [ java_field_name(a.name) for a in m.arguments ] - print " return new %s(%s);" % (ctor_call, ", ".join(ctor_arg_list)) + print(" return new %s(%s);" % (ctor_call, ", ".join(ctor_arg_list))) def genFields(spec, m): for a in m.arguments: (jfType, jfName, jfDefault) = typeNameDefault(spec, a) if a.defaultvalue != None: - print " private %s %s = %s;" % (jfType, jfName, jfDefault) + print(" private %s %s = %s;" % (jfType, jfName, jfDefault)) else: - print " private %s %s;" % (jfType, jfName) + print(" private %s %s;" % (jfType, jfName)) def genArgMethods(spec, m): for a in m.arguments: (jfType, jfName, jfDefault) = typeNameDefault(spec, a) - print " public Builder %s(%s %s)" % (jfName, jfType, jfName) - print " { this.%s = %s; return this; }" % (jfName, jfName) + print(" public Builder %s(%s %s)" % (jfName, jfType, jfName)) + print(" { this.%s = %s; return this; }" % (jfName, jfName)) if jfType == "boolean": - print " public Builder %s()" % (jfName) - print " { return this.%s(true); }" % (jfName) + print(" public Builder %s()" % (jfName)) + print(" { return this.%s(true); }" % (jfName)) elif jfType == "LongString": - print " public Builder %s(String %s)" % (jfName, jfName) - print " { return this.%s(LongStringHelper.asLongString(%s)); }" % (jfName, jfName) + print(" public Builder %s(String %s)" % (jfName, jfName)) + print(" { return this.%s(LongStringHelper.asLongString(%s)); }" % (jfName, jfName)) def genBuildMethod(c,m): - print " public %s build() {" % (java_class_name(m.name)) + print(" public %s build() {" % (java_class_name(m.name))) ctorCall(c,m) - print " }" + print(" }") - print - print " // Builder for instances of %s.%s" % (java_class_name(c.name), java_class_name(m.name)) - print " public static final class Builder" - print " {" + print() + print(" // Builder for instances of %s.%s" % (java_class_name(c.name), java_class_name(m.name))) + print(" public static final class Builder") + print(" {") genFields(spec, m) - print - print " public Builder() { }" - print + print() + print(" public Builder() { }") + print() genArgMethods(spec, m) genBuildMethod(c,m) - print " }" + print(" }") def printClassInterfaces(): for c in spec.classes: - print - print " public static class %s {" % (java_class_name(c.name)) + print() + print(" public static class %s {" % (java_class_name(c.name))) for m in c.allMethods(): - print " public interface %s extends Method {" % ((java_class_name(m.name))) + print(" public interface %s extends Method {" % ((java_class_name(m.name)))) for a in m.arguments: - print " %s %s();" % (java_field_type(spec, a.domain), java_getter_name(a.name)) + print(" %s %s();" % (java_field_type(spec, a.domain), java_getter_name(a.name))) builder(c,m) - print " }" - print " }" + print(" }") + print(" }") def printReadProperties(c): if c.fields: for f in c.fields: - print " boolean %s_present = reader.readPresence();" % (java_field_name(f.name)) - print + print(" boolean %s_present = reader.readPresence();" % (java_field_name(f.name))) + print() - print " reader.finishPresence();" + print(" reader.finishPresence();") if c.fields: - print + print() for f in c.fields: (jfName, jfClass) = (java_field_name(f.name), java_class_name(f.domain)) - print " this.%s = %s_present ? reader.read%s() : null;" % (jfName, jfName, jfClass) + print(" this.%s = %s_present ? reader.read%s() : null;" % (jfName, jfName, jfClass)) def printWritePropertiesTo(c): - print - print " public void writePropertiesTo(ContentHeaderPropertyWriter writer)" - print " throws IOException" - print " {" + print() + print(" public void writePropertiesTo(ContentHeaderPropertyWriter writer)") + print(" throws IOException") + print(" {") if c.fields: for f in c.fields: - print " writer.writePresence(this.%s != null);" % (java_field_name(f.name)) - print - print " writer.finishPresence();" + print(" writer.writePresence(this.%s != null);" % (java_field_name(f.name))) + print() + print(" writer.finishPresence();") if c.fields: - print + print() for f in c.fields: (jfName, jfClass) = (java_field_name(f.name), java_class_name(f.domain)) - print " if (this.%s != null) writer.write%s(this.%s);" % (jfName, jfClass, jfName) - print " }" + print(" if (this.%s != null) writer.write%s(this.%s);" % (jfName, jfClass, jfName)) + print(" }") def printAppendPropertyDebugStringTo(c): appendList = [ "%s=\")\n .append(this.%s)\n .append(\"" % (f.name, java_field_name(f.name)) for f in c.fields ] - print - print " public void appendPropertyDebugStringTo(StringBuilder acc) {" - print " acc.append(\"(%s)\");" % (", ".join(appendList)) - print " }" + print() + print(" public void appendPropertyDebugStringTo(StringBuilder acc) {") + print(" acc.append(\"(%s)\");" % (", ".join(appendList))) + print(" }") def printPropertiesBuilderClass(c): def printBuilderSetter(fieldType, fieldName): - print " public Builder %s(%s %s)" % (fieldName, java_boxed_type(fieldType), fieldName) - print " { this.%s = %s; return this; }" % (fieldName, fieldName) + print(" public Builder %s(%s %s)" % (fieldName, java_boxed_type(fieldType), fieldName)) + print(" { this.%s = %s; return this; }" % (fieldName, fieldName)) if fieldType == "boolean": - print " public Builder %s()" % (fieldName) - print " { return this.%s(true); }" % (fieldName) + print(" public Builder %s()" % (fieldName)) + print(" { return this.%s(true); }" % (fieldName)) elif fieldType == "LongString": - print " public Builder %s(String %s)" % (fieldName, fieldName) - print " { return this.%s(LongStringHelper.asLongString(%s)); }" % (fieldName, fieldName) + print(" public Builder %s(String %s)" % (fieldName, fieldName)) + print(" { return this.%s(LongStringHelper.asLongString(%s)); }" % (fieldName, fieldName)) - print - print " public static final class Builder {" + print() + print(" public static final class Builder {") # fields for f in c.fields: (fType, fName) = (java_field_type(spec, f.domain), java_field_name(f.name)) - print " private %s %s;" % (java_boxed_type(fType), fName) + print(" private %s %s;" % (java_boxed_type(fType), fName)) # ctor - print - print " public Builder() {};" + print() + print(" public Builder() {};") # setters - print + print() for f in c.fields: printBuilderSetter(java_field_type(spec, f.domain), java_field_name(f.name)) - print + print() jClassName = java_class_name(c.name) # build() objName = "%sProperties" % (jClassName) ctor_parm_list = [ java_field_name(f.name) for f in c.fields ] - print " public %s build() {" % (objName) - print " return new %s" % (objName) - print " ( %s" % ("\n , ".join(ctor_parm_list)) - print " );" - print " }" + print(" public %s build() {" % (objName)) + print(" return new %s" % (objName)) + print(" ( %s" % ("\n , ".join(ctor_parm_list))) + print(" );") + print(" }") - print " }" + print(" }") def printPropertiesBuilder(c): - print - print " public Builder builder() {" - print " Builder builder = new Builder()" + print() + print(" public Builder builder() {") + print(" Builder builder = new Builder()") setFieldList = [ "%s(%s)" % (fn, fn) for fn in [ java_field_name(f.name) for f in c.fields ] ] - print " .%s;" % ("\n .".join(setFieldList)) - print " return builder;" - print " }" + print(" .%s;" % ("\n .".join(setFieldList))) + print(" return builder;") + print(" }") def printPropertiesClass(c): def printGetter(fieldType, fieldName): capFieldName = fieldName[0].upper() + fieldName[1:] - print " public %s get%s() { return this.%s; }" % (java_boxed_type(fieldType), capFieldName, fieldName) + print(" public %s get%s() { return this.%s; }" % (java_boxed_type(fieldType), capFieldName, fieldName)) jClassName = java_class_name(c.name) - print - print " public static class %sProperties extends com.rabbitmq.client.impl.AMQ%sProperties {" % (jClassName, jClassName) + print() + print(" public static class %sProperties extends com.rabbitmq.client.impl.AMQ%sProperties {" % (jClassName, jClassName)) #property fields for f in c.fields: (fType, fName) = (java_boxed_type(java_field_type(spec, f.domain)), java_field_name(f.name)) - print " private %s %s;" % (fType, fName) + print(" private %s %s;" % (fType, fName)) #explicit constructor if c.fields: - print + print() consParmList = [ "%s %s" % (java_boxed_type(java_field_type(spec,f.domain)), java_field_name(f.name)) for f in c.fields ] - print " public %sProperties(" % (jClassName) - print " %s)" % (",\n ".join(consParmList)) - print " {" + print(" public %sProperties(" % (jClassName)) + print(" %s)" % (",\n ".join(consParmList))) + print(" {") for f in c.fields: (fType, fName) = (java_field_type(spec, f.domain), java_field_name(f.name)) if fType == "Map": - print " this.%s = %s==null ? null : Collections.unmodifiableMap(new HashMap(%s));" % (fName, fName, fName) + print(" this.%s = %s==null ? null : Collections.unmodifiableMap(new HashMap(%s));" % (fName, fName, fName)) else: - print " this.%s = %s;" % (fName, fName) - print " }" + print(" this.%s = %s;" % (fName, fName)) + print(" }") #datainputstream constructor - print - print " public %sProperties(DataInputStream in) throws IOException {" % (jClassName) - print " super(in);" - print " ContentHeaderPropertyReader reader = new ContentHeaderPropertyReader(in);" - + print() + print(" public %sProperties(DataInputStream in) throws IOException {" % (jClassName)) + print(" super(in);") + print(" ContentHeaderPropertyReader reader = new ContentHeaderPropertyReader(in);") + printReadProperties(c) - - print " }" + + print(" }") # default constructor - print " public %sProperties() {}" % (jClassName) + print(" public %sProperties() {}" % (jClassName)) #class properties - print " public int getClassId() { return %i; }" % (c.index) - print " public String getClassName() { return \"%s\"; }" % (c.name) + print(" public int getClassId() { return %i; }" % (c.index)) + print(" public String getClassName() { return \"%s\"; }" % (c.name)) printPropertiesBuilder(c) - + #accessor methods - print + print() for f in c.fields: (jType, jName) = (java_field_type(spec, f.domain), java_field_name(f.name)) printGetter(jType, jName) @@ -380,7 +382,7 @@ def printGetter(fieldType, fieldName): printAppendPropertyDebugStringTo(c) printPropertiesBuilderClass(c) - print " }" + print(" }") def printPropertiesClasses(): for c in spec.classes: @@ -388,81 +390,81 @@ def printPropertiesClasses(): printPropertiesClass(c) printHeader() - print - print "public interface AMQP {" + print() + print("public interface AMQP {") printProtocolClass() printConstants() printClassInterfaces() printPropertiesClasses() - print "}" + print("}") #-------------------------------------------------------------------------------- def genJavaImpl(spec): def printHeader(): printFileHeader() - print "package com.rabbitmq.client.impl;" - print - print "import java.io.IOException;" - print "import java.io.DataInputStream;" - print "import java.util.Collections;" - print "import java.util.HashMap;" - print "import java.util.Map;" - print - print "import com.rabbitmq.client.AMQP;" - print "import com.rabbitmq.client.LongString;" - print "import com.rabbitmq.client.UnknownClassOrMethodId;" - print "import com.rabbitmq.client.UnexpectedMethodError;" + print("package com.rabbitmq.client.impl;") + print() + print("import java.io.IOException;") + print("import java.io.DataInputStream;") + print("import java.util.Collections;") + print("import java.util.HashMap;") + print("import java.util.Map;") + print() + print("import com.rabbitmq.client.AMQP;") + print("import com.rabbitmq.client.LongString;") + print("import com.rabbitmq.client.UnknownClassOrMethodId;") + print("import com.rabbitmq.client.UnexpectedMethodError;") def printClassMethods(spec, c): - print - print " public static class %s {" % (java_class_name(c.name)) - print " public static final int INDEX = %s;" % (c.index) + print() + print(" public static class %s {" % (java_class_name(c.name))) + print(" public static final int INDEX = %s;" % (c.index)) for m in c.allMethods(): def getters(): if m.arguments: - print + print() for a in m.arguments: - print " public %s %s() { return %s; }" % (java_field_type(spec,a.domain), java_getter_name(a.name), java_field_name(a.name)) + print(" public %s %s() { return %s; }" % (java_field_type(spec,a.domain), java_getter_name(a.name), java_field_name(a.name))) def constructors(): - print + print() argList = [ "%s %s" % (java_field_type(spec,a.domain),java_field_name(a.name)) for a in m.arguments ] - print " public %s(%s) {" % (java_class_name(m.name), ", ".join(argList)) + print(" public %s(%s) {" % (java_class_name(m.name), ", ".join(argList))) fieldsToNullCheckInCons = nullCheckedFields(spec, m) for f in fieldsToNullCheckInCons: - print " if (%s == null)" % (f) - print " throw new IllegalStateException(\"Invalid configuration: '%s' must be non-null.\");" % (f) + print(" if (%s == null)" % (f)) + print(" throw new IllegalStateException(\"Invalid configuration: '%s' must be non-null.\");" % (f)) for a in m.arguments: (jfType, jfName) = (java_field_type(spec, a.domain), java_field_name(a.name)) if jfType == "Map": - print " this.%s = %s==null ? null : Collections.unmodifiableMap(new HashMap(%s));" % (jfName, jfName, jfName) + print(" this.%s = %s==null ? null : Collections.unmodifiableMap(new HashMap(%s));" % (jfName, jfName, jfName)) else: - print " this.%s = %s;" % (jfName, jfName) + print(" this.%s = %s;" % (jfName, jfName)) - print " }" + print(" }") consArgs = [ "rdr.read%s()" % (java_class_name(spec.resolveDomain(a.domain))) for a in m.arguments ] - print " public %s(MethodArgumentReader rdr) throws IOException {" % (java_class_name(m.name)) - print " this(%s);" % (", ".join(consArgs)) - print " }" + print(" public %s(MethodArgumentReader rdr) throws IOException {" % (java_class_name(m.name))) + print(" this(%s);" % (", ".join(consArgs))) + print(" }") def others(): - print - print " public int protocolClassId() { return %s; }" % (c.index) - print " public int protocolMethodId() { return %s; }" % (m.index) - print " public String protocolMethodName() { return \"%s.%s\";}" % (c.name, m.name) - print - print " public boolean hasContent() { return %s; }" % (trueOrFalse(m.hasContent)) - print - print " public Object visit(MethodVisitor visitor) throws IOException" - print " { return visitor.visit(this); }" + print() + print(" public int protocolClassId() { return %s; }" % (c.index)) + print(" public int protocolMethodId() { return %s; }" % (m.index)) + print(" public String protocolMethodName() { return \"%s.%s\";}" % (c.name, m.name)) + print() + print(" public boolean hasContent() { return %s; }" % (trueOrFalse(m.hasContent))) + print() + print(" public Object visit(MethodVisitor visitor) throws IOException") + print(" { return visitor.visit(this); }") def trueOrFalse(truthVal): if truthVal: @@ -474,30 +476,30 @@ def argument_debug_string(): appendList = [ "%s=\")\n .append(this.%s)\n .append(\"" % (a.name, java_field_name(a.name)) for a in m.arguments ] - print - print " public void appendArgumentDebugStringTo(StringBuilder acc) {" - print " acc.append(\"(%s)\");" % ", ".join(appendList) - print " }" + print() + print(" public void appendArgumentDebugStringTo(StringBuilder acc) {") + print(" acc.append(\"(%s)\");" % ", ".join(appendList)) + print(" }") def write_arguments(): - print - print " public void writeArgumentsTo(MethodArgumentWriter writer)" - print " throws IOException" - print " {" + print() + print(" public void writeArgumentsTo(MethodArgumentWriter writer)") + print(" throws IOException") + print(" {") for a in m.arguments: - print " writer.write%s(this.%s);" % (java_class_name(spec.resolveDomain(a.domain)), java_field_name(a.name)) - print " }" + print(" writer.write%s(this.%s);" % (java_class_name(spec.resolveDomain(a.domain)), java_field_name(a.name))) + print(" }") #start - print - print " public static class %s" % (java_class_name(m.name),) - print " extends Method" - print " implements com.rabbitmq.client.AMQP.%s.%s" % (java_class_name(c.name), java_class_name(m.name)) - print " {" - print " public static final int INDEX = %s;" % (m.index) - print + print() + print(" public static class %s" % (java_class_name(m.name),)) + print(" extends Method") + print(" implements com.rabbitmq.client.AMQP.%s.%s" % (java_class_name(c.name), java_class_name(m.name))) + print(" {") + print(" public static final int INDEX = %s;" % (m.index)) + print() for a in m.arguments: - print " private final %s %s;" % (java_field_type(spec, a.domain), java_field_name(a.name)) + print(" private final %s %s;" % (java_field_type(spec, a.domain), java_field_name(a.name))) getters() constructors() @@ -506,71 +508,71 @@ def write_arguments(): argument_debug_string() write_arguments() - print " }" - print " }" + print(" }") + print(" }") def printMethodVisitor(): - print - print " public interface MethodVisitor {" + print() + print(" public interface MethodVisitor {") for c in spec.allClasses(): for m in c.allMethods(): - print " Object visit(%s.%s x) throws IOException;" % (java_class_name(c.name), java_class_name(m.name)) - print " }" + print(" Object visit(%s.%s x) throws IOException;" % (java_class_name(c.name), java_class_name(m.name))) + print(" }") #default method visitor - print - print " public static class DefaultMethodVisitor implements MethodVisitor {" + print() + print(" public static class DefaultMethodVisitor implements MethodVisitor {") for c in spec.allClasses(): for m in c.allMethods(): - print " public Object visit(%s.%s x) throws IOException { throw new UnexpectedMethodError(x); }" % (java_class_name(c.name), java_class_name(m.name)) - print " }" + print(" public Object visit(%s.%s x) throws IOException { throw new UnexpectedMethodError(x); }" % (java_class_name(c.name), java_class_name(m.name))) + print(" }") def printMethodArgumentReader(): - print - print " public static Method readMethodFrom(DataInputStream in) throws IOException {" - print " int classId = in.readShort();" - print " int methodId = in.readShort();" - print " switch (classId) {" + print() + print(" public static Method readMethodFrom(DataInputStream in) throws IOException {") + print(" int classId = in.readShort();") + print(" int methodId = in.readShort();") + print(" switch (classId) {") for c in spec.allClasses(): - print " case %s:" % (c.index) - print " switch (methodId) {" + print(" case %s:" % (c.index)) + print(" switch (methodId) {") for m in c.allMethods(): fq_name = java_class_name(c.name) + '.' + java_class_name(m.name) - print " case %s: {" % (m.index) - print " return new %s(new MethodArgumentReader(new ValueReader(in)));" % (fq_name) - print " }" - print " default: break;" - print " } break;" - print " }" - print - print " throw new UnknownClassOrMethodId(classId, methodId);" - print " }" + print(" case %s: {" % (m.index)) + print(" return new %s(new MethodArgumentReader(new ValueReader(in)));" % (fq_name)) + print(" }") + print(" default: break;") + print(" } break;") + print(" }") + print() + print(" throw new UnknownClassOrMethodId(classId, methodId);") + print(" }") def printContentHeaderReader(): - print - print " public static AMQContentHeader readContentHeaderFrom(DataInputStream in) throws IOException {" - print " int classId = in.readShort();" - print " switch (classId) {" + print() + print(" public static AMQContentHeader readContentHeaderFrom(DataInputStream in) throws IOException {") + print(" int classId = in.readShort();") + print(" switch (classId) {") for c in spec.allClasses(): if c.fields: - print " case %s: return new %sProperties(in);" %(c.index, (java_class_name(c.name))) - print " default: break;" - print " }" - print - print " throw new UnknownClassOrMethodId(classId);" - print " }" + print(" case %s: return new %sProperties(in);" %(c.index, (java_class_name(c.name)))) + print(" default: break;") + print(" }") + print() + print(" throw new UnknownClassOrMethodId(classId);") + print(" }") printHeader() - print - print "public class AMQImpl implements AMQP {" + print() + print("public class AMQImpl implements AMQP {") for c in spec.allClasses(): printClassMethods(spec,c) - + printMethodVisitor() printMethodArgumentReader() printContentHeaderReader() - print "}" + print("}") #-------------------------------------------------------------------------------- From 6b15e547d8e7490c0dc70c1bd81bbab145b66b80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Fri, 18 Dec 2015 15:59:24 +0100 Subject: [PATCH 0089/2114] codegen.py: Sort fieldsToNullCheckInCons This makes Python 2 and Python 3 output the same file. --- codegen.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/codegen.py b/codegen.py index 1f9e59a618..7aaf009137 100644 --- a/codegen.py +++ b/codegen.py @@ -435,7 +435,8 @@ def constructors(): argList = [ "%s %s" % (java_field_type(spec,a.domain),java_field_name(a.name)) for a in m.arguments ] print(" public %s(%s) {" % (java_class_name(m.name), ", ".join(argList))) - fieldsToNullCheckInCons = nullCheckedFields(spec, m) + fieldsToNullCheckInCons = [f for f in nullCheckedFields(spec, m)] + fieldsToNullCheckInCons.sort() for f in fieldsToNullCheckInCons: print(" if (%s == null)" % (f)) From 48e1d4b33f0839323c49d0547d5e06d02c3db117 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Fri, 18 Dec 2015 16:03:00 +0100 Subject: [PATCH 0090/2114] codegen.py: Add shebang line + chmod 755 --- codegen.py | 2 ++ 1 file changed, 2 insertions(+) mode change 100644 => 100755 codegen.py diff --git a/codegen.py b/codegen.py old mode 100644 new mode 100755 index 7aaf009137..755b825f89 --- a/codegen.py +++ b/codegen.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python + ## The contents of this file are subject to the Mozilla Public License ## Version 1.1 (the "License"); you may not use this file except in ## compliance with the License. You may obtain a copy of the License From 3e6a2c5f9b7983f09ae161de04823ca9dca78dca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Thu, 24 Dec 2015 12:56:25 +0000 Subject: [PATCH 0091/2114] Makefile: Remove "stage-and-promote-maven-bundle" target This is now managed from the Umbrella. --- Makefile | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/Makefile b/Makefile index 629245a07e..867f7f7f69 100644 --- a/Makefile +++ b/Makefile @@ -75,20 +75,3 @@ srcdist: distclean (cd build; tar -zcf $(SRC_ARCHIVE).tar.gz $(SRC_ARCHIVE)) (cd build; zip -q -r $(SRC_ARCHIVE).zip $(SRC_ARCHIVE)) (cd build; rm -rf $(SRC_ARCHIVE)) - -stage-and-promote-maven-bundle: - ( \ - cd build/bundle; \ - NEXUS_USERNAME=`cat $(GNUPG_PATH)/../nexus/username`; \ - NEXUS_PASSWORD=`cat $(GNUPG_PATH)/../nexus/password`; \ - VERSION=$(VERSION) \ - SIGNING_KEY=$(SIGNING_KEY) \ - GNUPG_PATH=$(GNUPG_PATH) \ - CREDS="$$NEXUS_USERNAME:$$NEXUS_PASSWORD" \ - ../../nexus-upload.sh \ - amqp-client-$(VERSION).pom \ - amqp-client-$(VERSION).jar \ - amqp-client-$(VERSION)-javadoc.jar \ - amqp-client-$(VERSION)-sources.jar \ - ) - From de337b44be15f79b79a41d9b0a5f3d7c5cffe323 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 28 Dec 2015 12:57:23 +0100 Subject: [PATCH 0092/2114] Make sure artifacts are uploaded right under $NEXUS_ROOT In other words, the path to the artifacts should not be reflected upstream. --- nexus-upload.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nexus-upload.sh b/nexus-upload.sh index 51bfdaf9ab..40ee9a9b89 100755 --- a/nexus-upload.sh +++ b/nexus-upload.sh @@ -19,10 +19,10 @@ for artifact in $@; do rm -f $artifact.asc gpg --homedir $GNUPG_PATH/.gnupg --local-user $SIGNING_KEY --no-tty --armor --detach-sign --output $artifact.asc $artifact for ext in '' .asc ; do - curl --upload-file $artifact$ext $NEXUS_ROOT/$artifact$ext + curl --upload-file $artifact$ext $NEXUS_ROOT/$(basename "$artifact")$ext for sum in md5 sha1 ; do ${sum}sum $artifact$ext | (read a rest ; echo -n "$a") >$artifact$ext.$sum - curl --upload-file $artifact$ext.$sum $NEXUS_ROOT/$artifact$ext.$sum + curl --upload-file $artifact$ext.$sum $NEXUS_ROOT/$(basename "$artifact")$ext.$sum done done done From c49ac489c5b6b1afa16e7729756050345eee53d9 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Mon, 28 Dec 2015 18:54:18 +0300 Subject: [PATCH 0093/2114] Use relative paths in .gitignore --- .gitignore | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index 7feeba8f39..c80df7d958 100644 --- a/.gitignore +++ b/.gitignore @@ -9,12 +9,12 @@ *.ipr *.iws \#~ -/.idea/ -/build/ -/cover/ -/debug/ -/dist/ -/ebin/ -/out/ -/tmp/ +.idea/ +build/ +cover/ +debug/ +dist/ +ebin/ +out/ +tmp/ junit*.properties From 58c2e664b55abc9067702adfdfe854bb6a0167bb Mon Sep 17 00:00:00 2001 From: nick Date: Wed, 30 Dec 2015 09:14:56 -0800 Subject: [PATCH 0094/2114] rabbitmq-java-client #120: unsynchronized access to recordedBindings gives undesired results --- .../rabbitmq/client/impl/recovery/AutorecoveringConnection.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index 82d452df44..145b3aa14c 100644 --- a/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -766,7 +766,7 @@ boolean hasMoreConsumersOnQueue(Collection consumers, String q return result; } - Set removeBindingsWithDestination(String s) { + synchronized Set removeBindingsWithDestination(String s) { Set result = new HashSet(); for (Iterator it = this.recordedBindings.iterator(); it.hasNext(); ) { RecordedBinding b = it.next(); From 51cbfdf33af3489d05895d01ca465a31a1cef1b0 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 1 Jan 2016 12:59:17 +0300 Subject: [PATCH 0095/2114] Update (c) info --- LICENSE-MPL-RabbitMQ | 2 +- codegen.py | 4 ++-- src/com/rabbitmq/client/Address.java | 2 +- src/com/rabbitmq/client/AlreadyClosedException.java | 2 +- src/com/rabbitmq/client/BasicProperties.java | 2 +- src/com/rabbitmq/client/BlockedListener.java | 2 +- src/com/rabbitmq/client/Channel.java | 2 +- src/com/rabbitmq/client/Command.java | 2 +- src/com/rabbitmq/client/ConfirmListener.java | 2 +- src/com/rabbitmq/client/Connection.java | 2 +- src/com/rabbitmq/client/ConnectionFactory.java | 2 +- src/com/rabbitmq/client/Consumer.java | 2 +- src/com/rabbitmq/client/ConsumerCancelledException.java | 2 +- src/com/rabbitmq/client/ContentHeader.java | 2 +- src/com/rabbitmq/client/DefaultConsumer.java | 2 +- src/com/rabbitmq/client/DefaultSaslConfig.java | 2 +- src/com/rabbitmq/client/Envelope.java | 2 +- src/com/rabbitmq/client/ExceptionHandler.java | 2 +- src/com/rabbitmq/client/FlowListener.java | 2 +- src/com/rabbitmq/client/GetResponse.java | 2 +- src/com/rabbitmq/client/JDKSaslConfig.java | 2 +- src/com/rabbitmq/client/LongString.java | 2 +- src/com/rabbitmq/client/MalformedFrameException.java | 2 +- src/com/rabbitmq/client/MapRpcServer.java | 2 +- src/com/rabbitmq/client/MessageProperties.java | 2 +- src/com/rabbitmq/client/Method.java | 2 +- src/com/rabbitmq/client/MissedHeartbeatException.java | 2 +- src/com/rabbitmq/client/NullTrustManager.java | 2 +- .../client/PossibleAuthenticationFailureException.java | 2 +- src/com/rabbitmq/client/ProtocolVersionMismatchException.java | 2 +- src/com/rabbitmq/client/QueueingConsumer.java | 2 +- src/com/rabbitmq/client/ReturnListener.java | 2 +- src/com/rabbitmq/client/RpcClient.java | 2 +- src/com/rabbitmq/client/RpcServer.java | 2 +- src/com/rabbitmq/client/SaslConfig.java | 2 +- src/com/rabbitmq/client/SaslMechanism.java | 2 +- src/com/rabbitmq/client/ShutdownListener.java | 2 +- src/com/rabbitmq/client/ShutdownNotifier.java | 2 +- src/com/rabbitmq/client/ShutdownSignalException.java | 2 +- src/com/rabbitmq/client/StringRpcServer.java | 2 +- src/com/rabbitmq/client/UnexpectedFrameError.java | 2 +- src/com/rabbitmq/client/UnexpectedMethodError.java | 2 +- src/com/rabbitmq/client/UnknownClassOrMethodId.java | 2 +- src/com/rabbitmq/client/impl/AMQBasicProperties.java | 2 +- src/com/rabbitmq/client/impl/AMQChannel.java | 2 +- src/com/rabbitmq/client/impl/AMQCommand.java | 2 +- src/com/rabbitmq/client/impl/AMQConnection.java | 4 ++-- src/com/rabbitmq/client/impl/AMQContentHeader.java | 2 +- src/com/rabbitmq/client/impl/CRDemoMechanism.java | 2 +- src/com/rabbitmq/client/impl/ChannelManager.java | 2 +- src/com/rabbitmq/client/impl/ChannelN.java | 2 +- src/com/rabbitmq/client/impl/ClientVersion.java.in | 2 +- src/com/rabbitmq/client/impl/CommandAssembler.java | 2 +- src/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java | 2 +- src/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java | 2 +- src/com/rabbitmq/client/impl/DefaultExceptionHandler.java | 2 +- src/com/rabbitmq/client/impl/ExternalMechanism.java | 2 +- src/com/rabbitmq/client/impl/ForgivingExceptionHandler.java | 2 +- src/com/rabbitmq/client/impl/Frame.java | 2 +- src/com/rabbitmq/client/impl/FrameHandler.java | 2 +- src/com/rabbitmq/client/impl/HeartbeatSender.java | 2 +- src/com/rabbitmq/client/impl/LongStringHelper.java | 2 +- src/com/rabbitmq/client/impl/Method.java | 2 +- src/com/rabbitmq/client/impl/MethodArgumentReader.java | 2 +- src/com/rabbitmq/client/impl/MethodArgumentWriter.java | 2 +- src/com/rabbitmq/client/impl/PlainMechanism.java | 2 +- src/com/rabbitmq/client/impl/ShutdownNotifierComponent.java | 2 +- src/com/rabbitmq/client/impl/SocketFrameHandler.java | 2 +- src/com/rabbitmq/client/impl/StrictExceptionHandler.java | 2 +- src/com/rabbitmq/client/impl/TruncatedInputStream.java | 2 +- src/com/rabbitmq/client/impl/UnknownChannelException.java | 2 +- src/com/rabbitmq/client/impl/ValueReader.java | 2 +- src/com/rabbitmq/client/impl/ValueWriter.java | 2 +- src/com/rabbitmq/client/impl/Version.java | 2 +- src/com/rabbitmq/tools/Tracer.java | 2 +- src/com/rabbitmq/tools/json/JSONReader.java | 2 +- src/com/rabbitmq/tools/json/JSONSerializable.java | 2 +- src/com/rabbitmq/tools/json/JSONUtil.java | 2 +- src/com/rabbitmq/tools/json/JSONWriter.java | 2 +- src/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java | 2 +- src/com/rabbitmq/tools/jsonrpc/JsonRpcException.java | 2 +- src/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java | 2 +- src/com/rabbitmq/tools/jsonrpc/ParameterDescription.java | 2 +- src/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java | 2 +- src/com/rabbitmq/tools/jsonrpc/ServiceDescription.java | 2 +- src/com/rabbitmq/utility/BlockingCell.java | 2 +- src/com/rabbitmq/utility/BlockingValueOrException.java | 2 +- src/com/rabbitmq/utility/IntAllocator.java | 2 +- src/com/rabbitmq/utility/SensibleClone.java | 2 +- src/com/rabbitmq/utility/SingleShotLinearTimer.java | 2 +- src/com/rabbitmq/utility/Utility.java | 2 +- src/com/rabbitmq/utility/ValueOrException.java | 2 +- test/src/com/rabbitmq/client/test/AMQBuilderApiTest.java | 2 +- test/src/com/rabbitmq/client/test/AMQConnectionTest.java | 2 +- test/src/com/rabbitmq/client/test/BlockingCellTest.java | 2 +- test/src/com/rabbitmq/client/test/BrokenFramesTest.java | 2 +- test/src/com/rabbitmq/client/test/BrokerTestCase.java | 2 +- test/src/com/rabbitmq/client/test/Bug20004Test.java | 2 +- .../rabbitmq/client/test/ChannelNumberAllocationTests.java | 2 +- test/src/com/rabbitmq/client/test/ClientTests.java | 2 +- test/src/com/rabbitmq/client/test/ClonePropertiesTest.java | 2 +- test/src/com/rabbitmq/client/test/CloseInMainLoop.java | 2 +- test/src/com/rabbitmq/client/test/JSONReadWriteTest.java | 2 +- test/src/com/rabbitmq/client/test/MultiThreadedChannel.java | 2 +- .../rabbitmq/client/test/QueueingConsumerShutdownTests.java | 2 +- test/src/com/rabbitmq/client/test/TableTest.java | 2 +- .../com/rabbitmq/client/test/TruncatedInputStreamTest.java | 2 +- test/src/com/rabbitmq/client/test/ValueOrExceptionTest.java | 2 +- .../rabbitmq/client/test/functional/AbstractRejectTest.java | 2 +- .../rabbitmq/client/test/functional/AlternateExchange.java | 2 +- .../com/rabbitmq/client/test/functional/BindingLifecycle.java | 2 +- .../rabbitmq/client/test/functional/BindingLifecycleBase.java | 2 +- test/src/com/rabbitmq/client/test/functional/CcRoutes.java | 2 +- .../rabbitmq/client/test/functional/ClusteredTestBase.java | 2 +- test/src/com/rabbitmq/client/test/functional/Confirm.java | 2 +- .../com/rabbitmq/client/test/functional/ConnectionOpen.java | 2 +- .../client/test/functional/ConsumerCancelNotification.java | 2 +- .../com/rabbitmq/client/test/functional/DefaultExchange.java | 2 +- .../com/rabbitmq/client/test/functional/DoubleDeletion.java | 2 +- .../rabbitmq/client/test/functional/DurableOnTransient.java | 2 +- .../com/rabbitmq/client/test/functional/ExchangeDeclare.java | 2 +- .../client/test/functional/ExchangeDeleteIfUnused.java | 2 +- .../client/test/functional/ExchangeEquivalenceBase.java | 2 +- .../client/test/functional/ExchangeExchangeBindings.java | 2 +- .../test/functional/ExchangeExchangeBindingsAutoDelete.java | 2 +- test/src/com/rabbitmq/client/test/functional/FrameMax.java | 2 +- .../com/rabbitmq/client/test/functional/FunctionalTests.java | 2 +- test/src/com/rabbitmq/client/test/functional/Heartbeat.java | 2 +- .../com/rabbitmq/client/test/functional/InternalExchange.java | 2 +- test/src/com/rabbitmq/client/test/functional/InvalidAcks.java | 2 +- .../com/rabbitmq/client/test/functional/InvalidAcksBase.java | 2 +- .../com/rabbitmq/client/test/functional/InvalidAcksTx.java | 2 +- test/src/com/rabbitmq/client/test/functional/Nack.java | 2 +- .../rabbitmq/client/test/functional/NoRequeueOnCancel.java | 2 +- .../com/rabbitmq/client/test/functional/PerMessageTTL.java | 2 +- test/src/com/rabbitmq/client/test/functional/PerQueueTTL.java | 2 +- test/src/com/rabbitmq/client/test/functional/Policies.java | 2 +- test/src/com/rabbitmq/client/test/functional/QosTests.java | 2 +- .../com/rabbitmq/client/test/functional/QueueExclusivity.java | 2 +- test/src/com/rabbitmq/client/test/functional/QueueLease.java | 2 +- .../com/rabbitmq/client/test/functional/QueueLifecycle.java | 2 +- .../com/rabbitmq/client/test/functional/QueueSizeLimit.java | 2 +- test/src/com/rabbitmq/client/test/functional/Recover.java | 2 +- test/src/com/rabbitmq/client/test/functional/Reject.java | 2 +- .../client/test/functional/RequeueOnChannelClose.java | 2 +- .../com/rabbitmq/client/test/functional/RequeueOnClose.java | 2 +- .../client/test/functional/RequeueOnConnectionClose.java | 2 +- test/src/com/rabbitmq/client/test/functional/Routing.java | 2 +- .../com/rabbitmq/client/test/functional/SaslMechanisms.java | 2 +- test/src/com/rabbitmq/client/test/functional/Tables.java | 2 +- .../src/com/rabbitmq/client/test/functional/Transactions.java | 2 +- .../client/test/functional/UnbindAutoDeleteExchange.java | 2 +- .../com/rabbitmq/client/test/functional/UnexpectedFrames.java | 2 +- .../src/com/rabbitmq/client/test/functional/UserIDHeader.java | 2 +- test/src/com/rabbitmq/client/test/performance/CLIHelper.java | 2 +- test/src/com/rabbitmq/client/test/performance/QosScaling.java | 2 +- .../com/rabbitmq/client/test/performance/ScalabilityTest.java | 2 +- .../rabbitmq/client/test/performance/StressManagement.java | 2 +- test/src/com/rabbitmq/client/test/server/AbsentQueue.java | 2 +- .../client/test/server/AlternateExchangeEquivalence.java | 2 +- .../com/rabbitmq/client/test/server/BlockedConnection.java | 2 +- test/src/com/rabbitmq/client/test/server/Bug19219Test.java | 2 +- .../rabbitmq/client/test/server/DurableBindingLifecycle.java | 2 +- .../client/test/server/EffectVisibilityCrossNodeTest.java | 2 +- .../rabbitmq/client/test/server/ExclusiveQueueDurability.java | 2 +- test/src/com/rabbitmq/client/test/server/HATests.java | 2 +- test/src/com/rabbitmq/client/test/server/MemoryAlarms.java | 2 +- test/src/com/rabbitmq/client/test/server/MessageRecovery.java | 2 +- test/src/com/rabbitmq/client/test/server/Permissions.java | 2 +- test/src/com/rabbitmq/client/test/server/ServerTests.java | 2 +- .../com/rabbitmq/client/test/ssl/BadVerifiedConnection.java | 2 +- test/src/com/rabbitmq/client/test/ssl/SSLTests.java | 2 +- .../com/rabbitmq/client/test/ssl/UnverifiedConnection.java | 2 +- test/src/com/rabbitmq/client/test/ssl/VerifiedConnection.java | 2 +- test/src/com/rabbitmq/examples/BufferPerformanceMetrics.java | 2 +- .../src/com/rabbitmq/examples/ChannelCreationPerformance.java | 2 +- test/src/com/rabbitmq/examples/ConfirmDontLoseMessages.java | 2 +- test/src/com/rabbitmq/examples/ConsumerMain.java | 2 +- test/src/com/rabbitmq/examples/FileConsumer.java | 2 +- test/src/com/rabbitmq/examples/FileProducer.java | 2 +- test/src/com/rabbitmq/examples/HelloClient.java | 2 +- test/src/com/rabbitmq/examples/HelloJsonClient.java | 2 +- test/src/com/rabbitmq/examples/HelloJsonServer.java | 2 +- test/src/com/rabbitmq/examples/HelloJsonService.java | 2 +- test/src/com/rabbitmq/examples/HelloServer.java | 2 +- test/src/com/rabbitmq/examples/LogTail.java | 2 +- test/src/com/rabbitmq/examples/MulticastMain.java | 2 +- test/src/com/rabbitmq/examples/PerQueueTTLGetter.java | 2 +- test/src/com/rabbitmq/examples/PerQueueTTLPublisher.java | 2 +- test/src/com/rabbitmq/examples/PerfTest.java | 2 +- test/src/com/rabbitmq/examples/PerfTestMulti.java | 2 +- test/src/com/rabbitmq/examples/ProducerMain.java | 2 +- test/src/com/rabbitmq/examples/SendString.java | 2 +- test/src/com/rabbitmq/examples/SimpleConsumer.java | 2 +- test/src/com/rabbitmq/examples/SimpleProducer.java | 2 +- test/src/com/rabbitmq/examples/SimpleTopicConsumer.java | 2 +- test/src/com/rabbitmq/examples/SimpleTopicProducer.java | 2 +- test/src/com/rabbitmq/examples/SpammyTopicProducer.java | 2 +- test/src/com/rabbitmq/examples/StressPersister.java | 2 +- test/src/com/rabbitmq/examples/TestMain.java | 2 +- test/src/com/rabbitmq/examples/TracerConcurrencyTest.java | 2 +- test/src/com/rabbitmq/examples/perf/Broker.java | 2 +- test/src/com/rabbitmq/examples/perf/BrokerValue.java | 2 +- test/src/com/rabbitmq/examples/perf/BrokerVariable.java | 2 +- test/src/com/rabbitmq/examples/perf/Consumer.java | 2 +- test/src/com/rabbitmq/examples/perf/MulticastParams.java | 2 +- test/src/com/rabbitmq/examples/perf/MulticastSet.java | 2 +- test/src/com/rabbitmq/examples/perf/MulticastValue.java | 2 +- test/src/com/rabbitmq/examples/perf/MulticastVariable.java | 2 +- test/src/com/rabbitmq/examples/perf/Producer.java | 2 +- .../src/com/rabbitmq/examples/perf/RateVsLatencyScenario.java | 2 +- test/src/com/rabbitmq/examples/perf/Scenario.java | 2 +- test/src/com/rabbitmq/examples/perf/ScenarioStats.java | 2 +- test/src/com/rabbitmq/examples/perf/SimpleScenario.java | 2 +- test/src/com/rabbitmq/examples/perf/SimpleScenarioStats.java | 2 +- test/src/com/rabbitmq/examples/perf/Stats.java | 2 +- test/src/com/rabbitmq/examples/perf/Variable.java | 2 +- test/src/com/rabbitmq/examples/perf/VariableValue.java | 2 +- test/src/com/rabbitmq/examples/perf/VaryingScenario.java | 2 +- test/src/com/rabbitmq/examples/perf/VaryingScenarioStats.java | 2 +- test/src/com/rabbitmq/tools/Host.java | 2 +- 221 files changed, 223 insertions(+), 223 deletions(-) diff --git a/LICENSE-MPL-RabbitMQ b/LICENSE-MPL-RabbitMQ index 096b2c4eaa..02ee669400 100644 --- a/LICENSE-MPL-RabbitMQ +++ b/LICENSE-MPL-RabbitMQ @@ -447,7 +447,7 @@ EXHIBIT A -Mozilla Public License. The Original Code is RabbitMQ. The Initial Developer of the Original Code is GoPivotal, Inc. - Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. + Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. Alternatively, the contents of this file may be used under the terms of the GNU General Public License version 2 (the "GPL2"), or diff --git a/codegen.py b/codegen.py index 755b825f89..7d6955e74d 100755 --- a/codegen.py +++ b/codegen.py @@ -13,7 +13,7 @@ ## The Original Code is RabbitMQ. ## ## The Initial Developer of the Original Code is GoPivotal, Inc. -## Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +## Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. ## from __future__ import nested_scopes @@ -147,7 +147,7 @@ def printFileHeader(): // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // """) diff --git a/src/com/rabbitmq/client/Address.java b/src/com/rabbitmq/client/Address.java index 6c7283f8c1..f9ff0ad0cc 100644 --- a/src/com/rabbitmq/client/Address.java +++ b/src/com/rabbitmq/client/Address.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/AlreadyClosedException.java b/src/com/rabbitmq/client/AlreadyClosedException.java index e587001c50..21956dd58e 100644 --- a/src/com/rabbitmq/client/AlreadyClosedException.java +++ b/src/com/rabbitmq/client/AlreadyClosedException.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/BasicProperties.java b/src/com/rabbitmq/client/BasicProperties.java index 021b17d087..1ac3028126 100644 --- a/src/com/rabbitmq/client/BasicProperties.java +++ b/src/com/rabbitmq/client/BasicProperties.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/BlockedListener.java b/src/com/rabbitmq/client/BlockedListener.java index ca002185b7..ea30383f6f 100644 --- a/src/com/rabbitmq/client/BlockedListener.java +++ b/src/com/rabbitmq/client/BlockedListener.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/Channel.java b/src/com/rabbitmq/client/Channel.java index 824518f0f0..36ba7d1d0c 100644 --- a/src/com/rabbitmq/client/Channel.java +++ b/src/com/rabbitmq/client/Channel.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/Command.java b/src/com/rabbitmq/client/Command.java index b5007b542d..3a863ddb8c 100644 --- a/src/com/rabbitmq/client/Command.java +++ b/src/com/rabbitmq/client/Command.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/ConfirmListener.java b/src/com/rabbitmq/client/ConfirmListener.java index e6f113b16c..dca66c539e 100644 --- a/src/com/rabbitmq/client/ConfirmListener.java +++ b/src/com/rabbitmq/client/ConfirmListener.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/Connection.java b/src/com/rabbitmq/client/Connection.java index b216cacb04..e733ce957a 100644 --- a/src/com/rabbitmq/client/Connection.java +++ b/src/com/rabbitmq/client/Connection.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/ConnectionFactory.java b/src/com/rabbitmq/client/ConnectionFactory.java index ebacea27de..5869b0acd3 100644 --- a/src/com/rabbitmq/client/ConnectionFactory.java +++ b/src/com/rabbitmq/client/ConnectionFactory.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/Consumer.java b/src/com/rabbitmq/client/Consumer.java index 8279088163..e4bdf4fc8e 100644 --- a/src/com/rabbitmq/client/Consumer.java +++ b/src/com/rabbitmq/client/Consumer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/ConsumerCancelledException.java b/src/com/rabbitmq/client/ConsumerCancelledException.java index a711cb2b9b..1c8e2adfda 100644 --- a/src/com/rabbitmq/client/ConsumerCancelledException.java +++ b/src/com/rabbitmq/client/ConsumerCancelledException.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/ContentHeader.java b/src/com/rabbitmq/client/ContentHeader.java index b8cb340c26..4c005491de 100644 --- a/src/com/rabbitmq/client/ContentHeader.java +++ b/src/com/rabbitmq/client/ContentHeader.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/DefaultConsumer.java b/src/com/rabbitmq/client/DefaultConsumer.java index 7026d8107b..cb87aef8f7 100644 --- a/src/com/rabbitmq/client/DefaultConsumer.java +++ b/src/com/rabbitmq/client/DefaultConsumer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/DefaultSaslConfig.java b/src/com/rabbitmq/client/DefaultSaslConfig.java index b86b1c2e73..5aabf6d6b8 100644 --- a/src/com/rabbitmq/client/DefaultSaslConfig.java +++ b/src/com/rabbitmq/client/DefaultSaslConfig.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/Envelope.java b/src/com/rabbitmq/client/Envelope.java index 56269734b0..4edec670dc 100644 --- a/src/com/rabbitmq/client/Envelope.java +++ b/src/com/rabbitmq/client/Envelope.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/ExceptionHandler.java b/src/com/rabbitmq/client/ExceptionHandler.java index 8160ca1b5e..e8cc0f5e07 100644 --- a/src/com/rabbitmq/client/ExceptionHandler.java +++ b/src/com/rabbitmq/client/ExceptionHandler.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/FlowListener.java b/src/com/rabbitmq/client/FlowListener.java index b6b1ba8594..10ba13244a 100644 --- a/src/com/rabbitmq/client/FlowListener.java +++ b/src/com/rabbitmq/client/FlowListener.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/GetResponse.java b/src/com/rabbitmq/client/GetResponse.java index 1d06d2774a..e3dbc1bcbd 100644 --- a/src/com/rabbitmq/client/GetResponse.java +++ b/src/com/rabbitmq/client/GetResponse.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/JDKSaslConfig.java b/src/com/rabbitmq/client/JDKSaslConfig.java index f19d45c970..454e3c9e5e 100644 --- a/src/com/rabbitmq/client/JDKSaslConfig.java +++ b/src/com/rabbitmq/client/JDKSaslConfig.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/LongString.java b/src/com/rabbitmq/client/LongString.java index 05030dc5c7..205b53d720 100644 --- a/src/com/rabbitmq/client/LongString.java +++ b/src/com/rabbitmq/client/LongString.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/MalformedFrameException.java b/src/com/rabbitmq/client/MalformedFrameException.java index cde6fed01a..86369eba0e 100644 --- a/src/com/rabbitmq/client/MalformedFrameException.java +++ b/src/com/rabbitmq/client/MalformedFrameException.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/MapRpcServer.java b/src/com/rabbitmq/client/MapRpcServer.java index b150a5c09e..1226480bad 100644 --- a/src/com/rabbitmq/client/MapRpcServer.java +++ b/src/com/rabbitmq/client/MapRpcServer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/MessageProperties.java b/src/com/rabbitmq/client/MessageProperties.java index 2624b8c734..bf5aaa77c0 100644 --- a/src/com/rabbitmq/client/MessageProperties.java +++ b/src/com/rabbitmq/client/MessageProperties.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/Method.java b/src/com/rabbitmq/client/Method.java index c5b62f7dc4..bd046b4869 100644 --- a/src/com/rabbitmq/client/Method.java +++ b/src/com/rabbitmq/client/Method.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/MissedHeartbeatException.java b/src/com/rabbitmq/client/MissedHeartbeatException.java index 1808cde295..87e5c029ff 100644 --- a/src/com/rabbitmq/client/MissedHeartbeatException.java +++ b/src/com/rabbitmq/client/MissedHeartbeatException.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/NullTrustManager.java b/src/com/rabbitmq/client/NullTrustManager.java index 7ac9a213dd..0242995a8a 100644 --- a/src/com/rabbitmq/client/NullTrustManager.java +++ b/src/com/rabbitmq/client/NullTrustManager.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/PossibleAuthenticationFailureException.java b/src/com/rabbitmq/client/PossibleAuthenticationFailureException.java index a5858dd64c..e069b65df7 100644 --- a/src/com/rabbitmq/client/PossibleAuthenticationFailureException.java +++ b/src/com/rabbitmq/client/PossibleAuthenticationFailureException.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/ProtocolVersionMismatchException.java b/src/com/rabbitmq/client/ProtocolVersionMismatchException.java index fd187b833f..258a0a8f54 100644 --- a/src/com/rabbitmq/client/ProtocolVersionMismatchException.java +++ b/src/com/rabbitmq/client/ProtocolVersionMismatchException.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/QueueingConsumer.java b/src/com/rabbitmq/client/QueueingConsumer.java index c2cdd346a2..07bdaea4f3 100644 --- a/src/com/rabbitmq/client/QueueingConsumer.java +++ b/src/com/rabbitmq/client/QueueingConsumer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/ReturnListener.java b/src/com/rabbitmq/client/ReturnListener.java index 64017ee12f..68512c2b1a 100644 --- a/src/com/rabbitmq/client/ReturnListener.java +++ b/src/com/rabbitmq/client/ReturnListener.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/RpcClient.java b/src/com/rabbitmq/client/RpcClient.java index 10e8ea2c62..fa3dd4c6ed 100644 --- a/src/com/rabbitmq/client/RpcClient.java +++ b/src/com/rabbitmq/client/RpcClient.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/RpcServer.java b/src/com/rabbitmq/client/RpcServer.java index f900b7877c..6704de8ad7 100644 --- a/src/com/rabbitmq/client/RpcServer.java +++ b/src/com/rabbitmq/client/RpcServer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/SaslConfig.java b/src/com/rabbitmq/client/SaslConfig.java index 382df58ae2..78b7e11ff6 100644 --- a/src/com/rabbitmq/client/SaslConfig.java +++ b/src/com/rabbitmq/client/SaslConfig.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/SaslMechanism.java b/src/com/rabbitmq/client/SaslMechanism.java index c869d38eda..e3c9aa2a45 100644 --- a/src/com/rabbitmq/client/SaslMechanism.java +++ b/src/com/rabbitmq/client/SaslMechanism.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/ShutdownListener.java b/src/com/rabbitmq/client/ShutdownListener.java index 72b99a194b..29c668c636 100644 --- a/src/com/rabbitmq/client/ShutdownListener.java +++ b/src/com/rabbitmq/client/ShutdownListener.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/ShutdownNotifier.java b/src/com/rabbitmq/client/ShutdownNotifier.java index a8471b7827..09ea608662 100644 --- a/src/com/rabbitmq/client/ShutdownNotifier.java +++ b/src/com/rabbitmq/client/ShutdownNotifier.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/ShutdownSignalException.java b/src/com/rabbitmq/client/ShutdownSignalException.java index 5787e67322..d6d757166a 100644 --- a/src/com/rabbitmq/client/ShutdownSignalException.java +++ b/src/com/rabbitmq/client/ShutdownSignalException.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/StringRpcServer.java b/src/com/rabbitmq/client/StringRpcServer.java index 0c7b2e01d7..112fc6aaee 100644 --- a/src/com/rabbitmq/client/StringRpcServer.java +++ b/src/com/rabbitmq/client/StringRpcServer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/UnexpectedFrameError.java b/src/com/rabbitmq/client/UnexpectedFrameError.java index a86cda5cb3..3e0fe28070 100644 --- a/src/com/rabbitmq/client/UnexpectedFrameError.java +++ b/src/com/rabbitmq/client/UnexpectedFrameError.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/UnexpectedMethodError.java b/src/com/rabbitmq/client/UnexpectedMethodError.java index 38cff48085..d930a93635 100644 --- a/src/com/rabbitmq/client/UnexpectedMethodError.java +++ b/src/com/rabbitmq/client/UnexpectedMethodError.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/UnknownClassOrMethodId.java b/src/com/rabbitmq/client/UnknownClassOrMethodId.java index ffc4629ca5..273d0b27bd 100644 --- a/src/com/rabbitmq/client/UnknownClassOrMethodId.java +++ b/src/com/rabbitmq/client/UnknownClassOrMethodId.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/impl/AMQBasicProperties.java b/src/com/rabbitmq/client/impl/AMQBasicProperties.java index 32a390256b..e792c55c0e 100644 --- a/src/com/rabbitmq/client/impl/AMQBasicProperties.java +++ b/src/com/rabbitmq/client/impl/AMQBasicProperties.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/AMQChannel.java b/src/com/rabbitmq/client/impl/AMQChannel.java index 9b9526bc7e..900447b1f7 100644 --- a/src/com/rabbitmq/client/impl/AMQChannel.java +++ b/src/com/rabbitmq/client/impl/AMQChannel.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/impl/AMQCommand.java b/src/com/rabbitmq/client/impl/AMQCommand.java index d682b9abff..bbf60e2c63 100644 --- a/src/com/rabbitmq/client/impl/AMQCommand.java +++ b/src/com/rabbitmq/client/impl/AMQCommand.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/AMQConnection.java b/src/com/rabbitmq/client/impl/AMQConnection.java index fc0127edff..54e17c0918 100644 --- a/src/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/com/rabbitmq/client/impl/AMQConnection.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; @@ -48,7 +48,7 @@ import com.rabbitmq.utility.BlockingCell; final class Copyright { - final static String COPYRIGHT="Copyright (C) 2007-2015 Pivotal Software, Inc."; + final static String COPYRIGHT="Copyright (c) 2007-2016 Pivotal Software, Inc."; final static String LICENSE="Licensed under the MPL. See http://www.rabbitmq.com/"; } diff --git a/src/com/rabbitmq/client/impl/AMQContentHeader.java b/src/com/rabbitmq/client/impl/AMQContentHeader.java index 58eb8fe0b9..74154d7334 100644 --- a/src/com/rabbitmq/client/impl/AMQContentHeader.java +++ b/src/com/rabbitmq/client/impl/AMQContentHeader.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/CRDemoMechanism.java b/src/com/rabbitmq/client/impl/CRDemoMechanism.java index 90e3dac51c..90cf8d827c 100644 --- a/src/com/rabbitmq/client/impl/CRDemoMechanism.java +++ b/src/com/rabbitmq/client/impl/CRDemoMechanism.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/ChannelManager.java b/src/com/rabbitmq/client/impl/ChannelManager.java index 73a59d885e..bb855b2148 100644 --- a/src/com/rabbitmq/client/impl/ChannelManager.java +++ b/src/com/rabbitmq/client/impl/ChannelManager.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/ChannelN.java b/src/com/rabbitmq/client/impl/ChannelN.java index d7908d0b6f..18d4802fa2 100644 --- a/src/com/rabbitmq/client/impl/ChannelN.java +++ b/src/com/rabbitmq/client/impl/ChannelN.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/ClientVersion.java.in b/src/com/rabbitmq/client/impl/ClientVersion.java.in index 0aaaa5b6f0..cfe8961345 100644 --- a/src/com/rabbitmq/client/impl/ClientVersion.java.in +++ b/src/com/rabbitmq/client/impl/ClientVersion.java.in @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/CommandAssembler.java b/src/com/rabbitmq/client/impl/CommandAssembler.java index 16bf8242c7..3a75459782 100644 --- a/src/com/rabbitmq/client/impl/CommandAssembler.java +++ b/src/com/rabbitmq/client/impl/CommandAssembler.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java b/src/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java index b66d01e862..febbbf603a 100644 --- a/src/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java +++ b/src/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java b/src/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java index fcf4b0d7b6..a77f3f6793 100644 --- a/src/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java +++ b/src/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/impl/DefaultExceptionHandler.java b/src/com/rabbitmq/client/impl/DefaultExceptionHandler.java index 82ac3ff175..476e02376b 100644 --- a/src/com/rabbitmq/client/impl/DefaultExceptionHandler.java +++ b/src/com/rabbitmq/client/impl/DefaultExceptionHandler.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/ExternalMechanism.java b/src/com/rabbitmq/client/impl/ExternalMechanism.java index 698eccf483..c57a2f0d0e 100644 --- a/src/com/rabbitmq/client/impl/ExternalMechanism.java +++ b/src/com/rabbitmq/client/impl/ExternalMechanism.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/ForgivingExceptionHandler.java b/src/com/rabbitmq/client/impl/ForgivingExceptionHandler.java index a7365d835b..6305b1591f 100644 --- a/src/com/rabbitmq/client/impl/ForgivingExceptionHandler.java +++ b/src/com/rabbitmq/client/impl/ForgivingExceptionHandler.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/Frame.java b/src/com/rabbitmq/client/impl/Frame.java index 8c83640929..89d9abd952 100644 --- a/src/com/rabbitmq/client/impl/Frame.java +++ b/src/com/rabbitmq/client/impl/Frame.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/FrameHandler.java b/src/com/rabbitmq/client/impl/FrameHandler.java index 705d67629d..3f0d5f540a 100644 --- a/src/com/rabbitmq/client/impl/FrameHandler.java +++ b/src/com/rabbitmq/client/impl/FrameHandler.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/HeartbeatSender.java b/src/com/rabbitmq/client/impl/HeartbeatSender.java index 00ba30eb6e..698e5b7445 100644 --- a/src/com/rabbitmq/client/impl/HeartbeatSender.java +++ b/src/com/rabbitmq/client/impl/HeartbeatSender.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/impl/LongStringHelper.java b/src/com/rabbitmq/client/impl/LongStringHelper.java index bf7d609660..d2bee15697 100644 --- a/src/com/rabbitmq/client/impl/LongStringHelper.java +++ b/src/com/rabbitmq/client/impl/LongStringHelper.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/impl/Method.java b/src/com/rabbitmq/client/impl/Method.java index db6ba559b4..0b4ea70054 100644 --- a/src/com/rabbitmq/client/impl/Method.java +++ b/src/com/rabbitmq/client/impl/Method.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/impl/MethodArgumentReader.java b/src/com/rabbitmq/client/impl/MethodArgumentReader.java index 85fbf95675..44d9ca42c6 100644 --- a/src/com/rabbitmq/client/impl/MethodArgumentReader.java +++ b/src/com/rabbitmq/client/impl/MethodArgumentReader.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/impl/MethodArgumentWriter.java b/src/com/rabbitmq/client/impl/MethodArgumentWriter.java index f52e605818..8afe6d73a9 100644 --- a/src/com/rabbitmq/client/impl/MethodArgumentWriter.java +++ b/src/com/rabbitmq/client/impl/MethodArgumentWriter.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/impl/PlainMechanism.java b/src/com/rabbitmq/client/impl/PlainMechanism.java index 7eb0fa9cf0..b099f7ff34 100644 --- a/src/com/rabbitmq/client/impl/PlainMechanism.java +++ b/src/com/rabbitmq/client/impl/PlainMechanism.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/ShutdownNotifierComponent.java b/src/com/rabbitmq/client/impl/ShutdownNotifierComponent.java index 5e11fad487..dba413e3e5 100644 --- a/src/com/rabbitmq/client/impl/ShutdownNotifierComponent.java +++ b/src/com/rabbitmq/client/impl/ShutdownNotifierComponent.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/impl/SocketFrameHandler.java b/src/com/rabbitmq/client/impl/SocketFrameHandler.java index 565497e6ae..f9da39c787 100644 --- a/src/com/rabbitmq/client/impl/SocketFrameHandler.java +++ b/src/com/rabbitmq/client/impl/SocketFrameHandler.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/StrictExceptionHandler.java b/src/com/rabbitmq/client/impl/StrictExceptionHandler.java index 50d6b78f12..674a00e97a 100644 --- a/src/com/rabbitmq/client/impl/StrictExceptionHandler.java +++ b/src/com/rabbitmq/client/impl/StrictExceptionHandler.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/TruncatedInputStream.java b/src/com/rabbitmq/client/impl/TruncatedInputStream.java index 52dade475c..2042bb0f58 100644 --- a/src/com/rabbitmq/client/impl/TruncatedInputStream.java +++ b/src/com/rabbitmq/client/impl/TruncatedInputStream.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/impl/UnknownChannelException.java b/src/com/rabbitmq/client/impl/UnknownChannelException.java index d7730f559a..0811f5f829 100644 --- a/src/com/rabbitmq/client/impl/UnknownChannelException.java +++ b/src/com/rabbitmq/client/impl/UnknownChannelException.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/impl/ValueReader.java b/src/com/rabbitmq/client/impl/ValueReader.java index d8bfbcb05b..8d28346ced 100644 --- a/src/com/rabbitmq/client/impl/ValueReader.java +++ b/src/com/rabbitmq/client/impl/ValueReader.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/impl/ValueWriter.java b/src/com/rabbitmq/client/impl/ValueWriter.java index f5eb70a41d..2c9b6d283b 100644 --- a/src/com/rabbitmq/client/impl/ValueWriter.java +++ b/src/com/rabbitmq/client/impl/ValueWriter.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/client/impl/Version.java b/src/com/rabbitmq/client/impl/Version.java index 8f28027a44..5b219a55f2 100644 --- a/src/com/rabbitmq/client/impl/Version.java +++ b/src/com/rabbitmq/client/impl/Version.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/tools/Tracer.java b/src/com/rabbitmq/tools/Tracer.java index cf04a16390..12977b06a1 100644 --- a/src/com/rabbitmq/tools/Tracer.java +++ b/src/com/rabbitmq/tools/Tracer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.tools; diff --git a/src/com/rabbitmq/tools/json/JSONReader.java b/src/com/rabbitmq/tools/json/JSONReader.java index 349fa3a739..59920cf97f 100644 --- a/src/com/rabbitmq/tools/json/JSONReader.java +++ b/src/com/rabbitmq/tools/json/JSONReader.java @@ -1,6 +1,6 @@ /* Copyright (c) 2006-2007 Frank Carver - Copyright (c) 2007-2015 Pivotal Software, Inc. All Rights Reserved + Copyright (c) 2007-2016 Pivotal Software, Inc. All Rights Reserved Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/src/com/rabbitmq/tools/json/JSONSerializable.java b/src/com/rabbitmq/tools/json/JSONSerializable.java index 6c219ad093..9fa4d3fb19 100644 --- a/src/com/rabbitmq/tools/json/JSONSerializable.java +++ b/src/com/rabbitmq/tools/json/JSONSerializable.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/tools/json/JSONUtil.java b/src/com/rabbitmq/tools/json/JSONUtil.java index 2c71c6263d..b7bcdc64bc 100644 --- a/src/com/rabbitmq/tools/json/JSONUtil.java +++ b/src/com/rabbitmq/tools/json/JSONUtil.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/tools/json/JSONWriter.java b/src/com/rabbitmq/tools/json/JSONWriter.java index e6a3ebd845..24896c4201 100644 --- a/src/com/rabbitmq/tools/json/JSONWriter.java +++ b/src/com/rabbitmq/tools/json/JSONWriter.java @@ -1,6 +1,6 @@ /* Copyright (c) 2006-2007 Frank Carver - Copyright (c) 2007-2015 Pivotal Software, Inc. All Rights Reserved + Copyright (c) 2007-2016 Pivotal Software, Inc. All Rights Reserved Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/src/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java b/src/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java index 5579a5acbf..715e78a9f4 100644 --- a/src/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java +++ b/src/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.tools.jsonrpc; diff --git a/src/com/rabbitmq/tools/jsonrpc/JsonRpcException.java b/src/com/rabbitmq/tools/jsonrpc/JsonRpcException.java index c21315ae6a..723ccf472a 100644 --- a/src/com/rabbitmq/tools/jsonrpc/JsonRpcException.java +++ b/src/com/rabbitmq/tools/jsonrpc/JsonRpcException.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java b/src/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java index 72725bbdfc..b3dd744036 100644 --- a/src/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java +++ b/src/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/tools/jsonrpc/ParameterDescription.java b/src/com/rabbitmq/tools/jsonrpc/ParameterDescription.java index 7ae45f06c3..6d3232a426 100644 --- a/src/com/rabbitmq/tools/jsonrpc/ParameterDescription.java +++ b/src/com/rabbitmq/tools/jsonrpc/ParameterDescription.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java b/src/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java index 1d1419e3b4..3886e7f1d5 100644 --- a/src/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java +++ b/src/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/tools/jsonrpc/ServiceDescription.java b/src/com/rabbitmq/tools/jsonrpc/ServiceDescription.java index 0b8143b7e7..bb04f7b284 100644 --- a/src/com/rabbitmq/tools/jsonrpc/ServiceDescription.java +++ b/src/com/rabbitmq/tools/jsonrpc/ServiceDescription.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/utility/BlockingCell.java b/src/com/rabbitmq/utility/BlockingCell.java index a278811df6..4555378664 100644 --- a/src/com/rabbitmq/utility/BlockingCell.java +++ b/src/com/rabbitmq/utility/BlockingCell.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/utility/BlockingValueOrException.java b/src/com/rabbitmq/utility/BlockingValueOrException.java index 0d761255e5..0c6f9668df 100644 --- a/src/com/rabbitmq/utility/BlockingValueOrException.java +++ b/src/com/rabbitmq/utility/BlockingValueOrException.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.utility; diff --git a/src/com/rabbitmq/utility/IntAllocator.java b/src/com/rabbitmq/utility/IntAllocator.java index 160e730259..592275282b 100644 --- a/src/com/rabbitmq/utility/IntAllocator.java +++ b/src/com/rabbitmq/utility/IntAllocator.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.utility; diff --git a/src/com/rabbitmq/utility/SensibleClone.java b/src/com/rabbitmq/utility/SensibleClone.java index 25ad1a40c1..888eec89ab 100644 --- a/src/com/rabbitmq/utility/SensibleClone.java +++ b/src/com/rabbitmq/utility/SensibleClone.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.utility; diff --git a/src/com/rabbitmq/utility/SingleShotLinearTimer.java b/src/com/rabbitmq/utility/SingleShotLinearTimer.java index 8b4cbd11f8..c0c281d948 100644 --- a/src/com/rabbitmq/utility/SingleShotLinearTimer.java +++ b/src/com/rabbitmq/utility/SingleShotLinearTimer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/src/com/rabbitmq/utility/Utility.java b/src/com/rabbitmq/utility/Utility.java index a11470bd4d..426bd3b081 100644 --- a/src/com/rabbitmq/utility/Utility.java +++ b/src/com/rabbitmq/utility/Utility.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.utility; diff --git a/src/com/rabbitmq/utility/ValueOrException.java b/src/com/rabbitmq/utility/ValueOrException.java index a69a2fa57e..bb0c6ad591 100644 --- a/src/com/rabbitmq/utility/ValueOrException.java +++ b/src/com/rabbitmq/utility/ValueOrException.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.utility; diff --git a/test/src/com/rabbitmq/client/test/AMQBuilderApiTest.java b/test/src/com/rabbitmq/client/test/AMQBuilderApiTest.java index a9754038f3..8d40cedcfd 100644 --- a/test/src/com/rabbitmq/client/test/AMQBuilderApiTest.java +++ b/test/src/com/rabbitmq/client/test/AMQBuilderApiTest.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // // package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/AMQConnectionTest.java b/test/src/com/rabbitmq/client/test/AMQConnectionTest.java index e73c534e1a..3aff2fbdd8 100644 --- a/test/src/com/rabbitmq/client/test/AMQConnectionTest.java +++ b/test/src/com/rabbitmq/client/test/AMQConnectionTest.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/BlockingCellTest.java b/test/src/com/rabbitmq/client/test/BlockingCellTest.java index 0fe8be87d3..8848b874cd 100644 --- a/test/src/com/rabbitmq/client/test/BlockingCellTest.java +++ b/test/src/com/rabbitmq/client/test/BlockingCellTest.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/BrokenFramesTest.java b/test/src/com/rabbitmq/client/test/BrokenFramesTest.java index b11830c18a..e4a826bc6a 100644 --- a/test/src/com/rabbitmq/client/test/BrokenFramesTest.java +++ b/test/src/com/rabbitmq/client/test/BrokenFramesTest.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/BrokerTestCase.java b/test/src/com/rabbitmq/client/test/BrokerTestCase.java index 656c59893f..2f342f0238 100644 --- a/test/src/com/rabbitmq/client/test/BrokerTestCase.java +++ b/test/src/com/rabbitmq/client/test/BrokerTestCase.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/Bug20004Test.java b/test/src/com/rabbitmq/client/test/Bug20004Test.java index 60470d43d9..f778dc5405 100644 --- a/test/src/com/rabbitmq/client/test/Bug20004Test.java +++ b/test/src/com/rabbitmq/client/test/Bug20004Test.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/ChannelNumberAllocationTests.java b/test/src/com/rabbitmq/client/test/ChannelNumberAllocationTests.java index 73aa26f86f..6e1a8f617d 100644 --- a/test/src/com/rabbitmq/client/test/ChannelNumberAllocationTests.java +++ b/test/src/com/rabbitmq/client/test/ChannelNumberAllocationTests.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/ClientTests.java b/test/src/com/rabbitmq/client/test/ClientTests.java index 6f3274b8a8..af38902083 100644 --- a/test/src/com/rabbitmq/client/test/ClientTests.java +++ b/test/src/com/rabbitmq/client/test/ClientTests.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/ClonePropertiesTest.java b/test/src/com/rabbitmq/client/test/ClonePropertiesTest.java index 5e7ea4a6db..d56dda9df0 100644 --- a/test/src/com/rabbitmq/client/test/ClonePropertiesTest.java +++ b/test/src/com/rabbitmq/client/test/ClonePropertiesTest.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/CloseInMainLoop.java b/test/src/com/rabbitmq/client/test/CloseInMainLoop.java index eca14245bc..e2c7873a6f 100644 --- a/test/src/com/rabbitmq/client/test/CloseInMainLoop.java +++ b/test/src/com/rabbitmq/client/test/CloseInMainLoop.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/JSONReadWriteTest.java b/test/src/com/rabbitmq/client/test/JSONReadWriteTest.java index 8b681bd322..b385dc0b13 100644 --- a/test/src/com/rabbitmq/client/test/JSONReadWriteTest.java +++ b/test/src/com/rabbitmq/client/test/JSONReadWriteTest.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/MultiThreadedChannel.java b/test/src/com/rabbitmq/client/test/MultiThreadedChannel.java index 12d01b3153..22275d8318 100644 --- a/test/src/com/rabbitmq/client/test/MultiThreadedChannel.java +++ b/test/src/com/rabbitmq/client/test/MultiThreadedChannel.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/QueueingConsumerShutdownTests.java b/test/src/com/rabbitmq/client/test/QueueingConsumerShutdownTests.java index 39bb7fa0a5..2b649f27be 100644 --- a/test/src/com/rabbitmq/client/test/QueueingConsumerShutdownTests.java +++ b/test/src/com/rabbitmq/client/test/QueueingConsumerShutdownTests.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/TableTest.java b/test/src/com/rabbitmq/client/test/TableTest.java index 4c976b9a19..df436d44e9 100644 --- a/test/src/com/rabbitmq/client/test/TableTest.java +++ b/test/src/com/rabbitmq/client/test/TableTest.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/TruncatedInputStreamTest.java b/test/src/com/rabbitmq/client/test/TruncatedInputStreamTest.java index dbef4d4b22..870477472b 100644 --- a/test/src/com/rabbitmq/client/test/TruncatedInputStreamTest.java +++ b/test/src/com/rabbitmq/client/test/TruncatedInputStreamTest.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/ValueOrExceptionTest.java b/test/src/com/rabbitmq/client/test/ValueOrExceptionTest.java index 7fad3dc0fb..ee656599a0 100644 --- a/test/src/com/rabbitmq/client/test/ValueOrExceptionTest.java +++ b/test/src/com/rabbitmq/client/test/ValueOrExceptionTest.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/functional/AbstractRejectTest.java b/test/src/com/rabbitmq/client/test/functional/AbstractRejectTest.java index 5d60af44d0..8cd1d65905 100644 --- a/test/src/com/rabbitmq/client/test/functional/AbstractRejectTest.java +++ b/test/src/com/rabbitmq/client/test/functional/AbstractRejectTest.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/AlternateExchange.java b/test/src/com/rabbitmq/client/test/functional/AlternateExchange.java index a28ded58e0..e6b4de0199 100644 --- a/test/src/com/rabbitmq/client/test/functional/AlternateExchange.java +++ b/test/src/com/rabbitmq/client/test/functional/AlternateExchange.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/BindingLifecycle.java b/test/src/com/rabbitmq/client/test/functional/BindingLifecycle.java index 15af445c7e..0a9690a3af 100644 --- a/test/src/com/rabbitmq/client/test/functional/BindingLifecycle.java +++ b/test/src/com/rabbitmq/client/test/functional/BindingLifecycle.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/BindingLifecycleBase.java b/test/src/com/rabbitmq/client/test/functional/BindingLifecycleBase.java index f850648bc5..064758fcad 100644 --- a/test/src/com/rabbitmq/client/test/functional/BindingLifecycleBase.java +++ b/test/src/com/rabbitmq/client/test/functional/BindingLifecycleBase.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/CcRoutes.java b/test/src/com/rabbitmq/client/test/functional/CcRoutes.java index 40d7137d02..d1a3691d9b 100644 --- a/test/src/com/rabbitmq/client/test/functional/CcRoutes.java +++ b/test/src/com/rabbitmq/client/test/functional/CcRoutes.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/ClusteredTestBase.java b/test/src/com/rabbitmq/client/test/functional/ClusteredTestBase.java index a56c43cf25..c11e39d652 100644 --- a/test/src/com/rabbitmq/client/test/functional/ClusteredTestBase.java +++ b/test/src/com/rabbitmq/client/test/functional/ClusteredTestBase.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/Confirm.java b/test/src/com/rabbitmq/client/test/functional/Confirm.java index d6464aa5fc..24cbbc660b 100644 --- a/test/src/com/rabbitmq/client/test/functional/Confirm.java +++ b/test/src/com/rabbitmq/client/test/functional/Confirm.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/ConnectionOpen.java b/test/src/com/rabbitmq/client/test/functional/ConnectionOpen.java index a4564bf68e..62c42bfdb1 100644 --- a/test/src/com/rabbitmq/client/test/functional/ConnectionOpen.java +++ b/test/src/com/rabbitmq/client/test/functional/ConnectionOpen.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java b/test/src/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java index 9c7eb9455e..540380032e 100644 --- a/test/src/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java +++ b/test/src/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/DefaultExchange.java b/test/src/com/rabbitmq/client/test/functional/DefaultExchange.java index 985ac148d1..a9a8f618bc 100644 --- a/test/src/com/rabbitmq/client/test/functional/DefaultExchange.java +++ b/test/src/com/rabbitmq/client/test/functional/DefaultExchange.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/DoubleDeletion.java b/test/src/com/rabbitmq/client/test/functional/DoubleDeletion.java index 04f125c86b..be7ea14725 100644 --- a/test/src/com/rabbitmq/client/test/functional/DoubleDeletion.java +++ b/test/src/com/rabbitmq/client/test/functional/DoubleDeletion.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/DurableOnTransient.java b/test/src/com/rabbitmq/client/test/functional/DurableOnTransient.java index 088781e904..c6b7982c79 100644 --- a/test/src/com/rabbitmq/client/test/functional/DurableOnTransient.java +++ b/test/src/com/rabbitmq/client/test/functional/DurableOnTransient.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/ExchangeDeclare.java b/test/src/com/rabbitmq/client/test/functional/ExchangeDeclare.java index 5600f88b4b..a0039294bb 100644 --- a/test/src/com/rabbitmq/client/test/functional/ExchangeDeclare.java +++ b/test/src/com/rabbitmq/client/test/functional/ExchangeDeclare.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java b/test/src/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java index 43ae1492e2..439d8b5552 100644 --- a/test/src/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java +++ b/test/src/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java b/test/src/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java index 2d294d6506..15302f7bdb 100644 --- a/test/src/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java +++ b/test/src/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java b/test/src/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java index aac119ab08..223d1d7965 100644 --- a/test/src/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java +++ b/test/src/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java b/test/src/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java index d723ea630e..a0d81f38ce 100644 --- a/test/src/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java +++ b/test/src/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/FrameMax.java b/test/src/com/rabbitmq/client/test/functional/FrameMax.java index be7a0d00d3..d6f31fc5db 100644 --- a/test/src/com/rabbitmq/client/test/functional/FrameMax.java +++ b/test/src/com/rabbitmq/client/test/functional/FrameMax.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/FunctionalTests.java b/test/src/com/rabbitmq/client/test/functional/FunctionalTests.java index ab1a3b9303..a44b44e6f6 100644 --- a/test/src/com/rabbitmq/client/test/functional/FunctionalTests.java +++ b/test/src/com/rabbitmq/client/test/functional/FunctionalTests.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/Heartbeat.java b/test/src/com/rabbitmq/client/test/functional/Heartbeat.java index dfb4ef5091..15e66cea6a 100644 --- a/test/src/com/rabbitmq/client/test/functional/Heartbeat.java +++ b/test/src/com/rabbitmq/client/test/functional/Heartbeat.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/InternalExchange.java b/test/src/com/rabbitmq/client/test/functional/InternalExchange.java index 351b00b1d8..2238ea4794 100644 --- a/test/src/com/rabbitmq/client/test/functional/InternalExchange.java +++ b/test/src/com/rabbitmq/client/test/functional/InternalExchange.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/InvalidAcks.java b/test/src/com/rabbitmq/client/test/functional/InvalidAcks.java index 4051e79998..b620ed42ef 100644 --- a/test/src/com/rabbitmq/client/test/functional/InvalidAcks.java +++ b/test/src/com/rabbitmq/client/test/functional/InvalidAcks.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/InvalidAcksBase.java b/test/src/com/rabbitmq/client/test/functional/InvalidAcksBase.java index f71ccf1694..0c6010243d 100644 --- a/test/src/com/rabbitmq/client/test/functional/InvalidAcksBase.java +++ b/test/src/com/rabbitmq/client/test/functional/InvalidAcksBase.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/InvalidAcksTx.java b/test/src/com/rabbitmq/client/test/functional/InvalidAcksTx.java index 6c82b33d0d..a616e33dd9 100644 --- a/test/src/com/rabbitmq/client/test/functional/InvalidAcksTx.java +++ b/test/src/com/rabbitmq/client/test/functional/InvalidAcksTx.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/Nack.java b/test/src/com/rabbitmq/client/test/functional/Nack.java index f2e197187c..8473607a09 100644 --- a/test/src/com/rabbitmq/client/test/functional/Nack.java +++ b/test/src/com/rabbitmq/client/test/functional/Nack.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java b/test/src/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java index 3096c9fc57..8727d43766 100644 --- a/test/src/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java +++ b/test/src/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/PerMessageTTL.java b/test/src/com/rabbitmq/client/test/functional/PerMessageTTL.java index 53be989130..1779ec9a92 100644 --- a/test/src/com/rabbitmq/client/test/functional/PerMessageTTL.java +++ b/test/src/com/rabbitmq/client/test/functional/PerMessageTTL.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/PerQueueTTL.java b/test/src/com/rabbitmq/client/test/functional/PerQueueTTL.java index 46c74277b8..d178c67174 100644 --- a/test/src/com/rabbitmq/client/test/functional/PerQueueTTL.java +++ b/test/src/com/rabbitmq/client/test/functional/PerQueueTTL.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/Policies.java b/test/src/com/rabbitmq/client/test/functional/Policies.java index c450f4e70b..eed5d950ed 100644 --- a/test/src/com/rabbitmq/client/test/functional/Policies.java +++ b/test/src/com/rabbitmq/client/test/functional/Policies.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/QosTests.java b/test/src/com/rabbitmq/client/test/functional/QosTests.java index 6b0ce04877..526e140905 100644 --- a/test/src/com/rabbitmq/client/test/functional/QosTests.java +++ b/test/src/com/rabbitmq/client/test/functional/QosTests.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/QueueExclusivity.java b/test/src/com/rabbitmq/client/test/functional/QueueExclusivity.java index bcc40305d1..94e3a619b1 100644 --- a/test/src/com/rabbitmq/client/test/functional/QueueExclusivity.java +++ b/test/src/com/rabbitmq/client/test/functional/QueueExclusivity.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/QueueLease.java b/test/src/com/rabbitmq/client/test/functional/QueueLease.java index 50a4e223e0..1d63afd8bb 100644 --- a/test/src/com/rabbitmq/client/test/functional/QueueLease.java +++ b/test/src/com/rabbitmq/client/test/functional/QueueLease.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/QueueLifecycle.java b/test/src/com/rabbitmq/client/test/functional/QueueLifecycle.java index 3616cd8133..735f752ede 100644 --- a/test/src/com/rabbitmq/client/test/functional/QueueLifecycle.java +++ b/test/src/com/rabbitmq/client/test/functional/QueueLifecycle.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/QueueSizeLimit.java b/test/src/com/rabbitmq/client/test/functional/QueueSizeLimit.java index 96d858e867..b0c4204621 100644 --- a/test/src/com/rabbitmq/client/test/functional/QueueSizeLimit.java +++ b/test/src/com/rabbitmq/client/test/functional/QueueSizeLimit.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/Recover.java b/test/src/com/rabbitmq/client/test/functional/Recover.java index c9442354c4..ed18326691 100644 --- a/test/src/com/rabbitmq/client/test/functional/Recover.java +++ b/test/src/com/rabbitmq/client/test/functional/Recover.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/Reject.java b/test/src/com/rabbitmq/client/test/functional/Reject.java index 3c479a53f1..1e493af612 100644 --- a/test/src/com/rabbitmq/client/test/functional/Reject.java +++ b/test/src/com/rabbitmq/client/test/functional/Reject.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java b/test/src/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java index 522a6db719..36b6efa8b3 100644 --- a/test/src/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java +++ b/test/src/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/RequeueOnClose.java b/test/src/com/rabbitmq/client/test/functional/RequeueOnClose.java index cc9beeec9e..da0da3942e 100644 --- a/test/src/com/rabbitmq/client/test/functional/RequeueOnClose.java +++ b/test/src/com/rabbitmq/client/test/functional/RequeueOnClose.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java b/test/src/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java index 26d2ff7347..007f5bfff0 100644 --- a/test/src/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java +++ b/test/src/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/Routing.java b/test/src/com/rabbitmq/client/test/functional/Routing.java index 8c1c440f28..6dc9e2992c 100644 --- a/test/src/com/rabbitmq/client/test/functional/Routing.java +++ b/test/src/com/rabbitmq/client/test/functional/Routing.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/SaslMechanisms.java b/test/src/com/rabbitmq/client/test/functional/SaslMechanisms.java index d9b83d24d3..ed1022614e 100644 --- a/test/src/com/rabbitmq/client/test/functional/SaslMechanisms.java +++ b/test/src/com/rabbitmq/client/test/functional/SaslMechanisms.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/Tables.java b/test/src/com/rabbitmq/client/test/functional/Tables.java index 1b0239d48b..9413d74b6f 100644 --- a/test/src/com/rabbitmq/client/test/functional/Tables.java +++ b/test/src/com/rabbitmq/client/test/functional/Tables.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/Transactions.java b/test/src/com/rabbitmq/client/test/functional/Transactions.java index 40fdedb44a..ffe4badece 100644 --- a/test/src/com/rabbitmq/client/test/functional/Transactions.java +++ b/test/src/com/rabbitmq/client/test/functional/Transactions.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java b/test/src/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java index 31bde6ce15..f01a89cc92 100644 --- a/test/src/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java +++ b/test/src/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/UnexpectedFrames.java b/test/src/com/rabbitmq/client/test/functional/UnexpectedFrames.java index c69d4b2a07..33e5f91794 100644 --- a/test/src/com/rabbitmq/client/test/functional/UnexpectedFrames.java +++ b/test/src/com/rabbitmq/client/test/functional/UnexpectedFrames.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/UserIDHeader.java b/test/src/com/rabbitmq/client/test/functional/UserIDHeader.java index 0ca80c8985..f7644c806d 100644 --- a/test/src/com/rabbitmq/client/test/functional/UserIDHeader.java +++ b/test/src/com/rabbitmq/client/test/functional/UserIDHeader.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/performance/CLIHelper.java b/test/src/com/rabbitmq/client/test/performance/CLIHelper.java index 04d3887f31..223b80a037 100644 --- a/test/src/com/rabbitmq/client/test/performance/CLIHelper.java +++ b/test/src/com/rabbitmq/client/test/performance/CLIHelper.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/performance/QosScaling.java b/test/src/com/rabbitmq/client/test/performance/QosScaling.java index 09839d9e94..561c0726eb 100644 --- a/test/src/com/rabbitmq/client/test/performance/QosScaling.java +++ b/test/src/com/rabbitmq/client/test/performance/QosScaling.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/performance/ScalabilityTest.java b/test/src/com/rabbitmq/client/test/performance/ScalabilityTest.java index d38e073ec2..d8f18ed170 100644 --- a/test/src/com/rabbitmq/client/test/performance/ScalabilityTest.java +++ b/test/src/com/rabbitmq/client/test/performance/ScalabilityTest.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/performance/StressManagement.java b/test/src/com/rabbitmq/client/test/performance/StressManagement.java index 595b1d1adb..84c8027824 100644 --- a/test/src/com/rabbitmq/client/test/performance/StressManagement.java +++ b/test/src/com/rabbitmq/client/test/performance/StressManagement.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.performance; diff --git a/test/src/com/rabbitmq/client/test/server/AbsentQueue.java b/test/src/com/rabbitmq/client/test/server/AbsentQueue.java index d62d5acb2b..0aedd45411 100644 --- a/test/src/com/rabbitmq/client/test/server/AbsentQueue.java +++ b/test/src/com/rabbitmq/client/test/server/AbsentQueue.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java b/test/src/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java index 586dad58b6..23247251ef 100644 --- a/test/src/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java +++ b/test/src/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/server/BlockedConnection.java b/test/src/com/rabbitmq/client/test/server/BlockedConnection.java index 23239725fa..45f9652ceb 100644 --- a/test/src/com/rabbitmq/client/test/server/BlockedConnection.java +++ b/test/src/com/rabbitmq/client/test/server/BlockedConnection.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/server/Bug19219Test.java b/test/src/com/rabbitmq/client/test/server/Bug19219Test.java index a01fa96dbe..3c39622e19 100644 --- a/test/src/com/rabbitmq/client/test/server/Bug19219Test.java +++ b/test/src/com/rabbitmq/client/test/server/Bug19219Test.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.server; diff --git a/test/src/com/rabbitmq/client/test/server/DurableBindingLifecycle.java b/test/src/com/rabbitmq/client/test/server/DurableBindingLifecycle.java index 27e262f537..1a93c562aa 100644 --- a/test/src/com/rabbitmq/client/test/server/DurableBindingLifecycle.java +++ b/test/src/com/rabbitmq/client/test/server/DurableBindingLifecycle.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java b/test/src/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java index 9bb659e207..f6e060c171 100644 --- a/test/src/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java +++ b/test/src/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.server; diff --git a/test/src/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java b/test/src/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java index d6108c5db5..202271b15d 100644 --- a/test/src/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java +++ b/test/src/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/server/HATests.java b/test/src/com/rabbitmq/client/test/server/HATests.java index 3a2f7ea038..a6fcc793c7 100644 --- a/test/src/com/rabbitmq/client/test/server/HATests.java +++ b/test/src/com/rabbitmq/client/test/server/HATests.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.server; diff --git a/test/src/com/rabbitmq/client/test/server/MemoryAlarms.java b/test/src/com/rabbitmq/client/test/server/MemoryAlarms.java index 12dd19a424..ca0bde4db8 100644 --- a/test/src/com/rabbitmq/client/test/server/MemoryAlarms.java +++ b/test/src/com/rabbitmq/client/test/server/MemoryAlarms.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.server; diff --git a/test/src/com/rabbitmq/client/test/server/MessageRecovery.java b/test/src/com/rabbitmq/client/test/server/MessageRecovery.java index 45c33c242c..271c4c3bed 100644 --- a/test/src/com/rabbitmq/client/test/server/MessageRecovery.java +++ b/test/src/com/rabbitmq/client/test/server/MessageRecovery.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. package com.rabbitmq.client.test.server; diff --git a/test/src/com/rabbitmq/client/test/server/Permissions.java b/test/src/com/rabbitmq/client/test/server/Permissions.java index 0993499751..a03ae614ce 100644 --- a/test/src/com/rabbitmq/client/test/server/Permissions.java +++ b/test/src/com/rabbitmq/client/test/server/Permissions.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/server/ServerTests.java b/test/src/com/rabbitmq/client/test/server/ServerTests.java index bc86b366ab..7f46efb447 100644 --- a/test/src/com/rabbitmq/client/test/server/ServerTests.java +++ b/test/src/com/rabbitmq/client/test/server/ServerTests.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java b/test/src/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java index 9354a7084e..6281055406 100644 --- a/test/src/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java +++ b/test/src/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.ssl; diff --git a/test/src/com/rabbitmq/client/test/ssl/SSLTests.java b/test/src/com/rabbitmq/client/test/ssl/SSLTests.java index 4263bd241c..611df1ec40 100644 --- a/test/src/com/rabbitmq/client/test/ssl/SSLTests.java +++ b/test/src/com/rabbitmq/client/test/ssl/SSLTests.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/client/test/ssl/UnverifiedConnection.java b/test/src/com/rabbitmq/client/test/ssl/UnverifiedConnection.java index 785f8cae15..c71c995d31 100644 --- a/test/src/com/rabbitmq/client/test/ssl/UnverifiedConnection.java +++ b/test/src/com/rabbitmq/client/test/ssl/UnverifiedConnection.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.ssl; diff --git a/test/src/com/rabbitmq/client/test/ssl/VerifiedConnection.java b/test/src/com/rabbitmq/client/test/ssl/VerifiedConnection.java index 8a6ef3d617..82c3ae73d9 100644 --- a/test/src/com/rabbitmq/client/test/ssl/VerifiedConnection.java +++ b/test/src/com/rabbitmq/client/test/ssl/VerifiedConnection.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.client.test.ssl; diff --git a/test/src/com/rabbitmq/examples/BufferPerformanceMetrics.java b/test/src/com/rabbitmq/examples/BufferPerformanceMetrics.java index 919bd9c107..06c283194c 100644 --- a/test/src/com/rabbitmq/examples/BufferPerformanceMetrics.java +++ b/test/src/com/rabbitmq/examples/BufferPerformanceMetrics.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/ChannelCreationPerformance.java b/test/src/com/rabbitmq/examples/ChannelCreationPerformance.java index ca34ba1a2e..931e396e38 100644 --- a/test/src/com/rabbitmq/examples/ChannelCreationPerformance.java +++ b/test/src/com/rabbitmq/examples/ChannelCreationPerformance.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/ConfirmDontLoseMessages.java b/test/src/com/rabbitmq/examples/ConfirmDontLoseMessages.java index 996a498264..16b67d2612 100644 --- a/test/src/com/rabbitmq/examples/ConfirmDontLoseMessages.java +++ b/test/src/com/rabbitmq/examples/ConfirmDontLoseMessages.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/examples/ConsumerMain.java b/test/src/com/rabbitmq/examples/ConsumerMain.java index aaadf0dd49..f363c2252c 100644 --- a/test/src/com/rabbitmq/examples/ConsumerMain.java +++ b/test/src/com/rabbitmq/examples/ConsumerMain.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/examples/FileConsumer.java b/test/src/com/rabbitmq/examples/FileConsumer.java index 613961a2cb..b889fa17c8 100644 --- a/test/src/com/rabbitmq/examples/FileConsumer.java +++ b/test/src/com/rabbitmq/examples/FileConsumer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/examples/FileProducer.java b/test/src/com/rabbitmq/examples/FileProducer.java index fb051a43c0..e1aea5a710 100644 --- a/test/src/com/rabbitmq/examples/FileProducer.java +++ b/test/src/com/rabbitmq/examples/FileProducer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/examples/HelloClient.java b/test/src/com/rabbitmq/examples/HelloClient.java index 9eba3c0f15..fb4e1b20d8 100644 --- a/test/src/com/rabbitmq/examples/HelloClient.java +++ b/test/src/com/rabbitmq/examples/HelloClient.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/HelloJsonClient.java b/test/src/com/rabbitmq/examples/HelloJsonClient.java index 8917cc51b8..7b37b21eb3 100644 --- a/test/src/com/rabbitmq/examples/HelloJsonClient.java +++ b/test/src/com/rabbitmq/examples/HelloJsonClient.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/HelloJsonServer.java b/test/src/com/rabbitmq/examples/HelloJsonServer.java index d8628739d6..2ffe1bfddf 100644 --- a/test/src/com/rabbitmq/examples/HelloJsonServer.java +++ b/test/src/com/rabbitmq/examples/HelloJsonServer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/HelloJsonService.java b/test/src/com/rabbitmq/examples/HelloJsonService.java index 51b0d7924a..1943a02d6d 100644 --- a/test/src/com/rabbitmq/examples/HelloJsonService.java +++ b/test/src/com/rabbitmq/examples/HelloJsonService.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/examples/HelloServer.java b/test/src/com/rabbitmq/examples/HelloServer.java index 2117230aaf..2a7e34602f 100644 --- a/test/src/com/rabbitmq/examples/HelloServer.java +++ b/test/src/com/rabbitmq/examples/HelloServer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/examples/LogTail.java b/test/src/com/rabbitmq/examples/LogTail.java index 16e693fba0..604f732686 100644 --- a/test/src/com/rabbitmq/examples/LogTail.java +++ b/test/src/com/rabbitmq/examples/LogTail.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/MulticastMain.java b/test/src/com/rabbitmq/examples/MulticastMain.java index 2c9b3b43c6..8b5114de20 100644 --- a/test/src/com/rabbitmq/examples/MulticastMain.java +++ b/test/src/com/rabbitmq/examples/MulticastMain.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/PerQueueTTLGetter.java b/test/src/com/rabbitmq/examples/PerQueueTTLGetter.java index 63d9434727..afc9c9b830 100644 --- a/test/src/com/rabbitmq/examples/PerQueueTTLGetter.java +++ b/test/src/com/rabbitmq/examples/PerQueueTTLGetter.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/PerQueueTTLPublisher.java b/test/src/com/rabbitmq/examples/PerQueueTTLPublisher.java index c66161f4d2..ae14156236 100644 --- a/test/src/com/rabbitmq/examples/PerQueueTTLPublisher.java +++ b/test/src/com/rabbitmq/examples/PerQueueTTLPublisher.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/PerfTest.java b/test/src/com/rabbitmq/examples/PerfTest.java index 19254d9600..cd3cb2960b 100644 --- a/test/src/com/rabbitmq/examples/PerfTest.java +++ b/test/src/com/rabbitmq/examples/PerfTest.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/PerfTestMulti.java b/test/src/com/rabbitmq/examples/PerfTestMulti.java index 0edbfe9820..c663352978 100644 --- a/test/src/com/rabbitmq/examples/PerfTestMulti.java +++ b/test/src/com/rabbitmq/examples/PerfTestMulti.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/ProducerMain.java b/test/src/com/rabbitmq/examples/ProducerMain.java index 66613f03f5..20e96dea25 100644 --- a/test/src/com/rabbitmq/examples/ProducerMain.java +++ b/test/src/com/rabbitmq/examples/ProducerMain.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/SendString.java b/test/src/com/rabbitmq/examples/SendString.java index 3b1b9c1db0..6d0ce3900e 100644 --- a/test/src/com/rabbitmq/examples/SendString.java +++ b/test/src/com/rabbitmq/examples/SendString.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/SimpleConsumer.java b/test/src/com/rabbitmq/examples/SimpleConsumer.java index 2d0ab97740..05914daa88 100644 --- a/test/src/com/rabbitmq/examples/SimpleConsumer.java +++ b/test/src/com/rabbitmq/examples/SimpleConsumer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/SimpleProducer.java b/test/src/com/rabbitmq/examples/SimpleProducer.java index 70b54e9025..ee1c99e3ee 100644 --- a/test/src/com/rabbitmq/examples/SimpleProducer.java +++ b/test/src/com/rabbitmq/examples/SimpleProducer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/SimpleTopicConsumer.java b/test/src/com/rabbitmq/examples/SimpleTopicConsumer.java index a50e0956a6..2ad640a45a 100644 --- a/test/src/com/rabbitmq/examples/SimpleTopicConsumer.java +++ b/test/src/com/rabbitmq/examples/SimpleTopicConsumer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/SimpleTopicProducer.java b/test/src/com/rabbitmq/examples/SimpleTopicProducer.java index 335934f3c7..31d2ee1203 100644 --- a/test/src/com/rabbitmq/examples/SimpleTopicProducer.java +++ b/test/src/com/rabbitmq/examples/SimpleTopicProducer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/SpammyTopicProducer.java b/test/src/com/rabbitmq/examples/SpammyTopicProducer.java index a3d7915d33..111f60a3b7 100644 --- a/test/src/com/rabbitmq/examples/SpammyTopicProducer.java +++ b/test/src/com/rabbitmq/examples/SpammyTopicProducer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/StressPersister.java b/test/src/com/rabbitmq/examples/StressPersister.java index 48fcc23adb..b19b4a3c45 100644 --- a/test/src/com/rabbitmq/examples/StressPersister.java +++ b/test/src/com/rabbitmq/examples/StressPersister.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/TestMain.java b/test/src/com/rabbitmq/examples/TestMain.java index 0ef4cdb2aa..2cd08136c1 100644 --- a/test/src/com/rabbitmq/examples/TestMain.java +++ b/test/src/com/rabbitmq/examples/TestMain.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // diff --git a/test/src/com/rabbitmq/examples/TracerConcurrencyTest.java b/test/src/com/rabbitmq/examples/TracerConcurrencyTest.java index 01eb9f55aa..e80a197486 100644 --- a/test/src/com/rabbitmq/examples/TracerConcurrencyTest.java +++ b/test/src/com/rabbitmq/examples/TracerConcurrencyTest.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/perf/Broker.java b/test/src/com/rabbitmq/examples/perf/Broker.java index eabc659fb4..cd0793e51a 100644 --- a/test/src/com/rabbitmq/examples/perf/Broker.java +++ b/test/src/com/rabbitmq/examples/perf/Broker.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/BrokerValue.java b/test/src/com/rabbitmq/examples/perf/BrokerValue.java index 0631b9b8ac..9eb654c1df 100644 --- a/test/src/com/rabbitmq/examples/perf/BrokerValue.java +++ b/test/src/com/rabbitmq/examples/perf/BrokerValue.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/BrokerVariable.java b/test/src/com/rabbitmq/examples/perf/BrokerVariable.java index 17335ee033..263ffc0a3c 100644 --- a/test/src/com/rabbitmq/examples/perf/BrokerVariable.java +++ b/test/src/com/rabbitmq/examples/perf/BrokerVariable.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/Consumer.java b/test/src/com/rabbitmq/examples/perf/Consumer.java index cdecad8dd7..7355dbdafc 100644 --- a/test/src/com/rabbitmq/examples/perf/Consumer.java +++ b/test/src/com/rabbitmq/examples/perf/Consumer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/MulticastParams.java b/test/src/com/rabbitmq/examples/perf/MulticastParams.java index b54f142895..95ec326722 100644 --- a/test/src/com/rabbitmq/examples/perf/MulticastParams.java +++ b/test/src/com/rabbitmq/examples/perf/MulticastParams.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/MulticastSet.java b/test/src/com/rabbitmq/examples/perf/MulticastSet.java index 293bed2cbf..3e2c65cf43 100644 --- a/test/src/com/rabbitmq/examples/perf/MulticastSet.java +++ b/test/src/com/rabbitmq/examples/perf/MulticastSet.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/MulticastValue.java b/test/src/com/rabbitmq/examples/perf/MulticastValue.java index ca5ad0e558..45a4f29651 100644 --- a/test/src/com/rabbitmq/examples/perf/MulticastValue.java +++ b/test/src/com/rabbitmq/examples/perf/MulticastValue.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/MulticastVariable.java b/test/src/com/rabbitmq/examples/perf/MulticastVariable.java index 5a1368442c..6b0057c133 100644 --- a/test/src/com/rabbitmq/examples/perf/MulticastVariable.java +++ b/test/src/com/rabbitmq/examples/perf/MulticastVariable.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/Producer.java b/test/src/com/rabbitmq/examples/perf/Producer.java index 26a9c19404..b2748d417d 100644 --- a/test/src/com/rabbitmq/examples/perf/Producer.java +++ b/test/src/com/rabbitmq/examples/perf/Producer.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/RateVsLatencyScenario.java b/test/src/com/rabbitmq/examples/perf/RateVsLatencyScenario.java index 32ba0fafd2..2747a80788 100644 --- a/test/src/com/rabbitmq/examples/perf/RateVsLatencyScenario.java +++ b/test/src/com/rabbitmq/examples/perf/RateVsLatencyScenario.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/Scenario.java b/test/src/com/rabbitmq/examples/perf/Scenario.java index f680ccb71c..c02607e9fe 100644 --- a/test/src/com/rabbitmq/examples/perf/Scenario.java +++ b/test/src/com/rabbitmq/examples/perf/Scenario.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/ScenarioStats.java b/test/src/com/rabbitmq/examples/perf/ScenarioStats.java index e8fc10b223..486bf2e6dc 100644 --- a/test/src/com/rabbitmq/examples/perf/ScenarioStats.java +++ b/test/src/com/rabbitmq/examples/perf/ScenarioStats.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/SimpleScenario.java b/test/src/com/rabbitmq/examples/perf/SimpleScenario.java index 7b7d83d98b..4a5fbb3bf9 100644 --- a/test/src/com/rabbitmq/examples/perf/SimpleScenario.java +++ b/test/src/com/rabbitmq/examples/perf/SimpleScenario.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/SimpleScenarioStats.java b/test/src/com/rabbitmq/examples/perf/SimpleScenarioStats.java index 80f3ee03ba..749913eb2e 100644 --- a/test/src/com/rabbitmq/examples/perf/SimpleScenarioStats.java +++ b/test/src/com/rabbitmq/examples/perf/SimpleScenarioStats.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/Stats.java b/test/src/com/rabbitmq/examples/perf/Stats.java index 8ddf8664ce..2e65f395a8 100644 --- a/test/src/com/rabbitmq/examples/perf/Stats.java +++ b/test/src/com/rabbitmq/examples/perf/Stats.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/Variable.java b/test/src/com/rabbitmq/examples/perf/Variable.java index 1157ca691a..76b8973583 100644 --- a/test/src/com/rabbitmq/examples/perf/Variable.java +++ b/test/src/com/rabbitmq/examples/perf/Variable.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/VariableValue.java b/test/src/com/rabbitmq/examples/perf/VariableValue.java index edb27131c7..13f01ca41a 100644 --- a/test/src/com/rabbitmq/examples/perf/VariableValue.java +++ b/test/src/com/rabbitmq/examples/perf/VariableValue.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/VaryingScenario.java b/test/src/com/rabbitmq/examples/perf/VaryingScenario.java index 9a9512d67e..51ab11bc83 100644 --- a/test/src/com/rabbitmq/examples/perf/VaryingScenario.java +++ b/test/src/com/rabbitmq/examples/perf/VaryingScenario.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/VaryingScenarioStats.java b/test/src/com/rabbitmq/examples/perf/VaryingScenarioStats.java index 49be18b106..9ce509b1fc 100644 --- a/test/src/com/rabbitmq/examples/perf/VaryingScenarioStats.java +++ b/test/src/com/rabbitmq/examples/perf/VaryingScenarioStats.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/tools/Host.java b/test/src/com/rabbitmq/tools/Host.java index 7944a3cbd9..2bac5cb01c 100644 --- a/test/src/com/rabbitmq/tools/Host.java +++ b/test/src/com/rabbitmq/tools/Host.java @@ -11,7 +11,7 @@ // The Original Code is RabbitMQ. // // The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. // From fc94c0f5515cdfeb2bd67d9c8bb2eba5bd6c77b5 Mon Sep 17 00:00:00 2001 From: Patrick Sauts Date: Mon, 21 Dec 2015 11:28:04 -0800 Subject: [PATCH 0096/2114] Migrate build system from Ant to Maven Source files are moved from `src` to `src/main/java`. Tests are moved from `test` to `src/test/java`. `build.properties` is moved and split into two files: src/test/resources/build.properties src/test/resources/config.properties build.xml is replaced by pom.xml. Required system properties (eg. `make.bin`) are now verified in AbstractRMQTestSuite.java. Properties are verified before the tests start. This avoids to have a testsuite hanging because `make` is not GNU Make for instance. Fixes #37. --- .gitignore | 5 + build.xml | 18 +- pom.xml | 332 ++++++++++++++---- scripts/runperftestMaven.sh | 27 ++ scripts/stresspersisterMaven.sh | 72 ++++ .../java}/com/rabbitmq/client/Address.java | 0 .../client/AlreadyClosedException.java | 0 .../AuthenticationFailureException.java | 0 .../com/rabbitmq/client/BasicProperties.java | 0 .../com/rabbitmq/client/BlockedListener.java | 0 .../java}/com/rabbitmq/client/Channel.java | 0 .../java}/com/rabbitmq/client/Command.java | 0 .../com/rabbitmq/client/ConfirmListener.java | 0 .../java}/com/rabbitmq/client/Connection.java | 0 .../rabbitmq/client/ConnectionFactory.java | 0 .../java}/com/rabbitmq/client/Consumer.java | 0 .../client/ConsumerCancelledException.java | 0 .../com/rabbitmq/client/ContentHeader.java | 0 .../com/rabbitmq/client/DefaultConsumer.java | 0 .../rabbitmq/client/DefaultSaslConfig.java | 0 .../client/DefaultSocketConfigurator.java | 0 .../java}/com/rabbitmq/client/Envelope.java | 0 .../com/rabbitmq/client/ExceptionHandler.java | 0 .../com/rabbitmq/client/FlowListener.java | 0 .../com/rabbitmq/client/GetResponse.java | 0 .../com/rabbitmq/client/JDKSaslConfig.java | 0 .../java}/com/rabbitmq/client/LongString.java | 0 .../client/MalformedFrameException.java | 0 .../com/rabbitmq/client/MapRpcServer.java | 0 .../rabbitmq/client/MessageProperties.java | 0 .../java}/com/rabbitmq/client/Method.java | 0 .../client/MissedHeartbeatException.java | 0 .../com/rabbitmq/client/NullTrustManager.java | 0 ...ossibleAuthenticationFailureException.java | 0 .../ProtocolVersionMismatchException.java | 0 .../com/rabbitmq/client/QueueingConsumer.java | 0 .../com/rabbitmq/client/Recoverable.java | 0 .../com/rabbitmq/client/RecoveryListener.java | 0 .../com/rabbitmq/client/ReturnListener.java | 0 .../java}/com/rabbitmq/client/RpcClient.java | 0 .../java}/com/rabbitmq/client/RpcServer.java | 0 .../java}/com/rabbitmq/client/SaslConfig.java | 0 .../com/rabbitmq/client/SaslMechanism.java | 0 .../com/rabbitmq/client/ShutdownListener.java | 0 .../com/rabbitmq/client/ShutdownNotifier.java | 0 .../client/ShutdownSignalException.java | 0 .../rabbitmq/client/SocketConfigurator.java | 0 .../com/rabbitmq/client/StringRpcServer.java | 0 .../client/TopologyRecoveryException.java | 0 .../rabbitmq/client/UnexpectedFrameError.java | 0 .../client/UnexpectedMethodError.java | 0 .../client/UnknownClassOrMethodId.java | 0 .../client/impl/AMQBasicProperties.java | 0 .../com/rabbitmq/client/impl/AMQChannel.java | 0 .../com/rabbitmq/client/impl/AMQCommand.java | 0 .../rabbitmq/client/impl/AMQConnection.java | 0 .../client/impl/AMQContentHeader.java | 0 .../rabbitmq/client/impl/CRDemoMechanism.java | 0 .../rabbitmq/client/impl/ChannelManager.java | 0 .../com/rabbitmq/client/impl/ChannelN.java | 0 .../client/impl/ClientVersion.java.in | 0 .../client/impl/CommandAssembler.java | 0 .../client/impl/ConnectionParams.java | 0 .../client/impl/ConsumerDispatcher.java | 0 .../client/impl/ConsumerWorkService.java | 0 .../impl/ContentHeaderPropertyReader.java | 0 .../impl/ContentHeaderPropertyWriter.java | 0 .../client/impl/DefaultExceptionHandler.java | 0 .../com/rabbitmq/client/impl/Environment.java | 0 .../client/impl/ExternalMechanism.java | 0 .../impl/ForgivingExceptionHandler.java | 0 .../java}/com/rabbitmq/client/impl/Frame.java | 0 .../rabbitmq/client/impl/FrameHandler.java | 0 .../client/impl/FrameHandlerFactory.java | 0 .../rabbitmq/client/impl/HeartbeatSender.java | 0 .../client/impl/LongStringHelper.java | 0 .../com/rabbitmq/client/impl/Method.java | 0 .../client/impl/MethodArgumentReader.java | 0 .../client/impl/MethodArgumentWriter.java | 0 .../client/impl/NetworkConnection.java | 0 .../rabbitmq/client/impl/PlainMechanism.java | 0 .../com/rabbitmq/client/impl/SetQueue.java | 0 .../impl/ShutdownNotifierComponent.java | 0 .../client/impl/SocketFrameHandler.java | 0 .../client/impl/StrictExceptionHandler.java | 0 .../client/impl/TruncatedInputStream.java | 0 .../client/impl/UnknownChannelException.java | 0 .../com/rabbitmq/client/impl/ValueReader.java | 0 .../com/rabbitmq/client/impl/ValueWriter.java | 0 .../impl/VariableLinkedBlockingQueue.java | 0 .../com/rabbitmq/client/impl/Version.java | 0 .../com/rabbitmq/client/impl/WorkPool.java | 0 .../com/rabbitmq/client/impl/package.html | 0 .../impl/recovery/AutorecoveringChannel.java | 0 .../recovery/AutorecoveringConnection.java | 0 .../recovery/ConsumerRecoveryListener.java | 0 .../impl/recovery/QueueRecoveryListener.java | 0 .../client/impl/recovery/RecordedBinding.java | 0 .../impl/recovery/RecordedConsumer.java | 0 .../client/impl/recovery/RecordedEntity.java | 0 .../impl/recovery/RecordedExchange.java | 0 .../recovery/RecordedExchangeBinding.java | 0 .../impl/recovery/RecordedNamedEntity.java | 0 .../client/impl/recovery/RecordedQueue.java | 0 .../impl/recovery/RecordedQueueBinding.java | 0 .../recovery/RecoveryAwareAMQConnection.java | 0 .../RecoveryAwareAMQConnectionFactory.java | 0 .../recovery/RecoveryAwareChannelManager.java | 0 .../impl/recovery/RecoveryAwareChannelN.java | 0 .../java}/com/rabbitmq/client/package.html | 0 .../java}/com/rabbitmq/tools/Tracer.java | 0 .../com/rabbitmq/tools/json/JSONReader.java | 0 .../rabbitmq/tools/json/JSONSerializable.java | 0 .../com/rabbitmq/tools/json/JSONUtil.java | 0 .../com/rabbitmq/tools/json/JSONWriter.java | 0 .../com/rabbitmq/tools/json/package.html | 0 .../rabbitmq/tools/jsonrpc/JsonRpcClient.java | 0 .../tools/jsonrpc/JsonRpcException.java | 0 .../rabbitmq/tools/jsonrpc/JsonRpcServer.java | 0 .../tools/jsonrpc/ParameterDescription.java | 0 .../tools/jsonrpc/ProcedureDescription.java | 0 .../tools/jsonrpc/ServiceDescription.java | 0 .../com/rabbitmq/tools/jsonrpc/package.html | 0 .../java}/com/rabbitmq/tools/package.html | 0 .../com/rabbitmq/utility/BlockingCell.java | 0 .../utility/BlockingValueOrException.java | 0 .../com/rabbitmq/utility/IntAllocator.java | 0 .../com/rabbitmq/utility/SensibleClone.java | 0 .../utility/SingleShotLinearTimer.java | 0 .../java}/com/rabbitmq/utility/Utility.java | 0 .../rabbitmq/utility/ValueOrException.java | 0 .../java}/com/rabbitmq/utility/package.html | 0 .../rabbitmq/client/impl/WorkPoolTests.java | 0 .../client/test/AMQBuilderApiTest.java | 0 .../client/test/AMQConnectionTest.java | 0 .../client/test/AbstractRMQTestSuite.java | 114 ++++++ .../com/rabbitmq/client/test/AmqpUriTest.java | 0 .../client/test/BlockingCellTest.java | 0 .../client/test/BrokenFramesTest.java | 0 .../rabbitmq/client/test/BrokerTestCase.java | 10 +- .../rabbitmq/client/test/Bug20004Test.java | 0 .../test/ChannelNumberAllocationTests.java | 0 .../com/rabbitmq/client/test/ClientTests.java | 6 +- .../client/test/ClonePropertiesTest.java | 0 .../rabbitmq/client/test/CloseInMainLoop.java | 0 .../com/rabbitmq/client/test/ConfirmBase.java | 0 .../client/test/JSONReadWriteTest.java | 9 +- .../rabbitmq/client/test/LongStringTest.java | 0 .../client/test/MultiThreadedChannel.java | 0 .../test/QueueingConsumerShutdownTests.java | 0 .../client/test/SharedThreadPoolTest.java | 0 .../com/rabbitmq/client/test/TableTest.java | 0 .../client/test/TruncatedInputStreamTest.java | 0 .../client/test/ValueOrExceptionTest.java | 0 .../test/functional/AbstractRejectTest.java | 0 .../test/functional/AlternateExchange.java | 0 .../client/test/functional/BasicGet.java | 0 .../test/functional/BindingLifecycle.java | 0 .../test/functional/BindingLifecycleBase.java | 0 .../client/test/functional/CcRoutes.java | 0 .../test/functional/ClusteredTestBase.java | 0 .../client/test/functional/Confirm.java | 0 .../test/functional/ConnectionOpen.java | 0 .../test/functional/ConnectionRecovery.java | 0 .../ConsumerCancelNotification.java | 0 .../client/test/functional/ConsumerCount.java | 0 .../test/functional/ConsumerPriorities.java | 0 .../test/functional/DeadLetterExchange.java | 0 .../test/functional/DefaultExchange.java | 0 .../client/test/functional/DirectReplyTo.java | 0 .../test/functional/DoubleDeletion.java | 0 .../test/functional/DurableOnTransient.java | 0 .../test/functional/ExceptionHandling.java | 0 .../test/functional/ExceptionMessages.java | 0 .../test/functional/ExchangeDeclare.java | 0 .../functional/ExchangeDeleteIfUnused.java | 0 .../functional/ExchangeDeletePredeclared.java | 0 .../functional/ExchangeEquivalenceBase.java | 0 .../functional/ExchangeExchangeBindings.java | 0 .../ExchangeExchangeBindingsAutoDelete.java | 0 .../client/test/functional/FrameMax.java | 0 .../test/functional/FunctionalTests.java | 93 +++++ .../functional/HeadersExchangeValidation.java | 0 .../client/test/functional/Heartbeat.java | 0 .../test/functional/InternalExchange.java | 0 .../client/test/functional/InvalidAcks.java | 0 .../test/functional/InvalidAcksBase.java | 0 .../client/test/functional/InvalidAcksTx.java | 0 .../client/test/functional/MessageCount.java | 0 .../rabbitmq/client/test/functional/Nack.java | 0 .../test/functional/NoRequeueOnCancel.java | 0 .../client/test/functional/Nowait.java | 0 .../test/functional/PerConsumerPrefetch.java | 0 .../client/test/functional/PerMessageTTL.java | 0 .../client/test/functional/PerQueueTTL.java | 0 .../functional/PerQueueVsPerMessageTTL.java | 0 .../client/test/functional/Policies.java | 0 .../client/test/functional/QosTests.java | 0 .../test/functional/QueueExclusivity.java | 0 .../client/test/functional/QueueLease.java | 0 .../test/functional/QueueLifecycle.java | 0 .../test/functional/QueueSizeLimit.java | 0 .../client/test/functional/Recover.java | 0 .../client/test/functional/Reject.java | 0 .../functional/RequeueOnChannelClose.java | 0 .../test/functional/RequeueOnClose.java | 0 .../functional/RequeueOnConnectionClose.java | 0 .../client/test/functional/Routing.java | 0 .../test/functional/SaslMechanisms.java | 0 .../client/test/functional/TTLHandling.java | 0 .../client/test/functional/Tables.java | 0 .../client/test/functional/Transactions.java | 0 .../functional/UnbindAutoDeleteExchange.java | 0 .../test/functional/UnexpectedFrames.java | 0 .../client/test/functional/UserIDHeader.java | 0 .../client/test/performance/CLIHelper.java | 0 .../client/test/performance/QosScaling.java | 0 .../test/performance/ScalabilityTest.java | 0 .../test/performance/StressManagement.java | 0 .../client/test/server/AbsentQueue.java | 7 +- .../server/AlternateExchangeEquivalence.java | 0 .../client/test/server/BlockedConnection.java | 11 +- .../client/test/server/Bug19219Test.java | 0 .../test/server/ChannelLimitNegotiation.java | 0 .../server/DeadLetterExchangeDurable.java | 0 .../test/server/DurableBindingLifecycle.java | 0 .../server/EffectVisibilityCrossNodeTest.java | 0 .../test/server/ExclusiveQueueDurability.java | 1 - .../rabbitmq/client/test/server/Firehose.java | 0 .../rabbitmq/client/test/server/HATests.java | 10 +- .../client/test/server/LoopbackUsers.java | 0 .../client/test/server/MemoryAlarms.java | 1 - .../client/test/server/MessageRecovery.java | 5 +- .../client/test/server/Permissions.java | 0 .../test/server/PersistenceGuarantees.java | 0 .../client/test/server/PriorityQueues.java | 0 .../client/test/server/ServerTests.java | 52 +++ .../rabbitmq/client/test/server/Shutdown.java | 6 +- .../test/server/XDeathHeaderGrowth.java | 0 .../test/ssl/BadVerifiedConnection.java | 0 .../rabbitmq/client/test/ssl/SSLTests.java | 8 +- .../client/test/ssl/UnverifiedConnection.java | 0 .../client/test/ssl/VerifiedConnection.java | 0 .../examples/BufferPerformanceMetrics.java | 0 .../examples/ChannelCreationPerformance.java | 0 .../examples/ConfirmDontLoseMessages.java | 0 .../com/rabbitmq/examples/ConsumerMain.java | 0 .../examples/DirectReplyToPerformance.java | 0 .../com/rabbitmq/examples/FileConsumer.java | 0 .../com/rabbitmq/examples/FileProducer.java | 0 .../com/rabbitmq/examples/HelloClient.java | 0 .../rabbitmq/examples/HelloJsonClient.java | 0 .../rabbitmq/examples/HelloJsonServer.java | 0 .../rabbitmq/examples/HelloJsonService.java | 0 .../com/rabbitmq/examples/HelloServer.java | 0 .../java}/com/rabbitmq/examples/LogTail.java | 0 .../com/rabbitmq/examples/MulticastMain.java | 0 .../rabbitmq/examples/PerQueueTTLGetter.java | 0 .../examples/PerQueueTTLPublisher.java | 0 .../java}/com/rabbitmq/examples/PerfTest.java | 0 .../com/rabbitmq/examples/PerfTestMulti.java | 0 .../com/rabbitmq/examples/ProducerMain.java | 0 .../com/rabbitmq/examples/SendString.java | 0 .../com/rabbitmq/examples/SimpleConsumer.java | 0 .../com/rabbitmq/examples/SimpleProducer.java | 0 .../examples/SimpleTopicConsumer.java | 0 .../examples/SimpleTopicProducer.java | 0 .../examples/SpammyTopicProducer.java | 0 .../rabbitmq/examples/StressPersister.java | 0 .../java}/com/rabbitmq/examples/TestMain.java | 46 ++- .../examples/TracerConcurrencyTest.java | 0 .../com/rabbitmq/examples/perf/Broker.java | 0 .../rabbitmq/examples/perf/BrokerValue.java | 0 .../examples/perf/BrokerVariable.java | 0 .../com/rabbitmq/examples/perf/Consumer.java | 0 .../examples/perf/MulticastParams.java | 0 .../rabbitmq/examples/perf/MulticastSet.java | 0 .../examples/perf/MulticastValue.java | 0 .../examples/perf/MulticastVariable.java | 0 .../com/rabbitmq/examples/perf/PerfUtil.java | 0 .../com/rabbitmq/examples/perf/Producer.java | 0 .../examples/perf/ProducerConsumerBase.java | 0 .../examples/perf/RateVsLatencyScenario.java | 0 .../com/rabbitmq/examples/perf/Scenario.java | 0 .../examples/perf/ScenarioFactory.java | 0 .../rabbitmq/examples/perf/ScenarioStats.java | 0 .../examples/perf/SimpleScenario.java | 0 .../examples/perf/SimpleScenarioStats.java | 0 .../com/rabbitmq/examples/perf/Stats.java | 0 .../com/rabbitmq/examples/perf/Variable.java | 0 .../rabbitmq/examples/perf/VariableValue.java | 0 .../examples/perf/VaryingScenario.java | 0 .../examples/perf/VaryingScenarioStats.java | 0 .../test/java}/com/rabbitmq/tools/Host.java | 13 +- .../rabbitmq/utility/IntAllocatorTests.java | 0 .../test/resources/build.properties | 5 +- .../test/resources/config.properties | 1 + .../test/functional/FunctionalTests.java | 83 ----- .../client/test/server/ServerTests.java | 47 --- 299 files changed, 725 insertions(+), 257 deletions(-) create mode 100755 scripts/runperftestMaven.sh create mode 100755 scripts/stresspersisterMaven.sh rename src/{ => main/java}/com/rabbitmq/client/Address.java (100%) rename src/{ => main/java}/com/rabbitmq/client/AlreadyClosedException.java (100%) rename src/{ => main/java}/com/rabbitmq/client/AuthenticationFailureException.java (100%) rename src/{ => main/java}/com/rabbitmq/client/BasicProperties.java (100%) rename src/{ => main/java}/com/rabbitmq/client/BlockedListener.java (100%) rename src/{ => main/java}/com/rabbitmq/client/Channel.java (100%) rename src/{ => main/java}/com/rabbitmq/client/Command.java (100%) rename src/{ => main/java}/com/rabbitmq/client/ConfirmListener.java (100%) rename src/{ => main/java}/com/rabbitmq/client/Connection.java (100%) rename src/{ => main/java}/com/rabbitmq/client/ConnectionFactory.java (100%) rename src/{ => main/java}/com/rabbitmq/client/Consumer.java (100%) rename src/{ => main/java}/com/rabbitmq/client/ConsumerCancelledException.java (100%) rename src/{ => main/java}/com/rabbitmq/client/ContentHeader.java (100%) rename src/{ => main/java}/com/rabbitmq/client/DefaultConsumer.java (100%) rename src/{ => main/java}/com/rabbitmq/client/DefaultSaslConfig.java (100%) rename src/{ => main/java}/com/rabbitmq/client/DefaultSocketConfigurator.java (100%) rename src/{ => main/java}/com/rabbitmq/client/Envelope.java (100%) rename src/{ => main/java}/com/rabbitmq/client/ExceptionHandler.java (100%) rename src/{ => main/java}/com/rabbitmq/client/FlowListener.java (100%) rename src/{ => main/java}/com/rabbitmq/client/GetResponse.java (100%) rename src/{ => main/java}/com/rabbitmq/client/JDKSaslConfig.java (100%) rename src/{ => main/java}/com/rabbitmq/client/LongString.java (100%) rename src/{ => main/java}/com/rabbitmq/client/MalformedFrameException.java (100%) rename src/{ => main/java}/com/rabbitmq/client/MapRpcServer.java (100%) rename src/{ => main/java}/com/rabbitmq/client/MessageProperties.java (100%) rename src/{ => main/java}/com/rabbitmq/client/Method.java (100%) rename src/{ => main/java}/com/rabbitmq/client/MissedHeartbeatException.java (100%) rename src/{ => main/java}/com/rabbitmq/client/NullTrustManager.java (100%) rename src/{ => main/java}/com/rabbitmq/client/PossibleAuthenticationFailureException.java (100%) rename src/{ => main/java}/com/rabbitmq/client/ProtocolVersionMismatchException.java (100%) rename src/{ => main/java}/com/rabbitmq/client/QueueingConsumer.java (100%) rename src/{ => main/java}/com/rabbitmq/client/Recoverable.java (100%) rename src/{ => main/java}/com/rabbitmq/client/RecoveryListener.java (100%) rename src/{ => main/java}/com/rabbitmq/client/ReturnListener.java (100%) rename src/{ => main/java}/com/rabbitmq/client/RpcClient.java (100%) rename src/{ => main/java}/com/rabbitmq/client/RpcServer.java (100%) rename src/{ => main/java}/com/rabbitmq/client/SaslConfig.java (100%) rename src/{ => main/java}/com/rabbitmq/client/SaslMechanism.java (100%) rename src/{ => main/java}/com/rabbitmq/client/ShutdownListener.java (100%) rename src/{ => main/java}/com/rabbitmq/client/ShutdownNotifier.java (100%) rename src/{ => main/java}/com/rabbitmq/client/ShutdownSignalException.java (100%) rename src/{ => main/java}/com/rabbitmq/client/SocketConfigurator.java (100%) rename src/{ => main/java}/com/rabbitmq/client/StringRpcServer.java (100%) rename src/{ => main/java}/com/rabbitmq/client/TopologyRecoveryException.java (100%) rename src/{ => main/java}/com/rabbitmq/client/UnexpectedFrameError.java (100%) rename src/{ => main/java}/com/rabbitmq/client/UnexpectedMethodError.java (100%) rename src/{ => main/java}/com/rabbitmq/client/UnknownClassOrMethodId.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/AMQBasicProperties.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/AMQChannel.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/AMQCommand.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/AMQConnection.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/AMQContentHeader.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/CRDemoMechanism.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/ChannelManager.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/ChannelN.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/ClientVersion.java.in (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/CommandAssembler.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/ConnectionParams.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/ConsumerDispatcher.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/ConsumerWorkService.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/DefaultExceptionHandler.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/Environment.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/ExternalMechanism.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/ForgivingExceptionHandler.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/Frame.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/FrameHandler.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/FrameHandlerFactory.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/HeartbeatSender.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/LongStringHelper.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/Method.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/MethodArgumentReader.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/MethodArgumentWriter.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/NetworkConnection.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/PlainMechanism.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/SetQueue.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/ShutdownNotifierComponent.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/SocketFrameHandler.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/StrictExceptionHandler.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/TruncatedInputStream.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/UnknownChannelException.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/ValueReader.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/ValueWriter.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/Version.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/WorkPool.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/package.html (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/recovery/ConsumerRecoveryListener.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/recovery/QueueRecoveryListener.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/recovery/RecordedBinding.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/recovery/RecordedConsumer.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/recovery/RecordedEntity.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/recovery/RecordedExchange.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/recovery/RecordedExchangeBinding.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/recovery/RecordedNamedEntity.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/recovery/RecordedQueue.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnection.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelManager.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java (100%) rename src/{ => main/java}/com/rabbitmq/client/package.html (100%) rename src/{ => main/java}/com/rabbitmq/tools/Tracer.java (100%) rename src/{ => main/java}/com/rabbitmq/tools/json/JSONReader.java (100%) rename src/{ => main/java}/com/rabbitmq/tools/json/JSONSerializable.java (100%) rename src/{ => main/java}/com/rabbitmq/tools/json/JSONUtil.java (100%) rename src/{ => main/java}/com/rabbitmq/tools/json/JSONWriter.java (100%) rename src/{ => main/java}/com/rabbitmq/tools/json/package.html (100%) rename src/{ => main/java}/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java (100%) rename src/{ => main/java}/com/rabbitmq/tools/jsonrpc/JsonRpcException.java (100%) rename src/{ => main/java}/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java (100%) rename src/{ => main/java}/com/rabbitmq/tools/jsonrpc/ParameterDescription.java (100%) rename src/{ => main/java}/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java (100%) rename src/{ => main/java}/com/rabbitmq/tools/jsonrpc/ServiceDescription.java (100%) rename src/{ => main/java}/com/rabbitmq/tools/jsonrpc/package.html (100%) rename src/{ => main/java}/com/rabbitmq/tools/package.html (100%) rename src/{ => main/java}/com/rabbitmq/utility/BlockingCell.java (100%) rename src/{ => main/java}/com/rabbitmq/utility/BlockingValueOrException.java (100%) rename src/{ => main/java}/com/rabbitmq/utility/IntAllocator.java (100%) rename src/{ => main/java}/com/rabbitmq/utility/SensibleClone.java (100%) rename src/{ => main/java}/com/rabbitmq/utility/SingleShotLinearTimer.java (100%) rename src/{ => main/java}/com/rabbitmq/utility/Utility.java (100%) rename src/{ => main/java}/com/rabbitmq/utility/ValueOrException.java (100%) rename src/{ => main/java}/com/rabbitmq/utility/package.html (100%) rename {test/src => src/test/java}/com/rabbitmq/client/impl/WorkPoolTests.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/AMQBuilderApiTest.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/AMQConnectionTest.java (100%) create mode 100644 src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java rename {test/src => src/test/java}/com/rabbitmq/client/test/AmqpUriTest.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/BlockingCellTest.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/BrokenFramesTest.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/BrokerTestCase.java (99%) rename {test/src => src/test/java}/com/rabbitmq/client/test/Bug20004Test.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/ChannelNumberAllocationTests.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/ClientTests.java (93%) rename {test/src => src/test/java}/com/rabbitmq/client/test/ClonePropertiesTest.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/CloseInMainLoop.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/ConfirmBase.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/JSONReadWriteTest.java (96%) rename {test/src => src/test/java}/com/rabbitmq/client/test/LongStringTest.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/MultiThreadedChannel.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/QueueingConsumerShutdownTests.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/SharedThreadPoolTest.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/TableTest.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/TruncatedInputStreamTest.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/ValueOrExceptionTest.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/AbstractRejectTest.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/AlternateExchange.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/BasicGet.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/BindingLifecycle.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/BindingLifecycleBase.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/CcRoutes.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/ClusteredTestBase.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/Confirm.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/ConnectionOpen.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/ConnectionRecovery.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/ConsumerCount.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/ConsumerPriorities.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/DeadLetterExchange.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/DefaultExchange.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/DirectReplyTo.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/DoubleDeletion.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/DurableOnTransient.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/ExceptionHandling.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/ExceptionMessages.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/ExchangeDeclare.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/ExchangeDeletePredeclared.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/FrameMax.java (100%) create mode 100644 src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/Heartbeat.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/InternalExchange.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/InvalidAcks.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/InvalidAcksBase.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/InvalidAcksTx.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/MessageCount.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/Nack.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/Nowait.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/PerMessageTTL.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/PerQueueTTL.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/Policies.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/QosTests.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/QueueExclusivity.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/QueueLease.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/QueueLifecycle.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/QueueSizeLimit.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/Recover.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/Reject.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/RequeueOnClose.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/Routing.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/SaslMechanisms.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/TTLHandling.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/Tables.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/Transactions.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/UnexpectedFrames.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/UserIDHeader.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/performance/CLIHelper.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/performance/QosScaling.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/performance/ScalabilityTest.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/performance/StressManagement.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/server/AbsentQueue.java (99%) rename {test/src => src/test/java}/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/server/BlockedConnection.java (98%) rename {test/src => src/test/java}/com/rabbitmq/client/test/server/Bug19219Test.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/server/DurableBindingLifecycle.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java (98%) rename {test/src => src/test/java}/com/rabbitmq/client/test/server/Firehose.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/server/HATests.java (90%) rename {test/src => src/test/java}/com/rabbitmq/client/test/server/LoopbackUsers.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/server/MemoryAlarms.java (99%) rename {test/src => src/test/java}/com/rabbitmq/client/test/server/MessageRecovery.java (98%) rename {test/src => src/test/java}/com/rabbitmq/client/test/server/Permissions.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/server/PersistenceGuarantees.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/server/PriorityQueues.java (100%) create mode 100644 src/test/java/com/rabbitmq/client/test/server/ServerTests.java rename {test/src => src/test/java}/com/rabbitmq/client/test/server/Shutdown.java (74%) rename {test/src => src/test/java}/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/ssl/SSLTests.java (77%) rename {test/src => src/test/java}/com/rabbitmq/client/test/ssl/UnverifiedConnection.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/ssl/VerifiedConnection.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/BufferPerformanceMetrics.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/ChannelCreationPerformance.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/ConfirmDontLoseMessages.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/ConsumerMain.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/DirectReplyToPerformance.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/FileConsumer.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/FileProducer.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/HelloClient.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/HelloJsonClient.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/HelloJsonServer.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/HelloJsonService.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/HelloServer.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/LogTail.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/MulticastMain.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/PerQueueTTLGetter.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/PerQueueTTLPublisher.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/PerfTest.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/PerfTestMulti.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/ProducerMain.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/SendString.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/SimpleConsumer.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/SimpleProducer.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/SimpleTopicConsumer.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/SimpleTopicProducer.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/SpammyTopicProducer.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/StressPersister.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/TestMain.java (94%) rename {test/src => src/test/java}/com/rabbitmq/examples/TracerConcurrencyTest.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/perf/Broker.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/perf/BrokerValue.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/perf/BrokerVariable.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/perf/Consumer.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/perf/MulticastParams.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/perf/MulticastSet.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/perf/MulticastValue.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/perf/MulticastVariable.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/perf/PerfUtil.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/perf/Producer.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/perf/ProducerConsumerBase.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/perf/RateVsLatencyScenario.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/perf/Scenario.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/perf/ScenarioFactory.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/perf/ScenarioStats.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/perf/SimpleScenario.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/perf/SimpleScenarioStats.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/perf/Stats.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/perf/Variable.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/perf/VariableValue.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/perf/VaryingScenario.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/perf/VaryingScenarioStats.java (100%) rename {test/src => src/test/java}/com/rabbitmq/tools/Host.java (96%) rename {test/src => src/test/java}/com/rabbitmq/utility/IntAllocatorTests.java (100%) rename build.properties => src/test/resources/build.properties (86%) rename config.properties => src/test/resources/config.properties (91%) delete mode 100644 test/src/com/rabbitmq/client/test/functional/FunctionalTests.java delete mode 100644 test/src/com/rabbitmq/client/test/server/ServerTests.java diff --git a/.gitignore b/.gitignore index c80df7d958..9bfe0ec81b 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,8 @@ ebin/ out/ tmp/ junit*.properties +/target/ +/.DS_Store +/.classpath +/.project +/.settings diff --git a/build.xml b/build.xml index 0b5cc50339..383567a549 100644 --- a/build.xml +++ b/build.xml @@ -2,8 +2,8 @@ - - + + @@ -81,7 +81,7 @@ - @@ -340,6 +340,9 @@ + + + @@ -364,6 +367,9 @@ + + + @@ -380,6 +386,9 @@ + + + @@ -398,6 +407,9 @@ + + + diff --git a/pom.xml b/pom.xml index 5db8422d17..c55190e876 100644 --- a/pom.xml +++ b/pom.xml @@ -1,77 +1,277 @@ - - 4.0.0 - com.rabbitmq - amqp-client - VERSION - jar - RabbitMQ Java Client - RabbitMQ Java client - http://www.rabbitmq.com + + 4.0.0 - - - ASL 2.0 - http://www.apache.org/licenses/LICENSE-2.0.html - repo - - - GPL v2 - http://www.gnu.org/licenses/gpl-2.0.txt - repo - - - MPL 1.1 - http://www.mozilla.org/MPL/MPL-1.1.txt - repo - - + com.rabbitmq + amqp-client + 3.7.0-SNAPSHOT + jar - - https://github.com/rabbitmq/rabbitmq-java-client.git - scm:git:https://github.com/rabbitmq/rabbitmq-java-client.git - + RabbitMQ Java Client + RabbitMQ Java client + http://www.rabbitmq.com - - - rabbitmq.team - The RabbitMQ Team - - Developer - - - + + + ASL 2.0 + http://www.apache.org/licenses/LICENSE-2.0.html + repo + + + GPL v2 + http://www.gnu.org/licenses/gpl-2.0.txt + repo + + + MPL 1.1 + http://www.mozilla.org/MPL/MPL-1.1.txt + repo + + - + + https://github.com/rabbitmq/rabbitmq-java-client.git + scm:git:https://github.com/rabbitmq/rabbitmq-java-client.git + - - commons-cli - commons-cli - 1.1 - test - + + + rabbitmq.team + The RabbitMQ Team + + Developer + + + - - commons-io - commons-io - 1.2 - test - + + UTF-8 + - - junit - junit - 4.12 - test - + + + commons-cli + commons-cli + 1.1 + test + + + commons-io + commons-io + 1.2 + test + + + junit + junit + 4.12 + test + + - + + + + + maven-clean-plugin + 3.0.0 + + + + ${basedir}/build + + **/* + + false + + + + + + maven-antrun-plugin + 1.7 + + + generate-sources + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + run + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 1.10 + + + add-source + generate-sources + + add-source + + + + build/gensrc + + + + + + + maven-compiler-plugin + 3.2 + + 1.6 + 1.6 + + -Xlint:deprecation + -Xlint:unchecked + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.9 + + + ${project.build.directory} + + true + + **/ClientTests.* + **/FunctionalTests.* + **/SSLTests.* + **/ServerTests.* + **/FunctionalTests.* + **/HATests.* + **/TestMain.* + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.6 + + true + + true + true + + true + + + + + + + jar + test-jar + + + + + + org.apache.maven.plugins + maven-source-plugin + 2.4 + + + + jar + test-jar + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.10.3 + + -Xdoclint:none + + + + + jar + test-jar + + + + + + org.codehaus.mojo + versions-maven-plugin + 2.2 + + + - - - sonatype-nexus-staging - Nexus Release Repository - http://oss.sonatype.org/service/local/staging/deploy/maven2/ - - + + + sonatype-nexus-staging + Nexus Release Repository + http://oss.sonatype.org/service/local/staging/deploy/maven2/ + + diff --git a/scripts/runperftestMaven.sh b/scripts/runperftestMaven.sh new file mode 100755 index 0000000000..6bca7b6f7f --- /dev/null +++ b/scripts/runperftestMaven.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +cd `dirname $0`/.. +run() { + echo "=== running with '$2'" + mvn -q exec:java -Dexec.classpathScope=test -Dexec.mainClass="com.rabbitmq.examples.PerfTest" -Dexec.args=" -h $1 -z 10 -i 20 $2" + sleep 2 +} + +for sz in "" "-s 1000"; do + for pers in "" "-f persistent"; do + for args in \ + "" \ + "-a" \ + "-m 1" \ + "-m 1 -n 1" \ + "-m 10" \ + "-m 10 -n 10" \ + ; do + run $1 "${args} ${pers} ${sz}" + done + done +done + +for args in "-a -f mandatory" "-a -f mandatory -f immediate"; do + run $1 "$args" +done diff --git a/scripts/stresspersisterMaven.sh b/scripts/stresspersisterMaven.sh new file mode 100755 index 0000000000..a6e1182d04 --- /dev/null +++ b/scripts/stresspersisterMaven.sh @@ -0,0 +1,72 @@ +#!/bin/sh +cd `dirname $0`/.. +commentText=$1 +shift + +if [ -z "$commentText" ]; then + echo "Comment text must be supplied!" + exit 1 +fi + +echo "Comment text: $commentText. Press enter to continue." +read dummy + +function run1 { + (while true; do (date +%s.%N; ps ax -o '%mem rss sz vsz args' | grep "beam.*-s rabbit" | grep -v grep) | tr '\n' ' ' | awk '{print $1,$2/100,$3,$4,$5}'; sleep 1; done) > memlog.txt & + memlogger=$! + echo "STARTED MEMLOGGER $memlogger" + sleep 2 + mvn -q exec:java -Dexec.classpathScope=test -Dexec.mainClass="com.rabbitmq.examples.StressPersister" -Dexec.args=" -B $1 -b $2 -C $commentText "| tee stressoutput.txt + logfile=$(head -1 stressoutput.txt) + sleep 2 + kill $memlogger + echo "STOPPED MEMLOGGER $memlogger" + baselog=$(basename $logfile .out) + mv memlog.txt $baselog.mem + grep -v '^#' $logfile > stressoutput.txt + mv stressoutput.txt $logfile +} + +function run32b { + run1 32b 5000 + run1 32b 10000 + run1 32b 20000 + run1 32b 40000 + run1 32b 80000 +} + +function run1m { + run1 1m 125 + run1 1m 250 + run1 1m 500 + run1 1m 1000 + run1 1m 2000 + run1 1m 4000 +} + +function chartall { + for logfile in *.out + do + echo $logfile + baselog=$(basename $logfile .out) + firsttimestamp=$(cat $baselog.mem | head -1 | awk '{print $1}') + cat > $baselog.gnuplot < $baselog.png + done +} + +run32b +run1m +chartall diff --git a/src/com/rabbitmq/client/Address.java b/src/main/java/com/rabbitmq/client/Address.java similarity index 100% rename from src/com/rabbitmq/client/Address.java rename to src/main/java/com/rabbitmq/client/Address.java diff --git a/src/com/rabbitmq/client/AlreadyClosedException.java b/src/main/java/com/rabbitmq/client/AlreadyClosedException.java similarity index 100% rename from src/com/rabbitmq/client/AlreadyClosedException.java rename to src/main/java/com/rabbitmq/client/AlreadyClosedException.java diff --git a/src/com/rabbitmq/client/AuthenticationFailureException.java b/src/main/java/com/rabbitmq/client/AuthenticationFailureException.java similarity index 100% rename from src/com/rabbitmq/client/AuthenticationFailureException.java rename to src/main/java/com/rabbitmq/client/AuthenticationFailureException.java diff --git a/src/com/rabbitmq/client/BasicProperties.java b/src/main/java/com/rabbitmq/client/BasicProperties.java similarity index 100% rename from src/com/rabbitmq/client/BasicProperties.java rename to src/main/java/com/rabbitmq/client/BasicProperties.java diff --git a/src/com/rabbitmq/client/BlockedListener.java b/src/main/java/com/rabbitmq/client/BlockedListener.java similarity index 100% rename from src/com/rabbitmq/client/BlockedListener.java rename to src/main/java/com/rabbitmq/client/BlockedListener.java diff --git a/src/com/rabbitmq/client/Channel.java b/src/main/java/com/rabbitmq/client/Channel.java similarity index 100% rename from src/com/rabbitmq/client/Channel.java rename to src/main/java/com/rabbitmq/client/Channel.java diff --git a/src/com/rabbitmq/client/Command.java b/src/main/java/com/rabbitmq/client/Command.java similarity index 100% rename from src/com/rabbitmq/client/Command.java rename to src/main/java/com/rabbitmq/client/Command.java diff --git a/src/com/rabbitmq/client/ConfirmListener.java b/src/main/java/com/rabbitmq/client/ConfirmListener.java similarity index 100% rename from src/com/rabbitmq/client/ConfirmListener.java rename to src/main/java/com/rabbitmq/client/ConfirmListener.java diff --git a/src/com/rabbitmq/client/Connection.java b/src/main/java/com/rabbitmq/client/Connection.java similarity index 100% rename from src/com/rabbitmq/client/Connection.java rename to src/main/java/com/rabbitmq/client/Connection.java diff --git a/src/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java similarity index 100% rename from src/com/rabbitmq/client/ConnectionFactory.java rename to src/main/java/com/rabbitmq/client/ConnectionFactory.java diff --git a/src/com/rabbitmq/client/Consumer.java b/src/main/java/com/rabbitmq/client/Consumer.java similarity index 100% rename from src/com/rabbitmq/client/Consumer.java rename to src/main/java/com/rabbitmq/client/Consumer.java diff --git a/src/com/rabbitmq/client/ConsumerCancelledException.java b/src/main/java/com/rabbitmq/client/ConsumerCancelledException.java similarity index 100% rename from src/com/rabbitmq/client/ConsumerCancelledException.java rename to src/main/java/com/rabbitmq/client/ConsumerCancelledException.java diff --git a/src/com/rabbitmq/client/ContentHeader.java b/src/main/java/com/rabbitmq/client/ContentHeader.java similarity index 100% rename from src/com/rabbitmq/client/ContentHeader.java rename to src/main/java/com/rabbitmq/client/ContentHeader.java diff --git a/src/com/rabbitmq/client/DefaultConsumer.java b/src/main/java/com/rabbitmq/client/DefaultConsumer.java similarity index 100% rename from src/com/rabbitmq/client/DefaultConsumer.java rename to src/main/java/com/rabbitmq/client/DefaultConsumer.java diff --git a/src/com/rabbitmq/client/DefaultSaslConfig.java b/src/main/java/com/rabbitmq/client/DefaultSaslConfig.java similarity index 100% rename from src/com/rabbitmq/client/DefaultSaslConfig.java rename to src/main/java/com/rabbitmq/client/DefaultSaslConfig.java diff --git a/src/com/rabbitmq/client/DefaultSocketConfigurator.java b/src/main/java/com/rabbitmq/client/DefaultSocketConfigurator.java similarity index 100% rename from src/com/rabbitmq/client/DefaultSocketConfigurator.java rename to src/main/java/com/rabbitmq/client/DefaultSocketConfigurator.java diff --git a/src/com/rabbitmq/client/Envelope.java b/src/main/java/com/rabbitmq/client/Envelope.java similarity index 100% rename from src/com/rabbitmq/client/Envelope.java rename to src/main/java/com/rabbitmq/client/Envelope.java diff --git a/src/com/rabbitmq/client/ExceptionHandler.java b/src/main/java/com/rabbitmq/client/ExceptionHandler.java similarity index 100% rename from src/com/rabbitmq/client/ExceptionHandler.java rename to src/main/java/com/rabbitmq/client/ExceptionHandler.java diff --git a/src/com/rabbitmq/client/FlowListener.java b/src/main/java/com/rabbitmq/client/FlowListener.java similarity index 100% rename from src/com/rabbitmq/client/FlowListener.java rename to src/main/java/com/rabbitmq/client/FlowListener.java diff --git a/src/com/rabbitmq/client/GetResponse.java b/src/main/java/com/rabbitmq/client/GetResponse.java similarity index 100% rename from src/com/rabbitmq/client/GetResponse.java rename to src/main/java/com/rabbitmq/client/GetResponse.java diff --git a/src/com/rabbitmq/client/JDKSaslConfig.java b/src/main/java/com/rabbitmq/client/JDKSaslConfig.java similarity index 100% rename from src/com/rabbitmq/client/JDKSaslConfig.java rename to src/main/java/com/rabbitmq/client/JDKSaslConfig.java diff --git a/src/com/rabbitmq/client/LongString.java b/src/main/java/com/rabbitmq/client/LongString.java similarity index 100% rename from src/com/rabbitmq/client/LongString.java rename to src/main/java/com/rabbitmq/client/LongString.java diff --git a/src/com/rabbitmq/client/MalformedFrameException.java b/src/main/java/com/rabbitmq/client/MalformedFrameException.java similarity index 100% rename from src/com/rabbitmq/client/MalformedFrameException.java rename to src/main/java/com/rabbitmq/client/MalformedFrameException.java diff --git a/src/com/rabbitmq/client/MapRpcServer.java b/src/main/java/com/rabbitmq/client/MapRpcServer.java similarity index 100% rename from src/com/rabbitmq/client/MapRpcServer.java rename to src/main/java/com/rabbitmq/client/MapRpcServer.java diff --git a/src/com/rabbitmq/client/MessageProperties.java b/src/main/java/com/rabbitmq/client/MessageProperties.java similarity index 100% rename from src/com/rabbitmq/client/MessageProperties.java rename to src/main/java/com/rabbitmq/client/MessageProperties.java diff --git a/src/com/rabbitmq/client/Method.java b/src/main/java/com/rabbitmq/client/Method.java similarity index 100% rename from src/com/rabbitmq/client/Method.java rename to src/main/java/com/rabbitmq/client/Method.java diff --git a/src/com/rabbitmq/client/MissedHeartbeatException.java b/src/main/java/com/rabbitmq/client/MissedHeartbeatException.java similarity index 100% rename from src/com/rabbitmq/client/MissedHeartbeatException.java rename to src/main/java/com/rabbitmq/client/MissedHeartbeatException.java diff --git a/src/com/rabbitmq/client/NullTrustManager.java b/src/main/java/com/rabbitmq/client/NullTrustManager.java similarity index 100% rename from src/com/rabbitmq/client/NullTrustManager.java rename to src/main/java/com/rabbitmq/client/NullTrustManager.java diff --git a/src/com/rabbitmq/client/PossibleAuthenticationFailureException.java b/src/main/java/com/rabbitmq/client/PossibleAuthenticationFailureException.java similarity index 100% rename from src/com/rabbitmq/client/PossibleAuthenticationFailureException.java rename to src/main/java/com/rabbitmq/client/PossibleAuthenticationFailureException.java diff --git a/src/com/rabbitmq/client/ProtocolVersionMismatchException.java b/src/main/java/com/rabbitmq/client/ProtocolVersionMismatchException.java similarity index 100% rename from src/com/rabbitmq/client/ProtocolVersionMismatchException.java rename to src/main/java/com/rabbitmq/client/ProtocolVersionMismatchException.java diff --git a/src/com/rabbitmq/client/QueueingConsumer.java b/src/main/java/com/rabbitmq/client/QueueingConsumer.java similarity index 100% rename from src/com/rabbitmq/client/QueueingConsumer.java rename to src/main/java/com/rabbitmq/client/QueueingConsumer.java diff --git a/src/com/rabbitmq/client/Recoverable.java b/src/main/java/com/rabbitmq/client/Recoverable.java similarity index 100% rename from src/com/rabbitmq/client/Recoverable.java rename to src/main/java/com/rabbitmq/client/Recoverable.java diff --git a/src/com/rabbitmq/client/RecoveryListener.java b/src/main/java/com/rabbitmq/client/RecoveryListener.java similarity index 100% rename from src/com/rabbitmq/client/RecoveryListener.java rename to src/main/java/com/rabbitmq/client/RecoveryListener.java diff --git a/src/com/rabbitmq/client/ReturnListener.java b/src/main/java/com/rabbitmq/client/ReturnListener.java similarity index 100% rename from src/com/rabbitmq/client/ReturnListener.java rename to src/main/java/com/rabbitmq/client/ReturnListener.java diff --git a/src/com/rabbitmq/client/RpcClient.java b/src/main/java/com/rabbitmq/client/RpcClient.java similarity index 100% rename from src/com/rabbitmq/client/RpcClient.java rename to src/main/java/com/rabbitmq/client/RpcClient.java diff --git a/src/com/rabbitmq/client/RpcServer.java b/src/main/java/com/rabbitmq/client/RpcServer.java similarity index 100% rename from src/com/rabbitmq/client/RpcServer.java rename to src/main/java/com/rabbitmq/client/RpcServer.java diff --git a/src/com/rabbitmq/client/SaslConfig.java b/src/main/java/com/rabbitmq/client/SaslConfig.java similarity index 100% rename from src/com/rabbitmq/client/SaslConfig.java rename to src/main/java/com/rabbitmq/client/SaslConfig.java diff --git a/src/com/rabbitmq/client/SaslMechanism.java b/src/main/java/com/rabbitmq/client/SaslMechanism.java similarity index 100% rename from src/com/rabbitmq/client/SaslMechanism.java rename to src/main/java/com/rabbitmq/client/SaslMechanism.java diff --git a/src/com/rabbitmq/client/ShutdownListener.java b/src/main/java/com/rabbitmq/client/ShutdownListener.java similarity index 100% rename from src/com/rabbitmq/client/ShutdownListener.java rename to src/main/java/com/rabbitmq/client/ShutdownListener.java diff --git a/src/com/rabbitmq/client/ShutdownNotifier.java b/src/main/java/com/rabbitmq/client/ShutdownNotifier.java similarity index 100% rename from src/com/rabbitmq/client/ShutdownNotifier.java rename to src/main/java/com/rabbitmq/client/ShutdownNotifier.java diff --git a/src/com/rabbitmq/client/ShutdownSignalException.java b/src/main/java/com/rabbitmq/client/ShutdownSignalException.java similarity index 100% rename from src/com/rabbitmq/client/ShutdownSignalException.java rename to src/main/java/com/rabbitmq/client/ShutdownSignalException.java diff --git a/src/com/rabbitmq/client/SocketConfigurator.java b/src/main/java/com/rabbitmq/client/SocketConfigurator.java similarity index 100% rename from src/com/rabbitmq/client/SocketConfigurator.java rename to src/main/java/com/rabbitmq/client/SocketConfigurator.java diff --git a/src/com/rabbitmq/client/StringRpcServer.java b/src/main/java/com/rabbitmq/client/StringRpcServer.java similarity index 100% rename from src/com/rabbitmq/client/StringRpcServer.java rename to src/main/java/com/rabbitmq/client/StringRpcServer.java diff --git a/src/com/rabbitmq/client/TopologyRecoveryException.java b/src/main/java/com/rabbitmq/client/TopologyRecoveryException.java similarity index 100% rename from src/com/rabbitmq/client/TopologyRecoveryException.java rename to src/main/java/com/rabbitmq/client/TopologyRecoveryException.java diff --git a/src/com/rabbitmq/client/UnexpectedFrameError.java b/src/main/java/com/rabbitmq/client/UnexpectedFrameError.java similarity index 100% rename from src/com/rabbitmq/client/UnexpectedFrameError.java rename to src/main/java/com/rabbitmq/client/UnexpectedFrameError.java diff --git a/src/com/rabbitmq/client/UnexpectedMethodError.java b/src/main/java/com/rabbitmq/client/UnexpectedMethodError.java similarity index 100% rename from src/com/rabbitmq/client/UnexpectedMethodError.java rename to src/main/java/com/rabbitmq/client/UnexpectedMethodError.java diff --git a/src/com/rabbitmq/client/UnknownClassOrMethodId.java b/src/main/java/com/rabbitmq/client/UnknownClassOrMethodId.java similarity index 100% rename from src/com/rabbitmq/client/UnknownClassOrMethodId.java rename to src/main/java/com/rabbitmq/client/UnknownClassOrMethodId.java diff --git a/src/com/rabbitmq/client/impl/AMQBasicProperties.java b/src/main/java/com/rabbitmq/client/impl/AMQBasicProperties.java similarity index 100% rename from src/com/rabbitmq/client/impl/AMQBasicProperties.java rename to src/main/java/com/rabbitmq/client/impl/AMQBasicProperties.java diff --git a/src/com/rabbitmq/client/impl/AMQChannel.java b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java similarity index 100% rename from src/com/rabbitmq/client/impl/AMQChannel.java rename to src/main/java/com/rabbitmq/client/impl/AMQChannel.java diff --git a/src/com/rabbitmq/client/impl/AMQCommand.java b/src/main/java/com/rabbitmq/client/impl/AMQCommand.java similarity index 100% rename from src/com/rabbitmq/client/impl/AMQCommand.java rename to src/main/java/com/rabbitmq/client/impl/AMQCommand.java diff --git a/src/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java similarity index 100% rename from src/com/rabbitmq/client/impl/AMQConnection.java rename to src/main/java/com/rabbitmq/client/impl/AMQConnection.java diff --git a/src/com/rabbitmq/client/impl/AMQContentHeader.java b/src/main/java/com/rabbitmq/client/impl/AMQContentHeader.java similarity index 100% rename from src/com/rabbitmq/client/impl/AMQContentHeader.java rename to src/main/java/com/rabbitmq/client/impl/AMQContentHeader.java diff --git a/src/com/rabbitmq/client/impl/CRDemoMechanism.java b/src/main/java/com/rabbitmq/client/impl/CRDemoMechanism.java similarity index 100% rename from src/com/rabbitmq/client/impl/CRDemoMechanism.java rename to src/main/java/com/rabbitmq/client/impl/CRDemoMechanism.java diff --git a/src/com/rabbitmq/client/impl/ChannelManager.java b/src/main/java/com/rabbitmq/client/impl/ChannelManager.java similarity index 100% rename from src/com/rabbitmq/client/impl/ChannelManager.java rename to src/main/java/com/rabbitmq/client/impl/ChannelManager.java diff --git a/src/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java similarity index 100% rename from src/com/rabbitmq/client/impl/ChannelN.java rename to src/main/java/com/rabbitmq/client/impl/ChannelN.java diff --git a/src/com/rabbitmq/client/impl/ClientVersion.java.in b/src/main/java/com/rabbitmq/client/impl/ClientVersion.java.in similarity index 100% rename from src/com/rabbitmq/client/impl/ClientVersion.java.in rename to src/main/java/com/rabbitmq/client/impl/ClientVersion.java.in diff --git a/src/com/rabbitmq/client/impl/CommandAssembler.java b/src/main/java/com/rabbitmq/client/impl/CommandAssembler.java similarity index 100% rename from src/com/rabbitmq/client/impl/CommandAssembler.java rename to src/main/java/com/rabbitmq/client/impl/CommandAssembler.java diff --git a/src/com/rabbitmq/client/impl/ConnectionParams.java b/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java similarity index 100% rename from src/com/rabbitmq/client/impl/ConnectionParams.java rename to src/main/java/com/rabbitmq/client/impl/ConnectionParams.java diff --git a/src/com/rabbitmq/client/impl/ConsumerDispatcher.java b/src/main/java/com/rabbitmq/client/impl/ConsumerDispatcher.java similarity index 100% rename from src/com/rabbitmq/client/impl/ConsumerDispatcher.java rename to src/main/java/com/rabbitmq/client/impl/ConsumerDispatcher.java diff --git a/src/com/rabbitmq/client/impl/ConsumerWorkService.java b/src/main/java/com/rabbitmq/client/impl/ConsumerWorkService.java similarity index 100% rename from src/com/rabbitmq/client/impl/ConsumerWorkService.java rename to src/main/java/com/rabbitmq/client/impl/ConsumerWorkService.java diff --git a/src/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java b/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java similarity index 100% rename from src/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java rename to src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java diff --git a/src/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java b/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java similarity index 100% rename from src/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java rename to src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java diff --git a/src/com/rabbitmq/client/impl/DefaultExceptionHandler.java b/src/main/java/com/rabbitmq/client/impl/DefaultExceptionHandler.java similarity index 100% rename from src/com/rabbitmq/client/impl/DefaultExceptionHandler.java rename to src/main/java/com/rabbitmq/client/impl/DefaultExceptionHandler.java diff --git a/src/com/rabbitmq/client/impl/Environment.java b/src/main/java/com/rabbitmq/client/impl/Environment.java similarity index 100% rename from src/com/rabbitmq/client/impl/Environment.java rename to src/main/java/com/rabbitmq/client/impl/Environment.java diff --git a/src/com/rabbitmq/client/impl/ExternalMechanism.java b/src/main/java/com/rabbitmq/client/impl/ExternalMechanism.java similarity index 100% rename from src/com/rabbitmq/client/impl/ExternalMechanism.java rename to src/main/java/com/rabbitmq/client/impl/ExternalMechanism.java diff --git a/src/com/rabbitmq/client/impl/ForgivingExceptionHandler.java b/src/main/java/com/rabbitmq/client/impl/ForgivingExceptionHandler.java similarity index 100% rename from src/com/rabbitmq/client/impl/ForgivingExceptionHandler.java rename to src/main/java/com/rabbitmq/client/impl/ForgivingExceptionHandler.java diff --git a/src/com/rabbitmq/client/impl/Frame.java b/src/main/java/com/rabbitmq/client/impl/Frame.java similarity index 100% rename from src/com/rabbitmq/client/impl/Frame.java rename to src/main/java/com/rabbitmq/client/impl/Frame.java diff --git a/src/com/rabbitmq/client/impl/FrameHandler.java b/src/main/java/com/rabbitmq/client/impl/FrameHandler.java similarity index 100% rename from src/com/rabbitmq/client/impl/FrameHandler.java rename to src/main/java/com/rabbitmq/client/impl/FrameHandler.java diff --git a/src/com/rabbitmq/client/impl/FrameHandlerFactory.java b/src/main/java/com/rabbitmq/client/impl/FrameHandlerFactory.java similarity index 100% rename from src/com/rabbitmq/client/impl/FrameHandlerFactory.java rename to src/main/java/com/rabbitmq/client/impl/FrameHandlerFactory.java diff --git a/src/com/rabbitmq/client/impl/HeartbeatSender.java b/src/main/java/com/rabbitmq/client/impl/HeartbeatSender.java similarity index 100% rename from src/com/rabbitmq/client/impl/HeartbeatSender.java rename to src/main/java/com/rabbitmq/client/impl/HeartbeatSender.java diff --git a/src/com/rabbitmq/client/impl/LongStringHelper.java b/src/main/java/com/rabbitmq/client/impl/LongStringHelper.java similarity index 100% rename from src/com/rabbitmq/client/impl/LongStringHelper.java rename to src/main/java/com/rabbitmq/client/impl/LongStringHelper.java diff --git a/src/com/rabbitmq/client/impl/Method.java b/src/main/java/com/rabbitmq/client/impl/Method.java similarity index 100% rename from src/com/rabbitmq/client/impl/Method.java rename to src/main/java/com/rabbitmq/client/impl/Method.java diff --git a/src/com/rabbitmq/client/impl/MethodArgumentReader.java b/src/main/java/com/rabbitmq/client/impl/MethodArgumentReader.java similarity index 100% rename from src/com/rabbitmq/client/impl/MethodArgumentReader.java rename to src/main/java/com/rabbitmq/client/impl/MethodArgumentReader.java diff --git a/src/com/rabbitmq/client/impl/MethodArgumentWriter.java b/src/main/java/com/rabbitmq/client/impl/MethodArgumentWriter.java similarity index 100% rename from src/com/rabbitmq/client/impl/MethodArgumentWriter.java rename to src/main/java/com/rabbitmq/client/impl/MethodArgumentWriter.java diff --git a/src/com/rabbitmq/client/impl/NetworkConnection.java b/src/main/java/com/rabbitmq/client/impl/NetworkConnection.java similarity index 100% rename from src/com/rabbitmq/client/impl/NetworkConnection.java rename to src/main/java/com/rabbitmq/client/impl/NetworkConnection.java diff --git a/src/com/rabbitmq/client/impl/PlainMechanism.java b/src/main/java/com/rabbitmq/client/impl/PlainMechanism.java similarity index 100% rename from src/com/rabbitmq/client/impl/PlainMechanism.java rename to src/main/java/com/rabbitmq/client/impl/PlainMechanism.java diff --git a/src/com/rabbitmq/client/impl/SetQueue.java b/src/main/java/com/rabbitmq/client/impl/SetQueue.java similarity index 100% rename from src/com/rabbitmq/client/impl/SetQueue.java rename to src/main/java/com/rabbitmq/client/impl/SetQueue.java diff --git a/src/com/rabbitmq/client/impl/ShutdownNotifierComponent.java b/src/main/java/com/rabbitmq/client/impl/ShutdownNotifierComponent.java similarity index 100% rename from src/com/rabbitmq/client/impl/ShutdownNotifierComponent.java rename to src/main/java/com/rabbitmq/client/impl/ShutdownNotifierComponent.java diff --git a/src/com/rabbitmq/client/impl/SocketFrameHandler.java b/src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java similarity index 100% rename from src/com/rabbitmq/client/impl/SocketFrameHandler.java rename to src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java diff --git a/src/com/rabbitmq/client/impl/StrictExceptionHandler.java b/src/main/java/com/rabbitmq/client/impl/StrictExceptionHandler.java similarity index 100% rename from src/com/rabbitmq/client/impl/StrictExceptionHandler.java rename to src/main/java/com/rabbitmq/client/impl/StrictExceptionHandler.java diff --git a/src/com/rabbitmq/client/impl/TruncatedInputStream.java b/src/main/java/com/rabbitmq/client/impl/TruncatedInputStream.java similarity index 100% rename from src/com/rabbitmq/client/impl/TruncatedInputStream.java rename to src/main/java/com/rabbitmq/client/impl/TruncatedInputStream.java diff --git a/src/com/rabbitmq/client/impl/UnknownChannelException.java b/src/main/java/com/rabbitmq/client/impl/UnknownChannelException.java similarity index 100% rename from src/com/rabbitmq/client/impl/UnknownChannelException.java rename to src/main/java/com/rabbitmq/client/impl/UnknownChannelException.java diff --git a/src/com/rabbitmq/client/impl/ValueReader.java b/src/main/java/com/rabbitmq/client/impl/ValueReader.java similarity index 100% rename from src/com/rabbitmq/client/impl/ValueReader.java rename to src/main/java/com/rabbitmq/client/impl/ValueReader.java diff --git a/src/com/rabbitmq/client/impl/ValueWriter.java b/src/main/java/com/rabbitmq/client/impl/ValueWriter.java similarity index 100% rename from src/com/rabbitmq/client/impl/ValueWriter.java rename to src/main/java/com/rabbitmq/client/impl/ValueWriter.java diff --git a/src/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java b/src/main/java/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java similarity index 100% rename from src/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java rename to src/main/java/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java diff --git a/src/com/rabbitmq/client/impl/Version.java b/src/main/java/com/rabbitmq/client/impl/Version.java similarity index 100% rename from src/com/rabbitmq/client/impl/Version.java rename to src/main/java/com/rabbitmq/client/impl/Version.java diff --git a/src/com/rabbitmq/client/impl/WorkPool.java b/src/main/java/com/rabbitmq/client/impl/WorkPool.java similarity index 100% rename from src/com/rabbitmq/client/impl/WorkPool.java rename to src/main/java/com/rabbitmq/client/impl/WorkPool.java diff --git a/src/com/rabbitmq/client/impl/package.html b/src/main/java/com/rabbitmq/client/impl/package.html similarity index 100% rename from src/com/rabbitmq/client/impl/package.html rename to src/main/java/com/rabbitmq/client/impl/package.html diff --git a/src/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java similarity index 100% rename from src/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java rename to src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java diff --git a/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java similarity index 100% rename from src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java rename to src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java diff --git a/src/com/rabbitmq/client/impl/recovery/ConsumerRecoveryListener.java b/src/main/java/com/rabbitmq/client/impl/recovery/ConsumerRecoveryListener.java similarity index 100% rename from src/com/rabbitmq/client/impl/recovery/ConsumerRecoveryListener.java rename to src/main/java/com/rabbitmq/client/impl/recovery/ConsumerRecoveryListener.java diff --git a/src/com/rabbitmq/client/impl/recovery/QueueRecoveryListener.java b/src/main/java/com/rabbitmq/client/impl/recovery/QueueRecoveryListener.java similarity index 100% rename from src/com/rabbitmq/client/impl/recovery/QueueRecoveryListener.java rename to src/main/java/com/rabbitmq/client/impl/recovery/QueueRecoveryListener.java diff --git a/src/com/rabbitmq/client/impl/recovery/RecordedBinding.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedBinding.java similarity index 100% rename from src/com/rabbitmq/client/impl/recovery/RecordedBinding.java rename to src/main/java/com/rabbitmq/client/impl/recovery/RecordedBinding.java diff --git a/src/com/rabbitmq/client/impl/recovery/RecordedConsumer.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedConsumer.java similarity index 100% rename from src/com/rabbitmq/client/impl/recovery/RecordedConsumer.java rename to src/main/java/com/rabbitmq/client/impl/recovery/RecordedConsumer.java diff --git a/src/com/rabbitmq/client/impl/recovery/RecordedEntity.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedEntity.java similarity index 100% rename from src/com/rabbitmq/client/impl/recovery/RecordedEntity.java rename to src/main/java/com/rabbitmq/client/impl/recovery/RecordedEntity.java diff --git a/src/com/rabbitmq/client/impl/recovery/RecordedExchange.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchange.java similarity index 100% rename from src/com/rabbitmq/client/impl/recovery/RecordedExchange.java rename to src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchange.java diff --git a/src/com/rabbitmq/client/impl/recovery/RecordedExchangeBinding.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchangeBinding.java similarity index 100% rename from src/com/rabbitmq/client/impl/recovery/RecordedExchangeBinding.java rename to src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchangeBinding.java diff --git a/src/com/rabbitmq/client/impl/recovery/RecordedNamedEntity.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedNamedEntity.java similarity index 100% rename from src/com/rabbitmq/client/impl/recovery/RecordedNamedEntity.java rename to src/main/java/com/rabbitmq/client/impl/recovery/RecordedNamedEntity.java diff --git a/src/com/rabbitmq/client/impl/recovery/RecordedQueue.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java similarity index 100% rename from src/com/rabbitmq/client/impl/recovery/RecordedQueue.java rename to src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java diff --git a/src/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java similarity index 100% rename from src/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java rename to src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java diff --git a/src/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnection.java similarity index 100% rename from src/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnection.java rename to src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnection.java diff --git a/src/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java similarity index 100% rename from src/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java rename to src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java diff --git a/src/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelManager.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelManager.java similarity index 100% rename from src/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelManager.java rename to src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelManager.java diff --git a/src/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java similarity index 100% rename from src/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java rename to src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java diff --git a/src/com/rabbitmq/client/package.html b/src/main/java/com/rabbitmq/client/package.html similarity index 100% rename from src/com/rabbitmq/client/package.html rename to src/main/java/com/rabbitmq/client/package.html diff --git a/src/com/rabbitmq/tools/Tracer.java b/src/main/java/com/rabbitmq/tools/Tracer.java similarity index 100% rename from src/com/rabbitmq/tools/Tracer.java rename to src/main/java/com/rabbitmq/tools/Tracer.java diff --git a/src/com/rabbitmq/tools/json/JSONReader.java b/src/main/java/com/rabbitmq/tools/json/JSONReader.java similarity index 100% rename from src/com/rabbitmq/tools/json/JSONReader.java rename to src/main/java/com/rabbitmq/tools/json/JSONReader.java diff --git a/src/com/rabbitmq/tools/json/JSONSerializable.java b/src/main/java/com/rabbitmq/tools/json/JSONSerializable.java similarity index 100% rename from src/com/rabbitmq/tools/json/JSONSerializable.java rename to src/main/java/com/rabbitmq/tools/json/JSONSerializable.java diff --git a/src/com/rabbitmq/tools/json/JSONUtil.java b/src/main/java/com/rabbitmq/tools/json/JSONUtil.java similarity index 100% rename from src/com/rabbitmq/tools/json/JSONUtil.java rename to src/main/java/com/rabbitmq/tools/json/JSONUtil.java diff --git a/src/com/rabbitmq/tools/json/JSONWriter.java b/src/main/java/com/rabbitmq/tools/json/JSONWriter.java similarity index 100% rename from src/com/rabbitmq/tools/json/JSONWriter.java rename to src/main/java/com/rabbitmq/tools/json/JSONWriter.java diff --git a/src/com/rabbitmq/tools/json/package.html b/src/main/java/com/rabbitmq/tools/json/package.html similarity index 100% rename from src/com/rabbitmq/tools/json/package.html rename to src/main/java/com/rabbitmq/tools/json/package.html diff --git a/src/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java similarity index 100% rename from src/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java rename to src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java diff --git a/src/com/rabbitmq/tools/jsonrpc/JsonRpcException.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java similarity index 100% rename from src/com/rabbitmq/tools/jsonrpc/JsonRpcException.java rename to src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java diff --git a/src/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java similarity index 100% rename from src/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java rename to src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java diff --git a/src/com/rabbitmq/tools/jsonrpc/ParameterDescription.java b/src/main/java/com/rabbitmq/tools/jsonrpc/ParameterDescription.java similarity index 100% rename from src/com/rabbitmq/tools/jsonrpc/ParameterDescription.java rename to src/main/java/com/rabbitmq/tools/jsonrpc/ParameterDescription.java diff --git a/src/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java b/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java similarity index 100% rename from src/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java rename to src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java diff --git a/src/com/rabbitmq/tools/jsonrpc/ServiceDescription.java b/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java similarity index 100% rename from src/com/rabbitmq/tools/jsonrpc/ServiceDescription.java rename to src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java diff --git a/src/com/rabbitmq/tools/jsonrpc/package.html b/src/main/java/com/rabbitmq/tools/jsonrpc/package.html similarity index 100% rename from src/com/rabbitmq/tools/jsonrpc/package.html rename to src/main/java/com/rabbitmq/tools/jsonrpc/package.html diff --git a/src/com/rabbitmq/tools/package.html b/src/main/java/com/rabbitmq/tools/package.html similarity index 100% rename from src/com/rabbitmq/tools/package.html rename to src/main/java/com/rabbitmq/tools/package.html diff --git a/src/com/rabbitmq/utility/BlockingCell.java b/src/main/java/com/rabbitmq/utility/BlockingCell.java similarity index 100% rename from src/com/rabbitmq/utility/BlockingCell.java rename to src/main/java/com/rabbitmq/utility/BlockingCell.java diff --git a/src/com/rabbitmq/utility/BlockingValueOrException.java b/src/main/java/com/rabbitmq/utility/BlockingValueOrException.java similarity index 100% rename from src/com/rabbitmq/utility/BlockingValueOrException.java rename to src/main/java/com/rabbitmq/utility/BlockingValueOrException.java diff --git a/src/com/rabbitmq/utility/IntAllocator.java b/src/main/java/com/rabbitmq/utility/IntAllocator.java similarity index 100% rename from src/com/rabbitmq/utility/IntAllocator.java rename to src/main/java/com/rabbitmq/utility/IntAllocator.java diff --git a/src/com/rabbitmq/utility/SensibleClone.java b/src/main/java/com/rabbitmq/utility/SensibleClone.java similarity index 100% rename from src/com/rabbitmq/utility/SensibleClone.java rename to src/main/java/com/rabbitmq/utility/SensibleClone.java diff --git a/src/com/rabbitmq/utility/SingleShotLinearTimer.java b/src/main/java/com/rabbitmq/utility/SingleShotLinearTimer.java similarity index 100% rename from src/com/rabbitmq/utility/SingleShotLinearTimer.java rename to src/main/java/com/rabbitmq/utility/SingleShotLinearTimer.java diff --git a/src/com/rabbitmq/utility/Utility.java b/src/main/java/com/rabbitmq/utility/Utility.java similarity index 100% rename from src/com/rabbitmq/utility/Utility.java rename to src/main/java/com/rabbitmq/utility/Utility.java diff --git a/src/com/rabbitmq/utility/ValueOrException.java b/src/main/java/com/rabbitmq/utility/ValueOrException.java similarity index 100% rename from src/com/rabbitmq/utility/ValueOrException.java rename to src/main/java/com/rabbitmq/utility/ValueOrException.java diff --git a/src/com/rabbitmq/utility/package.html b/src/main/java/com/rabbitmq/utility/package.html similarity index 100% rename from src/com/rabbitmq/utility/package.html rename to src/main/java/com/rabbitmq/utility/package.html diff --git a/test/src/com/rabbitmq/client/impl/WorkPoolTests.java b/src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java similarity index 100% rename from test/src/com/rabbitmq/client/impl/WorkPoolTests.java rename to src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java diff --git a/test/src/com/rabbitmq/client/test/AMQBuilderApiTest.java b/src/test/java/com/rabbitmq/client/test/AMQBuilderApiTest.java similarity index 100% rename from test/src/com/rabbitmq/client/test/AMQBuilderApiTest.java rename to src/test/java/com/rabbitmq/client/test/AMQBuilderApiTest.java diff --git a/test/src/com/rabbitmq/client/test/AMQConnectionTest.java b/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java similarity index 100% rename from test/src/com/rabbitmq/client/test/AMQConnectionTest.java rename to src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java diff --git a/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java b/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java new file mode 100644 index 0000000000..16614b4f7f --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java @@ -0,0 +1,114 @@ +package com.rabbitmq.client.test; + +import java.io.File; +import java.io.IOException; +import java.net.Socket; +import java.nio.file.FileSystems; +import java.util.Properties; + +import junit.framework.Test; +import junit.framework.TestResult; +import junit.framework.TestSuite; + +import com.rabbitmq.tools.Host; + +public abstract class AbstractRMQTestSuite extends TestSuite { + private static final String DEFAULT_SSL_HOSTNAME = "localhost"; + private static final int DEFAULT_SSL_PORT = 5671; + + private static boolean buildSSLPropertiesFound = false; + + static { + Properties TESTS_PROPS = new Properties(System.getProperties()); + TESTS_PROPS.setProperty("make.bin", + System.getenv("MAKE") == null ? "make" : System.getenv("MAKE")); + try { + TESTS_PROPS.load(Host.class.getClassLoader().getResourceAsStream("build.properties")); + TESTS_PROPS.load(Host.class.getClassLoader().getResourceAsStream("config.properties")); + } catch (Exception e) { + System.out.println( + "\"build.properties\" or \"config.properties\" not found" + + " in classpath. Please copy \"build.properties\" and" + + " \"config.properties\" into src/test/resources. Ignore" + + " this message if running with ant."); + } finally { + System.setProperties(TESTS_PROPS); + } + } + + public static boolean requiredProperties() { + /* GNU Make. */ + String make = Host.makeCommand(); + boolean isGNUMake = false; + if (make != null) { + try { + Process makeProc = Host.executeCommandIgnoringErrors(make + " --version"); + String makeVersion = Host.capture(makeProc.getInputStream()); + isGNUMake = makeVersion.startsWith("GNU Make"); + } catch (IOException e) {} + } + if (!isGNUMake) { + System.err.println( + "GNU Make required; please set \"make.bin\" system property" + + " or \"$MAKE\" environment variable"); + return false; + } + + /* Path to rabbitmq_test. */ + String rabbitmq_test = Host.rabbitmqTestDir(); + if (rabbitmq_test == null || !new File(rabbitmq_test).isDirectory()) { + System.err.println( + "rabbitmq_test required; please set \"sibling.rabbitmq_test.dir\" system" + + " property"); + return false; + } + + /* Path to rabbitmqctl. */ + String rabbitmqctl = Host.rabbitmqctlCommand(); + if (rabbitmqctl == null || !new File(rabbitmqctl).isFile()) { + System.err.println( + "rabbitmqctl required; please set \"rabbitmqctl.bin\" system" + + " property"); + return false; + } + + return true; + } + + public static boolean isUnderUmbrella() { + return new File("../../UMBRELLA.md").isFile(); + } + + public static boolean isSSLAvailable() { + String SSL_CERTS_DIR = System.getenv("SSL_CERTS_DIR"); + String hostname = System.getProperty("broker.hostname"); + String port = System.getProperty("broker.sslport"); + if (SSL_CERTS_DIR == null || hostname == null || port == null) + return false; + + String sslClientCertsDir = SSL_CERTS_DIR + + FileSystems.getDefault().getSeparator() + "client"; + // If certificate is present and some server is listening on port 5671 + if (new File(sslClientCertsDir).exists() && + checkServerListening(hostname, Integer.parseInt(port))) { + return true; + } else + return false; + } + + private static boolean checkServerListening(String host, int port) { + Socket s = null; + try { + s = new Socket(host, port); + return true; + } catch (Exception e) { + return false; + } finally { + if (s != null) + try { + s.close(); + } catch (Exception e) { + } + } + } +} diff --git a/test/src/com/rabbitmq/client/test/AmqpUriTest.java b/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java similarity index 100% rename from test/src/com/rabbitmq/client/test/AmqpUriTest.java rename to src/test/java/com/rabbitmq/client/test/AmqpUriTest.java diff --git a/test/src/com/rabbitmq/client/test/BlockingCellTest.java b/src/test/java/com/rabbitmq/client/test/BlockingCellTest.java similarity index 100% rename from test/src/com/rabbitmq/client/test/BlockingCellTest.java rename to src/test/java/com/rabbitmq/client/test/BlockingCellTest.java diff --git a/test/src/com/rabbitmq/client/test/BrokenFramesTest.java b/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java similarity index 100% rename from test/src/com/rabbitmq/client/test/BrokenFramesTest.java rename to src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java diff --git a/test/src/com/rabbitmq/client/test/BrokerTestCase.java b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java similarity index 99% rename from test/src/com/rabbitmq/client/test/BrokerTestCase.java rename to src/test/java/com/rabbitmq/client/test/BrokerTestCase.java index 2f342f0238..4f1dd54ebb 100644 --- a/test/src/com/rabbitmq/client/test/BrokerTestCase.java +++ b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java @@ -24,23 +24,21 @@ import java.util.UUID; import java.util.concurrent.TimeoutException; +import javax.net.ssl.SSLContext; + import junit.framework.TestCase; +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.AlreadyClosedException; import com.rabbitmq.client.Channel; -import com.rabbitmq.client.Command; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.GetResponse; import com.rabbitmq.client.MessageProperties; import com.rabbitmq.client.Method; import com.rabbitmq.client.ShutdownSignalException; -import com.rabbitmq.client.AlreadyClosedException; -import com.rabbitmq.client.impl.ShutdownNotifierComponent; -import com.rabbitmq.client.AMQP; import com.rabbitmq.tools.Host; -import javax.net.ssl.SSLContext; - public class BrokerTestCase extends TestCase { protected ConnectionFactory connectionFactory = newConnectionFactory(); diff --git a/test/src/com/rabbitmq/client/test/Bug20004Test.java b/src/test/java/com/rabbitmq/client/test/Bug20004Test.java similarity index 100% rename from test/src/com/rabbitmq/client/test/Bug20004Test.java rename to src/test/java/com/rabbitmq/client/test/Bug20004Test.java diff --git a/test/src/com/rabbitmq/client/test/ChannelNumberAllocationTests.java b/src/test/java/com/rabbitmq/client/test/ChannelNumberAllocationTests.java similarity index 100% rename from test/src/com/rabbitmq/client/test/ChannelNumberAllocationTests.java rename to src/test/java/com/rabbitmq/client/test/ChannelNumberAllocationTests.java diff --git a/test/src/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java similarity index 93% rename from test/src/com/rabbitmq/client/test/ClientTests.java rename to src/test/java/com/rabbitmq/client/test/ClientTests.java index af38902083..ef2bf97710 100644 --- a/test/src/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -17,11 +17,11 @@ package com.rabbitmq.client.test; -import junit.framework.TestCase; import junit.framework.TestSuite; -public class ClientTests extends TestCase { - public static TestSuite suite() { +public class ClientTests extends AbstractRMQTestSuite { + + public static TestSuite suite() { TestSuite suite = new TestSuite("client"); suite.addTest(TableTest.suite()); suite.addTest(LongStringTest.suite()); diff --git a/test/src/com/rabbitmq/client/test/ClonePropertiesTest.java b/src/test/java/com/rabbitmq/client/test/ClonePropertiesTest.java similarity index 100% rename from test/src/com/rabbitmq/client/test/ClonePropertiesTest.java rename to src/test/java/com/rabbitmq/client/test/ClonePropertiesTest.java diff --git a/test/src/com/rabbitmq/client/test/CloseInMainLoop.java b/src/test/java/com/rabbitmq/client/test/CloseInMainLoop.java similarity index 100% rename from test/src/com/rabbitmq/client/test/CloseInMainLoop.java rename to src/test/java/com/rabbitmq/client/test/CloseInMainLoop.java diff --git a/test/src/com/rabbitmq/client/test/ConfirmBase.java b/src/test/java/com/rabbitmq/client/test/ConfirmBase.java similarity index 100% rename from test/src/com/rabbitmq/client/test/ConfirmBase.java rename to src/test/java/com/rabbitmq/client/test/ConfirmBase.java diff --git a/test/src/com/rabbitmq/client/test/JSONReadWriteTest.java b/src/test/java/com/rabbitmq/client/test/JSONReadWriteTest.java similarity index 96% rename from test/src/com/rabbitmq/client/test/JSONReadWriteTest.java rename to src/test/java/com/rabbitmq/client/test/JSONReadWriteTest.java index b385dc0b13..ad0b143dfa 100644 --- a/test/src/com/rabbitmq/client/test/JSONReadWriteTest.java +++ b/src/test/java/com/rabbitmq/client/test/JSONReadWriteTest.java @@ -17,15 +17,10 @@ package com.rabbitmq.client.test; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; +import junit.framework.TestCase; -import com.rabbitmq.tools.json.JSONWriter; import com.rabbitmq.tools.json.JSONReader; - -import junit.framework.TestCase; +import com.rabbitmq.tools.json.JSONWriter; public class JSONReadWriteTest extends TestCase { diff --git a/test/src/com/rabbitmq/client/test/LongStringTest.java b/src/test/java/com/rabbitmq/client/test/LongStringTest.java similarity index 100% rename from test/src/com/rabbitmq/client/test/LongStringTest.java rename to src/test/java/com/rabbitmq/client/test/LongStringTest.java diff --git a/test/src/com/rabbitmq/client/test/MultiThreadedChannel.java b/src/test/java/com/rabbitmq/client/test/MultiThreadedChannel.java similarity index 100% rename from test/src/com/rabbitmq/client/test/MultiThreadedChannel.java rename to src/test/java/com/rabbitmq/client/test/MultiThreadedChannel.java diff --git a/test/src/com/rabbitmq/client/test/QueueingConsumerShutdownTests.java b/src/test/java/com/rabbitmq/client/test/QueueingConsumerShutdownTests.java similarity index 100% rename from test/src/com/rabbitmq/client/test/QueueingConsumerShutdownTests.java rename to src/test/java/com/rabbitmq/client/test/QueueingConsumerShutdownTests.java diff --git a/test/src/com/rabbitmq/client/test/SharedThreadPoolTest.java b/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java similarity index 100% rename from test/src/com/rabbitmq/client/test/SharedThreadPoolTest.java rename to src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java diff --git a/test/src/com/rabbitmq/client/test/TableTest.java b/src/test/java/com/rabbitmq/client/test/TableTest.java similarity index 100% rename from test/src/com/rabbitmq/client/test/TableTest.java rename to src/test/java/com/rabbitmq/client/test/TableTest.java diff --git a/test/src/com/rabbitmq/client/test/TruncatedInputStreamTest.java b/src/test/java/com/rabbitmq/client/test/TruncatedInputStreamTest.java similarity index 100% rename from test/src/com/rabbitmq/client/test/TruncatedInputStreamTest.java rename to src/test/java/com/rabbitmq/client/test/TruncatedInputStreamTest.java diff --git a/test/src/com/rabbitmq/client/test/ValueOrExceptionTest.java b/src/test/java/com/rabbitmq/client/test/ValueOrExceptionTest.java similarity index 100% rename from test/src/com/rabbitmq/client/test/ValueOrExceptionTest.java rename to src/test/java/com/rabbitmq/client/test/ValueOrExceptionTest.java diff --git a/test/src/com/rabbitmq/client/test/functional/AbstractRejectTest.java b/src/test/java/com/rabbitmq/client/test/functional/AbstractRejectTest.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/AbstractRejectTest.java rename to src/test/java/com/rabbitmq/client/test/functional/AbstractRejectTest.java diff --git a/test/src/com/rabbitmq/client/test/functional/AlternateExchange.java b/src/test/java/com/rabbitmq/client/test/functional/AlternateExchange.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/AlternateExchange.java rename to src/test/java/com/rabbitmq/client/test/functional/AlternateExchange.java diff --git a/test/src/com/rabbitmq/client/test/functional/BasicGet.java b/src/test/java/com/rabbitmq/client/test/functional/BasicGet.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/BasicGet.java rename to src/test/java/com/rabbitmq/client/test/functional/BasicGet.java diff --git a/test/src/com/rabbitmq/client/test/functional/BindingLifecycle.java b/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/BindingLifecycle.java rename to src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java diff --git a/test/src/com/rabbitmq/client/test/functional/BindingLifecycleBase.java b/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycleBase.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/BindingLifecycleBase.java rename to src/test/java/com/rabbitmq/client/test/functional/BindingLifecycleBase.java diff --git a/test/src/com/rabbitmq/client/test/functional/CcRoutes.java b/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/CcRoutes.java rename to src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java diff --git a/test/src/com/rabbitmq/client/test/functional/ClusteredTestBase.java b/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/ClusteredTestBase.java rename to src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java diff --git a/test/src/com/rabbitmq/client/test/functional/Confirm.java b/src/test/java/com/rabbitmq/client/test/functional/Confirm.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/Confirm.java rename to src/test/java/com/rabbitmq/client/test/functional/Confirm.java diff --git a/test/src/com/rabbitmq/client/test/functional/ConnectionOpen.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionOpen.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/ConnectionOpen.java rename to src/test/java/com/rabbitmq/client/test/functional/ConnectionOpen.java diff --git a/test/src/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/ConnectionRecovery.java rename to src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java diff --git a/test/src/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java b/src/test/java/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java rename to src/test/java/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java diff --git a/test/src/com/rabbitmq/client/test/functional/ConsumerCount.java b/src/test/java/com/rabbitmq/client/test/functional/ConsumerCount.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/ConsumerCount.java rename to src/test/java/com/rabbitmq/client/test/functional/ConsumerCount.java diff --git a/test/src/com/rabbitmq/client/test/functional/ConsumerPriorities.java b/src/test/java/com/rabbitmq/client/test/functional/ConsumerPriorities.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/ConsumerPriorities.java rename to src/test/java/com/rabbitmq/client/test/functional/ConsumerPriorities.java diff --git a/test/src/com/rabbitmq/client/test/functional/DeadLetterExchange.java b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/DeadLetterExchange.java rename to src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java diff --git a/test/src/com/rabbitmq/client/test/functional/DefaultExchange.java b/src/test/java/com/rabbitmq/client/test/functional/DefaultExchange.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/DefaultExchange.java rename to src/test/java/com/rabbitmq/client/test/functional/DefaultExchange.java diff --git a/test/src/com/rabbitmq/client/test/functional/DirectReplyTo.java b/src/test/java/com/rabbitmq/client/test/functional/DirectReplyTo.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/DirectReplyTo.java rename to src/test/java/com/rabbitmq/client/test/functional/DirectReplyTo.java diff --git a/test/src/com/rabbitmq/client/test/functional/DoubleDeletion.java b/src/test/java/com/rabbitmq/client/test/functional/DoubleDeletion.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/DoubleDeletion.java rename to src/test/java/com/rabbitmq/client/test/functional/DoubleDeletion.java diff --git a/test/src/com/rabbitmq/client/test/functional/DurableOnTransient.java b/src/test/java/com/rabbitmq/client/test/functional/DurableOnTransient.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/DurableOnTransient.java rename to src/test/java/com/rabbitmq/client/test/functional/DurableOnTransient.java diff --git a/test/src/com/rabbitmq/client/test/functional/ExceptionHandling.java b/src/test/java/com/rabbitmq/client/test/functional/ExceptionHandling.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/ExceptionHandling.java rename to src/test/java/com/rabbitmq/client/test/functional/ExceptionHandling.java diff --git a/test/src/com/rabbitmq/client/test/functional/ExceptionMessages.java b/src/test/java/com/rabbitmq/client/test/functional/ExceptionMessages.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/ExceptionMessages.java rename to src/test/java/com/rabbitmq/client/test/functional/ExceptionMessages.java diff --git a/test/src/com/rabbitmq/client/test/functional/ExchangeDeclare.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/ExchangeDeclare.java rename to src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java diff --git a/test/src/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java rename to src/test/java/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java diff --git a/test/src/com/rabbitmq/client/test/functional/ExchangeDeletePredeclared.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeletePredeclared.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/ExchangeDeletePredeclared.java rename to src/test/java/com/rabbitmq/client/test/functional/ExchangeDeletePredeclared.java diff --git a/test/src/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java rename to src/test/java/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java diff --git a/test/src/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java rename to src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java diff --git a/test/src/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java rename to src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java diff --git a/test/src/com/rabbitmq/client/test/functional/FrameMax.java b/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/FrameMax.java rename to src/test/java/com/rabbitmq/client/test/functional/FrameMax.java diff --git a/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java b/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java new file mode 100644 index 0000000000..c44138e940 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java @@ -0,0 +1,93 @@ +// The contents of this file are subject to the Mozilla Public License +// Version 1.1 (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.mozilla.org/MPL/ +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and +// limitations under the License. +// +// The Original Code is RabbitMQ. +// +// The Initial Developer of the Original Code is GoPivotal, Inc. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// + + +package com.rabbitmq.client.test.functional; + +import com.rabbitmq.client.impl.WorkPoolTests; +import com.rabbitmq.client.test.AbstractRMQTestSuite; +import com.rabbitmq.client.test.Bug20004Test; + +import junit.framework.TestCase; +import junit.framework.TestSuite; + +public class FunctionalTests extends AbstractRMQTestSuite { + public static TestSuite suite() { + TestSuite suite = new TestSuite("functional"); + if (!requiredProperties()) return suite; + if (!isUnderUmbrella()) return suite; + add(suite); + return suite; + } + + public static void add(TestSuite suite) { + suite.addTestSuite(ConnectionOpen.class); + suite.addTestSuite(Heartbeat.class); + suite.addTestSuite(Tables.class); + suite.addTestSuite(DoubleDeletion.class); + suite.addTestSuite(Routing.class); + suite.addTestSuite(BindingLifecycle.class); + suite.addTestSuite(Recover.class); + suite.addTestSuite(Reject.class); + suite.addTestSuite(Transactions.class); + suite.addTestSuite(RequeueOnConnectionClose.class); + suite.addTestSuite(RequeueOnChannelClose.class); + suite.addTestSuite(DurableOnTransient.class); + suite.addTestSuite(NoRequeueOnCancel.class); + suite.addTestSuite(Bug20004Test.class); + suite.addTestSuite(ExchangeDeleteIfUnused.class); + suite.addTestSuite(QosTests.class); + suite.addTestSuite(AlternateExchange.class); + suite.addTestSuite(ExchangeExchangeBindings.class); + suite.addTestSuite(ExchangeExchangeBindingsAutoDelete.class); + suite.addTestSuite(ExchangeDeclare.class); + suite.addTestSuite(FrameMax.class); + suite.addTestSuite(QueueLifecycle.class); + suite.addTestSuite(QueueLease.class); + suite.addTestSuite(QueueExclusivity.class); + suite.addTestSuite(QueueSizeLimit.class); + suite.addTestSuite(InvalidAcks.class); + suite.addTestSuite(InvalidAcksTx.class); + suite.addTestSuite(DefaultExchange.class); + suite.addTestSuite(UnbindAutoDeleteExchange.class); + suite.addTestSuite(Confirm.class); + suite.addTestSuite(ConsumerCancelNotification.class); + suite.addTestSuite(UnexpectedFrames.class); + suite.addTestSuite(PerQueueTTL.class); + //needs rabbitmqctl + if (isUnderUmbrella()) { + suite.addTestSuite(PerMessageTTL.class); + suite.addTestSuite(PerQueueVsPerMessageTTL.class); + } + suite.addTestSuite(DeadLetterExchange.class); + suite.addTestSuite(SaslMechanisms.class); + //needs rabbitmqctl + if (isUnderUmbrella()) suite.addTestSuite(UserIDHeader.class); + suite.addTestSuite(InternalExchange.class); + suite.addTestSuite(CcRoutes.class); + suite.addTestSuite(WorkPoolTests.class); + suite.addTestSuite(HeadersExchangeValidation.class); + suite.addTestSuite(ConsumerPriorities.class); + //needs rabbitmqctl + if (isUnderUmbrella()) { + suite.addTestSuite(Policies.class); + suite.addTestSuite(ConnectionRecovery.class); + } + suite.addTestSuite(ExceptionHandling.class); + suite.addTestSuite(PerConsumerPrefetch.class); + suite.addTestSuite(DirectReplyTo.class); + } +} diff --git a/test/src/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java b/src/test/java/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java rename to src/test/java/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java diff --git a/test/src/com/rabbitmq/client/test/functional/Heartbeat.java b/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/Heartbeat.java rename to src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java diff --git a/test/src/com/rabbitmq/client/test/functional/InternalExchange.java b/src/test/java/com/rabbitmq/client/test/functional/InternalExchange.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/InternalExchange.java rename to src/test/java/com/rabbitmq/client/test/functional/InternalExchange.java diff --git a/test/src/com/rabbitmq/client/test/functional/InvalidAcks.java b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcks.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/InvalidAcks.java rename to src/test/java/com/rabbitmq/client/test/functional/InvalidAcks.java diff --git a/test/src/com/rabbitmq/client/test/functional/InvalidAcksBase.java b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksBase.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/InvalidAcksBase.java rename to src/test/java/com/rabbitmq/client/test/functional/InvalidAcksBase.java diff --git a/test/src/com/rabbitmq/client/test/functional/InvalidAcksTx.java b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksTx.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/InvalidAcksTx.java rename to src/test/java/com/rabbitmq/client/test/functional/InvalidAcksTx.java diff --git a/test/src/com/rabbitmq/client/test/functional/MessageCount.java b/src/test/java/com/rabbitmq/client/test/functional/MessageCount.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/MessageCount.java rename to src/test/java/com/rabbitmq/client/test/functional/MessageCount.java diff --git a/test/src/com/rabbitmq/client/test/functional/Nack.java b/src/test/java/com/rabbitmq/client/test/functional/Nack.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/Nack.java rename to src/test/java/com/rabbitmq/client/test/functional/Nack.java diff --git a/test/src/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java b/src/test/java/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java rename to src/test/java/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java diff --git a/test/src/com/rabbitmq/client/test/functional/Nowait.java b/src/test/java/com/rabbitmq/client/test/functional/Nowait.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/Nowait.java rename to src/test/java/com/rabbitmq/client/test/functional/Nowait.java diff --git a/test/src/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java b/src/test/java/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java rename to src/test/java/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java diff --git a/test/src/com/rabbitmq/client/test/functional/PerMessageTTL.java b/src/test/java/com/rabbitmq/client/test/functional/PerMessageTTL.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/PerMessageTTL.java rename to src/test/java/com/rabbitmq/client/test/functional/PerMessageTTL.java diff --git a/test/src/com/rabbitmq/client/test/functional/PerQueueTTL.java b/src/test/java/com/rabbitmq/client/test/functional/PerQueueTTL.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/PerQueueTTL.java rename to src/test/java/com/rabbitmq/client/test/functional/PerQueueTTL.java diff --git a/test/src/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java b/src/test/java/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java rename to src/test/java/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java diff --git a/test/src/com/rabbitmq/client/test/functional/Policies.java b/src/test/java/com/rabbitmq/client/test/functional/Policies.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/Policies.java rename to src/test/java/com/rabbitmq/client/test/functional/Policies.java diff --git a/test/src/com/rabbitmq/client/test/functional/QosTests.java b/src/test/java/com/rabbitmq/client/test/functional/QosTests.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/QosTests.java rename to src/test/java/com/rabbitmq/client/test/functional/QosTests.java diff --git a/test/src/com/rabbitmq/client/test/functional/QueueExclusivity.java b/src/test/java/com/rabbitmq/client/test/functional/QueueExclusivity.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/QueueExclusivity.java rename to src/test/java/com/rabbitmq/client/test/functional/QueueExclusivity.java diff --git a/test/src/com/rabbitmq/client/test/functional/QueueLease.java b/src/test/java/com/rabbitmq/client/test/functional/QueueLease.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/QueueLease.java rename to src/test/java/com/rabbitmq/client/test/functional/QueueLease.java diff --git a/test/src/com/rabbitmq/client/test/functional/QueueLifecycle.java b/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/QueueLifecycle.java rename to src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java diff --git a/test/src/com/rabbitmq/client/test/functional/QueueSizeLimit.java b/src/test/java/com/rabbitmq/client/test/functional/QueueSizeLimit.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/QueueSizeLimit.java rename to src/test/java/com/rabbitmq/client/test/functional/QueueSizeLimit.java diff --git a/test/src/com/rabbitmq/client/test/functional/Recover.java b/src/test/java/com/rabbitmq/client/test/functional/Recover.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/Recover.java rename to src/test/java/com/rabbitmq/client/test/functional/Recover.java diff --git a/test/src/com/rabbitmq/client/test/functional/Reject.java b/src/test/java/com/rabbitmq/client/test/functional/Reject.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/Reject.java rename to src/test/java/com/rabbitmq/client/test/functional/Reject.java diff --git a/test/src/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java rename to src/test/java/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java diff --git a/test/src/com/rabbitmq/client/test/functional/RequeueOnClose.java b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnClose.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/RequeueOnClose.java rename to src/test/java/com/rabbitmq/client/test/functional/RequeueOnClose.java diff --git a/test/src/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java rename to src/test/java/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java diff --git a/test/src/com/rabbitmq/client/test/functional/Routing.java b/src/test/java/com/rabbitmq/client/test/functional/Routing.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/Routing.java rename to src/test/java/com/rabbitmq/client/test/functional/Routing.java diff --git a/test/src/com/rabbitmq/client/test/functional/SaslMechanisms.java b/src/test/java/com/rabbitmq/client/test/functional/SaslMechanisms.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/SaslMechanisms.java rename to src/test/java/com/rabbitmq/client/test/functional/SaslMechanisms.java diff --git a/test/src/com/rabbitmq/client/test/functional/TTLHandling.java b/src/test/java/com/rabbitmq/client/test/functional/TTLHandling.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/TTLHandling.java rename to src/test/java/com/rabbitmq/client/test/functional/TTLHandling.java diff --git a/test/src/com/rabbitmq/client/test/functional/Tables.java b/src/test/java/com/rabbitmq/client/test/functional/Tables.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/Tables.java rename to src/test/java/com/rabbitmq/client/test/functional/Tables.java diff --git a/test/src/com/rabbitmq/client/test/functional/Transactions.java b/src/test/java/com/rabbitmq/client/test/functional/Transactions.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/Transactions.java rename to src/test/java/com/rabbitmq/client/test/functional/Transactions.java diff --git a/test/src/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java b/src/test/java/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java rename to src/test/java/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java diff --git a/test/src/com/rabbitmq/client/test/functional/UnexpectedFrames.java b/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/UnexpectedFrames.java rename to src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java diff --git a/test/src/com/rabbitmq/client/test/functional/UserIDHeader.java b/src/test/java/com/rabbitmq/client/test/functional/UserIDHeader.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/UserIDHeader.java rename to src/test/java/com/rabbitmq/client/test/functional/UserIDHeader.java diff --git a/test/src/com/rabbitmq/client/test/performance/CLIHelper.java b/src/test/java/com/rabbitmq/client/test/performance/CLIHelper.java similarity index 100% rename from test/src/com/rabbitmq/client/test/performance/CLIHelper.java rename to src/test/java/com/rabbitmq/client/test/performance/CLIHelper.java diff --git a/test/src/com/rabbitmq/client/test/performance/QosScaling.java b/src/test/java/com/rabbitmq/client/test/performance/QosScaling.java similarity index 100% rename from test/src/com/rabbitmq/client/test/performance/QosScaling.java rename to src/test/java/com/rabbitmq/client/test/performance/QosScaling.java diff --git a/test/src/com/rabbitmq/client/test/performance/ScalabilityTest.java b/src/test/java/com/rabbitmq/client/test/performance/ScalabilityTest.java similarity index 100% rename from test/src/com/rabbitmq/client/test/performance/ScalabilityTest.java rename to src/test/java/com/rabbitmq/client/test/performance/ScalabilityTest.java diff --git a/test/src/com/rabbitmq/client/test/performance/StressManagement.java b/src/test/java/com/rabbitmq/client/test/performance/StressManagement.java similarity index 100% rename from test/src/com/rabbitmq/client/test/performance/StressManagement.java rename to src/test/java/com/rabbitmq/client/test/performance/StressManagement.java diff --git a/test/src/com/rabbitmq/client/test/server/AbsentQueue.java b/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java similarity index 99% rename from test/src/com/rabbitmq/client/test/server/AbsentQueue.java rename to src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java index 0aedd45411..d0c586dbb5 100644 --- a/test/src/com/rabbitmq/client/test/server/AbsentQueue.java +++ b/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java @@ -17,13 +17,12 @@ package com.rabbitmq.client.test.server; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.test.functional.ClusteredTestBase; -import com.rabbitmq.tools.Host; - import java.io.IOException; import java.util.concurrent.TimeoutException; +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.test.functional.ClusteredTestBase; + /** * This tests whether 'absent' queues - durable queues whose home node * is down - are handled properly. diff --git a/test/src/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java b/src/test/java/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java similarity index 100% rename from test/src/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java rename to src/test/java/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java diff --git a/test/src/com/rabbitmq/client/test/server/BlockedConnection.java b/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java similarity index 98% rename from test/src/com/rabbitmq/client/test/server/BlockedConnection.java rename to src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java index 45f9652ceb..3880e5ffb0 100644 --- a/test/src/com/rabbitmq/client/test/server/BlockedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java @@ -17,18 +17,17 @@ package com.rabbitmq.client.test.server; +import java.io.IOException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + import com.rabbitmq.client.BlockedListener; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.MessageProperties; import com.rabbitmq.client.test.BrokerTestCase; -import com.rabbitmq.tools.Host; - -import java.io.IOException; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; public class BlockedConnection extends BrokerTestCase { protected void releaseResources() throws IOException { diff --git a/test/src/com/rabbitmq/client/test/server/Bug19219Test.java b/src/test/java/com/rabbitmq/client/test/server/Bug19219Test.java similarity index 100% rename from test/src/com/rabbitmq/client/test/server/Bug19219Test.java rename to src/test/java/com/rabbitmq/client/test/server/Bug19219Test.java diff --git a/test/src/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java b/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java similarity index 100% rename from test/src/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java rename to src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java diff --git a/test/src/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java b/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java similarity index 100% rename from test/src/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java rename to src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java diff --git a/test/src/com/rabbitmq/client/test/server/DurableBindingLifecycle.java b/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java similarity index 100% rename from test/src/com/rabbitmq/client/test/server/DurableBindingLifecycle.java rename to src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java diff --git a/test/src/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java b/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java similarity index 100% rename from test/src/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java rename to src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java diff --git a/test/src/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java b/src/test/java/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java similarity index 98% rename from test/src/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java rename to src/test/java/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java index 202271b15d..93f61199a7 100644 --- a/test/src/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java +++ b/src/test/java/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java @@ -23,7 +23,6 @@ import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; import com.rabbitmq.client.test.BrokerTestCase; -import com.rabbitmq.tools.Host; /** * This tests whether exclusive, durable queues are deleted when appropriate diff --git a/test/src/com/rabbitmq/client/test/server/Firehose.java b/src/test/java/com/rabbitmq/client/test/server/Firehose.java similarity index 100% rename from test/src/com/rabbitmq/client/test/server/Firehose.java rename to src/test/java/com/rabbitmq/client/test/server/Firehose.java diff --git a/test/src/com/rabbitmq/client/test/server/HATests.java b/src/test/java/com/rabbitmq/client/test/server/HATests.java similarity index 90% rename from test/src/com/rabbitmq/client/test/server/HATests.java rename to src/test/java/com/rabbitmq/client/test/server/HATests.java index a6fcc793c7..5a9226addf 100644 --- a/test/src/com/rabbitmq/client/test/server/HATests.java +++ b/src/test/java/com/rabbitmq/client/test/server/HATests.java @@ -16,17 +16,21 @@ package com.rabbitmq.client.test.server; -import com.rabbitmq.client.test.functional.FunctionalTests; -import com.rabbitmq.tools.Host; import junit.framework.TestCase; import junit.framework.TestSuite; -public class HATests extends TestSuite { +import com.rabbitmq.client.test.AbstractRMQTestSuite; +import com.rabbitmq.client.test.functional.FunctionalTests; +import com.rabbitmq.tools.Host; + +public class HATests extends AbstractRMQTestSuite { // this is horrific public static boolean HA_TESTS_RUNNING = false; public static TestSuite suite() { TestSuite suite = new TestSuite("server-tests"); + if (!requiredProperties()) return suite; + if (!isUnderUmbrella()) return suite; suite.addTestSuite(SetUp.class); FunctionalTests.add(suite); ServerTests.add(suite); diff --git a/test/src/com/rabbitmq/client/test/server/LoopbackUsers.java b/src/test/java/com/rabbitmq/client/test/server/LoopbackUsers.java similarity index 100% rename from test/src/com/rabbitmq/client/test/server/LoopbackUsers.java rename to src/test/java/com/rabbitmq/client/test/server/LoopbackUsers.java diff --git a/test/src/com/rabbitmq/client/test/server/MemoryAlarms.java b/src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java similarity index 99% rename from test/src/com/rabbitmq/client/test/server/MemoryAlarms.java rename to src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java index ca0bde4db8..b44235d9a9 100644 --- a/test/src/com/rabbitmq/client/test/server/MemoryAlarms.java +++ b/src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java @@ -23,7 +23,6 @@ import com.rabbitmq.client.Connection; import com.rabbitmq.client.QueueingConsumer; import com.rabbitmq.client.test.BrokerTestCase; -import com.rabbitmq.tools.Host; public class MemoryAlarms extends BrokerTestCase { diff --git a/test/src/com/rabbitmq/client/test/server/MessageRecovery.java b/src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java similarity index 98% rename from test/src/com/rabbitmq/client/test/server/MessageRecovery.java rename to src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java index 271c4c3bed..24d5ff01c4 100644 --- a/test/src/com/rabbitmq/client/test/server/MessageRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java @@ -15,13 +15,12 @@ package com.rabbitmq.client.test.server; +import java.io.IOException; + import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.Channel; import com.rabbitmq.client.MessageProperties; import com.rabbitmq.client.test.ConfirmBase; -import java.io.IOException; - public class MessageRecovery extends ConfirmBase { diff --git a/test/src/com/rabbitmq/client/test/server/Permissions.java b/src/test/java/com/rabbitmq/client/test/server/Permissions.java similarity index 100% rename from test/src/com/rabbitmq/client/test/server/Permissions.java rename to src/test/java/com/rabbitmq/client/test/server/Permissions.java diff --git a/test/src/com/rabbitmq/client/test/server/PersistenceGuarantees.java b/src/test/java/com/rabbitmq/client/test/server/PersistenceGuarantees.java similarity index 100% rename from test/src/com/rabbitmq/client/test/server/PersistenceGuarantees.java rename to src/test/java/com/rabbitmq/client/test/server/PersistenceGuarantees.java diff --git a/test/src/com/rabbitmq/client/test/server/PriorityQueues.java b/src/test/java/com/rabbitmq/client/test/server/PriorityQueues.java similarity index 100% rename from test/src/com/rabbitmq/client/test/server/PriorityQueues.java rename to src/test/java/com/rabbitmq/client/test/server/PriorityQueues.java diff --git a/src/test/java/com/rabbitmq/client/test/server/ServerTests.java b/src/test/java/com/rabbitmq/client/test/server/ServerTests.java new file mode 100644 index 0000000000..4e77517cb0 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/server/ServerTests.java @@ -0,0 +1,52 @@ +// The contents of this file are subject to the Mozilla Public License +// Version 1.1 (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.mozilla.org/MPL/ +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and +// limitations under the License. +// +// The Original Code is RabbitMQ. +// +// The Initial Developer of the Original Code is GoPivotal, Inc. +// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// + +package com.rabbitmq.client.test.server; + +import junit.framework.TestSuite; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; + +import com.rabbitmq.client.test.AbstractRMQTestSuite; + +public class ServerTests extends AbstractRMQTestSuite { + + public static TestSuite suite() { + TestSuite suite = new TestSuite("server-tests"); + if (!requiredProperties()) return suite; + if (!isUnderUmbrella()) return suite; + add(suite); + return suite; + } + + public static void add(TestSuite suite) { + suite.addTestSuite(Permissions.class); + suite.addTestSuite(DurableBindingLifecycle.class); + suite.addTestSuite(DeadLetterExchangeDurable.class); + suite.addTestSuite(EffectVisibilityCrossNodeTest.class); + suite.addTestSuite(ExclusiveQueueDurability.class); + suite.addTestSuite(AbsentQueue.class); + suite.addTestSuite(AlternateExchangeEquivalence.class); + suite.addTestSuite(MemoryAlarms.class); + suite.addTestSuite(MessageRecovery.class); + suite.addTestSuite(Firehose.class); + suite.addTestSuite(PersistenceGuarantees.class); + suite.addTestSuite(Shutdown.class); + suite.addTestSuite(BlockedConnection.class); + suite.addTestSuite(ChannelLimitNegotiation.class); + suite.addTestSuite(LoopbackUsers.class); + } +} diff --git a/test/src/com/rabbitmq/client/test/server/Shutdown.java b/src/test/java/com/rabbitmq/client/test/server/Shutdown.java similarity index 74% rename from test/src/com/rabbitmq/client/test/server/Shutdown.java rename to src/test/java/com/rabbitmq/client/test/server/Shutdown.java index 7280eb8be8..e077ce0394 100644 --- a/test/src/com/rabbitmq/client/test/server/Shutdown.java +++ b/src/test/java/com/rabbitmq/client/test/server/Shutdown.java @@ -1,11 +1,7 @@ package com.rabbitmq.client.test.server; -import com.rabbitmq.client.test.BrokerTestCase; import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.Connection; - -import java.io.IOException; +import com.rabbitmq.client.test.BrokerTestCase; public class Shutdown extends BrokerTestCase { diff --git a/test/src/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java b/src/test/java/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java similarity index 100% rename from test/src/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java rename to src/test/java/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java diff --git a/test/src/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java similarity index 100% rename from test/src/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java rename to src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java diff --git a/test/src/com/rabbitmq/client/test/ssl/SSLTests.java b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java similarity index 77% rename from test/src/com/rabbitmq/client/test/ssl/SSLTests.java rename to src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java index 611df1ec40..b3b660dd95 100644 --- a/test/src/com/rabbitmq/client/test/ssl/SSLTests.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java @@ -17,12 +17,16 @@ package com.rabbitmq.client.test.ssl; -import junit.framework.TestCase; import junit.framework.TestSuite; -public class SSLTests extends TestCase { +import com.rabbitmq.client.test.AbstractRMQTestSuite; + +public class SSLTests extends AbstractRMQTestSuite { public static TestSuite suite() { TestSuite suite = new TestSuite("ssl"); + //Skip the tests if not under umbrella and not SSL available + if (!requiredProperties()) return suite; + if (!(isUnderUmbrella() && isSSLAvailable())) return suite; suite.addTestSuite(UnverifiedConnection.class); suite.addTestSuite(VerifiedConnection.class); suite.addTestSuite(BadVerifiedConnection.class); diff --git a/test/src/com/rabbitmq/client/test/ssl/UnverifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java similarity index 100% rename from test/src/com/rabbitmq/client/test/ssl/UnverifiedConnection.java rename to src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java diff --git a/test/src/com/rabbitmq/client/test/ssl/VerifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java similarity index 100% rename from test/src/com/rabbitmq/client/test/ssl/VerifiedConnection.java rename to src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java diff --git a/test/src/com/rabbitmq/examples/BufferPerformanceMetrics.java b/src/test/java/com/rabbitmq/examples/BufferPerformanceMetrics.java similarity index 100% rename from test/src/com/rabbitmq/examples/BufferPerformanceMetrics.java rename to src/test/java/com/rabbitmq/examples/BufferPerformanceMetrics.java diff --git a/test/src/com/rabbitmq/examples/ChannelCreationPerformance.java b/src/test/java/com/rabbitmq/examples/ChannelCreationPerformance.java similarity index 100% rename from test/src/com/rabbitmq/examples/ChannelCreationPerformance.java rename to src/test/java/com/rabbitmq/examples/ChannelCreationPerformance.java diff --git a/test/src/com/rabbitmq/examples/ConfirmDontLoseMessages.java b/src/test/java/com/rabbitmq/examples/ConfirmDontLoseMessages.java similarity index 100% rename from test/src/com/rabbitmq/examples/ConfirmDontLoseMessages.java rename to src/test/java/com/rabbitmq/examples/ConfirmDontLoseMessages.java diff --git a/test/src/com/rabbitmq/examples/ConsumerMain.java b/src/test/java/com/rabbitmq/examples/ConsumerMain.java similarity index 100% rename from test/src/com/rabbitmq/examples/ConsumerMain.java rename to src/test/java/com/rabbitmq/examples/ConsumerMain.java diff --git a/test/src/com/rabbitmq/examples/DirectReplyToPerformance.java b/src/test/java/com/rabbitmq/examples/DirectReplyToPerformance.java similarity index 100% rename from test/src/com/rabbitmq/examples/DirectReplyToPerformance.java rename to src/test/java/com/rabbitmq/examples/DirectReplyToPerformance.java diff --git a/test/src/com/rabbitmq/examples/FileConsumer.java b/src/test/java/com/rabbitmq/examples/FileConsumer.java similarity index 100% rename from test/src/com/rabbitmq/examples/FileConsumer.java rename to src/test/java/com/rabbitmq/examples/FileConsumer.java diff --git a/test/src/com/rabbitmq/examples/FileProducer.java b/src/test/java/com/rabbitmq/examples/FileProducer.java similarity index 100% rename from test/src/com/rabbitmq/examples/FileProducer.java rename to src/test/java/com/rabbitmq/examples/FileProducer.java diff --git a/test/src/com/rabbitmq/examples/HelloClient.java b/src/test/java/com/rabbitmq/examples/HelloClient.java similarity index 100% rename from test/src/com/rabbitmq/examples/HelloClient.java rename to src/test/java/com/rabbitmq/examples/HelloClient.java diff --git a/test/src/com/rabbitmq/examples/HelloJsonClient.java b/src/test/java/com/rabbitmq/examples/HelloJsonClient.java similarity index 100% rename from test/src/com/rabbitmq/examples/HelloJsonClient.java rename to src/test/java/com/rabbitmq/examples/HelloJsonClient.java diff --git a/test/src/com/rabbitmq/examples/HelloJsonServer.java b/src/test/java/com/rabbitmq/examples/HelloJsonServer.java similarity index 100% rename from test/src/com/rabbitmq/examples/HelloJsonServer.java rename to src/test/java/com/rabbitmq/examples/HelloJsonServer.java diff --git a/test/src/com/rabbitmq/examples/HelloJsonService.java b/src/test/java/com/rabbitmq/examples/HelloJsonService.java similarity index 100% rename from test/src/com/rabbitmq/examples/HelloJsonService.java rename to src/test/java/com/rabbitmq/examples/HelloJsonService.java diff --git a/test/src/com/rabbitmq/examples/HelloServer.java b/src/test/java/com/rabbitmq/examples/HelloServer.java similarity index 100% rename from test/src/com/rabbitmq/examples/HelloServer.java rename to src/test/java/com/rabbitmq/examples/HelloServer.java diff --git a/test/src/com/rabbitmq/examples/LogTail.java b/src/test/java/com/rabbitmq/examples/LogTail.java similarity index 100% rename from test/src/com/rabbitmq/examples/LogTail.java rename to src/test/java/com/rabbitmq/examples/LogTail.java diff --git a/test/src/com/rabbitmq/examples/MulticastMain.java b/src/test/java/com/rabbitmq/examples/MulticastMain.java similarity index 100% rename from test/src/com/rabbitmq/examples/MulticastMain.java rename to src/test/java/com/rabbitmq/examples/MulticastMain.java diff --git a/test/src/com/rabbitmq/examples/PerQueueTTLGetter.java b/src/test/java/com/rabbitmq/examples/PerQueueTTLGetter.java similarity index 100% rename from test/src/com/rabbitmq/examples/PerQueueTTLGetter.java rename to src/test/java/com/rabbitmq/examples/PerQueueTTLGetter.java diff --git a/test/src/com/rabbitmq/examples/PerQueueTTLPublisher.java b/src/test/java/com/rabbitmq/examples/PerQueueTTLPublisher.java similarity index 100% rename from test/src/com/rabbitmq/examples/PerQueueTTLPublisher.java rename to src/test/java/com/rabbitmq/examples/PerQueueTTLPublisher.java diff --git a/test/src/com/rabbitmq/examples/PerfTest.java b/src/test/java/com/rabbitmq/examples/PerfTest.java similarity index 100% rename from test/src/com/rabbitmq/examples/PerfTest.java rename to src/test/java/com/rabbitmq/examples/PerfTest.java diff --git a/test/src/com/rabbitmq/examples/PerfTestMulti.java b/src/test/java/com/rabbitmq/examples/PerfTestMulti.java similarity index 100% rename from test/src/com/rabbitmq/examples/PerfTestMulti.java rename to src/test/java/com/rabbitmq/examples/PerfTestMulti.java diff --git a/test/src/com/rabbitmq/examples/ProducerMain.java b/src/test/java/com/rabbitmq/examples/ProducerMain.java similarity index 100% rename from test/src/com/rabbitmq/examples/ProducerMain.java rename to src/test/java/com/rabbitmq/examples/ProducerMain.java diff --git a/test/src/com/rabbitmq/examples/SendString.java b/src/test/java/com/rabbitmq/examples/SendString.java similarity index 100% rename from test/src/com/rabbitmq/examples/SendString.java rename to src/test/java/com/rabbitmq/examples/SendString.java diff --git a/test/src/com/rabbitmq/examples/SimpleConsumer.java b/src/test/java/com/rabbitmq/examples/SimpleConsumer.java similarity index 100% rename from test/src/com/rabbitmq/examples/SimpleConsumer.java rename to src/test/java/com/rabbitmq/examples/SimpleConsumer.java diff --git a/test/src/com/rabbitmq/examples/SimpleProducer.java b/src/test/java/com/rabbitmq/examples/SimpleProducer.java similarity index 100% rename from test/src/com/rabbitmq/examples/SimpleProducer.java rename to src/test/java/com/rabbitmq/examples/SimpleProducer.java diff --git a/test/src/com/rabbitmq/examples/SimpleTopicConsumer.java b/src/test/java/com/rabbitmq/examples/SimpleTopicConsumer.java similarity index 100% rename from test/src/com/rabbitmq/examples/SimpleTopicConsumer.java rename to src/test/java/com/rabbitmq/examples/SimpleTopicConsumer.java diff --git a/test/src/com/rabbitmq/examples/SimpleTopicProducer.java b/src/test/java/com/rabbitmq/examples/SimpleTopicProducer.java similarity index 100% rename from test/src/com/rabbitmq/examples/SimpleTopicProducer.java rename to src/test/java/com/rabbitmq/examples/SimpleTopicProducer.java diff --git a/test/src/com/rabbitmq/examples/SpammyTopicProducer.java b/src/test/java/com/rabbitmq/examples/SpammyTopicProducer.java similarity index 100% rename from test/src/com/rabbitmq/examples/SpammyTopicProducer.java rename to src/test/java/com/rabbitmq/examples/SpammyTopicProducer.java diff --git a/test/src/com/rabbitmq/examples/StressPersister.java b/src/test/java/com/rabbitmq/examples/StressPersister.java similarity index 100% rename from test/src/com/rabbitmq/examples/StressPersister.java rename to src/test/java/com/rabbitmq/examples/StressPersister.java diff --git a/test/src/com/rabbitmq/examples/TestMain.java b/src/test/java/com/rabbitmq/examples/TestMain.java similarity index 94% rename from test/src/com/rabbitmq/examples/TestMain.java rename to src/test/java/com/rabbitmq/examples/TestMain.java index 2cd08136c1..cd12760af7 100644 --- a/test/src/com/rabbitmq/examples/TestMain.java +++ b/src/test/java/com/rabbitmq/examples/TestMain.java @@ -42,26 +42,46 @@ import com.rabbitmq.client.impl.FrameHandler; import com.rabbitmq.client.impl.FrameHandlerFactory; import com.rabbitmq.client.impl.SocketFrameHandler; +import com.rabbitmq.client.test.AbstractRMQTestSuite; import com.rabbitmq.utility.BlockingCell; import javax.net.SocketFactory; +import org.junit.Test; +//FIXME needs to get the arguments from System.getProperty +//FIXME this test needs to be transform into Junit public class TestMain { - public static void main(String[] args) throws IOException, URISyntaxException { + //Ugly patch to initialize system properties + static{ + new AbstractRMQTestSuite(){}; + } + + static String URI = "amqp://localhost"; + + public static void main(String[] args) throws IOException, URISyntaxException { + if (args.length > 0) URI = args[0]; + new TestMain().test(); + } + + + @Test + public void test() throws IOException, URISyntaxException { // Show what version this class was compiled with, to check conformance testing Class clazz = TestMain.class; String javaVersion = System.getProperty("java.version"); System.out.println(clazz.getName() + " : javac v" + getCompilerVersion(clazz) + " on " + javaVersion); try { boolean silent = Boolean.getBoolean("silent"); - final String uri = (args.length > 0) ? args[0] : "amqp://localhost"; + final String uri = URI; runConnectionNegotiationTest(uri); final Connection conn = new ConnectionFactory(){{setUri(uri);}}.newConnection(); if (!silent) { System.out.println("Channel 0 fully open."); } - new TestMain(conn, silent).run(); + set_connection(conn); + set_silent(silent); + run(); runProducerConsumerTest(uri, 500); runProducerConsumerTest(uri, 0); @@ -218,19 +238,29 @@ public static void sleep(int ms) { } } - private final Connection _connection; + private Connection _connection; private Channel _ch1; private int _messageId = 0; - private final boolean _silent; + private boolean _silent; private volatile BlockingCell returnCell; - public TestMain(Connection connection, boolean silent) { - _connection = connection; - _silent = silent; + public TestMain() { + } +// public TestMain(Connection connection, boolean silent) { +// _connection = connection; +// _silent = silent; +// } + + public void set_connection(Connection _connection) { + this._connection = _connection; + } + + public void set_silent(boolean _silent) { + this._silent = _silent; } public Channel createChannel() throws IOException { diff --git a/test/src/com/rabbitmq/examples/TracerConcurrencyTest.java b/src/test/java/com/rabbitmq/examples/TracerConcurrencyTest.java similarity index 100% rename from test/src/com/rabbitmq/examples/TracerConcurrencyTest.java rename to src/test/java/com/rabbitmq/examples/TracerConcurrencyTest.java diff --git a/test/src/com/rabbitmq/examples/perf/Broker.java b/src/test/java/com/rabbitmq/examples/perf/Broker.java similarity index 100% rename from test/src/com/rabbitmq/examples/perf/Broker.java rename to src/test/java/com/rabbitmq/examples/perf/Broker.java diff --git a/test/src/com/rabbitmq/examples/perf/BrokerValue.java b/src/test/java/com/rabbitmq/examples/perf/BrokerValue.java similarity index 100% rename from test/src/com/rabbitmq/examples/perf/BrokerValue.java rename to src/test/java/com/rabbitmq/examples/perf/BrokerValue.java diff --git a/test/src/com/rabbitmq/examples/perf/BrokerVariable.java b/src/test/java/com/rabbitmq/examples/perf/BrokerVariable.java similarity index 100% rename from test/src/com/rabbitmq/examples/perf/BrokerVariable.java rename to src/test/java/com/rabbitmq/examples/perf/BrokerVariable.java diff --git a/test/src/com/rabbitmq/examples/perf/Consumer.java b/src/test/java/com/rabbitmq/examples/perf/Consumer.java similarity index 100% rename from test/src/com/rabbitmq/examples/perf/Consumer.java rename to src/test/java/com/rabbitmq/examples/perf/Consumer.java diff --git a/test/src/com/rabbitmq/examples/perf/MulticastParams.java b/src/test/java/com/rabbitmq/examples/perf/MulticastParams.java similarity index 100% rename from test/src/com/rabbitmq/examples/perf/MulticastParams.java rename to src/test/java/com/rabbitmq/examples/perf/MulticastParams.java diff --git a/test/src/com/rabbitmq/examples/perf/MulticastSet.java b/src/test/java/com/rabbitmq/examples/perf/MulticastSet.java similarity index 100% rename from test/src/com/rabbitmq/examples/perf/MulticastSet.java rename to src/test/java/com/rabbitmq/examples/perf/MulticastSet.java diff --git a/test/src/com/rabbitmq/examples/perf/MulticastValue.java b/src/test/java/com/rabbitmq/examples/perf/MulticastValue.java similarity index 100% rename from test/src/com/rabbitmq/examples/perf/MulticastValue.java rename to src/test/java/com/rabbitmq/examples/perf/MulticastValue.java diff --git a/test/src/com/rabbitmq/examples/perf/MulticastVariable.java b/src/test/java/com/rabbitmq/examples/perf/MulticastVariable.java similarity index 100% rename from test/src/com/rabbitmq/examples/perf/MulticastVariable.java rename to src/test/java/com/rabbitmq/examples/perf/MulticastVariable.java diff --git a/test/src/com/rabbitmq/examples/perf/PerfUtil.java b/src/test/java/com/rabbitmq/examples/perf/PerfUtil.java similarity index 100% rename from test/src/com/rabbitmq/examples/perf/PerfUtil.java rename to src/test/java/com/rabbitmq/examples/perf/PerfUtil.java diff --git a/test/src/com/rabbitmq/examples/perf/Producer.java b/src/test/java/com/rabbitmq/examples/perf/Producer.java similarity index 100% rename from test/src/com/rabbitmq/examples/perf/Producer.java rename to src/test/java/com/rabbitmq/examples/perf/Producer.java diff --git a/test/src/com/rabbitmq/examples/perf/ProducerConsumerBase.java b/src/test/java/com/rabbitmq/examples/perf/ProducerConsumerBase.java similarity index 100% rename from test/src/com/rabbitmq/examples/perf/ProducerConsumerBase.java rename to src/test/java/com/rabbitmq/examples/perf/ProducerConsumerBase.java diff --git a/test/src/com/rabbitmq/examples/perf/RateVsLatencyScenario.java b/src/test/java/com/rabbitmq/examples/perf/RateVsLatencyScenario.java similarity index 100% rename from test/src/com/rabbitmq/examples/perf/RateVsLatencyScenario.java rename to src/test/java/com/rabbitmq/examples/perf/RateVsLatencyScenario.java diff --git a/test/src/com/rabbitmq/examples/perf/Scenario.java b/src/test/java/com/rabbitmq/examples/perf/Scenario.java similarity index 100% rename from test/src/com/rabbitmq/examples/perf/Scenario.java rename to src/test/java/com/rabbitmq/examples/perf/Scenario.java diff --git a/test/src/com/rabbitmq/examples/perf/ScenarioFactory.java b/src/test/java/com/rabbitmq/examples/perf/ScenarioFactory.java similarity index 100% rename from test/src/com/rabbitmq/examples/perf/ScenarioFactory.java rename to src/test/java/com/rabbitmq/examples/perf/ScenarioFactory.java diff --git a/test/src/com/rabbitmq/examples/perf/ScenarioStats.java b/src/test/java/com/rabbitmq/examples/perf/ScenarioStats.java similarity index 100% rename from test/src/com/rabbitmq/examples/perf/ScenarioStats.java rename to src/test/java/com/rabbitmq/examples/perf/ScenarioStats.java diff --git a/test/src/com/rabbitmq/examples/perf/SimpleScenario.java b/src/test/java/com/rabbitmq/examples/perf/SimpleScenario.java similarity index 100% rename from test/src/com/rabbitmq/examples/perf/SimpleScenario.java rename to src/test/java/com/rabbitmq/examples/perf/SimpleScenario.java diff --git a/test/src/com/rabbitmq/examples/perf/SimpleScenarioStats.java b/src/test/java/com/rabbitmq/examples/perf/SimpleScenarioStats.java similarity index 100% rename from test/src/com/rabbitmq/examples/perf/SimpleScenarioStats.java rename to src/test/java/com/rabbitmq/examples/perf/SimpleScenarioStats.java diff --git a/test/src/com/rabbitmq/examples/perf/Stats.java b/src/test/java/com/rabbitmq/examples/perf/Stats.java similarity index 100% rename from test/src/com/rabbitmq/examples/perf/Stats.java rename to src/test/java/com/rabbitmq/examples/perf/Stats.java diff --git a/test/src/com/rabbitmq/examples/perf/Variable.java b/src/test/java/com/rabbitmq/examples/perf/Variable.java similarity index 100% rename from test/src/com/rabbitmq/examples/perf/Variable.java rename to src/test/java/com/rabbitmq/examples/perf/Variable.java diff --git a/test/src/com/rabbitmq/examples/perf/VariableValue.java b/src/test/java/com/rabbitmq/examples/perf/VariableValue.java similarity index 100% rename from test/src/com/rabbitmq/examples/perf/VariableValue.java rename to src/test/java/com/rabbitmq/examples/perf/VariableValue.java diff --git a/test/src/com/rabbitmq/examples/perf/VaryingScenario.java b/src/test/java/com/rabbitmq/examples/perf/VaryingScenario.java similarity index 100% rename from test/src/com/rabbitmq/examples/perf/VaryingScenario.java rename to src/test/java/com/rabbitmq/examples/perf/VaryingScenario.java diff --git a/test/src/com/rabbitmq/examples/perf/VaryingScenarioStats.java b/src/test/java/com/rabbitmq/examples/perf/VaryingScenarioStats.java similarity index 100% rename from test/src/com/rabbitmq/examples/perf/VaryingScenarioStats.java rename to src/test/java/com/rabbitmq/examples/perf/VaryingScenarioStats.java diff --git a/test/src/com/rabbitmq/tools/Host.java b/src/test/java/com/rabbitmq/tools/Host.java similarity index 96% rename from test/src/com/rabbitmq/tools/Host.java rename to src/test/java/com/rabbitmq/tools/Host.java index 2bac5cb01c..e4ea1129ee 100644 --- a/test/src/com/rabbitmq/tools/Host.java +++ b/src/test/java/com/rabbitmq/tools/Host.java @@ -17,20 +17,19 @@ package com.rabbitmq.tools; -import com.rabbitmq.client.impl.NetworkConnection; - import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; +import com.rabbitmq.client.impl.NetworkConnection; + public class Host { - private static String capture(InputStream is) + public static String capture(InputStream is) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(is)); @@ -109,17 +108,17 @@ public static Process invokeMakeTarget(String command) throws IOException { " " + command); } - private static String makeCommand() + public static String makeCommand() { return System.getProperty("make.bin"); } - private static String rabbitmqctlCommand() + public static String rabbitmqctlCommand() { return System.getProperty("rabbitmqctl.bin"); } - private static String rabbitmqTestDir() + public static String rabbitmqTestDir() { return System.getProperty("sibling.rabbitmq_test.dir"); } diff --git a/test/src/com/rabbitmq/utility/IntAllocatorTests.java b/src/test/java/com/rabbitmq/utility/IntAllocatorTests.java similarity index 100% rename from test/src/com/rabbitmq/utility/IntAllocatorTests.java rename to src/test/java/com/rabbitmq/utility/IntAllocatorTests.java diff --git a/build.properties b/src/test/resources/build.properties similarity index 86% rename from build.properties rename to src/test/resources/build.properties index 21ba4ff08a..acfbd12a33 100644 --- a/build.properties +++ b/src/test/resources/build.properties @@ -7,7 +7,7 @@ bundle.symbolicName=com.rabbitmq.client bundlor.home=bundlor dist.out=${build.out}/dist impl.version=0.0.0 -javac.debug=true +javac.debug=false javac.out=${build.out}/classes javadoc.out=build/doc/api lib.out=${build.out}/lib @@ -20,4 +20,5 @@ src.generated=${build.out}/gensrc standard.javac.source=1.6 standard.javac.target=1.6 test.javac.out=${build.out}/test/classes -test.src.home=test/src +test.src.home=${basedir}/src/test/java +maven.src.home=${basedir}/src/main/java diff --git a/config.properties b/src/test/resources/config.properties similarity index 91% rename from config.properties rename to src/test/resources/config.properties index c9851fb271..1f2f6018a1 100644 --- a/config.properties +++ b/src/test/resources/config.properties @@ -1,5 +1,6 @@ broker.hostname=localhost broker.port=5672 +broker.sslport=5671 test.main=com.rabbitmq.examples.TestMain test.producer.rate-limit=100000 test.producer.message-count=30000 diff --git a/test/src/com/rabbitmq/client/test/functional/FunctionalTests.java b/test/src/com/rabbitmq/client/test/functional/FunctionalTests.java deleted file mode 100644 index a44b44e6f6..0000000000 --- a/test/src/com/rabbitmq/client/test/functional/FunctionalTests.java +++ /dev/null @@ -1,83 +0,0 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ -// -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. -// -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. -// - - -package com.rabbitmq.client.test.functional; - -import com.rabbitmq.client.impl.WorkPoolTests; -import com.rabbitmq.client.test.Bug20004Test; - -import junit.framework.TestCase; -import junit.framework.TestSuite; - -public class FunctionalTests extends TestCase { - public static TestSuite suite() { - TestSuite suite = new TestSuite("functional"); - add(suite); - return suite; - } - - public static void add(TestSuite suite) { - suite.addTestSuite(ConnectionOpen.class); - suite.addTestSuite(Heartbeat.class); - suite.addTestSuite(Tables.class); - suite.addTestSuite(DoubleDeletion.class); - suite.addTestSuite(Routing.class); - suite.addTestSuite(BindingLifecycle.class); - suite.addTestSuite(Recover.class); - suite.addTestSuite(Reject.class); - suite.addTestSuite(Transactions.class); - suite.addTestSuite(RequeueOnConnectionClose.class); - suite.addTestSuite(RequeueOnChannelClose.class); - suite.addTestSuite(DurableOnTransient.class); - suite.addTestSuite(NoRequeueOnCancel.class); - suite.addTestSuite(Bug20004Test.class); - suite.addTestSuite(ExchangeDeleteIfUnused.class); - suite.addTestSuite(QosTests.class); - suite.addTestSuite(AlternateExchange.class); - suite.addTestSuite(ExchangeExchangeBindings.class); - suite.addTestSuite(ExchangeExchangeBindingsAutoDelete.class); - suite.addTestSuite(ExchangeDeclare.class); - suite.addTestSuite(FrameMax.class); - suite.addTestSuite(QueueLifecycle.class); - suite.addTestSuite(QueueLease.class); - suite.addTestSuite(QueueExclusivity.class); - suite.addTestSuite(QueueSizeLimit.class); - suite.addTestSuite(InvalidAcks.class); - suite.addTestSuite(InvalidAcksTx.class); - suite.addTestSuite(DefaultExchange.class); - suite.addTestSuite(UnbindAutoDeleteExchange.class); - suite.addTestSuite(Confirm.class); - suite.addTestSuite(ConsumerCancelNotification.class); - suite.addTestSuite(UnexpectedFrames.class); - suite.addTestSuite(PerQueueTTL.class); - suite.addTestSuite(PerMessageTTL.class); - suite.addTestSuite(PerQueueVsPerMessageTTL.class); - suite.addTestSuite(DeadLetterExchange.class); - suite.addTestSuite(SaslMechanisms.class); - suite.addTestSuite(UserIDHeader.class); - suite.addTestSuite(InternalExchange.class); - suite.addTestSuite(CcRoutes.class); - suite.addTestSuite(WorkPoolTests.class); - suite.addTestSuite(HeadersExchangeValidation.class); - suite.addTestSuite(ConsumerPriorities.class); - suite.addTestSuite(Policies.class); - suite.addTestSuite(ConnectionRecovery.class); - suite.addTestSuite(ExceptionHandling.class); - suite.addTestSuite(PerConsumerPrefetch.class); - suite.addTestSuite(DirectReplyTo.class); - } -} diff --git a/test/src/com/rabbitmq/client/test/server/ServerTests.java b/test/src/com/rabbitmq/client/test/server/ServerTests.java deleted file mode 100644 index 7f46efb447..0000000000 --- a/test/src/com/rabbitmq/client/test/server/ServerTests.java +++ /dev/null @@ -1,47 +0,0 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ -// -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. -// -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. -// - - -package com.rabbitmq.client.test.server; - -import junit.framework.TestCase; -import junit.framework.TestSuite; - -public class ServerTests extends TestCase { - public static TestSuite suite() { - TestSuite suite = new TestSuite("server-tests"); - add(suite); - return suite; - } - - public static void add(TestSuite suite) { - suite.addTestSuite(Permissions.class); - suite.addTestSuite(DurableBindingLifecycle.class); - suite.addTestSuite(DeadLetterExchangeDurable.class); - suite.addTestSuite(EffectVisibilityCrossNodeTest.class); - suite.addTestSuite(ExclusiveQueueDurability.class); - suite.addTestSuite(AbsentQueue.class); - suite.addTestSuite(AlternateExchangeEquivalence.class); - suite.addTestSuite(MemoryAlarms.class); - suite.addTestSuite(MessageRecovery.class); - suite.addTestSuite(Firehose.class); - suite.addTestSuite(PersistenceGuarantees.class); - suite.addTestSuite(Shutdown.class); - suite.addTestSuite(BlockedConnection.class); - suite.addTestSuite(ChannelLimitNegotiation.class); - suite.addTestSuite(LoopbackUsers.class); - } -} From a4e879a0261ccd78af7f201206e09089fa6c44e7 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 15 Jan 2016 00:27:33 +0300 Subject: [PATCH 0097/2114] 3.6.0 is out --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fb712fa298..f045113d86 100644 --- a/README.md +++ b/README.md @@ -14,14 +14,14 @@ Maven artifacts are [released to Maven Central](http://search.maven.org/#search% com.rabbitmq amqp-client - 3.5.5 + 3.6.0 ``` ### Gradle ``` groovy -compile 'com.rabbitmq:amqp-client:3.5.5' +compile 'com.rabbitmq:amqp-client:3.6.0' ``` From 1023b376b28c37d758e15846763111162790ec07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Fri, 15 Jan 2016 17:05:20 +0100 Subject: [PATCH 0098/2114] Use File.separator instead of FileSystems.getDefault().getSeparator() This fixes the build with Java 1.7. --- .../java/com/rabbitmq/client/test/AbstractRMQTestSuite.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java b/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java index 16614b4f7f..f01e137bc8 100644 --- a/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java +++ b/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java @@ -3,7 +3,6 @@ import java.io.File; import java.io.IOException; import java.net.Socket; -import java.nio.file.FileSystems; import java.util.Properties; import junit.framework.Test; @@ -86,8 +85,7 @@ public static boolean isSSLAvailable() { if (SSL_CERTS_DIR == null || hostname == null || port == null) return false; - String sslClientCertsDir = SSL_CERTS_DIR + - FileSystems.getDefault().getSeparator() + "client"; + String sslClientCertsDir = SSL_CERTS_DIR + File.separator + "client"; // If certificate is present and some server is listening on port 5671 if (new File(sslClientCertsDir).exists() && checkServerListening(hostname, Integer.parseInt(port))) { From 8087e915fa113df764c355d644ca50f47830f362 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 18 Jan 2016 16:35:24 +0100 Subject: [PATCH 0099/2114] Makefile: Fix path to `build.properties` This should fix `make distclean` and `make srcdist`. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 867f7f7f69..3e3f8d0631 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ WEB_URL=http://www.rabbitmq.com/ NEXUS_STAGE_URL=http://oss.sonatype.org/service/local/staging/deploy/maven2 MAVEN_NEXUS_VERSION=1.7 -AMQP_CODEGEN_DIR=$(shell fgrep sibling.codegen.dir build.properties | sed -e 's:sibling\.codegen\.dir=::') +AMQP_CODEGEN_DIR=$(shell fgrep sibling.codegen.dir src/test/resources/build.properties | sed -e 's:sibling\.codegen\.dir=::') MAVEN_RSYNC_DESTINATION=maven@195.224.125.254:/home/maven/rabbitmq-java-client/ From 12495f50c051e24a1ba2fbfd16c2666ea02aaa03 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Mon, 25 Jan 2016 17:16:59 +0300 Subject: [PATCH 0100/2114] Reduce the chance of hitting the same endpoint over and over when reconnecting Constant re-shuffling produced confusing effects in that there was a chance of 3-4 re-connections to the same (often unreachable in practice) endpoint. Fixes #124. --- .../impl/recovery/RecoveryAwareAMQConnectionFactory.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java b/src/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java index 6c5cb5541e..4910d1ff5e 100644 --- a/src/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java +++ b/src/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java @@ -29,7 +29,8 @@ public RecoveryAwareAMQConnectionFactory(ConnectionParams params, FrameHandlerFa */ RecoveryAwareAMQConnection newConnection() throws IOException, TimeoutException { IOException lastException = null; - for (Address addr : shuffle(addrs)) { + Address[] shuffled = shuffle(addrs); + for (Address addr : shuffled) { try { FrameHandler frameHandler = factory.create(addr); RecoveryAwareAMQConnection conn = new RecoveryAwareAMQConnection(params, frameHandler); From 029c21278d7a7256bbd21af84dbc61432aeaa6fb Mon Sep 17 00:00:00 2001 From: Dominik Bruhn Date: Mon, 25 Jan 2016 18:52:12 +0100 Subject: [PATCH 0101/2114] RpcClient: Make reply-to queue name configurable --- .../java/com/rabbitmq/client/RpcClient.java | 52 ++++++++++++++++--- 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/RpcClient.java b/src/main/java/com/rabbitmq/client/RpcClient.java index fa3dd4c6ed..a4dee5ae3d 100644 --- a/src/main/java/com/rabbitmq/client/RpcClient.java +++ b/src/main/java/com/rabbitmq/client/RpcClient.java @@ -48,6 +48,8 @@ public class RpcClient { private final String _exchange; /** Routing key to use for requests */ private final String _routingKey; + /** Queue where the server should put the reply */ + private final String _replyTo; /** timeout to use on call responses */ private final int _timeout; /** NO_TIMEOUT value must match convention on {@link BlockingCell#uninterruptibleGet(int)} */ @@ -65,17 +67,20 @@ public class RpcClient { * Construct a new RpcClient that will communicate on the given channel, sending * requests to the given exchange with the given routing key. *

- * Causes the creation of a temporary private autodelete queue. + * Causes the creation of a temporary private autodelete queue. The name of this queue can be specified. * @param channel the channel to use for communication * @param exchange the exchange to connect to * @param routingKey the routing key + * @param replyTo the queue where the server should put the reply * @param timeout milliseconds before timing out on wait for response * @throws IOException if an error is encountered */ - public RpcClient(Channel channel, String exchange, String routingKey, int timeout) throws IOException { + public RpcClient(Channel channel, String exchange, String routingKey, String replyTo, int timeout) throws + IOException { _channel = channel; _exchange = exchange; _routingKey = routingKey; + _replyTo = replyTo; if (timeout < NO_TIMEOUT) throw new IllegalArgumentException("Timeout arguument must be NO_TIMEOUT(-1) or non-negative."); _timeout = timeout; _correlationId = 0; @@ -87,7 +92,24 @@ public RpcClient(Channel channel, String exchange, String routingKey, int timeou * Construct a new RpcClient that will communicate on the given channel, sending * requests to the given exchange with the given routing key. *

- * Causes the creation of a temporary private autodelete queue. + * Causes the creation of a temporary private autodelete queue. The name of the queue can be provided + *

+ * Waits forever for responses (that is, no timeout). + * @param channel the channel to use for communication + * @param exchange the exchange to connect to + * @param routingKey the routing key + * @param replyTo the queue where the server should put the reply + * @throws IOException if an error is encountered + */ + public RpcClient(Channel channel, String exchange, String routingKey, String replyTo) throws IOException { + this(channel, exchange, routingKey, replyTo, NO_TIMEOUT); + } + + /** + * Construct a new RpcClient that will communicate on the given channel, sending + * requests to the given exchange with the given routing key. + *

+ * Causes the creation of a temporary private autodelete queue. This queue will be named "amq.rabbitmq.reply-to". *

* Waits forever for responses (that is, no timeout). * @param channel the channel to use for communication @@ -96,9 +118,27 @@ public RpcClient(Channel channel, String exchange, String routingKey, int timeou * @throws IOException if an error is encountered */ public RpcClient(Channel channel, String exchange, String routingKey) throws IOException { - this(channel, exchange, routingKey, NO_TIMEOUT); + this(channel, exchange, routingKey, "amq.rabbitmq.reply-to", NO_TIMEOUT); } + + /** + * Construct a new RpcClient that will communicate on the given channel, sending + * requests to the given exchange with the given routing key. + *

+ * Causes the creation of a temporary private autodelete queue. The name of this queue will be + * "amq.rabbitmq.reply-to". + * @param channel the channel to use for communication + * @param exchange the exchange to connect to + * @param routingKey the routing key + * @param timeout milliseconds before timing out on wait for response + * @throws IOException if an error is encountered + */ + public RpcClient(Channel channel, String exchange, String routingKey, int timeout) throws IOException { + this(channel, exchange, routingKey, "amq.rabbitmq.reply-to", timeout) + } + + /** * Private API - ensures the RpcClient is correctly open. * @throws IOException if an error is encountered @@ -152,7 +192,7 @@ public void handleDelivery(String consumerTag, } } }; - _channel.basicConsume("amq.rabbitmq.reply-to", true, consumer); + _channel.basicConsume(_replyTo, true, consumer); return consumer; } @@ -171,7 +211,7 @@ public byte[] primitiveCall(AMQP.BasicProperties props, byte[] message) _correlationId++; String replyId = "" + _correlationId; props = ((props==null) ? new AMQP.BasicProperties.Builder() : props.builder()) - .correlationId(replyId).replyTo("amq.rabbitmq.reply-to").build(); + .correlationId(replyId).replyTo(_replyTo).build(); _continuationMap.put(replyId, k); } publish(props, message); From 6d4e5bcbaaee256e80b717ce44d7b603e34d5853 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Tue, 26 Jan 2016 08:56:34 -0800 Subject: [PATCH 0102/2114] Correct comment --- src/main/java/com/rabbitmq/client/RpcClient.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/RpcClient.java b/src/main/java/com/rabbitmq/client/RpcClient.java index a4dee5ae3d..0d83ba6ef5 100644 --- a/src/main/java/com/rabbitmq/client/RpcClient.java +++ b/src/main/java/com/rabbitmq/client/RpcClient.java @@ -108,9 +108,10 @@ public RpcClient(Channel channel, String exchange, String routingKey, String rep /** * Construct a new RpcClient that will communicate on the given channel, sending * requests to the given exchange with the given routing key. - *

- * Causes the creation of a temporary private autodelete queue. This queue will be named "amq.rabbitmq.reply-to". - *

+ * + * Direct Reply-to will be used + * for response propagation. + * * Waits forever for responses (that is, no timeout). * @param channel the channel to use for communication * @param exchange the exchange to connect to From 01fce68d2047844a594b4026f38141087803faf2 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Tue, 26 Jan 2016 08:57:41 -0800 Subject: [PATCH 0103/2114] Explicitly mention Direct Reply-to --- src/main/java/com/rabbitmq/client/RpcClient.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/RpcClient.java b/src/main/java/com/rabbitmq/client/RpcClient.java index 0d83ba6ef5..b3b191a017 100644 --- a/src/main/java/com/rabbitmq/client/RpcClient.java +++ b/src/main/java/com/rabbitmq/client/RpcClient.java @@ -66,7 +66,7 @@ public class RpcClient { /** * Construct a new RpcClient that will communicate on the given channel, sending * requests to the given exchange with the given routing key. - *

+ * * Causes the creation of a temporary private autodelete queue. The name of this queue can be specified. * @param channel the channel to use for communication * @param exchange the exchange to connect to @@ -91,9 +91,11 @@ public RpcClient(Channel channel, String exchange, String routingKey, String rep /** * Construct a new RpcClient that will communicate on the given channel, sending * requests to the given exchange with the given routing key. - *

- * Causes the creation of a temporary private autodelete queue. The name of the queue can be provided - *

+ * + * Causes the creation of a temporary private autodelete queue. + * The name of the queue can be provided (only relevant for RabbitMQ servers + * that do not support Direct Reply-to. + * * Waits forever for responses (that is, no timeout). * @param channel the channel to use for communication * @param exchange the exchange to connect to From 56afacb40d414c70b4d66b10ab04fa5163946cf5 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Tue, 26 Jan 2016 09:09:11 -0800 Subject: [PATCH 0104/2114] Compile --- src/main/java/com/rabbitmq/client/RpcClient.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/RpcClient.java b/src/main/java/com/rabbitmq/client/RpcClient.java index b3b191a017..379e36178c 100644 --- a/src/main/java/com/rabbitmq/client/RpcClient.java +++ b/src/main/java/com/rabbitmq/client/RpcClient.java @@ -138,7 +138,7 @@ public RpcClient(Channel channel, String exchange, String routingKey) throws IOE * @throws IOException if an error is encountered */ public RpcClient(Channel channel, String exchange, String routingKey, int timeout) throws IOException { - this(channel, exchange, routingKey, "amq.rabbitmq.reply-to", timeout) + this(channel, exchange, routingKey, "amq.rabbitmq.reply-to", timeout); } From 66f692b902e3ffc7510ce82fbd25c26124672ee4 Mon Sep 17 00:00:00 2001 From: Dominik Bruhn Date: Mon, 25 Jan 2016 18:52:12 +0100 Subject: [PATCH 0105/2114] RpcClient: Make reply-to queue name configurable --- src/com/rabbitmq/client/RpcClient.java | 52 +++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/src/com/rabbitmq/client/RpcClient.java b/src/com/rabbitmq/client/RpcClient.java index fa3dd4c6ed..a4dee5ae3d 100644 --- a/src/com/rabbitmq/client/RpcClient.java +++ b/src/com/rabbitmq/client/RpcClient.java @@ -48,6 +48,8 @@ public class RpcClient { private final String _exchange; /** Routing key to use for requests */ private final String _routingKey; + /** Queue where the server should put the reply */ + private final String _replyTo; /** timeout to use on call responses */ private final int _timeout; /** NO_TIMEOUT value must match convention on {@link BlockingCell#uninterruptibleGet(int)} */ @@ -65,17 +67,20 @@ public class RpcClient { * Construct a new RpcClient that will communicate on the given channel, sending * requests to the given exchange with the given routing key. *

- * Causes the creation of a temporary private autodelete queue. + * Causes the creation of a temporary private autodelete queue. The name of this queue can be specified. * @param channel the channel to use for communication * @param exchange the exchange to connect to * @param routingKey the routing key + * @param replyTo the queue where the server should put the reply * @param timeout milliseconds before timing out on wait for response * @throws IOException if an error is encountered */ - public RpcClient(Channel channel, String exchange, String routingKey, int timeout) throws IOException { + public RpcClient(Channel channel, String exchange, String routingKey, String replyTo, int timeout) throws + IOException { _channel = channel; _exchange = exchange; _routingKey = routingKey; + _replyTo = replyTo; if (timeout < NO_TIMEOUT) throw new IllegalArgumentException("Timeout arguument must be NO_TIMEOUT(-1) or non-negative."); _timeout = timeout; _correlationId = 0; @@ -87,7 +92,24 @@ public RpcClient(Channel channel, String exchange, String routingKey, int timeou * Construct a new RpcClient that will communicate on the given channel, sending * requests to the given exchange with the given routing key. *

- * Causes the creation of a temporary private autodelete queue. + * Causes the creation of a temporary private autodelete queue. The name of the queue can be provided + *

+ * Waits forever for responses (that is, no timeout). + * @param channel the channel to use for communication + * @param exchange the exchange to connect to + * @param routingKey the routing key + * @param replyTo the queue where the server should put the reply + * @throws IOException if an error is encountered + */ + public RpcClient(Channel channel, String exchange, String routingKey, String replyTo) throws IOException { + this(channel, exchange, routingKey, replyTo, NO_TIMEOUT); + } + + /** + * Construct a new RpcClient that will communicate on the given channel, sending + * requests to the given exchange with the given routing key. + *

+ * Causes the creation of a temporary private autodelete queue. This queue will be named "amq.rabbitmq.reply-to". *

* Waits forever for responses (that is, no timeout). * @param channel the channel to use for communication @@ -96,9 +118,27 @@ public RpcClient(Channel channel, String exchange, String routingKey, int timeou * @throws IOException if an error is encountered */ public RpcClient(Channel channel, String exchange, String routingKey) throws IOException { - this(channel, exchange, routingKey, NO_TIMEOUT); + this(channel, exchange, routingKey, "amq.rabbitmq.reply-to", NO_TIMEOUT); } + + /** + * Construct a new RpcClient that will communicate on the given channel, sending + * requests to the given exchange with the given routing key. + *

+ * Causes the creation of a temporary private autodelete queue. The name of this queue will be + * "amq.rabbitmq.reply-to". + * @param channel the channel to use for communication + * @param exchange the exchange to connect to + * @param routingKey the routing key + * @param timeout milliseconds before timing out on wait for response + * @throws IOException if an error is encountered + */ + public RpcClient(Channel channel, String exchange, String routingKey, int timeout) throws IOException { + this(channel, exchange, routingKey, "amq.rabbitmq.reply-to", timeout) + } + + /** * Private API - ensures the RpcClient is correctly open. * @throws IOException if an error is encountered @@ -152,7 +192,7 @@ public void handleDelivery(String consumerTag, } } }; - _channel.basicConsume("amq.rabbitmq.reply-to", true, consumer); + _channel.basicConsume(_replyTo, true, consumer); return consumer; } @@ -171,7 +211,7 @@ public byte[] primitiveCall(AMQP.BasicProperties props, byte[] message) _correlationId++; String replyId = "" + _correlationId; props = ((props==null) ? new AMQP.BasicProperties.Builder() : props.builder()) - .correlationId(replyId).replyTo("amq.rabbitmq.reply-to").build(); + .correlationId(replyId).replyTo(_replyTo).build(); _continuationMap.put(replyId, k); } publish(props, message); From 4f07bec93122b148d456cd0906d6f4f29180b0c5 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Tue, 26 Jan 2016 08:56:34 -0800 Subject: [PATCH 0106/2114] Correct comment --- src/com/rabbitmq/client/RpcClient.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/com/rabbitmq/client/RpcClient.java b/src/com/rabbitmq/client/RpcClient.java index a4dee5ae3d..0d83ba6ef5 100644 --- a/src/com/rabbitmq/client/RpcClient.java +++ b/src/com/rabbitmq/client/RpcClient.java @@ -108,9 +108,10 @@ public RpcClient(Channel channel, String exchange, String routingKey, String rep /** * Construct a new RpcClient that will communicate on the given channel, sending * requests to the given exchange with the given routing key. - *

- * Causes the creation of a temporary private autodelete queue. This queue will be named "amq.rabbitmq.reply-to". - *

+ * + * Direct Reply-to will be used + * for response propagation. + * * Waits forever for responses (that is, no timeout). * @param channel the channel to use for communication * @param exchange the exchange to connect to From 91bbc991d58366e83457737928b5b38c194f49ab Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Tue, 26 Jan 2016 08:57:41 -0800 Subject: [PATCH 0107/2114] Explicitly mention Direct Reply-to --- src/com/rabbitmq/client/RpcClient.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/com/rabbitmq/client/RpcClient.java b/src/com/rabbitmq/client/RpcClient.java index 0d83ba6ef5..b3b191a017 100644 --- a/src/com/rabbitmq/client/RpcClient.java +++ b/src/com/rabbitmq/client/RpcClient.java @@ -66,7 +66,7 @@ public class RpcClient { /** * Construct a new RpcClient that will communicate on the given channel, sending * requests to the given exchange with the given routing key. - *

+ * * Causes the creation of a temporary private autodelete queue. The name of this queue can be specified. * @param channel the channel to use for communication * @param exchange the exchange to connect to @@ -91,9 +91,11 @@ public RpcClient(Channel channel, String exchange, String routingKey, String rep /** * Construct a new RpcClient that will communicate on the given channel, sending * requests to the given exchange with the given routing key. - *

- * Causes the creation of a temporary private autodelete queue. The name of the queue can be provided - *

+ * + * Causes the creation of a temporary private autodelete queue. + * The name of the queue can be provided (only relevant for RabbitMQ servers + * that do not support Direct Reply-to. + * * Waits forever for responses (that is, no timeout). * @param channel the channel to use for communication * @param exchange the exchange to connect to From 16d34abc4caf2d24753c344db29f711baadf14cc Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Tue, 26 Jan 2016 09:09:11 -0800 Subject: [PATCH 0108/2114] Compile --- src/com/rabbitmq/client/RpcClient.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/rabbitmq/client/RpcClient.java b/src/com/rabbitmq/client/RpcClient.java index b3b191a017..379e36178c 100644 --- a/src/com/rabbitmq/client/RpcClient.java +++ b/src/com/rabbitmq/client/RpcClient.java @@ -138,7 +138,7 @@ public RpcClient(Channel channel, String exchange, String routingKey) throws IOE * @throws IOException if an error is encountered */ public RpcClient(Channel channel, String exchange, String routingKey, int timeout) throws IOException { - this(channel, exchange, routingKey, "amq.rabbitmq.reply-to", timeout) + this(channel, exchange, routingKey, "amq.rabbitmq.reply-to", timeout); } From be7540d696f9cfd6f1d5d1b8d14a3f3a1af87a4c Mon Sep 17 00:00:00 2001 From: Brandon Shroyer Date: Mon, 25 Jan 2016 15:57:53 -0500 Subject: [PATCH 0109/2114] Overload ConnectionFactory.newConnection methods to use lists as well as arrays. * Public newConnection() methods that took arrays as inputs are still present, but wrap around list-based invocations. Addresses [issue #125](https://github.com/rabbitmq/rabbitmq-java-client/issues/125). --- build.xml | 3 +- .../rabbitmq/client/ConnectionFactory.java | 53 ++++++++++--- .../recovery/AutorecoveringConnection.java | 7 ++ .../RecoveryAwareAMQConnectionFactory.java | 74 ++++++++++--------- .../test/functional/ConnectionRecovery.java | 33 ++++++++- .../client/test/functional/FrameMax.java | 18 +---- 6 files changed, 125 insertions(+), 63 deletions(-) diff --git a/build.xml b/build.xml index 0b5cc50339..b0e0fe931f 100644 --- a/build.xml +++ b/build.xml @@ -87,7 +87,8 @@ - automatic connection recovery + * is enabled, the connection returned by this method will be {@link Recoverable}. Future + * reconnection attempts will pick a random accessible address from the provided list. + * + * @param addr_list a List of known broker addresses (hostname/port pairs) to try in order + * @return an interface to the connection + * @throws IOException if it encounters a problem + */ + public Connection newConnection(List

addr_list) throws IOException, TimeoutException { + return newConnection(this.sharedExecutor, addr_list); } /** @@ -658,7 +676,25 @@ public Connection newConnection(Address[] addrs) throws IOException, TimeoutExce * @throws java.io.IOException if it encounters a problem * @see Automatic Recovery */ - public Connection newConnection(ExecutorService executor, Address[] addrs) + public Connection newConnection(ExecutorService executor, Address[] addrs) throws IOException, TimeoutException { + return newConnection(executor, Arrays.asList(addrs)); + } + + /** + * Create a new broker connection, picking the first available address from + * the list. + * + * If automatic connection recovery + * is enabled, the connection returned by this method will be {@link Recoverable}. Future + * reconnection attempts will pick a random accessible address from the provided list. + * + * @param executor thread execution service for consumers on the connection + * @param addr_list a List of known broker addresses (hostname/port pairs) to try in order + * @return an interface to the connection + * @throws java.io.IOException if it encounters a problem + * @see Automatic Recovery + */ + public Connection newConnection(ExecutorService executor, List
addr_list) throws IOException, TimeoutException { // make sure we respect the provided thread factory FrameHandlerFactory fhFactory = createFrameHandlerFactory(); @@ -666,12 +702,13 @@ public Connection newConnection(ExecutorService executor, Address[] addrs) if (isAutomaticRecoveryEnabled()) { // see com.rabbitmq.client.impl.recovery.RecoveryAwareAMQConnectionFactory#newConnection - AutorecoveringConnection conn = new AutorecoveringConnection(params, fhFactory, addrs); + AutorecoveringConnection conn = new AutorecoveringConnection(params, fhFactory, addr_list); + conn.init(); return conn; } else { IOException lastException = null; - for (Address addr : addrs) { + for (Address addr : addr_list) { try { FrameHandler handler = fhFactory.create(addr); AMQConnection conn = new AMQConnection(params, handler); @@ -719,9 +756,7 @@ public ConnectionParams params(ExecutorService consumerWorkServiceExecutor) { * @throws IOException if it encounters a problem */ public Connection newConnection() throws IOException, TimeoutException { - return newConnection(this.sharedExecutor, - new Address[] {new Address(getHost(), getPort())} - ); + return newConnection(this.sharedExecutor, Arrays.asList(new Address(getHost(), getPort()))); } /** @@ -736,9 +771,7 @@ public Connection newConnection() throws IOException, TimeoutException { * @throws IOException if it encounters a problem */ public Connection newConnection(ExecutorService executor) throws IOException, TimeoutException { - return newConnection(executor, - new Address[] {new Address(getHost(), getPort())} - ); + return newConnection(executor, Arrays.asList(new Address(getHost(), getPort()))); } @Override public ConnectionFactory clone(){ diff --git a/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index 145b3aa14c..9fc5dd0da0 100644 --- a/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -82,6 +82,13 @@ public AutorecoveringConnection(ConnectionParams params, FrameHandlerFactory f, this.channels = new ConcurrentHashMap(); } + public AutorecoveringConnection(ConnectionParams params, FrameHandlerFactory f, List
addr_list) { + this.cf = new RecoveryAwareAMQConnectionFactory(params, f, addr_list); + this.params = params; + + this.channels = new ConcurrentHashMap(); + } + /** * Private API. * @throws IOException diff --git a/src/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java b/src/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java index 4910d1ff5e..99fc17bf55 100644 --- a/src/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java +++ b/src/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java @@ -13,42 +13,46 @@ import java.util.concurrent.TimeoutException; public class RecoveryAwareAMQConnectionFactory { - private final ConnectionParams params; - private final FrameHandlerFactory factory; - private final Address[] addrs; - - public RecoveryAwareAMQConnectionFactory(ConnectionParams params, FrameHandlerFactory factory, Address[] addrs) { - this.params = params; - this.factory = factory; - this.addrs = addrs; - } + private final ConnectionParams params; + private final FrameHandlerFactory factory; + private final List
addrs; - /** - * @return an interface to the connection - * @throws java.io.IOException if it encounters a problem - */ - RecoveryAwareAMQConnection newConnection() throws IOException, TimeoutException { - IOException lastException = null; - Address[] shuffled = shuffle(addrs); - for (Address addr : shuffled) { - try { - FrameHandler frameHandler = factory.create(addr); - RecoveryAwareAMQConnection conn = new RecoveryAwareAMQConnection(params, frameHandler); - conn.start(); - return conn; - } catch (IOException e) { - lastException = e; - } - } - - throw (lastException != null) ? lastException : new IOException("failed to connect"); - } + public RecoveryAwareAMQConnectionFactory(ConnectionParams params, FrameHandlerFactory factory, Address[] addrs) { + this.params = params; + this.factory = factory; + this.addrs = Arrays.asList(addrs); + } + + public RecoveryAwareAMQConnectionFactory(ConnectionParams params, FrameHandlerFactory factory, List
addrs){ + this.params = params; + this.factory = factory; + this.addrs = addrs; + } + /** + * @return an interface to the connection + * @throws java.io.IOException if it encounters a problem + */ + RecoveryAwareAMQConnection newConnection() throws IOException, TimeoutException { + IOException lastException = null; + List
shuffled = shuffle(addrs); - private Address[] shuffle(Address[] addrs) { - List
list = new ArrayList
(Arrays.asList(addrs)); - Collections.shuffle(list); - Address[] result = new Address[addrs.length]; - list.toArray(result); - return result; + for (Address addr : shuffled) { + try { + FrameHandler frameHandler = factory.create(addr); + RecoveryAwareAMQConnection conn = new RecoveryAwareAMQConnection(params, frameHandler); + conn.start(); + return conn; + } catch (IOException e) { + lastException = e; + } } + + throw (lastException != null) ? lastException : new IOException("failed to connect"); + } + + private List
shuffle(List
addrs) { + List
list = new ArrayList
(addrs); + Collections.shuffle(list); + return list; + } } diff --git a/test/src/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/test/src/com/rabbitmq/client/test/functional/ConnectionRecovery.java index c310c81c1b..68dcb4f1a2 100644 --- a/test/src/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/test/src/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -11,6 +11,7 @@ import com.rabbitmq.tools.Host; import java.io.IOException; +import java.util.Arrays; import java.util.List; import java.util.ArrayList; import java.util.UUID; @@ -35,7 +36,7 @@ public void testConnectionRecoveryWithServerRestart() throws IOException, Interr assertTrue(connection.isOpen()); } - public void testConnectionRecoveryWithMultipleAddresses() + public void testConnectionRecoveryWithArrayOfAddresses() throws IOException, InterruptedException, TimeoutException { final Address[] addresses = {new Address("127.0.0.1"), new Address("127.0.0.1", 5672)}; AutorecoveringConnection c = newRecoveringConnection(addresses); @@ -49,6 +50,21 @@ public void testConnectionRecoveryWithMultipleAddresses() } + public void testConnectionRecoveryWithListOfAddresses() + throws IOException, InterruptedException, TimeoutException { + + final List
addresses = Arrays.asList(new Address("127.0.0.1"), new Address("127.0.0.1", 5672)); + + AutorecoveringConnection c = newRecoveringConnection(addresses); + try { + assertTrue(c.isOpen()); + closeAndWaitForRecovery(c); + assertTrue(c.isOpen()); + } finally { + c.abort(); + } + } + public void testConnectionRecoveryWithDisabledTopologyRecovery() throws IOException, InterruptedException, TimeoutException { AutorecoveringConnection c = newRecoveringConnection(true); @@ -705,17 +721,28 @@ private AutorecoveringConnection newRecoveringConnection(boolean disableTopology return (AutorecoveringConnection) cf.newConnection(); } + private AutorecoveringConnection newRecoveringConnection(boolean disableTopologyRecovery, Address[] addresses) + throws IOException, TimeoutException { + ConnectionFactory cf = buildConnectionFactoryWithRecoveryEnabled(disableTopologyRecovery); + return (AutorecoveringConnection) cf.newConnection(addresses); + } + private AutorecoveringConnection newRecoveringConnection(Address[] addresses) throws IOException, TimeoutException { - return newRecoveringConnection(false, addresses); + return newRecoveringConnection(false, Arrays.asList(addresses)); } - private AutorecoveringConnection newRecoveringConnection(boolean disableTopologyRecovery, Address[] addresses) + private AutorecoveringConnection newRecoveringConnection(boolean disableTopologyRecovery, List
addresses) throws IOException, TimeoutException { ConnectionFactory cf = buildConnectionFactoryWithRecoveryEnabled(disableTopologyRecovery); return (AutorecoveringConnection) cf.newConnection(addresses); } + private AutorecoveringConnection newRecoveringConnection(List
addresses) + throws IOException, TimeoutException { + return newRecoveringConnection(false, addresses); + } + private ConnectionFactory buildConnectionFactoryWithRecoveryEnabled(boolean disableTopologyRecovery) { ConnectionFactory cf = new ConnectionFactory(); cf.setNetworkRecoveryInterval(RECOVERY_INTERVAL); diff --git a/test/src/com/rabbitmq/client/test/functional/FrameMax.java b/test/src/com/rabbitmq/client/test/functional/FrameMax.java index d6f31fc5db..9a388a93ca 100644 --- a/test/src/com/rabbitmq/client/test/functional/FrameMax.java +++ b/test/src/com/rabbitmq/client/test/functional/FrameMax.java @@ -17,26 +17,16 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.impl.ConnectionParams; +import com.rabbitmq.client.*; +import com.rabbitmq.client.impl.*; import com.rabbitmq.client.test.BrokerTestCase; import java.io.IOException; import java.net.Socket; +import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeoutException; -import com.rabbitmq.client.Address; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.ConnectionFactory; -import com.rabbitmq.client.GetResponse; -import com.rabbitmq.client.impl.AMQConnection; -import com.rabbitmq.client.impl.AMQCommand; -import com.rabbitmq.client.impl.Frame; -import com.rabbitmq.client.impl.FrameHandler; -import com.rabbitmq.client.impl.LongStringHelper; -import com.rabbitmq.client.impl.SocketFrameHandler; - public class FrameMax extends BrokerTestCase { /* This value for FrameMax is larger than the minimum and less * than what Rabbit suggests. */ @@ -147,7 +137,7 @@ public GenerousAMQConnection(ConnectionFactory factory, private static class GenerousConnectionFactory extends ConnectionFactory { - @Override public Connection newConnection(ExecutorService executor, Address[] addrs) + @Override public Connection newConnection(ExecutorService executor, List
addrs) throws IOException, TimeoutException { IOException lastException = null; for (Address addr : addrs) { From c67d868f5e43572f02e938cfe135ac2f4f034be5 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 27 Jan 2016 00:56:14 +0300 Subject: [PATCH 0110/2114] Cosmetics --- src/com/rabbitmq/client/ConnectionFactory.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/com/rabbitmq/client/ConnectionFactory.java b/src/com/rabbitmq/client/ConnectionFactory.java index e6f3588180..70010ba343 100644 --- a/src/com/rabbitmq/client/ConnectionFactory.java +++ b/src/com/rabbitmq/client/ConnectionFactory.java @@ -654,12 +654,12 @@ public Connection newConnection(Address[] addrs) throws IOException, TimeoutExce * is enabled, the connection returned by this method will be {@link Recoverable}. Future * reconnection attempts will pick a random accessible address from the provided list. * - * @param addr_list a List of known broker addresses (hostname/port pairs) to try in order + * @param addrs a List of known broker addresses (hostname/port pairs) to try in order * @return an interface to the connection * @throws IOException if it encounters a problem */ - public Connection newConnection(List
addr_list) throws IOException, TimeoutException { - return newConnection(this.sharedExecutor, addr_list); + public Connection newConnection(List
addrs) throws IOException, TimeoutException { + return newConnection(this.sharedExecutor, addrs); } /** @@ -689,12 +689,12 @@ public Connection newConnection(ExecutorService executor, Address[] addrs) throw * reconnection attempts will pick a random accessible address from the provided list. * * @param executor thread execution service for consumers on the connection - * @param addr_list a List of known broker addresses (hostname/port pairs) to try in order + * @param addrs a List of known broker addrs (hostname/port pairs) to try in order * @return an interface to the connection * @throws java.io.IOException if it encounters a problem * @see Automatic Recovery */ - public Connection newConnection(ExecutorService executor, List
addr_list) + public Connection newConnection(ExecutorService executor, List
addrs) throws IOException, TimeoutException { // make sure we respect the provided thread factory FrameHandlerFactory fhFactory = createFrameHandlerFactory(); @@ -702,13 +702,13 @@ public Connection newConnection(ExecutorService executor, List
addr_lis if (isAutomaticRecoveryEnabled()) { // see com.rabbitmq.client.impl.recovery.RecoveryAwareAMQConnectionFactory#newConnection - AutorecoveringConnection conn = new AutorecoveringConnection(params, fhFactory, addr_list); + AutorecoveringConnection conn = new AutorecoveringConnection(params, fhFactory, addrs); conn.init(); return conn; } else { IOException lastException = null; - for (Address addr : addr_list) { + for (Address addr : addrs) { try { FrameHandler handler = fhFactory.create(addr); AMQConnection conn = new AMQConnection(params, handler); From 2ce046deac950091f6a391ca0d31eb4b8740cc6b Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 27 Jan 2016 01:05:23 +0300 Subject: [PATCH 0111/2114] Cosmetics --- .../impl/recovery/AutorecoveringConnection.java | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index 9fc5dd0da0..32e875fce4 100644 --- a/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -74,16 +74,9 @@ public class AutorecoveringConnection implements Connection, Recoverable, Networ // This lock guards the manuallyClosed flag and the delegate connection. Guarding these two ensures that a new connection can never // be created after application code has initiated shutdown. private final Object recoveryLock = new Object(); - - public AutorecoveringConnection(ConnectionParams params, FrameHandlerFactory f, Address[] addrs) { - this.cf = new RecoveryAwareAMQConnectionFactory(params, f, addrs); - this.params = params; - this.channels = new ConcurrentHashMap(); - } - - public AutorecoveringConnection(ConnectionParams params, FrameHandlerFactory f, List
addr_list) { - this.cf = new RecoveryAwareAMQConnectionFactory(params, f, addr_list); + public AutorecoveringConnection(ConnectionParams params, FrameHandlerFactory f, List
addrs) { + this.cf = new RecoveryAwareAMQConnectionFactory(params, f, addrs); this.params = params; this.channels = new ConcurrentHashMap(); From a642b961c06f5ec37668d7dd8675d588c1c6ff65 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 27 Jan 2016 01:07:51 +0300 Subject: [PATCH 0112/2114] Cosmetics, remove unused code * The Address[] constructor is not used by user apps. --- .../RecoveryAwareAMQConnectionFactory.java | 74 +++++++++---------- 1 file changed, 34 insertions(+), 40 deletions(-) diff --git a/src/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java b/src/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java index 99fc17bf55..54bda056bb 100644 --- a/src/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java +++ b/src/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java @@ -7,52 +7,46 @@ import java.io.IOException; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.concurrent.TimeoutException; public class RecoveryAwareAMQConnectionFactory { - private final ConnectionParams params; - private final FrameHandlerFactory factory; - private final List
addrs; - - public RecoveryAwareAMQConnectionFactory(ConnectionParams params, FrameHandlerFactory factory, Address[] addrs) { - this.params = params; - this.factory = factory; - this.addrs = Arrays.asList(addrs); - } - - public RecoveryAwareAMQConnectionFactory(ConnectionParams params, FrameHandlerFactory factory, List
addrs){ - this.params = params; - this.factory = factory; - this.addrs = addrs; - } - /** - * @return an interface to the connection - * @throws java.io.IOException if it encounters a problem - */ - RecoveryAwareAMQConnection newConnection() throws IOException, TimeoutException { - IOException lastException = null; - List
shuffled = shuffle(addrs); - - for (Address addr : shuffled) { - try { - FrameHandler frameHandler = factory.create(addr); - RecoveryAwareAMQConnection conn = new RecoveryAwareAMQConnection(params, frameHandler); - conn.start(); - return conn; - } catch (IOException e) { - lastException = e; - } + private final ConnectionParams params; + private final FrameHandlerFactory factory; + private final List
addrs; + + public RecoveryAwareAMQConnectionFactory(ConnectionParams params, FrameHandlerFactory factory, List
addrs) { + this.params = params; + this.factory = factory; + this.addrs = addrs; } - throw (lastException != null) ? lastException : new IOException("failed to connect"); - } + /** + * @return an interface to the connection + * @throws java.io.IOException if it encounters a problem + */ + RecoveryAwareAMQConnection newConnection() throws IOException, TimeoutException { + IOException lastException = null; + List
shuffled = shuffle(addrs); + + for (Address addr : shuffled) { + try { + FrameHandler frameHandler = factory.create(addr); + RecoveryAwareAMQConnection conn = new RecoveryAwareAMQConnection(params, frameHandler); + conn.start(); + return conn; + } catch (IOException e) { + lastException = e; + } + } + + throw (lastException != null) ? lastException : new IOException("failed to connect"); + } - private List
shuffle(List
addrs) { - List
list = new ArrayList
(addrs); - Collections.shuffle(list); - return list; - } + private List
shuffle(List
addrs) { + List
list = new ArrayList
(addrs); + Collections.shuffle(list); + return list; + } } From 8c30a4012a3bc64367c35b9d61bfdd5ff1a724e0 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 27 Jan 2016 01:08:22 +0300 Subject: [PATCH 0113/2114] Specifically invoke the Address[] version Otherwise we test a test helper method. --- .../client/test/functional/ConnectionRecovery.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/test/src/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/test/src/com/rabbitmq/client/test/functional/ConnectionRecovery.java index 68dcb4f1a2..efb944a347 100644 --- a/test/src/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/test/src/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -721,15 +721,11 @@ private AutorecoveringConnection newRecoveringConnection(boolean disableTopology return (AutorecoveringConnection) cf.newConnection(); } - private AutorecoveringConnection newRecoveringConnection(boolean disableTopologyRecovery, Address[] addresses) - throws IOException, TimeoutException { - ConnectionFactory cf = buildConnectionFactoryWithRecoveryEnabled(disableTopologyRecovery); - return (AutorecoveringConnection) cf.newConnection(addresses); - } - private AutorecoveringConnection newRecoveringConnection(Address[] addresses) throws IOException, TimeoutException { - return newRecoveringConnection(false, Arrays.asList(addresses)); + ConnectionFactory cf = buildConnectionFactoryWithRecoveryEnabled(false); + // specifically use the Address[] overload + return (AutorecoveringConnection) cf.newConnection(addresses); } private AutorecoveringConnection newRecoveringConnection(boolean disableTopologyRecovery, List
addresses) From 643f5613330decb8404174e3fa79168a6e7c550e Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 27 Jan 2016 01:37:45 +0300 Subject: [PATCH 0114/2114] Cosmetics --- src/com/rabbitmq/client/ConnectionFactory.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/com/rabbitmq/client/ConnectionFactory.java b/src/com/rabbitmq/client/ConnectionFactory.java index 70010ba343..191175180b 100644 --- a/src/com/rabbitmq/client/ConnectionFactory.java +++ b/src/com/rabbitmq/client/ConnectionFactory.java @@ -19,6 +19,7 @@ import java.io.IOException; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; +import java.util.Collections; import java.util.Map; import java.util.concurrent.*; import java.util.List; @@ -756,7 +757,7 @@ public ConnectionParams params(ExecutorService consumerWorkServiceExecutor) { * @throws IOException if it encounters a problem */ public Connection newConnection() throws IOException, TimeoutException { - return newConnection(this.sharedExecutor, Arrays.asList(new Address(getHost(), getPort()))); + return newConnection(this.sharedExecutor, Collections.singletonList(new Address(getHost(), getPort()))); } /** @@ -771,7 +772,7 @@ public Connection newConnection() throws IOException, TimeoutException { * @throws IOException if it encounters a problem */ public Connection newConnection(ExecutorService executor) throws IOException, TimeoutException { - return newConnection(executor, Arrays.asList(new Address(getHost(), getPort()))); + return newConnection(executor, Collections.singletonList(new Address(getHost(), getPort()))); } @Override public ConnectionFactory clone(){ From f7dee0a84093de5ecff2227a355bd188e8094131 Mon Sep 17 00:00:00 2001 From: Brandon Shroyer Date: Mon, 25 Jan 2016 15:57:53 -0500 Subject: [PATCH 0115/2114] Overload ConnectionFactory.newConnection methods to use lists as well as arrays. * Public newConnection() methods that took arrays as inputs are still present, but wrap around list-based invocations. Addresses [issue #125](https://github.com/rabbitmq/rabbitmq-java-client/issues/125). --- build.xml | 3 +- .../rabbitmq/client/ConnectionFactory.java | 53 ++++++++++--- .../recovery/AutorecoveringConnection.java | 7 ++ .../RecoveryAwareAMQConnectionFactory.java | 74 ++++++++++--------- .../test/functional/ConnectionRecovery.java | 33 ++++++++- .../client/test/functional/FrameMax.java | 18 +---- 6 files changed, 125 insertions(+), 63 deletions(-) diff --git a/build.xml b/build.xml index 383567a549..847bfef516 100644 --- a/build.xml +++ b/build.xml @@ -87,7 +87,8 @@ - automatic connection recovery + * is enabled, the connection returned by this method will be {@link Recoverable}. Future + * reconnection attempts will pick a random accessible address from the provided list. + * + * @param addr_list a List of known broker addresses (hostname/port pairs) to try in order + * @return an interface to the connection + * @throws IOException if it encounters a problem + */ + public Connection newConnection(List
addr_list) throws IOException, TimeoutException { + return newConnection(this.sharedExecutor, addr_list); } /** @@ -658,7 +676,25 @@ public Connection newConnection(Address[] addrs) throws IOException, TimeoutExce * @throws java.io.IOException if it encounters a problem * @see Automatic Recovery */ - public Connection newConnection(ExecutorService executor, Address[] addrs) + public Connection newConnection(ExecutorService executor, Address[] addrs) throws IOException, TimeoutException { + return newConnection(executor, Arrays.asList(addrs)); + } + + /** + * Create a new broker connection, picking the first available address from + * the list. + * + * If automatic connection recovery + * is enabled, the connection returned by this method will be {@link Recoverable}. Future + * reconnection attempts will pick a random accessible address from the provided list. + * + * @param executor thread execution service for consumers on the connection + * @param addr_list a List of known broker addresses (hostname/port pairs) to try in order + * @return an interface to the connection + * @throws java.io.IOException if it encounters a problem + * @see Automatic Recovery + */ + public Connection newConnection(ExecutorService executor, List
addr_list) throws IOException, TimeoutException { // make sure we respect the provided thread factory FrameHandlerFactory fhFactory = createFrameHandlerFactory(); @@ -666,12 +702,13 @@ public Connection newConnection(ExecutorService executor, Address[] addrs) if (isAutomaticRecoveryEnabled()) { // see com.rabbitmq.client.impl.recovery.RecoveryAwareAMQConnectionFactory#newConnection - AutorecoveringConnection conn = new AutorecoveringConnection(params, fhFactory, addrs); + AutorecoveringConnection conn = new AutorecoveringConnection(params, fhFactory, addr_list); + conn.init(); return conn; } else { IOException lastException = null; - for (Address addr : addrs) { + for (Address addr : addr_list) { try { FrameHandler handler = fhFactory.create(addr); AMQConnection conn = new AMQConnection(params, handler); @@ -719,9 +756,7 @@ public ConnectionParams params(ExecutorService consumerWorkServiceExecutor) { * @throws IOException if it encounters a problem */ public Connection newConnection() throws IOException, TimeoutException { - return newConnection(this.sharedExecutor, - new Address[] {new Address(getHost(), getPort())} - ); + return newConnection(this.sharedExecutor, Arrays.asList(new Address(getHost(), getPort()))); } /** @@ -736,9 +771,7 @@ public Connection newConnection() throws IOException, TimeoutException { * @throws IOException if it encounters a problem */ public Connection newConnection(ExecutorService executor) throws IOException, TimeoutException { - return newConnection(executor, - new Address[] {new Address(getHost(), getPort())} - ); + return newConnection(executor, Arrays.asList(new Address(getHost(), getPort()))); } @Override public ConnectionFactory clone(){ diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index 145b3aa14c..9fc5dd0da0 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -82,6 +82,13 @@ public AutorecoveringConnection(ConnectionParams params, FrameHandlerFactory f, this.channels = new ConcurrentHashMap(); } + public AutorecoveringConnection(ConnectionParams params, FrameHandlerFactory f, List
addr_list) { + this.cf = new RecoveryAwareAMQConnectionFactory(params, f, addr_list); + this.params = params; + + this.channels = new ConcurrentHashMap(); + } + /** * Private API. * @throws IOException diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java index 4910d1ff5e..99fc17bf55 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java @@ -13,42 +13,46 @@ import java.util.concurrent.TimeoutException; public class RecoveryAwareAMQConnectionFactory { - private final ConnectionParams params; - private final FrameHandlerFactory factory; - private final Address[] addrs; - - public RecoveryAwareAMQConnectionFactory(ConnectionParams params, FrameHandlerFactory factory, Address[] addrs) { - this.params = params; - this.factory = factory; - this.addrs = addrs; - } + private final ConnectionParams params; + private final FrameHandlerFactory factory; + private final List
addrs; - /** - * @return an interface to the connection - * @throws java.io.IOException if it encounters a problem - */ - RecoveryAwareAMQConnection newConnection() throws IOException, TimeoutException { - IOException lastException = null; - Address[] shuffled = shuffle(addrs); - for (Address addr : shuffled) { - try { - FrameHandler frameHandler = factory.create(addr); - RecoveryAwareAMQConnection conn = new RecoveryAwareAMQConnection(params, frameHandler); - conn.start(); - return conn; - } catch (IOException e) { - lastException = e; - } - } - - throw (lastException != null) ? lastException : new IOException("failed to connect"); - } + public RecoveryAwareAMQConnectionFactory(ConnectionParams params, FrameHandlerFactory factory, Address[] addrs) { + this.params = params; + this.factory = factory; + this.addrs = Arrays.asList(addrs); + } + + public RecoveryAwareAMQConnectionFactory(ConnectionParams params, FrameHandlerFactory factory, List
addrs){ + this.params = params; + this.factory = factory; + this.addrs = addrs; + } + /** + * @return an interface to the connection + * @throws java.io.IOException if it encounters a problem + */ + RecoveryAwareAMQConnection newConnection() throws IOException, TimeoutException { + IOException lastException = null; + List
shuffled = shuffle(addrs); - private Address[] shuffle(Address[] addrs) { - List
list = new ArrayList
(Arrays.asList(addrs)); - Collections.shuffle(list); - Address[] result = new Address[addrs.length]; - list.toArray(result); - return result; + for (Address addr : shuffled) { + try { + FrameHandler frameHandler = factory.create(addr); + RecoveryAwareAMQConnection conn = new RecoveryAwareAMQConnection(params, frameHandler); + conn.start(); + return conn; + } catch (IOException e) { + lastException = e; + } } + + throw (lastException != null) ? lastException : new IOException("failed to connect"); + } + + private List
shuffle(List
addrs) { + List
list = new ArrayList
(addrs); + Collections.shuffle(list); + return list; + } } diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java index c310c81c1b..68dcb4f1a2 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -11,6 +11,7 @@ import com.rabbitmq.tools.Host; import java.io.IOException; +import java.util.Arrays; import java.util.List; import java.util.ArrayList; import java.util.UUID; @@ -35,7 +36,7 @@ public void testConnectionRecoveryWithServerRestart() throws IOException, Interr assertTrue(connection.isOpen()); } - public void testConnectionRecoveryWithMultipleAddresses() + public void testConnectionRecoveryWithArrayOfAddresses() throws IOException, InterruptedException, TimeoutException { final Address[] addresses = {new Address("127.0.0.1"), new Address("127.0.0.1", 5672)}; AutorecoveringConnection c = newRecoveringConnection(addresses); @@ -49,6 +50,21 @@ public void testConnectionRecoveryWithMultipleAddresses() } + public void testConnectionRecoveryWithListOfAddresses() + throws IOException, InterruptedException, TimeoutException { + + final List
addresses = Arrays.asList(new Address("127.0.0.1"), new Address("127.0.0.1", 5672)); + + AutorecoveringConnection c = newRecoveringConnection(addresses); + try { + assertTrue(c.isOpen()); + closeAndWaitForRecovery(c); + assertTrue(c.isOpen()); + } finally { + c.abort(); + } + } + public void testConnectionRecoveryWithDisabledTopologyRecovery() throws IOException, InterruptedException, TimeoutException { AutorecoveringConnection c = newRecoveringConnection(true); @@ -705,17 +721,28 @@ private AutorecoveringConnection newRecoveringConnection(boolean disableTopology return (AutorecoveringConnection) cf.newConnection(); } + private AutorecoveringConnection newRecoveringConnection(boolean disableTopologyRecovery, Address[] addresses) + throws IOException, TimeoutException { + ConnectionFactory cf = buildConnectionFactoryWithRecoveryEnabled(disableTopologyRecovery); + return (AutorecoveringConnection) cf.newConnection(addresses); + } + private AutorecoveringConnection newRecoveringConnection(Address[] addresses) throws IOException, TimeoutException { - return newRecoveringConnection(false, addresses); + return newRecoveringConnection(false, Arrays.asList(addresses)); } - private AutorecoveringConnection newRecoveringConnection(boolean disableTopologyRecovery, Address[] addresses) + private AutorecoveringConnection newRecoveringConnection(boolean disableTopologyRecovery, List
addresses) throws IOException, TimeoutException { ConnectionFactory cf = buildConnectionFactoryWithRecoveryEnabled(disableTopologyRecovery); return (AutorecoveringConnection) cf.newConnection(addresses); } + private AutorecoveringConnection newRecoveringConnection(List
addresses) + throws IOException, TimeoutException { + return newRecoveringConnection(false, addresses); + } + private ConnectionFactory buildConnectionFactoryWithRecoveryEnabled(boolean disableTopologyRecovery) { ConnectionFactory cf = new ConnectionFactory(); cf.setNetworkRecoveryInterval(RECOVERY_INTERVAL); diff --git a/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java b/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java index d6f31fc5db..9a388a93ca 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java +++ b/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java @@ -17,26 +17,16 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.impl.ConnectionParams; +import com.rabbitmq.client.*; +import com.rabbitmq.client.impl.*; import com.rabbitmq.client.test.BrokerTestCase; import java.io.IOException; import java.net.Socket; +import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeoutException; -import com.rabbitmq.client.Address; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.ConnectionFactory; -import com.rabbitmq.client.GetResponse; -import com.rabbitmq.client.impl.AMQConnection; -import com.rabbitmq.client.impl.AMQCommand; -import com.rabbitmq.client.impl.Frame; -import com.rabbitmq.client.impl.FrameHandler; -import com.rabbitmq.client.impl.LongStringHelper; -import com.rabbitmq.client.impl.SocketFrameHandler; - public class FrameMax extends BrokerTestCase { /* This value for FrameMax is larger than the minimum and less * than what Rabbit suggests. */ @@ -147,7 +137,7 @@ public GenerousAMQConnection(ConnectionFactory factory, private static class GenerousConnectionFactory extends ConnectionFactory { - @Override public Connection newConnection(ExecutorService executor, Address[] addrs) + @Override public Connection newConnection(ExecutorService executor, List
addrs) throws IOException, TimeoutException { IOException lastException = null; for (Address addr : addrs) { From 0b6229e8a306e3d3891027913bd08681b314ad06 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 27 Jan 2016 00:56:14 +0300 Subject: [PATCH 0116/2114] Cosmetics --- .../com/rabbitmq/client/ConnectionFactory.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index e6f3588180..70010ba343 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -654,12 +654,12 @@ public Connection newConnection(Address[] addrs) throws IOException, TimeoutExce * is enabled, the connection returned by this method will be {@link Recoverable}. Future * reconnection attempts will pick a random accessible address from the provided list. * - * @param addr_list a List of known broker addresses (hostname/port pairs) to try in order + * @param addrs a List of known broker addresses (hostname/port pairs) to try in order * @return an interface to the connection * @throws IOException if it encounters a problem */ - public Connection newConnection(List
addr_list) throws IOException, TimeoutException { - return newConnection(this.sharedExecutor, addr_list); + public Connection newConnection(List
addrs) throws IOException, TimeoutException { + return newConnection(this.sharedExecutor, addrs); } /** @@ -689,12 +689,12 @@ public Connection newConnection(ExecutorService executor, Address[] addrs) throw * reconnection attempts will pick a random accessible address from the provided list. * * @param executor thread execution service for consumers on the connection - * @param addr_list a List of known broker addresses (hostname/port pairs) to try in order + * @param addrs a List of known broker addrs (hostname/port pairs) to try in order * @return an interface to the connection * @throws java.io.IOException if it encounters a problem * @see Automatic Recovery */ - public Connection newConnection(ExecutorService executor, List
addr_list) + public Connection newConnection(ExecutorService executor, List
addrs) throws IOException, TimeoutException { // make sure we respect the provided thread factory FrameHandlerFactory fhFactory = createFrameHandlerFactory(); @@ -702,13 +702,13 @@ public Connection newConnection(ExecutorService executor, List
addr_lis if (isAutomaticRecoveryEnabled()) { // see com.rabbitmq.client.impl.recovery.RecoveryAwareAMQConnectionFactory#newConnection - AutorecoveringConnection conn = new AutorecoveringConnection(params, fhFactory, addr_list); + AutorecoveringConnection conn = new AutorecoveringConnection(params, fhFactory, addrs); conn.init(); return conn; } else { IOException lastException = null; - for (Address addr : addr_list) { + for (Address addr : addrs) { try { FrameHandler handler = fhFactory.create(addr); AMQConnection conn = new AMQConnection(params, handler); From 5a2a5fda27568bcdc8445fb51d43f9ff33b2a960 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 27 Jan 2016 01:05:23 +0300 Subject: [PATCH 0117/2114] Cosmetics --- .../impl/recovery/AutorecoveringConnection.java | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index 9fc5dd0da0..32e875fce4 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -74,16 +74,9 @@ public class AutorecoveringConnection implements Connection, Recoverable, Networ // This lock guards the manuallyClosed flag and the delegate connection. Guarding these two ensures that a new connection can never // be created after application code has initiated shutdown. private final Object recoveryLock = new Object(); - - public AutorecoveringConnection(ConnectionParams params, FrameHandlerFactory f, Address[] addrs) { - this.cf = new RecoveryAwareAMQConnectionFactory(params, f, addrs); - this.params = params; - this.channels = new ConcurrentHashMap(); - } - - public AutorecoveringConnection(ConnectionParams params, FrameHandlerFactory f, List
addr_list) { - this.cf = new RecoveryAwareAMQConnectionFactory(params, f, addr_list); + public AutorecoveringConnection(ConnectionParams params, FrameHandlerFactory f, List
addrs) { + this.cf = new RecoveryAwareAMQConnectionFactory(params, f, addrs); this.params = params; this.channels = new ConcurrentHashMap(); From 5edfb82674e9a9d68e7872cdc1a810f7489939b8 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 27 Jan 2016 01:07:51 +0300 Subject: [PATCH 0118/2114] Cosmetics, remove unused code * The Address[] constructor is not used by user apps. --- .../RecoveryAwareAMQConnectionFactory.java | 74 +++++++++---------- 1 file changed, 34 insertions(+), 40 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java index 99fc17bf55..54bda056bb 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java @@ -7,52 +7,46 @@ import java.io.IOException; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.concurrent.TimeoutException; public class RecoveryAwareAMQConnectionFactory { - private final ConnectionParams params; - private final FrameHandlerFactory factory; - private final List
addrs; - - public RecoveryAwareAMQConnectionFactory(ConnectionParams params, FrameHandlerFactory factory, Address[] addrs) { - this.params = params; - this.factory = factory; - this.addrs = Arrays.asList(addrs); - } - - public RecoveryAwareAMQConnectionFactory(ConnectionParams params, FrameHandlerFactory factory, List
addrs){ - this.params = params; - this.factory = factory; - this.addrs = addrs; - } - /** - * @return an interface to the connection - * @throws java.io.IOException if it encounters a problem - */ - RecoveryAwareAMQConnection newConnection() throws IOException, TimeoutException { - IOException lastException = null; - List
shuffled = shuffle(addrs); - - for (Address addr : shuffled) { - try { - FrameHandler frameHandler = factory.create(addr); - RecoveryAwareAMQConnection conn = new RecoveryAwareAMQConnection(params, frameHandler); - conn.start(); - return conn; - } catch (IOException e) { - lastException = e; - } + private final ConnectionParams params; + private final FrameHandlerFactory factory; + private final List
addrs; + + public RecoveryAwareAMQConnectionFactory(ConnectionParams params, FrameHandlerFactory factory, List
addrs) { + this.params = params; + this.factory = factory; + this.addrs = addrs; } - throw (lastException != null) ? lastException : new IOException("failed to connect"); - } + /** + * @return an interface to the connection + * @throws java.io.IOException if it encounters a problem + */ + RecoveryAwareAMQConnection newConnection() throws IOException, TimeoutException { + IOException lastException = null; + List
shuffled = shuffle(addrs); + + for (Address addr : shuffled) { + try { + FrameHandler frameHandler = factory.create(addr); + RecoveryAwareAMQConnection conn = new RecoveryAwareAMQConnection(params, frameHandler); + conn.start(); + return conn; + } catch (IOException e) { + lastException = e; + } + } + + throw (lastException != null) ? lastException : new IOException("failed to connect"); + } - private List
shuffle(List
addrs) { - List
list = new ArrayList
(addrs); - Collections.shuffle(list); - return list; - } + private List
shuffle(List
addrs) { + List
list = new ArrayList
(addrs); + Collections.shuffle(list); + return list; + } } From a975c3ecaf71d744e610a8cb552fce160b67c19f Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 27 Jan 2016 01:08:22 +0300 Subject: [PATCH 0119/2114] Specifically invoke the Address[] version Otherwise we test a test helper method. --- .../client/test/functional/ConnectionRecovery.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java index 68dcb4f1a2..efb944a347 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -721,15 +721,11 @@ private AutorecoveringConnection newRecoveringConnection(boolean disableTopology return (AutorecoveringConnection) cf.newConnection(); } - private AutorecoveringConnection newRecoveringConnection(boolean disableTopologyRecovery, Address[] addresses) - throws IOException, TimeoutException { - ConnectionFactory cf = buildConnectionFactoryWithRecoveryEnabled(disableTopologyRecovery); - return (AutorecoveringConnection) cf.newConnection(addresses); - } - private AutorecoveringConnection newRecoveringConnection(Address[] addresses) throws IOException, TimeoutException { - return newRecoveringConnection(false, Arrays.asList(addresses)); + ConnectionFactory cf = buildConnectionFactoryWithRecoveryEnabled(false); + // specifically use the Address[] overload + return (AutorecoveringConnection) cf.newConnection(addresses); } private AutorecoveringConnection newRecoveringConnection(boolean disableTopologyRecovery, List
addresses) From 75695731f279a4312d692b274c27f44179ce702d Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 27 Jan 2016 01:37:45 +0300 Subject: [PATCH 0120/2114] Cosmetics --- src/main/java/com/rabbitmq/client/ConnectionFactory.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 70010ba343..191175180b 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -19,6 +19,7 @@ import java.io.IOException; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; +import java.util.Collections; import java.util.Map; import java.util.concurrent.*; import java.util.List; @@ -756,7 +757,7 @@ public ConnectionParams params(ExecutorService consumerWorkServiceExecutor) { * @throws IOException if it encounters a problem */ public Connection newConnection() throws IOException, TimeoutException { - return newConnection(this.sharedExecutor, Arrays.asList(new Address(getHost(), getPort()))); + return newConnection(this.sharedExecutor, Collections.singletonList(new Address(getHost(), getPort()))); } /** @@ -771,7 +772,7 @@ public Connection newConnection() throws IOException, TimeoutException { * @throws IOException if it encounters a problem */ public Connection newConnection(ExecutorService executor) throws IOException, TimeoutException { - return newConnection(executor, Arrays.asList(new Address(getHost(), getPort()))); + return newConnection(executor, Collections.singletonList(new Address(getHost(), getPort()))); } @Override public ConnectionFactory clone(){ From 5f935770289255cb5eafaec14e90f3544641ce81 Mon Sep 17 00:00:00 2001 From: nick Date: Tue, 2 Feb 2016 17:50:21 -0800 Subject: [PATCH 0121/2114] Remove existing bindings and replace with new ones when a new binding is created so they stay in sync with Channels --- .../client/impl/recovery/AutorecoveringConnection.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index 32e875fce4..b559625fb5 100644 --- a/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -638,9 +638,10 @@ synchronized void recordQueueBinding(AutorecoveringChannel ch, destination(queue). routingKey(routingKey). arguments(arguments); - if (!this.recordedBindings.contains(binding)) { - this.recordedBindings.add(binding); + if (this.recordedBindings.contains(binding)) { + this.recordedBindings.remove(binding); } + this.recordedBindings.add(binding); } synchronized boolean deleteRecordedQueueBinding(AutorecoveringChannel ch, @@ -666,6 +667,9 @@ synchronized void recordExchangeBinding(AutorecoveringChannel ch, destination(destination). routingKey(routingKey). arguments(arguments); + if (this.recordedBindings.contains(binding)) { + this.recordedBindings.remove(binding); + } this.recordedBindings.add(binding); } From 484414ebd425e06dca269f173e64b19d9b8890bc Mon Sep 17 00:00:00 2001 From: Karl Andersson Date: Sat, 6 Feb 2016 16:31:45 +0100 Subject: [PATCH 0122/2114] Added Closable-inteface to Connection-class for future try-with-resource support in JDK7 (automatic on compile with JDK7) --- src/main/java/com/rabbitmq/client/Connection.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/Connection.java b/src/main/java/com/rabbitmq/client/Connection.java index e733ce957a..203ae7d73d 100644 --- a/src/main/java/com/rabbitmq/client/Connection.java +++ b/src/main/java/com/rabbitmq/client/Connection.java @@ -16,6 +16,7 @@ package com.rabbitmq.client; +import java.io.Closeable; import java.io.IOException; import java.net.InetAddress; import java.util.Map; @@ -50,7 +51,7 @@ * Current implementations are thread-safe for code at the client API level, * and in fact thread-safe internally except for code within RPC calls. */ -public interface Connection extends ShutdownNotifier { // rename to AMQPConnection later, this is a temporary name +public interface Connection extends ShutdownNotifier, Closeable { // rename to AMQPConnection later, this is a temporary name /** * Retrieve the host. * @return the hostname of the peer we're connected to. From 53567ce631b593c50c6ccd47c708e0f0b9afb73b Mon Sep 17 00:00:00 2001 From: Zac Farrell Date: Fri, 19 Feb 2016 12:19:43 -0800 Subject: [PATCH 0123/2114] Enhance RpcClient: Provide access to msg metadata This provides a simple way to get at the other parameters from the Consumer's `handleDelivery` method (e.g. consumerTag, envelope, properties). It is backwards compatible, and only those using the new interface `responseCall` will have access to the additional data. --- .../java/com/rabbitmq/client/RpcClient.java | 70 +++++++++++++++++-- 1 file changed, 64 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/RpcClient.java b/src/main/java/com/rabbitmq/client/RpcClient.java index 379e36178c..230fec93b7 100644 --- a/src/main/java/com/rabbitmq/client/RpcClient.java +++ b/src/main/java/com/rabbitmq/client/RpcClient.java @@ -191,7 +191,7 @@ public void handleDelivery(String consumerTag, String replyId = properties.getCorrelationId(); BlockingCell blocker = _continuationMap.get(replyId); _continuationMap.remove(replyId); - blocker.set(body); + blocker.set(new Response(consumerTag, envelope, properties, body)); } } }; @@ -205,16 +205,15 @@ public void publish(AMQP.BasicProperties props, byte[] message) _channel.basicPublish(_exchange, _routingKey, props, message); } - public byte[] primitiveCall(AMQP.BasicProperties props, byte[] message) - throws IOException, ShutdownSignalException, TimeoutException - { + public Response doCall(AMQP.BasicProperties props, byte[] message) + throws IOException, ShutdownSignalException, TimeoutException { checkConsumer(); BlockingCell k = new BlockingCell(); synchronized (_continuationMap) { _correlationId++; String replyId = "" + _correlationId; props = ((props==null) ? new AMQP.BasicProperties.Builder() : props.builder()) - .correlationId(replyId).replyTo(_replyTo).build(); + .correlationId(replyId).replyTo(_replyTo).build(); _continuationMap.put(replyId, k); } publish(props, message); @@ -229,10 +228,16 @@ public byte[] primitiveCall(AMQP.BasicProperties props, byte[] message) wrapper.initCause(sig); throw wrapper; } else { - return (byte[]) reply; + return (Response) reply; } } + public byte[] primitiveCall(AMQP.BasicProperties props, byte[] message) + throws IOException, ShutdownSignalException, TimeoutException + { + return doCall(props, message).getBody(); + } + /** * Perform a simple byte-array-based RPC roundtrip. * @param message the byte array request message to send @@ -246,6 +251,21 @@ public byte[] primitiveCall(byte[] message) return primitiveCall(null, message); } + /** + * Perform a simple byte-array-based RPC roundtrip + * + * Useful if you need to get at more than just the body of the message + * + * @param message the byte array request message to send + * @return The response object is an envelope that contains all of the data provided to the `handleDelivery` consumer + * @throws ShutdownSignalException if the connection dies during our wait + * @throws IOException if an error is encountered + * @throws TimeoutException if a response is not received within the configured timeout + */ + public Response responseCall(byte[] message) throws IOException, ShutdownSignalException, TimeoutException { + return doCall(null, message); + } + /** * Perform a simple string-based RPC roundtrip. * @param message the string request message to send @@ -368,5 +388,43 @@ public int getCorrelationId() { public Consumer getConsumer() { return _consumer; } + + /** + * The response object is an envelope that contains all of the data provided to the `handleDelivery` consumer + */ + public static class Response { + protected String consumerTag; + protected Envelope envelope; + protected AMQP.BasicProperties properties; + protected byte[] body; + + public Response() { + } + + public Response( + final String consumerTag, final Envelope envelope, final AMQP.BasicProperties properties, + final byte[] body) { + this.consumerTag = consumerTag; + this.envelope = envelope; + this.properties = properties; + this.body = body; + } + + public String getConsumerTag() { + return consumerTag; + } + + public Envelope getEnvelope() { + return envelope; + } + + public AMQP.BasicProperties getProperties() { + return properties; + } + + public byte[] getBody() { + return body; + } + } } From 7bb9443fbea68758ebffeae1570bd8c712c9352a Mon Sep 17 00:00:00 2001 From: nick Date: Tue, 8 Mar 2016 16:21:23 -0800 Subject: [PATCH 0124/2114] PR 132: inform recovery listeners when recovery has started in case an app wants to log something / set a flag / fire an event when recovery has begun but before it has completed. --- .../java/com/rabbitmq/client/RecoveryListener.java | 1 + .../client/impl/recovery/AutorecoveringChannel.java | 11 +++++++++-- .../impl/recovery/AutorecoveringConnection.java | 13 +++++++++++-- .../client/test/functional/ConnectionRecovery.java | 8 ++++++++ 4 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/RecoveryListener.java b/src/main/java/com/rabbitmq/client/RecoveryListener.java index 88b0ece2e5..756075a55a 100644 --- a/src/main/java/com/rabbitmq/client/RecoveryListener.java +++ b/src/main/java/com/rabbitmq/client/RecoveryListener.java @@ -8,4 +8,5 @@ */ public interface RecoveryListener { public void handleRecovery(Recoverable recoverable); + public void handleRecoveryStarted(Recoverable recoverable); } diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java index a07c78f5f5..5faeefe604 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java @@ -489,12 +489,13 @@ public void automaticallyRecover(AutorecoveringConnection connection, Connection this.delegate = (RecoveryAwareChannelN) connDelegate.createChannel(this.getChannelNumber()); this.delegate.inheritOffsetFrom(defunctChannel); + this.notifyRecoveryListenersStarted(); this.recoverShutdownListeners(); this.recoverReturnListeners(); this.recoverConfirmListeners(); this.recoverFlowListeners(); this.recoverState(); - this.notifyRecoveryListeners(); + this.notifyRecoveryListenersComplete(); } private void recoverShutdownListeners() { @@ -538,12 +539,18 @@ private void recoverState() throws IOException { } } - private void notifyRecoveryListeners() { + private void notifyRecoveryListenersComplete() { for (RecoveryListener f : this.recoveryListeners) { f.handleRecovery(this); } } + private void notifyRecoveryListenersStarted() { + for (RecoveryListener f : this.recoveryListeners) { + f.handleRecoveryStarted(this); + } + } + private void recordQueueBinding(String queue, String exchange, String routingKey, Map arguments) { this.connection.recordQueueBinding(this, queue, exchange, routingKey, arguments); } diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index b559625fb5..aba249d5d4 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -441,6 +441,9 @@ public void removeConsumerRecoveryListener(ConsumerRecoveryListener listener) { synchronized private void beginAutomaticRecovery() throws InterruptedException, IOException, TopologyRecoveryException { Thread.sleep(this.params.getNetworkRecoveryInterval()); + + this.notifyRecoveryListenersStarted(); + if (!this.recoverConnection()) return; @@ -452,7 +455,7 @@ synchronized private void beginAutomaticRecovery() throws InterruptedException, this.recoverConsumers(); } - this.notifyRecoveryListeners(); + this.notifyRecoveryListenersComplete(); } private void recoverShutdownListeners() { @@ -506,12 +509,18 @@ private void recoverChannels() { } } - private void notifyRecoveryListeners() { + private void notifyRecoveryListenersComplete() { for (RecoveryListener f : this.recoveryListeners) { f.handleRecovery(this); } } + private void notifyRecoveryListenersStarted() { + for (RecoveryListener f : this.recoveryListeners) { + f.handleRecoveryStarted(this); + } + } + private void recoverEntities() throws TopologyRecoveryException { // The recovery sequence is the following: // diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java index efb944a347..546d7efc6f 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -550,10 +550,14 @@ public void testQueueRecoveryWithManyQueues() throws IOException, InterruptedExc public void testChannelRecoveryCallback() throws IOException, InterruptedException { final CountDownLatch latch = new CountDownLatch(2); + final CountDownLatch startLatch = new CountDownLatch(2); final RecoveryListener listener = new RecoveryListener() { public void handleRecovery(Recoverable recoverable) { latch.countDown(); } + public void handleRecoveryStarted(Recoverable recoverable) { + startLatch.countDown(); + } }; AutorecoveringChannel ch1 = (AutorecoveringChannel) connection.createChannel(); ch1.addRecoveryListener(listener); @@ -566,6 +570,7 @@ public void handleRecovery(Recoverable recoverable) { expectChannelRecovery(ch1); expectChannelRecovery(ch2); wait(latch); + wait(startLatch); } public void testBasicAckAfterChannelRecovery() throws IOException, InterruptedException, TimeoutException { @@ -670,6 +675,9 @@ private CountDownLatch prepareForRecovery(Connection conn) { public void handleRecovery(Recoverable recoverable) { latch.countDown(); } + public void handleRecoveryStarted(Recoverable recoverable) { + // No-op + } }); return latch; } From 9aa8f809bbd947873a7b52703b5157bcb0376eb8 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 16 Mar 2016 15:22:01 +0000 Subject: [PATCH 0125/2114] Explain the difference --- .../com/rabbitmq/client/test/server/BlockedConnection.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java b/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java index 3880e5ffb0..2099ed8d54 100644 --- a/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java @@ -37,6 +37,8 @@ protected void releaseResources() throws IOException { e.printStackTrace(); } } + // this test first opens a connection, then triggers + // and alarm and blocks public void testBlock() throws Exception { final CountDownLatch latch = new CountDownLatch(1); @@ -47,6 +49,8 @@ public void testBlock() throws Exception { assertTrue(latch.await(10, TimeUnit.SECONDS)); } + // this test first triggers an alarm, then opens a + // connection public void testInitialBlock() throws Exception { final CountDownLatch latch = new CountDownLatch(1); From 52c7b1c362d2f14db1fdf4d9df8ca26e690e2180 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 16 Mar 2016 15:22:01 +0000 Subject: [PATCH 0126/2114] Explain the difference --- .../com/rabbitmq/client/test/server/BlockedConnection.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/src/com/rabbitmq/client/test/server/BlockedConnection.java b/test/src/com/rabbitmq/client/test/server/BlockedConnection.java index 45f9652ceb..cb0caa2de3 100644 --- a/test/src/com/rabbitmq/client/test/server/BlockedConnection.java +++ b/test/src/com/rabbitmq/client/test/server/BlockedConnection.java @@ -38,6 +38,8 @@ protected void releaseResources() throws IOException { e.printStackTrace(); } } + // this test first opens a connection, then triggers + // and alarm and blocks public void testBlock() throws Exception { final CountDownLatch latch = new CountDownLatch(1); @@ -48,6 +50,8 @@ public void testBlock() throws Exception { assertTrue(latch.await(10, TimeUnit.SECONDS)); } + // this test first triggers an alarm, then opens a + // connection public void testInitialBlock() throws Exception { final CountDownLatch latch = new CountDownLatch(1); From 0b40139bd98e58ce3c30219a4147fafac908b7d5 Mon Sep 17 00:00:00 2001 From: Mike Playle Date: Mon, 4 Apr 2016 16:46:20 +0100 Subject: [PATCH 0127/2114] Set the nowait flag in queueBindNoWait() This prevents us from being confused by a reply we didn't expect. Also fix the associated javadoc comment. --- src/main/java/com/rabbitmq/client/Channel.java | 2 +- src/main/java/com/rabbitmq/client/impl/ChannelN.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/Channel.java b/src/main/java/com/rabbitmq/client/Channel.java index 36ba7d1d0c..f38b7a6ef0 100644 --- a/src/main/java/com/rabbitmq/client/Channel.java +++ b/src/main/java/com/rabbitmq/client/Channel.java @@ -616,7 +616,7 @@ void queueDeclareNoWait(String queue, boolean durable, boolean exclusive, boolea Queue.BindOk queueBind(String queue, String exchange, String routingKey, Map arguments) throws IOException; /** - * Same as {@link Channel#queueDeclare(String, boolean, boolean, boolean, java.util.Map)} but sets nowait + * Same as {@link Channel#queueBind(String, String, String, java.util.Map)} but sets nowait * parameter to true and returns void (as there will be no response * from the server). * @param queue the name of the queue diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java index 18d4802fa2..782a968229 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelN.java @@ -970,6 +970,7 @@ public void queueBindNoWait(String queue, .exchange(exchange) .routingKey(routingKey) .arguments(arguments) + .nowait(true) .build())); } From 20f1fb62940339d63fc2f117531ac1d99bcf8cbc Mon Sep 17 00:00:00 2001 From: Daniil Fedotov Date: Mon, 11 Apr 2016 17:21:45 +0100 Subject: [PATCH 0128/2114] Connection name parameter to create connections --- .../rabbitmq/client/ConnectionFactory.java | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/com/rabbitmq/client/ConnectionFactory.java b/src/com/rabbitmq/client/ConnectionFactory.java index 191175180b..1ea28a2e9b 100644 --- a/src/com/rabbitmq/client/ConnectionFactory.java +++ b/src/com/rabbitmq/client/ConnectionFactory.java @@ -644,7 +644,11 @@ protected FrameHandlerFactory createFrameHandlerFactory() throws IOException { * @throws IOException if it encounters a problem */ public Connection newConnection(Address[] addrs) throws IOException, TimeoutException { - return newConnection(this.sharedExecutor, Arrays.asList(addrs)); + return newConnection(this.sharedExecutor, Arrays.asList(addrs), null); + } + + public Connection newConnection(Address[] addrs, String connectionName) throws IOException, TimeoutException { + return newConnection(this.sharedExecutor, Arrays.asList(addrs), connectionName); } /** @@ -660,7 +664,11 @@ public Connection newConnection(Address[] addrs) throws IOException, TimeoutExce * @throws IOException if it encounters a problem */ public Connection newConnection(List
addrs) throws IOException, TimeoutException { - return newConnection(this.sharedExecutor, addrs); + return newConnection(this.sharedExecutor, addrs, null); + } + + public Connection newConnection(List
addrs, String connectionName) throws IOException, TimeoutException { + return newConnection(this.sharedExecutor, addrs, connectionName); } /** @@ -678,7 +686,11 @@ public Connection newConnection(List
addrs) throws IOException, Timeout * @see Automatic Recovery */ public Connection newConnection(ExecutorService executor, Address[] addrs) throws IOException, TimeoutException { - return newConnection(executor, Arrays.asList(addrs)); + return newConnection(executor, Arrays.asList(addrs), null); + } + + public Connection newConnection(ExecutorService executor, Address[] addrs, String connectionName) throws IOException, TimeoutException { + return newConnection(executor, Arrays.asList(addrs), connectionName); } /** @@ -695,11 +707,16 @@ public Connection newConnection(ExecutorService executor, Address[] addrs) throw * @throws java.io.IOException if it encounters a problem * @see Automatic Recovery */ - public Connection newConnection(ExecutorService executor, List
addrs) + public Connection newConnection(ExecutorService executor, List
addrs, String connectionName) throws IOException, TimeoutException { // make sure we respect the provided thread factory FrameHandlerFactory fhFactory = createFrameHandlerFactory(); ConnectionParams params = params(executor); + if (connectionName != null) { + Map properties = params.getClientProperties().clone(); + properties.put("connection_name", connectionName); + params.setClientProperties(properties); + } if (isAutomaticRecoveryEnabled()) { // see com.rabbitmq.client.impl.recovery.RecoveryAwareAMQConnectionFactory#newConnection From 5066bccc4d1fd6d8bc4d6779954055cc0f86ec5c Mon Sep 17 00:00:00 2001 From: Daniil Fedotov Date: Tue, 12 Apr 2016 12:50:10 +0100 Subject: [PATCH 0129/2114] Getter for connection name and docs --- src/com/rabbitmq/client/Connection.java | 7 ++ .../rabbitmq/client/ConnectionFactory.java | 66 ++++++++++++++++++- .../rabbitmq/client/impl/AMQConnection.java | 9 +++ .../recovery/AutorecoveringConnection.java | 7 ++ 4 files changed, 88 insertions(+), 1 deletion(-) diff --git a/src/com/rabbitmq/client/Connection.java b/src/com/rabbitmq/client/Connection.java index e733ce957a..95d6445f69 100644 --- a/src/com/rabbitmq/client/Connection.java +++ b/src/com/rabbitmq/client/Connection.java @@ -93,6 +93,13 @@ public interface Connection extends ShutdownNotifier { // rename to AMQPConnecti */ Map getClientProperties(); + /** + * Get connection name client property value + * + * @return string connection name from client properties, or null if there is not such property. + */ + String getConnectionName(); + /** * Retrieve the server properties. * @return a map of the server properties. This typically includes the product name and version of the server. diff --git a/src/com/rabbitmq/client/ConnectionFactory.java b/src/com/rabbitmq/client/ConnectionFactory.java index 1ea28a2e9b..9c005370f8 100644 --- a/src/com/rabbitmq/client/ConnectionFactory.java +++ b/src/com/rabbitmq/client/ConnectionFactory.java @@ -21,6 +21,7 @@ import java.security.NoSuchAlgorithmException; import java.util.Collections; import java.util.Map; +import java.util.HashMap; import java.util.concurrent.*; import java.util.List; import java.util.Arrays; @@ -647,6 +648,20 @@ public Connection newConnection(Address[] addrs) throws IOException, TimeoutExce return newConnection(this.sharedExecutor, Arrays.asList(addrs), null); } + + /** + * Create a new broker connection, picking the first available address from + * the list. + * + * If automatic connection recovery + * is enabled, the connection returned by this method will be {@link Recoverable}. Future + * reconnection attempts will pick a random accessible address from the provided list. + * + * @param addrs an array of known broker addresses (hostname/port pairs) to try in order + * @param connectionName arbitrary sring for connection name client property + * @return an interface to the connection + * @throws IOException if it encounters a problem + */ public Connection newConnection(Address[] addrs, String connectionName) throws IOException, TimeoutException { return newConnection(this.sharedExecutor, Arrays.asList(addrs), connectionName); } @@ -667,6 +682,19 @@ public Connection newConnection(List
addrs) throws IOException, Timeout return newConnection(this.sharedExecutor, addrs, null); } + /** + * Create a new broker connection, picking the first available address from + * the list. + * + * If automatic connection recovery + * is enabled, the connection returned by this method will be {@link Recoverable}. Future + * reconnection attempts will pick a random accessible address from the provided list. + * + * @param addrs a List of known broker addresses (hostname/port pairs) to try in order + * @param connectionName arbitrary sring for connection name client property + * @return an interface to the connection + * @throws IOException if it encounters a problem + */ public Connection newConnection(List
addrs, String connectionName) throws IOException, TimeoutException { return newConnection(this.sharedExecutor, addrs, connectionName); } @@ -689,6 +717,22 @@ public Connection newConnection(ExecutorService executor, Address[] addrs) throw return newConnection(executor, Arrays.asList(addrs), null); } + + /** + * Create a new broker connection, picking the first available address from + * the list. + * + * If automatic connection recovery + * is enabled, the connection returned by this method will be {@link Recoverable}. Future + * reconnection attempts will pick a random accessible address from the provided list. + * + * @param executor thread execution service for consumers on the connection + * @param addrs an array of known broker addresses (hostname/port pairs) to try in order + * @param connectionName arbitrary sring for connection name client property + * @return an interface to the connection + * @throws java.io.IOException if it encounters a problem + * @see Automatic Recovery + */ public Connection newConnection(ExecutorService executor, Address[] addrs, String connectionName) throws IOException, TimeoutException { return newConnection(executor, Arrays.asList(addrs), connectionName); } @@ -707,13 +751,33 @@ public Connection newConnection(ExecutorService executor, Address[] addrs, Strin * @throws java.io.IOException if it encounters a problem * @see Automatic Recovery */ + public Connection newConnection(ExecutorService executor, List
addrs) throws IOException, TimeoutException { + return newConnection(executor, addrs, null); + } + + /** + * Create a new broker connection, picking the first available address from + * the list. + * + * If automatic connection recovery + * is enabled, the connection returned by this method will be {@link Recoverable}. Future + * reconnection attempts will pick a random accessible address from the provided list. + * + * @param executor thread execution service for consumers on the connection + * @param addrs a List of known broker addrs (hostname/port pairs) to try in order + * @param connectionName arbitrary sring for connection name client property + * @return an interface to the connection + * @throws java.io.IOException if it encounters a problem + * @see Automatic Recovery + */ public Connection newConnection(ExecutorService executor, List
addrs, String connectionName) throws IOException, TimeoutException { // make sure we respect the provided thread factory FrameHandlerFactory fhFactory = createFrameHandlerFactory(); ConnectionParams params = params(executor); + // set connection name client property if (connectionName != null) { - Map properties = params.getClientProperties().clone(); + Map properties = new HashMap(params.getClientProperties()); properties.put("connection_name", connectionName); params.setClientProperties(properties); } diff --git a/src/com/rabbitmq/client/impl/AMQConnection.java b/src/com/rabbitmq/client/impl/AMQConnection.java index 54e17c0918..3634165950 100644 --- a/src/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/com/rabbitmq/client/impl/AMQConnection.java @@ -470,6 +470,15 @@ public Map getClientProperties() { return new HashMap(_clientProperties); } + public String getConnectionName() { + Object connectionName = _clientProperties.get("connection_name"); + if (connectionName == null){ + return null; + } else { + return connectionName.toString(); + } + } + /** * Protected API - retrieve the current ExceptionHandler */ diff --git a/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index b559625fb5..c7663d16b8 100644 --- a/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -156,6 +156,13 @@ public Map getClientProperties() { return delegate.getClientProperties(); } + /** + * @see com.rabbitmq.client.Connection#getConnectionName() + */ + public String getConnectionName() { + return delegate.getConnectionName(); + } + /** * @see com.rabbitmq.client.Connection#getFrameMax() */ From f04af95e29683320c53d423956d211fa70da62eb Mon Sep 17 00:00:00 2001 From: Daniil Fedotov Date: Wed, 13 Apr 2016 12:53:03 +0100 Subject: [PATCH 0130/2114] Named connection tests --- .../rabbitmq/client/ConnectionFactory.java | 31 +++++++++++++++++ .../client/test/AMQConnectionTest.java | 33 +++++++++++++++++++ .../test/functional/ConnectionRecovery.java | 26 +++++++++++++++ 3 files changed, 90 insertions(+) diff --git a/src/com/rabbitmq/client/ConnectionFactory.java b/src/com/rabbitmq/client/ConnectionFactory.java index 9c005370f8..3eb7645745 100644 --- a/src/com/rabbitmq/client/ConnectionFactory.java +++ b/src/com/rabbitmq/client/ConnectionFactory.java @@ -841,6 +841,21 @@ public Connection newConnection() throws IOException, TimeoutException { return newConnection(this.sharedExecutor, Collections.singletonList(new Address(getHost(), getPort()))); } + /** + * Create a new broker connection. + * + * If automatic connection recovery + * is enabled, the connection returned by this method will be {@link Recoverable}. Reconnection + * attempts will always use the address configured on {@link ConnectionFactory}. + * + * @param connectionName arbitrary sring for connection name client property + * @return an interface to the connection + * @throws IOException if it encounters a problem + */ + public Connection newConnection(String connectionName) throws IOException, TimeoutException { + return newConnection(this.sharedExecutor, Collections.singletonList(new Address(getHost(), getPort())), connectionName); + } + /** * Create a new broker connection. * @@ -856,6 +871,22 @@ public Connection newConnection(ExecutorService executor) throws IOException, Ti return newConnection(executor, Collections.singletonList(new Address(getHost(), getPort()))); } + /** + * Create a new broker connection. + * + * If automatic connection recovery + * is enabled, the connection returned by this method will be {@link Recoverable}. Reconnection + * attempts will always use the address configured on {@link ConnectionFactory}. + * + * @param executor thread execution service for consumers on the connection + * @param connectionName arbitrary sring for connection name client property + * @return an interface to the connection + * @throws IOException if it encounters a problem + */ + public Connection newConnection(ExecutorService executor, String connectionName) throws IOException, TimeoutException { + return newConnection(executor, Collections.singletonList(new Address(getHost(), getPort())), connectionName); + } + @Override public ConnectionFactory clone(){ try { return (ConnectionFactory)super.clone(); diff --git a/test/src/com/rabbitmq/client/test/AMQConnectionTest.java b/test/src/com/rabbitmq/client/test/AMQConnectionTest.java index 3aff2fbdd8..db650404cb 100644 --- a/test/src/com/rabbitmq/client/test/AMQConnectionTest.java +++ b/test/src/com/rabbitmq/client/test/AMQConnectionTest.java @@ -25,6 +25,9 @@ import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.TimeoutException; +import java.util.concurrent.ExecutorService; +import com.rabbitmq.client.Address; +import java.util.Arrays; import com.rabbitmq.client.impl.ConnectionParams; import com.rabbitmq.client.TopologyRecoveryException; @@ -174,6 +177,36 @@ public void testConnectionHangInNegotiation() { assertEquals("Wrong type of exception returned.", SocketTimeoutException.class, exceptionList.get(0).getClass()); } + public void testConnectionName() throws IOException, TimeoutException { + String connectionName = "custom name"; + Connection connection = factory.newConnection(connectionName); + assertEquals(connectionName, connection.getConnectionName()); + connection.close(); + + List
addresses_list = Arrays.asList(new Address("127.0.0.1"), new Address("127.0.0.1", 5672)); + connection = factory.newConnection(addresses_list, connectionName); + assertEquals(connectionName, connection.getConnectionName()); + connection.close(); + + Address[] addresses_arr = {new Address("127.0.0.1"), new Address("127.0.0.1", 5672)}; + connection = factory.newConnection(addresses_arr, connectionName); + assertEquals(connectionName, connection.getConnectionName()); + connection.close(); + + ExecutorService executor = Executors.newSingleThreadExecutor(); + connection = factory.newConnection(executor, connectionName); + assertEquals(connectionName, connection.getConnectionName()); + connection.close(); + + connection = factory.newConnection(executor, addresses_list, connectionName); + assertEquals(connectionName, connection.getConnectionName()); + connection.close(); + + connection = factory.newConnection(executor, addresses_arr, connectionName); + assertEquals(connectionName, connection.getConnectionName()); + connection.close(); + } + /** Mock frame handler to facilitate testing. */ private static class MockFrameHandler implements FrameHandler { /** How many times has sendHeader() been called? */ diff --git a/test/src/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/test/src/com/rabbitmq/client/test/functional/ConnectionRecovery.java index efb944a347..e80d5dbbbc 100644 --- a/test/src/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/test/src/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -30,6 +30,21 @@ public void testConnectionRecovery() throws IOException, InterruptedException { assertTrue(connection.isOpen()); } + public void testNamedConnectionRecovery() + throws IOException, InterruptedException, TimeoutException { + String connectionName = "custom name"; + AutorecoveringConnection c = newRecoveringConnection(connectionName); + try { + assertTrue(c.isOpen()); + assertEquals(connectionName, c.getConnectionName()); + closeAndWaitForRecovery(c); + assertTrue(c.isOpen()); + assertEquals(connectionName, c.getConnectionName()); + } finally { + c.abort(); + } + } + public void testConnectionRecoveryWithServerRestart() throws IOException, InterruptedException { assertTrue(connection.isOpen()); restartPrimaryAndWaitForRecovery(); @@ -739,6 +754,17 @@ private AutorecoveringConnection newRecoveringConnection(List
addresses return newRecoveringConnection(false, addresses); } + private AutorecoveringConnection newRecoveringConnection(boolean disableTopologyRecovery, String connectionName) + throws IOException, TimeoutException { + ConnectionFactory cf = buildConnectionFactoryWithRecoveryEnabled(disableTopologyRecovery); + return (AutorecoveringConnection) cf.newConnection(connectionName); + } + + private AutorecoveringConnection newRecoveringConnection(String connectionName) + throws IOException, TimeoutException { + return newRecoveringConnection(false, connectionName); + } + private ConnectionFactory buildConnectionFactoryWithRecoveryEnabled(boolean disableTopologyRecovery) { ConnectionFactory cf = new ConnectionFactory(); cf.setNetworkRecoveryInterval(RECOVERY_INTERVAL); From 593a6340f1045d395656ce27aec10fa863b821be Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 13 Apr 2016 17:16:35 +0300 Subject: [PATCH 0131/2114] Use a more reasonable timeout --- .../rabbitmq/client/test/functional/ConnectionRecovery.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java index efb944a347..84b1f521b0 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -750,9 +750,9 @@ private ConnectionFactory buildConnectionFactoryWithRecoveryEnabled(boolean disa } private static void wait(CountDownLatch latch) throws InterruptedException { - // Very very generous amount of time to wait, just make sure we never - // hang forever - assertTrue(latch.await(1800, TimeUnit.SECONDS)); + // we want to wait for recovery to complete for a reasonable amount of time + // but still make recovery failures easy to notice in development environments + assertTrue(latch.await(90, TimeUnit.SECONDS)); } private void waitForConfirms(Channel ch) throws InterruptedException, TimeoutException { From 066ce86e747b2ea6781bfc93515a41a4a8e6e076 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 13 Apr 2016 17:16:50 +0300 Subject: [PATCH 0132/2114] Introduce a way for AMQConnection to notify its recovery aware wrapper Fixes #135. --- .../rabbitmq/client/impl/AMQConnection.java | 30 +++++++++++++--- .../recovery/AutorecoveringConnection.java | 35 ++++++++++--------- .../recovery/RecoveryCanBeginListener.java | 12 +++++++ 3 files changed, 56 insertions(+), 21 deletions(-) create mode 100644 src/main/java/com/rabbitmq/client/impl/recovery/RecoveryCanBeginListener.java diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index 54e17c0918..d0f598e236 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -21,10 +21,7 @@ import java.net.InetAddress; import java.net.SocketException; import java.net.SocketTimeoutException; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; +import java.util.*; import java.util.concurrent.*; import com.rabbitmq.client.AMQP; @@ -45,6 +42,7 @@ import com.rabbitmq.client.SaslMechanism; import com.rabbitmq.client.ShutdownSignalException; import com.rabbitmq.client.impl.AMQChannel.BlockingRpcContinuation; +import com.rabbitmq.client.impl.recovery.RecoveryCanBeginListener; import com.rabbitmq.utility.BlockingCell; final class Copyright { @@ -65,6 +63,9 @@ public class AMQConnection extends ShutdownNotifierComponent implements Connecti private Thread mainLoopThread; private ThreadFactory threadFactory = Executors.defaultThreadFactory(); + private final List recoveryCanBeginListeners = + new ArrayList(); + /** * Retrieve a copy of the default table of client properties that * will be sent to the server during connection startup. This @@ -576,10 +577,31 @@ public void run() { _frameHandler.close(); _appContinuation.set(null); notifyListeners(); + // assuming that shutdown listeners do not do anything + // asynchronously, e.g. start new threads, this effectively + // guarantees that we only begin recovery when all shutdown + // listeners have executed + notifyRecoveryCanBeginListeners(); } } } + private void notifyRecoveryCanBeginListeners() { + ShutdownSignalException sse = this.getCloseReason(); + for(RecoveryCanBeginListener fn : this.recoveryCanBeginListeners) { + fn.recoveryCanBegin(sse); + } + } + + public void addRecoveryCanBeginListener(RecoveryCanBeginListener fn) { + this.recoveryCanBeginListeners.add(fn); + } + + @SuppressWarnings(value = "unused") + public void removeRecoveryCanBeginListener(RecoveryCanBeginListener fn) { + this.recoveryCanBeginListeners.remove(fn); + } + /** * Called when a frame-read operation times out * @throws MissedHeartbeatException if heart-beats have been missed diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index b559625fb5..24ecf9d522 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -376,8 +376,10 @@ public int getLocalPort() { private void addAutomaticRecoveryListener() { final AutorecoveringConnection c = this; - ShutdownListener automaticRecoveryListener = new ShutdownListener() { - public void shutdownCompleted(ShutdownSignalException cause) { + // this listener will run after shutdown listeners, + // see https://github.com/rabbitmq/rabbitmq-java-client/issues/135 + RecoveryCanBeginListener starter = new RecoveryCanBeginListener() { + public void recoveryCanBegin(ShutdownSignalException cause) { try { if (shouldTriggerConnectionRecovery(cause)) { c.beginAutomaticRecovery(); @@ -388,10 +390,7 @@ public void shutdownCompleted(ShutdownSignalException cause) { } }; synchronized (this) { - if(!this.shutdownHooks.contains(automaticRecoveryListener)) { - this.shutdownHooks.add(automaticRecoveryListener); - } - this.delegate.addShutdownListener(automaticRecoveryListener); + this.delegate.addRecoveryCanBeginListener(starter); } } @@ -441,18 +440,20 @@ public void removeConsumerRecoveryListener(ConsumerRecoveryListener listener) { synchronized private void beginAutomaticRecovery() throws InterruptedException, IOException, TopologyRecoveryException { Thread.sleep(this.params.getNetworkRecoveryInterval()); - if (!this.recoverConnection()) - return; - - this.recoverShutdownListeners(); - this.recoverBlockedListeners(); - this.recoverChannels(); - if(this.params.isTopologyRecoveryEnabled()) { - this.recoverEntities(); - this.recoverConsumers(); - } + if (!this.recoverConnection()) { + return; + } - this.notifyRecoveryListeners(); + this.addAutomaticRecoveryListener(); + this.recoverShutdownListeners(); + this.recoverBlockedListeners(); + this.recoverChannels(); + if(this.params.isTopologyRecoveryEnabled()) { + this.recoverEntities(); + this.recoverConsumers(); + } + + this.notifyRecoveryListeners(); } private void recoverShutdownListeners() { diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryCanBeginListener.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryCanBeginListener.java new file mode 100644 index 0000000000..6326f3d288 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryCanBeginListener.java @@ -0,0 +1,12 @@ +package com.rabbitmq.client.impl.recovery; + +import com.rabbitmq.client.ShutdownSignalException; + +/** + * Used internally to indicate when connection recovery can + * begin. See {@link https://github.com/rabbitmq/rabbitmq-java-client/issues/135}. + * This is package-local by design. + */ +public interface RecoveryCanBeginListener { + void recoveryCanBegin(ShutdownSignalException cause); +} From 62898ad354c9a250394c8668b7d46331a4fae332 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 13 Apr 2016 17:22:03 +0300 Subject: [PATCH 0133/2114] Squash a few warnings from IDEA --- .../client/test/functional/ConnectionRecovery.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java index 84b1f521b0..4354d63c82 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -21,8 +21,9 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; +@SuppressWarnings("ThrowFromFinallyBlock") public class ConnectionRecovery extends BrokerTestCase { - public static final long RECOVERY_INTERVAL = 2000; + private static final long RECOVERY_INTERVAL = 2000; public void testConnectionRecovery() throws IOException, InterruptedException { assertTrue(connection.isOpen()); @@ -211,7 +212,7 @@ public void testClientNamedQueueRecoveryWithNoWait() throws IOException, Interru testClientNamedQueueRecoveryWith("java-client.test.recovery.q1-nowait", true); } - protected void testClientNamedQueueRecoveryWith(String q, boolean noWait) throws IOException, InterruptedException, TimeoutException { + private void testClientNamedQueueRecoveryWith(String q, boolean noWait) throws IOException, InterruptedException, TimeoutException { Channel ch = connection.createChannel(); if(noWait) { declareClientNamedQueueNoWait(ch, q); @@ -759,11 +760,11 @@ private void waitForConfirms(Channel ch) throws InterruptedException, TimeoutExc ch.waitForConfirms(30 * 60 * 1000); } - protected void assertRecordedQueues(Connection conn, int size) { + private void assertRecordedQueues(Connection conn, int size) { assertEquals(size, ((AutorecoveringConnection)conn).getRecordedQueues().size()); } - protected void assertRecordedExchanges(Connection conn, int size) { + private void assertRecordedExchanges(Connection conn, int size) { assertEquals(size, ((AutorecoveringConnection)conn).getRecordedExchanges().size()); } } From bb252ff2a5ef66464c6b04e18cacf423f5ffb5cb Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 13 Apr 2016 18:03:28 +0300 Subject: [PATCH 0134/2114] Test that recovery starts after all connection shutdown hooks have executed Note: we cannot guarantee that they'd have *finished* by the time recovery starts. Provided that ShutdownListeners are typically basic sequential functions, that'll be the case most of the time. Fixes #135 --- .../recovery/AutorecoveringConnection.java | 8 ++++ .../test/functional/ConnectionRecovery.java | 44 +++++++++++++++++-- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index 24ecf9d522..49b65cc28a 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -11,6 +11,7 @@ import com.rabbitmq.client.ShutdownListener; import com.rabbitmq.client.ShutdownSignalException; import com.rabbitmq.client.TopologyRecoveryException; +import com.rabbitmq.client.impl.AMQConnection; import com.rabbitmq.client.impl.ConnectionParams; import com.rabbitmq.client.ExceptionHandler; import com.rabbitmq.client.impl.FrameHandlerFactory; @@ -254,6 +255,13 @@ public void abort(int timeout) { delegate.abort(timeout); } + /** + * Not supposed to be used outside of automated tests. + */ + public AMQConnection getDelegate() { + return delegate; + } + /** * @see com.rabbitmq.client.Connection#getCloseReason() */ diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java index 4354d63c82..bcd3df2b8d 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -1,12 +1,10 @@ package com.rabbitmq.client.test.functional; import com.rabbitmq.client.*; -import com.rabbitmq.client.impl.recovery.AutorecoveringChannel; -import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; +import com.rabbitmq.client.impl.AMQConnection; +import com.rabbitmq.client.impl.recovery.*; import com.rabbitmq.client.Recoverable; import com.rabbitmq.client.RecoveryListener; -import com.rabbitmq.client.impl.recovery.ConsumerRecoveryListener; -import com.rabbitmq.client.impl.recovery.QueueRecoveryListener; import com.rabbitmq.client.test.BrokerTestCase; import com.rabbitmq.tools.Host; @@ -90,6 +88,44 @@ public void testConnectionRecoveryWithDisabledTopologyRecovery() } } + // see https://github.com/rabbitmq/rabbitmq-java-client/issues/135 + public void testThatShutdownHooksOnConnectionFireBeforeRecoveryStarts() throws IOException, InterruptedException { + final List events = new ArrayList(); + final CountDownLatch latch = new CountDownLatch(1); + connection.addShutdownListener(new ShutdownListener() { + public void shutdownCompleted(ShutdownSignalException cause) { + events.add("shutdown hook 1"); + } + }); + connection.addShutdownListener(new ShutdownListener() { + public void shutdownCompleted(ShutdownSignalException cause) { + events.add("shutdown hook 2"); + } + }); + // note: we do not want to expose RecoveryCanBeginListener so this + // test does not use it + ((AutorecoveringConnection)connection).getDelegate().addRecoveryCanBeginListener(new RecoveryCanBeginListener() { + @Override + public void recoveryCanBegin(ShutdownSignalException cause) { + events.add("recovery start hook 1"); + } + }); + ((AutorecoveringConnection)connection).addRecoveryListener(new RecoveryListener() { + @Override + public void handleRecovery(Recoverable recoverable) { + latch.countDown(); + } + }); + assertTrue(connection.isOpen()); + closeAndWaitForRecovery(); + assertTrue(connection.isOpen()); + assertEquals("shutdown hook 1", events.get(0)); + assertEquals("shutdown hook 2", events.get(1)); + assertEquals("recovery start hook 1", events.get(2)); + connection.close(); + wait(latch); + } + public void testShutdownHooksRecoveryOnConnection() throws IOException, InterruptedException { final CountDownLatch latch = new CountDownLatch(2); connection.addShutdownListener(new ShutdownListener() { From 6f016cb80156ac165af72b3f2cdcb46430357cb7 Mon Sep 17 00:00:00 2001 From: nick Date: Tue, 8 Mar 2016 16:21:23 -0800 Subject: [PATCH 0135/2114] PR 132: inform recovery listeners when recovery has started in case an app wants to log something / set a flag / fire an event when recovery has begun but before it has completed. --- .../java/com/rabbitmq/client/RecoveryListener.java | 1 + .../client/impl/recovery/AutorecoveringChannel.java | 11 +++++++++-- .../impl/recovery/AutorecoveringConnection.java | 13 +++++++++++-- .../client/test/functional/ConnectionRecovery.java | 8 ++++++++ 4 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/RecoveryListener.java b/src/main/java/com/rabbitmq/client/RecoveryListener.java index 88b0ece2e5..756075a55a 100644 --- a/src/main/java/com/rabbitmq/client/RecoveryListener.java +++ b/src/main/java/com/rabbitmq/client/RecoveryListener.java @@ -8,4 +8,5 @@ */ public interface RecoveryListener { public void handleRecovery(Recoverable recoverable); + public void handleRecoveryStarted(Recoverable recoverable); } diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java index a07c78f5f5..5faeefe604 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java @@ -489,12 +489,13 @@ public void automaticallyRecover(AutorecoveringConnection connection, Connection this.delegate = (RecoveryAwareChannelN) connDelegate.createChannel(this.getChannelNumber()); this.delegate.inheritOffsetFrom(defunctChannel); + this.notifyRecoveryListenersStarted(); this.recoverShutdownListeners(); this.recoverReturnListeners(); this.recoverConfirmListeners(); this.recoverFlowListeners(); this.recoverState(); - this.notifyRecoveryListeners(); + this.notifyRecoveryListenersComplete(); } private void recoverShutdownListeners() { @@ -538,12 +539,18 @@ private void recoverState() throws IOException { } } - private void notifyRecoveryListeners() { + private void notifyRecoveryListenersComplete() { for (RecoveryListener f : this.recoveryListeners) { f.handleRecovery(this); } } + private void notifyRecoveryListenersStarted() { + for (RecoveryListener f : this.recoveryListeners) { + f.handleRecoveryStarted(this); + } + } + private void recordQueueBinding(String queue, String exchange, String routingKey, Map arguments) { this.connection.recordQueueBinding(this, queue, exchange, routingKey, arguments); } diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index 49b65cc28a..ef2bc60680 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -448,6 +448,9 @@ public void removeConsumerRecoveryListener(ConsumerRecoveryListener listener) { synchronized private void beginAutomaticRecovery() throws InterruptedException, IOException, TopologyRecoveryException { Thread.sleep(this.params.getNetworkRecoveryInterval()); + + this.notifyRecoveryListenersStarted(); + if (!this.recoverConnection()) { return; } @@ -461,7 +464,7 @@ synchronized private void beginAutomaticRecovery() throws InterruptedException, this.recoverConsumers(); } - this.notifyRecoveryListeners(); + this.notifyRecoveryListeners(); } private void recoverShutdownListeners() { @@ -515,12 +518,18 @@ private void recoverChannels() { } } - private void notifyRecoveryListeners() { + private void notifyRecoveryListenersComplete() { for (RecoveryListener f : this.recoveryListeners) { f.handleRecovery(this); } } + private void notifyRecoveryListenersStarted() { + for (RecoveryListener f : this.recoveryListeners) { + f.handleRecoveryStarted(this); + } + } + private void recoverEntities() throws TopologyRecoveryException { // The recovery sequence is the following: // diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java index bcd3df2b8d..be85d6b194 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -587,10 +587,14 @@ public void testQueueRecoveryWithManyQueues() throws IOException, InterruptedExc public void testChannelRecoveryCallback() throws IOException, InterruptedException { final CountDownLatch latch = new CountDownLatch(2); + final CountDownLatch startLatch = new CountDownLatch(2); final RecoveryListener listener = new RecoveryListener() { public void handleRecovery(Recoverable recoverable) { latch.countDown(); } + public void handleRecoveryStarted(Recoverable recoverable) { + startLatch.countDown(); + } }; AutorecoveringChannel ch1 = (AutorecoveringChannel) connection.createChannel(); ch1.addRecoveryListener(listener); @@ -603,6 +607,7 @@ public void handleRecovery(Recoverable recoverable) { expectChannelRecovery(ch1); expectChannelRecovery(ch2); wait(latch); + wait(startLatch); } public void testBasicAckAfterChannelRecovery() throws IOException, InterruptedException, TimeoutException { @@ -707,6 +712,9 @@ private CountDownLatch prepareForRecovery(Connection conn) { public void handleRecovery(Recoverable recoverable) { latch.countDown(); } + public void handleRecoveryStarted(Recoverable recoverable) { + // No-op + } }); return latch; } From 7a40fa57b3609fd6e3f8cc879c1ec85d6900031a Mon Sep 17 00:00:00 2001 From: nick Date: Thu, 14 Apr 2016 12:28:35 -0700 Subject: [PATCH 0136/2114] interface impl fix --- .../rabbitmq/client/test/functional/ConnectionRecovery.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java index be85d6b194..2d0860416b 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -115,6 +115,10 @@ public void recoveryCanBegin(ShutdownSignalException cause) { public void handleRecovery(Recoverable recoverable) { latch.countDown(); } + @Override + public void handleRecoveryStarted(Recoverable recoverable) { + // todo + } }); assertTrue(connection.isOpen()); closeAndWaitForRecovery(); From e5e5ccb8c50e01e43fb47e7096e0c9485b8d145c Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 15 Apr 2016 21:01:25 +0300 Subject: [PATCH 0137/2114] Bump default TLS version to v1.2 with a fallback for older JDKs Namely JDK 6. --- .../rabbitmq/client/ConnectionFactory.java | 18 ++++++++++-- .../ConnectionFactoryDefaultTlsVersion.java | 29 +++++++++++++++++++ .../rabbitmq/client/test/ssl/SSLTests.java | 3 +- 3 files changed, 46 insertions(+), 4 deletions(-) create mode 100644 src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 191175180b..f32738af54 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -81,8 +81,9 @@ public class ConnectionFactory implements Cloneable { * zero means wait indefinitely */ public static final int DEFAULT_SHUTDOWN_TIMEOUT = 10000; - /** The default SSL protocol */ - private static final String DEFAULT_SSL_PROTOCOL = "TLSv1"; + private static final String PREFERED_TLS_PROTOCOL = "TLSv1.2"; + + private static final String FALLBACK_TLS_PROTOCOL = "TLSv1"; private String username = DEFAULT_USER; private String password = DEFAULT_PASS; @@ -552,7 +553,7 @@ public boolean isSSL(){ public void useSslProtocol() throws NoSuchAlgorithmException, KeyManagementException { - useSslProtocol(DEFAULT_SSL_PROTOCOL); + useSslProtocol(computeDefaultTlsProcotol(SSLContext.getDefault().getSupportedSSLParameters().getProtocols())); } /** @@ -589,6 +590,17 @@ public void useSslProtocol(SSLContext context) { setSocketFactory(context.getSocketFactory()); } + public String computeDefaultTlsProcotol(String [] supportedProtocols) { + if(supportedProtocols != null) { + for (String supportedProtocol : supportedProtocols) { + if(PREFERED_TLS_PROTOCOL.equalsIgnoreCase(supportedProtocol)) { + return supportedProtocol; + } + } + } + return FALLBACK_TLS_PROTOCOL; + } + /** * Returns true if automatic connection recovery * is enabled, false otherwise diff --git a/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java b/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java new file mode 100644 index 0000000000..28247fcdf5 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java @@ -0,0 +1,29 @@ +package com.rabbitmq.client.test.ssl; + +import com.rabbitmq.client.ConnectionFactory; +import junit.framework.TestCase; +import org.junit.Assert; + +public class ConnectionFactoryDefaultTlsVersion extends TestCase { + + private ConnectionFactory connectionFactory = new ConnectionFactory(); + + public void testDefaultTlsVersionJdk16ShouldTakeFallback() { + String [] supportedProtocols = {"SSLv2Hello", "SSLv3", "TLSv1"}; + String tlsProtocol = connectionFactory.computeDefaultTlsProcotol(supportedProtocols); + Assert.assertEquals("TLSv1",tlsProtocol); + } + + public void testDefaultTlsVersionJdk17ShouldTakePrefered() { + String [] supportedProtocols = {"SSLv2Hello", "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2"}; + String tlsProtocol = connectionFactory.computeDefaultTlsProcotol(supportedProtocols); + Assert.assertEquals("TLSv1.2",tlsProtocol); + } + + public void testDefaultTlsVersionJdk18ShouldTakePrefered() { + String [] supportedProtocols = {"SSLv2Hello", "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2"}; + String tlsProtocol = connectionFactory.computeDefaultTlsProcotol(supportedProtocols); + Assert.assertEquals("TLSv1.2",tlsProtocol); + } + +} diff --git a/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java index b3b660dd95..ddc0797bd8 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java @@ -24,7 +24,8 @@ public class SSLTests extends AbstractRMQTestSuite { public static TestSuite suite() { TestSuite suite = new TestSuite("ssl"); - //Skip the tests if not under umbrella and not SSL available + suite.addTestSuite(ConnectionFactoryDefaultTlsVersion.class); + // Skip the tests if not under umbrella and no TLS setup available if (!requiredProperties()) return suite; if (!(isUnderUmbrella() && isSSLAvailable())) return suite; suite.addTestSuite(UnverifiedConnection.class); From bd70ec9784b1bb9bbdae7ff0b2c4136def9653fe Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 15 Apr 2016 21:12:57 +0300 Subject: [PATCH 0138/2114] This method is a pure function => make it static --- src/main/java/com/rabbitmq/client/ConnectionFactory.java | 2 +- .../client/test/ssl/ConnectionFactoryDefaultTlsVersion.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index f32738af54..623f18f6a1 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -590,7 +590,7 @@ public void useSslProtocol(SSLContext context) { setSocketFactory(context.getSocketFactory()); } - public String computeDefaultTlsProcotol(String [] supportedProtocols) { + public static String computeDefaultTlsProcotol(String[] supportedProtocols) { if(supportedProtocols != null) { for (String supportedProtocol : supportedProtocols) { if(PREFERED_TLS_PROTOCOL.equalsIgnoreCase(supportedProtocol)) { diff --git a/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java b/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java index 28247fcdf5..098ff2e187 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java @@ -10,19 +10,19 @@ public class ConnectionFactoryDefaultTlsVersion extends TestCase { public void testDefaultTlsVersionJdk16ShouldTakeFallback() { String [] supportedProtocols = {"SSLv2Hello", "SSLv3", "TLSv1"}; - String tlsProtocol = connectionFactory.computeDefaultTlsProcotol(supportedProtocols); + String tlsProtocol = ConnectionFactory.computeDefaultTlsProcotol(supportedProtocols); Assert.assertEquals("TLSv1",tlsProtocol); } public void testDefaultTlsVersionJdk17ShouldTakePrefered() { String [] supportedProtocols = {"SSLv2Hello", "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2"}; - String tlsProtocol = connectionFactory.computeDefaultTlsProcotol(supportedProtocols); + String tlsProtocol = ConnectionFactory.computeDefaultTlsProcotol(supportedProtocols); Assert.assertEquals("TLSv1.2",tlsProtocol); } public void testDefaultTlsVersionJdk18ShouldTakePrefered() { String [] supportedProtocols = {"SSLv2Hello", "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2"}; - String tlsProtocol = connectionFactory.computeDefaultTlsProcotol(supportedProtocols); + String tlsProtocol = ConnectionFactory.computeDefaultTlsProcotol(supportedProtocols); Assert.assertEquals("TLSv1.2",tlsProtocol); } From a3ee0f4517c6f06582901ee316642c09e9d4c04c Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 15 Apr 2016 23:40:22 +0300 Subject: [PATCH 0139/2114] More test cases for queue.declare --- .../test/functional/QueueLifecycle.java | 31 ++++++++++++++++--- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java b/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java index 735f752ede..ee1ed30a7c 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java @@ -17,16 +17,15 @@ package com.rabbitmq.client.test.functional; +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.QueueingConsumer; +import com.rabbitmq.client.test.BrokerTestCase; + import java.io.IOException; -import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeoutException; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.QueueingConsumer; -import com.rabbitmq.client.test.BrokerTestCase; - /** * Test queue auto-delete and exclusive semantics. */ @@ -177,4 +176,26 @@ public void testQueueNamesLongerThan255Characters() throws IOException { // expected } } + + public void testSingleLineFeedStrippedFromQueueName() throws IOException { + channel.queueDeclare("que\nue_test", false, false, true, null); + verifyQueue(NAME_STRIPPED, false, false, true, null); + } + + public void testMultipleLineFeedsStrippedFromQueueName() throws IOException { + channel.queueDeclare("que\nue_\ntest\n", false, false, true, null); + verifyQueue(NAME_STRIPPED, false, false, true, null); + } + + public void testMultipleLineFeedAndCarriageReturnsStrippedFromQueueName() throws IOException { + channel.queueDeclare("q\ru\ne\r\nue_\ntest\n\r", false, false, true, null); + verifyQueue(NAME_STRIPPED, false, false, true, null); + } + + static final String NAME_STRIPPED = "queue_test"; + + @Override + protected void releaseResources() throws IOException { + channel.queueDelete(NAME_STRIPPED); + } } From d0a885e77e4c1e5c439a6364a2b6443d40d99d90 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Sat, 16 Apr 2016 00:01:20 +0300 Subject: [PATCH 0140/2114] Cover exchange.declare --- .../client/test/functional/ExchangeDeclare.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java index a0039294bb..1a755911a2 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java @@ -36,6 +36,21 @@ public void testExchangeNoArgsEquivalence() throws IOException { verifyEquivalent(NAME, TYPE, false, false, null); } + public void testSingleLineFeedStrippedFromExchangeName() throws IOException { + channel.exchangeDeclare("exchange_test\n", TYPE, false, false, null); + verifyEquivalent(NAME, TYPE, false, false, null); + } + + public void testMultipleLineFeedsStrippedFromExchangeName() throws IOException { + channel.exchangeDeclare("exchange\n_test\n", TYPE, false, false, null); + verifyEquivalent(NAME, TYPE, false, false, null); + } + + public void testMultipleLineFeedAndCarriageReturnsStrippedFromExchangeName() throws IOException { + channel.exchangeDeclare("e\nxc\rhange\n\r_test\n\r", TYPE, false, false, null); + verifyEquivalent(NAME, TYPE, false, false, null); + } + public void testExchangeNonsenseArgsEquivalent() throws IOException { channel.exchangeDeclare(NAME, TYPE, false, false, null); Map args = new HashMap(); From 1835085a6af90728c0627a9f8722195c6a5302fe Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Mon, 18 Apr 2016 01:11:16 +0300 Subject: [PATCH 0141/2114] Naming, docs, cosmetics --- src/com/rabbitmq/client/Connection.java | 13 +++-- .../rabbitmq/client/ConnectionFactory.java | 52 ++++++++++++------- .../rabbitmq/client/impl/AMQConnection.java | 9 +--- .../recovery/AutorecoveringConnection.java | 10 ++-- .../client/test/AMQConnectionTest.java | 34 ++++++------ .../test/functional/ConnectionRecovery.java | 4 +- 6 files changed, 72 insertions(+), 50 deletions(-) diff --git a/src/com/rabbitmq/client/Connection.java b/src/com/rabbitmq/client/Connection.java index 95d6445f69..27d21d1f6a 100644 --- a/src/com/rabbitmq/client/Connection.java +++ b/src/com/rabbitmq/client/Connection.java @@ -19,6 +19,7 @@ import java.io.IOException; import java.net.InetAddress; import java.util.Map; +import java.util.concurrent.ExecutorService; /** * Public API: Interface to an AMQ connection. See the see the spec for details. @@ -94,11 +95,17 @@ public interface Connection extends ShutdownNotifier { // rename to AMQPConnecti Map getClientProperties(); /** - * Get connection name client property value + * Returns client-provided connection name, if any. Note that the value + * returned does not uniquely identify a connection and cannot be used + * as a connection identifier in HTTP API requests. * - * @return string connection name from client properties, or null if there is not such property. + * + * + * @return client-provided connection name, if any + * @see ConnectionFactory#newConnection(Address[], String) + * @see ConnectionFactory#newConnection(ExecutorService, Address[], String) */ - String getConnectionName(); + String getClientProvidedName(); /** * Retrieve the server properties. diff --git a/src/com/rabbitmq/client/ConnectionFactory.java b/src/com/rabbitmq/client/ConnectionFactory.java index 3eb7645745..599de713c0 100644 --- a/src/com/rabbitmq/client/ConnectionFactory.java +++ b/src/com/rabbitmq/client/ConnectionFactory.java @@ -650,7 +650,7 @@ public Connection newConnection(Address[] addrs) throws IOException, TimeoutExce /** - * Create a new broker connection, picking the first available address from + * Create a new broker connection with a client-provided name, picking the first available address from * the list. * * If automatic connection recovery @@ -658,12 +658,16 @@ public Connection newConnection(Address[] addrs) throws IOException, TimeoutExce * reconnection attempts will pick a random accessible address from the provided list. * * @param addrs an array of known broker addresses (hostname/port pairs) to try in order - * @param connectionName arbitrary sring for connection name client property + * @param clientProvidedName application-specific connection name, will be displayed + * in the management UI if RabbitMQ server supports it. + * This value doesn't have to be unique and cannot be used + * as a connection identifier e.g. in HTTP API requests. + * This value is supposed to be human-readable. * @return an interface to the connection * @throws IOException if it encounters a problem */ - public Connection newConnection(Address[] addrs, String connectionName) throws IOException, TimeoutException { - return newConnection(this.sharedExecutor, Arrays.asList(addrs), connectionName); + public Connection newConnection(Address[] addrs, String clientProvidedName) throws IOException, TimeoutException { + return newConnection(this.sharedExecutor, Arrays.asList(addrs), clientProvidedName); } /** @@ -683,7 +687,7 @@ public Connection newConnection(List
addrs) throws IOException, Timeout } /** - * Create a new broker connection, picking the first available address from + * Create a new broker connection with a client-provided name, picking the first available address from * the list. * * If automatic connection recovery @@ -691,12 +695,16 @@ public Connection newConnection(List
addrs) throws IOException, Timeout * reconnection attempts will pick a random accessible address from the provided list. * * @param addrs a List of known broker addresses (hostname/port pairs) to try in order - * @param connectionName arbitrary sring for connection name client property + * @param clientProvidedName application-specific connection name, will be displayed + * in the management UI if RabbitMQ server supports it. + * This value doesn't have to be unique and cannot be used + * as a connection identifier e.g. in HTTP API requests. + * This value is supposed to be human-readable. * @return an interface to the connection * @throws IOException if it encounters a problem */ - public Connection newConnection(List
addrs, String connectionName) throws IOException, TimeoutException { - return newConnection(this.sharedExecutor, addrs, connectionName); + public Connection newConnection(List
addrs, String clientProvidedName) throws IOException, TimeoutException { + return newConnection(this.sharedExecutor, addrs, clientProvidedName); } /** @@ -719,7 +727,7 @@ public Connection newConnection(ExecutorService executor, Address[] addrs) throw /** - * Create a new broker connection, picking the first available address from + * Create a new broker connection with a client-provided name, picking the first available address from * the list. * * If automatic connection recovery @@ -728,13 +736,17 @@ public Connection newConnection(ExecutorService executor, Address[] addrs) throw * * @param executor thread execution service for consumers on the connection * @param addrs an array of known broker addresses (hostname/port pairs) to try in order - * @param connectionName arbitrary sring for connection name client property + * @param clientProvidedName application-specific connection name, will be displayed + * in the management UI if RabbitMQ server supports it. + * This value doesn't have to be unique and cannot be used + * as a connection identifier e.g. in HTTP API requests. + * This value is supposed to be human-readable. * @return an interface to the connection * @throws java.io.IOException if it encounters a problem * @see Automatic Recovery */ - public Connection newConnection(ExecutorService executor, Address[] addrs, String connectionName) throws IOException, TimeoutException { - return newConnection(executor, Arrays.asList(addrs), connectionName); + public Connection newConnection(ExecutorService executor, Address[] addrs, String clientProvidedName) throws IOException, TimeoutException { + return newConnection(executor, Arrays.asList(addrs), clientProvidedName); } /** @@ -756,7 +768,7 @@ public Connection newConnection(ExecutorService executor, List
addrs) t } /** - * Create a new broker connection, picking the first available address from + * Create a new broker connection with a client-provided name, picking the first available address from * the list. * * If automatic connection recovery @@ -765,20 +777,24 @@ public Connection newConnection(ExecutorService executor, List
addrs) t * * @param executor thread execution service for consumers on the connection * @param addrs a List of known broker addrs (hostname/port pairs) to try in order - * @param connectionName arbitrary sring for connection name client property + * @param clientProvidedName application-specific connection name, will be displayed + * in the management UI if RabbitMQ server supports it. + * This value doesn't have to be unique and cannot be used + * as a connection identifier e.g. in HTTP API requests. + * This value is supposed to be human-readable. * @return an interface to the connection * @throws java.io.IOException if it encounters a problem * @see Automatic Recovery */ - public Connection newConnection(ExecutorService executor, List
addrs, String connectionName) + public Connection newConnection(ExecutorService executor, List
addrs, String clientProvidedName) throws IOException, TimeoutException { // make sure we respect the provided thread factory FrameHandlerFactory fhFactory = createFrameHandlerFactory(); ConnectionParams params = params(executor); - // set connection name client property - if (connectionName != null) { + // set client-provided via a client property + if (clientProvidedName != null) { Map properties = new HashMap(params.getClientProperties()); - properties.put("connection_name", connectionName); + properties.put("connection_name", clientProvidedName); params.setClientProperties(properties); } diff --git a/src/com/rabbitmq/client/impl/AMQConnection.java b/src/com/rabbitmq/client/impl/AMQConnection.java index 3634165950..ee6b0054a7 100644 --- a/src/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/com/rabbitmq/client/impl/AMQConnection.java @@ -470,13 +470,8 @@ public Map getClientProperties() { return new HashMap(_clientProperties); } - public String getConnectionName() { - Object connectionName = _clientProperties.get("connection_name"); - if (connectionName == null){ - return null; - } else { - return connectionName.toString(); - } + public String getClientProvidedName() { + return (String) _clientProperties.get("connection_name"); } /** diff --git a/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index c7663d16b8..451d53308e 100644 --- a/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -5,6 +5,7 @@ import com.rabbitmq.client.BlockedListener; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.MissedHeartbeatException; import com.rabbitmq.client.Recoverable; import com.rabbitmq.client.RecoveryListener; @@ -27,6 +28,7 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeoutException; /** @@ -157,10 +159,12 @@ public Map getClientProperties() { } /** - * @see com.rabbitmq.client.Connection#getConnectionName() + * @see com.rabbitmq.client.Connection#getClientProvidedName() + * @see ConnectionFactory#newConnection(Address[], String) + * @see ConnectionFactory#newConnection(ExecutorService, Address[], String) */ - public String getConnectionName() { - return delegate.getConnectionName(); + public String getClientProvidedName() { + return delegate.getClientProvidedName(); } /** diff --git a/test/src/com/rabbitmq/client/test/AMQConnectionTest.java b/test/src/com/rabbitmq/client/test/AMQConnectionTest.java index db650404cb..a267661018 100644 --- a/test/src/com/rabbitmq/client/test/AMQConnectionTest.java +++ b/test/src/com/rabbitmq/client/test/AMQConnectionTest.java @@ -177,33 +177,33 @@ public void testConnectionHangInNegotiation() { assertEquals("Wrong type of exception returned.", SocketTimeoutException.class, exceptionList.get(0).getClass()); } - public void testConnectionName() throws IOException, TimeoutException { - String connectionName = "custom name"; - Connection connection = factory.newConnection(connectionName); - assertEquals(connectionName, connection.getConnectionName()); + public void testClientProvidedConnectionName() throws IOException, TimeoutException { + String providedName = "event consumers connection"; + Connection connection = factory.newConnection(providedName); + assertEquals(providedName, connection.getClientProvidedName()); connection.close(); - List
addresses_list = Arrays.asList(new Address("127.0.0.1"), new Address("127.0.0.1", 5672)); - connection = factory.newConnection(addresses_list, connectionName); - assertEquals(connectionName, connection.getConnectionName()); + List
addrs1 = Arrays.asList(new Address("127.0.0.1"), new Address("127.0.0.1", 5672)); + connection = factory.newConnection(addrs1, providedName); + assertEquals(providedName, connection.getClientProvidedName()); connection.close(); - Address[] addresses_arr = {new Address("127.0.0.1"), new Address("127.0.0.1", 5672)}; - connection = factory.newConnection(addresses_arr, connectionName); - assertEquals(connectionName, connection.getConnectionName()); + Address[] addrs2 = {new Address("127.0.0.1"), new Address("127.0.0.1", 5672)}; + connection = factory.newConnection(addrs2, providedName); + assertEquals(providedName, connection.getClientProvidedName()); connection.close(); - ExecutorService executor = Executors.newSingleThreadExecutor(); - connection = factory.newConnection(executor, connectionName); - assertEquals(connectionName, connection.getConnectionName()); + ExecutorService xs = Executors.newSingleThreadExecutor(); + connection = factory.newConnection(xs, providedName); + assertEquals(providedName, connection.getClientProvidedName()); connection.close(); - connection = factory.newConnection(executor, addresses_list, connectionName); - assertEquals(connectionName, connection.getConnectionName()); + connection = factory.newConnection(xs, addrs1, providedName); + assertEquals(providedName, connection.getClientProvidedName()); connection.close(); - connection = factory.newConnection(executor, addresses_arr, connectionName); - assertEquals(connectionName, connection.getConnectionName()); + connection = factory.newConnection(xs, addrs2, providedName); + assertEquals(providedName, connection.getClientProvidedName()); connection.close(); } diff --git a/test/src/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/test/src/com/rabbitmq/client/test/functional/ConnectionRecovery.java index e80d5dbbbc..471557a791 100644 --- a/test/src/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/test/src/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -36,10 +36,10 @@ public void testNamedConnectionRecovery() AutorecoveringConnection c = newRecoveringConnection(connectionName); try { assertTrue(c.isOpen()); - assertEquals(connectionName, c.getConnectionName()); + assertEquals(connectionName, c.getClientProvidedName()); closeAndWaitForRecovery(c); assertTrue(c.isOpen()); - assertEquals(connectionName, c.getConnectionName()); + assertEquals(connectionName, c.getClientProvidedName()); } finally { c.abort(); } From 71c816622c75ab523e723e6fa48ada7129d7ae7f Mon Sep 17 00:00:00 2001 From: Daniil Fedotov Date: Wed, 27 Apr 2016 11:03:49 +0100 Subject: [PATCH 0142/2114] Functional test for requeueing of dead-lettered messages and invalid x-death headers --- .../test/functional/DeadLetterExchange.java | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/test/src/com/rabbitmq/client/test/functional/DeadLetterExchange.java b/test/src/com/rabbitmq/client/test/functional/DeadLetterExchange.java index 77e1693f46..80e30ca6a5 100644 --- a/test/src/com/rabbitmq/client/test/functional/DeadLetterExchange.java +++ b/test/src/com/rabbitmq/client/test/functional/DeadLetterExchange.java @@ -400,6 +400,79 @@ public void process(GetResponse getResponse) { }); } + public void testRepublish() throws Exception { + Map args = new HashMap(); + args.put("x-message-ttl", 100); + declareQueue(TEST_QUEUE_NAME, DLX, null, args); + channel.queueBind(TEST_QUEUE_NAME, "amq.direct", "test"); + channel.queueBind(DLQ, DLX, "test"); + publishN(1); + + sleep(100); + + GetResponse getResponse = channel.basicGet(DLQ, true); + assertNotNull("Message not dead-lettered", + getResponse); + assertEquals("test message", new String(getResponse.getBody())); + BasicProperties props = getResponse.getProps(); + Map headers = props.getHeaders(); + assertNotNull(headers); + ArrayList death = (ArrayList) headers.get("x-death"); + assertNotNull(death); + assertEquals(1, death.size()); + assertDeathReason(death, 0, TEST_QUEUE_NAME, "expired", "amq.direct", + Arrays.asList("test")); + + // Make queue zero length + args = new HashMap(); + args.put("x-max-length", 0); + channel.queueDelete(TEST_QUEUE_NAME); + declareQueue(TEST_QUEUE_NAME, DLX, null, args); + channel.queueBind(TEST_QUEUE_NAME, "amq.direct", "test"); + + sleep(100); + //Queueing second time with same props + channel.basicPublish("amq.direct", "test", + new AMQP.BasicProperties.Builder() + .headers(headers) + .build(), "test message".getBytes()); + + sleep(100); + + getResponse = channel.basicGet(DLQ, true); + assertNotNull("Message not dead-lettered", getResponse); + assertEquals("test message", new String(getResponse.getBody())); + headers = getResponse.getProps().getHeaders(); + assertNotNull(headers); + death = (ArrayList) headers.get("x-death"); + assertNotNull(death); + assertEquals(2, death.size()); + assertDeathReason(death, 0, TEST_QUEUE_NAME, "maxlen", "amq.direct", + Arrays.asList("test")); + assertDeathReason(death, 1, TEST_QUEUE_NAME, "expired", "amq.direct", + Arrays.asList("test")); + + //Set invalid headers + headers.put("x-death", "[I, am, not, array]"); + channel.basicPublish("amq.direct", "test", + new AMQP.BasicProperties.Builder() + .headers(headers) + .build(), "test message".getBytes()); + sleep(100); + + getResponse = channel.basicGet(DLQ, true); + assertNotNull("Message not dead-lettered", getResponse); + assertEquals("test message", new String(getResponse.getBody())); + headers = getResponse.getProps().getHeaders(); + assertNotNull(headers); + death = (ArrayList) headers.get("x-death"); + assertNotNull(death); + assertEquals(1, death.size()); + assertDeathReason(death, 0, TEST_QUEUE_NAME, "maxlen", "amq.direct", + Arrays.asList("test")); + + } + public void rejectionTest(final boolean useNack) throws Exception { deadLetterTest(new Callable() { public Void call() throws Exception { From 94bb21b035a1de4cc16c56a9255cf305d84071ad Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 27 Apr 2016 16:29:25 -0500 Subject: [PATCH 0143/2114] Supress unchecked warnings for this test --- .../com/rabbitmq/client/test/functional/DeadLetterExchange.java | 1 + 1 file changed, 1 insertion(+) diff --git a/test/src/com/rabbitmq/client/test/functional/DeadLetterExchange.java b/test/src/com/rabbitmq/client/test/functional/DeadLetterExchange.java index 80e30ca6a5..7382f604f2 100644 --- a/test/src/com/rabbitmq/client/test/functional/DeadLetterExchange.java +++ b/test/src/com/rabbitmq/client/test/functional/DeadLetterExchange.java @@ -400,6 +400,7 @@ public void process(GetResponse getResponse) { }); } + @SuppressWarnings("unchecked") public void testRepublish() throws Exception { Map args = new HashMap(); args.put("x-message-ttl", 100); From 92ab2bcc3e74d761853faaba895fda22b6805c88 Mon Sep 17 00:00:00 2001 From: nick Date: Tue, 8 Mar 2016 16:21:23 -0800 Subject: [PATCH 0144/2114] PR 132: inform recovery listeners when recovery has started in case an app wants to log something / set a flag / fire an event when recovery has begun but before it has completed. --- .../java/com/rabbitmq/client/RecoveryListener.java | 1 + .../client/impl/recovery/AutorecoveringChannel.java | 11 +++++++++-- .../impl/recovery/AutorecoveringConnection.java | 13 +++++++++++-- .../client/test/functional/ConnectionRecovery.java | 8 ++++++++ 4 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/RecoveryListener.java b/src/main/java/com/rabbitmq/client/RecoveryListener.java index 88b0ece2e5..756075a55a 100644 --- a/src/main/java/com/rabbitmq/client/RecoveryListener.java +++ b/src/main/java/com/rabbitmq/client/RecoveryListener.java @@ -8,4 +8,5 @@ */ public interface RecoveryListener { public void handleRecovery(Recoverable recoverable); + public void handleRecoveryStarted(Recoverable recoverable); } diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java index a07c78f5f5..5faeefe604 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java @@ -489,12 +489,13 @@ public void automaticallyRecover(AutorecoveringConnection connection, Connection this.delegate = (RecoveryAwareChannelN) connDelegate.createChannel(this.getChannelNumber()); this.delegate.inheritOffsetFrom(defunctChannel); + this.notifyRecoveryListenersStarted(); this.recoverShutdownListeners(); this.recoverReturnListeners(); this.recoverConfirmListeners(); this.recoverFlowListeners(); this.recoverState(); - this.notifyRecoveryListeners(); + this.notifyRecoveryListenersComplete(); } private void recoverShutdownListeners() { @@ -538,12 +539,18 @@ private void recoverState() throws IOException { } } - private void notifyRecoveryListeners() { + private void notifyRecoveryListenersComplete() { for (RecoveryListener f : this.recoveryListeners) { f.handleRecovery(this); } } + private void notifyRecoveryListenersStarted() { + for (RecoveryListener f : this.recoveryListeners) { + f.handleRecoveryStarted(this); + } + } + private void recordQueueBinding(String queue, String exchange, String routingKey, Map arguments) { this.connection.recordQueueBinding(this, queue, exchange, routingKey, arguments); } diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index b559625fb5..aba249d5d4 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -441,6 +441,9 @@ public void removeConsumerRecoveryListener(ConsumerRecoveryListener listener) { synchronized private void beginAutomaticRecovery() throws InterruptedException, IOException, TopologyRecoveryException { Thread.sleep(this.params.getNetworkRecoveryInterval()); + + this.notifyRecoveryListenersStarted(); + if (!this.recoverConnection()) return; @@ -452,7 +455,7 @@ synchronized private void beginAutomaticRecovery() throws InterruptedException, this.recoverConsumers(); } - this.notifyRecoveryListeners(); + this.notifyRecoveryListenersComplete(); } private void recoverShutdownListeners() { @@ -506,12 +509,18 @@ private void recoverChannels() { } } - private void notifyRecoveryListeners() { + private void notifyRecoveryListenersComplete() { for (RecoveryListener f : this.recoveryListeners) { f.handleRecovery(this); } } + private void notifyRecoveryListenersStarted() { + for (RecoveryListener f : this.recoveryListeners) { + f.handleRecoveryStarted(this); + } + } + private void recoverEntities() throws TopologyRecoveryException { // The recovery sequence is the following: // diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java index efb944a347..546d7efc6f 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -550,10 +550,14 @@ public void testQueueRecoveryWithManyQueues() throws IOException, InterruptedExc public void testChannelRecoveryCallback() throws IOException, InterruptedException { final CountDownLatch latch = new CountDownLatch(2); + final CountDownLatch startLatch = new CountDownLatch(2); final RecoveryListener listener = new RecoveryListener() { public void handleRecovery(Recoverable recoverable) { latch.countDown(); } + public void handleRecoveryStarted(Recoverable recoverable) { + startLatch.countDown(); + } }; AutorecoveringChannel ch1 = (AutorecoveringChannel) connection.createChannel(); ch1.addRecoveryListener(listener); @@ -566,6 +570,7 @@ public void handleRecovery(Recoverable recoverable) { expectChannelRecovery(ch1); expectChannelRecovery(ch2); wait(latch); + wait(startLatch); } public void testBasicAckAfterChannelRecovery() throws IOException, InterruptedException, TimeoutException { @@ -670,6 +675,9 @@ private CountDownLatch prepareForRecovery(Connection conn) { public void handleRecovery(Recoverable recoverable) { latch.countDown(); } + public void handleRecoveryStarted(Recoverable recoverable) { + // No-op + } }); return latch; } From d3331029113563143c8a4c4e7fbff64a000b99ac Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 16 Mar 2016 15:22:01 +0000 Subject: [PATCH 0145/2114] Explain the difference --- .../com/rabbitmq/client/test/server/BlockedConnection.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java b/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java index 3880e5ffb0..2099ed8d54 100644 --- a/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java @@ -37,6 +37,8 @@ protected void releaseResources() throws IOException { e.printStackTrace(); } } + // this test first opens a connection, then triggers + // and alarm and blocks public void testBlock() throws Exception { final CountDownLatch latch = new CountDownLatch(1); @@ -47,6 +49,8 @@ public void testBlock() throws Exception { assertTrue(latch.await(10, TimeUnit.SECONDS)); } + // this test first triggers an alarm, then opens a + // connection public void testInitialBlock() throws Exception { final CountDownLatch latch = new CountDownLatch(1); From b1bfed8d6329c95674bd85b4c6727a906f05ca85 Mon Sep 17 00:00:00 2001 From: Mike Playle Date: Mon, 4 Apr 2016 16:46:20 +0100 Subject: [PATCH 0146/2114] Set the nowait flag in queueBindNoWait() This prevents us from being confused by a reply we didn't expect. Also fix the associated javadoc comment. --- src/main/java/com/rabbitmq/client/Channel.java | 2 +- src/main/java/com/rabbitmq/client/impl/ChannelN.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/Channel.java b/src/main/java/com/rabbitmq/client/Channel.java index 36ba7d1d0c..f38b7a6ef0 100644 --- a/src/main/java/com/rabbitmq/client/Channel.java +++ b/src/main/java/com/rabbitmq/client/Channel.java @@ -616,7 +616,7 @@ void queueDeclareNoWait(String queue, boolean durable, boolean exclusive, boolea Queue.BindOk queueBind(String queue, String exchange, String routingKey, Map arguments) throws IOException; /** - * Same as {@link Channel#queueDeclare(String, boolean, boolean, boolean, java.util.Map)} but sets nowait + * Same as {@link Channel#queueBind(String, String, String, java.util.Map)} but sets nowait * parameter to true and returns void (as there will be no response * from the server). * @param queue the name of the queue diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java index 18d4802fa2..782a968229 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelN.java @@ -970,6 +970,7 @@ public void queueBindNoWait(String queue, .exchange(exchange) .routingKey(routingKey) .arguments(arguments) + .nowait(true) .build())); } From ac8adf964c29465fe7a1c1311e93fa0a4c3140a2 Mon Sep 17 00:00:00 2001 From: Daniil Fedotov Date: Mon, 11 Apr 2016 17:21:45 +0100 Subject: [PATCH 0147/2114] Connection name parameter to create connections --- .../rabbitmq/client/ConnectionFactory.java | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 191175180b..1ea28a2e9b 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -644,7 +644,11 @@ protected FrameHandlerFactory createFrameHandlerFactory() throws IOException { * @throws IOException if it encounters a problem */ public Connection newConnection(Address[] addrs) throws IOException, TimeoutException { - return newConnection(this.sharedExecutor, Arrays.asList(addrs)); + return newConnection(this.sharedExecutor, Arrays.asList(addrs), null); + } + + public Connection newConnection(Address[] addrs, String connectionName) throws IOException, TimeoutException { + return newConnection(this.sharedExecutor, Arrays.asList(addrs), connectionName); } /** @@ -660,7 +664,11 @@ public Connection newConnection(Address[] addrs) throws IOException, TimeoutExce * @throws IOException if it encounters a problem */ public Connection newConnection(List
addrs) throws IOException, TimeoutException { - return newConnection(this.sharedExecutor, addrs); + return newConnection(this.sharedExecutor, addrs, null); + } + + public Connection newConnection(List
addrs, String connectionName) throws IOException, TimeoutException { + return newConnection(this.sharedExecutor, addrs, connectionName); } /** @@ -678,7 +686,11 @@ public Connection newConnection(List
addrs) throws IOException, Timeout * @see Automatic Recovery */ public Connection newConnection(ExecutorService executor, Address[] addrs) throws IOException, TimeoutException { - return newConnection(executor, Arrays.asList(addrs)); + return newConnection(executor, Arrays.asList(addrs), null); + } + + public Connection newConnection(ExecutorService executor, Address[] addrs, String connectionName) throws IOException, TimeoutException { + return newConnection(executor, Arrays.asList(addrs), connectionName); } /** @@ -695,11 +707,16 @@ public Connection newConnection(ExecutorService executor, Address[] addrs) throw * @throws java.io.IOException if it encounters a problem * @see Automatic Recovery */ - public Connection newConnection(ExecutorService executor, List
addrs) + public Connection newConnection(ExecutorService executor, List
addrs, String connectionName) throws IOException, TimeoutException { // make sure we respect the provided thread factory FrameHandlerFactory fhFactory = createFrameHandlerFactory(); ConnectionParams params = params(executor); + if (connectionName != null) { + Map properties = params.getClientProperties().clone(); + properties.put("connection_name", connectionName); + params.setClientProperties(properties); + } if (isAutomaticRecoveryEnabled()) { // see com.rabbitmq.client.impl.recovery.RecoveryAwareAMQConnectionFactory#newConnection From 0b6ace55121db2881d2ac53afe8529fbf857135b Mon Sep 17 00:00:00 2001 From: Daniil Fedotov Date: Tue, 12 Apr 2016 12:50:10 +0100 Subject: [PATCH 0148/2114] Getter for connection name and docs --- .../java/com/rabbitmq/client/Connection.java | 7 ++ .../rabbitmq/client/ConnectionFactory.java | 66 ++++++++++++++++++- .../rabbitmq/client/impl/AMQConnection.java | 9 +++ .../recovery/AutorecoveringConnection.java | 7 ++ 4 files changed, 88 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/Connection.java b/src/main/java/com/rabbitmq/client/Connection.java index 203ae7d73d..1809be6e44 100644 --- a/src/main/java/com/rabbitmq/client/Connection.java +++ b/src/main/java/com/rabbitmq/client/Connection.java @@ -94,6 +94,13 @@ public interface Connection extends ShutdownNotifier, Closeable { // rename to A */ Map getClientProperties(); + /** + * Get connection name client property value + * + * @return string connection name from client properties, or null if there is not such property. + */ + String getConnectionName(); + /** * Retrieve the server properties. * @return a map of the server properties. This typically includes the product name and version of the server. diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 1ea28a2e9b..9c005370f8 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -21,6 +21,7 @@ import java.security.NoSuchAlgorithmException; import java.util.Collections; import java.util.Map; +import java.util.HashMap; import java.util.concurrent.*; import java.util.List; import java.util.Arrays; @@ -647,6 +648,20 @@ public Connection newConnection(Address[] addrs) throws IOException, TimeoutExce return newConnection(this.sharedExecutor, Arrays.asList(addrs), null); } + + /** + * Create a new broker connection, picking the first available address from + * the list. + * + * If automatic connection recovery + * is enabled, the connection returned by this method will be {@link Recoverable}. Future + * reconnection attempts will pick a random accessible address from the provided list. + * + * @param addrs an array of known broker addresses (hostname/port pairs) to try in order + * @param connectionName arbitrary sring for connection name client property + * @return an interface to the connection + * @throws IOException if it encounters a problem + */ public Connection newConnection(Address[] addrs, String connectionName) throws IOException, TimeoutException { return newConnection(this.sharedExecutor, Arrays.asList(addrs), connectionName); } @@ -667,6 +682,19 @@ public Connection newConnection(List
addrs) throws IOException, Timeout return newConnection(this.sharedExecutor, addrs, null); } + /** + * Create a new broker connection, picking the first available address from + * the list. + * + * If automatic connection recovery + * is enabled, the connection returned by this method will be {@link Recoverable}. Future + * reconnection attempts will pick a random accessible address from the provided list. + * + * @param addrs a List of known broker addresses (hostname/port pairs) to try in order + * @param connectionName arbitrary sring for connection name client property + * @return an interface to the connection + * @throws IOException if it encounters a problem + */ public Connection newConnection(List
addrs, String connectionName) throws IOException, TimeoutException { return newConnection(this.sharedExecutor, addrs, connectionName); } @@ -689,6 +717,22 @@ public Connection newConnection(ExecutorService executor, Address[] addrs) throw return newConnection(executor, Arrays.asList(addrs), null); } + + /** + * Create a new broker connection, picking the first available address from + * the list. + * + * If automatic connection recovery + * is enabled, the connection returned by this method will be {@link Recoverable}. Future + * reconnection attempts will pick a random accessible address from the provided list. + * + * @param executor thread execution service for consumers on the connection + * @param addrs an array of known broker addresses (hostname/port pairs) to try in order + * @param connectionName arbitrary sring for connection name client property + * @return an interface to the connection + * @throws java.io.IOException if it encounters a problem + * @see Automatic Recovery + */ public Connection newConnection(ExecutorService executor, Address[] addrs, String connectionName) throws IOException, TimeoutException { return newConnection(executor, Arrays.asList(addrs), connectionName); } @@ -707,13 +751,33 @@ public Connection newConnection(ExecutorService executor, Address[] addrs, Strin * @throws java.io.IOException if it encounters a problem * @see Automatic Recovery */ + public Connection newConnection(ExecutorService executor, List
addrs) throws IOException, TimeoutException { + return newConnection(executor, addrs, null); + } + + /** + * Create a new broker connection, picking the first available address from + * the list. + * + * If automatic connection recovery + * is enabled, the connection returned by this method will be {@link Recoverable}. Future + * reconnection attempts will pick a random accessible address from the provided list. + * + * @param executor thread execution service for consumers on the connection + * @param addrs a List of known broker addrs (hostname/port pairs) to try in order + * @param connectionName arbitrary sring for connection name client property + * @return an interface to the connection + * @throws java.io.IOException if it encounters a problem + * @see Automatic Recovery + */ public Connection newConnection(ExecutorService executor, List
addrs, String connectionName) throws IOException, TimeoutException { // make sure we respect the provided thread factory FrameHandlerFactory fhFactory = createFrameHandlerFactory(); ConnectionParams params = params(executor); + // set connection name client property if (connectionName != null) { - Map properties = params.getClientProperties().clone(); + Map properties = new HashMap(params.getClientProperties()); properties.put("connection_name", connectionName); params.setClientProperties(properties); } diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index 54e17c0918..3634165950 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -470,6 +470,15 @@ public Map getClientProperties() { return new HashMap(_clientProperties); } + public String getConnectionName() { + Object connectionName = _clientProperties.get("connection_name"); + if (connectionName == null){ + return null; + } else { + return connectionName.toString(); + } + } + /** * Protected API - retrieve the current ExceptionHandler */ diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index aba249d5d4..50cc600ee1 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -156,6 +156,13 @@ public Map getClientProperties() { return delegate.getClientProperties(); } + /** + * @see com.rabbitmq.client.Connection#getConnectionName() + */ + public String getConnectionName() { + return delegate.getConnectionName(); + } + /** * @see com.rabbitmq.client.Connection#getFrameMax() */ From f9ef4990d85caac15b319a7cdcd8125dabce019a Mon Sep 17 00:00:00 2001 From: Daniil Fedotov Date: Wed, 13 Apr 2016 12:53:03 +0100 Subject: [PATCH 0149/2114] Named connection tests --- .../rabbitmq/client/ConnectionFactory.java | 31 +++++++++++++++++ .../client/test/AMQConnectionTest.java | 33 +++++++++++++++++++ .../test/functional/ConnectionRecovery.java | 26 +++++++++++++++ 3 files changed, 90 insertions(+) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 9c005370f8..3eb7645745 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -841,6 +841,21 @@ public Connection newConnection() throws IOException, TimeoutException { return newConnection(this.sharedExecutor, Collections.singletonList(new Address(getHost(), getPort()))); } + /** + * Create a new broker connection. + * + * If automatic connection recovery + * is enabled, the connection returned by this method will be {@link Recoverable}. Reconnection + * attempts will always use the address configured on {@link ConnectionFactory}. + * + * @param connectionName arbitrary sring for connection name client property + * @return an interface to the connection + * @throws IOException if it encounters a problem + */ + public Connection newConnection(String connectionName) throws IOException, TimeoutException { + return newConnection(this.sharedExecutor, Collections.singletonList(new Address(getHost(), getPort())), connectionName); + } + /** * Create a new broker connection. * @@ -856,6 +871,22 @@ public Connection newConnection(ExecutorService executor) throws IOException, Ti return newConnection(executor, Collections.singletonList(new Address(getHost(), getPort()))); } + /** + * Create a new broker connection. + * + * If automatic connection recovery + * is enabled, the connection returned by this method will be {@link Recoverable}. Reconnection + * attempts will always use the address configured on {@link ConnectionFactory}. + * + * @param executor thread execution service for consumers on the connection + * @param connectionName arbitrary sring for connection name client property + * @return an interface to the connection + * @throws IOException if it encounters a problem + */ + public Connection newConnection(ExecutorService executor, String connectionName) throws IOException, TimeoutException { + return newConnection(executor, Collections.singletonList(new Address(getHost(), getPort())), connectionName); + } + @Override public ConnectionFactory clone(){ try { return (ConnectionFactory)super.clone(); diff --git a/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java b/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java index 3aff2fbdd8..db650404cb 100644 --- a/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java +++ b/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java @@ -25,6 +25,9 @@ import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.TimeoutException; +import java.util.concurrent.ExecutorService; +import com.rabbitmq.client.Address; +import java.util.Arrays; import com.rabbitmq.client.impl.ConnectionParams; import com.rabbitmq.client.TopologyRecoveryException; @@ -174,6 +177,36 @@ public void testConnectionHangInNegotiation() { assertEquals("Wrong type of exception returned.", SocketTimeoutException.class, exceptionList.get(0).getClass()); } + public void testConnectionName() throws IOException, TimeoutException { + String connectionName = "custom name"; + Connection connection = factory.newConnection(connectionName); + assertEquals(connectionName, connection.getConnectionName()); + connection.close(); + + List
addresses_list = Arrays.asList(new Address("127.0.0.1"), new Address("127.0.0.1", 5672)); + connection = factory.newConnection(addresses_list, connectionName); + assertEquals(connectionName, connection.getConnectionName()); + connection.close(); + + Address[] addresses_arr = {new Address("127.0.0.1"), new Address("127.0.0.1", 5672)}; + connection = factory.newConnection(addresses_arr, connectionName); + assertEquals(connectionName, connection.getConnectionName()); + connection.close(); + + ExecutorService executor = Executors.newSingleThreadExecutor(); + connection = factory.newConnection(executor, connectionName); + assertEquals(connectionName, connection.getConnectionName()); + connection.close(); + + connection = factory.newConnection(executor, addresses_list, connectionName); + assertEquals(connectionName, connection.getConnectionName()); + connection.close(); + + connection = factory.newConnection(executor, addresses_arr, connectionName); + assertEquals(connectionName, connection.getConnectionName()); + connection.close(); + } + /** Mock frame handler to facilitate testing. */ private static class MockFrameHandler implements FrameHandler { /** How many times has sendHeader() been called? */ diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java index 546d7efc6f..371d6f6b97 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -30,6 +30,21 @@ public void testConnectionRecovery() throws IOException, InterruptedException { assertTrue(connection.isOpen()); } + public void testNamedConnectionRecovery() + throws IOException, InterruptedException, TimeoutException { + String connectionName = "custom name"; + AutorecoveringConnection c = newRecoveringConnection(connectionName); + try { + assertTrue(c.isOpen()); + assertEquals(connectionName, c.getConnectionName()); + closeAndWaitForRecovery(c); + assertTrue(c.isOpen()); + assertEquals(connectionName, c.getConnectionName()); + } finally { + c.abort(); + } + } + public void testConnectionRecoveryWithServerRestart() throws IOException, InterruptedException { assertTrue(connection.isOpen()); restartPrimaryAndWaitForRecovery(); @@ -747,6 +762,17 @@ private AutorecoveringConnection newRecoveringConnection(List
addresses return newRecoveringConnection(false, addresses); } + private AutorecoveringConnection newRecoveringConnection(boolean disableTopologyRecovery, String connectionName) + throws IOException, TimeoutException { + ConnectionFactory cf = buildConnectionFactoryWithRecoveryEnabled(disableTopologyRecovery); + return (AutorecoveringConnection) cf.newConnection(connectionName); + } + + private AutorecoveringConnection newRecoveringConnection(String connectionName) + throws IOException, TimeoutException { + return newRecoveringConnection(false, connectionName); + } + private ConnectionFactory buildConnectionFactoryWithRecoveryEnabled(boolean disableTopologyRecovery) { ConnectionFactory cf = new ConnectionFactory(); cf.setNetworkRecoveryInterval(RECOVERY_INTERVAL); From 30d95c7ef23b165b5553cb1ceb45dc2526a80e10 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 13 Apr 2016 17:16:35 +0300 Subject: [PATCH 0150/2114] Use a more reasonable timeout --- .../rabbitmq/client/test/functional/ConnectionRecovery.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java index 371d6f6b97..47304fd6f9 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -784,9 +784,9 @@ private ConnectionFactory buildConnectionFactoryWithRecoveryEnabled(boolean disa } private static void wait(CountDownLatch latch) throws InterruptedException { - // Very very generous amount of time to wait, just make sure we never - // hang forever - assertTrue(latch.await(1800, TimeUnit.SECONDS)); + // we want to wait for recovery to complete for a reasonable amount of time + // but still make recovery failures easy to notice in development environments + assertTrue(latch.await(90, TimeUnit.SECONDS)); } private void waitForConfirms(Channel ch) throws InterruptedException, TimeoutException { From f8f1372de26f779f311223a9e9a03287bd99edcd Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 13 Apr 2016 17:16:50 +0300 Subject: [PATCH 0151/2114] Introduce a way for AMQConnection to notify its recovery aware wrapper Fixes #135. --- .../rabbitmq/client/impl/AMQConnection.java | 30 ++++++++++++++--- .../recovery/AutorecoveringConnection.java | 33 ++++++++++--------- .../recovery/RecoveryCanBeginListener.java | 12 +++++++ 3 files changed, 55 insertions(+), 20 deletions(-) create mode 100644 src/main/java/com/rabbitmq/client/impl/recovery/RecoveryCanBeginListener.java diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index 3634165950..e0f45fb87e 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -21,10 +21,7 @@ import java.net.InetAddress; import java.net.SocketException; import java.net.SocketTimeoutException; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; +import java.util.*; import java.util.concurrent.*; import com.rabbitmq.client.AMQP; @@ -45,6 +42,7 @@ import com.rabbitmq.client.SaslMechanism; import com.rabbitmq.client.ShutdownSignalException; import com.rabbitmq.client.impl.AMQChannel.BlockingRpcContinuation; +import com.rabbitmq.client.impl.recovery.RecoveryCanBeginListener; import com.rabbitmq.utility.BlockingCell; final class Copyright { @@ -65,6 +63,9 @@ public class AMQConnection extends ShutdownNotifierComponent implements Connecti private Thread mainLoopThread; private ThreadFactory threadFactory = Executors.defaultThreadFactory(); + private final List recoveryCanBeginListeners = + new ArrayList(); + /** * Retrieve a copy of the default table of client properties that * will be sent to the server during connection startup. This @@ -585,10 +586,31 @@ public void run() { _frameHandler.close(); _appContinuation.set(null); notifyListeners(); + // assuming that shutdown listeners do not do anything + // asynchronously, e.g. start new threads, this effectively + // guarantees that we only begin recovery when all shutdown + // listeners have executed + notifyRecoveryCanBeginListeners(); } } } + private void notifyRecoveryCanBeginListeners() { + ShutdownSignalException sse = this.getCloseReason(); + for(RecoveryCanBeginListener fn : this.recoveryCanBeginListeners) { + fn.recoveryCanBegin(sse); + } + } + + public void addRecoveryCanBeginListener(RecoveryCanBeginListener fn) { + this.recoveryCanBeginListeners.add(fn); + } + + @SuppressWarnings(value = "unused") + public void removeRecoveryCanBeginListener(RecoveryCanBeginListener fn) { + this.recoveryCanBeginListeners.remove(fn); + } + /** * Called when a frame-read operation times out * @throws MissedHeartbeatException if heart-beats have been missed diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index 50cc600ee1..aa28699aed 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -383,8 +383,10 @@ public int getLocalPort() { private void addAutomaticRecoveryListener() { final AutorecoveringConnection c = this; - ShutdownListener automaticRecoveryListener = new ShutdownListener() { - public void shutdownCompleted(ShutdownSignalException cause) { + // this listener will run after shutdown listeners, + // see https://github.com/rabbitmq/rabbitmq-java-client/issues/135 + RecoveryCanBeginListener starter = new RecoveryCanBeginListener() { + public void recoveryCanBegin(ShutdownSignalException cause) { try { if (shouldTriggerConnectionRecovery(cause)) { c.beginAutomaticRecovery(); @@ -395,10 +397,7 @@ public void shutdownCompleted(ShutdownSignalException cause) { } }; synchronized (this) { - if(!this.shutdownHooks.contains(automaticRecoveryListener)) { - this.shutdownHooks.add(automaticRecoveryListener); - } - this.delegate.addShutdownListener(automaticRecoveryListener); + this.delegate.addRecoveryCanBeginListener(starter); } } @@ -451,16 +450,18 @@ synchronized private void beginAutomaticRecovery() throws InterruptedException, this.notifyRecoveryListenersStarted(); - if (!this.recoverConnection()) - return; - - this.recoverShutdownListeners(); - this.recoverBlockedListeners(); - this.recoverChannels(); - if(this.params.isTopologyRecoveryEnabled()) { - this.recoverEntities(); - this.recoverConsumers(); - } + if (!this.recoverConnection()) { + return; + } + + this.addAutomaticRecoveryListener(); + this.recoverShutdownListeners(); + this.recoverBlockedListeners(); + this.recoverChannels(); + if(this.params.isTopologyRecoveryEnabled()) { + this.recoverEntities(); + this.recoverConsumers(); + } this.notifyRecoveryListenersComplete(); } diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryCanBeginListener.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryCanBeginListener.java new file mode 100644 index 0000000000..6326f3d288 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryCanBeginListener.java @@ -0,0 +1,12 @@ +package com.rabbitmq.client.impl.recovery; + +import com.rabbitmq.client.ShutdownSignalException; + +/** + * Used internally to indicate when connection recovery can + * begin. See {@link https://github.com/rabbitmq/rabbitmq-java-client/issues/135}. + * This is package-local by design. + */ +public interface RecoveryCanBeginListener { + void recoveryCanBegin(ShutdownSignalException cause); +} From 4c0c4741200fa53fe7ef2327b0fae2f5d593c74b Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 13 Apr 2016 17:22:03 +0300 Subject: [PATCH 0152/2114] Squash a few warnings from IDEA --- .../client/test/functional/ConnectionRecovery.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java index 47304fd6f9..66de974708 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -21,8 +21,9 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; +@SuppressWarnings("ThrowFromFinallyBlock") public class ConnectionRecovery extends BrokerTestCase { - public static final long RECOVERY_INTERVAL = 2000; + private static final long RECOVERY_INTERVAL = 2000; public void testConnectionRecovery() throws IOException, InterruptedException { assertTrue(connection.isOpen()); @@ -226,7 +227,7 @@ public void testClientNamedQueueRecoveryWithNoWait() throws IOException, Interru testClientNamedQueueRecoveryWith("java-client.test.recovery.q1-nowait", true); } - protected void testClientNamedQueueRecoveryWith(String q, boolean noWait) throws IOException, InterruptedException, TimeoutException { + private void testClientNamedQueueRecoveryWith(String q, boolean noWait) throws IOException, InterruptedException, TimeoutException { Channel ch = connection.createChannel(); if(noWait) { declareClientNamedQueueNoWait(ch, q); @@ -793,11 +794,11 @@ private void waitForConfirms(Channel ch) throws InterruptedException, TimeoutExc ch.waitForConfirms(30 * 60 * 1000); } - protected void assertRecordedQueues(Connection conn, int size) { + private void assertRecordedQueues(Connection conn, int size) { assertEquals(size, ((AutorecoveringConnection)conn).getRecordedQueues().size()); } - protected void assertRecordedExchanges(Connection conn, int size) { + private void assertRecordedExchanges(Connection conn, int size) { assertEquals(size, ((AutorecoveringConnection)conn).getRecordedExchanges().size()); } } From 7f3da664c31d1bae6f0784a4c33644fd6105134b Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 13 Apr 2016 18:03:28 +0300 Subject: [PATCH 0153/2114] Test that recovery starts after all connection shutdown hooks have executed Note: we cannot guarantee that they'd have *finished* by the time recovery starts. Provided that ShutdownListeners are typically basic sequential functions, that'll be the case most of the time. Fixes #135 --- .../recovery/AutorecoveringConnection.java | 8 ++++ .../test/functional/ConnectionRecovery.java | 44 +++++++++++++++++-- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index aa28699aed..27dc9b5a3d 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -11,6 +11,7 @@ import com.rabbitmq.client.ShutdownListener; import com.rabbitmq.client.ShutdownSignalException; import com.rabbitmq.client.TopologyRecoveryException; +import com.rabbitmq.client.impl.AMQConnection; import com.rabbitmq.client.impl.ConnectionParams; import com.rabbitmq.client.ExceptionHandler; import com.rabbitmq.client.impl.FrameHandlerFactory; @@ -261,6 +262,13 @@ public void abort(int timeout) { delegate.abort(timeout); } + /** + * Not supposed to be used outside of automated tests. + */ + public AMQConnection getDelegate() { + return delegate; + } + /** * @see com.rabbitmq.client.Connection#getCloseReason() */ diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java index 66de974708..bbf7cd86da 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -1,12 +1,10 @@ package com.rabbitmq.client.test.functional; import com.rabbitmq.client.*; -import com.rabbitmq.client.impl.recovery.AutorecoveringChannel; -import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; +import com.rabbitmq.client.impl.AMQConnection; +import com.rabbitmq.client.impl.recovery.*; import com.rabbitmq.client.Recoverable; import com.rabbitmq.client.RecoveryListener; -import com.rabbitmq.client.impl.recovery.ConsumerRecoveryListener; -import com.rabbitmq.client.impl.recovery.QueueRecoveryListener; import com.rabbitmq.client.test.BrokerTestCase; import com.rabbitmq.tools.Host; @@ -105,6 +103,44 @@ public void testConnectionRecoveryWithDisabledTopologyRecovery() } } + // see https://github.com/rabbitmq/rabbitmq-java-client/issues/135 + public void testThatShutdownHooksOnConnectionFireBeforeRecoveryStarts() throws IOException, InterruptedException { + final List events = new ArrayList(); + final CountDownLatch latch = new CountDownLatch(1); + connection.addShutdownListener(new ShutdownListener() { + public void shutdownCompleted(ShutdownSignalException cause) { + events.add("shutdown hook 1"); + } + }); + connection.addShutdownListener(new ShutdownListener() { + public void shutdownCompleted(ShutdownSignalException cause) { + events.add("shutdown hook 2"); + } + }); + // note: we do not want to expose RecoveryCanBeginListener so this + // test does not use it + ((AutorecoveringConnection)connection).getDelegate().addRecoveryCanBeginListener(new RecoveryCanBeginListener() { + @Override + public void recoveryCanBegin(ShutdownSignalException cause) { + events.add("recovery start hook 1"); + } + }); + ((AutorecoveringConnection)connection).addRecoveryListener(new RecoveryListener() { + @Override + public void handleRecovery(Recoverable recoverable) { + latch.countDown(); + } + }); + assertTrue(connection.isOpen()); + closeAndWaitForRecovery(); + assertTrue(connection.isOpen()); + assertEquals("shutdown hook 1", events.get(0)); + assertEquals("shutdown hook 2", events.get(1)); + assertEquals("recovery start hook 1", events.get(2)); + connection.close(); + wait(latch); + } + public void testShutdownHooksRecoveryOnConnection() throws IOException, InterruptedException { final CountDownLatch latch = new CountDownLatch(2); connection.addShutdownListener(new ShutdownListener() { From 4cd166fa1fd6becf1cd4e20bc9dcbe4425da26be Mon Sep 17 00:00:00 2001 From: nick Date: Thu, 14 Apr 2016 12:28:35 -0700 Subject: [PATCH 0154/2114] interface impl fix --- .../rabbitmq/client/test/functional/ConnectionRecovery.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java index bbf7cd86da..6b32b07d13 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -130,6 +130,10 @@ public void recoveryCanBegin(ShutdownSignalException cause) { public void handleRecovery(Recoverable recoverable) { latch.countDown(); } + @Override + public void handleRecoveryStarted(Recoverable recoverable) { + // todo + } }); assertTrue(connection.isOpen()); closeAndWaitForRecovery(); From eb824ef577b9bb375bfcac2a13fae325fd6a6517 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 15 Apr 2016 21:01:25 +0300 Subject: [PATCH 0155/2114] Bump default TLS version to v1.2 with a fallback for older JDKs Namely JDK 6. --- .../rabbitmq/client/ConnectionFactory.java | 18 ++++++++++-- .../ConnectionFactoryDefaultTlsVersion.java | 29 +++++++++++++++++++ .../rabbitmq/client/test/ssl/SSLTests.java | 3 +- 3 files changed, 46 insertions(+), 4 deletions(-) create mode 100644 src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 3eb7645745..abb52279c5 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -82,8 +82,9 @@ public class ConnectionFactory implements Cloneable { * zero means wait indefinitely */ public static final int DEFAULT_SHUTDOWN_TIMEOUT = 10000; - /** The default SSL protocol */ - private static final String DEFAULT_SSL_PROTOCOL = "TLSv1"; + private static final String PREFERED_TLS_PROTOCOL = "TLSv1.2"; + + private static final String FALLBACK_TLS_PROTOCOL = "TLSv1"; private String username = DEFAULT_USER; private String password = DEFAULT_PASS; @@ -553,7 +554,7 @@ public boolean isSSL(){ public void useSslProtocol() throws NoSuchAlgorithmException, KeyManagementException { - useSslProtocol(DEFAULT_SSL_PROTOCOL); + useSslProtocol(computeDefaultTlsProcotol(SSLContext.getDefault().getSupportedSSLParameters().getProtocols())); } /** @@ -590,6 +591,17 @@ public void useSslProtocol(SSLContext context) { setSocketFactory(context.getSocketFactory()); } + public String computeDefaultTlsProcotol(String [] supportedProtocols) { + if(supportedProtocols != null) { + for (String supportedProtocol : supportedProtocols) { + if(PREFERED_TLS_PROTOCOL.equalsIgnoreCase(supportedProtocol)) { + return supportedProtocol; + } + } + } + return FALLBACK_TLS_PROTOCOL; + } + /** * Returns true if automatic connection recovery * is enabled, false otherwise diff --git a/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java b/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java new file mode 100644 index 0000000000..28247fcdf5 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java @@ -0,0 +1,29 @@ +package com.rabbitmq.client.test.ssl; + +import com.rabbitmq.client.ConnectionFactory; +import junit.framework.TestCase; +import org.junit.Assert; + +public class ConnectionFactoryDefaultTlsVersion extends TestCase { + + private ConnectionFactory connectionFactory = new ConnectionFactory(); + + public void testDefaultTlsVersionJdk16ShouldTakeFallback() { + String [] supportedProtocols = {"SSLv2Hello", "SSLv3", "TLSv1"}; + String tlsProtocol = connectionFactory.computeDefaultTlsProcotol(supportedProtocols); + Assert.assertEquals("TLSv1",tlsProtocol); + } + + public void testDefaultTlsVersionJdk17ShouldTakePrefered() { + String [] supportedProtocols = {"SSLv2Hello", "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2"}; + String tlsProtocol = connectionFactory.computeDefaultTlsProcotol(supportedProtocols); + Assert.assertEquals("TLSv1.2",tlsProtocol); + } + + public void testDefaultTlsVersionJdk18ShouldTakePrefered() { + String [] supportedProtocols = {"SSLv2Hello", "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2"}; + String tlsProtocol = connectionFactory.computeDefaultTlsProcotol(supportedProtocols); + Assert.assertEquals("TLSv1.2",tlsProtocol); + } + +} diff --git a/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java index b3b660dd95..ddc0797bd8 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java @@ -24,7 +24,8 @@ public class SSLTests extends AbstractRMQTestSuite { public static TestSuite suite() { TestSuite suite = new TestSuite("ssl"); - //Skip the tests if not under umbrella and not SSL available + suite.addTestSuite(ConnectionFactoryDefaultTlsVersion.class); + // Skip the tests if not under umbrella and no TLS setup available if (!requiredProperties()) return suite; if (!(isUnderUmbrella() && isSSLAvailable())) return suite; suite.addTestSuite(UnverifiedConnection.class); From 1e437e7e03de7648e0a6d89afc4e88047f12536f Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 15 Apr 2016 21:12:57 +0300 Subject: [PATCH 0156/2114] This method is a pure function => make it static --- src/main/java/com/rabbitmq/client/ConnectionFactory.java | 2 +- .../client/test/ssl/ConnectionFactoryDefaultTlsVersion.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index abb52279c5..52028e23fd 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -591,7 +591,7 @@ public void useSslProtocol(SSLContext context) { setSocketFactory(context.getSocketFactory()); } - public String computeDefaultTlsProcotol(String [] supportedProtocols) { + public static String computeDefaultTlsProcotol(String[] supportedProtocols) { if(supportedProtocols != null) { for (String supportedProtocol : supportedProtocols) { if(PREFERED_TLS_PROTOCOL.equalsIgnoreCase(supportedProtocol)) { diff --git a/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java b/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java index 28247fcdf5..098ff2e187 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java @@ -10,19 +10,19 @@ public class ConnectionFactoryDefaultTlsVersion extends TestCase { public void testDefaultTlsVersionJdk16ShouldTakeFallback() { String [] supportedProtocols = {"SSLv2Hello", "SSLv3", "TLSv1"}; - String tlsProtocol = connectionFactory.computeDefaultTlsProcotol(supportedProtocols); + String tlsProtocol = ConnectionFactory.computeDefaultTlsProcotol(supportedProtocols); Assert.assertEquals("TLSv1",tlsProtocol); } public void testDefaultTlsVersionJdk17ShouldTakePrefered() { String [] supportedProtocols = {"SSLv2Hello", "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2"}; - String tlsProtocol = connectionFactory.computeDefaultTlsProcotol(supportedProtocols); + String tlsProtocol = ConnectionFactory.computeDefaultTlsProcotol(supportedProtocols); Assert.assertEquals("TLSv1.2",tlsProtocol); } public void testDefaultTlsVersionJdk18ShouldTakePrefered() { String [] supportedProtocols = {"SSLv2Hello", "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2"}; - String tlsProtocol = connectionFactory.computeDefaultTlsProcotol(supportedProtocols); + String tlsProtocol = ConnectionFactory.computeDefaultTlsProcotol(supportedProtocols); Assert.assertEquals("TLSv1.2",tlsProtocol); } From 4aa938372198e3c5b52412ae3a3d6b1fb2d1af80 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 15 Apr 2016 23:40:22 +0300 Subject: [PATCH 0157/2114] More test cases for queue.declare --- .../test/functional/QueueLifecycle.java | 31 ++++++++++++++++--- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java b/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java index 735f752ede..ee1ed30a7c 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java @@ -17,16 +17,15 @@ package com.rabbitmq.client.test.functional; +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.QueueingConsumer; +import com.rabbitmq.client.test.BrokerTestCase; + import java.io.IOException; -import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeoutException; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.QueueingConsumer; -import com.rabbitmq.client.test.BrokerTestCase; - /** * Test queue auto-delete and exclusive semantics. */ @@ -177,4 +176,26 @@ public void testQueueNamesLongerThan255Characters() throws IOException { // expected } } + + public void testSingleLineFeedStrippedFromQueueName() throws IOException { + channel.queueDeclare("que\nue_test", false, false, true, null); + verifyQueue(NAME_STRIPPED, false, false, true, null); + } + + public void testMultipleLineFeedsStrippedFromQueueName() throws IOException { + channel.queueDeclare("que\nue_\ntest\n", false, false, true, null); + verifyQueue(NAME_STRIPPED, false, false, true, null); + } + + public void testMultipleLineFeedAndCarriageReturnsStrippedFromQueueName() throws IOException { + channel.queueDeclare("q\ru\ne\r\nue_\ntest\n\r", false, false, true, null); + verifyQueue(NAME_STRIPPED, false, false, true, null); + } + + static final String NAME_STRIPPED = "queue_test"; + + @Override + protected void releaseResources() throws IOException { + channel.queueDelete(NAME_STRIPPED); + } } From 5c518ab3234b47a199530fb9befbb2446cc88694 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Sat, 16 Apr 2016 00:01:20 +0300 Subject: [PATCH 0158/2114] Cover exchange.declare --- .../client/test/functional/ExchangeDeclare.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java index a0039294bb..1a755911a2 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java @@ -36,6 +36,21 @@ public void testExchangeNoArgsEquivalence() throws IOException { verifyEquivalent(NAME, TYPE, false, false, null); } + public void testSingleLineFeedStrippedFromExchangeName() throws IOException { + channel.exchangeDeclare("exchange_test\n", TYPE, false, false, null); + verifyEquivalent(NAME, TYPE, false, false, null); + } + + public void testMultipleLineFeedsStrippedFromExchangeName() throws IOException { + channel.exchangeDeclare("exchange\n_test\n", TYPE, false, false, null); + verifyEquivalent(NAME, TYPE, false, false, null); + } + + public void testMultipleLineFeedAndCarriageReturnsStrippedFromExchangeName() throws IOException { + channel.exchangeDeclare("e\nxc\rhange\n\r_test\n\r", TYPE, false, false, null); + verifyEquivalent(NAME, TYPE, false, false, null); + } + public void testExchangeNonsenseArgsEquivalent() throws IOException { channel.exchangeDeclare(NAME, TYPE, false, false, null); Map args = new HashMap(); From 443d4440e8928bb904ef3bc214b95f42443d26af Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Mon, 18 Apr 2016 01:11:16 +0300 Subject: [PATCH 0159/2114] Naming, docs, cosmetics --- .../java/com/rabbitmq/client/Connection.java | 13 +++-- .../rabbitmq/client/ConnectionFactory.java | 52 ++++++++++++------- .../rabbitmq/client/impl/AMQConnection.java | 9 +--- .../recovery/AutorecoveringConnection.java | 10 ++-- .../client/test/AMQConnectionTest.java | 34 ++++++------ .../test/functional/ConnectionRecovery.java | 4 +- 6 files changed, 72 insertions(+), 50 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/Connection.java b/src/main/java/com/rabbitmq/client/Connection.java index 1809be6e44..8b74ce508f 100644 --- a/src/main/java/com/rabbitmq/client/Connection.java +++ b/src/main/java/com/rabbitmq/client/Connection.java @@ -20,6 +20,7 @@ import java.io.IOException; import java.net.InetAddress; import java.util.Map; +import java.util.concurrent.ExecutorService; /** * Public API: Interface to an AMQ connection. See the see the spec for details. @@ -95,11 +96,17 @@ public interface Connection extends ShutdownNotifier, Closeable { // rename to A Map getClientProperties(); /** - * Get connection name client property value + * Returns client-provided connection name, if any. Note that the value + * returned does not uniquely identify a connection and cannot be used + * as a connection identifier in HTTP API requests. * - * @return string connection name from client properties, or null if there is not such property. + * + * + * @return client-provided connection name, if any + * @see ConnectionFactory#newConnection(Address[], String) + * @see ConnectionFactory#newConnection(ExecutorService, Address[], String) */ - String getConnectionName(); + String getClientProvidedName(); /** * Retrieve the server properties. diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 52028e23fd..60c64ea2a3 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -662,7 +662,7 @@ public Connection newConnection(Address[] addrs) throws IOException, TimeoutExce /** - * Create a new broker connection, picking the first available address from + * Create a new broker connection with a client-provided name, picking the first available address from * the list. * * If automatic connection recovery @@ -670,12 +670,16 @@ public Connection newConnection(Address[] addrs) throws IOException, TimeoutExce * reconnection attempts will pick a random accessible address from the provided list. * * @param addrs an array of known broker addresses (hostname/port pairs) to try in order - * @param connectionName arbitrary sring for connection name client property + * @param clientProvidedName application-specific connection name, will be displayed + * in the management UI if RabbitMQ server supports it. + * This value doesn't have to be unique and cannot be used + * as a connection identifier e.g. in HTTP API requests. + * This value is supposed to be human-readable. * @return an interface to the connection * @throws IOException if it encounters a problem */ - public Connection newConnection(Address[] addrs, String connectionName) throws IOException, TimeoutException { - return newConnection(this.sharedExecutor, Arrays.asList(addrs), connectionName); + public Connection newConnection(Address[] addrs, String clientProvidedName) throws IOException, TimeoutException { + return newConnection(this.sharedExecutor, Arrays.asList(addrs), clientProvidedName); } /** @@ -695,7 +699,7 @@ public Connection newConnection(List
addrs) throws IOException, Timeout } /** - * Create a new broker connection, picking the first available address from + * Create a new broker connection with a client-provided name, picking the first available address from * the list. * * If automatic connection recovery @@ -703,12 +707,16 @@ public Connection newConnection(List
addrs) throws IOException, Timeout * reconnection attempts will pick a random accessible address from the provided list. * * @param addrs a List of known broker addresses (hostname/port pairs) to try in order - * @param connectionName arbitrary sring for connection name client property + * @param clientProvidedName application-specific connection name, will be displayed + * in the management UI if RabbitMQ server supports it. + * This value doesn't have to be unique and cannot be used + * as a connection identifier e.g. in HTTP API requests. + * This value is supposed to be human-readable. * @return an interface to the connection * @throws IOException if it encounters a problem */ - public Connection newConnection(List
addrs, String connectionName) throws IOException, TimeoutException { - return newConnection(this.sharedExecutor, addrs, connectionName); + public Connection newConnection(List
addrs, String clientProvidedName) throws IOException, TimeoutException { + return newConnection(this.sharedExecutor, addrs, clientProvidedName); } /** @@ -731,7 +739,7 @@ public Connection newConnection(ExecutorService executor, Address[] addrs) throw /** - * Create a new broker connection, picking the first available address from + * Create a new broker connection with a client-provided name, picking the first available address from * the list. * * If automatic connection recovery @@ -740,13 +748,17 @@ public Connection newConnection(ExecutorService executor, Address[] addrs) throw * * @param executor thread execution service for consumers on the connection * @param addrs an array of known broker addresses (hostname/port pairs) to try in order - * @param connectionName arbitrary sring for connection name client property + * @param clientProvidedName application-specific connection name, will be displayed + * in the management UI if RabbitMQ server supports it. + * This value doesn't have to be unique and cannot be used + * as a connection identifier e.g. in HTTP API requests. + * This value is supposed to be human-readable. * @return an interface to the connection * @throws java.io.IOException if it encounters a problem * @see Automatic Recovery */ - public Connection newConnection(ExecutorService executor, Address[] addrs, String connectionName) throws IOException, TimeoutException { - return newConnection(executor, Arrays.asList(addrs), connectionName); + public Connection newConnection(ExecutorService executor, Address[] addrs, String clientProvidedName) throws IOException, TimeoutException { + return newConnection(executor, Arrays.asList(addrs), clientProvidedName); } /** @@ -768,7 +780,7 @@ public Connection newConnection(ExecutorService executor, List
addrs) t } /** - * Create a new broker connection, picking the first available address from + * Create a new broker connection with a client-provided name, picking the first available address from * the list. * * If automatic connection recovery @@ -777,20 +789,24 @@ public Connection newConnection(ExecutorService executor, List
addrs) t * * @param executor thread execution service for consumers on the connection * @param addrs a List of known broker addrs (hostname/port pairs) to try in order - * @param connectionName arbitrary sring for connection name client property + * @param clientProvidedName application-specific connection name, will be displayed + * in the management UI if RabbitMQ server supports it. + * This value doesn't have to be unique and cannot be used + * as a connection identifier e.g. in HTTP API requests. + * This value is supposed to be human-readable. * @return an interface to the connection * @throws java.io.IOException if it encounters a problem * @see Automatic Recovery */ - public Connection newConnection(ExecutorService executor, List
addrs, String connectionName) + public Connection newConnection(ExecutorService executor, List
addrs, String clientProvidedName) throws IOException, TimeoutException { // make sure we respect the provided thread factory FrameHandlerFactory fhFactory = createFrameHandlerFactory(); ConnectionParams params = params(executor); - // set connection name client property - if (connectionName != null) { + // set client-provided via a client property + if (clientProvidedName != null) { Map properties = new HashMap(params.getClientProperties()); - properties.put("connection_name", connectionName); + properties.put("connection_name", clientProvidedName); params.setClientProperties(properties); } diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index e0f45fb87e..4f63ed47c1 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -471,13 +471,8 @@ public Map getClientProperties() { return new HashMap(_clientProperties); } - public String getConnectionName() { - Object connectionName = _clientProperties.get("connection_name"); - if (connectionName == null){ - return null; - } else { - return connectionName.toString(); - } + public String getClientProvidedName() { + return (String) _clientProperties.get("connection_name"); } /** diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index 27dc9b5a3d..8505fd65f8 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -5,6 +5,7 @@ import com.rabbitmq.client.BlockedListener; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.MissedHeartbeatException; import com.rabbitmq.client.Recoverable; import com.rabbitmq.client.RecoveryListener; @@ -28,6 +29,7 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeoutException; /** @@ -158,10 +160,12 @@ public Map getClientProperties() { } /** - * @see com.rabbitmq.client.Connection#getConnectionName() + * @see com.rabbitmq.client.Connection#getClientProvidedName() + * @see ConnectionFactory#newConnection(Address[], String) + * @see ConnectionFactory#newConnection(ExecutorService, Address[], String) */ - public String getConnectionName() { - return delegate.getConnectionName(); + public String getClientProvidedName() { + return delegate.getClientProvidedName(); } /** diff --git a/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java b/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java index db650404cb..a267661018 100644 --- a/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java +++ b/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java @@ -177,33 +177,33 @@ public void testConnectionHangInNegotiation() { assertEquals("Wrong type of exception returned.", SocketTimeoutException.class, exceptionList.get(0).getClass()); } - public void testConnectionName() throws IOException, TimeoutException { - String connectionName = "custom name"; - Connection connection = factory.newConnection(connectionName); - assertEquals(connectionName, connection.getConnectionName()); + public void testClientProvidedConnectionName() throws IOException, TimeoutException { + String providedName = "event consumers connection"; + Connection connection = factory.newConnection(providedName); + assertEquals(providedName, connection.getClientProvidedName()); connection.close(); - List
addresses_list = Arrays.asList(new Address("127.0.0.1"), new Address("127.0.0.1", 5672)); - connection = factory.newConnection(addresses_list, connectionName); - assertEquals(connectionName, connection.getConnectionName()); + List
addrs1 = Arrays.asList(new Address("127.0.0.1"), new Address("127.0.0.1", 5672)); + connection = factory.newConnection(addrs1, providedName); + assertEquals(providedName, connection.getClientProvidedName()); connection.close(); - Address[] addresses_arr = {new Address("127.0.0.1"), new Address("127.0.0.1", 5672)}; - connection = factory.newConnection(addresses_arr, connectionName); - assertEquals(connectionName, connection.getConnectionName()); + Address[] addrs2 = {new Address("127.0.0.1"), new Address("127.0.0.1", 5672)}; + connection = factory.newConnection(addrs2, providedName); + assertEquals(providedName, connection.getClientProvidedName()); connection.close(); - ExecutorService executor = Executors.newSingleThreadExecutor(); - connection = factory.newConnection(executor, connectionName); - assertEquals(connectionName, connection.getConnectionName()); + ExecutorService xs = Executors.newSingleThreadExecutor(); + connection = factory.newConnection(xs, providedName); + assertEquals(providedName, connection.getClientProvidedName()); connection.close(); - connection = factory.newConnection(executor, addresses_list, connectionName); - assertEquals(connectionName, connection.getConnectionName()); + connection = factory.newConnection(xs, addrs1, providedName); + assertEquals(providedName, connection.getClientProvidedName()); connection.close(); - connection = factory.newConnection(executor, addresses_arr, connectionName); - assertEquals(connectionName, connection.getConnectionName()); + connection = factory.newConnection(xs, addrs2, providedName); + assertEquals(providedName, connection.getClientProvidedName()); connection.close(); } diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java index 6b32b07d13..9148e3191e 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -35,10 +35,10 @@ public void testNamedConnectionRecovery() AutorecoveringConnection c = newRecoveringConnection(connectionName); try { assertTrue(c.isOpen()); - assertEquals(connectionName, c.getConnectionName()); + assertEquals(connectionName, c.getClientProvidedName()); closeAndWaitForRecovery(c); assertTrue(c.isOpen()); - assertEquals(connectionName, c.getConnectionName()); + assertEquals(connectionName, c.getClientProvidedName()); } finally { c.abort(); } From 6465c026749a33eee7f69c0875ce2c1042047132 Mon Sep 17 00:00:00 2001 From: Daniil Fedotov Date: Wed, 27 Apr 2016 11:03:49 +0100 Subject: [PATCH 0160/2114] Functional test for requeueing of dead-lettered messages and invalid x-death headers --- .../test/functional/DeadLetterExchange.java | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java index 77e1693f46..80e30ca6a5 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java @@ -400,6 +400,79 @@ public void process(GetResponse getResponse) { }); } + public void testRepublish() throws Exception { + Map args = new HashMap(); + args.put("x-message-ttl", 100); + declareQueue(TEST_QUEUE_NAME, DLX, null, args); + channel.queueBind(TEST_QUEUE_NAME, "amq.direct", "test"); + channel.queueBind(DLQ, DLX, "test"); + publishN(1); + + sleep(100); + + GetResponse getResponse = channel.basicGet(DLQ, true); + assertNotNull("Message not dead-lettered", + getResponse); + assertEquals("test message", new String(getResponse.getBody())); + BasicProperties props = getResponse.getProps(); + Map headers = props.getHeaders(); + assertNotNull(headers); + ArrayList death = (ArrayList) headers.get("x-death"); + assertNotNull(death); + assertEquals(1, death.size()); + assertDeathReason(death, 0, TEST_QUEUE_NAME, "expired", "amq.direct", + Arrays.asList("test")); + + // Make queue zero length + args = new HashMap(); + args.put("x-max-length", 0); + channel.queueDelete(TEST_QUEUE_NAME); + declareQueue(TEST_QUEUE_NAME, DLX, null, args); + channel.queueBind(TEST_QUEUE_NAME, "amq.direct", "test"); + + sleep(100); + //Queueing second time with same props + channel.basicPublish("amq.direct", "test", + new AMQP.BasicProperties.Builder() + .headers(headers) + .build(), "test message".getBytes()); + + sleep(100); + + getResponse = channel.basicGet(DLQ, true); + assertNotNull("Message not dead-lettered", getResponse); + assertEquals("test message", new String(getResponse.getBody())); + headers = getResponse.getProps().getHeaders(); + assertNotNull(headers); + death = (ArrayList) headers.get("x-death"); + assertNotNull(death); + assertEquals(2, death.size()); + assertDeathReason(death, 0, TEST_QUEUE_NAME, "maxlen", "amq.direct", + Arrays.asList("test")); + assertDeathReason(death, 1, TEST_QUEUE_NAME, "expired", "amq.direct", + Arrays.asList("test")); + + //Set invalid headers + headers.put("x-death", "[I, am, not, array]"); + channel.basicPublish("amq.direct", "test", + new AMQP.BasicProperties.Builder() + .headers(headers) + .build(), "test message".getBytes()); + sleep(100); + + getResponse = channel.basicGet(DLQ, true); + assertNotNull("Message not dead-lettered", getResponse); + assertEquals("test message", new String(getResponse.getBody())); + headers = getResponse.getProps().getHeaders(); + assertNotNull(headers); + death = (ArrayList) headers.get("x-death"); + assertNotNull(death); + assertEquals(1, death.size()); + assertDeathReason(death, 0, TEST_QUEUE_NAME, "maxlen", "amq.direct", + Arrays.asList("test")); + + } + public void rejectionTest(final boolean useNack) throws Exception { deadLetterTest(new Callable() { public Void call() throws Exception { From 7bb692458340cf7c77d840475ba27c7471ed5d6c Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 27 Apr 2016 16:29:25 -0500 Subject: [PATCH 0161/2114] Supress unchecked warnings for this test --- .../com/rabbitmq/client/test/functional/DeadLetterExchange.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java index 80e30ca6a5..7382f604f2 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java @@ -400,6 +400,7 @@ public void process(GetResponse getResponse) { }); } + @SuppressWarnings("unchecked") public void testRepublish() throws Exception { Map args = new HashMap(); args.put("x-message-ttl", 100); From e1c842d7719ad68d378e733695e30a6044047f18 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 27 May 2016 16:09:54 +0300 Subject: [PATCH 0162/2114] 3.6.2 is avaialble --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f045113d86..dc223b6568 100644 --- a/README.md +++ b/README.md @@ -14,14 +14,14 @@ Maven artifacts are [released to Maven Central](http://search.maven.org/#search% com.rabbitmq amqp-client - 3.6.0 + 3.6.2 ``` ### Gradle ``` groovy -compile 'com.rabbitmq:amqp-client:3.6.0' +compile 'com.rabbitmq:amqp-client:3.6.2' ``` From a4995c4c3f2cbbe08e4d3e332a4ce12e507643ef Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Sat, 28 May 2016 14:22:50 +0300 Subject: [PATCH 0163/2114] Update CONTRIBUTING.md, add CODE_OF_CONDUCT.md --- CODE_OF_CONDUCT.md | 44 ++++++++++++++++++++++++++++++++++++++++++++ CONTRIBUTING.md | 17 ++--------------- 2 files changed, 46 insertions(+), 15 deletions(-) create mode 100644 CODE_OF_CONDUCT.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000..1f6ef1c576 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,44 @@ +# Contributor Code of Conduct + +As contributors and maintainers of this project, and in the interest of fostering an open +and welcoming community, we pledge to respect all people who contribute through reporting +issues, posting feature requests, updating documentation, submitting pull requests or +patches, and other activities. + +We are committed to making participation in this project a harassment-free experience for +everyone, regardless of level of experience, gender, gender identity and expression, +sexual orientation, disability, personal appearance, body size, race, ethnicity, age, +religion, or nationality. + +Examples of unacceptable behavior by participants include: + + * The use of sexualized language or imagery + * Personal attacks + * Trolling or insulting/derogatory comments + * Public or private harassment + * Publishing other's private information, such as physical or electronic addresses, + without explicit permission + * Other unethical or unprofessional conduct + +Project maintainers have the right and responsibility to remove, edit, or reject comments, +commits, code, wiki edits, issues, and other contributions that are not aligned to this +Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors +that they deem inappropriate, threatening, offensive, or harmful. + +By adopting this Code of Conduct, project maintainers commit themselves to fairly and +consistently applying these principles to every aspect of managing this project. Project +maintainers who do not follow or enforce the Code of Conduct may be permanently removed +from the project team. + +This Code of Conduct applies both within project spaces and in public spaces when an +individual is representing the project or its community. + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by +contacting a project maintainer at [info@rabbitmq.com](mailto:info@rabbitmq.com). All complaints will +be reviewed and investigated and will result in a response that is deemed necessary and +appropriate to the circumstances. Maintainers are obligated to maintain confidentiality +with regard to the reporter of an incident. + +This Code of Conduct is adapted from the +[Contributor Covenant](http://contributor-covenant.org), version 1.3.0, available at +[contributor-covenant.org/version/1/3/0/](http://contributor-covenant.org/version/1/3/0/) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 69a4b4a437..45bbcbe62e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -20,22 +20,9 @@ If what you are going to work on is a substantial change, please first ask the c of their opinion on [RabbitMQ mailing list](https://groups.google.com/forum/#!forum/rabbitmq-users). -## (Brief) Code of Conduct +## Code of Conduct -In one line: don't be a dick. - -Be respectful to the maintainers and other contributors. Open source -contributors put long hours into developing projects and doing user -support. Those projects and user support are available for free. We -believe this deserves some respect. - -Be respectful to people of all races, genders, religious beliefs and -political views. Regardless of how brilliant a pull request is -technically, we will not tolerate disrespectful or aggressive -behaviour. - -Contributors who violate this straightforward Code of Conduct will see -their pull requests closed and locked. +See [CODE_OF_CONDUCT.md](./CODE_OF_CONDUCT.md). ## Contributor Agreement From 0937e107837baa3404bce9413315dd170d8d9076 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Sat, 28 May 2016 14:22:50 +0300 Subject: [PATCH 0164/2114] Update CONTRIBUTING.md, add CODE_OF_CONDUCT.md --- CODE_OF_CONDUCT.md | 44 ++++++++++++++++++++++++++++++++++++++++++++ CONTRIBUTING.md | 17 ++--------------- 2 files changed, 46 insertions(+), 15 deletions(-) create mode 100644 CODE_OF_CONDUCT.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000..1f6ef1c576 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,44 @@ +# Contributor Code of Conduct + +As contributors and maintainers of this project, and in the interest of fostering an open +and welcoming community, we pledge to respect all people who contribute through reporting +issues, posting feature requests, updating documentation, submitting pull requests or +patches, and other activities. + +We are committed to making participation in this project a harassment-free experience for +everyone, regardless of level of experience, gender, gender identity and expression, +sexual orientation, disability, personal appearance, body size, race, ethnicity, age, +religion, or nationality. + +Examples of unacceptable behavior by participants include: + + * The use of sexualized language or imagery + * Personal attacks + * Trolling or insulting/derogatory comments + * Public or private harassment + * Publishing other's private information, such as physical or electronic addresses, + without explicit permission + * Other unethical or unprofessional conduct + +Project maintainers have the right and responsibility to remove, edit, or reject comments, +commits, code, wiki edits, issues, and other contributions that are not aligned to this +Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors +that they deem inappropriate, threatening, offensive, or harmful. + +By adopting this Code of Conduct, project maintainers commit themselves to fairly and +consistently applying these principles to every aspect of managing this project. Project +maintainers who do not follow or enforce the Code of Conduct may be permanently removed +from the project team. + +This Code of Conduct applies both within project spaces and in public spaces when an +individual is representing the project or its community. + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by +contacting a project maintainer at [info@rabbitmq.com](mailto:info@rabbitmq.com). All complaints will +be reviewed and investigated and will result in a response that is deemed necessary and +appropriate to the circumstances. Maintainers are obligated to maintain confidentiality +with regard to the reporter of an incident. + +This Code of Conduct is adapted from the +[Contributor Covenant](http://contributor-covenant.org), version 1.3.0, available at +[contributor-covenant.org/version/1/3/0/](http://contributor-covenant.org/version/1/3/0/) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 69a4b4a437..45bbcbe62e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -20,22 +20,9 @@ If what you are going to work on is a substantial change, please first ask the c of their opinion on [RabbitMQ mailing list](https://groups.google.com/forum/#!forum/rabbitmq-users). -## (Brief) Code of Conduct +## Code of Conduct -In one line: don't be a dick. - -Be respectful to the maintainers and other contributors. Open source -contributors put long hours into developing projects and doing user -support. Those projects and user support are available for free. We -believe this deserves some respect. - -Be respectful to people of all races, genders, religious beliefs and -political views. Regardless of how brilliant a pull request is -technically, we will not tolerate disrespectful or aggressive -behaviour. - -Contributors who violate this straightforward Code of Conduct will see -their pull requests closed and locked. +See [CODE_OF_CONDUCT.md](./CODE_OF_CONDUCT.md). ## Contributor Agreement From b5fd47e24f9d70b8de3bcfb4346056ef919e7e9f Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Sun, 29 May 2016 22:34:42 +0300 Subject: [PATCH 0165/2114] Update developer info Sync it with another Java library we'll be open sourcing soon. --- pom.xml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index 5db8422d17..3e9b9e8d0b 100644 --- a/pom.xml +++ b/pom.xml @@ -34,11 +34,10 @@ - rabbitmq.team - The RabbitMQ Team - - Developer - + info@rabbitmq.com + Team RabbitMQ + Pivotal Software, Inc. + https://rabbitmq.com From 9128879d72b9b0a66d68a70f66fc0715a306745b Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Sun, 29 May 2016 22:36:54 +0300 Subject: [PATCH 0166/2114] Re-format pom.xml with 2 spaces --- pom.xml | 128 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/pom.xml b/pom.xml index 3e9b9e8d0b..c784b1d4cd 100644 --- a/pom.xml +++ b/pom.xml @@ -1,76 +1,76 @@ - 4.0.0 - com.rabbitmq - amqp-client - VERSION - jar - RabbitMQ Java Client - RabbitMQ Java client - http://www.rabbitmq.com + 4.0.0 + com.rabbitmq + amqp-client + VERSION + jar + RabbitMQ Java Client + RabbitMQ Java client + http://www.rabbitmq.com - - - ASL 2.0 - http://www.apache.org/licenses/LICENSE-2.0.html - repo - - - GPL v2 - http://www.gnu.org/licenses/gpl-2.0.txt - repo - - - MPL 1.1 - http://www.mozilla.org/MPL/MPL-1.1.txt - repo - - + + + ASL 2.0 + http://www.apache.org/licenses/LICENSE-2.0.html + repo + + + GPL v2 + http://www.gnu.org/licenses/gpl-2.0.txt + repo + + + MPL 1.1 + http://www.mozilla.org/MPL/MPL-1.1.txt + repo + + - - https://github.com/rabbitmq/rabbitmq-java-client.git - scm:git:https://github.com/rabbitmq/rabbitmq-java-client.git - + + https://github.com/rabbitmq/rabbitmq-java-client.git + scm:git:https://github.com/rabbitmq/rabbitmq-java-client.git + - - - info@rabbitmq.com - Team RabbitMQ - Pivotal Software, Inc. - https://rabbitmq.com - - + + + info@rabbitmq.com + Team RabbitMQ + Pivotal Software, Inc. + https://rabbitmq.com + + - + - - commons-cli - commons-cli - 1.1 - test - + + commons-cli + commons-cli + 1.1 + test + - - commons-io - commons-io - 1.2 - test - + + commons-io + commons-io + 1.2 + test + - - junit - junit - 4.12 - test - + + junit + junit + 4.12 + test + - + - - - sonatype-nexus-staging - Nexus Release Repository - http://oss.sonatype.org/service/local/staging/deploy/maven2/ - - + + + sonatype-nexus-staging + Nexus Release Repository + http://oss.sonatype.org/service/local/staging/deploy/maven2/ + + From 73acb41b63860ad20f3b271642242e9788fe28f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 1 Jun 2016 17:05:49 +0200 Subject: [PATCH 0167/2114] Fix typo in constant name Issue #139 --- src/main/java/com/rabbitmq/client/ConnectionFactory.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 60c64ea2a3..0f9f7fbd13 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -82,7 +82,7 @@ public class ConnectionFactory implements Cloneable { * zero means wait indefinitely */ public static final int DEFAULT_SHUTDOWN_TIMEOUT = 10000; - private static final String PREFERED_TLS_PROTOCOL = "TLSv1.2"; + private static final String PREFERRED_TLS_PROTOCOL = "TLSv1.2"; private static final String FALLBACK_TLS_PROTOCOL = "TLSv1"; @@ -594,7 +594,7 @@ public void useSslProtocol(SSLContext context) { public static String computeDefaultTlsProcotol(String[] supportedProtocols) { if(supportedProtocols != null) { for (String supportedProtocol : supportedProtocols) { - if(PREFERED_TLS_PROTOCOL.equalsIgnoreCase(supportedProtocol)) { + if(PREFERRED_TLS_PROTOCOL.equalsIgnoreCase(supportedProtocol)) { return supportedProtocol; } } From 4b547358c15437456d06d281a42b21d1cef437bf Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Mon, 6 Jun 2016 13:12:13 +0300 Subject: [PATCH 0168/2114] Delete resources before re-creating them here --- .../com/rabbitmq/client/test/functional/DeadLetterExchange.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/src/com/rabbitmq/client/test/functional/DeadLetterExchange.java b/test/src/com/rabbitmq/client/test/functional/DeadLetterExchange.java index 7382f604f2..24e1886b9b 100644 --- a/test/src/com/rabbitmq/client/test/functional/DeadLetterExchange.java +++ b/test/src/com/rabbitmq/client/test/functional/DeadLetterExchange.java @@ -34,6 +34,8 @@ public class DeadLetterExchange extends BrokerTestCase { @Override protected void createResources() throws IOException { + channel.exchangeDelete(DLX); + channel.queueDelete(DLQ); channel.exchangeDeclare(DLX, "direct"); channel.queueDeclare(DLQ, false, true, false, null); } From f66240b149ae2a32e27a30181f8eb009b6691df4 Mon Sep 17 00:00:00 2001 From: Diana Corbacho Date: Mon, 27 Jun 2016 11:33:01 +0100 Subject: [PATCH 0169/2114] Test publisher confirms are not blocked by purge of durable queues * Tests rabbitmq-server #854 --- .../rabbitmq/client/test/functional/Confirm.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/src/com/rabbitmq/client/test/functional/Confirm.java b/test/src/com/rabbitmq/client/test/functional/Confirm.java index 24cbbc660b..22cb120740 100644 --- a/test/src/com/rabbitmq/client/test/functional/Confirm.java +++ b/test/src/com/rabbitmq/client/test/functional/Confirm.java @@ -44,6 +44,8 @@ protected void setUp() throws IOException, TimeoutException { super.setUp(); channel.confirmSelect(); channel.queueDeclare("confirm-test", true, true, false, null); + channel.queueDeclare("confirm-durable-nonexclusive", true, false, + false, null); channel.basicConsume("confirm-test", true, new DefaultConsumer(channel)); channel.queueDeclare("confirm-test-nondurable", false, true, @@ -116,6 +118,20 @@ public void testQueuePurge() channel.waitForConfirmsOrDie(); } + /* Tests rabbitmq-server #854 */ + public void testConfirmQueuePurge() + throws IOException, InterruptedException + { + channel.basicQos(1); + for (int i = 0; i < 20000; i++) { + publish("", "confirm-durable-nonexclusive", true, false); + if (i % 100 == 0) { + channel.queuePurge("confirm-durable-nonexclusive"); + } + } + channel.waitForConfirmsOrDie(); + } + public void testBasicReject() throws IOException, InterruptedException { From 3ea9fdb2bd342b4291f264bf36a197967977557d Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Mon, 27 Jun 2016 14:47:31 +0300 Subject: [PATCH 0170/2114] Use 60s timeouts when waiting for confirms --- .../client/test/functional/Confirm.java | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/test/src/com/rabbitmq/client/test/functional/Confirm.java b/test/src/com/rabbitmq/client/test/functional/Confirm.java index 24cbbc660b..cd469e417b 100644 --- a/test/src/com/rabbitmq/client/test/functional/Confirm.java +++ b/test/src/com/rabbitmq/client/test/functional/Confirm.java @@ -97,13 +97,12 @@ public void testMultipleQueues() * internal_sync that notifies the clients. */ public void testQueueDelete() - throws IOException, InterruptedException - { + throws IOException, InterruptedException, TimeoutException { publishN("","confirm-test-noconsumer", true, false); channel.queueDelete("confirm-test-noconsumer"); - channel.waitForConfirmsOrDie(); + channel.waitForConfirmsOrDie(60000); } public void testQueuePurge() @@ -113,7 +112,7 @@ public void testQueuePurge() channel.queuePurge("confirm-test-noconsumer"); - channel.waitForConfirmsOrDie(); + channel.waitForConfirmsOrDie(60000); } public void testBasicReject() @@ -121,7 +120,7 @@ public void testBasicReject() { basicRejectCommon(false); - channel.waitForConfirmsOrDie(); + channel.waitForConfirmsOrDie(60000); } public void testQueueTTL() @@ -133,7 +132,7 @@ public void testQueueTTL() channel.queueDeclare("confirm-ttl", true, true, false, argMap); publishN("", "confirm-ttl", true, false); - channel.waitForConfirmsOrDie(); + channel.waitForConfirmsOrDie(60000); channel.queueDelete("confirm-ttl"); } @@ -150,7 +149,7 @@ public void testBasicRejectRequeue() channel.basicConsume("confirm-test-noconsumer", true, new DefaultConsumer(channel)); - channel.waitForConfirmsOrDie(); + channel.waitForConfirmsOrDie(60000); } public void testBasicRecover() @@ -172,7 +171,7 @@ public void testBasicRecover() channel.basicConsume("confirm-test-noconsumer", true, new DefaultConsumer(channel)); - channel.waitForConfirmsOrDie(); + channel.waitForConfirmsOrDie(60000); } public void testSelect() @@ -224,7 +223,7 @@ public void handleNack(long seqNo, boolean multiple) { publish("", "confirm-test", true, false); } - channel.waitForConfirmsOrDie(); + channel.waitForConfirmsOrDie(60000); if (!unconfirmedSet.isEmpty()) { fail("waitForConfirms returned with unconfirmed messages"); } @@ -237,7 +236,7 @@ public void testWaitForConfirmsWithoutConfirmSelected() // Don't enable Confirm mode publish("", "confirm-test", true, false); try { - channel.waitForConfirms(); + channel.waitForConfirms(60000); fail("waitForConfirms without confirms selected succeeded"); } catch (IllegalStateException _e) {} } @@ -247,7 +246,7 @@ public void testWaitForConfirmsException() publishN("", "confirm-test", true, false); channel.close(); try { - channel.waitForConfirmsOrDie(); + channel.waitForConfirmsOrDie(60000); fail("waitAcks worked on a closed channel"); } catch (ShutdownSignalException sse) { if (!(sse.getReason() instanceof AMQP.Channel.Close)) @@ -265,7 +264,7 @@ public void confirmTest(String exchange, String queueName, { publishN(exchange, queueName, persistent, mandatory); - channel.waitForConfirmsOrDie(); + channel.waitForConfirmsOrDie(60000); } private void publishN(String exchangeName, String queueName, From a485ea14c46ac52af29ed54ecba165becc774432 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Mon, 27 Jun 2016 14:51:31 +0300 Subject: [PATCH 0171/2114] Add timeouts to publisher confirms tests --- .../client/test/functional/Confirm.java | 42 +++++++------------ 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/test/src/com/rabbitmq/client/test/functional/Confirm.java b/test/src/com/rabbitmq/client/test/functional/Confirm.java index ba4af10639..098912773b 100644 --- a/test/src/com/rabbitmq/client/test/functional/Confirm.java +++ b/test/src/com/rabbitmq/client/test/functional/Confirm.java @@ -64,8 +64,7 @@ protected void setUp() throws IOException, TimeoutException { } public void testPersistentMandatoryCombinations() - throws IOException, InterruptedException - { + throws IOException, InterruptedException, TimeoutException { boolean b[] = { false, true }; for (boolean persistent : b) { for (boolean mandatory : b) { @@ -75,21 +74,18 @@ public void testPersistentMandatoryCombinations() } public void testNonDurable() - throws IOException, InterruptedException - { + throws IOException, InterruptedException, TimeoutException { confirmTest("", "confirm-test-nondurable", true, false); } public void testMandatoryNoRoute() - throws IOException, InterruptedException - { + throws IOException, InterruptedException, TimeoutException { confirmTest("", "confirm-test-doesnotexist", false, true); confirmTest("", "confirm-test-doesnotexist", true, true); } public void testMultipleQueues() - throws IOException, InterruptedException - { + throws IOException, InterruptedException, TimeoutException { confirmTest("amq.direct", "confirm-multiple-queues", true, false); } @@ -108,8 +104,7 @@ public void testQueueDelete() } public void testQueuePurge() - throws IOException, InterruptedException - { + throws IOException, InterruptedException, TimeoutException { publishN("", "confirm-test-noconsumer", true, false); channel.queuePurge("confirm-test-noconsumer"); @@ -119,8 +114,7 @@ public void testQueuePurge() /* Tests rabbitmq-server #854 */ public void testConfirmQueuePurge() - throws IOException, InterruptedException - { + throws IOException, InterruptedException, TimeoutException { channel.basicQos(1); for (int i = 0; i < 20000; i++) { publish("", "confirm-durable-nonexclusive", true, false); @@ -128,20 +122,18 @@ public void testConfirmQueuePurge() channel.queuePurge("confirm-durable-nonexclusive"); } } - channel.waitForConfirmsOrDie(); + channel.waitForConfirmsOrDie(90000); } public void testBasicReject() - throws IOException, InterruptedException - { + throws IOException, InterruptedException, TimeoutException { basicRejectCommon(false); channel.waitForConfirmsOrDie(60000); } public void testQueueTTL() - throws IOException, InterruptedException - { + throws IOException, InterruptedException, TimeoutException { for (int ttl : new int[]{ 1, 0 }) { Map argMap = Collections.singletonMap(TTL_ARG, (Object)ttl); @@ -155,8 +147,7 @@ public void testQueueTTL() } public void testBasicRejectRequeue() - throws IOException, InterruptedException - { + throws IOException, InterruptedException, TimeoutException { basicRejectCommon(true); /* wait confirms to go through the broker */ @@ -169,8 +160,7 @@ public void testBasicRejectRequeue() } public void testBasicRecover() - throws IOException, InterruptedException - { + throws IOException, InterruptedException, TimeoutException { publishN("", "confirm-test-noconsumer", true, false); for (long i = 0; i < NUM_MESSAGES; i++) { @@ -213,8 +203,7 @@ public void testSelect() } public void testWaitForConfirms() - throws IOException, InterruptedException - { + throws IOException, InterruptedException, TimeoutException { final SortedSet unconfirmedSet = Collections.synchronizedSortedSet(new TreeSet()); channel.addConfirmListener(new ConfirmListener() { @@ -254,7 +243,9 @@ public void testWaitForConfirmsWithoutConfirmSelected() try { channel.waitForConfirms(60000); fail("waitForConfirms without confirms selected succeeded"); - } catch (IllegalStateException _e) {} + } catch (IllegalStateException _e) {} catch (TimeoutException e) { + e.printStackTrace(); + } } public void testWaitForConfirmsException() @@ -276,8 +267,7 @@ public void testWaitForConfirmsException() /* Publish NUM_MESSAGES messages and wait for confirmations. */ public void confirmTest(String exchange, String queueName, boolean persistent, boolean mandatory) - throws IOException, InterruptedException - { + throws IOException, InterruptedException, TimeoutException { publishN(exchange, queueName, persistent, mandatory); channel.waitForConfirmsOrDie(60000); From b0e897d0f43fc55e3b1bf67c910b8cd9042fac2d Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Mon, 27 Jun 2016 14:58:06 +0300 Subject: [PATCH 0172/2114] Use 60s timeouts when waiting for confirms --- .../client/test/functional/Confirm.java | 37 +++++++------------ 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/test/src/com/rabbitmq/client/test/functional/Confirm.java b/test/src/com/rabbitmq/client/test/functional/Confirm.java index cd469e417b..ab76ea5878 100644 --- a/test/src/com/rabbitmq/client/test/functional/Confirm.java +++ b/test/src/com/rabbitmq/client/test/functional/Confirm.java @@ -62,8 +62,7 @@ protected void setUp() throws IOException, TimeoutException { } public void testPersistentMandatoryCombinations() - throws IOException, InterruptedException - { + throws IOException, InterruptedException, TimeoutException { boolean b[] = { false, true }; for (boolean persistent : b) { for (boolean mandatory : b) { @@ -73,21 +72,18 @@ public void testPersistentMandatoryCombinations() } public void testNonDurable() - throws IOException, InterruptedException - { + throws IOException, InterruptedException, TimeoutException { confirmTest("", "confirm-test-nondurable", true, false); } public void testMandatoryNoRoute() - throws IOException, InterruptedException - { + throws IOException, InterruptedException, TimeoutException { confirmTest("", "confirm-test-doesnotexist", false, true); confirmTest("", "confirm-test-doesnotexist", true, true); } public void testMultipleQueues() - throws IOException, InterruptedException - { + throws IOException, InterruptedException, TimeoutException { confirmTest("amq.direct", "confirm-multiple-queues", true, false); } @@ -106,8 +102,7 @@ public void testQueueDelete() } public void testQueuePurge() - throws IOException, InterruptedException - { + throws IOException, InterruptedException, TimeoutException { publishN("", "confirm-test-noconsumer", true, false); channel.queuePurge("confirm-test-noconsumer"); @@ -116,16 +111,14 @@ public void testQueuePurge() } public void testBasicReject() - throws IOException, InterruptedException - { + throws IOException, InterruptedException, TimeoutException { basicRejectCommon(false); channel.waitForConfirmsOrDie(60000); } public void testQueueTTL() - throws IOException, InterruptedException - { + throws IOException, InterruptedException, TimeoutException { for (int ttl : new int[]{ 1, 0 }) { Map argMap = Collections.singletonMap(TTL_ARG, (Object)ttl); @@ -139,8 +132,7 @@ public void testQueueTTL() } public void testBasicRejectRequeue() - throws IOException, InterruptedException - { + throws IOException, InterruptedException, TimeoutException { basicRejectCommon(true); /* wait confirms to go through the broker */ @@ -153,8 +145,7 @@ public void testBasicRejectRequeue() } public void testBasicRecover() - throws IOException, InterruptedException - { + throws IOException, InterruptedException, TimeoutException { publishN("", "confirm-test-noconsumer", true, false); for (long i = 0; i < NUM_MESSAGES; i++) { @@ -197,8 +188,7 @@ public void testSelect() } public void testWaitForConfirms() - throws IOException, InterruptedException - { + throws IOException, InterruptedException, TimeoutException { final SortedSet unconfirmedSet = Collections.synchronizedSortedSet(new TreeSet()); channel.addConfirmListener(new ConfirmListener() { @@ -238,7 +228,9 @@ public void testWaitForConfirmsWithoutConfirmSelected() try { channel.waitForConfirms(60000); fail("waitForConfirms without confirms selected succeeded"); - } catch (IllegalStateException _e) {} + } catch (IllegalStateException _e) {} catch (TimeoutException e) { + e.printStackTrace(); + } } public void testWaitForConfirmsException() @@ -260,8 +252,7 @@ public void testWaitForConfirmsException() /* Publish NUM_MESSAGES messages and wait for confirmations. */ public void confirmTest(String exchange, String queueName, boolean persistent, boolean mandatory) - throws IOException, InterruptedException - { + throws IOException, InterruptedException, TimeoutException { publishN(exchange, queueName, persistent, mandatory); channel.waitForConfirmsOrDie(60000); From faa0fa85c8fcb0d4f5a08d8a2a6f0dbcd78525ab Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 15 Apr 2016 21:01:25 +0300 Subject: [PATCH 0173/2114] Bump default TLS version to v1.2 with a fallback for older JDKs Namely JDK 6. --- .../rabbitmq/client/ConnectionFactory.java | 18 ++++++++++-- .../ConnectionFactoryDefaultTlsVersion.java | 29 +++++++++++++++++++ .../rabbitmq/client/test/ssl/SSLTests.java | 4 +++ 3 files changed, 48 insertions(+), 3 deletions(-) create mode 100644 src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java diff --git a/src/com/rabbitmq/client/ConnectionFactory.java b/src/com/rabbitmq/client/ConnectionFactory.java index 599de713c0..8bc8c59218 100644 --- a/src/com/rabbitmq/client/ConnectionFactory.java +++ b/src/com/rabbitmq/client/ConnectionFactory.java @@ -82,8 +82,9 @@ public class ConnectionFactory implements Cloneable { * zero means wait indefinitely */ public static final int DEFAULT_SHUTDOWN_TIMEOUT = 10000; - /** The default SSL protocol */ - private static final String DEFAULT_SSL_PROTOCOL = "TLSv1"; + private static final String PREFERED_TLS_PROTOCOL = "TLSv1.2"; + + private static final String FALLBACK_TLS_PROTOCOL = "TLSv1"; private String username = DEFAULT_USER; private String password = DEFAULT_PASS; @@ -553,7 +554,7 @@ public boolean isSSL(){ public void useSslProtocol() throws NoSuchAlgorithmException, KeyManagementException { - useSslProtocol(DEFAULT_SSL_PROTOCOL); + useSslProtocol(computeDefaultTlsProcotol(SSLContext.getDefault().getSupportedSSLParameters().getProtocols())); } /** @@ -590,6 +591,17 @@ public void useSslProtocol(SSLContext context) { setSocketFactory(context.getSocketFactory()); } + public String computeDefaultTlsProcotol(String [] supportedProtocols) { + if(supportedProtocols != null) { + for (String supportedProtocol : supportedProtocols) { + if(PREFERED_TLS_PROTOCOL.equalsIgnoreCase(supportedProtocol)) { + return supportedProtocol; + } + } + } + return FALLBACK_TLS_PROTOCOL; + } + /** * Returns true if automatic connection recovery * is enabled, false otherwise diff --git a/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java b/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java new file mode 100644 index 0000000000..28247fcdf5 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java @@ -0,0 +1,29 @@ +package com.rabbitmq.client.test.ssl; + +import com.rabbitmq.client.ConnectionFactory; +import junit.framework.TestCase; +import org.junit.Assert; + +public class ConnectionFactoryDefaultTlsVersion extends TestCase { + + private ConnectionFactory connectionFactory = new ConnectionFactory(); + + public void testDefaultTlsVersionJdk16ShouldTakeFallback() { + String [] supportedProtocols = {"SSLv2Hello", "SSLv3", "TLSv1"}; + String tlsProtocol = connectionFactory.computeDefaultTlsProcotol(supportedProtocols); + Assert.assertEquals("TLSv1",tlsProtocol); + } + + public void testDefaultTlsVersionJdk17ShouldTakePrefered() { + String [] supportedProtocols = {"SSLv2Hello", "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2"}; + String tlsProtocol = connectionFactory.computeDefaultTlsProcotol(supportedProtocols); + Assert.assertEquals("TLSv1.2",tlsProtocol); + } + + public void testDefaultTlsVersionJdk18ShouldTakePrefered() { + String [] supportedProtocols = {"SSLv2Hello", "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2"}; + String tlsProtocol = connectionFactory.computeDefaultTlsProcotol(supportedProtocols); + Assert.assertEquals("TLSv1.2",tlsProtocol); + } + +} diff --git a/test/src/com/rabbitmq/client/test/ssl/SSLTests.java b/test/src/com/rabbitmq/client/test/ssl/SSLTests.java index 611df1ec40..fc71651b17 100644 --- a/test/src/com/rabbitmq/client/test/ssl/SSLTests.java +++ b/test/src/com/rabbitmq/client/test/ssl/SSLTests.java @@ -23,6 +23,10 @@ public class SSLTests extends TestCase { public static TestSuite suite() { TestSuite suite = new TestSuite("ssl"); + suite.addTestSuite(ConnectionFactoryDefaultTlsVersion.class); + // Skip the tests if not under umbrella and no TLS setup available + if (!requiredProperties()) return suite; + if (!(isUnderUmbrella() && isSSLAvailable())) return suite; suite.addTestSuite(UnverifiedConnection.class); suite.addTestSuite(VerifiedConnection.class); suite.addTestSuite(BadVerifiedConnection.class); From 40500f21202469bc0200b3feb1e5fb0dfaa44fd4 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 15 Apr 2016 21:12:57 +0300 Subject: [PATCH 0174/2114] This method is a pure function => make it static --- src/com/rabbitmq/client/ConnectionFactory.java | 2 +- .../client/test/ssl/ConnectionFactoryDefaultTlsVersion.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/com/rabbitmq/client/ConnectionFactory.java b/src/com/rabbitmq/client/ConnectionFactory.java index 8bc8c59218..60c64ea2a3 100644 --- a/src/com/rabbitmq/client/ConnectionFactory.java +++ b/src/com/rabbitmq/client/ConnectionFactory.java @@ -591,7 +591,7 @@ public void useSslProtocol(SSLContext context) { setSocketFactory(context.getSocketFactory()); } - public String computeDefaultTlsProcotol(String [] supportedProtocols) { + public static String computeDefaultTlsProcotol(String[] supportedProtocols) { if(supportedProtocols != null) { for (String supportedProtocol : supportedProtocols) { if(PREFERED_TLS_PROTOCOL.equalsIgnoreCase(supportedProtocol)) { diff --git a/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java b/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java index 28247fcdf5..098ff2e187 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java @@ -10,19 +10,19 @@ public class ConnectionFactoryDefaultTlsVersion extends TestCase { public void testDefaultTlsVersionJdk16ShouldTakeFallback() { String [] supportedProtocols = {"SSLv2Hello", "SSLv3", "TLSv1"}; - String tlsProtocol = connectionFactory.computeDefaultTlsProcotol(supportedProtocols); + String tlsProtocol = ConnectionFactory.computeDefaultTlsProcotol(supportedProtocols); Assert.assertEquals("TLSv1",tlsProtocol); } public void testDefaultTlsVersionJdk17ShouldTakePrefered() { String [] supportedProtocols = {"SSLv2Hello", "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2"}; - String tlsProtocol = connectionFactory.computeDefaultTlsProcotol(supportedProtocols); + String tlsProtocol = ConnectionFactory.computeDefaultTlsProcotol(supportedProtocols); Assert.assertEquals("TLSv1.2",tlsProtocol); } public void testDefaultTlsVersionJdk18ShouldTakePrefered() { String [] supportedProtocols = {"SSLv2Hello", "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2"}; - String tlsProtocol = connectionFactory.computeDefaultTlsProcotol(supportedProtocols); + String tlsProtocol = ConnectionFactory.computeDefaultTlsProcotol(supportedProtocols); Assert.assertEquals("TLSv1.2",tlsProtocol); } From e6eb118bc30c38d8cfbfe0fe7423eaad87b342ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 1 Jun 2016 17:05:49 +0200 Subject: [PATCH 0175/2114] Fix typo in constant name Issue #139 --- src/com/rabbitmq/client/ConnectionFactory.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/com/rabbitmq/client/ConnectionFactory.java b/src/com/rabbitmq/client/ConnectionFactory.java index 60c64ea2a3..0f9f7fbd13 100644 --- a/src/com/rabbitmq/client/ConnectionFactory.java +++ b/src/com/rabbitmq/client/ConnectionFactory.java @@ -82,7 +82,7 @@ public class ConnectionFactory implements Cloneable { * zero means wait indefinitely */ public static final int DEFAULT_SHUTDOWN_TIMEOUT = 10000; - private static final String PREFERED_TLS_PROTOCOL = "TLSv1.2"; + private static final String PREFERRED_TLS_PROTOCOL = "TLSv1.2"; private static final String FALLBACK_TLS_PROTOCOL = "TLSv1"; @@ -594,7 +594,7 @@ public void useSslProtocol(SSLContext context) { public static String computeDefaultTlsProcotol(String[] supportedProtocols) { if(supportedProtocols != null) { for (String supportedProtocol : supportedProtocols) { - if(PREFERED_TLS_PROTOCOL.equalsIgnoreCase(supportedProtocol)) { + if(PREFERRED_TLS_PROTOCOL.equalsIgnoreCase(supportedProtocol)) { return supportedProtocol; } } From 6eed7ca72a60ae54d084fa9eeda0052b63f5c5b1 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 13 Jul 2016 16:46:03 +0300 Subject: [PATCH 0176/2114] These helpers are only available in master --- test/src/com/rabbitmq/client/test/ssl/SSLTests.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/src/com/rabbitmq/client/test/ssl/SSLTests.java b/test/src/com/rabbitmq/client/test/ssl/SSLTests.java index fc71651b17..2fccc6ab3b 100644 --- a/test/src/com/rabbitmq/client/test/ssl/SSLTests.java +++ b/test/src/com/rabbitmq/client/test/ssl/SSLTests.java @@ -24,9 +24,6 @@ public class SSLTests extends TestCase { public static TestSuite suite() { TestSuite suite = new TestSuite("ssl"); suite.addTestSuite(ConnectionFactoryDefaultTlsVersion.class); - // Skip the tests if not under umbrella and no TLS setup available - if (!requiredProperties()) return suite; - if (!(isUnderUmbrella() && isSSLAvailable())) return suite; suite.addTestSuite(UnverifiedConnection.class); suite.addTestSuite(VerifiedConnection.class); suite.addTestSuite(BadVerifiedConnection.class); From d220ddc67d38a853e87dde3cba04cc7eb2c0d4a9 Mon Sep 17 00:00:00 2001 From: kjnilsson Date: Thu, 14 Jul 2016 17:28:16 +0100 Subject: [PATCH 0177/2114] improve the resilience of some integration tests --- .../client/test/functional/DeadLetterExchange.java | 2 +- .../com/rabbitmq/client/test/server/MessageRecovery.java | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java index 24e1886b9b..63a4476145 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java @@ -411,7 +411,7 @@ public void testRepublish() throws Exception { channel.queueBind(DLQ, DLX, "test"); publishN(1); - sleep(100); + sleep(200); GetResponse getResponse = channel.basicGet(DLQ, true); assertNotNull("Message not dead-lettered", diff --git a/src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java b/src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java index 24d5ff01c4..6f4e9b0ae2 100644 --- a/src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java @@ -30,6 +30,8 @@ public class MessageRecovery extends ConfirmBase public void testMessageRecovery() throws Exception { + channel.queueDelete(Q); + channel.queueDelete(Q2); channel.confirmSelect(); channel.queueDeclare(Q, true, false, false, null); channel.basicPublish("", Q, false, false, @@ -45,11 +47,13 @@ public void testMessageRecovery() // a promoted slave and will have its redelivered flag // set. But that only happens if there actually *is* a // slave. We test that by passively declaring, and - // subsequently deletign, the secondary, non-durable queue, + // subsequently deleting, the secondary, non-durable queue, // which only succeeds if the queue survived the restart, // which in turn implies that it must have been a HA queue // with slave(s). - boolean expectDelivered = false; + // NB: this wont work when running against a single node broker + // and running the test individually outside of the HA suite + boolean expectDelivered = HATests.HA_TESTS_RUNNING; try { channel.queueDeclarePassive(Q2); channel.queueDelete(Q2); @@ -60,6 +64,7 @@ public void testMessageRecovery() } assertDelivered(Q, 1, expectDelivered); channel.queueDelete(Q); + channel.queueDelete(Q2); } } From c6f85cb6be04c7c8c0a206a49bbc3d5651948f27 Mon Sep 17 00:00:00 2001 From: kjnilsson Date: Fri, 15 Jul 2016 09:07:26 +0100 Subject: [PATCH 0178/2114] try to run integration tests without the umbrella --- .../client/test/functional/FunctionalTests.java | 17 ++++------------- .../rabbitmq/client/test/server/HATests.java | 1 - .../client/test/server/ServerTests.java | 1 - .../com/rabbitmq/client/test/ssl/SSLTests.java | 4 ++-- 4 files changed, 6 insertions(+), 17 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java b/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java index c44138e940..0a74510412 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java +++ b/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java @@ -28,7 +28,6 @@ public class FunctionalTests extends AbstractRMQTestSuite { public static TestSuite suite() { TestSuite suite = new TestSuite("functional"); if (!requiredProperties()) return suite; - if (!isUnderUmbrella()) return suite; add(suite); return suite; } @@ -67,25 +66,17 @@ public static void add(TestSuite suite) { suite.addTestSuite(ConsumerCancelNotification.class); suite.addTestSuite(UnexpectedFrames.class); suite.addTestSuite(PerQueueTTL.class); - //needs rabbitmqctl - if (isUnderUmbrella()) { - suite.addTestSuite(PerMessageTTL.class); - suite.addTestSuite(PerQueueVsPerMessageTTL.class); - } + suite.addTestSuite(PerMessageTTL.class); + suite.addTestSuite(PerQueueVsPerMessageTTL.class); suite.addTestSuite(DeadLetterExchange.class); suite.addTestSuite(SaslMechanisms.class); - //needs rabbitmqctl - if (isUnderUmbrella()) suite.addTestSuite(UserIDHeader.class); suite.addTestSuite(InternalExchange.class); suite.addTestSuite(CcRoutes.class); suite.addTestSuite(WorkPoolTests.class); suite.addTestSuite(HeadersExchangeValidation.class); suite.addTestSuite(ConsumerPriorities.class); - //needs rabbitmqctl - if (isUnderUmbrella()) { - suite.addTestSuite(Policies.class); - suite.addTestSuite(ConnectionRecovery.class); - } + suite.addTestSuite(Policies.class); + suite.addTestSuite(ConnectionRecovery.class); suite.addTestSuite(ExceptionHandling.class); suite.addTestSuite(PerConsumerPrefetch.class); suite.addTestSuite(DirectReplyTo.class); diff --git a/src/test/java/com/rabbitmq/client/test/server/HATests.java b/src/test/java/com/rabbitmq/client/test/server/HATests.java index 5a9226addf..460e10a8bc 100644 --- a/src/test/java/com/rabbitmq/client/test/server/HATests.java +++ b/src/test/java/com/rabbitmq/client/test/server/HATests.java @@ -30,7 +30,6 @@ public class HATests extends AbstractRMQTestSuite { public static TestSuite suite() { TestSuite suite = new TestSuite("server-tests"); if (!requiredProperties()) return suite; - if (!isUnderUmbrella()) return suite; suite.addTestSuite(SetUp.class); FunctionalTests.add(suite); ServerTests.add(suite); diff --git a/src/test/java/com/rabbitmq/client/test/server/ServerTests.java b/src/test/java/com/rabbitmq/client/test/server/ServerTests.java index 4e77517cb0..e4c0768d2a 100644 --- a/src/test/java/com/rabbitmq/client/test/server/ServerTests.java +++ b/src/test/java/com/rabbitmq/client/test/server/ServerTests.java @@ -27,7 +27,6 @@ public class ServerTests extends AbstractRMQTestSuite { public static TestSuite suite() { TestSuite suite = new TestSuite("server-tests"); if (!requiredProperties()) return suite; - if (!isUnderUmbrella()) return suite; add(suite); return suite; } diff --git a/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java index ea28df5061..c75b92b940 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java @@ -24,10 +24,10 @@ public class SSLTests extends AbstractRMQTestSuite { public static TestSuite suite() { TestSuite suite = new TestSuite("ssl"); + suite.addTestSuite(ConnectionFactoryDefaultTlsVersion.class); // Skip the tests if not under umbrella and no TLS setup available if (!requiredProperties()) return suite; - if (!(isUnderUmbrella() && isSSLAvailable())) return suite; - suite.addTestSuite(ConnectionFactoryDefaultTlsVersion.class); + if (!isSSLAvailable()) return suite; suite.addTestSuite(UnverifiedConnection.class); suite.addTestSuite(VerifiedConnection.class); suite.addTestSuite(BadVerifiedConnection.class); From 812cefdd2eec4ed4343be58fa1b429439f78a453 Mon Sep 17 00:00:00 2001 From: kjnilsson Date: Thu, 14 Jul 2016 17:28:16 +0100 Subject: [PATCH 0179/2114] improve the resilience of some integration tests --- .../client/test/functional/DeadLetterExchange.java | 2 +- .../com/rabbitmq/client/test/server/MessageRecovery.java | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/test/src/com/rabbitmq/client/test/functional/DeadLetterExchange.java b/test/src/com/rabbitmq/client/test/functional/DeadLetterExchange.java index 24e1886b9b..63a4476145 100644 --- a/test/src/com/rabbitmq/client/test/functional/DeadLetterExchange.java +++ b/test/src/com/rabbitmq/client/test/functional/DeadLetterExchange.java @@ -411,7 +411,7 @@ public void testRepublish() throws Exception { channel.queueBind(DLQ, DLX, "test"); publishN(1); - sleep(100); + sleep(200); GetResponse getResponse = channel.basicGet(DLQ, true); assertNotNull("Message not dead-lettered", diff --git a/test/src/com/rabbitmq/client/test/server/MessageRecovery.java b/test/src/com/rabbitmq/client/test/server/MessageRecovery.java index 271c4c3bed..c163f1bb85 100644 --- a/test/src/com/rabbitmq/client/test/server/MessageRecovery.java +++ b/test/src/com/rabbitmq/client/test/server/MessageRecovery.java @@ -31,6 +31,8 @@ public class MessageRecovery extends ConfirmBase public void testMessageRecovery() throws Exception { + channel.queueDelete(Q); + channel.queueDelete(Q2); channel.confirmSelect(); channel.queueDeclare(Q, true, false, false, null); channel.basicPublish("", Q, false, false, @@ -46,11 +48,13 @@ public void testMessageRecovery() // a promoted slave and will have its redelivered flag // set. But that only happens if there actually *is* a // slave. We test that by passively declaring, and - // subsequently deletign, the secondary, non-durable queue, + // subsequently deleting, the secondary, non-durable queue, // which only succeeds if the queue survived the restart, // which in turn implies that it must have been a HA queue // with slave(s). - boolean expectDelivered = false; + // NB: this wont work when running against a single node broker + // and running the test individually outside of the HA suite + boolean expectDelivered = HATests.HA_TESTS_RUNNING; try { channel.queueDeclarePassive(Q2); channel.queueDelete(Q2); @@ -61,6 +65,7 @@ public void testMessageRecovery() } assertDelivered(Q, 1, expectDelivered); channel.queueDelete(Q); + channel.queueDelete(Q2); } } From 61dde69a9332fdc8a4f0b14bf9a6519fe0613bea Mon Sep 17 00:00:00 2001 From: Andrew Bruce Date: Tue, 26 Jul 2016 17:30:17 +0100 Subject: [PATCH 0180/2114] Update license / copyright headers [#127089993] --- codegen.py | 45 +++++++++---------- src/com/rabbitmq/client/Address.java | 23 +++++----- .../client/AlreadyClosedException.java | 23 +++++----- .../AuthenticationFailureException.java | 23 +++++----- src/com/rabbitmq/client/BasicProperties.java | 23 +++++----- src/com/rabbitmq/client/BlockedListener.java | 23 +++++----- src/com/rabbitmq/client/Channel.java | 23 +++++----- src/com/rabbitmq/client/Command.java | 23 +++++----- src/com/rabbitmq/client/ConfirmListener.java | 23 +++++----- src/com/rabbitmq/client/Connection.java | 23 +++++----- .../rabbitmq/client/ConnectionFactory.java | 23 +++++----- src/com/rabbitmq/client/Consumer.java | 23 +++++----- .../client/ConsumerCancelledException.java | 23 +++++----- src/com/rabbitmq/client/ContentHeader.java | 23 +++++----- src/com/rabbitmq/client/DefaultConsumer.java | 23 +++++----- .../rabbitmq/client/DefaultSaslConfig.java | 23 +++++----- .../client/DefaultSocketConfigurator.java | 15 +++++++ src/com/rabbitmq/client/Envelope.java | 23 +++++----- src/com/rabbitmq/client/ExceptionHandler.java | 23 +++++----- src/com/rabbitmq/client/FlowListener.java | 23 +++++----- src/com/rabbitmq/client/GetResponse.java | 23 +++++----- src/com/rabbitmq/client/JDKSaslConfig.java | 23 +++++----- src/com/rabbitmq/client/LongString.java | 23 +++++----- .../client/MalformedFrameException.java | 23 +++++----- src/com/rabbitmq/client/MapRpcServer.java | 23 +++++----- .../rabbitmq/client/MessageProperties.java | 23 +++++----- src/com/rabbitmq/client/Method.java | 23 +++++----- .../client/MissedHeartbeatException.java | 23 +++++----- src/com/rabbitmq/client/NullTrustManager.java | 23 +++++----- ...ossibleAuthenticationFailureException.java | 23 +++++----- .../ProtocolVersionMismatchException.java | 23 +++++----- src/com/rabbitmq/client/QueueingConsumer.java | 23 +++++----- src/com/rabbitmq/client/Recoverable.java | 15 +++++++ src/com/rabbitmq/client/RecoveryListener.java | 15 +++++++ src/com/rabbitmq/client/ReturnListener.java | 23 +++++----- src/com/rabbitmq/client/RpcClient.java | 23 +++++----- src/com/rabbitmq/client/RpcServer.java | 23 +++++----- src/com/rabbitmq/client/SaslConfig.java | 23 +++++----- src/com/rabbitmq/client/SaslMechanism.java | 23 +++++----- src/com/rabbitmq/client/ShutdownListener.java | 23 +++++----- src/com/rabbitmq/client/ShutdownNotifier.java | 23 +++++----- .../client/ShutdownSignalException.java | 23 +++++----- .../rabbitmq/client/SocketConfigurator.java | 15 +++++++ src/com/rabbitmq/client/StringRpcServer.java | 23 +++++----- .../client/TopologyRecoveryException.java | 15 +++++++ .../rabbitmq/client/UnexpectedFrameError.java | 23 +++++----- .../client/UnexpectedMethodError.java | 23 +++++----- .../client/UnknownClassOrMethodId.java | 23 +++++----- .../client/impl/AMQBasicProperties.java | 23 +++++----- src/com/rabbitmq/client/impl/AMQChannel.java | 23 +++++----- src/com/rabbitmq/client/impl/AMQCommand.java | 23 +++++----- .../rabbitmq/client/impl/AMQConnection.java | 23 +++++----- .../client/impl/AMQContentHeader.java | 23 +++++----- .../rabbitmq/client/impl/CRDemoMechanism.java | 23 +++++----- .../rabbitmq/client/impl/ChannelManager.java | 23 +++++----- src/com/rabbitmq/client/impl/ChannelN.java | 23 +++++----- .../client/impl/ClientVersion.java.in | 23 +++++----- .../client/impl/CommandAssembler.java | 23 +++++----- .../client/impl/ConnectionParams.java | 15 +++++++ .../client/impl/ConsumerDispatcher.java | 22 ++++----- .../client/impl/ConsumerWorkService.java | 22 ++++----- .../impl/ContentHeaderPropertyReader.java | 23 +++++----- .../impl/ContentHeaderPropertyWriter.java | 23 +++++----- .../client/impl/DefaultExceptionHandler.java | 23 +++++----- src/com/rabbitmq/client/impl/Environment.java | 15 +++++++ .../client/impl/ExternalMechanism.java | 23 +++++----- .../impl/ForgivingExceptionHandler.java | 23 +++++----- src/com/rabbitmq/client/impl/Frame.java | 23 +++++----- .../rabbitmq/client/impl/FrameHandler.java | 23 +++++----- .../client/impl/FrameHandlerFactory.java | 15 +++++++ .../rabbitmq/client/impl/HeartbeatSender.java | 23 +++++----- .../client/impl/LongStringHelper.java | 23 +++++----- src/com/rabbitmq/client/impl/Method.java | 23 +++++----- .../client/impl/MethodArgumentReader.java | 23 +++++----- .../client/impl/MethodArgumentWriter.java | 23 +++++----- .../client/impl/NetworkConnection.java | 15 +++++++ .../rabbitmq/client/impl/PlainMechanism.java | 23 +++++----- src/com/rabbitmq/client/impl/SetQueue.java | 15 +++++++ .../impl/ShutdownNotifierComponent.java | 23 +++++----- .../client/impl/SocketFrameHandler.java | 23 +++++----- .../client/impl/StrictExceptionHandler.java | 23 +++++----- .../client/impl/TruncatedInputStream.java | 23 +++++----- .../client/impl/UnknownChannelException.java | 23 +++++----- src/com/rabbitmq/client/impl/ValueReader.java | 23 +++++----- src/com/rabbitmq/client/impl/ValueWriter.java | 23 +++++----- .../impl/VariableLinkedBlockingQueue.java | 15 +++++++ src/com/rabbitmq/client/impl/Version.java | 23 +++++----- src/com/rabbitmq/client/impl/WorkPool.java | 15 +++++++ .../impl/recovery/AutorecoveringChannel.java | 15 +++++++ .../recovery/AutorecoveringConnection.java | 15 +++++++ .../recovery/ConsumerRecoveryListener.java | 15 +++++++ .../impl/recovery/QueueRecoveryListener.java | 15 +++++++ .../client/impl/recovery/RecordedBinding.java | 15 +++++++ .../impl/recovery/RecordedConsumer.java | 15 +++++++ .../client/impl/recovery/RecordedEntity.java | 15 +++++++ .../impl/recovery/RecordedExchange.java | 15 +++++++ .../recovery/RecordedExchangeBinding.java | 15 +++++++ .../impl/recovery/RecordedNamedEntity.java | 15 +++++++ .../client/impl/recovery/RecordedQueue.java | 15 +++++++ .../impl/recovery/RecordedQueueBinding.java | 15 +++++++ .../recovery/RecoveryAwareAMQConnection.java | 15 +++++++ .../RecoveryAwareAMQConnectionFactory.java | 15 +++++++ .../recovery/RecoveryAwareChannelManager.java | 15 +++++++ .../impl/recovery/RecoveryAwareChannelN.java | 15 +++++++ src/com/rabbitmq/tools/Tracer.java | 23 +++++----- src/com/rabbitmq/tools/json/JSONReader.java | 15 +++++++ .../rabbitmq/tools/json/JSONSerializable.java | 23 +++++----- src/com/rabbitmq/tools/json/JSONUtil.java | 23 +++++----- src/com/rabbitmq/tools/json/JSONWriter.java | 15 +++++++ .../rabbitmq/tools/jsonrpc/JsonRpcClient.java | 23 +++++----- .../tools/jsonrpc/JsonRpcException.java | 23 +++++----- .../rabbitmq/tools/jsonrpc/JsonRpcServer.java | 23 +++++----- .../tools/jsonrpc/ParameterDescription.java | 23 +++++----- .../tools/jsonrpc/ProcedureDescription.java | 23 +++++----- .../tools/jsonrpc/ServiceDescription.java | 23 +++++----- src/com/rabbitmq/utility/BlockingCell.java | 23 +++++----- .../utility/BlockingValueOrException.java | 23 +++++----- src/com/rabbitmq/utility/IntAllocator.java | 23 +++++----- src/com/rabbitmq/utility/SensibleClone.java | 23 +++++----- .../utility/SingleShotLinearTimer.java | 23 +++++----- src/com/rabbitmq/utility/Utility.java | 23 +++++----- .../rabbitmq/utility/ValueOrException.java | 23 +++++----- .../ConnectionFactoryDefaultTlsVersion.java | 15 +++++++ .../rabbitmq/client/impl/WorkPoolTests.java | 15 +++++++ .../client/test/AMQBuilderApiTest.java | 24 +++++----- .../client/test/AMQConnectionTest.java | 23 +++++----- .../com/rabbitmq/client/test/AmqpUriTest.java | 24 +++++----- .../client/test/BlockingCellTest.java | 23 +++++----- .../client/test/BrokenFramesTest.java | 23 +++++----- .../rabbitmq/client/test/BrokerTestCase.java | 23 +++++----- .../rabbitmq/client/test/Bug20004Test.java | 23 +++++----- .../test/ChannelNumberAllocationTests.java | 23 +++++----- .../com/rabbitmq/client/test/ClientTests.java | 23 +++++----- .../client/test/ClonePropertiesTest.java | 23 +++++----- .../rabbitmq/client/test/CloseInMainLoop.java | 23 +++++----- .../com/rabbitmq/client/test/ConfirmBase.java | 23 +++++----- .../client/test/JSONReadWriteTest.java | 23 +++++----- .../rabbitmq/client/test/LongStringTest.java | 15 +++++++ .../client/test/MultiThreadedChannel.java | 23 +++++----- .../test/QueueingConsumerShutdownTests.java | 23 +++++----- .../client/test/SharedThreadPoolTest.java | 15 +++++++ .../com/rabbitmq/client/test/TableTest.java | 23 +++++----- .../client/test/TruncatedInputStreamTest.java | 23 +++++----- .../client/test/ValueOrExceptionTest.java | 23 +++++----- .../test/functional/AbstractRejectTest.java | 23 +++++----- .../test/functional/AlternateExchange.java | 23 +++++----- .../client/test/functional/BasicGet.java | 15 +++++++ .../test/functional/BindingLifecycle.java | 23 +++++----- .../test/functional/BindingLifecycleBase.java | 23 +++++----- .../client/test/functional/CcRoutes.java | 23 +++++----- .../test/functional/ClusteredTestBase.java | 23 +++++----- .../client/test/functional/Confirm.java | 23 +++++----- .../test/functional/ConnectionOpen.java | 23 +++++----- .../test/functional/ConnectionRecovery.java | 15 +++++++ .../ConsumerCancelNotification.java | 23 +++++----- .../client/test/functional/ConsumerCount.java | 15 +++++++ .../test/functional/ConsumerPriorities.java | 15 +++++++ .../test/functional/DeadLetterExchange.java | 15 +++++++ .../test/functional/DefaultExchange.java | 23 +++++----- .../client/test/functional/DirectReplyTo.java | 15 +++++++ .../test/functional/DoubleDeletion.java | 23 +++++----- .../test/functional/DurableOnTransient.java | 23 +++++----- .../test/functional/ExceptionHandling.java | 15 +++++++ .../test/functional/ExceptionMessages.java | 15 +++++++ .../test/functional/ExchangeDeclare.java | 23 +++++----- .../functional/ExchangeDeleteIfUnused.java | 23 +++++----- .../functional/ExchangeDeletePredeclared.java | 15 +++++++ .../functional/ExchangeEquivalenceBase.java | 23 +++++----- .../functional/ExchangeExchangeBindings.java | 23 +++++----- .../ExchangeExchangeBindingsAutoDelete.java | 23 +++++----- .../client/test/functional/FrameMax.java | 23 +++++----- .../test/functional/FunctionalTests.java | 23 +++++----- .../functional/HeadersExchangeValidation.java | 15 +++++++ .../client/test/functional/Heartbeat.java | 23 +++++----- .../test/functional/InternalExchange.java | 23 +++++----- .../client/test/functional/InvalidAcks.java | 23 +++++----- .../test/functional/InvalidAcksBase.java | 23 +++++----- .../client/test/functional/InvalidAcksTx.java | 23 +++++----- .../client/test/functional/MessageCount.java | 15 +++++++ .../rabbitmq/client/test/functional/Nack.java | 23 +++++----- .../test/functional/NoRequeueOnCancel.java | 23 +++++----- .../client/test/functional/Nowait.java | 15 +++++++ .../test/functional/PerConsumerPrefetch.java | 15 +++++++ .../client/test/functional/PerMessageTTL.java | 23 +++++----- .../client/test/functional/PerQueueTTL.java | 23 +++++----- .../functional/PerQueueVsPerMessageTTL.java | 15 +++++++ .../client/test/functional/Policies.java | 23 +++++----- .../client/test/functional/QosTests.java | 23 +++++----- .../test/functional/QueueExclusivity.java | 23 +++++----- .../client/test/functional/QueueLease.java | 23 +++++----- .../test/functional/QueueLifecycle.java | 23 +++++----- .../test/functional/QueueSizeLimit.java | 23 +++++----- .../client/test/functional/Recover.java | 23 +++++----- .../client/test/functional/Reject.java | 23 +++++----- .../functional/RequeueOnChannelClose.java | 23 +++++----- .../test/functional/RequeueOnClose.java | 23 +++++----- .../functional/RequeueOnConnectionClose.java | 23 +++++----- .../client/test/functional/Routing.java | 23 +++++----- .../test/functional/SaslMechanisms.java | 23 +++++----- .../client/test/functional/TTLHandling.java | 15 +++++++ .../client/test/functional/Tables.java | 23 +++++----- .../client/test/functional/Transactions.java | 23 +++++----- .../functional/UnbindAutoDeleteExchange.java | 23 +++++----- .../test/functional/UnexpectedFrames.java | 23 +++++----- .../client/test/functional/UserIDHeader.java | 23 +++++----- .../client/test/performance/CLIHelper.java | 23 +++++----- .../client/test/performance/QosScaling.java | 23 +++++----- .../test/performance/ScalabilityTest.java | 23 +++++----- .../test/performance/StressManagement.java | 23 +++++----- .../client/test/server/AbsentQueue.java | 23 +++++----- .../server/AlternateExchangeEquivalence.java | 23 +++++----- .../client/test/server/BlockedConnection.java | 23 +++++----- .../client/test/server/Bug19219Test.java | 23 +++++----- .../test/server/ChannelLimitNegotiation.java | 15 +++++++ .../server/DeadLetterExchangeDurable.java | 15 +++++++ .../test/server/DurableBindingLifecycle.java | 23 +++++----- .../server/EffectVisibilityCrossNodeTest.java | 23 +++++----- .../test/server/ExclusiveQueueDurability.java | 23 +++++----- .../rabbitmq/client/test/server/Firehose.java | 15 +++++++ .../rabbitmq/client/test/server/HATests.java | 23 +++++----- .../client/test/server/LoopbackUsers.java | 15 +++++++ .../client/test/server/MemoryAlarms.java | 23 +++++----- .../client/test/server/MessageRecovery.java | 22 ++++----- .../client/test/server/Permissions.java | 23 +++++----- .../test/server/PersistenceGuarantees.java | 15 +++++++ .../client/test/server/PriorityQueues.java | 15 +++++++ .../client/test/server/ServerTests.java | 23 +++++----- .../rabbitmq/client/test/server/Shutdown.java | 15 +++++++ .../test/server/XDeathHeaderGrowth.java | 15 +++++++ .../test/ssl/BadVerifiedConnection.java | 23 +++++----- .../rabbitmq/client/test/ssl/SSLTests.java | 23 +++++----- .../client/test/ssl/UnverifiedConnection.java | 23 +++++----- .../client/test/ssl/VerifiedConnection.java | 23 +++++----- .../examples/BufferPerformanceMetrics.java | 23 +++++----- .../examples/ChannelCreationPerformance.java | 23 +++++----- .../examples/ConfirmDontLoseMessages.java | 23 +++++----- .../com/rabbitmq/examples/ConsumerMain.java | 23 +++++----- .../examples/DirectReplyToPerformance.java | 15 +++++++ .../com/rabbitmq/examples/FileConsumer.java | 23 +++++----- .../com/rabbitmq/examples/FileProducer.java | 23 +++++----- .../com/rabbitmq/examples/HelloClient.java | 23 +++++----- .../rabbitmq/examples/HelloJsonClient.java | 23 +++++----- .../rabbitmq/examples/HelloJsonServer.java | 23 +++++----- .../rabbitmq/examples/HelloJsonService.java | 23 +++++----- .../com/rabbitmq/examples/HelloServer.java | 23 +++++----- test/src/com/rabbitmq/examples/LogTail.java | 23 +++++----- .../com/rabbitmq/examples/MulticastMain.java | 23 +++++----- .../rabbitmq/examples/PerQueueTTLGetter.java | 23 +++++----- .../examples/PerQueueTTLPublisher.java | 23 +++++----- test/src/com/rabbitmq/examples/PerfTest.java | 23 +++++----- .../com/rabbitmq/examples/PerfTestMulti.java | 23 +++++----- .../com/rabbitmq/examples/ProducerMain.java | 23 +++++----- .../src/com/rabbitmq/examples/SendString.java | 23 +++++----- .../com/rabbitmq/examples/SimpleConsumer.java | 23 +++++----- .../com/rabbitmq/examples/SimpleProducer.java | 23 +++++----- .../examples/SimpleTopicConsumer.java | 23 +++++----- .../examples/SimpleTopicProducer.java | 23 +++++----- .../examples/SpammyTopicProducer.java | 23 +++++----- .../rabbitmq/examples/StressPersister.java | 23 +++++----- test/src/com/rabbitmq/examples/TestMain.java | 23 +++++----- .../examples/TracerConcurrencyTest.java | 23 +++++----- .../com/rabbitmq/examples/perf/Broker.java | 23 +++++----- .../rabbitmq/examples/perf/BrokerValue.java | 23 +++++----- .../examples/perf/BrokerVariable.java | 23 +++++----- .../com/rabbitmq/examples/perf/Consumer.java | 23 +++++----- .../examples/perf/MulticastParams.java | 23 +++++----- .../rabbitmq/examples/perf/MulticastSet.java | 23 +++++----- .../examples/perf/MulticastValue.java | 23 +++++----- .../examples/perf/MulticastVariable.java | 23 +++++----- .../com/rabbitmq/examples/perf/PerfUtil.java | 15 +++++++ .../com/rabbitmq/examples/perf/Producer.java | 23 +++++----- .../examples/perf/ProducerConsumerBase.java | 15 +++++++ .../examples/perf/RateVsLatencyScenario.java | 23 +++++----- .../com/rabbitmq/examples/perf/Scenario.java | 23 +++++----- .../examples/perf/ScenarioFactory.java | 15 +++++++ .../rabbitmq/examples/perf/ScenarioStats.java | 23 +++++----- .../examples/perf/SimpleScenario.java | 23 +++++----- .../examples/perf/SimpleScenarioStats.java | 23 +++++----- .../src/com/rabbitmq/examples/perf/Stats.java | 23 +++++----- .../com/rabbitmq/examples/perf/Variable.java | 23 +++++----- .../rabbitmq/examples/perf/VariableValue.java | 23 +++++----- .../examples/perf/VaryingScenario.java | 23 +++++----- .../examples/perf/VaryingScenarioStats.java | 23 +++++----- test/src/com/rabbitmq/tools/Host.java | 23 +++++----- .../rabbitmq/utility/IntAllocatorTests.java | 23 +++++----- 285 files changed, 3390 insertions(+), 2698 deletions(-) diff --git a/codegen.py b/codegen.py index 7d6955e74d..b9e1af0c99 100755 --- a/codegen.py +++ b/codegen.py @@ -1,20 +1,19 @@ #!/usr/bin/env python -## The contents of this file are subject to the Mozilla Public License -## Version 1.1 (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.mozilla.org/MPL/ +## Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. ## -## Software distributed under the License is distributed on an "AS IS" -## basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -## the License for the specific language governing rights and -## limitations under the License. +## This software, the RabbitMQ Java client library, is triple-licensed under the +## Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +## ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +## LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +## please see LICENSE-APACHE2. ## -## The Original Code is RabbitMQ. -## -## The Initial Developer of the Original Code is GoPivotal, Inc. -## Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +## This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +## either express or implied. See the LICENSE file for specific language governing +## rights and limitations of this software. ## +## If you have any questions regarding licensing, please contact us at +## info@rabbitmq.com. from __future__ import nested_scopes from __future__ import print_function @@ -134,20 +133,20 @@ def printFileHeader(): print("""// NOTE: This -*- java -*- source code is autogenerated from the AMQP // specification! // -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. // """) diff --git a/src/com/rabbitmq/client/Address.java b/src/com/rabbitmq/client/Address.java index f9ff0ad0cc..a0ebf8372d 100644 --- a/src/com/rabbitmq/client/Address.java +++ b/src/com/rabbitmq/client/Address.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/AlreadyClosedException.java b/src/com/rabbitmq/client/AlreadyClosedException.java index 21956dd58e..06cca515ac 100644 --- a/src/com/rabbitmq/client/AlreadyClosedException.java +++ b/src/com/rabbitmq/client/AlreadyClosedException.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/AuthenticationFailureException.java b/src/com/rabbitmq/client/AuthenticationFailureException.java index ceb5e85a62..998bddd2a1 100644 --- a/src/com/rabbitmq/client/AuthenticationFailureException.java +++ b/src/com/rabbitmq/client/AuthenticationFailureException.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2013-2015 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/BasicProperties.java b/src/com/rabbitmq/client/BasicProperties.java index 1ac3028126..2dc7150cd1 100644 --- a/src/com/rabbitmq/client/BasicProperties.java +++ b/src/com/rabbitmq/client/BasicProperties.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/BlockedListener.java b/src/com/rabbitmq/client/BlockedListener.java index ea30383f6f..70a2fdffae 100644 --- a/src/com/rabbitmq/client/BlockedListener.java +++ b/src/com/rabbitmq/client/BlockedListener.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/Channel.java b/src/com/rabbitmq/client/Channel.java index 36ba7d1d0c..bf7c7f002c 100644 --- a/src/com/rabbitmq/client/Channel.java +++ b/src/com/rabbitmq/client/Channel.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/Command.java b/src/com/rabbitmq/client/Command.java index 3a863ddb8c..b6c0e349a0 100644 --- a/src/com/rabbitmq/client/Command.java +++ b/src/com/rabbitmq/client/Command.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/ConfirmListener.java b/src/com/rabbitmq/client/ConfirmListener.java index dca66c539e..4c8f21b092 100644 --- a/src/com/rabbitmq/client/ConfirmListener.java +++ b/src/com/rabbitmq/client/ConfirmListener.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/Connection.java b/src/com/rabbitmq/client/Connection.java index 27d21d1f6a..c26d5f1dec 100644 --- a/src/com/rabbitmq/client/Connection.java +++ b/src/com/rabbitmq/client/Connection.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/ConnectionFactory.java b/src/com/rabbitmq/client/ConnectionFactory.java index 0f9f7fbd13..645ff774f5 100644 --- a/src/com/rabbitmq/client/ConnectionFactory.java +++ b/src/com/rabbitmq/client/ConnectionFactory.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/Consumer.java b/src/com/rabbitmq/client/Consumer.java index e4bdf4fc8e..e0a5f3ab0e 100644 --- a/src/com/rabbitmq/client/Consumer.java +++ b/src/com/rabbitmq/client/Consumer.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/ConsumerCancelledException.java b/src/com/rabbitmq/client/ConsumerCancelledException.java index 1c8e2adfda..552eeb1445 100644 --- a/src/com/rabbitmq/client/ConsumerCancelledException.java +++ b/src/com/rabbitmq/client/ConsumerCancelledException.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/ContentHeader.java b/src/com/rabbitmq/client/ContentHeader.java index 4c005491de..36e2ec29d2 100644 --- a/src/com/rabbitmq/client/ContentHeader.java +++ b/src/com/rabbitmq/client/ContentHeader.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/DefaultConsumer.java b/src/com/rabbitmq/client/DefaultConsumer.java index cb87aef8f7..a2b05b8b8a 100644 --- a/src/com/rabbitmq/client/DefaultConsumer.java +++ b/src/com/rabbitmq/client/DefaultConsumer.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/DefaultSaslConfig.java b/src/com/rabbitmq/client/DefaultSaslConfig.java index 5aabf6d6b8..75e05147d6 100644 --- a/src/com/rabbitmq/client/DefaultSaslConfig.java +++ b/src/com/rabbitmq/client/DefaultSaslConfig.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/DefaultSocketConfigurator.java b/src/com/rabbitmq/client/DefaultSocketConfigurator.java index ec99b4145b..0ae347fcac 100644 --- a/src/com/rabbitmq/client/DefaultSocketConfigurator.java +++ b/src/com/rabbitmq/client/DefaultSocketConfigurator.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client; import java.io.IOException; diff --git a/src/com/rabbitmq/client/Envelope.java b/src/com/rabbitmq/client/Envelope.java index 4edec670dc..3a83a05058 100644 --- a/src/com/rabbitmq/client/Envelope.java +++ b/src/com/rabbitmq/client/Envelope.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/ExceptionHandler.java b/src/com/rabbitmq/client/ExceptionHandler.java index e8cc0f5e07..958bb1c5df 100644 --- a/src/com/rabbitmq/client/ExceptionHandler.java +++ b/src/com/rabbitmq/client/ExceptionHandler.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/FlowListener.java b/src/com/rabbitmq/client/FlowListener.java index 10ba13244a..de6461ebc2 100644 --- a/src/com/rabbitmq/client/FlowListener.java +++ b/src/com/rabbitmq/client/FlowListener.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/GetResponse.java b/src/com/rabbitmq/client/GetResponse.java index e3dbc1bcbd..f6980304d6 100644 --- a/src/com/rabbitmq/client/GetResponse.java +++ b/src/com/rabbitmq/client/GetResponse.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/JDKSaslConfig.java b/src/com/rabbitmq/client/JDKSaslConfig.java index 454e3c9e5e..3dde4ef093 100644 --- a/src/com/rabbitmq/client/JDKSaslConfig.java +++ b/src/com/rabbitmq/client/JDKSaslConfig.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/LongString.java b/src/com/rabbitmq/client/LongString.java index 205b53d720..a8942c1537 100644 --- a/src/com/rabbitmq/client/LongString.java +++ b/src/com/rabbitmq/client/LongString.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/MalformedFrameException.java b/src/com/rabbitmq/client/MalformedFrameException.java index 86369eba0e..2d63e5b961 100644 --- a/src/com/rabbitmq/client/MalformedFrameException.java +++ b/src/com/rabbitmq/client/MalformedFrameException.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/MapRpcServer.java b/src/com/rabbitmq/client/MapRpcServer.java index 1226480bad..32ac62311d 100644 --- a/src/com/rabbitmq/client/MapRpcServer.java +++ b/src/com/rabbitmq/client/MapRpcServer.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/MessageProperties.java b/src/com/rabbitmq/client/MessageProperties.java index bf5aaa77c0..4ba9b40e17 100644 --- a/src/com/rabbitmq/client/MessageProperties.java +++ b/src/com/rabbitmq/client/MessageProperties.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/Method.java b/src/com/rabbitmq/client/Method.java index bd046b4869..93715c0cce 100644 --- a/src/com/rabbitmq/client/Method.java +++ b/src/com/rabbitmq/client/Method.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/MissedHeartbeatException.java b/src/com/rabbitmq/client/MissedHeartbeatException.java index 87e5c029ff..90e8cdb83a 100644 --- a/src/com/rabbitmq/client/MissedHeartbeatException.java +++ b/src/com/rabbitmq/client/MissedHeartbeatException.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/NullTrustManager.java b/src/com/rabbitmq/client/NullTrustManager.java index 0242995a8a..850b1bffcc 100644 --- a/src/com/rabbitmq/client/NullTrustManager.java +++ b/src/com/rabbitmq/client/NullTrustManager.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/PossibleAuthenticationFailureException.java b/src/com/rabbitmq/client/PossibleAuthenticationFailureException.java index e069b65df7..bbb053d611 100644 --- a/src/com/rabbitmq/client/PossibleAuthenticationFailureException.java +++ b/src/com/rabbitmq/client/PossibleAuthenticationFailureException.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/ProtocolVersionMismatchException.java b/src/com/rabbitmq/client/ProtocolVersionMismatchException.java index 258a0a8f54..7b031b9621 100644 --- a/src/com/rabbitmq/client/ProtocolVersionMismatchException.java +++ b/src/com/rabbitmq/client/ProtocolVersionMismatchException.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/QueueingConsumer.java b/src/com/rabbitmq/client/QueueingConsumer.java index 07bdaea4f3..221bf69302 100644 --- a/src/com/rabbitmq/client/QueueingConsumer.java +++ b/src/com/rabbitmq/client/QueueingConsumer.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/Recoverable.java b/src/com/rabbitmq/client/Recoverable.java index e91166a3a9..6e22fbff44 100644 --- a/src/com/rabbitmq/client/Recoverable.java +++ b/src/com/rabbitmq/client/Recoverable.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client; /** diff --git a/src/com/rabbitmq/client/RecoveryListener.java b/src/com/rabbitmq/client/RecoveryListener.java index 88b0ece2e5..62e278b5ae 100644 --- a/src/com/rabbitmq/client/RecoveryListener.java +++ b/src/com/rabbitmq/client/RecoveryListener.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client; /** diff --git a/src/com/rabbitmq/client/ReturnListener.java b/src/com/rabbitmq/client/ReturnListener.java index 68512c2b1a..b06a7beea7 100644 --- a/src/com/rabbitmq/client/ReturnListener.java +++ b/src/com/rabbitmq/client/ReturnListener.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/RpcClient.java b/src/com/rabbitmq/client/RpcClient.java index 379e36178c..362a80d2a2 100644 --- a/src/com/rabbitmq/client/RpcClient.java +++ b/src/com/rabbitmq/client/RpcClient.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/RpcServer.java b/src/com/rabbitmq/client/RpcServer.java index 6704de8ad7..6f9210a096 100644 --- a/src/com/rabbitmq/client/RpcServer.java +++ b/src/com/rabbitmq/client/RpcServer.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/SaslConfig.java b/src/com/rabbitmq/client/SaslConfig.java index 78b7e11ff6..1db18614dc 100644 --- a/src/com/rabbitmq/client/SaslConfig.java +++ b/src/com/rabbitmq/client/SaslConfig.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/SaslMechanism.java b/src/com/rabbitmq/client/SaslMechanism.java index e3c9aa2a45..08aeefdbd0 100644 --- a/src/com/rabbitmq/client/SaslMechanism.java +++ b/src/com/rabbitmq/client/SaslMechanism.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/ShutdownListener.java b/src/com/rabbitmq/client/ShutdownListener.java index 29c668c636..bd7904e1be 100644 --- a/src/com/rabbitmq/client/ShutdownListener.java +++ b/src/com/rabbitmq/client/ShutdownListener.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/ShutdownNotifier.java b/src/com/rabbitmq/client/ShutdownNotifier.java index 09ea608662..ebd551a1c0 100644 --- a/src/com/rabbitmq/client/ShutdownNotifier.java +++ b/src/com/rabbitmq/client/ShutdownNotifier.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/ShutdownSignalException.java b/src/com/rabbitmq/client/ShutdownSignalException.java index d6d757166a..fb53c771fb 100644 --- a/src/com/rabbitmq/client/ShutdownSignalException.java +++ b/src/com/rabbitmq/client/ShutdownSignalException.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/SocketConfigurator.java b/src/com/rabbitmq/client/SocketConfigurator.java index ca553a1ed7..8896baf3e5 100644 --- a/src/com/rabbitmq/client/SocketConfigurator.java +++ b/src/com/rabbitmq/client/SocketConfigurator.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client; import java.io.IOException; diff --git a/src/com/rabbitmq/client/StringRpcServer.java b/src/com/rabbitmq/client/StringRpcServer.java index 112fc6aaee..1032d83724 100644 --- a/src/com/rabbitmq/client/StringRpcServer.java +++ b/src/com/rabbitmq/client/StringRpcServer.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/TopologyRecoveryException.java b/src/com/rabbitmq/client/TopologyRecoveryException.java index c220ab09e5..e2cb4dfdf8 100644 --- a/src/com/rabbitmq/client/TopologyRecoveryException.java +++ b/src/com/rabbitmq/client/TopologyRecoveryException.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client; /** diff --git a/src/com/rabbitmq/client/UnexpectedFrameError.java b/src/com/rabbitmq/client/UnexpectedFrameError.java index 3e0fe28070..ee6d0d8f86 100644 --- a/src/com/rabbitmq/client/UnexpectedFrameError.java +++ b/src/com/rabbitmq/client/UnexpectedFrameError.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/UnexpectedMethodError.java b/src/com/rabbitmq/client/UnexpectedMethodError.java index d930a93635..af49cea646 100644 --- a/src/com/rabbitmq/client/UnexpectedMethodError.java +++ b/src/com/rabbitmq/client/UnexpectedMethodError.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/UnknownClassOrMethodId.java b/src/com/rabbitmq/client/UnknownClassOrMethodId.java index 273d0b27bd..adcaff628d 100644 --- a/src/com/rabbitmq/client/UnknownClassOrMethodId.java +++ b/src/com/rabbitmq/client/UnknownClassOrMethodId.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client; diff --git a/src/com/rabbitmq/client/impl/AMQBasicProperties.java b/src/com/rabbitmq/client/impl/AMQBasicProperties.java index e792c55c0e..35e2507b0c 100644 --- a/src/com/rabbitmq/client/impl/AMQBasicProperties.java +++ b/src/com/rabbitmq/client/impl/AMQBasicProperties.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/AMQChannel.java b/src/com/rabbitmq/client/impl/AMQChannel.java index 900447b1f7..ced9d6e05a 100644 --- a/src/com/rabbitmq/client/impl/AMQChannel.java +++ b/src/com/rabbitmq/client/impl/AMQChannel.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/AMQCommand.java b/src/com/rabbitmq/client/impl/AMQCommand.java index bbf60e2c63..7dcbc369ad 100644 --- a/src/com/rabbitmq/client/impl/AMQCommand.java +++ b/src/com/rabbitmq/client/impl/AMQCommand.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/AMQConnection.java b/src/com/rabbitmq/client/impl/AMQConnection.java index ee6b0054a7..9fba8064b0 100644 --- a/src/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/com/rabbitmq/client/impl/AMQConnection.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/AMQContentHeader.java b/src/com/rabbitmq/client/impl/AMQContentHeader.java index 74154d7334..76c2d4ff37 100644 --- a/src/com/rabbitmq/client/impl/AMQContentHeader.java +++ b/src/com/rabbitmq/client/impl/AMQContentHeader.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/CRDemoMechanism.java b/src/com/rabbitmq/client/impl/CRDemoMechanism.java index 90cf8d827c..1ad424ab32 100644 --- a/src/com/rabbitmq/client/impl/CRDemoMechanism.java +++ b/src/com/rabbitmq/client/impl/CRDemoMechanism.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/ChannelManager.java b/src/com/rabbitmq/client/impl/ChannelManager.java index bb855b2148..314a8fe60a 100644 --- a/src/com/rabbitmq/client/impl/ChannelManager.java +++ b/src/com/rabbitmq/client/impl/ChannelManager.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/ChannelN.java b/src/com/rabbitmq/client/impl/ChannelN.java index 18d4802fa2..01151f794e 100644 --- a/src/com/rabbitmq/client/impl/ChannelN.java +++ b/src/com/rabbitmq/client/impl/ChannelN.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/ClientVersion.java.in b/src/com/rabbitmq/client/impl/ClientVersion.java.in index cfe8961345..f9b2a800eb 100644 --- a/src/com/rabbitmq/client/impl/ClientVersion.java.in +++ b/src/com/rabbitmq/client/impl/ClientVersion.java.in @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/CommandAssembler.java b/src/com/rabbitmq/client/impl/CommandAssembler.java index 3a75459782..c909b5a9ce 100644 --- a/src/com/rabbitmq/client/impl/CommandAssembler.java +++ b/src/com/rabbitmq/client/impl/CommandAssembler.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/ConnectionParams.java b/src/com/rabbitmq/client/impl/ConnectionParams.java index 9114d81a95..d13e6facc9 100644 --- a/src/com/rabbitmq/client/impl/ConnectionParams.java +++ b/src/com/rabbitmq/client/impl/ConnectionParams.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.impl; import com.rabbitmq.client.ExceptionHandler; diff --git a/src/com/rabbitmq/client/impl/ConsumerDispatcher.java b/src/com/rabbitmq/client/impl/ConsumerDispatcher.java index f5bf62b6e1..62c95f8d25 100644 --- a/src/com/rabbitmq/client/impl/ConsumerDispatcher.java +++ b/src/com/rabbitmq/client/impl/ConsumerDispatcher.java @@ -1,17 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2011-2015 Pivotal Software, Inc. All rights reserved. +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/ConsumerWorkService.java b/src/com/rabbitmq/client/impl/ConsumerWorkService.java index a38c63e0c2..6cbfa07239 100644 --- a/src/com/rabbitmq/client/impl/ConsumerWorkService.java +++ b/src/com/rabbitmq/client/impl/ConsumerWorkService.java @@ -1,17 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2011-2015 Pivotal Software, Inc. All rights reserved. +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java b/src/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java index febbbf603a..42e2d964ea 100644 --- a/src/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java +++ b/src/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java b/src/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java index a77f3f6793..1d22f9daa2 100644 --- a/src/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java +++ b/src/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/DefaultExceptionHandler.java b/src/com/rabbitmq/client/impl/DefaultExceptionHandler.java index 476e02376b..8183a9f296 100644 --- a/src/com/rabbitmq/client/impl/DefaultExceptionHandler.java +++ b/src/com/rabbitmq/client/impl/DefaultExceptionHandler.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/Environment.java b/src/com/rabbitmq/client/impl/Environment.java index a387b195a0..8a3b8c8420 100644 --- a/src/com/rabbitmq/client/impl/Environment.java +++ b/src/com/rabbitmq/client/impl/Environment.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.impl; import java.util.concurrent.ThreadFactory; diff --git a/src/com/rabbitmq/client/impl/ExternalMechanism.java b/src/com/rabbitmq/client/impl/ExternalMechanism.java index c57a2f0d0e..8232129798 100644 --- a/src/com/rabbitmq/client/impl/ExternalMechanism.java +++ b/src/com/rabbitmq/client/impl/ExternalMechanism.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/ForgivingExceptionHandler.java b/src/com/rabbitmq/client/impl/ForgivingExceptionHandler.java index 6305b1591f..af0f376713 100644 --- a/src/com/rabbitmq/client/impl/ForgivingExceptionHandler.java +++ b/src/com/rabbitmq/client/impl/ForgivingExceptionHandler.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/Frame.java b/src/com/rabbitmq/client/impl/Frame.java index 89d9abd952..db1463ba69 100644 --- a/src/com/rabbitmq/client/impl/Frame.java +++ b/src/com/rabbitmq/client/impl/Frame.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/FrameHandler.java b/src/com/rabbitmq/client/impl/FrameHandler.java index 3f0d5f540a..65e20c2091 100644 --- a/src/com/rabbitmq/client/impl/FrameHandler.java +++ b/src/com/rabbitmq/client/impl/FrameHandler.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/FrameHandlerFactory.java b/src/com/rabbitmq/client/impl/FrameHandlerFactory.java index dc95fac7e9..4590f41bad 100644 --- a/src/com/rabbitmq/client/impl/FrameHandlerFactory.java +++ b/src/com/rabbitmq/client/impl/FrameHandlerFactory.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.impl; import com.rabbitmq.client.Address; diff --git a/src/com/rabbitmq/client/impl/HeartbeatSender.java b/src/com/rabbitmq/client/impl/HeartbeatSender.java index 698e5b7445..6660fb0ff5 100644 --- a/src/com/rabbitmq/client/impl/HeartbeatSender.java +++ b/src/com/rabbitmq/client/impl/HeartbeatSender.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/LongStringHelper.java b/src/com/rabbitmq/client/impl/LongStringHelper.java index d2bee15697..6842faa4ba 100644 --- a/src/com/rabbitmq/client/impl/LongStringHelper.java +++ b/src/com/rabbitmq/client/impl/LongStringHelper.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/Method.java b/src/com/rabbitmq/client/impl/Method.java index 0b4ea70054..8bfee2fab2 100644 --- a/src/com/rabbitmq/client/impl/Method.java +++ b/src/com/rabbitmq/client/impl/Method.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/MethodArgumentReader.java b/src/com/rabbitmq/client/impl/MethodArgumentReader.java index 44d9ca42c6..e61ffc5380 100644 --- a/src/com/rabbitmq/client/impl/MethodArgumentReader.java +++ b/src/com/rabbitmq/client/impl/MethodArgumentReader.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/MethodArgumentWriter.java b/src/com/rabbitmq/client/impl/MethodArgumentWriter.java index 8afe6d73a9..139f9eb5ea 100644 --- a/src/com/rabbitmq/client/impl/MethodArgumentWriter.java +++ b/src/com/rabbitmq/client/impl/MethodArgumentWriter.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/NetworkConnection.java b/src/com/rabbitmq/client/impl/NetworkConnection.java index ec12df8ca5..281e36f892 100644 --- a/src/com/rabbitmq/client/impl/NetworkConnection.java +++ b/src/com/rabbitmq/client/impl/NetworkConnection.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.impl; import java.net.InetAddress; diff --git a/src/com/rabbitmq/client/impl/PlainMechanism.java b/src/com/rabbitmq/client/impl/PlainMechanism.java index b099f7ff34..2408afd846 100644 --- a/src/com/rabbitmq/client/impl/PlainMechanism.java +++ b/src/com/rabbitmq/client/impl/PlainMechanism.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/SetQueue.java b/src/com/rabbitmq/client/impl/SetQueue.java index 6a02c66463..e97b559f97 100644 --- a/src/com/rabbitmq/client/impl/SetQueue.java +++ b/src/com/rabbitmq/client/impl/SetQueue.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.impl; import java.util.HashSet; diff --git a/src/com/rabbitmq/client/impl/ShutdownNotifierComponent.java b/src/com/rabbitmq/client/impl/ShutdownNotifierComponent.java index dba413e3e5..17a7597f18 100644 --- a/src/com/rabbitmq/client/impl/ShutdownNotifierComponent.java +++ b/src/com/rabbitmq/client/impl/ShutdownNotifierComponent.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/SocketFrameHandler.java b/src/com/rabbitmq/client/impl/SocketFrameHandler.java index f9da39c787..2d1b6a90e3 100644 --- a/src/com/rabbitmq/client/impl/SocketFrameHandler.java +++ b/src/com/rabbitmq/client/impl/SocketFrameHandler.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/StrictExceptionHandler.java b/src/com/rabbitmq/client/impl/StrictExceptionHandler.java index 674a00e97a..55433d0c6f 100644 --- a/src/com/rabbitmq/client/impl/StrictExceptionHandler.java +++ b/src/com/rabbitmq/client/impl/StrictExceptionHandler.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/TruncatedInputStream.java b/src/com/rabbitmq/client/impl/TruncatedInputStream.java index 2042bb0f58..651ea58fee 100644 --- a/src/com/rabbitmq/client/impl/TruncatedInputStream.java +++ b/src/com/rabbitmq/client/impl/TruncatedInputStream.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/UnknownChannelException.java b/src/com/rabbitmq/client/impl/UnknownChannelException.java index 0811f5f829..1bf87a0d8f 100644 --- a/src/com/rabbitmq/client/impl/UnknownChannelException.java +++ b/src/com/rabbitmq/client/impl/UnknownChannelException.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/ValueReader.java b/src/com/rabbitmq/client/impl/ValueReader.java index 8d28346ced..8cc639891b 100644 --- a/src/com/rabbitmq/client/impl/ValueReader.java +++ b/src/com/rabbitmq/client/impl/ValueReader.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/ValueWriter.java b/src/com/rabbitmq/client/impl/ValueWriter.java index 2c9b6d283b..28d516dec4 100644 --- a/src/com/rabbitmq/client/impl/ValueWriter.java +++ b/src/com/rabbitmq/client/impl/ValueWriter.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java b/src/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java index b7a2ed408f..41cb56a0a1 100644 --- a/src/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java +++ b/src/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + /* * Modifications Copyright 2015 Pivotal Software, Inc and licenced as per * the rest of the RabbitMQ Java client. diff --git a/src/com/rabbitmq/client/impl/Version.java b/src/com/rabbitmq/client/impl/Version.java index 5b219a55f2..657c6f93df 100644 --- a/src/com/rabbitmq/client/impl/Version.java +++ b/src/com/rabbitmq/client/impl/Version.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.impl; diff --git a/src/com/rabbitmq/client/impl/WorkPool.java b/src/com/rabbitmq/client/impl/WorkPool.java index 0377f52912..80e3127411 100644 --- a/src/com/rabbitmq/client/impl/WorkPool.java +++ b/src/com/rabbitmq/client/impl/WorkPool.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.impl; import java.util.Collection; diff --git a/src/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java b/src/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java index a07c78f5f5..10445d697a 100644 --- a/src/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java +++ b/src/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.impl.recovery; import com.rabbitmq.client.AMQP; diff --git a/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index 451d53308e..e72988ebca 100644 --- a/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.impl.recovery; import com.rabbitmq.client.AMQP; diff --git a/src/com/rabbitmq/client/impl/recovery/ConsumerRecoveryListener.java b/src/com/rabbitmq/client/impl/recovery/ConsumerRecoveryListener.java index b8ca880565..1018f9a332 100644 --- a/src/com/rabbitmq/client/impl/recovery/ConsumerRecoveryListener.java +++ b/src/com/rabbitmq/client/impl/recovery/ConsumerRecoveryListener.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.impl.recovery; /** diff --git a/src/com/rabbitmq/client/impl/recovery/QueueRecoveryListener.java b/src/com/rabbitmq/client/impl/recovery/QueueRecoveryListener.java index e9c4ed0d5b..ca3d518685 100644 --- a/src/com/rabbitmq/client/impl/recovery/QueueRecoveryListener.java +++ b/src/com/rabbitmq/client/impl/recovery/QueueRecoveryListener.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.impl.recovery; /** diff --git a/src/com/rabbitmq/client/impl/recovery/RecordedBinding.java b/src/com/rabbitmq/client/impl/recovery/RecordedBinding.java index 9a57d7a035..9a84a200d0 100644 --- a/src/com/rabbitmq/client/impl/recovery/RecordedBinding.java +++ b/src/com/rabbitmq/client/impl/recovery/RecordedBinding.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.impl.recovery; import java.io.IOException; diff --git a/src/com/rabbitmq/client/impl/recovery/RecordedConsumer.java b/src/com/rabbitmq/client/impl/recovery/RecordedConsumer.java index 16978e44b8..4d7a992a5f 100644 --- a/src/com/rabbitmq/client/impl/recovery/RecordedConsumer.java +++ b/src/com/rabbitmq/client/impl/recovery/RecordedConsumer.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.impl.recovery; import com.rabbitmq.client.Consumer; diff --git a/src/com/rabbitmq/client/impl/recovery/RecordedEntity.java b/src/com/rabbitmq/client/impl/recovery/RecordedEntity.java index 7dae5d1442..b92dd6028b 100644 --- a/src/com/rabbitmq/client/impl/recovery/RecordedEntity.java +++ b/src/com/rabbitmq/client/impl/recovery/RecordedEntity.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.impl.recovery; import com.rabbitmq.client.Channel; diff --git a/src/com/rabbitmq/client/impl/recovery/RecordedExchange.java b/src/com/rabbitmq/client/impl/recovery/RecordedExchange.java index 5bc725c32e..7ff9604a94 100644 --- a/src/com/rabbitmq/client/impl/recovery/RecordedExchange.java +++ b/src/com/rabbitmq/client/impl/recovery/RecordedExchange.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.impl.recovery; import java.io.IOException; diff --git a/src/com/rabbitmq/client/impl/recovery/RecordedExchangeBinding.java b/src/com/rabbitmq/client/impl/recovery/RecordedExchangeBinding.java index 7dbabcda7b..010c9a2f1b 100644 --- a/src/com/rabbitmq/client/impl/recovery/RecordedExchangeBinding.java +++ b/src/com/rabbitmq/client/impl/recovery/RecordedExchangeBinding.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.impl.recovery; import java.io.IOException; diff --git a/src/com/rabbitmq/client/impl/recovery/RecordedNamedEntity.java b/src/com/rabbitmq/client/impl/recovery/RecordedNamedEntity.java index 138e5fca43..7bb2e43514 100644 --- a/src/com/rabbitmq/client/impl/recovery/RecordedNamedEntity.java +++ b/src/com/rabbitmq/client/impl/recovery/RecordedNamedEntity.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.impl.recovery; /** diff --git a/src/com/rabbitmq/client/impl/recovery/RecordedQueue.java b/src/com/rabbitmq/client/impl/recovery/RecordedQueue.java index 8d4c96b72b..5053ce06ad 100644 --- a/src/com/rabbitmq/client/impl/recovery/RecordedQueue.java +++ b/src/com/rabbitmq/client/impl/recovery/RecordedQueue.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.impl.recovery; import java.io.IOException; diff --git a/src/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java b/src/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java index ac8e4a6161..791440f9d6 100644 --- a/src/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java +++ b/src/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.impl.recovery; import java.io.IOException; diff --git a/src/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnection.java b/src/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnection.java index b4a3475de1..3bd4c88838 100644 --- a/src/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnection.java +++ b/src/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnection.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.impl.recovery; import com.rabbitmq.client.impl.AMQConnection; diff --git a/src/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java b/src/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java index 54bda056bb..d4e87fbf1c 100644 --- a/src/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java +++ b/src/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.impl.recovery; import com.rabbitmq.client.Address; diff --git a/src/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelManager.java b/src/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelManager.java index 2f93c3e8c0..f5a4327f8c 100644 --- a/src/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelManager.java +++ b/src/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelManager.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.impl.recovery; import com.rabbitmq.client.impl.AMQConnection; diff --git a/src/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java b/src/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java index 5b629cce53..96a4e2f5f4 100644 --- a/src/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java +++ b/src/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.impl.recovery; import com.rabbitmq.client.Command; diff --git a/src/com/rabbitmq/tools/Tracer.java b/src/com/rabbitmq/tools/Tracer.java index 12977b06a1..cbb25dc6bf 100644 --- a/src/com/rabbitmq/tools/Tracer.java +++ b/src/com/rabbitmq/tools/Tracer.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.tools; diff --git a/src/com/rabbitmq/tools/json/JSONReader.java b/src/com/rabbitmq/tools/json/JSONReader.java index 59920cf97f..983976c579 100644 --- a/src/com/rabbitmq/tools/json/JSONReader.java +++ b/src/com/rabbitmq/tools/json/JSONReader.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + /* Copyright (c) 2006-2007 Frank Carver Copyright (c) 2007-2016 Pivotal Software, Inc. All Rights Reserved diff --git a/src/com/rabbitmq/tools/json/JSONSerializable.java b/src/com/rabbitmq/tools/json/JSONSerializable.java index 9fa4d3fb19..1cb1b0a77e 100644 --- a/src/com/rabbitmq/tools/json/JSONSerializable.java +++ b/src/com/rabbitmq/tools/json/JSONSerializable.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.tools.json; diff --git a/src/com/rabbitmq/tools/json/JSONUtil.java b/src/com/rabbitmq/tools/json/JSONUtil.java index b7bcdc64bc..2266d26593 100644 --- a/src/com/rabbitmq/tools/json/JSONUtil.java +++ b/src/com/rabbitmq/tools/json/JSONUtil.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.tools.json; diff --git a/src/com/rabbitmq/tools/json/JSONWriter.java b/src/com/rabbitmq/tools/json/JSONWriter.java index 24896c4201..60ca587f7f 100644 --- a/src/com/rabbitmq/tools/json/JSONWriter.java +++ b/src/com/rabbitmq/tools/json/JSONWriter.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + /* Copyright (c) 2006-2007 Frank Carver Copyright (c) 2007-2016 Pivotal Software, Inc. All Rights Reserved diff --git a/src/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java b/src/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java index 715e78a9f4..5f5c2d58ee 100644 --- a/src/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java +++ b/src/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.tools.jsonrpc; diff --git a/src/com/rabbitmq/tools/jsonrpc/JsonRpcException.java b/src/com/rabbitmq/tools/jsonrpc/JsonRpcException.java index 723ccf472a..cbefc4fb21 100644 --- a/src/com/rabbitmq/tools/jsonrpc/JsonRpcException.java +++ b/src/com/rabbitmq/tools/jsonrpc/JsonRpcException.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.tools.jsonrpc; diff --git a/src/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java b/src/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java index b3dd744036..2e5c0151d7 100644 --- a/src/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java +++ b/src/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.tools.jsonrpc; diff --git a/src/com/rabbitmq/tools/jsonrpc/ParameterDescription.java b/src/com/rabbitmq/tools/jsonrpc/ParameterDescription.java index 6d3232a426..4046c61602 100644 --- a/src/com/rabbitmq/tools/jsonrpc/ParameterDescription.java +++ b/src/com/rabbitmq/tools/jsonrpc/ParameterDescription.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.tools.jsonrpc; diff --git a/src/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java b/src/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java index 3886e7f1d5..57dcc39b05 100644 --- a/src/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java +++ b/src/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.tools.jsonrpc; diff --git a/src/com/rabbitmq/tools/jsonrpc/ServiceDescription.java b/src/com/rabbitmq/tools/jsonrpc/ServiceDescription.java index bb04f7b284..79d750278b 100644 --- a/src/com/rabbitmq/tools/jsonrpc/ServiceDescription.java +++ b/src/com/rabbitmq/tools/jsonrpc/ServiceDescription.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.tools.jsonrpc; diff --git a/src/com/rabbitmq/utility/BlockingCell.java b/src/com/rabbitmq/utility/BlockingCell.java index 4555378664..68068fa3ff 100644 --- a/src/com/rabbitmq/utility/BlockingCell.java +++ b/src/com/rabbitmq/utility/BlockingCell.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.utility; diff --git a/src/com/rabbitmq/utility/BlockingValueOrException.java b/src/com/rabbitmq/utility/BlockingValueOrException.java index 0c6f9668df..683358c206 100644 --- a/src/com/rabbitmq/utility/BlockingValueOrException.java +++ b/src/com/rabbitmq/utility/BlockingValueOrException.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.utility; diff --git a/src/com/rabbitmq/utility/IntAllocator.java b/src/com/rabbitmq/utility/IntAllocator.java index 592275282b..917a036d3a 100644 --- a/src/com/rabbitmq/utility/IntAllocator.java +++ b/src/com/rabbitmq/utility/IntAllocator.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.utility; diff --git a/src/com/rabbitmq/utility/SensibleClone.java b/src/com/rabbitmq/utility/SensibleClone.java index 888eec89ab..01f51b4f21 100644 --- a/src/com/rabbitmq/utility/SensibleClone.java +++ b/src/com/rabbitmq/utility/SensibleClone.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.utility; diff --git a/src/com/rabbitmq/utility/SingleShotLinearTimer.java b/src/com/rabbitmq/utility/SingleShotLinearTimer.java index c0c281d948..8c477bc1d0 100644 --- a/src/com/rabbitmq/utility/SingleShotLinearTimer.java +++ b/src/com/rabbitmq/utility/SingleShotLinearTimer.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.utility; diff --git a/src/com/rabbitmq/utility/Utility.java b/src/com/rabbitmq/utility/Utility.java index 426bd3b081..58a2b22278 100644 --- a/src/com/rabbitmq/utility/Utility.java +++ b/src/com/rabbitmq/utility/Utility.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.utility; diff --git a/src/com/rabbitmq/utility/ValueOrException.java b/src/com/rabbitmq/utility/ValueOrException.java index bb0c6ad591..d882b28430 100644 --- a/src/com/rabbitmq/utility/ValueOrException.java +++ b/src/com/rabbitmq/utility/ValueOrException.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.utility; diff --git a/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java b/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java index 098ff2e187..85808b87a6 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.test.ssl; import com.rabbitmq.client.ConnectionFactory; diff --git a/test/src/com/rabbitmq/client/impl/WorkPoolTests.java b/test/src/com/rabbitmq/client/impl/WorkPoolTests.java index 4137954864..b0bd7653ca 100644 --- a/test/src/com/rabbitmq/client/impl/WorkPoolTests.java +++ b/test/src/com/rabbitmq/client/impl/WorkPoolTests.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.impl; import junit.framework.TestCase; diff --git a/test/src/com/rabbitmq/client/test/AMQBuilderApiTest.java b/test/src/com/rabbitmq/client/test/AMQBuilderApiTest.java index 8d40cedcfd..4a9ec8f430 100644 --- a/test/src/com/rabbitmq/client/test/AMQBuilderApiTest.java +++ b/test/src/com/rabbitmq/client/test/AMQBuilderApiTest.java @@ -1,19 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. -// -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test; import com.rabbitmq.client.AMQP; diff --git a/test/src/com/rabbitmq/client/test/AMQConnectionTest.java b/test/src/com/rabbitmq/client/test/AMQConnectionTest.java index a267661018..4d21de328b 100644 --- a/test/src/com/rabbitmq/client/test/AMQConnectionTest.java +++ b/test/src/com/rabbitmq/client/test/AMQConnectionTest.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/AmqpUriTest.java b/test/src/com/rabbitmq/client/test/AmqpUriTest.java index 2b38d7aefa..db68cfa3f9 100644 --- a/test/src/com/rabbitmq/client/test/AmqpUriTest.java +++ b/test/src/com/rabbitmq/client/test/AmqpUriTest.java @@ -1,19 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. -// -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2011-2015 Pivotal Software, Inc. All rights reserved. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test; import com.rabbitmq.client.ConnectionFactory; diff --git a/test/src/com/rabbitmq/client/test/BlockingCellTest.java b/test/src/com/rabbitmq/client/test/BlockingCellTest.java index 8848b874cd..afc4acc5c7 100644 --- a/test/src/com/rabbitmq/client/test/BlockingCellTest.java +++ b/test/src/com/rabbitmq/client/test/BlockingCellTest.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/BrokenFramesTest.java b/test/src/com/rabbitmq/client/test/BrokenFramesTest.java index e4a826bc6a..77faa8f1f3 100644 --- a/test/src/com/rabbitmq/client/test/BrokenFramesTest.java +++ b/test/src/com/rabbitmq/client/test/BrokenFramesTest.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/BrokerTestCase.java b/test/src/com/rabbitmq/client/test/BrokerTestCase.java index 2f342f0238..3f8316b4c4 100644 --- a/test/src/com/rabbitmq/client/test/BrokerTestCase.java +++ b/test/src/com/rabbitmq/client/test/BrokerTestCase.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/Bug20004Test.java b/test/src/com/rabbitmq/client/test/Bug20004Test.java index f778dc5405..86288f3582 100644 --- a/test/src/com/rabbitmq/client/test/Bug20004Test.java +++ b/test/src/com/rabbitmq/client/test/Bug20004Test.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/ChannelNumberAllocationTests.java b/test/src/com/rabbitmq/client/test/ChannelNumberAllocationTests.java index 6e1a8f617d..0d817325b1 100644 --- a/test/src/com/rabbitmq/client/test/ChannelNumberAllocationTests.java +++ b/test/src/com/rabbitmq/client/test/ChannelNumberAllocationTests.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/ClientTests.java b/test/src/com/rabbitmq/client/test/ClientTests.java index af38902083..077e478ec4 100644 --- a/test/src/com/rabbitmq/client/test/ClientTests.java +++ b/test/src/com/rabbitmq/client/test/ClientTests.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/ClonePropertiesTest.java b/test/src/com/rabbitmq/client/test/ClonePropertiesTest.java index d56dda9df0..1db2a86013 100644 --- a/test/src/com/rabbitmq/client/test/ClonePropertiesTest.java +++ b/test/src/com/rabbitmq/client/test/ClonePropertiesTest.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/CloseInMainLoop.java b/test/src/com/rabbitmq/client/test/CloseInMainLoop.java index e2c7873a6f..d21b5e93af 100644 --- a/test/src/com/rabbitmq/client/test/CloseInMainLoop.java +++ b/test/src/com/rabbitmq/client/test/CloseInMainLoop.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/ConfirmBase.java b/test/src/com/rabbitmq/client/test/ConfirmBase.java index 584d03d79c..b712239d26 100644 --- a/test/src/com/rabbitmq/client/test/ConfirmBase.java +++ b/test/src/com/rabbitmq/client/test/ConfirmBase.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2011-2015 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/JSONReadWriteTest.java b/test/src/com/rabbitmq/client/test/JSONReadWriteTest.java index b385dc0b13..5fc00d434e 100644 --- a/test/src/com/rabbitmq/client/test/JSONReadWriteTest.java +++ b/test/src/com/rabbitmq/client/test/JSONReadWriteTest.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/LongStringTest.java b/test/src/com/rabbitmq/client/test/LongStringTest.java index 61955ed541..56db5fa1e0 100644 --- a/test/src/com/rabbitmq/client/test/LongStringTest.java +++ b/test/src/com/rabbitmq/client/test/LongStringTest.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.test; import com.rabbitmq.client.LongString; diff --git a/test/src/com/rabbitmq/client/test/MultiThreadedChannel.java b/test/src/com/rabbitmq/client/test/MultiThreadedChannel.java index 22275d8318..96ee123215 100644 --- a/test/src/com/rabbitmq/client/test/MultiThreadedChannel.java +++ b/test/src/com/rabbitmq/client/test/MultiThreadedChannel.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/QueueingConsumerShutdownTests.java b/test/src/com/rabbitmq/client/test/QueueingConsumerShutdownTests.java index 2b649f27be..a0e249579a 100644 --- a/test/src/com/rabbitmq/client/test/QueueingConsumerShutdownTests.java +++ b/test/src/com/rabbitmq/client/test/QueueingConsumerShutdownTests.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/SharedThreadPoolTest.java b/test/src/com/rabbitmq/client/test/SharedThreadPoolTest.java index 48763e40f7..c709d0e9f7 100644 --- a/test/src/com/rabbitmq/client/test/SharedThreadPoolTest.java +++ b/test/src/com/rabbitmq/client/test/SharedThreadPoolTest.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.test; import com.rabbitmq.client.ConnectionFactory; diff --git a/test/src/com/rabbitmq/client/test/TableTest.java b/test/src/com/rabbitmq/client/test/TableTest.java index df436d44e9..c2e914d4ba 100644 --- a/test/src/com/rabbitmq/client/test/TableTest.java +++ b/test/src/com/rabbitmq/client/test/TableTest.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/TruncatedInputStreamTest.java b/test/src/com/rabbitmq/client/test/TruncatedInputStreamTest.java index 870477472b..7a1f62f53e 100644 --- a/test/src/com/rabbitmq/client/test/TruncatedInputStreamTest.java +++ b/test/src/com/rabbitmq/client/test/TruncatedInputStreamTest.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/ValueOrExceptionTest.java b/test/src/com/rabbitmq/client/test/ValueOrExceptionTest.java index ee656599a0..9f7d6e1753 100644 --- a/test/src/com/rabbitmq/client/test/ValueOrExceptionTest.java +++ b/test/src/com/rabbitmq/client/test/ValueOrExceptionTest.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test; diff --git a/test/src/com/rabbitmq/client/test/functional/AbstractRejectTest.java b/test/src/com/rabbitmq/client/test/functional/AbstractRejectTest.java index 8cd1d65905..50d3a18868 100644 --- a/test/src/com/rabbitmq/client/test/functional/AbstractRejectTest.java +++ b/test/src/com/rabbitmq/client/test/functional/AbstractRejectTest.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/AlternateExchange.java b/test/src/com/rabbitmq/client/test/functional/AlternateExchange.java index e6b4de0199..794b19f0cd 100644 --- a/test/src/com/rabbitmq/client/test/functional/AlternateExchange.java +++ b/test/src/com/rabbitmq/client/test/functional/AlternateExchange.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/BasicGet.java b/test/src/com/rabbitmq/client/test/functional/BasicGet.java index 87c4961fdf..c110c7f987 100644 --- a/test/src/com/rabbitmq/client/test/functional/BasicGet.java +++ b/test/src/com/rabbitmq/client/test/functional/BasicGet.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.test.functional; import com.rabbitmq.client.AlreadyClosedException; diff --git a/test/src/com/rabbitmq/client/test/functional/BindingLifecycle.java b/test/src/com/rabbitmq/client/test/functional/BindingLifecycle.java index 0a9690a3af..2c155d579b 100644 --- a/test/src/com/rabbitmq/client/test/functional/BindingLifecycle.java +++ b/test/src/com/rabbitmq/client/test/functional/BindingLifecycle.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/BindingLifecycleBase.java b/test/src/com/rabbitmq/client/test/functional/BindingLifecycleBase.java index 064758fcad..0ff9be86ef 100644 --- a/test/src/com/rabbitmq/client/test/functional/BindingLifecycleBase.java +++ b/test/src/com/rabbitmq/client/test/functional/BindingLifecycleBase.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/CcRoutes.java b/test/src/com/rabbitmq/client/test/functional/CcRoutes.java index d1a3691d9b..6b2db8320f 100644 --- a/test/src/com/rabbitmq/client/test/functional/CcRoutes.java +++ b/test/src/com/rabbitmq/client/test/functional/CcRoutes.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/ClusteredTestBase.java b/test/src/com/rabbitmq/client/test/functional/ClusteredTestBase.java index c11e39d652..6f71533679 100644 --- a/test/src/com/rabbitmq/client/test/functional/ClusteredTestBase.java +++ b/test/src/com/rabbitmq/client/test/functional/ClusteredTestBase.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/Confirm.java b/test/src/com/rabbitmq/client/test/functional/Confirm.java index 098912773b..ef56719774 100644 --- a/test/src/com/rabbitmq/client/test/functional/Confirm.java +++ b/test/src/com/rabbitmq/client/test/functional/Confirm.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/ConnectionOpen.java b/test/src/com/rabbitmq/client/test/functional/ConnectionOpen.java index 62c42bfdb1..b53e347f10 100644 --- a/test/src/com/rabbitmq/client/test/functional/ConnectionOpen.java +++ b/test/src/com/rabbitmq/client/test/functional/ConnectionOpen.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/test/src/com/rabbitmq/client/test/functional/ConnectionRecovery.java index 471557a791..a7dbd7b6cb 100644 --- a/test/src/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/test/src/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.test.functional; import com.rabbitmq.client.*; diff --git a/test/src/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java b/test/src/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java index 540380032e..f73625cd62 100644 --- a/test/src/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java +++ b/test/src/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/ConsumerCount.java b/test/src/com/rabbitmq/client/test/functional/ConsumerCount.java index ea22dbcde5..1bc4c76944 100644 --- a/test/src/com/rabbitmq/client/test/functional/ConsumerCount.java +++ b/test/src/com/rabbitmq/client/test/functional/ConsumerCount.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.test.functional; import com.rabbitmq.client.DefaultConsumer; diff --git a/test/src/com/rabbitmq/client/test/functional/ConsumerPriorities.java b/test/src/com/rabbitmq/client/test/functional/ConsumerPriorities.java index c1b2841c67..6b2da2a114 100644 --- a/test/src/com/rabbitmq/client/test/functional/ConsumerPriorities.java +++ b/test/src/com/rabbitmq/client/test/functional/ConsumerPriorities.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.test.functional; import com.rabbitmq.client.AMQP; diff --git a/test/src/com/rabbitmq/client/test/functional/DeadLetterExchange.java b/test/src/com/rabbitmq/client/test/functional/DeadLetterExchange.java index 63a4476145..354e51a8e2 100644 --- a/test/src/com/rabbitmq/client/test/functional/DeadLetterExchange.java +++ b/test/src/com/rabbitmq/client/test/functional/DeadLetterExchange.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.test.functional; import com.rabbitmq.client.AMQP; diff --git a/test/src/com/rabbitmq/client/test/functional/DefaultExchange.java b/test/src/com/rabbitmq/client/test/functional/DefaultExchange.java index a9a8f618bc..25c4c99390 100644 --- a/test/src/com/rabbitmq/client/test/functional/DefaultExchange.java +++ b/test/src/com/rabbitmq/client/test/functional/DefaultExchange.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/DirectReplyTo.java b/test/src/com/rabbitmq/client/test/functional/DirectReplyTo.java index 0b859d801c..aa39e4804c 100644 --- a/test/src/com/rabbitmq/client/test/functional/DirectReplyTo.java +++ b/test/src/com/rabbitmq/client/test/functional/DirectReplyTo.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.test.functional; import com.rabbitmq.client.AMQP; diff --git a/test/src/com/rabbitmq/client/test/functional/DoubleDeletion.java b/test/src/com/rabbitmq/client/test/functional/DoubleDeletion.java index be7ea14725..bae5eb7c8d 100644 --- a/test/src/com/rabbitmq/client/test/functional/DoubleDeletion.java +++ b/test/src/com/rabbitmq/client/test/functional/DoubleDeletion.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/DurableOnTransient.java b/test/src/com/rabbitmq/client/test/functional/DurableOnTransient.java index c6b7982c79..84f488df7c 100644 --- a/test/src/com/rabbitmq/client/test/functional/DurableOnTransient.java +++ b/test/src/com/rabbitmq/client/test/functional/DurableOnTransient.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/ExceptionHandling.java b/test/src/com/rabbitmq/client/test/functional/ExceptionHandling.java index fd9c27485f..8a25798cd3 100644 --- a/test/src/com/rabbitmq/client/test/functional/ExceptionHandling.java +++ b/test/src/com/rabbitmq/client/test/functional/ExceptionHandling.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.test.functional; import com.rabbitmq.client.AMQP; diff --git a/test/src/com/rabbitmq/client/test/functional/ExceptionMessages.java b/test/src/com/rabbitmq/client/test/functional/ExceptionMessages.java index f098743da7..27c52f2d50 100644 --- a/test/src/com/rabbitmq/client/test/functional/ExceptionMessages.java +++ b/test/src/com/rabbitmq/client/test/functional/ExceptionMessages.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.test.functional; import com.rabbitmq.client.AlreadyClosedException; diff --git a/test/src/com/rabbitmq/client/test/functional/ExchangeDeclare.java b/test/src/com/rabbitmq/client/test/functional/ExchangeDeclare.java index a0039294bb..14010acb96 100644 --- a/test/src/com/rabbitmq/client/test/functional/ExchangeDeclare.java +++ b/test/src/com/rabbitmq/client/test/functional/ExchangeDeclare.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java b/test/src/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java index 439d8b5552..f5c3defcf5 100644 --- a/test/src/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java +++ b/test/src/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/ExchangeDeletePredeclared.java b/test/src/com/rabbitmq/client/test/functional/ExchangeDeletePredeclared.java index 4f73987b71..0b1cf6969b 100644 --- a/test/src/com/rabbitmq/client/test/functional/ExchangeDeletePredeclared.java +++ b/test/src/com/rabbitmq/client/test/functional/ExchangeDeletePredeclared.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.test.functional; import com.rabbitmq.client.AMQP; diff --git a/test/src/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java b/test/src/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java index 15302f7bdb..82e4eccbdc 100644 --- a/test/src/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java +++ b/test/src/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java b/test/src/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java index 223d1d7965..64c07c9ddd 100644 --- a/test/src/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java +++ b/test/src/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java b/test/src/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java index a0d81f38ce..8773f6d29f 100644 --- a/test/src/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java +++ b/test/src/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/FrameMax.java b/test/src/com/rabbitmq/client/test/functional/FrameMax.java index 9a388a93ca..757674455d 100644 --- a/test/src/com/rabbitmq/client/test/functional/FrameMax.java +++ b/test/src/com/rabbitmq/client/test/functional/FrameMax.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/FunctionalTests.java b/test/src/com/rabbitmq/client/test/functional/FunctionalTests.java index a44b44e6f6..d99927e908 100644 --- a/test/src/com/rabbitmq/client/test/functional/FunctionalTests.java +++ b/test/src/com/rabbitmq/client/test/functional/FunctionalTests.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java b/test/src/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java index 491fb4c37a..7959d88af6 100644 --- a/test/src/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java +++ b/test/src/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.test.functional; import com.rabbitmq.client.AMQP; diff --git a/test/src/com/rabbitmq/client/test/functional/Heartbeat.java b/test/src/com/rabbitmq/client/test/functional/Heartbeat.java index 15e66cea6a..67e63886c5 100644 --- a/test/src/com/rabbitmq/client/test/functional/Heartbeat.java +++ b/test/src/com/rabbitmq/client/test/functional/Heartbeat.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/InternalExchange.java b/test/src/com/rabbitmq/client/test/functional/InternalExchange.java index 2238ea4794..a4091820c5 100644 --- a/test/src/com/rabbitmq/client/test/functional/InternalExchange.java +++ b/test/src/com/rabbitmq/client/test/functional/InternalExchange.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/InvalidAcks.java b/test/src/com/rabbitmq/client/test/functional/InvalidAcks.java index b620ed42ef..b869378d50 100644 --- a/test/src/com/rabbitmq/client/test/functional/InvalidAcks.java +++ b/test/src/com/rabbitmq/client/test/functional/InvalidAcks.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/InvalidAcksBase.java b/test/src/com/rabbitmq/client/test/functional/InvalidAcksBase.java index 0c6010243d..18f4764272 100644 --- a/test/src/com/rabbitmq/client/test/functional/InvalidAcksBase.java +++ b/test/src/com/rabbitmq/client/test/functional/InvalidAcksBase.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/InvalidAcksTx.java b/test/src/com/rabbitmq/client/test/functional/InvalidAcksTx.java index a616e33dd9..388c7ee414 100644 --- a/test/src/com/rabbitmq/client/test/functional/InvalidAcksTx.java +++ b/test/src/com/rabbitmq/client/test/functional/InvalidAcksTx.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/MessageCount.java b/test/src/com/rabbitmq/client/test/functional/MessageCount.java index 80996a4b29..bced38a762 100644 --- a/test/src/com/rabbitmq/client/test/functional/MessageCount.java +++ b/test/src/com/rabbitmq/client/test/functional/MessageCount.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.test.functional; import com.rabbitmq.client.test.BrokerTestCase; diff --git a/test/src/com/rabbitmq/client/test/functional/Nack.java b/test/src/com/rabbitmq/client/test/functional/Nack.java index 8473607a09..983355b2ea 100644 --- a/test/src/com/rabbitmq/client/test/functional/Nack.java +++ b/test/src/com/rabbitmq/client/test/functional/Nack.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java b/test/src/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java index 8727d43766..e6b91ccb8b 100644 --- a/test/src/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java +++ b/test/src/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/Nowait.java b/test/src/com/rabbitmq/client/test/functional/Nowait.java index db0faca82a..b6c03cb593 100644 --- a/test/src/com/rabbitmq/client/test/functional/Nowait.java +++ b/test/src/com/rabbitmq/client/test/functional/Nowait.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.test.functional; import com.rabbitmq.client.test.BrokerTestCase; diff --git a/test/src/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java b/test/src/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java index 0b5531da1d..9c7c4de68e 100644 --- a/test/src/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java +++ b/test/src/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.test.functional; import com.rabbitmq.client.GetResponse; diff --git a/test/src/com/rabbitmq/client/test/functional/PerMessageTTL.java b/test/src/com/rabbitmq/client/test/functional/PerMessageTTL.java index 1779ec9a92..a0fbb8898a 100644 --- a/test/src/com/rabbitmq/client/test/functional/PerMessageTTL.java +++ b/test/src/com/rabbitmq/client/test/functional/PerMessageTTL.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/PerQueueTTL.java b/test/src/com/rabbitmq/client/test/functional/PerQueueTTL.java index d178c67174..138965f3eb 100644 --- a/test/src/com/rabbitmq/client/test/functional/PerQueueTTL.java +++ b/test/src/com/rabbitmq/client/test/functional/PerQueueTTL.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java b/test/src/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java index a7c1502059..64b01b6dfa 100644 --- a/test/src/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java +++ b/test/src/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.test.functional; import com.rabbitmq.client.AMQP; diff --git a/test/src/com/rabbitmq/client/test/functional/Policies.java b/test/src/com/rabbitmq/client/test/functional/Policies.java index eed5d950ed..f1ae122d1c 100644 --- a/test/src/com/rabbitmq/client/test/functional/Policies.java +++ b/test/src/com/rabbitmq/client/test/functional/Policies.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/QosTests.java b/test/src/com/rabbitmq/client/test/functional/QosTests.java index 526e140905..dbf3b8cba0 100644 --- a/test/src/com/rabbitmq/client/test/functional/QosTests.java +++ b/test/src/com/rabbitmq/client/test/functional/QosTests.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/QueueExclusivity.java b/test/src/com/rabbitmq/client/test/functional/QueueExclusivity.java index 94e3a619b1..dcc994ce84 100644 --- a/test/src/com/rabbitmq/client/test/functional/QueueExclusivity.java +++ b/test/src/com/rabbitmq/client/test/functional/QueueExclusivity.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/QueueLease.java b/test/src/com/rabbitmq/client/test/functional/QueueLease.java index 1d63afd8bb..284869acda 100644 --- a/test/src/com/rabbitmq/client/test/functional/QueueLease.java +++ b/test/src/com/rabbitmq/client/test/functional/QueueLease.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/QueueLifecycle.java b/test/src/com/rabbitmq/client/test/functional/QueueLifecycle.java index 735f752ede..e7c6885f88 100644 --- a/test/src/com/rabbitmq/client/test/functional/QueueLifecycle.java +++ b/test/src/com/rabbitmq/client/test/functional/QueueLifecycle.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/QueueSizeLimit.java b/test/src/com/rabbitmq/client/test/functional/QueueSizeLimit.java index b0c4204621..411c040a78 100644 --- a/test/src/com/rabbitmq/client/test/functional/QueueSizeLimit.java +++ b/test/src/com/rabbitmq/client/test/functional/QueueSizeLimit.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/Recover.java b/test/src/com/rabbitmq/client/test/functional/Recover.java index ed18326691..e54f4591f4 100644 --- a/test/src/com/rabbitmq/client/test/functional/Recover.java +++ b/test/src/com/rabbitmq/client/test/functional/Recover.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/Reject.java b/test/src/com/rabbitmq/client/test/functional/Reject.java index 1e493af612..7f3ebb80f9 100644 --- a/test/src/com/rabbitmq/client/test/functional/Reject.java +++ b/test/src/com/rabbitmq/client/test/functional/Reject.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java b/test/src/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java index 36b6efa8b3..c9e44830c3 100644 --- a/test/src/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java +++ b/test/src/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/RequeueOnClose.java b/test/src/com/rabbitmq/client/test/functional/RequeueOnClose.java index da0da3942e..60bdb6d163 100644 --- a/test/src/com/rabbitmq/client/test/functional/RequeueOnClose.java +++ b/test/src/com/rabbitmq/client/test/functional/RequeueOnClose.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java b/test/src/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java index 007f5bfff0..8f36f0e2b6 100644 --- a/test/src/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java +++ b/test/src/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/Routing.java b/test/src/com/rabbitmq/client/test/functional/Routing.java index 6dc9e2992c..a10fc6e3ee 100644 --- a/test/src/com/rabbitmq/client/test/functional/Routing.java +++ b/test/src/com/rabbitmq/client/test/functional/Routing.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/SaslMechanisms.java b/test/src/com/rabbitmq/client/test/functional/SaslMechanisms.java index ed1022614e..2946e73537 100644 --- a/test/src/com/rabbitmq/client/test/functional/SaslMechanisms.java +++ b/test/src/com/rabbitmq/client/test/functional/SaslMechanisms.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/TTLHandling.java b/test/src/com/rabbitmq/client/test/functional/TTLHandling.java index 0756ec00ea..83e139de3f 100644 --- a/test/src/com/rabbitmq/client/test/functional/TTLHandling.java +++ b/test/src/com/rabbitmq/client/test/functional/TTLHandling.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.test.functional; import com.rabbitmq.client.AMQP; diff --git a/test/src/com/rabbitmq/client/test/functional/Tables.java b/test/src/com/rabbitmq/client/test/functional/Tables.java index 9413d74b6f..0e72ea11e6 100644 --- a/test/src/com/rabbitmq/client/test/functional/Tables.java +++ b/test/src/com/rabbitmq/client/test/functional/Tables.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/Transactions.java b/test/src/com/rabbitmq/client/test/functional/Transactions.java index ffe4badece..5276be217e 100644 --- a/test/src/com/rabbitmq/client/test/functional/Transactions.java +++ b/test/src/com/rabbitmq/client/test/functional/Transactions.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java b/test/src/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java index f01a89cc92..6678c6c0c2 100644 --- a/test/src/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java +++ b/test/src/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/UnexpectedFrames.java b/test/src/com/rabbitmq/client/test/functional/UnexpectedFrames.java index 33e5f91794..b79caf2e00 100644 --- a/test/src/com/rabbitmq/client/test/functional/UnexpectedFrames.java +++ b/test/src/com/rabbitmq/client/test/functional/UnexpectedFrames.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/functional/UserIDHeader.java b/test/src/com/rabbitmq/client/test/functional/UserIDHeader.java index f7644c806d..ad5ba89ff4 100644 --- a/test/src/com/rabbitmq/client/test/functional/UserIDHeader.java +++ b/test/src/com/rabbitmq/client/test/functional/UserIDHeader.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/test/src/com/rabbitmq/client/test/performance/CLIHelper.java b/test/src/com/rabbitmq/client/test/performance/CLIHelper.java index 223b80a037..7b316efd7d 100644 --- a/test/src/com/rabbitmq/client/test/performance/CLIHelper.java +++ b/test/src/com/rabbitmq/client/test/performance/CLIHelper.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.performance; diff --git a/test/src/com/rabbitmq/client/test/performance/QosScaling.java b/test/src/com/rabbitmq/client/test/performance/QosScaling.java index 561c0726eb..597a0694dc 100644 --- a/test/src/com/rabbitmq/client/test/performance/QosScaling.java +++ b/test/src/com/rabbitmq/client/test/performance/QosScaling.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.performance; diff --git a/test/src/com/rabbitmq/client/test/performance/ScalabilityTest.java b/test/src/com/rabbitmq/client/test/performance/ScalabilityTest.java index d8f18ed170..5445ffcb05 100644 --- a/test/src/com/rabbitmq/client/test/performance/ScalabilityTest.java +++ b/test/src/com/rabbitmq/client/test/performance/ScalabilityTest.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.performance; diff --git a/test/src/com/rabbitmq/client/test/performance/StressManagement.java b/test/src/com/rabbitmq/client/test/performance/StressManagement.java index 84c8027824..32937c07ad 100644 --- a/test/src/com/rabbitmq/client/test/performance/StressManagement.java +++ b/test/src/com/rabbitmq/client/test/performance/StressManagement.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.performance; diff --git a/test/src/com/rabbitmq/client/test/server/AbsentQueue.java b/test/src/com/rabbitmq/client/test/server/AbsentQueue.java index 0aedd45411..716ac7c195 100644 --- a/test/src/com/rabbitmq/client/test/server/AbsentQueue.java +++ b/test/src/com/rabbitmq/client/test/server/AbsentQueue.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.server; diff --git a/test/src/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java b/test/src/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java index 23247251ef..d2eae1bc79 100644 --- a/test/src/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java +++ b/test/src/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.server; diff --git a/test/src/com/rabbitmq/client/test/server/BlockedConnection.java b/test/src/com/rabbitmq/client/test/server/BlockedConnection.java index cb0caa2de3..2b21a187fe 100644 --- a/test/src/com/rabbitmq/client/test/server/BlockedConnection.java +++ b/test/src/com/rabbitmq/client/test/server/BlockedConnection.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.server; diff --git a/test/src/com/rabbitmq/client/test/server/Bug19219Test.java b/test/src/com/rabbitmq/client/test/server/Bug19219Test.java index 3c39622e19..fb7b6801c2 100644 --- a/test/src/com/rabbitmq/client/test/server/Bug19219Test.java +++ b/test/src/com/rabbitmq/client/test/server/Bug19219Test.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.server; diff --git a/test/src/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java b/test/src/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java index c590d05aa7..d6f887b2a3 100644 --- a/test/src/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java +++ b/test/src/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.test.server; import com.rabbitmq.client.AMQP; diff --git a/test/src/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java b/test/src/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java index 58fc7de989..510fb403ea 100644 --- a/test/src/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java +++ b/test/src/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.test.server; import com.rabbitmq.client.MessageProperties; diff --git a/test/src/com/rabbitmq/client/test/server/DurableBindingLifecycle.java b/test/src/com/rabbitmq/client/test/server/DurableBindingLifecycle.java index 1a93c562aa..64507360b6 100644 --- a/test/src/com/rabbitmq/client/test/server/DurableBindingLifecycle.java +++ b/test/src/com/rabbitmq/client/test/server/DurableBindingLifecycle.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.server; diff --git a/test/src/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java b/test/src/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java index f6e060c171..10ccf71495 100644 --- a/test/src/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java +++ b/test/src/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.server; diff --git a/test/src/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java b/test/src/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java index 202271b15d..c1ada2e619 100644 --- a/test/src/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java +++ b/test/src/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.server; diff --git a/test/src/com/rabbitmq/client/test/server/Firehose.java b/test/src/com/rabbitmq/client/test/server/Firehose.java index c6b3b0f869..7a2c3329fe 100644 --- a/test/src/com/rabbitmq/client/test/server/Firehose.java +++ b/test/src/com/rabbitmq/client/test/server/Firehose.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.test.server; import com.rabbitmq.client.GetResponse; diff --git a/test/src/com/rabbitmq/client/test/server/HATests.java b/test/src/com/rabbitmq/client/test/server/HATests.java index a6fcc793c7..c1eaa47d42 100644 --- a/test/src/com/rabbitmq/client/test/server/HATests.java +++ b/test/src/com/rabbitmq/client/test/server/HATests.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.server; diff --git a/test/src/com/rabbitmq/client/test/server/LoopbackUsers.java b/test/src/com/rabbitmq/client/test/server/LoopbackUsers.java index 2ded79cf77..ea4c1a6af3 100644 --- a/test/src/com/rabbitmq/client/test/server/LoopbackUsers.java +++ b/test/src/com/rabbitmq/client/test/server/LoopbackUsers.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.test.server; import com.rabbitmq.client.AuthenticationFailureException; diff --git a/test/src/com/rabbitmq/client/test/server/MemoryAlarms.java b/test/src/com/rabbitmq/client/test/server/MemoryAlarms.java index ca0bde4db8..f4d7068dbd 100644 --- a/test/src/com/rabbitmq/client/test/server/MemoryAlarms.java +++ b/test/src/com/rabbitmq/client/test/server/MemoryAlarms.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.server; diff --git a/test/src/com/rabbitmq/client/test/server/MessageRecovery.java b/test/src/com/rabbitmq/client/test/server/MessageRecovery.java index c163f1bb85..b30b86ccda 100644 --- a/test/src/com/rabbitmq/client/test/server/MessageRecovery.java +++ b/test/src/com/rabbitmq/client/test/server/MessageRecovery.java @@ -1,17 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.server; diff --git a/test/src/com/rabbitmq/client/test/server/Permissions.java b/test/src/com/rabbitmq/client/test/server/Permissions.java index a03ae614ce..782754833d 100644 --- a/test/src/com/rabbitmq/client/test/server/Permissions.java +++ b/test/src/com/rabbitmq/client/test/server/Permissions.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.server; diff --git a/test/src/com/rabbitmq/client/test/server/PersistenceGuarantees.java b/test/src/com/rabbitmq/client/test/server/PersistenceGuarantees.java index 096211438b..b4df0710db 100644 --- a/test/src/com/rabbitmq/client/test/server/PersistenceGuarantees.java +++ b/test/src/com/rabbitmq/client/test/server/PersistenceGuarantees.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.test.server; import com.rabbitmq.client.MessageProperties; diff --git a/test/src/com/rabbitmq/client/test/server/PriorityQueues.java b/test/src/com/rabbitmq/client/test/server/PriorityQueues.java index 3aec1357f6..1810f39ad9 100644 --- a/test/src/com/rabbitmq/client/test/server/PriorityQueues.java +++ b/test/src/com/rabbitmq/client/test/server/PriorityQueues.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.test.server; import com.rabbitmq.client.AMQP; diff --git a/test/src/com/rabbitmq/client/test/server/ServerTests.java b/test/src/com/rabbitmq/client/test/server/ServerTests.java index 7f46efb447..48bec5479b 100644 --- a/test/src/com/rabbitmq/client/test/server/ServerTests.java +++ b/test/src/com/rabbitmq/client/test/server/ServerTests.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.server; diff --git a/test/src/com/rabbitmq/client/test/server/Shutdown.java b/test/src/com/rabbitmq/client/test/server/Shutdown.java index 7280eb8be8..e5226273f6 100644 --- a/test/src/com/rabbitmq/client/test/server/Shutdown.java +++ b/test/src/com/rabbitmq/client/test/server/Shutdown.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.test.server; import com.rabbitmq.client.test.BrokerTestCase; diff --git a/test/src/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java b/test/src/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java index f4492a0ac0..5a6b9bac33 100644 --- a/test/src/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java +++ b/test/src/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.test.server; import com.rabbitmq.client.AMQP; diff --git a/test/src/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java b/test/src/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java index 6281055406..957e384881 100644 --- a/test/src/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java +++ b/test/src/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.ssl; diff --git a/test/src/com/rabbitmq/client/test/ssl/SSLTests.java b/test/src/com/rabbitmq/client/test/ssl/SSLTests.java index 2fccc6ab3b..184805eb80 100644 --- a/test/src/com/rabbitmq/client/test/ssl/SSLTests.java +++ b/test/src/com/rabbitmq/client/test/ssl/SSLTests.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.ssl; diff --git a/test/src/com/rabbitmq/client/test/ssl/UnverifiedConnection.java b/test/src/com/rabbitmq/client/test/ssl/UnverifiedConnection.java index c71c995d31..d7462ef989 100644 --- a/test/src/com/rabbitmq/client/test/ssl/UnverifiedConnection.java +++ b/test/src/com/rabbitmq/client/test/ssl/UnverifiedConnection.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.ssl; diff --git a/test/src/com/rabbitmq/client/test/ssl/VerifiedConnection.java b/test/src/com/rabbitmq/client/test/ssl/VerifiedConnection.java index 82c3ae73d9..c12a3a2e66 100644 --- a/test/src/com/rabbitmq/client/test/ssl/VerifiedConnection.java +++ b/test/src/com/rabbitmq/client/test/ssl/VerifiedConnection.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.ssl; diff --git a/test/src/com/rabbitmq/examples/BufferPerformanceMetrics.java b/test/src/com/rabbitmq/examples/BufferPerformanceMetrics.java index 06c283194c..ca8d77e5e9 100644 --- a/test/src/com/rabbitmq/examples/BufferPerformanceMetrics.java +++ b/test/src/com/rabbitmq/examples/BufferPerformanceMetrics.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/ChannelCreationPerformance.java b/test/src/com/rabbitmq/examples/ChannelCreationPerformance.java index 931e396e38..ccb6745155 100644 --- a/test/src/com/rabbitmq/examples/ChannelCreationPerformance.java +++ b/test/src/com/rabbitmq/examples/ChannelCreationPerformance.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/ConfirmDontLoseMessages.java b/test/src/com/rabbitmq/examples/ConfirmDontLoseMessages.java index 16b67d2612..9d5fe019ad 100644 --- a/test/src/com/rabbitmq/examples/ConfirmDontLoseMessages.java +++ b/test/src/com/rabbitmq/examples/ConfirmDontLoseMessages.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/ConsumerMain.java b/test/src/com/rabbitmq/examples/ConsumerMain.java index f363c2252c..e114d1f5de 100644 --- a/test/src/com/rabbitmq/examples/ConsumerMain.java +++ b/test/src/com/rabbitmq/examples/ConsumerMain.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/DirectReplyToPerformance.java b/test/src/com/rabbitmq/examples/DirectReplyToPerformance.java index 5fc8c9a85c..f6905fcd60 100644 --- a/test/src/com/rabbitmq/examples/DirectReplyToPerformance.java +++ b/test/src/com/rabbitmq/examples/DirectReplyToPerformance.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.examples; import com.rabbitmq.client.AMQP; diff --git a/test/src/com/rabbitmq/examples/FileConsumer.java b/test/src/com/rabbitmq/examples/FileConsumer.java index b889fa17c8..fda5e67c97 100644 --- a/test/src/com/rabbitmq/examples/FileConsumer.java +++ b/test/src/com/rabbitmq/examples/FileConsumer.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/FileProducer.java b/test/src/com/rabbitmq/examples/FileProducer.java index e1aea5a710..56bd647e5f 100644 --- a/test/src/com/rabbitmq/examples/FileProducer.java +++ b/test/src/com/rabbitmq/examples/FileProducer.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/HelloClient.java b/test/src/com/rabbitmq/examples/HelloClient.java index fb4e1b20d8..02df7d5e61 100644 --- a/test/src/com/rabbitmq/examples/HelloClient.java +++ b/test/src/com/rabbitmq/examples/HelloClient.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/HelloJsonClient.java b/test/src/com/rabbitmq/examples/HelloJsonClient.java index 7b37b21eb3..c88315b750 100644 --- a/test/src/com/rabbitmq/examples/HelloJsonClient.java +++ b/test/src/com/rabbitmq/examples/HelloJsonClient.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/HelloJsonServer.java b/test/src/com/rabbitmq/examples/HelloJsonServer.java index 2ffe1bfddf..ed581b6a1a 100644 --- a/test/src/com/rabbitmq/examples/HelloJsonServer.java +++ b/test/src/com/rabbitmq/examples/HelloJsonServer.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/HelloJsonService.java b/test/src/com/rabbitmq/examples/HelloJsonService.java index 1943a02d6d..e75e1c2753 100644 --- a/test/src/com/rabbitmq/examples/HelloJsonService.java +++ b/test/src/com/rabbitmq/examples/HelloJsonService.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/HelloServer.java b/test/src/com/rabbitmq/examples/HelloServer.java index 2a7e34602f..26a7c495d0 100644 --- a/test/src/com/rabbitmq/examples/HelloServer.java +++ b/test/src/com/rabbitmq/examples/HelloServer.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/LogTail.java b/test/src/com/rabbitmq/examples/LogTail.java index 604f732686..92f9af5b1e 100644 --- a/test/src/com/rabbitmq/examples/LogTail.java +++ b/test/src/com/rabbitmq/examples/LogTail.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/MulticastMain.java b/test/src/com/rabbitmq/examples/MulticastMain.java index 8b5114de20..da54616310 100644 --- a/test/src/com/rabbitmq/examples/MulticastMain.java +++ b/test/src/com/rabbitmq/examples/MulticastMain.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/PerQueueTTLGetter.java b/test/src/com/rabbitmq/examples/PerQueueTTLGetter.java index afc9c9b830..c7f5a20118 100644 --- a/test/src/com/rabbitmq/examples/PerQueueTTLGetter.java +++ b/test/src/com/rabbitmq/examples/PerQueueTTLGetter.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/PerQueueTTLPublisher.java b/test/src/com/rabbitmq/examples/PerQueueTTLPublisher.java index ae14156236..127911922b 100644 --- a/test/src/com/rabbitmq/examples/PerQueueTTLPublisher.java +++ b/test/src/com/rabbitmq/examples/PerQueueTTLPublisher.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/PerfTest.java b/test/src/com/rabbitmq/examples/PerfTest.java index cd3cb2960b..e65c057ed4 100644 --- a/test/src/com/rabbitmq/examples/PerfTest.java +++ b/test/src/com/rabbitmq/examples/PerfTest.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/PerfTestMulti.java b/test/src/com/rabbitmq/examples/PerfTestMulti.java index c663352978..e21b5a4b17 100644 --- a/test/src/com/rabbitmq/examples/PerfTestMulti.java +++ b/test/src/com/rabbitmq/examples/PerfTestMulti.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/ProducerMain.java b/test/src/com/rabbitmq/examples/ProducerMain.java index 20e96dea25..23c37e7886 100644 --- a/test/src/com/rabbitmq/examples/ProducerMain.java +++ b/test/src/com/rabbitmq/examples/ProducerMain.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/SendString.java b/test/src/com/rabbitmq/examples/SendString.java index 6d0ce3900e..d2c2438bba 100644 --- a/test/src/com/rabbitmq/examples/SendString.java +++ b/test/src/com/rabbitmq/examples/SendString.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/SimpleConsumer.java b/test/src/com/rabbitmq/examples/SimpleConsumer.java index 05914daa88..a34fe88a77 100644 --- a/test/src/com/rabbitmq/examples/SimpleConsumer.java +++ b/test/src/com/rabbitmq/examples/SimpleConsumer.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/SimpleProducer.java b/test/src/com/rabbitmq/examples/SimpleProducer.java index ee1c99e3ee..351d87a750 100644 --- a/test/src/com/rabbitmq/examples/SimpleProducer.java +++ b/test/src/com/rabbitmq/examples/SimpleProducer.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/SimpleTopicConsumer.java b/test/src/com/rabbitmq/examples/SimpleTopicConsumer.java index 2ad640a45a..3eced929c9 100644 --- a/test/src/com/rabbitmq/examples/SimpleTopicConsumer.java +++ b/test/src/com/rabbitmq/examples/SimpleTopicConsumer.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/SimpleTopicProducer.java b/test/src/com/rabbitmq/examples/SimpleTopicProducer.java index 31d2ee1203..e687cc4d15 100644 --- a/test/src/com/rabbitmq/examples/SimpleTopicProducer.java +++ b/test/src/com/rabbitmq/examples/SimpleTopicProducer.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/SpammyTopicProducer.java b/test/src/com/rabbitmq/examples/SpammyTopicProducer.java index 111f60a3b7..c0ab87eb64 100644 --- a/test/src/com/rabbitmq/examples/SpammyTopicProducer.java +++ b/test/src/com/rabbitmq/examples/SpammyTopicProducer.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/StressPersister.java b/test/src/com/rabbitmq/examples/StressPersister.java index b19b4a3c45..e55dafd782 100644 --- a/test/src/com/rabbitmq/examples/StressPersister.java +++ b/test/src/com/rabbitmq/examples/StressPersister.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/TestMain.java b/test/src/com/rabbitmq/examples/TestMain.java index 2cd08136c1..411730bc79 100644 --- a/test/src/com/rabbitmq/examples/TestMain.java +++ b/test/src/com/rabbitmq/examples/TestMain.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/TracerConcurrencyTest.java b/test/src/com/rabbitmq/examples/TracerConcurrencyTest.java index e80a197486..0c651e15cf 100644 --- a/test/src/com/rabbitmq/examples/TracerConcurrencyTest.java +++ b/test/src/com/rabbitmq/examples/TracerConcurrencyTest.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples; diff --git a/test/src/com/rabbitmq/examples/perf/Broker.java b/test/src/com/rabbitmq/examples/perf/Broker.java index cd0793e51a..d0561e983f 100644 --- a/test/src/com/rabbitmq/examples/perf/Broker.java +++ b/test/src/com/rabbitmq/examples/perf/Broker.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/BrokerValue.java b/test/src/com/rabbitmq/examples/perf/BrokerValue.java index 9eb654c1df..2ceba3e7ec 100644 --- a/test/src/com/rabbitmq/examples/perf/BrokerValue.java +++ b/test/src/com/rabbitmq/examples/perf/BrokerValue.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/BrokerVariable.java b/test/src/com/rabbitmq/examples/perf/BrokerVariable.java index 263ffc0a3c..e91aabb5c0 100644 --- a/test/src/com/rabbitmq/examples/perf/BrokerVariable.java +++ b/test/src/com/rabbitmq/examples/perf/BrokerVariable.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/Consumer.java b/test/src/com/rabbitmq/examples/perf/Consumer.java index 7355dbdafc..8825a91a24 100644 --- a/test/src/com/rabbitmq/examples/perf/Consumer.java +++ b/test/src/com/rabbitmq/examples/perf/Consumer.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/MulticastParams.java b/test/src/com/rabbitmq/examples/perf/MulticastParams.java index 95ec326722..5263ed4029 100644 --- a/test/src/com/rabbitmq/examples/perf/MulticastParams.java +++ b/test/src/com/rabbitmq/examples/perf/MulticastParams.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/MulticastSet.java b/test/src/com/rabbitmq/examples/perf/MulticastSet.java index 3e2c65cf43..9c46a670ac 100644 --- a/test/src/com/rabbitmq/examples/perf/MulticastSet.java +++ b/test/src/com/rabbitmq/examples/perf/MulticastSet.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/MulticastValue.java b/test/src/com/rabbitmq/examples/perf/MulticastValue.java index 45a4f29651..d728667713 100644 --- a/test/src/com/rabbitmq/examples/perf/MulticastValue.java +++ b/test/src/com/rabbitmq/examples/perf/MulticastValue.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/MulticastVariable.java b/test/src/com/rabbitmq/examples/perf/MulticastVariable.java index 6b0057c133..c051281529 100644 --- a/test/src/com/rabbitmq/examples/perf/MulticastVariable.java +++ b/test/src/com/rabbitmq/examples/perf/MulticastVariable.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/PerfUtil.java b/test/src/com/rabbitmq/examples/perf/PerfUtil.java index 13bdd900d8..2adead26f0 100644 --- a/test/src/com/rabbitmq/examples/perf/PerfUtil.java +++ b/test/src/com/rabbitmq/examples/perf/PerfUtil.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.examples.perf; import java.beans.IntrospectionException; diff --git a/test/src/com/rabbitmq/examples/perf/Producer.java b/test/src/com/rabbitmq/examples/perf/Producer.java index b2748d417d..477f2319b7 100644 --- a/test/src/com/rabbitmq/examples/perf/Producer.java +++ b/test/src/com/rabbitmq/examples/perf/Producer.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/ProducerConsumerBase.java b/test/src/com/rabbitmq/examples/perf/ProducerConsumerBase.java index ad4bca9ae7..a5edf755a8 100644 --- a/test/src/com/rabbitmq/examples/perf/ProducerConsumerBase.java +++ b/test/src/com/rabbitmq/examples/perf/ProducerConsumerBase.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.examples.perf; /** diff --git a/test/src/com/rabbitmq/examples/perf/RateVsLatencyScenario.java b/test/src/com/rabbitmq/examples/perf/RateVsLatencyScenario.java index 2747a80788..588ae18e18 100644 --- a/test/src/com/rabbitmq/examples/perf/RateVsLatencyScenario.java +++ b/test/src/com/rabbitmq/examples/perf/RateVsLatencyScenario.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/Scenario.java b/test/src/com/rabbitmq/examples/perf/Scenario.java index c02607e9fe..733920dd8e 100644 --- a/test/src/com/rabbitmq/examples/perf/Scenario.java +++ b/test/src/com/rabbitmq/examples/perf/Scenario.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/ScenarioFactory.java b/test/src/com/rabbitmq/examples/perf/ScenarioFactory.java index cb1e536dbf..287249875e 100644 --- a/test/src/com/rabbitmq/examples/perf/ScenarioFactory.java +++ b/test/src/com/rabbitmq/examples/perf/ScenarioFactory.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.examples.perf; import com.rabbitmq.client.ConnectionFactory; diff --git a/test/src/com/rabbitmq/examples/perf/ScenarioStats.java b/test/src/com/rabbitmq/examples/perf/ScenarioStats.java index 486bf2e6dc..89ca97e3d2 100644 --- a/test/src/com/rabbitmq/examples/perf/ScenarioStats.java +++ b/test/src/com/rabbitmq/examples/perf/ScenarioStats.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/SimpleScenario.java b/test/src/com/rabbitmq/examples/perf/SimpleScenario.java index 4a5fbb3bf9..219e6792ac 100644 --- a/test/src/com/rabbitmq/examples/perf/SimpleScenario.java +++ b/test/src/com/rabbitmq/examples/perf/SimpleScenario.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/SimpleScenarioStats.java b/test/src/com/rabbitmq/examples/perf/SimpleScenarioStats.java index 749913eb2e..91f5fb80ab 100644 --- a/test/src/com/rabbitmq/examples/perf/SimpleScenarioStats.java +++ b/test/src/com/rabbitmq/examples/perf/SimpleScenarioStats.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/Stats.java b/test/src/com/rabbitmq/examples/perf/Stats.java index 2e65f395a8..ba0c9d44e7 100644 --- a/test/src/com/rabbitmq/examples/perf/Stats.java +++ b/test/src/com/rabbitmq/examples/perf/Stats.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/Variable.java b/test/src/com/rabbitmq/examples/perf/Variable.java index 76b8973583..17042f5f56 100644 --- a/test/src/com/rabbitmq/examples/perf/Variable.java +++ b/test/src/com/rabbitmq/examples/perf/Variable.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/VariableValue.java b/test/src/com/rabbitmq/examples/perf/VariableValue.java index 13f01ca41a..44812fa055 100644 --- a/test/src/com/rabbitmq/examples/perf/VariableValue.java +++ b/test/src/com/rabbitmq/examples/perf/VariableValue.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/VaryingScenario.java b/test/src/com/rabbitmq/examples/perf/VaryingScenario.java index 51ab11bc83..d34938e247 100644 --- a/test/src/com/rabbitmq/examples/perf/VaryingScenario.java +++ b/test/src/com/rabbitmq/examples/perf/VaryingScenario.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/examples/perf/VaryingScenarioStats.java b/test/src/com/rabbitmq/examples/perf/VaryingScenarioStats.java index 9ce509b1fc..317b24c863 100644 --- a/test/src/com/rabbitmq/examples/perf/VaryingScenarioStats.java +++ b/test/src/com/rabbitmq/examples/perf/VaryingScenarioStats.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.examples.perf; diff --git a/test/src/com/rabbitmq/tools/Host.java b/test/src/com/rabbitmq/tools/Host.java index 2bac5cb01c..8db1de8501 100644 --- a/test/src/com/rabbitmq/tools/Host.java +++ b/test/src/com/rabbitmq/tools/Host.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.tools; diff --git a/test/src/com/rabbitmq/utility/IntAllocatorTests.java b/test/src/com/rabbitmq/utility/IntAllocatorTests.java index 77fe5ab3c4..ba0f5a8633 100644 --- a/test/src/com/rabbitmq/utility/IntAllocatorTests.java +++ b/test/src/com/rabbitmq/utility/IntAllocatorTests.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2011-2015 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.utility; From ea03f4c973a8bee9e573e321f9a28b5caac93e6f Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 27 Jul 2016 10:51:32 +0300 Subject: [PATCH 0181/2114] Update two files that were moved in master --- .../test/functional/FunctionalTests.java | 23 +++++++++---------- .../client/test/server/ServerTests.java | 23 +++++++++---------- 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java b/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java index 0a74510412..46996c7cc3 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java +++ b/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.functional; diff --git a/src/test/java/com/rabbitmq/client/test/server/ServerTests.java b/src/test/java/com/rabbitmq/client/test/server/ServerTests.java index e4c0768d2a..04d6fc4ba1 100644 --- a/src/test/java/com/rabbitmq/client/test/server/ServerTests.java +++ b/src/test/java/com/rabbitmq/client/test/server/ServerTests.java @@ -1,18 +1,17 @@ -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (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.mozilla.org/MPL/ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -// the License for the specific language governing rights and -// limitations under the License. +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. // -// The Original Code is RabbitMQ. -// -// The Initial Developer of the Original Code is GoPivotal, Inc. -// Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. // +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. package com.rabbitmq.client.test.server; From c6c7e70162e5a642b90b7abcb0c7fdaf4c6e5051 Mon Sep 17 00:00:00 2001 From: Andrew Bruce Date: Wed, 27 Jul 2016 09:24:53 +0100 Subject: [PATCH 0182/2114] Add license text to two files added since stable [#127089993] --- .../impl/recovery/RecoveryCanBeginListener.java | 15 +++++++++++++++ .../client/test/AbstractRMQTestSuite.java | 15 +++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryCanBeginListener.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryCanBeginListener.java index 6326f3d288..73b5d25206 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryCanBeginListener.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryCanBeginListener.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.impl.recovery; import com.rabbitmq.client.ShutdownSignalException; diff --git a/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java b/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java index f01e137bc8..48c15f45e4 100644 --- a/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java +++ b/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.test; import java.io.File; From 7936b295a029cd82b22846c937e8fd8def5229fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Thu, 4 Aug 2016 18:29:25 +0200 Subject: [PATCH 0183/2114] Fix a few Javadoc warnings [#127354185] --- src/com/rabbitmq/client/Channel.java | 7 +++---- src/com/rabbitmq/client/TopologyRecoveryException.java | 2 +- .../rabbitmq/client/impl/VariableLinkedBlockingQueue.java | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/com/rabbitmq/client/Channel.java b/src/com/rabbitmq/client/Channel.java index bf7c7f002c..20c098ea5f 100644 --- a/src/com/rabbitmq/client/Channel.java +++ b/src/com/rabbitmq/client/Channel.java @@ -259,7 +259,7 @@ public interface Channel extends ShutdownNotifier { * resource-driven alarm is in effect. * * @see com.rabbitmq.client.AMQP.Basic.Publish - * @see Resource-driven alarms. + * @see Resource-driven alarms * @param exchange the exchange to publish the message to * @param routingKey the routing key * @param props other properties for the message - routing headers etc @@ -275,7 +275,7 @@ public interface Channel extends ShutdownNotifier { * resource-driven alarm is in effect. * * @see com.rabbitmq.client.AMQP.Basic.Publish - * @see Resource-driven alarms. + * @see Resource-driven alarms * @param exchange the exchange to publish the message to * @param routingKey the routing key * @param mandatory true if the 'mandatory' flag is to be set @@ -296,7 +296,7 @@ void basicPublish(String exchange, String routingKey, boolean mandatory, BasicPr * resource-driven alarm is in effect. * * @see com.rabbitmq.client.AMQP.Basic.Publish - * @see Resource-driven alarms. + * @see Resource-driven alarms * @param exchange the exchange to publish the message to * @param routingKey the routing key * @param mandatory true if the 'mandatory' flag is to be set @@ -381,7 +381,6 @@ Exchange.DeclareOk exchangeDeclare(String exchange, * @param internal true if the exchange is internal, i.e. can't be directly * published to by a client. * @param arguments other properties (construction arguments) for the exchange - * @return a declaration-confirm method to indicate the exchange was successfully declared * @throws java.io.IOException if an error is encountered */ void exchangeDeclareNoWait(String exchange, diff --git a/src/com/rabbitmq/client/TopologyRecoveryException.java b/src/com/rabbitmq/client/TopologyRecoveryException.java index e2cb4dfdf8..0c2bcc1f5d 100644 --- a/src/com/rabbitmq/client/TopologyRecoveryException.java +++ b/src/com/rabbitmq/client/TopologyRecoveryException.java @@ -18,7 +18,7 @@ /** * Indicates an exception thrown during topology recovery. * - * @see com.rabbitmq.client.ConnectionFactory#setTopologyRecovery(boolean) + * @see com.rabbitmq.client.ConnectionFactory#setTopologyRecoveryEnabled(boolean) * @since 3.3.0 */ public class TopologyRecoveryException extends Exception { diff --git a/src/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java b/src/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java index 41cb56a0a1..756d54e614 100644 --- a/src/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java +++ b/src/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java @@ -235,7 +235,7 @@ public int size() { /** * Set a new capacity for the queue. Increasing the capacity can - * cause any waiting {@link #put(E)} invocations to succeed if the new + * cause any waiting {@link #put(Object)} invocations to succeed if the new * capacity is larger than the queue. * @param capacity the new capacity for the queue */ From ffcf86681eb0909f73393842b970ca2b70f74924 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Thu, 4 Aug 2016 18:32:01 +0200 Subject: [PATCH 0184/2114] Fix one more Javadoc warning specific to `master` [#127354185] --- .../rabbitmq/client/impl/recovery/RecoveryCanBeginListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryCanBeginListener.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryCanBeginListener.java index 73b5d25206..c9f6d2fe04 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryCanBeginListener.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryCanBeginListener.java @@ -19,7 +19,7 @@ /** * Used internally to indicate when connection recovery can - * begin. See {@link https://github.com/rabbitmq/rabbitmq-java-client/issues/135}. + * begin. See {@link Issue 135 on GitHub}. * This is package-local by design. */ public interface RecoveryCanBeginListener { From 33eefc56ed34c690297cb50921897779f43954fa Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Mon, 8 Aug 2016 09:40:03 +0300 Subject: [PATCH 0185/2114] Add a note per https://github.com/rabbitmq/rabbitmq-java-client/issues/163 --- src/com/rabbitmq/client/ConnectionFactory.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/com/rabbitmq/client/ConnectionFactory.java b/src/com/rabbitmq/client/ConnectionFactory.java index 645ff774f5..a0251f1b7c 100644 --- a/src/com/rabbitmq/client/ConnectionFactory.java +++ b/src/com/rabbitmq/client/ConnectionFactory.java @@ -377,6 +377,8 @@ public int getShutdownTimeout() { /** * Set the requested heartbeat timeout. Heartbeat frames will be sent at about 1/2 the timeout interval. + * If server heartbeat timeout is configured to a non-zero value, this method can only be used + * to lower the value; otherwise any value provided by the client will be used. * @param requestedHeartbeat the initially requested heartbeat timeout, in seconds; zero for none * @see RabbitMQ Heartbeats Guide */ From 90c72901abc955ff307cbcf3cc3613f2dbf77359 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Wed, 27 Jul 2016 15:08:03 +0200 Subject: [PATCH 0186/2114] Remove copies of third-party dependencies Maven fetches dependencies itself. [#127354185] --- .../com.springsource.bundlor-1.0.0.RELEASE.jar | Bin 133712 -> 0 bytes ....springsource.bundlor.ant-1.0.0.RELEASE.jar | Bin 17007 -> 0 bytes ...pringsource.bundlor.blint-1.0.0.RELEASE.jar | Bin 13577 -> 0 bytes ...ource.bundlor.commandline-1.0.0.RELEASE.jar | Bin 13838 -> 0 bytes ...ringsource.org.apache.commons.cli-1.2.0.jar | Bin 41571 -> 0 bytes ...om.springsource.org.objectweb.asm-3.1.0.jar | Bin 43557 -> 0 bytes ...gsource.org.objectweb.asm.commons-3.1.0.jar | Bin 33255 -> 0 bytes ...ringsource.org.objectweb.asm.tree-3.1.0.jar | Bin 22502 -> 0 bytes ....springsource.util.common-2.0.0.RELEASE.jar | Bin 42376 -> 0 bytes ...om.springsource.util.math-2.0.0.RELEASE.jar | Bin 8384 -> 0 bytes ...om.springsource.util.osgi-2.0.0.RELEASE.jar | Bin 94153 -> 0 bytes ...urce.util.parser.manifest-2.0.0.RELEASE.jar | Bin 24242 -> 0 bytes bundlor/lib/org.osgi.core-4.1.0.jar | Bin 163485 -> 0 bytes lib/commons-cli-1.1.jar | Bin 36174 -> 0 bytes lib/commons-io-1.2.jar | Bin 65621 -> 0 bytes lib/hamcrest-core.jar | Bin 45024 -> 0 bytes lib/junit.jar | Bin 314932 -> 0 bytes 17 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 bundlor/dist/com.springsource.bundlor-1.0.0.RELEASE.jar delete mode 100644 bundlor/dist/com.springsource.bundlor.ant-1.0.0.RELEASE.jar delete mode 100644 bundlor/dist/com.springsource.bundlor.blint-1.0.0.RELEASE.jar delete mode 100644 bundlor/dist/com.springsource.bundlor.commandline-1.0.0.RELEASE.jar delete mode 100644 bundlor/lib/com.springsource.org.apache.commons.cli-1.2.0.jar delete mode 100644 bundlor/lib/com.springsource.org.objectweb.asm-3.1.0.jar delete mode 100644 bundlor/lib/com.springsource.org.objectweb.asm.commons-3.1.0.jar delete mode 100644 bundlor/lib/com.springsource.org.objectweb.asm.tree-3.1.0.jar delete mode 100644 bundlor/lib/com.springsource.util.common-2.0.0.RELEASE.jar delete mode 100644 bundlor/lib/com.springsource.util.math-2.0.0.RELEASE.jar delete mode 100644 bundlor/lib/com.springsource.util.osgi-2.0.0.RELEASE.jar delete mode 100644 bundlor/lib/com.springsource.util.parser.manifest-2.0.0.RELEASE.jar delete mode 100644 bundlor/lib/org.osgi.core-4.1.0.jar delete mode 100644 lib/commons-cli-1.1.jar delete mode 100644 lib/commons-io-1.2.jar delete mode 100644 lib/hamcrest-core.jar delete mode 100644 lib/junit.jar diff --git a/bundlor/dist/com.springsource.bundlor-1.0.0.RELEASE.jar b/bundlor/dist/com.springsource.bundlor-1.0.0.RELEASE.jar deleted file mode 100644 index e8a8fa37ef201751101159168e7611b23daf4ac8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 133712 zcmb?@1yH5Qk}gf-+PJ&BySux)9^BpC-QC@xacJBdcN%Nly>Wlcojdz>CU)n|ZagB2 z{}54`@#lBGl*+0?Ug|Rl6wq%!*z%0r|N8LnUywi`Kr$lA0yGk`qI7SgKtS^Uo(chk z^)VG!dfYDy7zk+jLmK%*b!*pU@`qDdS`m2wKg?^&& z5D&lxuIjHt?mQ*tvf5rufswFT^W_`WQ!wOe<^mZJAjZob5gV0D0dspQ4Mo4)5C#02andR3-|%~c|DZllT#m=~>> zre^SZOqtqnbmlNNRwwU6K6ushph26a2A|f)ofS8LRo38mhG&wa(bK(Y^0lT=A689o#rl@ zD``7@EvhX%CJ1v}Zzb4Lq288n$p0)*A*$AH2HL7#`)I@SEGx;iZI+6y#>%c7`Ovp` zBa11$4+6^6MVB_8HHOwi0Bj$HuT!t)e

eu>^r!D|n`@w0JG1G^Y$n|7OrKZLFRM)o(a zuyru~n;E}lf!}8Q?iD5u2G#&qTL;U(k@(Fq{ws+;y$Zy?9MqznVSn~xy6Gn%Ao7pr zZw~q=_xr=2gnpx={0ALr|3yr$TiYdGFfcG7Fdr8%Qc)FoK{mQwa+N zLq%CiqR(O;7U7n<5(*?lfz=`Kf+BX1BdC@#czvn?O`;6n3{a1r_NGWXxXQHkx9 z?c@Iv^4=?0jE~52g+PtQmctQ2ObQmg)!+U2v_?)4uIbf58|>Clww9?BUn^vEHOX+Lj$Siia^*-{b)v%Pb;qiaiJe zG;88$V|xX1n%TJ^IZ?7BudOmCC3z5;Q$AS0@%q7&kc!w{(W3EAZk)Wj0sk<>B+yrf z_TD;MAg|C|#~^T@QCK$Xhc}+!LE?yKF1M(5;_Hhu&^>6$V&hPGQJz;+4@ocStU|uU z4G~FrV@|)_`nHfxuqdnGBNA97rm^9n9Br)rcCz+R7T3$MNoR*73b9oxjLy|Ze}#Po z{%5nd+vtItKFsC#AjaQ@OqqX&O0nPUHTVd=zuTN0+YJ{$k3LWv<|ix58_4;Cohjk4 zU}j*ZTwg@oTtaKj8){>)7yL3mYO_0d0;_AyZiCMCe)twlKO_e}R6n6CAVblVk)>i5 zvecgBUeLVVkde#I2u<5zqH2~`J3wGkHVTSVsXfLqM?C=Fn~c2|&}el(4*8xN};#{6Ix12m{Q^u`INRlmX7BlCrVcoD$ZD zAr$uei#SnsYek1hQI;+S%8V*AXJ7Y=iNb30Ny&fR;*~oJ&Zc0D!CLb+(z%o;?~E=R zHs2>HTAWaHa$7B*zjhr#mZ!$1*k%Jfs0o8Z_cZlZl>hs*L=*dX__Q#Wfu)-M_7wC4)j8gGfOC zu?k*6^N6|BU8}CM~wO>HrOMnWjbGaL^^EO+HIym zqkX~tV(Noz=z_$ef*?q)^F8Ov?ZulZ=j!d{_KeGqQ4$pq#>wITc3HT z&#=-8WM418`3^TyDEG}c?fqUp#5nX8^hETm^Bxw>DnWTKoT~&3Gys|+%o<47%pT^+ai(ew%&cz*X0S?Tx?c=lp17|2a;Dd!vm} zt5T_G>JbZLP;;}2=H?++XKd(*731=mG?Nf}4E-Ko-J4-4eKjSc zVbE<>MvUSKm_mNUD~Pnb7s|&H>W4gfFW5ZiTaj&u518k6?!>Nc`qq_`g964 zr-TCy8scazj0ImeStp)m?EyDOj;@QgG5$lXvFVZIETOIYE_4I%7jU7?g9n&E>h zfqBDj&LX#hln`a?u>;MRD=yJf!Xbp{7Kv<48)p)mZHK^-Kwa?w!k=ggqVeM;f+VEc z?aj~0!D;0Z;b@+mfwNaHT8JSC6>*kf@ecMnQph4Tk5?p%Kq8ZT zm9#o-wZRgdRmX5;X3E9@{nnTy=-$HbeD#YN98Gp5b8O{8z=t)t|}9C>fkS5%=F~x z${2)L9KT-O1f*Pn1cW*%-GhN<5O&T1`x8)A2G0bkf=)m{tuYs5uBa2_E@n}%SepT_ zidIEgNLR+to=`=9y68BEin6BM2iXE(%iNl6E|07|wObF@vkcF%u(8^!WKrMB+|=;B zgrp%7tWndqGLRTF7P7$j-%}m(m-bA|rwxd8(_(WG!v%u%@@JO>aZu+6!pc%HyiPJH3$&wX5xE<#SbwuF>Q!;nH4w z0<~72O0K7i@+=DN1V%dXREJaa5izxzRhp-Iy_H_n-mfIG~_v|O2+=0B{!iBZL3(pLrZ@u zcNUhs>U(VUvuvW@NO4QT-#piz=2m*8Ip0*dO=cv07PV7zfUL+r)C=5DR7%aPcFYnYNDg0XqBzeMzg7MrJwB72M_LAN@m^+=(UUq4Q(G$> z)!3CNXZDllxa@lBKuZSOC0sevu^C_C-a6`z8f z!EE71hf&Z+pq&u*Eb_+K>K2+h=79#9L~TUh)Un!%#L*KXl?Uly8ajfoL21R^JhUe& z=hQYI!8&Tee_cu!WX3}lN*5DU-|;dc|@>JWe;%2T#M1{PzD zVX{(-tD0=G-Rj6KJyF2*PnvRUr}Zqz_Ph-V`$C7u8_gmM@wpC z$R=EhDOmrhU6j~$uQH|(({Qk1(v*F1&!TY^u%xwX`f?$Ca>aOrX_6oRswcAZ!y1F7-8;^)dMAdrPE@k}vq$Yr0IW-gXOxy`Vb*%jPb3_;-Z0!Pe{2+~a${|Y;F$rZJ8KYs^4yUb^R=sSe`CW`s!I=-2kHrRbh{}#@&u-8$#@{{HZGVerE7|(0r>Vl^COD@W z<1;R7va!$tH6MR8(E=H7nHj3oD-zKcLZY`{fDXlhlcb;M(UU`gYH+Mn?`k(64-}Alo$C?M2;fpX^>Cf`y;@rIGNPX90{bF^9yEgP#>^5R6M83&B z_{+k9EHi@k!Mefm%r?FnHX!xBGQX%^$seelL;wq0BFJzRW-@C?Z>LGc9vrq~YHxKd zBykl6b;`Uc{n<-su?d;z=Zbhjdi2OxF-CIJRXi6M$-bnw>82V7I2s0>LylsHl37RB9z8j%pbv^`PL|PeW#GvM?ltWM z!RE{4d!khQ{G z4as5prSU3YF(=IhlO1xVej>V(K7rMijaH&lU<28rxBS(?qmPoqJ|qP|mC2S>Z_PL^ zm0F5;A#JUS7%qp@U}VX*MKU+i+UIzinD~rN+u|6TNo`!^JVp{a!a<>+eOJzN7ty9N zjuAs)M%-^X!mL)=J#sKK@;y9GxxlA9)FQ2NzCkUy)es%E4~^JQJ6PAWr4Q6Khmy&s z#U~sE^!psWgrg~k^{)A=Bf2k~xKXo9v^!`o;C{KtsK}wj2@3;tBm3%{`+VKlTVi6H zaW;uAy;#s@wGpFciKpMw2-4GPbX04Sxj#PskW%Pco4}}f8)DLeJ(>w2%k;43XQ9R_ ztBc!hHG60SjsAmtzXJBoj2Nb7hncWYCfXo#qvy;pCTGWCL5M6}dr|&sB(3G)Z2=YL z)AUrK9CKD5kh?(NXy*Nx7R8+IR!c}em4Y}{n@WGPo9F$oiD`cUMs~S30p&y--DB0! zNR9ArO?=tL%lU&3jHSCyQAU!EEia7jmM0Ie_GN_pGL`jq6n@@iH+U$5BIl+#BFrVt z>^D5o3w*3oq~q0#pvX`PnY%up1ch|;qc!M4B(pGW@jWxI(rPjCX%ujA{GM^MSi*2H z%^g2q8s&BS3e;+S-&0mbj7N6>d2Eo|sO89xzNJM!V^^4d@Ycf{$LeH_2%T~tFT`bBJ+MrqUMsOE0 zq5Bu&Fx&wZF3KUM;7R3cfmjMT$Hn0SwMnQC7(86T24_yb`tl~SU*8ostX;NPK5 zR(B2tv!Pdo2rbyPVv1I7nXzD3hIp`G$9`o?+r&%kZj;a{o*Gl8Bri6RED2P^=+S`L z;-)qDVjp2+gq}+jL53de&rqebVaY6bJv&(13ipOKjEvA}$mb|ETMmBV$b82I=35Pc z>*(7-%paqQKL@-U0?$Y+R6|a{1Z=zrj*&vJloXcNSz zGXt)O_~e#U%%m z8x2%TV*5oq;Qkt-Wkkf<6Q$|*DH?py^b?`13;Wh$_rvkDOh1wLhaAW=2hb23Ih^NK zjQb1r5ixAu1{U(@#|y^S0_piQtzMsx!CGtFPw zW~**!#U>R6>*!>=MoS!!jf$##_3%_FAtZrFLD$tDipELShg~ZUIA2JuyQ5oMso}yH z%!INLrv%SpnumXKV*LQieShuD<&z7`OI{|zRkv0KxV_H26Yme|57ReIOX%S|69;LO zV^sTksCr&0{_L^6i z2(kG7rI}@CtZ!NN0ovBb_(#paKZ*kxTVrz*^FQDNd@Soeb_#+wgk|POhq%mk5;%+X z0d-$a+3b;6tz7!wAap1CKD&`KAbg#s2%-4-+~v+~>k33+0!b*SnUT^qDXGJSWJRHl zaHD}SrhUk1#52~Gl5EGzW~w1!fD{E88KTFoq`h=1&s=a5)QSVFCfL04E)bX+;k?Fa zpz-|4=et&6=k!m&36g=27n_SBWZy5fE{qNafBHW9`FBPEZf)@=9D^s|KQqT^)XBQz z!*I}#PU!!LIf?)S+up(!ig zNg-Z*Jd*Pu@}QgIqnd(aZ@o!9pv5!*I=TFoCX}v)7U+^hZ<1>>vn;vOPp;u1Ya$9)(0y<3D`^bS>uaQKAA|2>{68DRe{ew=U~Ok*-~{+HC!A$}+Z93Yn95bn_WI3=?bscXB%Mas;LNmzSh6*7|Z6Dd{%n>zo1$o5-!Q!AQ z){rKe(;o_bFMie^H>3XbF;K2AA$OK@bUGWQoJB~8|ie`gu* z;6`vTOS}xsvauYx)kb*ntTg&77lZX35^#Pr*v-?t$SipgolX8d$e)3@oVH}H_yFM3 z2QPU42@vwXZvg*+$DeTs{`XG7MdeCGBHkwWp`jhpS~hh=fagjH35kqg2Gm=|zqSgh zIU%>PXl+}wJkMiKV0#b?AwC%-XGAP4O6bg&*q7@|6fyy@E3qu2udSxCQ?&=R$F%2p zS<}ah?GT=VB)(5&QPe;;OG(Ci2&y{=Llfj!zt^8->UjS+#djM*BI#mXx<)ea@?v29 z@Q$0%g#sif$ROPILRAO9y5}!V82S%?L17a|%YOR9dh7os3W@+nTPv48+{8IfK=#8; zM0^7oH%C9a0j;asoA$vWsiDK<Vb1(Q*TY5{`!%0_US9Yrc56tE{ds zvH6ijLEXUQRMr(BFFbJui&Ev+UqPcKDIyt7OJ7ti*Lxb-@{#Pd6>TmSfY!j+q;{A% zoLXiiOO@9P}{KPdAbi;dqG7=!B2Zc2L?KJTpG%@Z3`$w7hpI#x?) z1bQkYs!^%st)XWXsgG}%Ig<1}5EGRl^RD}pS+l;i9%X%FXXA1WmMKq$U5n;uX*)Wf zYs);}K6gZOP3(NB^q^cB7`UF1em2YJ>$8W#}xHy*MpacLrD%s1oQ#+)N%ylRQ=Z z$-Eqm>S9I)njEbzQ8}{hrIE0v`31b?6N#dJU1ft5C_EGBEG@ws(*E*`>i`$YqBh`k zqsjgx4SXcEbquDP^R4_(JPVbu1J3?O+2LWR7judX?zVhR0M?gB0+7tARsw@}K^8$rr$Y6uB1CI_~Ai&7*{%JpmDe))X2I}|0w z>2h-5N*!!+@@Ps~MyD0@pPeRA`Ams9Z8l>ST_XZWgF>X4)_|HwNKw{ZCpI&XNCBk` zP$!ocsy@p!I)X76UeHmv@4okpj~G-JOqmX_7qwK-VQo3OSvpN4)g?QFex8nMK*<_x zc0R;HIlv!q8fI*h<+%QG1ozB=pgCQ!sof{%Rk_WbCFg~ zb_@e=#m+y%h1xW{=;2V1h6VTVQUR%(^~ zv}XINQ#5FU?vQVC!~)|R6ZX}Gq_7c|;kaJ_%Nnet?dRq!c(g*bK~3`nQ*qvLNtF|2 zZ9)~C3;ATG*?fo29uAU9>ZJR8yv~H>)Jiv;8hj~cp-9t~!?XIYN4xVSv*J9roK#hG z%Q2+_N(}hfIb8P7b`RJn?4A|gzH56BtRrUdP)^CyH&SQtx86{Oz*3~3%or<3M!+|M zx*lH<$RzJ~C_{>#8?ZTCZ5W{tLzNWLY(mT6!D>|F6Ns<(O$jGqh+QY#3|fj6HC6Ax z>1I z=+6RP5QWA;2=?pgN8ZfwiHA~Ta$Eax zMIMZD@-@tw9`DBT%FdSR@D$cP zmPK?raNZ8iq75jn-657&Wo_|R8sgnGD8U^DGV~AGa*u~8<@G$_zhy;C?LY%p7$FkJ zC~!_zGC@OmNeq5^{HmFcrGTU%x@nK17Z1N4??yOLq2Y15vYT|xf}%Gyack|>DG+JA zQUx>ud4N?sejDt-s3uqLhPknw3StjPq<9gprQyTU=)7`)#VEyW-Wa;j}s*QiMy z;gi1-;uaD`XzLe;Gks893i6Ct_pvUI-o1mE8Xr0D4Jm-p0AQAfbW3cI_!j*r{3GwFZ5SyE-5#qgOmSc}i}6rLE2E z%RL#*1Dj*Z8po$zZ$vXnr}7DZ;#TV$a|F$O&inO%`O`Vg($CyKq_gbU_DA53D1#&N z+q#!}$d3C>2K2E#HgMW-WqJzG{!WvhdvRJ`T=)HQ-K)0Jq@%MwG8qUa?$CGtp-}r{ z_Cu#uH>=&R;Vv}%C;_AokSXf89h~sG)+>4;SoWO9)GPoEw}&JUNbaD-`@Al$Y4(Vc zxUqH~BN$T$t6x!@Al;@g#UherlJm9%ayY1Hw4c886 z2fH5FC%G+)_j^lIqqP^QCy>77Mvu_`LnR8@CXhNB!sLX(8AEwo!FPs6@8qn(Ybk3g zDOrTkN>&_1yH}ns=M2OYWxG+Uk<6f>Lby_wm{N6yAlI)b&HAiG@^Oe-phI@v7>nQ4 zN*)}OI2SG~@&sm6GP!>Y5+`MTUj^cejZ8}$lpaf$He!l3-O|QY!w(|wds%_o(rnz8 z%?kB&_W_dPNYn1&DZ!DudVx``r*ejnh3gx;hOz0mo~990C*gEE@5M~~vI-~&&LIM+ zwdseGfY9wkuq7m*9N7C2zG|-3bl9KyxF`}?vIW->yc?5%Z#%f^=1g|x%@u32BJc0I zncd-$T(3wGfL!j zkXs=KS3spK0Z0$^QtiBjw)vZIb>*V>M(?w$k|(TV8|j5!gZV_V7bm|S;SH5!&7m1l z?aHGStl{AxY1ObwYt{k865N&CQ&$j2A-MYn?5eAK6Ox>~5UgsZ0y){8HWL(7uES-0 z0sbPRM?KDYUBz~#stP@#gvNTwj+_hISBGv2sqIxjkucsx*OW*VNXu=3J-0D_cIXc)4JznAH?xu^d@phOsw*Ayk)lDvfgD6Ak_B2roAz3aAuO`#jvCeuY22@ zOb7fkl2F!t|BrwZw`SlUGGzY5wY8)SirU%vH}p~$nxla5`egFeu)6f`Q-}a6g=U5z zHhIdiWUcUK*rn@p)-@}z<^|&Q7%zR-w0xxfWRxE}=^1EOSYR#;w0*W$Tq~Uc@7=?A z(gpT{&Ed_#t_cOu)nDFcVC?T9USwSS^o}jYK_6-XW}_@sed}AOh)=3nLymE(Q5SH~ z*Q&IQ)mi=9FW_$yM~ocHD=t=yt^%l0b1^jt^UV9Fhea6gjC1CimxlSET;X0^P3OCJ zuAxTP&_7T|6q7wT3O7-d?lyft{do4F&`xh6n`2^S`Nx|J0pP(@;WILw=)W zl5Sv*EZZEQjtHrX#YD#WB7z(*^BJU2L%P3lnsbil=!hV}d*eRsmVvHos6tp!F?rO{ zNATA!p2V+pE-WUP8EK90QW2O>F1enQuao!Ly!UstzAq0 z;;bSr+mQVP7vkgAd|^ghS8Y1xGYppjJ0heIYaM2!pFu~oX*FQo{I4WN-yuX`JqesV z&J#E;%po9xY%m!4lK7R@?0Ck)OmgJXA<5c_X|}Gkz_^swTIBGjZI@Hn@a#X1P%fLACsYGK4yWY_aGvmoxIWoe{XHP;#F+-f8wqFJ>6r*tR*or(AToX1q~(nenzkRrIdC}H zhlmjECgU26rqYWkTj`}|hrb{k*>w6asj@Hon)`9`e|Gc{5CKdYSS2q+Z!wI(+Isfg zGjuFzkJ97UFr7iMihB;TsldM=!_APZGUx8v?w~Xz% znT)M@b7faxzM@atsc-U|V;-^x6ar_WO566;oeI#&@Gx!6uQY@81tA<*4BKh<$MMVL z2n<8QT+buOc?8aoZ^SGDi!Dn$F%;||iNs&Er^7?J|hP^wVMvlOT95LM9Rib*LI@N08Id}VjZ zj&r#)PE(GZHd7~*!qVg(1>qRMTnAQUCB8hM%3b9IN;1-&y2jd21}mV8obzI|F8tl{ z2s)?t#jIqQRul+Rso^Vz77$B<0_b})rB>pvpCyJHMWx#Ihh!jA)%u?7)3`8BRhu@t zoJy&*?vHTJ*#hsBE)QQ8AL@9@s`E%#2-LfPb-MuQxxfomg3XBXSjRJypj>XoXWIfr zSm5cG3a3i^rHWFf{%|w6gwh-<{R-)rXL}>1qR*H3TcZl_cZo%kLH2%&Ktyc$sb5*J z3v}d$5A!>-6x_6Bl^$VezCx)=mOgby^fGdAQ-m75)ZOXz%ch?S0e5en8jCGa zPTGqe7nn$$>;UV%KYGeWh@w0K4R;PW#;uyrxi-{|HtKBQPMB~)5oI5d?<<#NH%<@< zdI5d`rT2|N`s{;@f1!gm7p$0HwtECK1ZfT!FisuCKfUPiFSdJRVFn*lyNc?=fdhF( zWf8A%}U-^Be~pYckpP6lh~wJ!_?Qn?uCQ-waid}PB=Bp(07F_TOlo~=vJRT zz6rZO8WIHA5#FL~a7(4)6*U*was}sTmS2Cd&BNH3n{&Z5<)>%?Zd%OEmuG767P|b1 zM{(=sHGz6IEIC+-Em8B0tHHxsuQGKzXxvM2D2PdNy(4F$MWCEPba3c#G>YME7c;rN zq0PCHI|$QTbQf?_)_WjXteq{PmB#8%hdf00{+E`o)c3r^p^tQg@X^%b`X_1WkKU&E zzgoWkx$$cqBlBD1H(2kH&4QJH%MoZMS_V~vLIVsfP>>YOY}nB3=m_J9EUvQc5(rmv zmWhy7nkK^IlJ}TPFNO@r)=hGnpyNP=Lfbl-LL0?u(hzN2S5385eku8OJ9A7^YRWRj zvsv#w` zl)T1%oEgOaxWXj%PvH6Og3!nL;Exlo|2`k=2ypn<6$@2!NAv$UEZ(HH?ufO3@?LFi zPU0?vO$JqF?k~?a5@X0>jxZ?kN#ut}`5A~WiL75;%Hkd8tmJ8pGz>{&w2+iy9u397 zO<*exi*-81IP#!*iTikz`*EV))AW1M(Z$bX07nWW(qVtiC! zud)IG0Y;^f;p_ryO(fZTW7DVy_3xwmP%di}D3PG6(I>LJIgL6-+Ec9(Qd1M`A=#rx zF-(S>C0cbV%oIOV>d3Z(zfutGbm>P)U{Fq?QIq}5rfX+X(d`cKT)JL7R;nXe$i&9x zUd}x|;dM98`$pz1Ens<(#9KY=*v^80=M?L_;}bL0rD;$FD`;k9 z`&ouZja8HC%?3gK0!afTzb2IKu#r!vlO;$`Nlx9@o<# zY;)|iaYY=9pxFQ`EDZ#eSyXc@NdBe`EG8?%yzU(1lhh+aKkn?XL&%6KLE(X@(<<^t z@*t_}tP^sP&BekQzG+gIxd7#1Y{}e7{v$UP*&*wEOGT?*@7)vR;w4a*>@FG1 zecc*%g4;lWbE9=o{Kz^R^IGr(0e6@SiUO!7pPC}&75q1o$(d>YbtuA{qSBA5K&>^uHvm# zw=itnXFmp;A0f$Czy`hC&m{9#;jl;qI&SLyu9xBqI|gDuvfmI-ZH(`jUKH|Vv6_ug zsX-+(UaL$QLxg-Ys39$;8OW&DX_gacQD9d;a~W&a7&HKaF0@XR*(#eyx5KScWRe=I z0xG}F>Z{=-#Vk?ns^ll7Zh02)D5DmGdnzs3F%l9xe5c66KIk8Um00B|i65h6 zN9pV*tf$F-zfNk<2JlQ>HpdC$x^J*bN=deWXiD3DLG!%li(@-bRD^lM*`slW@ z*l+Hjj>#~6B9?@OX2l{UHk4csKQ5{&y9o4839o~!1+-Ai{t5|U6S*;%;}BkUTCCG% z7&#MA05+t47wo4S4Mmz>7X(67VBktAO21TmL&)L^-fVmz@LX? z^f){~O(P41^h9tng10}Ln*QvO3kUU9_Jz~N!^L8F#S@d(D93xk<>RPzF*ia5wyd+I ze*Y0|(yKr}o?6Y9&tM0wd-)G!Kfhc+46?k1T=M?hf1sB&jVeH&x?xa%-5knOUNef& z=(uj6)yO8K#of)K@bdEV1*HTo3hd}+!w*ume@$erWqi4{uLae5u-Q|CU&4C8I&KZ9 z#`(tAdlyS`!Q-_dV$F}1QJ1>{hu>FwhRarc3PeoO*Z_2?;x#c>F1&R>Y3DOVcz&kH zMR-hRcJjd0EH*E4+8&|)c|dKB&wj(qXh5u_SLE~>eUX-w@NK4M|0G=Ah_KZ!lyG8e zv#W+b+Ac504#2>GrQFwRXZE&VTFKx%ZG z5xENrpPrJoPke`^o23(pzuINxLdUHU)y5RV6(^P<441pKE8&<{iNMHEdZ7e%$al+L zXcudlr+afOPT%M8GV5IT;mbgEmbXK)Vn7 z`h2*Xn9xUaYDZ_ZLf8boo0O#P8P-QjfI<#eVO)xkmGJhPWVW(}F+w+5ub3Cx5B9E^ zn$26`JcfMQ%{OuSs`HayOC{yAq74;@s{Q_tneWS6p780(Med_WEy($%_yjQA^+Wtx z(f%rLC`92E@xFTf&n!LERlswDvY%={Pq2@bGmiN>9$eDv0>0<;fAMro(qRdQX73Mt zqSiG%{@Jtf;F(NT2V~$^ZfID6Ppu-LUJ+2I3~Epg)rZK7f62SD62a#K<1f4r5uwi<`xzK5jjj5 z4hWA86QGKhOGfu6)n{I|DRmxkX-UssyzG513Kupk;OoHybTBE)Q|K4?q@{DkdQPTu zncknY$ms!5Z>wTLh6La(d|U??QI9MvxoOj~2}#CJuvxQWCM?&ctN8|6?zV8PLU0qX zo;Ie^8z?C;ASl8ZjohzHY-ywXbF0gve~dKL??eIpo7^#Mlc!sArorjMa_$v6Bdi?d z7N}gOys~>0IxgB&((+_^i{qMUw;?q{(Y#F{QxtOSwe2)q_Ms2HV15dQ?*3cOB{62H zu%c=KR7;%jkSHB3J+Y%~IXH|4mU-6POkOmux^h$j#G__|?!H4m6}XeX6~nL2yj_X> zgR{XT4;sUeN zcE;K+E8SaLW6YP|_n1kvCBgCJIc-|W;L0 zAo(IJJ=W|H%a~D+MB|j&r{yf$3 z3!1-xP!PBm8vccRAba_CC}v6KOWw%c`f}TS7RUYC`pe_eR5x&IKr}ihx`|3dLPKSW zNs@JgNjZ0m3X^2J`QE8!lZB?N>{qI`fW1p=5of57f{WEP&E3fu4b3I135II)KA4>n zmC1Ci*tX--E1GoSWU3N_gLCDI$*yj;QM+bmTP1;zoC-sZi~>5!kmd>NP&d?AlH)z) zj;yuUeM}}81JmwNjF5r9~6*57A*rZ$CWDebjT;4I^FSBSU?I)_+~gp`(P zbQo*xI~(}5+Iffv!4?yS z2soH!K!EY|@R4bnCzq62*>}E1gXU|NRwu&_mTQ3Ee8sT<>9<=&#&oesGAlJndPsb# zYC|G7MwT2WrB_okOjiO3krSM+N$BI+GTzK)2dLDjv~IcCWJ6_SG@qG>xAm~B&p=6e z)#_`EcC8Ng`bk39@HIjazr&by&tHVYC+oBF9-C6#2;ijZV0qpqm^IU)L2n`p|aV1--iZOhN1 zE4_Fn-df1#9N+z&#{}_VfQLxXA(8<2(;!#i&*RtaXn}5fO}=0dZ`YXxurr7mTe*EQ zCsWeg0=h)+2!A}Y^3M|Ks3jLmhtHTOtuZ#zMscc>ZRX+z5OMK-28@XOILPou1A&j| z3L0cQ?tV;C>3B0}Z=i)(`Q^!=MjHDF;P0T`Ko&8C zR}sezA=4_jfS|<*X;a##zg60odkLN(JmK&eGhmadI+LC&-T~1?CJPa?@A+>G0iDl! z=96=1J5xPk4_#6IO6X^oNGX;^&?zJ*ChDb^zOPLTqs_D}3pkXG0Gg5>#$+E1*i4le zMhVbOz8tfufX_{kmljRL^@3vh7;KmA$TY#3$Rfr!UH+barK)E57TD)P_Z{ zYpdSTt&vMqHtlIvwm4TP5PaN}pvUq`zFju{dKjK?i_gQa57EKSlT1(ySQ7Kkmx-H)b}za7qTr0lJ;x3 zwi|KRpv;()n6z2Ba<1H_BiVIg3CQKOY!pm*GzT5tPyX@WHyEC15<>G5yA7Bj?x8XL z>5h7Dn+9;48obvKsuX0N)IMK~cHF;#{W&b>6;#0If0P%4AE8sU&7%Dn87r}(naVD)@V|;e~`{&J9?QK-!;zIEKr@^ft zCeA&)k$(B6GY-{e;RGtwEaASYTNbF8j4<9TV<;!qr4#|MKN~@XYWCCDY%Y5e zPK=pw&eRF|70(!FDPb^Ut--#jD-qI6sXM>AD8~Z#W=o!_bDVvV*)x>PO|-J%T5D<+ zM#r$-zSXR+5#M?mB~yBc-)qYc`4sYIlrxD38wg{hTW9T7afm0P^j)Lb9lZ;sg9I4I z9p?KiEE7z2b>956U1a`~Z8E0<;s4?7Era50l&#T(0Kr{`;O_43?(Xiv-5rMD7Tg_z zySuwXfWZmw?tHwp_dVzAx6Z9PyUx8|O+9~}nqO1X-K$rxUM;#%Eku3w!wTFu{+O*# z>eBD0pqc*gHp1ELz-H0U2?oXTOk&QF{8}p5lr70$aF5I`%qB59i!J$dv!!(=2d)QT zD{%DmRiP~4M+$(!sRX3#Z!Je;Ze`+b^!hxRT8BQ6%;22Hqa3&~48?|bRcevEb?%Xr zze4S`x45ZS2$`?8_2Iq@%vv76Wg*KobgISbDwZfyRgP;_QEyezEF0$UvrI$==NE@? zrF7bQn$5B(pU=97s6kFd?wyT%IoKFJ5K0=vYv2s9VlgxRdXpDpCI!JhOr0!nOPvyH z4bA8My z!L9~V>NwFi0FJ!`K`t~$V_3$g+~0%>V3x9(0@%Z`vxkw^b~=ihR}xGiUbddA`3uhQs8*zG9td%>S2WU2M3fFEg%6RqN&@i6UQ1#p= zP1%=TW%o$IeSyaVv0L${z;~LlQEKriJ9GfIqz3UlRJnNF*S8B(M-5?)17ayH0fP?c zlEAn#IW9SZft>hJF63dAvEJi?Xk`iJgB!DDHXnW!{jL@WU?=Vbn|&P!WmRz}l6ZaXj<&J6JM>bj8p zOt~P_0t!)L5kkp48W85jNj0rachg^k{|wMbC6o=Tthaf7RJWOHY^2e{WE4ph(Yoe> z0hma5e5@VcRy|_eH!H)k&loG`fqa zDw#kp8d$hX3I&61(!p0_FKsH@+E~^d*dbesL*(N~u)SA>UVCyAgp9NWJ_ivK^6#Nq z_wmmHh)FJ>L0sULaMt9|xP7klVJqe}z>kc;@*4*443{UN#W7PMx-^KjPrNEd6FF*< z&}RXuE9GU#vT}BqV60#24*f}QmH;d&%b|rM0G#*M{>!ql$@4(+io<$QEYU&32_6tw zuOFM!BVqcL*fE!12k;7S?z(JiYvGEBx->-8B{U{FbZ4K1fe1dOY(OAAg|kNN5xGq? ziM)okcECA~`cA4dfDZjLgh*s$Zx{hdD9e?3CH*MUv7SqM9XVW`quWQuDQ?p!y!49RV?YN#fRrIWBjTxHCTbjGrh^p)!%4! zc16pWf{)sF@bL)#Pio+Qnr8inU(r7uBL0yKT%u+Favuraf1LY8&Au+k4(TS8ETj$* zl0^`e+t^P=Qo6aICT=x!28!d5`|HKqM;TZl$mXeWmsCQ*E_pFSD< zdq07grM0QD$A{sL&42tDB>&Aj$qy&5|MaIRRFzg^GT?tyQHd^#yZqQ@stXp@kV6W5UX|rMe)ka6~{XM#h1q>D*Ai^qzKf3B_GR9c#LHD{j$dUDSQ^S$aGr&;UWSvN!O0>V+z83Hql zxRgdKDLXfkuF(Z~1sq~eC>i=K6!Qbo3@HRHT!pxYxQ+H|<~%NYuo+88_jFMn?s?oN z5X~+)CEe8_$WTJXr1XwV5rV*>MEq+dg?o1Hxn<_|wu=}CS22CR+@^B#vnXx=ZJHjsyBQh1$^xyEHTlG~5wZ||TFJna6KIlH z)0r~(GaMzrL?I^V7hn*IwN%i5dkr}gU6(smqd)qWI|X>f3d z3Hk5K!y>BoKu+{)4FbfuTBo#Jzo}#wX5)@n$LX_HqT-!Ne=VgNnjEcB1*ds16!9Jy z;VYw8GAqsp~e^>8iN8e~*%R-?#BZ$Hv)Gbo=t z-<;wOo9ljN;-YSs=4x@29?=x9VfW7;!@PF9-Y7Q-G`g0@Q0zH?I1nxsE6#i4w5T#lzseosdn=n(VMCpYP+ZJK0X2JDaQ&c zU>&b-2!6=fT_VQieH&}Sj$OSzhElF`s{NRvGPhriaeH`qF0&$Dd$PXp=pLS3oEy5} z>n|BR4t=tMtzUS%*`OC^J&Lz14x5InG)zLv$`79)4ukmS9-&cehs^@f&jz$q7OByx zD_3W(nYB%|rhxAqlk3t(ZYf0fV-FE1~NA+q@9se~}%mP3c9he#g2nb@F_ zK(Zn&XNuy2k`d?90>>(9*IUN9o`-pPD&0#`Q=~T(LxBC~(MxP=YDPpRCMSJtdV=)e zqU7P(bGoTr8TALcp(>LJN|9LjbEeL+ULtPu6(D>QOpoB^Z1c?-?L0{jAi(Dg6ztW00TSBJL!E+9l0gX=*3!z9IwN-HHE}=pRS3Sdd9j zL~`W?A|OjVFp*xBP*5Efli68O#sx#kf$UJW7QrlYKao?%)^qR*Ko_7;gi-$R%{E9FNKMVd@GLl@r|3ElswsnMEVCL zz+TtLQwq7#(qC)#vdB+AyJpxePrGFG$kWdmPjn_D9{FmNX}^s!6o`K7%lYFTaH8a% zIfykVkA2V}YzqpH4%I07BC~IqkLNB&;l4j;p-So?jm5SQ>Zu4eyS(hGdsaqK9F_eR zDgi2{W)?Un=rF$8o5l~uNw9v>%U#AWy7{D41K*+X1l%G{8(@&yfLj35>_6lvV33CD z79q!0XGAE86EVHf$!|a~OQ13_Jp)g`57%eZ`M&d1cExDx+cOMprcw?X1QBwd#78M2 zGsLi*A>Dw@{6XK6`T9#bCI1$JND6gLH!pgIBL?gh16@s0(!F2>@&@%Mx-NEvUo&uC zOLOZuvmGis&NQ_oDn4z_%em6Nv^drUHn|!HosOE{zkq~qFzC9Un)i03gikE~&pl%n zg*w)Vu{+Eu`@eDyTcVpI#~)E}^brM;|7)=EUmOuDl(m)T1km0Z(UgQJG+M&cVk3T{ zh52KmiBzM7rXp~4GklRRA{9zuJ0!tQeBb>t2{k?(+4-E0Gi7T8PjR&^e0P$?yK#To zvilrEum4$Qt1u8;ICpyyuIp@hGV2^tZ-8kupibL`w-52?!`w%#@cWbR+V1mUxNZX* zf{*P2Oz(Y~w`izWC`>$D=GQ&$xstTWtjk~C2CB`07{D6o!zpD365gdhaEI}`HM*s2 z;%`kRSXz5FLwm4rUs|q__vLrAgDINZlETRfSW6BJEJma38UnY{AR#Dg+A4F=DS^@P zry5p*71kcjfYMn2omDfrUWx6nrB+-*R)@7CSqMN8nbK!Mf`E80)psv4#jKWgSA9mT zOsv=@+=6H|H#<*v3O`>tn?r05wFTuMzM7;$xE=wu2Wl1|%I*Ov4Dg(W9nOq3bR-W( zsXy;ik315{GQC-o@5WR${&uCV5MCi8p+Sc^(g&~$|Mqg zTHuIj9BeYIxQox_S-|YjFp1_-6y~r8gL@=gP)9Nbdjk`N3NYas$=DRUnt;y2V;x;0 z>N6v)!4M)cBJ;$Zk(Kr&K%b@cZTHWP*;0moi5PT>gxV<2&aqeYW`wl0^^ais{)hZu zBT9cE@4 za)Rwb^Z+g5A}|=Xo+g{r?s(UxLRivBvBCb)bT0Dy!c z_e8-98E3eeWw!H}9BNmsf)SrY(>#jT6`6Y0 z!3l?9aFRyA#btE#s0M!!v?xY!TOzf;KLe@1q1Bfii0kxx65eP5e1l{ZdEpFUZ5d-o zk!Um^5vclp;6FO8%0SzxQkB$PXZBNM%?P5+S|uE49PUOC>8?#?hynYaKcqrrI%c2z zP)V-ochFC9Mgia+Xb1=ZIz%d*?cNN!x_9=LiKJgeXrK_w&TEr-;;h@n2D0>lAS@&S zahJUCsMAUx(8$KRaj z`)e&Ck_K=~H!A}eN3H?$F96$F~(Yr@kKLnWxmhbKfM z-0>m7sz;yJN^kHyl@EPxP7NO->buC0iJa-CQ;Ewl4+Qa+BxldPwjl>X+QWWC`Zh73 zY|4+Z=M;4sJz(21dvgs&Nlj3P6+Wtc#z4h|MH11;jld^rkfZ3}o7DyCH~aaQPRY85 zK(;?Ht_zP&4y6-WPAK^|x z6@ls3_})MYx^M6S;B|q};5)`mk#0fThUqD>MHAzh zUQ?V-W@l$r8-HQ4?q5JO;pMxS@oGE{J=z=WfQgCkeXDM--Ei2qt@u!Lt`!XB+S}dU zHW1j+V@oERv=A%>SWgHQF-eD7dJ~{ZJV$Md1A`Q~U>h}Ni%?{OJ_*rWmf)Qrr?e!Wk^_i*6L(Zib8r-PsPTAp;C_|3viL=U#7F) zYs1NwTgd~b{$QHI@4&UOEATq8+UE)l0murug+4|f!h7HIwa2_Y3X3sXJAl2Mb3-mZ@X7gM6G&a5(B~y`^_-vuwucP_po#WKO zRJ#L1hfe6t_)WiXDy56F!vKbeL-?@_SybhxJp~^b{E7Y)SjZGF-vo<#k_=Fe(@S)5 zDVp}QCOdgmZ(&! z3XV=d;_eg(5rMMmn4#BIim0+38$RE8FRq%Yn;u)VSBkik1XsyNz0Szq0Zh0>

A;V4$Q4B`0m+WlyFI97Dj0M)Y*FeHbAr`IpGrX<>mgg9V zi9PK${O}Bb9_Q9-tsb>fx#f6?4=`Rwwqt0gdaoK*(LS2KS=W-ATfNhnD@jmlY1fBu zx^0Yz59e+!-lXd@D1rPYW}hu+mwW*0cH?sft`$5><=)NUxwcyTSbCWZO)A2M$2oXiIM;Q2q@oEM;(JfKc<2a1IurAtQmpT}57(Z=e`phO} zlV(UlV)?FDI5_d+m$)h#Bei2j+hk3?3?tN9`(;`i%Rplads?6my8MMo50NmLw?E7H z4&wwPX{+IU>Cb>NmO@Aoxej{hw0IyXkFkVjqaFI8V$@M%2HZP(Bv7s=lA!;ioE}CH z2i5~*JSQv}lj_Nb*WsfU@t#(RV<=8LLSPGE2ADxqGTFKB*r`N-pVfd0ZZ5AfMraljc@rd7 z(&cLtN~BH-Vl!_bff1r;s!()n%5x>;ZX&7Rr^aTCHWLe)ph= z9ayx-2sFtn4`!$9Cg#e;2u9X7jA*}gEI&%LE>Q3BXFj>dt^;uTrhpyVi|`xI$FKhy zBy$9PG}0eIlKnxQ{+pf5|6?)mAHeHh7~~4&e+*H-gd`RQqA5~9$2zxe5=F*Kd#HADI~!`*2c)9O==xq2YgH*+;og?qu%VUwPE2xsxy zQtM}ZlVAXGY@N6KaXcU9D#_+(WMUXq!1?q>MALWRv<2PJ_mS#Vu~106wo(9t?kJFz zj50|f`zN6jt;C2PYc2pK(~UjbMCsi78s^++(e7&PH$<(7{?Q}^_26e3Z9Yt0#cxe1 zZLN~{zbp*W2(cDmHdavSN~H|N%322)oUp7_&Bw_YLs|Noq4b~*`<3&y+L`S`4b4CK ze28yY6y)mU$NG6NSVKvHr76NPF;CbUcqbhC4yDr17m#Q1jZmyAy$y2BCx22jdh){H z7M-76fX<*dBcpy|@yqMa9q_!QX_IH-tCo~oUSzeurx_rC%lzaX?liB6PeLLD+HiBc zA@qn(3vkB0Rv}WTi%o~wK?kH3Y;dT4@?imSPDS3(3-2sSn@i@kjn9G|gv`W>lVR7zPb(v9`K zMrKAeypk~H_J>&KDpgVLI}Ir2$FAgtu+YfdI~$&;6u!7p*5AjSqWRK}bsytSN~lkt zeEvsi{lC~?(+hqas&M?+CD5?3{;(f3vov@4;PgMPR{Y(AoaFCcko!0%@o{Fv*z_;g zLQ{9=f1soR)eR?9RkXJ=HWHiKLKZM8i;8aymXs0vB^K0$D$^+}1OXbyb7UZ(DO;O^ zpT&+o(fGkb&Q*7iiXIFa<7Ts_YI|F&4R zs;o0*6`q2lS<<`(vx<0A9jfQfmZWdu&oOE&*kHqsUl*|bN=X794PxbIgkN<|8*F&e zUCv>rj8$H@F>W)(p4|Ld^Ui}fM87oQn*IV&G^*IkP;DJFNg5FLYr%P(;HIGaaqDB} zP50(|4!Fj*TOE_=-P%7IJ)!~DzWQ%MvYSG0`h}|Es8(k-se^#%gJAKoOzLKus(Wev3R)vMVMN*f6(U@`h z^}98QUP$amQd>6)PInYh#Pr=qB&%7V+D27IF^#$%C}&<6g$r1&NvhU_FRiR|2!)64guHz>MjTdXui_P!F}ozs_GbQk655=s5H8veO;1D)B>>-~-} zyNS3yWjnOh6{vD7^5WNDsT{&iIaK^X=%O4!=sJrvMJSQiqca_|93j+PmA|mb{|x0? zK2x3P;)l;6S77+fG94-j7N`xZ=N4G2iBr zoRoVzPj}Q%2ykXit0+tQejYM}n^#Ab?62pHb6BxlbS}*w0w1vA$6OCq_s-I&!VwR* z|9jr}1$Uditdpl6^(AIHRxI!s&biVnOA@DOZBr^=c8a%m9`q73>^rpvh`#bj!Fb3Z zKffIJ!Pz-;r%$_+B+$B5$lBH_KJ}Q@f#!)q^``nc!8bY%LL8oSb5JrKJ$&2qfbZI# zm%A&>{INuLg}M7cDz{z6JIu^@1qYK7VZUdbaSlkxp}kekR^*`mJ{LkbJx~Ug_;r}p z`4UKQH2UNWafT3H!(Vb-R2_H@wR8E~e!II%^HJ2vfYXdCVuR4E^K%C41(T zHK8arY}40I`0?j3U2^FoVO@V48^)#{)c>`RRQ<6=tn>d{Hu-0=P(RnkSwQzauVtv_ zCIc7Il|;2RZbP!q57Qu&6@mgd6Y>kB;eW$53pMRM8#gnjN6&e}7$?`ot41j}8t_ z=E9BZ#2jr&s>^+RAZATvMXJ<@>Qt8+dFsx%*2puIG3wd4GYDCvGd1IUF2coXp*?5D zbZn7jsr@C|T+Yd-dsgWYqE8VCjpI)Ln9t;Rx!%x2#p>sLE0B1)dZ}K1etj508*eM1JIU!eNeSu=bF$FLk;|2`C^9T5Omv*h_KL(}DA3E~2(4dRq|5 z)!)o5*n%%&S;D=5*@wUHSDZ-48a2h~bMcVaT(>ZPDQ7DlP)bXTjPgQ(jIq__c~n3=BAQLB7MP^RfXnW{g!7F+5%3LU=(m+I5b#Ocln7X}!yGxHMDPGjI6Myii04Jd<6 z{260v>IDq`2rr(I>EG>^9~SF}5OISt=J>S<6{9+vvki#84n7G_vt;C49rMA-n8|S1 z(OIl^Zgu*F3}>6uMjR}ep>UyV*4D2m(P|mWH?=xxoqLRS!#_s&$Qh>WJXB{6Kc>S# zcGA1&zhmJMKyGCs9_7uc+d+owB{y(Adq|KxOW6KNwkHB??N}`+W|Ce@QVDqzO(Tv_ zd9fxHz-K1@}b~Vh-%+k__F%UcTd@Tjx*DyH zlr{fgFCAyv6MyNLnWs;D7a5RuNEIE-enz;fcW>Liy8n`7 z+&y`HqJBNPtVpR~nK5y#tD|@UyJs%@K;;{D4+W}#XlK@{Q&+=^vwWlDQ@Et|$fdYp zH6CSOZ=^?Ht((&~buCBLhUh|1dFLOHLwV*#uV`iuMy#RHZ|O206sN{>d{ednePuiG zT5~Ff!ix)k@C4M*^j$uu)4W7S*+Xzcl_Olyk1O(idr;+A4f-T5Agq2t_U(OK(H}+N zM_0G4)LFo2oK|cv?{9GMpew=6cU#Jj$%fw{C+Vs;@4bUJKi(!quSe`L;uBkf2+FRV z)zV~E`tKt@?w51+#ZUDQM9-F2pP~@$eW$<9s&Z(3+K%ZAvwPgsLKZDXY)e$)wj?3I zk2BqCEA%jQ5dYq~?(!uj^7iG+m@Z3))xLhUIfReP12@7A#Ifgbat#2waiMC{z~8FR z2R;snjzg9{1?oOPhpUnsvfElt@X4L>Oh59(POc$F`EKQ1E+0n0Zr@6e1HI9kN)6>E z-b*b3e&LyKVP$RA`t;b9RMSx+1f%4usz3>~7}5A7VGm&rQR$nd9WgG5^&KuQ&5&h_ z(t5zKQ&qe=;ym!x9nu`h92HkI?cOZuS`=r9G;#-5rusL+j0En{N~Ko$)2rsy0eyx;c2YdjKU0|wuzJ-3YpU0AMcH$$o8F`lQ;bkk34zRTQ?SlgqBjD4dVI`s z!u#w2b#OoWX2uw5`j@p+2E2a02IuPJZ)$}FT9Lw3CQ>{!i}VztKuC+icsAere7DOP zP=zUyLZeAkytsf2xfp$KM8Y_)N5WvI0Z(?g7#2!GP9uiBmKn!^C6w300K8w*1SdDA zn-jM80y;;9G)xG`Ymn%?EkiDXln7s{RiH4XLhO6=t>WH!RBHunK6e#1Z1l#6wb^aX zYRE6izF0$?gHP8vL7acRC=RcDfb5cXek9^vOE=Z6>DU!&Lrgw51#A7Gf9;Gq^#-Ya zC=}uChPLWQzdx&ZYxi(LGPjwZ{@^~L71ZU{ass9hfdK~h}%(vS7H{vc&8L|>!c?@%|DHAOn z=huAar#Np<&-eVF;Ebe2gSzt$F`T;&mM4?WlX&K4ok-1z&pli9sW5cur)8I*dAQYK zbf%Wb9ep>k%&L`!KUTJsdK?3x>8sgVShoO=x*Jz26kszpJBhjb@aEFlQ#RUWIeD4} z7b?c!b!7(pnpys7)XR_XoNbBmIaRkyA?om81aw*xNY_TMifX;W*Z3fvDb+)nlotpy!;$I|hGr$)Lih)d*ie-EjWPl=`tegz%i| z6f1L$($Y$WYZN$j>q%cE?MC!(EWLmWD#gk=7VJmX%Qlj8s?K%U7cGK_#>6^u9=pww zL9hPL^}KS}_5odS_FhO64{(Z;Tw_Mf5(L3@uFgmzfeotNcTi+o3721V-r#i)O{Vxf z6P}wH^PH)_JU8Q>tNDsG zh-Zwjcq3#;)?E}3;yQpVkFveY+B>9_&l@b1!T@DSo zpI*|?^TVC>s?+UQfLprU-o z3Gu%<^H!m5sgAvbZsD3V3V zT#Uwcmc}OG%<5?Iu(Oqy9Dg=ZA$x9a>UAZ1I_4GPb@r~sEf^`jBuqKmxZs&?%4hvg z=lzl0``fktC!TXGW?&MX=2%N$1!tjAjX|4MkwHsiD&5DG zrx`LwQei+F@+zzPO(b^B4QNre?=Dxgr`PLCL;>y+*% zN@~kt=Hg#Lf03S>9f+&X)!tTasw-?aY*}e;Q)ThgJ6WEKHg{~@ISI$<(_7{o3`tURREpjWQz!7M@S_!uGP>74=K2U=~8wHII@ekC`C zNO=1?PR1C+$Vtw@(2AEAga%HUkT7zxV~5GnkrLI_)$E!=Ai7J^wU|Y-QZn_4?~Rui zwvnde$)7Ljl~+l0m_!1K>15?Z_jXDP4`i5FJ!l)yvctrbYEldE$xAa++i+lq;+3^L zn}i#tr_K0^HyI*=u? zOfLNRc7bXAipk75$F#->G2!zH3!{}6V%isqS7eQ7pyj5P8uSTIv?{#LT|;nH^w1R? zhOcD%v-87cb6}D4OpGr?uIdtPw8hHc;Gja!NSZJNcNwG9SZTP|Ygq2J@ct^Je>Gyz z$+-`-IwN>gc{u4HH%ML7kIbiUxH?M4q}CE^M2XMlHzjW-bN?2V$qgvbHrFPb;MZ&HCp6P6d{w&w_6A@Y50 zFXGh|n>_p*yq9a4ChmAN#OlG=pc)O;_u`Rr<~lKiT<~rcCp6sELj*oG~Gc z2ob|-kp)??EgZjVB_B4tTOPh|9|BJmb|&gsS@ouHyM#C3T2Q^&*B)s6%t}?c{mpBH z(eB&T%|P&BUUpcSUMIx~U#Zat5co+}oH==?G~GatSyP(sM5C0UitcxN=Mu0x$Y70*UX&ng*ionxJKIhw|{MB__nMmDZ|$3A88pJ`Xr#?()kzdAqWKGZF= z-NnGI^Z(IgQf4>Xm=ZH0GDnzEId@C`q}Olm?H)!;16lXA-l&ca8^UX%@2W9tUp=cU z`7%8D{O9=nh!_s0kGpKo;}`L~(C=3lfV!*hA=u?|!><=qo?jk#)-SeP)Q&pD_6%hm z(lAbF(e=AAIb~>#^R>#l`7Bb{z$%M|KpXhPjYr8Jv&Bxw&EIX9f#FqQrE_$wSwbL@ z4J7spb`LWT0e8dawNak$)Jgfg79|@Ab%6q6O}h=d7w8wd5Ha|_36Q1r$f4IJ%3;i! zM6m3(Xwf%@5Z%9B3kmu|cFdM|J(SGYEFmrB0g$Yl+C$58_J2A-aPYq zs-eD0kb5TZ#WIWzc$^pLj3gP4L1EXi@7goKxr?5ubMXh^U(lZ`7k=F;RzBMAv?^By z>EKt*W^cBZeSamOeRwJT?f2<)o-a6*(jz$D;f(q%vo%7z%5G=;+~LfP1Jj%4cT&7^(<-Lfy1KhdH$cDicf&aeWkG$l11}5Z|k~PKhXVJ_O_7R&Gfa zBJdK~*VPC--?W|4GmLjd=*wzzb0|veEXQ?XER=4RDwd%4GX*g!qc}nst91E3LU&rM zhTtU=wef3$V*RC)jloyNUw9zFa%ewMBIIwNK^dm@FK-0iuszfG_Jr<6UzgJDZxIG5 z{PcPxj&X0?n$85&4-#-Kk=52{xfzxrxQC@lro=VS!)~&>V0$Ox?df5m^jb4h%n323 z``E*P$0@x;dYk+3JoH~Y!U^MyNMjqMlrXkXgjvL4NZG`hedLXCv1!K4S_raiBU*FZ zC1zHva?+VTdyI+_P9d~M$Zv=(>9&t5`Q7Py(=iTbc$Y$-|2Sf|+c`d0VZtThk(l|K zxiJTF)I>SG%%KvQ+SaZO3VM0AX{T&@L(rq#f0NaU=mwr|W8A;!37JfdS&iX3NAQfc zlf?&Z1@Ld(+0-|-(-ttryj%FT_3qb~Z&A51Ish$U8AXF$d_O1cqQ`rOQnv#yg-6EZ z&+)g0L^%8AZcr=JEgzL%%EuYT8UD% zOqa+C7q1Jcri#M%=^1q?kE%#|6|izcP;)SL8mJc)_PCzIA@W>&{-mlGwDJ0AkCm8Tp@ z*#g;q2_i|^m;A^L&bkmA2SL=nzO0SZ>o%XR z6HiC;PPvcTE&+(@nF5nsR{N?f^))>^T- zR8zYYlNzQkLEyFSdLEqQu~O^}>kFzI&jPCY*dBs8;@3D+RO5CZviUIzhf*~paB%FB zst3fC-2q+Qex0YTaj8)HvUL|r1D(wigl#L^d`L%+&LXZ5y0mQ^VRrIOMW6H`>Yh7~ zh5oT-f>@2|NpswVJK^W~^9-heRDF9j9q#gH6%X^K$L+HTrpK!MOrv(Q9+$!@EGC8v zpg&J68w&$9!+lpP3czAZ#=t(iW?$x&c+mJ1DZs__sh7(1V4bd zJKmoqR;k9gJ5&4|>b8L2D2H60wJk0;uOedDkoArk`^7x`xhv)e1N#z}h5Sl`a~zNd z>5ikoA!d$s`^z%mmvJ*cu_>iXw|G=PgV=&|KFEDByxCPqVDfz5@RtnTA!yPoB(WE| z?HbS`q7(KoT^ws|>gq}X?H5c2ga~Ii=6as!_9Em(W;j5z=ou#5wY1So_(A91Pe0)i zJH~)>3Lohmesn^s&2w{|d=7bT)cQ*zy=~c&TniDUt)_T+R#B#8ba0;d)z;$bh8ZjR zx*R6P9LwO+Y|c-%30|S1%@MZV@@J<-I7Qz8^9cB+JwNx=Q|^baJzn8)R=NSyEHy1Q zEy7*zCA6t=GA5-~X~XnvH=!=F8ZRe4GV5MKnii%IL_kU(FZe1eu8FhHQ3EN}JnO+) zsLbxL-x>E61-9+}HOr89WJvmd2ou0Q1Z`ITx3bJX<}@Au-2ZMuYb-CMp!h+gpI0xc zdE1jr1dSr`{Z~p30IzsVBgxt=eOZ%;tkdGA>VYauiYV+uhaKq_swGJIU@&ZEX8xCW zVX}jH!_WH>W|QqqLjt(~doi;lw><|Vq{gvOIV#A7Uqud${afyAG&ZD`$AU&EmE#$? zRLf=rg(uC;VEgR4)7H_Wz{4tiVVXCA3a3TCrzkb$5iK{YW$&_V4JnR3IIDR}E2XYY zZUn?%*NG@ukvt>M+#$F*+{LdmsSgyrEC2TbAHX=#uaVD`FL=6~VUbS4%* z7{*j<>-kw%9ZPtl)-J#oeym!W_2U;kv`^wR`r9uBy;?h%InTZbsD{x}94hnF%X*bS zL8vc}y#XR)vYe~VRqhP}2O5k$kHk@CtJgLV+9sW=g)Q+R(!ou|@%r44^eb#Yh77dv zy`U0F8w!*&R#@9_QM#!nr596JS^#31S4j77EXwi6V^JiPn2-_lI?ECmY+^HgridbI z_5Jz|(3zF^Vj%6MxF!Zs0AD3mU5d!0P~5cLc>6RZeN!It33{K;h;*9GRj_fUBmva2 zBa(z^xrs>+A;xyIKRIXs^c)tzL@39CxVDRcLxU^G8}U65!a z$18LPcf0f!&J^bz1dCVyNzDLMcXuc2lLH<@8F=DDn}KuC;B#J2r9$DQ)f}_?)3lOcYJlZcy3N(tiJ`L%=FZ03g`bPRYS92y5VQ_!dGlt4j3vKR z?=Ev?hxpTSbeu+p=$67{mF5+&V;#4LF2s^~qg(dv{xX~)NL!*3_Oi|H{cmSd9#F=} z!9Ivdn~!p9|9>kG{)^zPLv=$L`$OVj>sxKOEEGUQ+Zdu|Eeus&5uT*-Q{lU^aEZS~ z_`-59tToy41PIiyt-qtK?_I*oh9zC>bJ2tK@yu{>?R0JW%4wh#H2f%nVnW&BSy0TGMl3#(wJtjS8(9H&@lXVFv+K(j+_jwM( z!&6m~y(=wLshVh7Sg8v-4FCKoH%4#j+BCW;B2|)GP8d_NFPpDVC;wpsPYB$BIA$KB z(V8r3Nuj=IpP%lrzf{2RA_NeHBe zM&yLtd;EbvRx(+pp)+&IZMb=M5*>BQHCl*@DJaWOxb(hleN%3mLn~?MubH>0aVf5Q>E~ArGL#@ zfM?f8kqn3F>U4Dt2cbzG0Q#DN0O+;OPDr{(gV)IBRJh`m>dK8W zwPq6o05KQY<*&SlZ|E#5Z1MxGW0g8}5b*wGE6J^gjYLmH0ZWXcHgs!TJ|WU4RZJP2 zIb(U`+QE`J;=Jo@7YJsOnQgsE1z}=Tg-XBF_Zh0TRw}zge~xv#v`bfrKHmcSDd8!B zx#qoe9?|vE-f!1D^wO&?&Y*5Ds-2sc!)M0=|KkcY)>jVjf+D}Nq zJ``a;jmhpccH>Ty!?922Q z^cpZIMfZi+4N!kOW1x8{4iZn~{C>kARDo2W5BPjjDi7&1_&onLNG)oz&0zW((6L6? zMo{ru^R3mm=JJ~-z5xM-pMOu)A&0+mr`3 zH{RPY-X-Svqr-x5$m(jS^h&p`d?U|S9dk6TrnaK0?jGNNC-o(oA(-{?%Ul-Ue|;|< z-~`ztlypS_uZ^jMQWg(!NorZ!8>YDf#p7h`shkmYFT*wkO2Shw!>HnyOBFW9{N7qa zjZ<+!!*cWX*OKkwAzDMmWV#_}j!>ums2E&e&Gek{RhlIbfEq#|-Q*ZV zu&frGu7<$j#tQokDNXERwhNeLTiYhHY%TO^t#X#cTmcAye)FDkzUKM~PaS4YzvrCZ zXB7yd{N|{XN8GnqciiyV=(umY*L{0CcdG*92rl~u1}0o;O?I}2GnVC4=Rs~dnBd_> zmg%x>%a=UHrN@)lz&j+h*HOMRC_gNFZL(s&hTNBa?!;rYDBN_J zE5>8<+v##^H!$^zWgZ4+l1ZYC4kSrYpqrP4@dnq_} z>j`lrUctF~aTQHDt<&J+Y~L5DD8Ihp6)EnDtx8ea;x{*QZ&Nl~VOrZ*xXF&7_8hy~ zAWmzGkJ?;UxbpKLxLbLltO-*17fjapWQyT@j^vQ-33`cTn4HCri=!y&C!8UTpZCEv zh_bgx&FbR3y^hY=(YnpT(FjMs1FE|#1;^M>A7y5p2O~{ZezKV}rJ|7u_ zwnzGliahk0zGytd+|)*0*lMKV2+yzh^Xb7f66$YFENxr|XC}JA@yPD1qzUIRIV<-R z!ex#|1CC2&pt6}(it6T%$O~ey=SDU?;Hxm$o(;UX6DgcNT_hb3)#VKoNPlu~Vj7x8 z#uazr5|Dz-9Tj-w3*Ac+P@Z)Bb)@UO5nPGuvN@VBl`L0n8nttnX-}r|iY);3o!cnD-;`O{?nG~v+4Q$h;e3gK2C}|$D}wO&Zv;F%k=I+yW_4%*1t9Mu5owa^%&))ls>$*P7^3!_l_mrj#H$Bl!&fy4p*OD8171N60W--t6GwINW_`Jn zJlMe!1RJ0`>GaP24M~l+g*UlEX_=}jbJ-mg9)Xx? zCRzRFZ(XaSVz{_hECQuF3B3TAMIQaWO16kQ%%jbMw9UVZAK&#-uTh&`)wL$?ToXa# zPeX&v@+(@bdQ*)opCWs|uPyVz8=!ky`fzJWVd7pvbk_iJS?=IdUPJb0W~v&fWG-7= zeQ_PegqxMTF~QF=sXL_~IQR?i%M;XB1~x=z4{hQrzL6kxSxwB5{#dvsmEw$POkV5& zA$}7bq0UO__%VO&LU)UDk)o!mUW7tkxe4m^mdYa#9@ZbeyUeqhpfJh+9ZDj8@|I>& z^f%@mV}$*!W`Rq22nlY?;tc;)N%>q<2OQoF_!} zZ#;**V+Xw478(;y^vmup7*rSQ5gkumd2Aq%I?HvX_b?A~)jJpCtziQ=2#>nMA4|>S zTy?_fIGb>6*ZO&=LXFBUkQe5R&fgG$AWfyNJKrrK7Rr9^3jy5xVQG1}Q4)NT?02-| z8p?!k83FA6BRX5dALTjQ22Wk3e)x7EvXMD6=y(~{Is-d7NIPzFV!}2@fa-h?>=^#0 z_?az5Oz7&}YsvGbda0}0@tG$dJFyQ3p}H_nkPfKmE8ZZbdw8n(b|?hTkPbap1=*4(&>Xg)E}Uru!^07`!|7 zH*H#mHD5z$gUGMNLvZh)aV{+An&9c%T;?oG2VJP{k-FtU@hu^5^fsxs(Xjo=&$mK5 ze9RRK-vU4MT-^~18>Y5hV28qx?YDY7_Sq~hh?R_-0|QWtWBrJZOJg zs}(IP+H$!9L%O-UTNsx2nhP4UctnCZaLYyDrxghs6Ks?VB%@)(R*(Wp5vL;rGT%5H zpUm;0=Zlv!^{5N$dTwzFx3#2_aY>mO0xVZ7+#$lDOjeI1K4XJJQa7LY(ky8=BO`SW zG&{``i|~0sFX8dHyfe_QL?WCs)DgRq54SfXa)s9wM>YFo_t-=0N6pnMLH|FefG?1J zRES?K2^ZS8Z^r+286f6qV(VsVW-4Xp=-})sWN#|w`L7@UN6uxF#;Xq6*QPLRZJPyo zg$hP)C={#BJdq=^-cke!HWVB*T&U3KFMdk=M*8Gg-rSuvxzE(uls>iPTv%8(>ml#q>*nR_=B=N_S4F^i3F-;sp{7dZ$!tw2 za-3wMecjl#CmJ)eo`5d%_shwbB)tN_ja*GRO>>c{IWH0k#w?5|PD93(htcXm$L*wo z0JZ}&yh#dl4m#uAN!=&1IN>G4l7s9H?{2-R@^!9f{;qSAo>Y`6A+65XtFMIQkAzfc zgF|wzH!{Ti40^}C$YDt+54pe*nJco;>;rt1mq(;R7+_&>JGov_K>|%sRT5!>NV%se z^zu2Xw(~*Oq&wR8^y}uxX~IaA&FF)kE4#2<+`5#I+@@@AWf|Md zN!W}_^l&y=tcK|~^qk?qW6>jCrQ->9Qie&okk?q!_l2iBvwqzwKIyYzOg_EZyvPCo zRAsg{x$27Sh9lA6Xl4s`_&r63UeWlnME+iKz1082?j>ln1-Z8I#9A9Va)RgmEfc-U z#^&XMkCX8`>ZiEuIF_FD6!uh-Kq?cMJ#PhNiQ5R;W%?+MM<3bW2GUQ3lBg%Hy>X|F z(MYtAHEBEPSe5ofj;}1VhPhInHXu$)CPGx%B88tAB%x|-&^f4@yTJG*&zVGQHrlygtZLWE!J_HEHf; zeV*cip1cB2TZB0D?>GSCI1aLhs?t4W9qQ+`s8|Jjfe<5f5twESX*RqOmx*7;H~@yW z4bAN>NAnyU5-b&FX_ORc_Gq9N%Pb4S+~T>N8NP`abn0|yHXyT2SMpO>KZ3_v6qQFV ztywJ$I%|e0CNX3@4saqB4=~ixvak@nQuvM31fL2*s@_?)12@IO?@dRslq@w(y>nLu zf$svd0M5@(^A5}}J+K=knWHWfV6-mKr0GM|n-ne?CeRPt$#m9Bs_#$i$r{V~_?@8q zBo7x+fxQ8izgeFA4W&+%Ov+#_!UAoQSN0fuP3z9pt3<)^573fyzt~W^#884ex>S{E zPN7Bzg1?%g!7O_G_J{EZFch_S+!ERl8dEjPqU2(kRbiQ#e=NAJYKJ66i*5w39wpvaOt+Nel&Fp^h$>{Pv5+^HD(u%ImJ_twIW%TrL~G%c2QOQZD@N%x@q zwDBIh5-CTG1m?Y`Rc0F7dL7lS!R%KWdd$cQbHalc=~}SM8i5_{s+#UPpF(&3PNvqH z{??R+axM*6#r9JNrZf$0zvjb3Q#!8pYh&ak)!+1<1#LEC5pVB6@9&=Y8eq%am3h=# z2S2kV>ja~e=LG20;iLY32o4}#lY)b=X2(Pkp*u=c9!dhV*uthWeA7ATK)TNEe=g{ zUg+Z;k7brmxIq^B-?2wKuS|uYolA{L1=^nYDYr+2-p14U0l(W z+{M;tFXiRN@Ld?{8*?4KztMgSE;J?j!VP z*%5EWF7OJs!%KCcn=o(K)6wp(wc9J36(tqycq%hGF6ifS>^4|RRM|(>2hB?*C+xD! zM>d{97g__yFj;7o`pS;`KR%DzJ-f;At4iAP<)3;t3w@Q2?*`#OF$h!ShHHL64Po3k> zJ=Zz3pnO6sOs@Vvw+Hv z{k1YX-F*3}wb@`qQ+=d2&saI;jlG{DH^)Mo^j6-XJr>8G*q~|q(%IKJVvN8XQs2K} zgu^XYc0tuh_#3fnHYjiGS|pbH2>Q9lx_$ecS6!PGm6phCNeifhXWD&_jDZ>yl4K(&eDyzqJpz!r#s>%i|PeT-P_VgUcqK@CTZ@BZYYb=$l| z>hG%tusPfX|oAW4$PHV+3lu&$-mwuP>Nr@y0vrZj76=08USx zMjrHNQ||GX=Q*{R=bPZS&X`!RYpk67TzbP_>6_zmu4OqxPy*>cGbdBh4m%ouvuA5x z4mMcLKa^&mmuWAfY%HwyIL)^=UreRsG=JoD*EE;)c0QaB$K_l2(H2X{^=J{{H6@6q zxyc0v%#4VIfN|7N-R>azE$N2EKlrBO zw=u5bf%40{;$w}d5Rbe7KI|!;R5q$ZqD52e%@Q<^tzSNw zPd|cv1Z(t#thP!=R%E4L5%u?`Y2K0LvGqKI#?$jL2QlFsY0h-&X|sm`4j^&qh*6KB z-QA|q@m^%GM4(~KO@d{nOveqa+)ms!MAH(p@Jd5eqqW76NtI2z(N#2P(dKXSH75ws zPPVcZRuMC}ScZi4p|Ns1cNfK^lhA<^Ou}*1j1q%uiQD+r4m&}i93!9`C5?7A**36d znsXn=Go#L|lH+>A568cE*4w(p3G7o1|Dti2~!d{j%=;FY^s7^Q6X!Rw76`TeG7k@Kn z)5gB6`VyD-`doJ-)tD1!&W1!j0>8r%J;(np0#Yu@*Qzzx8Yl*uhSaJl0bsxh(TqE4 zAj=DDn_?QV+n5SY)rAdCV@;j2i>xwhgmUkj`Z@)viMew2$6aU_DCrn4w5?cpG?|P{ z|G4gNf@egZn#wK{QY#k2`xMQ3;G}Q=;#kSnqg_U;7_pOGg#2lzY>Tpr+-^IBYk_xH z|GV62CYl42546$dXqV z?egWH$IShAT>+2**d6&maL7k$F2TSKHD8#=x(7ITXUo4F5m>cmQaW{?cAah zYG(ufOI$90B+W)a15;LyF{e&#)j0j!p%9_z=%NKFbNS9w4mAwnV#~hJgYmUhjGgKg z)|`t?3fVHKv8?sKPB6ASXdS;Pls(}IC=9~+FfyZF_pf4u>I5?Gjv{prM)}Q|mG6#w zN((TifrXm+p!C6Uo^gO1klSgb6rw1Mvm00p!csQh{6?QNaL8gf-W*F-c`T~8qGoi#;J{z}_P zl`BGkI3aDzwUq<@)C}_m!T9S+C$PzZEmiGJ9>Ox;W*DDy)(#=2ZZiqh(tWnV{rrnv443gmwg&rV)#3Qjmyj6!(r-k)%(jZK+@{ra3Kh&)vE zFxID;afV)8L6sO*5vQ|>o${j$O6*%C73Dk!mn(h3feh0wB941Vivt-VKT9B)@k%_1 zfa{*w6Q4&UgwmI6-4DRMP~E5ufj{ya4)a!~87yianA(NpBc}KlQQ^eqMrg2^qSoRg zRhbjgh1-OH@+vWzC)_MqLLhRi+gL8@A=whP(64y4z|tVy-LsLgh#v4jy_#TYV3yvT z#8MQvVh6u(w5mNe(Bzi1xavJNv|O9W>+@r(Le&K!n-rf%g9j}UfxJlM`&@osZ~l3pNO>|?SC^(htyELb}0@u5RjP-itlA* z`3ZGX)SF$DLbe=nKlJL@=dZioZH$)cvA}70i9Mhu=83di=cm{0_ijI76@bNgSN%6E z6JcEfw>VlD-+oe}DhCWKT|W|5auT*}T#W2^NV6X?rtrxi%!cbwd-#6%o1CBED5?{# zAEbup6ZWl=cJ??{09?zwHGfmbmD7ndR;GgD?I;mCn7ho|u5Ll9&qW1gQAdXK31RO& z?ZfUS^SVLw2=kJvc4vhxr+9@-<=F6*BeEN0hVWuOv#)xd)JjxCMKZH*K2%Gd4`V0= zkKJPAL$Z?Zx%ou7y7+ZW$(21_0M_(_TI$(I%j1rZ^BrU#(x=2Vu*A{L^M}7XD-BNN zfXR~^G6N&3n%QEp$x~PFd99vzoJM6@(l&wbYe7agW8q`Woew(yMM3S_kyVht{_uPo zj7L0Si__jFk#RcFZ;yRa3Y~!dTx|H27uXM+tV@Qs7+tE8cb#j*6Y19RmUl^CmF<%*|K+IcPExA``NV6eOB{mxAi}b5< zy52g<-c~A33(!IoBGiQ&>hzX7(HxI#zB(Hi#HvDKD9urZ5RCAd9N$ZXiR4BdqW)LW zp}^4H>q0nylR_AtO&y+}1h$VqEz6lF)=9{om%Q{m*F$QWo|O z&Sqc3IV%^}ud?_*7?mz^M)p?bW-hLB4yIP-R%Xusv9xQ_u<<}$M&DRYVHYQGRO~fW zLBUB-<=}uJA1t@C#9#ZVEJKmP1R`xjr#Jq6E}9Pq-5w^XpW!>3Bj4wU(Z?&A}A^7g6DX`*q#t?lGX}*5Vtaql!qTAcYMk za6iFB`?+4vsh&l^;I}jQT0|;sal(1)b(LKkfZM>yt`tvUkA5w_t-R8FrFhKAYOhE| z9w()ZXxx5oDjl}Ol`RD9qQg>`V;6j2Y{cS#ajdG6n9k8~;2kH%4QB9C+iuB4N)Y+yeDjmc;Gs?YjJWw0xye(A67VdsXc~ z0-QtPulfo*oyQcFswrhVxI4rwPDQ8dB!{9jBt+ zfzv^gm>RtNv5SL)#AY*=n0u(VJw<9hb7f!AJpQF0lt>wME-XRrcgIJ42=IhRtpRS2 zP9w}I$*{<0!dnzjd}TlZTeU*OlfR+opd0fgsM^*#nkznE`F+N^p(xECT@|{>!Rlg%g-HP{9B-BiKqS!?gHY@Q1 z?Zzrke3QfVum=6%ML-qSGmY?__$cbw88?cIw1G8*jH6HXG557b3UgF3?mGjXx&uP> zE%JFlq#PndOVRCFO;W8F+)_3^Esa|NTvF44aDY;@6XNtEjj}WMlH}&c{oQ3hvajrb z1bFj;jB7NI`k>#n*u=BwqI@6~>cGkfMS@*6-Zw@Wf5b5hu5nLIcmu-*=FAGE#Eaw1 zc~f`tR~X~Pt)sFzEJO>FT_r5E?5QM)m*3b(P1>GpY%ur7kwT*&VEu@>@UAiDViG6Y{3yTH_P(kMHi}0EWFS#9j3RM zyu<_kd-NXN3iWr{0i_3j4&_q))-r4VHdHMT<{4=Fx#j?(Afr7ux_&YN2^6Q4pwT9y zOii||M%@ZYT3QL6$w$t5_8=K5YbvNS&7s{tot-#8j9QD*iU)!w{h+H&X%<9qb3NwzUveUW*O+DM}w%!0Ny@3ae)M@ML9)>zO$kxeFzmbxye zOor39>?RSuae&@OW$I>3*3N38y3pIN3t+f6<(OCX*CWzX-Amv~cax(u#=cZt-JBR<#qlS((i{i$wpg=l--LLO%db6mx{`Q;`yqEmF0*$I z51a;w9jx(Ko2DO|;r|$6lw_CD*P=yt)NVqYgsXLn{oTVEtGV0L?*`vvzk+3JDm3D- zK)${&eRV{7<3UbD;JSB{7EJ2<{U3p8Q@pf7^d9Q6V^wb^0V0i{59Nq90s9rrxr^d9&Te; zLR`2jA05w}5xpDmv3UhU0ahFlk5Iusv-UeEmQ|NF?b=nHX)RR68lCm!Cg6klY11tP za_eb+W1_bOcA2|1U7Gg|FZ~)VoQi)fqOoJ2V`{HwROO9p@7d z2BLPOs&7ld8HBZH5?VOZ3^8XIDzoZ~rL^txmQ9ibccZI9qKF;|)L%`p&ew!VsI>Ks za9pEG@4fX5bc9^_7JzMFL?zA?QoCzYBo!3GKjM~wNg#$Eu()hf*}W5goGGbvF#o1Q zU>4f-4K!0Ep#SRl;V9(}-}iNx2Li{Ytb^OJUhaN}-GtF=I8r|u#OHCN53wfyP_MJU z|LGY2jgI?|;b%QOr|L@M*06&{%N4EI+#@*PR<`lju4RN%EoxN1bEggI>o^S(meF5H zOpnF<^VJPX(Zk&T((FlpO{A3n?P-*>qmiPSv&+|;Yi4iqzhe}s>v;Stct}3cb(Kt) z4h@H4za*|PNyy$hSXf7yx+FhUQKn0tqV#;*)I2S{@mO2n<-70wETz70U$LMY{e3#& zj)GE8VhGY&5(B2d#02+i*6n#$k01B#Tdjfr_bUz#Hdp99xt0RR90zXNK%INJ^3)3X z6?Z@WGVh$zu=Zn~e23(U{8Pvm{OPoKe?#zmS6S|ZFy|Gf0p^i9PS9hUaF~e?&cWZx zNH2q$RexJ_8?@u)ThY~t7;JJFgL|Fv167_OhclGsZP0aUy~JB97^kkXZR|#2Tn$?A zXx{{h5~k>&L@C$nqe+8AzbXl|qEr@Gr?Vk{_*XE1n`l-Md`(aMAnp;WB$u<_7_@LO z05(h3f+us9FG+11GVy4HIFNv#nh~bRohS9Y?`QAV*jWFDSGgFq{jkGEUF(IiM_|Qh zu`z~7avKU@#YHo-h0GTL#6p|F!kMnO`dD<`fZ5>4LiZC;?Hju=)Wogr$^%Lb&Q$L- z_Qt0oxu{V#(y(Z-7GpZw;FVsL?7q+k2DYNqI&jx3 zRwor1s3L*-c`dV@fe*ASbW%r$R;m*zJ{hQFaCE4-wD+3$ zo-sSas3>))7a(TPV|!xua$lfczXojW*vi=nOEJ=b8_`Y?Dw}3In4k1gPnPX86VKbJ z=nYKu)~4<9guJx!OkH=qv+A#2mcb%phS`_fxu{V@1I=q0?bCtL69} zQKj;@h8BaRT$P6^fZ2E3yOUpI3zT+rv+4ElQKlBx!qn)lU+p2BV4~d{P#EQr&B*ND z%xNhl4`0YvkeV%{aV@k7fF+1Gq$F=uSlFucF73XrNd{goGm^T4g*_wLHl2$Jmxmf& z=fh^$nnFSU@sPy3SU16uU!h?g#}ysocHk%_xQfI}n?fHEFM&xs*BAt+=#nN*&>zC7 z6??9;{@aIx=7oR-s}GU>d&jAC$%#0gwXGF){-PSI-f#UagV%pV6}Bgt!peSS zd7^$1UL^kgOV!2kpI)Q?=v%7Qbu>^d&^8PtS(xGU3j_<6w6)nVCDD-SiBL!_(MZw3 zW}Dqvo+TkDS%DLS6k(IZ_m>X3Lsg7%P635UW-+Sc;ida6($_E$%kX`g$0@JQ&yTORvp}nY`QwMoVxSw z&Kh{M4jrrY1?^rUvxNKy%^^eso9O$2|AJX&bm;5vRL~MnINl_0GX^uCvawxWv&e7xPUKViD>k(eX+vV!NnY|pm?xBSJ*@j-{#I<7NOi(LmDb-xDbL( zscXjVf{Ay&bLh%VuXK(P9+@Ume(T4IwHG&*RKk%LY^V|Is9cQ{^} z(4DQrVURkM_Otb2sy%2zBT>FXb*P?XhAQ3O5j>bKLDd0UeG9NnA!PRT?}!wmlWM&eR=A%YZH?iUhUcW2DmYjo@yrc` z562}OYmJI68w3>FpuJqX(|N3-`yrcQS2)_nrJVGG>kijD3R#SU-^S80EZML$R$rv4 zE%+>a2_{$D6-)#63RN;O;@tGF4}+p#a-nYwH4nuXtG)IaBH>xezbki-TP0;L-RGG8 z&Q{^Q{^CCQPB1;UgQr|W#U8^qwOOyKsw(MtuhEd~;aiJ!QSHt(J7z21q(@JKi(igo z;T|71zQte8A7z!guG)NDbLer&P`vY#cdifIX2-SaYKQp#=XX*+0 z?)rii6U@eYu_Hh#hr%DF5U1@OG@)z`A8fGA_ zUYlY%CC{N;iLlj<0_1!DPo2WX-R)lE%x4Y!YQ@q`4&5gcJFm0f;K}fz05>@#5O5T zC1xQxg!GI5#0tMeQEDi32}PZ++L$Z>l_&)6i){V zP4-_ud>K@%T)mXdTpVoO|HlMM)$S|VAIZO&UYC0;N^DO|NpVIWd%9Rhnizl|Yw3oFIKa zqYj+{Uuzm75#cMeV zZy{i9;-;n=0rE#`r%z!*i=(e8f$+#;li6Fd(dwWu_Uvf5D7ap#8UQ+d^yWhdm>L$i zmJItnj|^+@Wh{syhqZawQ#mn|0XRK`9sV@>h=fR`bw$T_S>_W#Wvl_YP%;mhzGnId zY>2h(=D|0TJTW-J9KF!+FTd8mu)VjPL$)0YW0&)1|qsW9Ccu zFQ7W5ms-HdwR%z@Xb4at)}-7>groQ9Y*W>(K^w5R6$$1sft!!=n1ZM;nEL^JW3 z%b2c{3)Kl6$B_0cpmy)g`_JwB3a92`&3S6u>*G62*z<4K1qNv0-Q5043+fO|gPxc#$NNNyfqLR;+E zIu)km!fOMuojqlyUhmo_0SsX$JZJzk8=k)06P6m}mnd(jRF#GDDXi0Xw93e0bWnbp zT}dh~n!4Lx5fL!ybmM)+L9V_P!?RI9kmHPAz+!jFfv%6zbY_AnEf;m%>Y&v|k)Y31 z-JWG}R_cYSAqkhfyAWro+cMMvyU|20D_>w`ZF!Za=);GHK6r+3d2c2znX({~=CnE3 zvdKP#SS<%qpfgR?%8&|p^`Gz@&Wwo{ID3NMg{(Xqbf+oIwEPAgO4$arldM9J;mbyz zFbpuZK0Bq|bCGl}=(-e~@Fw1yvwY~^u}s+tO}+;w2CIN}sK*-~n;moWI00gv)12nJ_uPi4pqn*Ic$rVH} zp|Lm2S~PpApKwXRkw08InHwzXOQopc*Rs2HO_r`zFv4rO4h+H$ zEX1W~*u^bbBFuUvO3KWNKR|Q}D`(}y;fxe{tomjg%qo!Bt9Jw=fYEwau~vNAnbyjar$gbmRI{O2^t^lbjjov_YZA^yAZIv99I52LJHeDbWtQT{tC%9;nYJ8UaOdF%Imx% z4;+?Fv8zQZ*NJYYJIG9ZT6<2_Hxjb5WWOuY-rL5rI@vzs9wisVFk@6pg-r7UxN4HD<2W;2gy5>U7N*G*TyT@h`-;&yB*ih0WP6ahxz`^ z8I_bdk2>_r0$4xY$!(}9kpZ);U28<+K*p?L?Cut0-rBu}#)Tn;D3^82e0SQ%2PF*P z=511^#3a@srf_EfiXH5h3I7kGjaPn#YD22Xt+>-Dv1tze{@b6PWKM_-?CiFI zBQ5K>;7kgK7%16~qBLfnulECCwbmI{?B}R%ovsy&G2*v>JdW4YY`AwHnET%B zr2dFYEK?X6gc9gg+SHK2SS2RXos&PWs;Ee_o#|f5_F|+5dlEu}`qzCcYL4Q0GLPBz z&ptt5^*qCmGOgzPU-MMQi=eR4;i_C^;8T{wUCSw0pvih#TkCBY6(@%&#JE#OH(%8cHN`yPSg%*kJSko+J~W5PL^v@ zk5Jeu)ul5h6;>J3HZu!C(J3BgwDUDj_Tm%-W+XAM<8eqI8vr$-jq0F{ z`e?`tsNf0(xe&0`Mvm!SgJE)g>xoy5`tdYq%-m9BO}rcg1%H2B71yD_R4c#@TNE;)I-9*m_e$LIEFVb43-Lj3kAmV^dn5H zEV2O$S#wa^QoC>9rOy6%_9wx_UGT48^_2#5-ugo>o;moyB#cXUEK>!nB#!R9U9pJv zUa^hLH6t41HVPyjW&%^_LZBv71YEK<@E zx8Wh@7J+_Zn+F}wHM7oXqt5MPIGR?vI(un(J=Kyr5yDK-RBV{z6v$LXV4u&EVBc%e z<)`<7@%cRH1l{m(*i-mdR*3|KGsEwg~y)o4<+GY=Sg?&z?} zg`{p^=ZtQ$M~+Pup{)AK*}3gTY;k9H#i@c#!_U&?*)5Adyb2qQEvZc`2z8O~WoZEo zd4?RhKBl*Oa{jTlO1>InYnW~aPP!q_Z#5II2XfIs<*93dkwX&yY_fvwjv6DpDBKI< z(OxbB?1B0-NAR#AJO+Y+3S0zr`rO6FZ+OXHhJLn$dh@ECN9(By29loBCk#)x%?10+ ztoy8S(B!YI!mMA5HB3#4fRowY(rpNx1-%=Qjd!u9yQ(oa$Hl8mCMP!%Dm_PXvSh%})rLN2XysKgaj>VcMC; z9zAqh`|esO(@?gI*kX2a zQYauo6ww#M2V_%B%q`)vY6Y+@A$DT8BX4#rh1 z_vp8k|0?~+V-@6NdE7lquQz|6^^s7rI>Q$7M$j>weHj7bLnyEGf@30;DOr9 z@W%TsxA%8hG90hfn(Poht%*d;l_~|gjHdhF(W3d3^Uy-|v8KuLXqy#z&%Y6wq|I(i zvRJ|1V|+GT7isabl&;HIjm8IB^L5{^U>CCIr%!i6aw5aRN~f@uIDc9Pb}=5?QWt_| zN>ECSkOW(Zdwa(|-~qCZ3GuK61l-N}oP8SuJSFq|4QKbuX!Ts7t4^Af0hOiePWLtX>!vb16|@nJrY@^@k{^}`Z2b?VZL;;89q$TpV>($Rq4j4GF1 zZ0sZKs0G6=w2JcwJXh&R;`w!cP#t>SO(W(Qd<#2%E8V)YbOehfrx;TS?bxX!r(gti zLOcS3(;pp;16iG^?EcnRap_G0K|l0q&B2s@+2J%Bb_lAKdGUp76mb8H>wS@q#L=FiQN-n3 zuX0p3lqk!BnA|TQ0$XKwC6Wb{Ibu{c+gYJTS?NlB?_gVxl56s0zd$tP6k+t27$E2r z&l`4yKNunT#Tg27erK_-*Yr24<{QuG&W#@YYh5n1G&ZIl1&JzF^s<&JKhaE6bpK)j zEUz|h zfAJ1-mU#}|EwqSPTMvds9^_S8Z%zkmwUP9VCA}A0S!THygVg3A8y1(0!aBXxQZY4h z@0WLf_rAz>#|6hcF0Y}?u8zz4k530^he$EMPJ0a#<`JcqvXk?(eWGj*4(4%$w?4L1 zQbv-K&`weob-|e}kHlK3Og^Ir-DmEknxyWxs>60MPX6ZVX=wu?E-uEf7w|c{h0AMu z^#N2*`iQC#WBv%y(Uln+a+Io$yG37?pUcqeDkqnQ!?H-~NU3#lC_C^to8g?-Os$44 z>)vVL6sgv+Yp{)UV^zxxUTk{(I&7Wj4v9iV^WroVb<_(wIq6w|1<$Zhk6pdJpEmoN z+I%y&bh_h%X(%B%e^@EYC^0YvEF!gZ=5TAdDPlBu?Dn|mFd0)(ZlIp)LSwfJ;bJHG z2XSGHmcqv5<+VOz$CN3I`R_|ZKZh8eF5W8J!LyGZ6fv4jpS0(xbpDb{XwobNi{iBER5Q_)&^}u&Qg!r zppo0BINgB`EYefBKJKari@V=5NzC8YZbEOe3%+OKg7B#=Gz_-UlbkPXcgT|7A6!+1 z+T467O@_zfthY^NS34ha!*lKds@&c4)X2>;mXl1=Ipy`0CW|^Dp{o=nwO#^Y0M8fi z9?4t;zmm^3n%(a>E_}!B;)(o24ZyBk0u{|fk|?TGm)@bJJySkVdTuU+OilD~ZMfc8gub01l)bF7m6w_IH3i)F#RAjFkDFY7}!TOZU&f=&MPiO4b zF?da9!5TkQ$Lf4g+kt;}T7{jG40g}(KJ-BR4~TmW+~Im={Ggnx(W^9^x=IZ7M%?`R zyz!TDVU}>){I&Yp108Ooew|KQZ~VFU6FapQa1cTbXi;`X_x}I^G)(}}>FKNQachl6 z_*Qd5O>x~uq;HTU@~R6(g^eh zO+vz^Wui%GbtO(p)|>i~@`iYn%Xe{s?6Duud+_N!`oHXw3w+Xvj-3u5vPRX>tukNy zYzfly-K7~`G&?vhw{Tn8xMP<+Ue?t5cr|o~9#TTl+cG$x4zG)J3F4nC?5>uZ^ae61 z>l0`hyJxn0LR+TyQRjuVgVol0GwjS4n^A2ce~3Knvd!O9sW^rvNMPwV5^=LW?@g3l z{qpv1ksgGo-{$wND9C>IWZWFNdLWAaGH2LUj3g@rs5dazuB0v77L`1HKt6XXY?3v= zGs*Ceb~)m@+z>Y(g9?;LI>M(?lCerYG`}cJ0$H7}!P}l#Fr)5jGyp)&SS$4rvR)VP zB!t6Yn1*Evw8lCZ!KIkxRNsy6ifz7W%JgU_p4W_C(C+=@LSBQIHu(UZ_j%FfZG&D` z64<8ffYZZ*0zt-W7ZS_G5 z;9ZVyQes&(uFUb3rAGD4i9<>ouJazc@}!;;z8T6_sbDs=hq}vmH|Il57xly~?oI7+ z{4dZyAzn;&QEb_7h!+Uj{@}EV8wWF5fqOB*ggxp`9|6FWplb&S`6uq78DR8@mFC0e4Jaj({Wq8@?cWYBaZjXS#P@BNwFB8Mr808(|2wn88$v7agv zKe~$n3Z0AjO_Cf*B3%Xr5$(SabD)3}8Q{Ss!cQWo{qdH6fRKz*j$$l(1&UvXBFh*S z|6BCM8X}c!gyM92mr9iY7BPY(`mSLeMNqW789-!Vt5`44rZlL$jt%ulI%L+2w2mEbx4e2T zuIA4Xom$uo8GM3r0T}QA8HjI7)Lx}X7S=z0<<*QTXYHXM zU9z2A4h$dPd}SfzmfxL{&6*$3Y$|2qx%h;Ew^;ec{npfLxr(@#FWWC4OaxVrRsR<-~e9jZY2k_(ijhNydE_)!ypa6q0HD{(611(m1jV7CP9SPrM$0^vRug>d(&h7{FR9(t>ig?M z5ZCs_#lMP})){Gum3$xvqOm406+@$$?4Obr@6PtCvf;E7Ak-dpT0LZQ$ zY3Yz~F%BlXi{(fMgy{1)=sLs5Cqozrr+#nm?PxwwU_zy&<1H5WT)kUt7?&n)0J9w( z{K;M-5X3O+6#>Sr2VP8{J@Ph-UQcx(R0;s2N-7P-PL7Rzq@J;D{Li2@Q#aqR+Z3Wt zmM97JCZQYl_E?`Wjz!1(=m4r4Iutw=BWDGhAp#+8tHg|OmT3hyEC1fFod0M`g)weomDQFGLpX`@Q{R~{&n zPfa990^zDWBuj%?&|mpj@)v*XMkB^DZsS1g;arA-P#npxLy(ONS>F*R!ncfx$q(;^ z))yTix7zeed^_5e*dN(iqwc=*?@o@xaJ<84zhKg-+p44c2DX6fNk9!OFD2h*vo0fT zxA2)ktyE>u?lr5d3NhQrGzR56w~%^S$TS6cE`LhDNQ~$VpU6xC^q}vvh6Q}#=>`DH zM|{$~ARkHkm?r-HICgH3JH5m&XjHej+WjiVKnw@>-0s{jY`0y1&tXz6+c=n?6>}a7=^k?N&I&zv%jEPB71p}x&5;dd zkOS5CWU-srumfeVITZAY&c5LCRZtxZmKT2Q-Q#neUZneQ1+tu-N1Ao{6H;~lrT=Fh zU-9(Q68Kg_w)zHv|L>`u-yW(?=7#_FjP303|4Q{#-ubqSLHVL1F@oLrS{8BD;cSGy5%8V16=E_-6)=x@p1!QH`*d+w{4?fp1@xtWJF^wd04I-k zI&jTk;)$S&GCXB0!@X0GXoKFMbm$EjF#E%&$9F<2b#^8iCw;uUyz zgi%RN07Wx9irTz4k)jo`qCrMS`JUs=v$`;+5eC_>+nv@cd*2bCMR!8&qydb9Dy7fg zjP81uMPV4j$%XVwOarAV+eV|6;5u<56vHxydJNKyh4ky6x?;j|?jy*6A=O<6+XOMi zi-D=A^(022cVF11>E8!sle-#KBxabaG5AkQArYWAOIo36xwsBm{8@sdl(3r@_P=Z* z)z@N`yuC|ToQdwHc-4X=!F@6Zz(Vdrec)v8Qv1m{wLfz4C}EHnS_c`f|EP2Ns9o}| z7n5knuFa+JvD$+%15WmR$YpNXJu?`MifmxPkL4?Z%xNeiJ10K(Ffek@Se7&7uvJRBijjSH zgoV&4@u`_GZ6%s4^^zi*m$c_FKxD8k)1{`+EkA^icPu*zKduozK{%_5>LvzO@3AFF zEEQuPn*QQVr^_NI1?j@Q)jw>WC2a%Va)_sjljhR1-eF$(B{2LY{?-}YQ}N~ZqyfwK zf>yDJyrjyD#4{IW$xU_=H5fMf@ba6(%eN;`8jI@orQ_2YgSYaS%PoVySTS;E(duIF zM)J#-%9=t@^awbEhU(Ijve6K!k=Z(?=1n&-#BK;HF>A)>AP2eDgqUd*1voMTk( zrPj6RuF6L~12k%jk!Lre^0@I#is;<8TQ4fr{5^=_(*0%Tq3qgWbrT)1xd*A`7E*VJ zN63AKS0px@D|^&Ye=&t5Y&3w_7uFsrD$kxVA$z8hq0uy!!BJ7a5F`DBhyC|vlDmzX zFp3P|F#C$ucDBvA+?ms8_D zkC5fE!_a+%62cc1{i@*5bHwJf*4$-9DqeL|C=g3wFp{lV8Gy3`$(PFud z=7PNM3q}d}pHxLPV}t)P+Wad4?7z@aw4JnNTZq zSd|kKXYcHobY_}eo%bdDsU`mVq13NS3zhYzb-s7v4@&DEW+=j+zn6^h<2k?CE3Z$^ z$4fgspFrPpZ9$$afpxq47QI_?!)b@eOrl5g>7mui!lyyru7|%(yX>yUn!&C|Hy?4s zm|$PCG;ysq`5D-9fIhgyw?tizxSWu%-basyw8>|0LG)Uu_X=yI`xz(;HMNQN85B;s z#N*6NOyS8w0mxX{-dxmAEsr&IMyCxsw8ycZ?ia`$47*%DdK`U?`sl{U>0oe*tc;nM zi)zMC=bGEab!&Bpi?d!9E>=XWoDzmIVNicG;qAwo2oxB2h-*UshNBvvUbdKi!zlG2 zXG!=_3v6CJ>9(B9y6MeF5c7GH$9a+&dsVAUt6s~k?t%Je?$sk5B4rb-N@&V5NPQl8 zUKf=lsWP_S7s}3UnKEt;0>2#YH!!m&JNnQjTx15|=p{?6@3`rxYiX52Hm4efIz1}Q zBo-2ix+yyDTYjq8pzPjVu?;7i>AvwD$Q~BrtIMuN=ZVsGD`_KoagaGw z7WN6=S09%RPkW*K(Zs6ZLUApS=GNTQtTBv>_>4c40VQ*kv%*Wain)gLUEOGzL+-FA zpzD^jQ2oHtB?Rlp!EyO9<#3b;btyr=Y63#cUmn5fi7X zujhyyx>uGKV~%Rkm9+2e#jGTt`|li8sfXevv|=U^uaytQiBL@d<-ao6*+r*J%t$mE z-9L|gb?h%Ar`geEatRNiaW)Dhfdg*apQRj04XDgS&C#I`56oAz7S(K1J!0&wuP3{= zoHzMxt`mBhE<5+sVKULZD}`ed&-j*}=AZ$;K;m$=@08liheuwNLBxt0Or$fk)?)YI z;-kozJ=j^((vdhcl0ZjxZ_!#wAN~Mht&V{TSvFBQ8sv%%Fa~*J!jvoKAXAHsoNJ;@ zQi?RD<*n6pI*M2UFgRth&LQ_X$KbYo2z;@G(TGo}sG~e3w0xUM+muqs1(Ry5+{RKW zm1sr`cmtqhV4CR03_~r`ejcwJK;FY0E-OqC@2PXW9ysgn=mVAY$b@mR25`U3+$ijf zXZF!SCYB)nOjQxcPY;y%YGz;SbIdKQF$N7w*&;VIz>S z{+vhR7%KGP8@l*hnB>#h@ddW7%aojb!ofN3T~uWZVtRf{O~*In|8Ud#k$VEx{^cdw z1-{M~P2K2`l%ACr3TUHbar~`iAKM~y2!DUX2%Xik6-I&ID%zR5h}bP#v!F;Fx7qvN zxF~Tgvq?lB0Dnu!iLbyU*v>xqnog1Nl6m?ChVJPzd65K0a5P5Nu4OQc{z4-+pUEEH`PrnF^;ZIv=w^ zvCDYx1XZ%zS90jQOt`C5;1ahi#d=l%W-N4JZs`$|ltc9cTZp_3VQ?;994rW}-Ne#> zH_`X*U&bU4Mju<)@0US7tRFwv|F3y6R^MD;3pyhwqb`jt#|>cw-BzAXUZ#4f8AVegt)$KRHPty3zx69u5Ejs7x8QOtQ6g5 zjN`&Cjc*KItl{0z!a2rN={;lbHyUm{?H;LK{!}zH{J4$}GX;wkfReX_E65ainUSVh zN|u0Y$)7YR{*C$|*02GzOPxZ%1Si-pDvtM)go!jkq|A<#^~0}<c;9cCTUbUH;Ga4;3;b>-JTk2}J2ZG)P8ct-F+`h$q&F z9Z43uX6U@yX*ev|va7@2dEH;&jVKej?CE_*%Yiwf4P!Kb-Po~@l=l(N4@M6+44IRJ zKY(le-8UZ(<}|tMk{1`4f-|ibXQnPF|AHiW=)b?E1Y;49>j`4#lIScl-6Ehp=pFD# zCrAW~>Q%;6aa4f^cnfkz+crtS-0ObY+56eoN+iN%?aLSF+qpbZ&8Gb*P^=23q1*GI zRhZ-4C=v{@o613YX_GE+fP6H;rcAM8^xC71r9e#{D^Da-cQ04+Q-xvC7N|yRi?$ep zf=lt=QVBYx?*dqHKJ>9z9OXQTg?S0oY{crj{0V)+Eoh&jIR7^`Hyw}Wp!tZZf3Hs@JkFL;IQ z?#}w)?Do&DdbwFePKaPF=fmZ_0lF)1vf%ZejOmJ}+4sa%@U+PEth`*ymZCiL8AFkJ zHfY;S_ye&FF**;bH?p8sf9OU>+sdniFNkuwcmkgX__U?Bv%iUuS2?68VVoQLwW>-g zBB6{XX%*iilbla`#Ud1^Ix+yx4X)x_=Qcuo7zkmC!GcnRf5TT}qB=TUvopEVednc_ zWMRjDaFM9r<8bYX@%M?t9b-os8zFdYZd<+yTFVb+HMhRj5HLEItr=U>WT;b$Ewn0PUx#)~YIgb*3FS=_~FGR%^l^)y^ z)NXt#Kgfq%6y>($A7#)w@Z))X71MwZ_l3?8g{M5)!@+>Ze*ax^0|RhWcvMiH@J;Au zw_q{Ch(B<=-!RbKsT%j|w=^78{Zg|yo#MBNRnTX}aY25FI z`&dWN&15Z4XanjI^CzE*k)-GK8;|{)kSFcXG-afkR|C&uiq!Cj|9oQ)-*e^^(EpT8 z>|821r(l+CxU>34qSKohSCt^=O`EVlvAV`qtQZnR>~DW^ZrMm^K>4LvjPn)0*~k=E zp)0=AnrhzzHZ2bIh_%3Mti7%?^AD%C7U%pd>zRp)Hdn3|GGDBXCt(op0dL#&k6g;4 zt`2L79(k`sRBRB{5`$>m9LgDb9+jLo#ikO2u%l3LAY16-WDzN6XOpw!E9hPP2M9Fm zi|cs}x<uL;5OwS3+VonqfwabIh)j)1T8IyA5huAn%;kOed zo`|cz0?-|C6E%_$agX6E?JUM|bw+rd_P5P z@o+@(v9`(aXQ@qjIwo9&PrCA&N~&K&1EHIzn!>mt-+V#ZW%atQh@5sS4F`q@AM+OI zlEUnyQS;m8x4}leTrPe*!2c81Q7j{illEw!Lm+9e7-Y1p8w{T{0)PF56BrZ!+(*9BuDr zdVD{?^pHeg@j`+#DMT{stu?{KlrM2&ji^<>%{jxAC{u!IiAe{TR@#VLtdtzMk=P@7 z9;=AmDcfq)ol&tm0b3cv?4pHc>cOK9E(s@vA#5RW$c8LJ44IO{$!G`nWe)>M>K^`m zIUGNvCBP6!3pn*T=WC6IDOBCKxiH`2@6T3W_7!;)K~lwsF&{Lqsmw#FsnRJoi6G0Y zha06iCuWhYRHIEWIvt5-yv_W7iJ^O7Y6cWw!hV8om|Y0rZ!4miVurx=;Y|6kEC7W# zayexhaAYyib}LgFw`H-_Q;GNr9!41q*UFII*m@j=oH1<5e*EgnpYLi$h|gPUG71Ba z4Nxo8h)RUrAS}eP>oQyf8KXUu7m4sE#6@S6?xM77GgvJwQ{2YIu`U+Ij6H=kNIX4> zl@a5jYj{o~sx+KbNyIyn*_dMx(8jfMYcY^$7(Bs0annfew-_M}xy>v^xd)OO{W*Oc za_C==&HodU#jl^O4H@CWKTh9Ncqnz=9#bvMbDSmFS-6hqHG+`cEX<;fjcqctqP1AR z-MqPi3wOmnFkT1UWsHEX1|qhdUmS-Ian3L>%20G_HWctVl3UvL9u`s%H)cWZohl;j zp8cc`caOzqlFDN*y&1Eu2wd~{2hW<5YyTw(vJ`36s#mY;)hctBA~V2!cNvF%JzT`A ze2;Bl@xt>0lAv$a(+=U8To<>Kw9-u7=DN_6%W1Pu2TMpH&*A-|ni@qz5vElkqM2Bx zK^+EJek8;KAif8;Tze!0o@1_Fv^vsyp+4Y^g{l&%ZJO#{rNEgOk)AxGGSj2Su>qO5 zT|1QA&a^4?iVzY~bGmG4A}FS+V^YQ03D)x|xX5acq~g7)<8Vt33A=ybx}DK>Tn- zXfT(|OLCe~XL_IpZ?@ORzTp>Zr3=b7v_n6z{0e)PYpiTiMolPFd(nfK>(ZI5E~~=b zln(i|x4e3ze!GiK@>yo`ZoR4H?cYZl%-S6Y;mO`<=v&}uh5f7B&(*oNV}+u-P>^S| zzz@gUR|a1XW@pbcK4+Jl$N5=h&;DW7F{ls$6?d40>{K$GKtdY*^lv|S@#s4fjy7RX zMG!+YKEhBe2|wX0oFPXB49`Cs!{lY)#bG9!X_f)#u17LpmkCy(7OLg`@niE@{)h(!`xsOr_) z8irj{omz9tkyvBO7qV;;$1TW8}s?%AK9bYm*cbi`NHz6Q7iO z?v@+Q6W8NU-=0r8KiZcH;GCZ)VQCTTm=of$YbMKBa|Huy4}S{HMXs#K3^iq0ii)BY zwp^ywLkhI!ywjJANgl5^&;2^ed+Ft!1-Yw45;Q$%)|tHo@$FHRA+2=fe^SEui->Y1 zIFmT~lfLVigkUD!tNQ1rIYW1#T8pmRxjoVpIfYU$m4#SS^L zRBdjdn^k2^FkN7bnTa-7WzRHFb5svVb9=1UnVTV4+Vuo90bA6;C|3@6yh-sVEyXK) zxKIBQA!u5L1;3T>S4rGbr|DocmHm;EKNl@aMI3CUTnCi_H5*oB8M9qd!h}b*5ux$S z6)$(OnbfWrgt7=#NuwJvhCxtQT@+9%qMnaNsM+KyRFNAeiBA92iWtwo;b-?-;p=xm z6>x^MCC$mIf|S&msq{tRiI#iqz@#+J@t|rQ?1uRzBswUTsWF;4E4Ja#o#urBG+uGw zmQ2b$RMii61Q|$bGsITkX`iy?DYFE$8F>SdkF1PL`tBIr-hG%g8xs!3m&uP|-pkGi0eJFJAo z2KacW@}+IYr_B$}I&qEDPHaV5>4vFi%aTq7Vgj9@Yec}P5O(spOjS9~TnQc#G-q2p z9s4Xwv(&W)F)~?;`b1$u9F_U_Ad42#uKR$wjvPbs@#nmTAXD>lod9wW=xi`6R7QziPU{@h2|Gv z_i|&kE!XApulalZ$EBnDEY$G0%89YSbHPpN?Ec29SxIGIagLq8LIx73_^5eXoU|J{ zWTa;LZ0P$JIBIs&6e-B8#N^6a{Y=kvw)Gopdp~|uP29una{9x1Cnq;Z)d9rcYsCO<^z8L-W_{-!rKv&!b-rG^b5+y#Y<-1@?r|Q@F)#pNDfTcvTdqB^F0+$J1t=iY9M8OXIE#(5{Bi4!1 zw_lWpY6;#W+_rG!Jkm__Q)*>Vqmy?zh24^BQ*m5#tD_}&KoT*@>gz%+%9;=++v&1O z`(>~pXy7uoUD3Oy`b|OIi!HieLttOP4a(H^sK+F~5wT?sqc*D;tg%z+s{w2Fc`%@t zn#%wruYu06YBQZz?-d4IRFW2XUK(5Q|)4}Prd8A_0L@iUArR^`*l@Q z>P}W=qeqL5rGoJ%%U-C8DK=QUGgg1vV(bZ^%`@>G-4c>?n187S8PQMKa;^lH9%>!Y z2t+XXq%6xB+Izonm7f!@AhwT_;wQI_e0Z_nZi#~{&=B4qX_x(p(Faonz7~%_ycUPP zv+smn%Es7%DE-|(WSFltcu}J;&Kgu)`-apUVj&2>*&C94hq*|0xXf~HI{UknE=TkM z91kZ|Ac1>rZa+sjDbrm!b0(LQ(43TAQLdn=gAb|OUuR)e=_;q6nD!`vp<=?;pohRE zRFkTlx_B0yiz&Eo;`EtpWK%*~7Oy9W6_FDoJaG$JTAzj~7}-lPp)_)GSH7Q@F&aQw z{^?*aa)C{>z>z?nSU(M={dF76{zv&V|1WML={S!e{|a|7JwV#SqbIfWN$#McMJsU> zw{kLP+WS{_kZr_ovX5 zI&|Az#1Bx$9AqYIC&;ei2c9S`@qdv zW5S)S!tr_!7L}17XGMrTGp{hvWhSdk=C4R}xX-vG(22Kz=5a~3^yhI&w;0)&nW)4t z*Q4salpP+hx~DK6;?9A)h2B355O#*1&7SG_Y7X8T*<;E!&0zoLZR-^#FN~*{&%kqV z#gg9&eT4N)q8@%3&Mq{fM_I-dyp?4rcTzh_peE-ZF=vRPUJDMZC_b_|O1>FoOg+zV zJUKqbPZ&fPrn%|pW4h!K>rMuDl>(4``6z8~Qd`&qsl#tsd=O(a4Yb7t|vgN(Vrj_i+e)k+|1Hza^0cKN>4+yGkSompZi7pj{uZSRel! zGD#nR<5Gc`8N{&C+iOqX48L30Q6oIFGA2+H!x~Sd6|fI1K5Pjm>^#4P{xwkUVXwI4 zT1Jsq2g^2=X%knSvHv8poVj1^<&&annKIOtw<(CMwi83Y<#s6V_4vT^&2@-0JIDQq z8-KYaR~yg4Ec3hMuDN}M3HVo1D>1u_QRR0B1NYt0{!coYf3~rr`i4%n4(|V}li_}} zUEu=<2NwdDbpa<61z$P*(Ei*H$e-+d*#DT%KUDrKobOD`{2=<=pAQK5$Vd9z9PFHI zT-=Yp%b$#2B=Y`6!HzTOEG11hMqh4Zs;6&+Fe*tSwKyX&DYfz}H!dkdr*EVuMJFjk zBVlZGyK*Zq3ZCLu*)WVU_t1BSrEFP+iP;*^2ffMU=r=5-@0^4;3d|-7E(&e}j-Ut1 z6`$k}J7}N>5ibqE`SDL+;`Tuy@8>t+1pWIx{J&+G`7gl4H{Ha>NZ-Ne|8O`}iCZ>E z0vI7Xd5KN6&CQxas#-tz#8He2mWF1Gc?P#ueofLK9Y!vyS4C!>VID-HNc6pt zOg;^jtUoOS{^*@#y!sq_ADfzKRy zv|LCUJGT;VuV#CY2iF&=C~TTLtZhPV)c`-E*;1(CVTCbea_`!-vtb4OK?0@@04vg#I9_x4G4}|-?}78 z<&ESqmuvPLQlxxcyhRSK{AN=tl%G!gvJw_C58iJj_vGrW6=aOLS7)*FCuCOLr=Dvb z-LTKH+fO0=HrsRD97v)pkbgv zp%F!tn?ewS~Af7D~JM~vi6V#!N``&g$v@oeYZatpS?*Lz8u)6k!A|kQ zT^1T$V7Nt^j;KE88osC~Tr1ke!lVwb?f}yDTjZH7ko0t$_FSZtNNA!9ndaGs;il`? zKLfVgMiWx!J7C%Wy9}v+4cLE2(d3++{u#0VF_9>5*dQsO=#+qk^qWyzm#NYySN!aY zS=53ZhRCo;muD0(_rfU_KhJq+*tFhYNBW6 z_w{}U$_)_1BE!hmsyB4gQRA?dd#fIbPQJNZn`hJFoJ#p@d}&`B0BgfDBnR+=F}!(yy1dViIOM!jscO zlEB5<2Q0Ae-J<)H3~i~IOdJEs(i^2a%-f0Fo}&>TW!(T9O@9-$k_fRp7?fd31iVSD z3M||42s3}cDQ+aj?8n@d4;6=KgtXNP3u3{d{(OK$5+_XiiIu`i!=OBT4p){94(}s) zn=YLlL#<9?H*r+FUjPS~eiey@O4QZ*fWkhiAdBmZ53vMX{Kcy>1lI^z6TB*v|HMPd zP*NX;guke=t!pJP2UnG9`q#(uq9zOSzZA~IQ%(Oh+4!yL_+)acFHQk9w;kn>hy>aF4Qjl zvxFB73*Fw|rR&5mGPO9NJy_~<7vv6ZH@W9~)d|CqyNEuO-gjsT%1gA`D@aRB{WECv zS|2h_0L}Fc^h|yN>1tLkbwuoNFG{b?oG?v zN1PYC)EC3U`UCu*aa_{hB)|V%jU2wKk?4PCuC~*6a5C4o`pzHOGArw|P;tTY3Rcw=%~Ulk90V zH?eX*Ryd|-^;?rXhO+9CsIqJ-N%(A)6)Y!o45ON}vGu)4&y(br0y0k$2Jtns^;7nY zD0RVVf~j8Jx=GG3-;xWPhZ2a{5${A22km?q-%!8llU=VJZC)lAWY5I3qw(>|liM;J zc5gHO6f+4t;nU4s86N^~ZJv=sY#UzfbUwe9`~fZJIzyd!AOmpw7a`3$4+vVOt6B#> zk?xTYh=B(TlW;LU|5Co}M}Lk|exIPhcSiVc;p+c-ii*biM*0R;#{b*XOj6{P8(=`- zMVB;twV<@Jf-Iv^mj;v}z(5ufm50z-$vQ-9iFjPAg^K=k))!Bj#Uapv2u%IN^8J*wUgchE zqcD*V-blM$x+k;x*1v&v^AlpTxr5(b>nd602Kk?%9e++IyjhPZ^*3pAwvg4-b z@8|PXH_zW;r5WH<@@30W|20n?C;r5f;(-g#s^Tu~f<`{=B!D{fV53!Q~d7qOM~rC#O-6e$#5PL4Xf}JCU%5M)guj1rc1ZQsaUC*mjgAQ89x(co zr+*4Gu&(b|hj2$<`%$Vux<~&^L42Bc=9txgd?g0Hnkw0-VVNn^U66#_L<3wlbS+vu zWE`ria&EAhFWy0%r+*?wl569BZRhHX3?yD&5<;E;9{VD|VHcS9N4D(>fK4q^(^eH( zumWH!np@<*o!o{0z;3OSmkRa4coBy^>2xPF1Y^@MaG@DOCAbja z+@;5bWf=jcS4WM;h+cgWP<0fmjJeJimg+A6OIU_O4UEQ*MdZ{h$V7BWy{{#5AY^3s zG+4Q2Fml5XBI?1cSgJ5Ie4Im0l|x+qb(K1_A^fXmb=gj0v>NrpCd!3qhJKsN2VSr; zR$!ReTy#H~rI^D<1=*~;B_Jebn$FDzz!jAgizB>6j%MfC3x&Vj#?if|3cGW=ar=C~Ktaf_X%*sNCU6hi7+^9~Fy5$xV*nXPJN zArnnAts@2`di~Ud*fU0Eb#VDceb88*=Z_DlL+k8nV)$Ob$ev#UyOZSy&oLOfzVLcn zqt9S53JcSl71FFXwV&|a+v>T0VZof&!+c_;^4yEzA8`dhGG--&#AalnRyi0M7~>Q$ zq!8u%C+D!A4{*^4pCJyMOh5zs7ia2oJD^D@CfdP2nXgjU?vlh@v`Qa4F$erDvdb1 zMfz#EFJgziamZ}Qd`FOU29Az7IMJ3N>KmO{t z;042a#Z;I}?IR5V^W@Sl&9%-OB>Y`{<2UzAS!r`X zZc_))bt#<(d%w_;pAQ8^6Y zDp92y?u*muvt=p+ag>P$rB1JDF*ye+%TZzGMHBUUM)idX3HZF3-!i6&FYgTzvSb7e zrzBL;cl~PTGf(;gJ^JqNixk-*T=PhAS0f2B16Ev2S*pi2KAa0wYJXk#V}T9Yu@`Pl zaeco(zC9q63qMb8Uzw4{-gSQs^O?|OU#E#k^dW5xER z1&~DaiCZTgnpP>(CN4M|cdN9YjSIaMcv6a3tca-wke~T`ME*i%V{W8WA(gB_Qp2{q z_6(XnVa)lV;=5+%$76+nlVl^>MNp9`acC47^{$-etH!7W9~UVQBiM&?G0Gu3f*nUy z@1GfTtN+xs#^%ac*Tl{MJC12Kk=%}Ss#Bl0Z(?b#Hovs8+{r)QNA}U>SYmLDG|m@5 ze#~4Jl^Xq8O?e5Um`0q?s0}>Me$es1{rmF1Cm)U#F(^4#8txeSx#~m&-L6i`|BOp2h|Z4e#v$AESqhBd`{dMi)7`hEhaZXa}K>qNXoACKFY?@sEFlIa@3cN2gs$CvDa0x0<>0uN;u<1dqFjkel z?4qztkkEcgYB%tO=EIaE7c2Y3BxjtVr~wU>iv@~gQp#yj741v}O3s%|FTj!(xPm8& zqh^Igg(Z01tPf3xw0$R>`Q^8p;0QQMo@6bdzQbDvwSOqk6bw66!_W zph@=1h$CsDsksawI`iuRV|rqMoUv*fF*K2k5KJXIK%j9E9dAGsdR?JrX?T_r0mM_R z>w-Y{zSW>rn8L_3sbuy5M_8__gDWJfbDzr)gW!TF_ML<78D*$8O6kH< zLcAtE<7T&5*Tp;Fm0-K5m!0yqYHjzK>h`_9&z16a%Y0Xpa`>GxBzrS7JdsWE`CG^SAOM9?>AbTGJZ)U_KmP|k_jONixa<@0b(D>z$dd5m++A2>?Q^6m$ zRDc^T4+MKI-1@X%R$E-nwy$ZhGw%1hJ>uhb47xp|t_ZtsXv#HHFg9;KpvwUKqp|_l z0E!-Zet><=N75~o`b;KIb$-R&g48=JmdTzi+jx;%o^bd8SsOK1^t7?B1S2t0n2&EN zNpwxO&$RWTkcWP+!7b(@D+p)g1cRPkv47?O2C%gv@fVK=K5Kre*Km+(82v!ObitcY z;#sQDGUvnL?oh3DJi#};wm?=}8q?Tj8!fi3UU^YPg8uugNen7~Gd>v*4QE1_dzvy0 zvw#FFr#$6^*DTjj)E{58o%nNAB#d4@(o60+sU`cYCW}| zgDRVHtyn$EKIy{aJ^6CbqvSy=i8-nUygpMp(L8Fq><=-KnHRTOA2IUge;pJX3-1ZActRfl z*^7Almk^MRpIJ7InWd%S(X!%QmEO|0$k@r)@%(5h$#o8}tRp^qPa!32;;MwMuDZoR zEp177#bx=ErF=q1GvJfF3*t1h)#|smCAx}s?QUPA*sX&(CQW4B>i>*sS)C!kcYDqhQyfAQO!auVL?wp%o`MXz-vUmQ`kpc9$V0< zIpn#vC#;AYB-B`6g~R0+kiJYfbx2r^Z=%L6e8QK0+!;~$fm+TYzKu#lW8>T|o&>Ze z?S>sIRVUL0qBIh&u~eQKi`(v zE}D5J!B;|Zco1pG&NFkb(W1kMoU2rQ{6#%3bf7-s5I$mQjV5-kSi#%InMXGCY8w|(ZjnlEjPlPpb>zatcWEkDdArm)QXZmkCfb4 zsBzg&nnz0^BJTJ52O%K>5-=g5|4(tqAjp%hzb7*`=;4yMJ-#~~8*L}u@9X$qCruYW zt_QW~I8Yv9#fm@vm`y^;4HJ*8wqD~)g#_k_PvXmo7R0Id<1ZON3Bkyi>l+Hjl79q3 z(c&x`^a1I>SQrv^?QGsOJ?Yp{mGV^LE`1Qv@|^8(x~SuqG)nh9{asT-#D^|#f3~{9 zygt9?TIHYZqOC3Ql<$l1<~45#gxWKK5t=IrHs@WfiRRCjIkyL!m~tEoLcD`Nhr*-6 zXCWKVB*I)kt(@4t8f9OXh%OpVG}j6M4nf#@6`A>PZyi@6X08`mw)j$rgIB*Tocgd*nCSC8BAom?;UaJBtAd)n7` zO$a8%H7q2$D(*x@@rNyjp{FV?_qsp5ay|VItw2|RBB8ZTz=j)3HlQV0sPBqOTYbOZ zW0^YZKwf$!tpxj`RzU>B0wvK|{Fh*f!jMHP*l$tw8!6f7vpT}QAH|!*cldJ#Auq{- z?2@$#W=-W3p<0#K@^vUS=-1!DW2A7HgZ8;6f4A5xZzEFq@WR15NcFGkl|An<=Q#FFq_@7!e}T?1 z{{WSlr|XE@+JXVE?)3*6*`Zx2KjfwiEeG`Bs5JPOmFE&!VBIVf8wo%+YB@7$6Ts{_ z{~XG-Q$SlNArdR=ArVolUc-V4 z#wbFBLdMp=$&Coji(4#ic^AwBVw{2Uj#fw*TNIf}3*-(;3z&?QifX${NLk&nBER^LS(M!V8&dHbpbhW;ICiYqM>%tJH zK|lk`Pj@1o)apJEI3S@$xGN1L0q?E*+17KAe(TrTlCMycvx56SCQ+oYA2M^; zs!WbN2<}y*lNCz6IS2K|0l}cmY06k3n zP^Rs>Y)=wMU}>^OvKUT4h7!$w3Jb%t9RgqTZJ#->rESQfOv$cfG-uP1_N;4DItsH4 zOtlCy(4@nuL-372jbJ1S0G4QxB-u?K-sK>_98&VtX6?`=PH+dOOIUvbnSdU3ZJB@* z@ch7+uTkU;ZE#TU^%mb5q}rA20kud-evVhPx$sHe5V!AS+qt+B^HM%IcdzZl);qMn zfJfvJ&>}kY3d+E^;T~D8GGe^SRnRryMNNnMDktj*TAe|V-qMAek;L^*qNA`$Rm_R|X#6Q@2U@?NqwXPV1atm4k+Wi~+7gy{KRb1hp|R>%|rnS5kdC=qU%AW7-#=NI!-C0KBab3 zU$x4jRabpevHRA4ezix!je$~mHIag9EbN=^SUW4yA$OUPvoOKHI>Cc|ho;mmc*OZg z3I})F#}n+yC8=SNI`p&E2uL5|b#gB=(e+x+8?d2cq6)u$<)qAZ5^vSwa1u6j$WFI; z&=jJiXUz8S5Y|IVHlLy##h(5m%$}b<+LWRPAw`E|4gka2^$oKc48NmMscAegDrF02FwLH2p&a@GuBg4=7<(+x7q`c%;9QRnjlE8@#gh zLo&tQ!K5O^KZu;_gIyJp)_L{&y+q~M8yaq&adr83oTcVsXP2jzW|;%QQ(+T`L}Ho^ zck2^8Y&6RUrN%hC@m^8WQhqChD>uR~^Wxblw&5n$aYU94V@qZURY7z-#CeV(O>o{5 zo$tjF=Y$ObnaW6i1l`tqW`W$&wg%10(A^GT&hBmy&aFC42-?LEc4XyF=r+N6SNE2O zg$3DBs<6YC!VJ-+xdvRYn6(OjCp-aZyQ65mmCy{U?6vtSc8)Hpder7E-Tn>`O~OXO5H?|+WRkrntM*% zT1OTSub?Zuq#j-ubS54;*r&d@=dY@6S}>GPF^qq#KrJ#Zx3Fwe&^y<-NiF7NLVLpO zc8$xCCL<&ukYo-iUto0n5@^>6TpmQzQh07R(G^`i*Be=eN%ri$Kwr7ld&5+{*~CYG z#xm|@1Gwk3D!`@TTAv`{Wxr(R`1{90e9?kwkv36bow!*~y5UK|6|pNI=>n>gilJHA z4<`Q2$X1roy4B0d^pJ?%n{98BvgvAEJRIX}n8_(&&jhoFePlQLa=Ium7izg!vSvEw# z>=%@}s*?S$a#~^Rs^fN7eYscR_YXS0H*n)IX@(!gjT_2iQ3#634Vvdo8uK%P6$|2x zWsmrkUV|dulPjN)wMR+lm8TZUj>&a{Yh~fab!9%`+BZ*2!6fiA8DdBqJK zEO#Q9kw=bk-#kgPvZ|2f{n%&sL>{_bO>e)lo{N9&_(?5u4JzZ*h^ z_B4W)HV&@e(xm_SEdO`4mj7r675teJ2jD{*>Y6JxFDpz*6iu?in3qu|0wV)UM1aWI z`wotVTieDbK{j9g+2=(`k719a!;F?Bf4Bb*cD3G&o*IAZsJeQR{!wIdy8Nrz<{caw zu%|=zSh!brKB_(E3=%_#ZyQn+a0gUEWRl;F4Sc`8E944+S2!q}zA=;Xn-LzexvGCC zg3ac4sg0xUne=Pv04M1PNUeItMn~4T~DLt&M_S^4)b98{XZ2rr9sl|OE9BLs=XB7#Ix`>)F>6Ou_w#9)g;KDP zm_xx^LsEDHbeh+5d}FONTcr+0v-%=YlZ(X(V>oEunLYt-Oq(qHBfb@8>bIV7GLN_( zm$I&Seh^mU^$`7;#1t%$V{Vw09Vkw9RUApzQd)3gSt2mkVt6+3~GnkXg^my{PCPveuG#JmgP zfroWqw;Im8^baX<;CesVDx-+HE;V6NA!8ugd7WzaN6xjfcpTv zja_P3DRlCOExbr-f4jp6OJvb~CIeX=kwwf6%3@n+^m1Ax=*!ilo#EPnNK>|bE&BG% z69>tjJP)@Lpr-UxHkMCgr+F_c9Z>8Zt{#8)l|{i@UHTN-eM4Ptp9?qr6|i}giitdw zr^GdEL66tZeE|-^Hl&Ws&rs4S{sIPJRZMU-pH&b4MNSvNo0M9h#bZi1lww}K1T-eO zAER^_XUjhfkV@#)(iFm(U=5|D3Mz(DRMfOC#Ner@r3H^W3=rfW$e0#9_-;->UA=wN zQ)9{y6yN?bEhQI6f2kZC*M!me&;7={IUX)tx})=H(Bi5CE3|NxZ3XQmWM1VI|b`155kT z0;57jF|)Dw#4vM;X5ABKuE(aIK>?}>n)FJ>k|Qv#1CZh&Vpj50`6!QKX#FEmv==Kw zB$T@bTWJ-@57M`(aGi5axrYHSUvmX@9{i|KELuytK)99SKDNSOh(qw5e;HMnkZck# z`nL1XZyKP;zxguc9sZ`M`LAC|!8b%8@*#bKs3lUX_t@0{p!^(Ytk=9^2?>3O{iE=U zKNT*s(GWmjbz{Oo>0rcrNBepJR5G48_PC8ljI(a7KIBTi3+K(;|} zFpl*}mpTeJZVPOj)wO<|tycnHO7+D#QCxdUldmOZP8A@u8(NcUHf=&%1b_k31;uzC zCFrwYIWK9IUEHgFPd0f{k6#Z%KkQ9>#g3q$R#h)oIZJCZ3I zhH%|DHHUf;QW4rjE&tpk(e z!fVWjo}!a@%+~^`M3DSEm&|w*bEynf)tEU~b|=)``R+t$aWsIC!~&sJs?yS${2HQN zO;9_#rG-)s7*qB)iX4-S)E7}~Z=EY>QY7I{YlAuM7^g`-yV>-br6pAj?<8Sj8I`l(WOT=9s(Aa03==wasfv_l(TIWU<1dr%O?X0cP7A* zw9lUA^+)w-&tLpDALxv8)wkc~_$G$^+qV4o0lfbgTb9!l$K*re+9OugWD(kHYV@KI zt*3sFM9RTMf-uDl0pqsXg%f6O8#^!GPU9I4hVY6<`P+uPn@Qq)^%3zK-7CARb^FT} zxK>l*a>4AS^sYe7EBv~|<|&rnnmlCVD7KcnD=aCRj?(dn;(`7UjX z6!VAyp-_FtDejl-nP*MuxRDH-3g0R)Z(n_%u}M9z?xVDdl0yArE+vaxLF=8@f$Tc8 zVh034<3-y6>a>5F=zzw4`|9T6&i8`d3h0oo($bme0>~2+f2|bM)kK<()9$NlEXai! zi5+~VGTx;}y0+sv>Xvi6;7F1cq;|FJWTL1SLu7eJuR&A8ZUhN)pqBB?Jw$1cIc!oH z&6i~RW|dWSQPEqlt_T3h6^HjXR1Fewf#0^x-3lJ3+g+$`bMj`!gI5<~(M?L%Rg^7+1rq)(8q6UV4-=3&or)yDf zevXSJEqa3agLV;(XVok)mb5j@ni%CbTsR*t0)*%KM!D^%kyA{CPv)l>i1rDkA(02XREBM1$$4mMDHT_z6jBGo zrf%`a8>RzMO75cvYxa$p<$T9^3e7OeFh&C^=Cm zg}UWJe96@%hrc5I_E}|m?@{izbuu3ANn#LBU#HZ1`HXGoinX5T`}1>>hj~%MSk51X zX{e{LoP_eUlEP)+=_%@K>;mP^ti9_fwa}a?mljTB(s;qwG88H7>yLJEe6G!-V$BnUxSC}q6;&n0`uCn9o89VjvAe)FZ_U7tvt?xF3 z=5h;}6Zeli5VsP7kD9$=8vD{7DJ$r3dmA^Tn|)EF*X!>rDee z>ru*%APz53*6`O=OEJGS|LXiV0y~Bv-KFfWEKIGa-K+J+RWaJEiyplJ|Jj6c6zuY^ zzwvSSd$pk6|JsCPEOhk^O{^^p4DJ3g?HH#gj=)qJEkQ}wQTy?m2y9yf8KGcsgG#_l$ zNBO4E8$u42TCLI*>8KW73{tMuH(#J+@GsgjHEo*}!mCd&U~SPpC|VUM3aIZzahR4< z-?SH$QA?+lt)>oIqH_o7r=9*yb48zvIcsB|O*yEaw!LZ#;*vT!Yv&d-jVZGrL)St3 zE^I}zQqCfLb9h>dm~Rh8zyL;0A-T0M1wRD) z^vE9_@ylL~gjo>oT|d(yvRUq@-YmJaL=Gpp7bBF2p`0p1CKsbb8|)h9 zD&Tm?xmZH7j`-jr+=EX)j~J2*RU-c~RpKfuo8g!uX&UA8suBe**5Mq4e8fRKU1pt9EXPIYwAF2<)Zy_r!*S@6rr&A;q3cNwkn-wtdk(5N ztZIuH0J`Od%!Z$&)g-fm3?lAGz;O*89U26qZ1@FwbRD{6y5si5W(?lX@$7L7kftJs z1>0rnXxUfD-zT}+m49r)BHTy9p0Ej zub`d6OAM(E+dz@RBB=A#o@j&tcn)*rZTXRLE|AxRzN5#eLek)IA0VNNzREN+ZS>WV z&a*VOW`>woQ_$zzfI-;5`)PkStUdxQ^;&W?4_`Cv+G;O zK#fPN;^d$Y|DA4}ExVPc@Kdr*x5MwEfVkT`45B>&*baVVUOlsrKhfqH)QSsPdzrDu4{B08EXD#z^pyI7c4w&^4j6L zc+u_8LZW*2&|wS=65WIx`4Y?%7-AeEgzwe*u5~ z#owl2^ak|*t?c*>+5aPbXq*2iUHvm;%Nc&}2h=yT{08oSh1%A0ym0Atd-=-S(n zF)}5(j8AhT$t4p6UF@7Xvg(_3$Q8AN;x4@&>-qQK2GvoUoO83Q=%Yyl?2|0uAFxZ! zrmN#65WP^&^d5GFQ{8FBLy>$f@Tg^*CzAE$9l|su?b$T^&MrwF>sLqxS>uV&E`P*= z-gCi{qXpteS1JC8m6#%ZztHAc%jTK;!i`Oi$YkjgiqLz_s8cWU^jUt5xl;O;uE{lG3dHwpcc|RcGipGn^@`}|)c~ns-dd@GFPx*Z) zwITCs;v_r@dZqh13&!jh;WH?-x;cC@a+(aZaxm}a7YLmptHTmIt0R@FaswEUzUcbXd z3iA&(Orrw1;c2m5^1kB{*BNA~G4R>s!SX2cWP+n+ic%*IyLd7|SH`M65EQgn4umZ; zdWqP`0&a|1`fg1ggxLzn0Qw}|^WNH#y2Hy?VUQtFMpFbWRS|pi!HK!ZHqyuhlBm1u z@Zy#Dx&zw$p4>+^=rX83!(7-;H$K!s7jIE(I>Tun^&c6n@xZ2|1lZ`DM#-$^f>jES zDskwlK`JWx$*-8G0Lf4ao1=a zb1Q(yD=AfIFA{BNLMLqHcE&N;u<5;6P^*$ob#y_tyn?X_oV@|;ZMmgINX~KiBRczD zdasUNxC|>aXs+HNXYOJ{#idCekonhzyIEICSa+BKTXKj{JIp9#?x8Xne=bu>+~PDl zTvt0>Z?|IHoqae8($8PuQ)}MA0S8C9FFO^d@o-9AaHSukNSIBOWI!Wbj6)nlU8D;q zpA<~i#3?mXkNV##p=Tket zPjN~;am>n_nmJh!bQBqEfuKF^>Z&uIx?~eZ@cw#xqxiuxqih?L!+jqm*0b!q-q)S> zEYQZ7+zd)EMFSjnvwYV#yZkiRh>HUn#|Ov0L+HTSH2>h$xWVMQVZRQD3?8&Df0m+% zp?axXaw!#s7M~%Nq}#-nL^TRk^17$hU`k79o}pAW`scZ`u1nz2smigcb1Iw5>@ngC zZ>jQ1sV&m$qhH6N>}^A+O-RbXX#3%D5=!dmjHjKB$6poRv_jkR@zfy*RQfPcxs@J^ ztrF2ncH}mY`#|vy=A1DW15Jr_a)*;hHB>Y4Zel5rnZL%fMfTWu_z6H5p@dQ4XA-Nz zPt%`Sw)wyYKps6Y@Y&$Q_9g(e0F`zIz&1ZwSet!-f3mQl0PO>L48$N-lWvZD|0^_fj9Z<$-e|GzaDC^A=^|PprQMCl%kmgVn0U zdSlw_VXkW^g>Eqe?$YOIsg1J&qcDAz^N!PVvQDzo#By9He>^eRG!*;JAjGlGgU#kxIg~D1WaY zcos2{M&h-rSZ`_oMQMN|c;NTKivaW2`K#9aSZ>GlKlcUP5A8%JjhQj^WG9%KaSp;$ zpQ7czRhY(q2ZRTuMA)p*%EK>0$wyXOC7*x^_RWttWCU1X5*oA%#)ejl<_b3Ja|*w( zjNUcL7^+7s@WAk{{Vixbc9&7 zo9`hgiLRlEGq`7(UekK{OLLA&toGUMJHmPTMl8PnHCp}s*8b;>l^YWSq(kB|Ewdbw zEn9qgtC@z!(tP8EOVFDMoc)l%WMn56h=qTrL>08z`DTXhN+Nml0=7Ku+u2Lm#YRsx zIsb51Daq}x-cpRN8EN>_B!t{LwpahBL*ir^$+faR(!Rp3@}iDRPCt;UT!y|=7FI(^ zR@Y>mL|QbR=$5%t?8HI;WFe!&hFbSOOdW_v@BRh7Lqmmfv*wia`kE@o6&@L3tP47&H91doy~t6R4$0 zw1T!_%|6Jd8bpaq5jxn2%iWBMc~>9FJ>|-#ZkmTN^3<;T^|oD-THl?u-}LK?{v)nIduJRF^FLl7X$zuQUJ+kMOh?CHIgM%V^ z?>R=&aB4u(?`ty@oNj?oS-9W0oXO~&zAZeJEI%0T5gE~x3fOFoMNdXkcnkIgr{7lL zoO{#+GS%soV!N7USgSm)M@=&0rZ07l3CZ}vb#0K0d(3kvI;o;+@1aV*Xrc0M4pE1R zzho&d6bb@i3DJYXJwB%>hg>rycNy-Tt_I8%h25^1Okd3$e*_V04ej&n)Ez^KZ)Yjz2CbWQ3nf=6m`Yt}g!PwBI$7R~{)6hgQuut9(pbn*!=FyDL z2T!UP2ZT+sa&zqE(R@OF@j6~)KVZ(N%3P!tILR2A3m}i58=#?RFyt(Fz05XuQM^=^2M$!;?PcDp^VON`)MbsBDh5IsFQ6|x zdjOk{PQ6RKM8*n=QpA2T%7i*45^h>&TT`V^&-8i(qgQEMf---k89sHB9J_x7hUqUV z^;NtoLf8Y)Uh3z<4)_w64P>>M%w)p9CMebAcm#Xi3%zjzV>AQHl~S8B0mGxLFoIqS zQwj%xb_C#HC^UpZO*Dc!isgsQ)#1t2#mXft>JzaE6<2Nxf^m?8W*5|( zfNLyd`%toQIu%iHx5K(MdwFtso+|; zrk9G*8EZaK^gh^)+*2mjHU6yA>pdnQ2qq$^5)qP8hL=5kWci)mtqOf~UCL|1=Nycz zH)=^9!KZWyw#S)7p{ubS`^S?WL#vznXBGzm+*&DZ_`YSSc>c>!>``X##dbY(0kiLK z&J3xqG~Y7WX!GQ5^#Dd|I5BWER#b3YRn>s~*)0nuSuU3@=(AG8TjkZWVR zoteJD?Rcp#Xvy1py*BEDdJe>8EDt=`tMOI3$HCTctki}D84Qu9#%7d-5MctAEx$#M zS|-qyPU1aA)d~4E#4h_gG0GoUaUAWmAUAkc#WwlZofvQHbwCY`d;X7SzGr zB<0JbMTUr*rJ|~FSc67Sr2i)vVGq8K9A)+0n4wK(vd`d5QuI)E< zu4YpiE4^iUS)x0PQ>ga{9&yxo;H#C{PveIz-5MQsEupRn84-MpIFiOKFQAyBf+Ygxg z$-$)YclEPaZ@`qh_*TFCoyq*Cj$gv?U3k&odu_kM=-#7jztf50y|y;kIQ&2|+t{iz zQtEK?W_*5Aq+uMuVKBxx#m_ z(KH#HA=On_v2atypOaDY495aIAerGu52nVUXYc zE1xCB7D(OZ0Dpw*X)`_DeK=bCZzYrv4n+z0M^IvM4XXqkcKKyriPu1GiAYI}n4`g0 z!Y1OR#jMuctM=PKWg!wSQ|zpaIE`btbBr|bEjILF&iOJ@_|&1@3K6-S;E^+a_ktzu(If{RIyk;g^! zA#{M5Le~-zLnE;~a#1$ZA2c|3^>c{wU<(rLBtd**GOv?cR#euF)OTf#sK6Jc+0Gxh zG~8f7@Ae@R0EN@P(UFA~LMm_dob@Em_bIRJBedvXJ{T_EwCT1s*#-9OEz}M@sS_{h zXE3xogOP>I^PDvL$l>zN+DV02T!3GRt)fm4xdkfLKm7)az-@_$mk4w{=V^%v*TXcM zrv4(D*v(xBmwSSEzxzC>*qSb(Qzo`0)Pd`4s_SL_!@> zOHTOH9}lP(UnXAE4gn-Kg%;8eztVDpikh_9w;`fJErH)}wshgqsqL|`siLW4VNJbl zUCGkDZOLl=>1`^7A&!<3)fH#*{b;N6OMTP&Mf&-bN81g(+x7N0o*hu6Wz1!&iZmnA zWrQHY40Br{6TH<`*l%;a(9BE`My)x-$ou7)=R}oUCKT8K#2Xnxjk@)y!R1BkOYoqF z0yebBl^Onh@UTTt7GU#Mzn#fc!HTns#%7)547DYMr8po0jJdM(8g#$*M;%VmVO33v z>ofN}?8}HML=pdAO(Y12Nc{wu=d{{kSOEKlWrcJ|;r4IYi898lXwttedvbryF-Xfz z7PzfPtmJF0Cx!@J*sMn|3iIzYV-uwXWvz*AhUhbfy!RN7k=-?d!D%&e8cAQBY`Wg)oq5rLM5enAn8d zoeTfi1LdQg@e9Ozb&3jfq>M{Xd;JvA^nw&A)wnvHnU+SoCKoYW&x~_ zPqo~@i3V-Dg*_f#1sQWzC=X#Lm>O){GmL{hp|M)ot&$2qgtq_duPQ8Y-S#F2Qs<^ah+8%N3luvEk}E#p)Qbmu$$-R`6wSmz%O4GkbObX6JktVwHOXh z@ATU#wAj8Fq_S>>jtyrn2GggQH93X0W|`KvwksUBr+E|Y@XaC&r2md`dU+ijedd;- z_2MT8q~_`rOEVb|yu7#AcJ9!l3YxE;XSf<#s2)!%ymA8(P~4~zv;+d+TiIw5?BK$( zT*w5F)0ZgZ(zcoyHl(J08tY>AkcP2tGr`RRN*GqCb-hiT7;8VwV3JIMQ~2ReP5bb` znbG)deH89Wa}fK9UJ>_V0s~>kcV@_@J(wtG(5Cv;haMMALMtitf;wl_W_9P6<}xMt zQva;#YA(T1EM;6PWwOgU8y=kPLn)3*_|}|vkv`O2zMcr!7)VfEP$#wJz~GWpXuOBO z7hK{dDaNj(xakN!7o=#^-I}<;p&x!IP83N3>WP!8we>kAjkc=deYb902jGxd64DFW zJ5n##WIc?7PG+N4ut0!mSlz%9TCnvq$bRXeAY#f%Aov!eVt^G;DA*ET7Z_APqL9)% zb5KZhOD(8Lp2edCWqI6^lj49qE^|5a-)wnlIWeFHEaDDR^WY1ot$L0rdy4qvJv+%ff$F&9eMVoxQMBYH?a|ek-aR&Z zQLpLe%2lt9Z5>nvQ1Fr=h$>M&as!vhHF@N{M|zXw5z&J_!?trNgNOlBjI{QW zTiUZyOxH7iTWA7$T5O79vgGaC@lUf*zEf;w!}wiX0FIU^jB6GAWb2TXafgsHp5IMn z=0GXiN(OTp0NL5P+2HpGHvQNSVX3c6g&t@!z|z}scZuVRcwxseFhbGricL4hv-6oR0Pk{IN~IG+en&;2fABdSh|71a+&r^Yp36Q~5sQRb)VJDPgxBbv-;#|Wow z461-`WUV-Q8CKXt^`4YFvL*40iAtTd$tx7#u?xAHha3OUt>m5LSryMq>`QEl>H2fJ zr1XXDGq{wlr3Md+N6c^|o6)PJdsC@tPZnS3oQDT8E2kIJ9Y;M)nK zO|)7t(U0bD2&=Zy53v&|MgFwf!F?v#kmqudTGy>hWVrW&M=s1B(;)SX9kW|BWS+k8 z>rd|FSVoBi(mTTst$gGy!!Cvj?!y2qU6FzTO1$NUCw&m*rWpF6t$44Kq&2fz_6lr} zg# z!mCV1fj{Gv1!ahK0#m6x5>AOuO#r46honcr@0KwML07?IkRRB!%bOFyeF6(8ex6yW zleSU8a=@7DK_7&bb(SRCyi7tgs!e(x$1pCQCap5DUou2CW~^qHDAWtE21J-8F&?qd zP6>*SJqK7&Ck9wxhRwWCI3r@I^*V5x^FiPz&B{!jnl0NxJ_~QtNm3lT9>`6G>OqJT zI{j;hO3TPZTytLE>IZnq2*FMzl|~acLWYFzcooJBBu*GSDsKHbC(R#`0wP5W5r|V% znzXs)+}13M9rfhwxFa>Y%#tc4N;SD6c~liWHhEMv`h|0GVBDB+s+4^RsV0LUGV|2a zqbb!<&Ll0yv0hl(9+D(l?JOT^ajr zu!TT&fx!oJ?B6ss`GVmGeC?6>{DH&t;)!jTa)u2Wx+7xp=Jo|F&8xA|$Gy2SXZe%!Ozs%x)V7MS&5j2+n~TXb>D6%&K;dX2NkB=;vMf;Y3T# z9BOXI1MH0pv1bm#c+Ms+J47{+@b@66E)S`-b`Q&Glr5@OGnVa%mWv!kLRyFA*uCac zC%3jjaj=RY#u^A15*KXqchx9G%g8Mou^jQz-t#bxm`JoDFirsZstTme49+;JAkGdl zE-jFIF9hES{aA-zDPsH9*&#Z2OP1Bn(+CW6|AWB%OoCTIOS0GrajbvFxG`IeQcrRo z{LUg=i#1(q3hL~XGSLbTucQ*hI4JZ^HFm`X#GoFtAol(V*ikM1C@^h+^PUINHI*>U zdEtTMM!o;W;x75=Ts!QZ{C*Uyv-)PGB*(0!aLZoa#-}Oz+t4-oT9r4mx3n<0@Sv>$ zMa!tJyOkjBWHD<%_b7L|;}2uyeVp!mhc3nsH7!}!9|<&QW()7w(ri8}!vbtA9X=Y8 zeL&;9z|?%u;yxqk*ca(NpDjMF9MSCAem30B`#KOqx657A*Nh3A;Ob{^21GBd#jtak zPm>h1_K`uA2jvX&4qhNeID8l3mr>>vk9l_eE&6Km3r>!8$#DSeBBeNjTlAdV_7W67&|uOS5G~ zdWICF@Qfw5r%=)qBB)iviPvC_Ri}0->jJOZ2nOjawL*-|R54ZdWa>*FVZ{5_Y4;QN z{IpP{ZjABAB>&c8Ga7R7d?w9OcgFsNOyh8*T9AjkZiXl!d}F!lw;Aw02!D2iQ6i*M;Oe<3 zF^N;C6*VOml6TtXtG$I2SfTE{fTzDT8Qe+8yd=Mod{1M0SI@jGY{l6rTMo8<+Todv z|1f&Ok@La_Oy-77<`J3sV~<9A%la5F^YsZeP{&ZB<1E(l<*IRzx)M0MpL|r&fhL=< z6poAC&jET9UPuU{+)_pOyg7QR^m>;GKm)md5!9!6EWTvQdYOIUUcp1oIROJKJ>6_Eq`a=_F3GXJG!AF%SLTYl|b8} zW5GuQ!xKcN4{6tuU+l)BpAVr)$ri6hU{fQb30cZjQ-)om2@!Q!c!c;xsQK|6YCW}V z!N|kRBk*uQp+OH!jh^>LP+WW&EZ@7twZW1S?;et;oo(JeZu0_xeWJK~A70;MF5z3n z(Aq9!{7TQfLoxrRToY+kmv%vN1I-!D(!87Yj3E0V?yuGyO=ltpygL0}uec`tNEbQk^-%h*Y&MLb&Q z*D0I`em~WoJ5e>F@x#_^m*}qCUZ?b*TK%oM=&P<#&4fO6_E?KN9N#OsyDfd!2Z8j^ zCY8%}$*yPkx$Wo^iYr?CuK?~xdE$vII=s(x*F)6in8h~KE4thcY4I`xQz6Il5d{N9J(gCyNjDuqXiE~L? zH&mjSVm-=Fq<5_JL#Rm!y$Z;vR74Qr**(k08{d4@b;6r^Hx9IHSBf4T_G1-vKM3?N zjPGiDJ{Y6{>teMg#lUfV4A@*bIC^A-9flS0FRP>)7ZItUJs=^u$?hcs&P|;+Z1C-9 zJ7R8~H|G>mU?4sW>cGkoaxl6f1E%Lrjj-Uzk;}*J+h3A}Beg_jhL0oZ9pz4(p|QnI z4>CzP!Fnmq=XQMtZe#?lqq6wOqy(u+!}}2uTf2A`mC8ozlK=y{w^mK#$!oaEN!Xyu zZw5VDP~!GkPZF05AL75*qKVnEh*S9EG(yPek?RidwepG#ubG$R5745U{sg~_P+LnA z)(BjIc$||lP<+ch???eQ4~S|MZ4^i)1b+fDbXM;5z0p(8hDUkGh^U0Lcb00u5cxniNkGz8TW8h zBisvsIYjKEDW|42OIy+W)(p~)vq0_c38KuG)BuHaRBAM|XDL_?Iiudagy>JCm5ku9 z4hx2KaeB%)^`AEaT&L^$=Zr4m4voMz4S45#@vxc`rp)Bk{E~j^`05?QIhF5o^)IAu zkl;!x)|t=FRT-sZW@K*08M^Viy*>~W&NYgsnb3pCXEFusE1D!Wn8YZRc0kM4*fu%n zw3YYO)#AJv0)|9K&_C&vjxSgXR_1EwXxVL;2XQetC(1_KpOWKn7%C00_L`s)o3}Zk zPR=-;P)95|El@|`7{f7*8*)A0X7*LNAc#te^4QMuC#zTe{zJn>8c#YX0>wZSC2qiA zotJ%C#)aatN9oxTCVWQkYFD6|N*vd9UN2&vJwDn1z&I{SL0&d2Q|l2Y_hM>e?Ie6Pqg=dyH>2O?~;&! zos1*h+ZfJ|o^~_0!rjkmXHpX~7UPC;kSB%8=s7Biq68>1Bb6MT)TXe47xAN&GQ`V@ z^N-iL&@|*2FXB|mxU)X?!i8&?FrDM-?3=z=*Qut2%E&n?{D%q)zRvmz9uT-xc_JBc zV%wA+N4O*x3a4YFk;XjVHDfrKqD4DfRdA*^sa)yFt=BXAy7s#L*<~ukmGe6tl%7VV zK1$hsk$V5+c1_WGhnW1MOc#1#;0i5&;0SU|gDzFX%IT8MJX$%=qVmLkDv-e`QGT@R z5J9;4z@ADFjh@aUb>G{cBCLvX-r_L+S4nXjF|jzo@2Lk5|F@=Oh4PC! z<`Objv>>2fb!6-`fR+AI6a|X9lZ8Gg7Q(5IEEE8NAh^?-!yiyI%86nI0*lss@zz4o zIpU37tCQ5qlDWab04wb~^{?W_qmCH>k^cF^xuO)7t4=m&j;GG=F~}(nZ%`X3?*$nW z8@#=JJ*~}#bJr=dW^@K-^=cYpY?edhTi2lneb=Rtw92k?WFxMvTgc9X<(m2vxAtg_ zG0aA+e2vW`EEeNd3=E)0N(^x!O7rErnvoSjhCOpI@chzvcq+_2i>PFIK|y&{0)1-M zm9at&OE)Q}5eL}HG;z!ozZO32xb6{-));#Gm-3x7{lXldg9N8S;lj9^k^VaQzLNQ2 z2YfO(^s42|d!pTJ-ZRyqM~}Y8gh%4~QDuKLtW0{3EeA{K?7&|{`NZe&)3?47*(>om zxl+_?*d{Wa(rB)|EF=}KYuAvKWYx{GZiTDg!O9dmG&)wSSHc8_Grcl1J1${VIKMIF z+HEkow$R*rQ(86XvhgX*O5@g=bX|4( z!XpOY9v`4<$+ahtwmGU}p{gJp-_N$b>6zd@sMYopX|zPHbB3xq;H~^7%b82ba}z$O zAx132T4pc@&WOEna6TXy!7{`pO|F8S{h(DSFk~YusT0;n;bMUmEpilJ{~5E-iYA-& zTaQ%M5Mict_~i!KTz#-;a7I;1fIepxn+weMaMYtv+K4&~ZhmqFaYs&H_}d=ls+oni zJSJ?8q4dScpuGw81P#(JJw8;I-f;uy(q9~Ev|-IrB(|A{^!eZfBy;egiw;iwAUt^2 zyo_3XXrW96dw%1#6gA{8&;+4HjQK!LA@lNKrtGsWsWGyhmgM%n;!N_*3|zls?S+N} zHSiJdfD4Ztpoy)*(_#T|=Wc8{$2wbdT)-178`Hz{Eyz5P^)frxUXe{SVkI@qWGQu0 zpDd*4(>D2S!(AL81=n&Hvh%4*e(zda*p9u(rKPRszm0R9#7TCn&@{07l9&^Eb1-Zy z$YX>ooiyM1lG#&#w4OFAi{*n6Knh!dyQ-ow{hF(t`BR=rXdVz)6Do<2ovjb9?2nO7 zi()wT3wT$qzI;#KFvgI>?8Df>qme$v7Mtyb4LfTH705wKixf@Od@?p=eVHvxDe#7~ zvwTM!fPg~|fxXkODwexvkbD|Da%gWYjOK!hOoVjQMEqxc_vTGS-{e#3xLr-wT2Jq1 zVN}u$6^=Q5IrgRermMZHyqWmHIL3uRwfF&>sc{mZ70TOjPARwA_txHi0}s%xx$BKt z;sPbuw#u4uuDiGApL=F5x0b%axk-%{6lZ6wb&=5LTH@3ZxVu9bUi}wxhh#rW3I89) zz9~AhwoNltvCYbxRBW3S+qP{R72CFL+qP}n_N4pop6U74nw~z~`*82)er{b5(*-Tf z+KsM!2l)e=sv*YIlDc3g+cyOgX_Ybww4m2Lp@WX$e0XGt*b!Mt>lLDH{*2nT^mV5C zm&wea`KESvv)kH5r*5L`te||iB2v2H?^2qw`O!+EpuzstH8^b7*6q9_2?)SDo+KTO z2oePAlh9_1xKvcg|Au%ow&Q%tVtakx_1yAy%w3vP8>UYwZ5oh)2tl&&Dl2~Z<85=V z+D#yJXcM8ya*ivFiF4|nv7P_G`HhKa`T=K4o^_O3Gm4$jH_Pr=fWctPYDZWf;J|&Q z_SF6h(Y5vH&hzxeE7EoFh_#>13vj*KQv@x5((e3Fo?T}Q>u#)c-IL}L-RB0!VXgP2 z4z&$bg;)w2dA-UH>ZyR)$2)oa0|ciRZJ>RineI33^fQ-p2+t7UBk{tWUz=;ujCkv9K`dZbW>T!DpGzXJA24^H zDIwk?CJZ4o3p?!ir#Vg7&$$vrhcBJZ*7qH6@Tar;=tzi>4C6y%PE8bC1o4rvl}D`T zMGgWhTa}dOG;3Q`7O3x@zmCYDMLt7ouTZFxG8>rRVM&Zm3EXa(wJQ8c^8G^``z@(@ z7e{C+=$Fl*D3u)^fjnD3u~wI^*yPOE6sw2&(X@@|M=J`e!sH+*Mc@fN&VmHLva2u{<4S(KPzHaSNV7d9s&hSp?!0A z@Oe=z%lKId{YGFiFsWBh)mjt(drQQ!~YF1r?2F?$~W{d+f1EYk@DDNu)ooI_#Ff@mL5~- z941^D7|pX$UZc}*AD9plB{4BtPlC{CpjNmAx-SVEDG{{Hh1(@NphJ(Qh zgHT^?-u#Vuv^a{1{CMWsKH>uZ(4u=Iy_p4iOr-QVeHY4UeH2s8W+v#E2-P;1dfGq+^WeM`I*t{KYKi3u;W1Fh4 zfRNg)$6p|uRn6eVs)W=^}U%)Pp4}rnWsS)Pv|9l$*MnT}T5WR%p z`(7@)ZPLusr8J`F&ys@y?rlIci%SNG?oFEC8`&?Dn}PU;l1kweI}>|f)r6}~<2)Hc zuZ#5==v=U~hs2~=c6Ai41%xqzom|*Cc4v+vW(fjwwnGP_M9X$Lg z4>~*P5PcX6v~uT_^d*sL7<=kVvEtZieS-e6EF5(l)HYU0FA#jCJs_7R&6-R0fI(Bay5qt8 zgsgcNVg~E~7V_QLS#%Rrtl`aTaCL{z!j|0|IwqG!sx8_CowQ)VgGz-P7ZBuy1^!~n zwdd`g5u6QkQ^lkz6p$3tk{opaVeVX_RW9EjOg^=l2d^d1sM9Rzp}^y2m7^!u9a1)? zZ<=H?HoELd%<0B{w&`c__vjB z{ie#tIYQdD($`$k0(GIwM&1YFO81L4P;K*p$LEZ@lIa};hZG}=BtQ0~#&KS@`+Ro*uz4^fg^h=H3@XB;`t*IfNvT0oED`IyLT$u`|2i@IvBpU~Cw6RYN6pIu6- zu?qh)FfhmlhUz(YyVz&{FSNtF;0Tcz_1&-8Jq{~~Zd zw|W50`?U;pIZH6h~;zGEkO7grHT4h6;yMZ?@u7MMfsAbl|EQd{`C zfCYjc)y;)h4C$NjBi?8I_nIHC#S2qk=|7B~$@@A6L11>Fp87n}HhK`~tdQ6Q_iYWH zImJi#!x3yzpyRm;&oK?BN-E@>7p2djmA*%oOqn`};u5L=O9cQ$v22iVeHme-*f~5W z^7G8qUy^?|I8krPi}&AH7rk$+3;loB;QaeF$#0=+Z!e{5Y4~4m$OO49>sc9;&&y@f z_*3RX=A)~L7E}Z*eGff4Jb_GdD>PRf_2Gi`ZcVY3)!f0Z5p<@MLGUl2FVek}fbf#@ z9^#7=wvS2Y$)|_U_lFPgza*q4$@(tmaNtTVSR!5MaKb(m<&(o#ZhhTYg0pp{IPiV! zxWO#(0a%BaiBiw%R<7$;s#WYHy%89R=HL%b3ze)=?p?Dc?Jk#hQH~a<5?93B=dCnIXdm4Dkv{7PnlvR6J zXiOT$DqVX1K17rZCixc%ZoWAtt8*0@q)O_Onk_n5Fce^D(FQ8@1vIC5yuu)`n;|W= zkJATQap3fmBm?`Ivv~wQX<&=d_>!{PfiOgG-q^(U4w%d>By9~0S-OskyA{hm?qHXD zKSHpthcCkZ?wlA}G)w^tr$_i-g<{HSN2ZOkH&$2d?7+~FAOJ^I+tU#%c$W`EJGE>j zXyT9wf3CzBu!>nozI5Fdjmm`&eOu6F=MCFXJf?0UiSXv79g|VWg;zN!eSz&k*JhEX z^ufBFqVR%{-RdYR>Zdk@DTV2+w?}`4KA5V@p$<_EV*G_om13~@TN|nSThEmG|9gfcbsh9g{>%A^P@J+y zGRE-YR#_%2C(f0n6P;TueW#VFkX$R4{aH*3Y1-YdO+|g4S{@6k8**~5!jW;}&_2Xp z#K7e;lGBkrH|cVo^CdCWG0)wWh7it5z)`pL)VcL`=Zf3;@z(W6>nCe~Fg@qb9WhI$ znQ|5w`xaGmCUUpjb@~RgiWn1BAtt&qwSCfoIQVpBGP-AA6VLP!hC5>$jeB zptWRI6pg4HlSN~6XFsBG^01EggUy2kCrXGK0(;f4RiBxhmZxqwpxXT8k8yG!6V*1X zFdAsSg5(_dx7Hri;B{uV&Lr(a%c7a8HOhjWV$)6Ww{L3hDy@a9IGHMiko@md_obb5 z!ycf-@eJ=$L9Ku(x~bEAZs(Yjq~LEaLz#vBweV#bGG%-NQ4oc!g5@>g3fLGA26jYy|}l9ZVu)v&&Z3c?q#_` z(}y(*s_}v)1vjfzA&dHiIQtru@sNz5f~sm95SFL9liK`Vugk_hG#IyfI+H2Mp*cGX zab2jr4=mYcz3mWpp~!Cnd8H^V!Av!?CAHgt9k9c39HcZsnKoOT+y;g-Z5o4RRJil0 zWUKcw#xlM*Sy!-uZi3WSWJ$7wyZt)C_9)mkPs;>ukHbpjmr?gr_6e>1TcuisrF5kc zv(|xGOg7!~G8R~Ja>k78v17s9+h*+z{`Xs`MvK95Zr9t`JBl@*Px)wL(Z@)$3gam} zRM(TgfAJ!`3`$~tSu-G-MD^RvOi1o=gdY@kx~yx3oTW*I(?ofW!q8jMQcbnZWLMVa zGEO|ua|7m5gV1&@3KtxII11#7_j$XBQ2thi+t&-mVISy#OY>H1lwb3fd-SbsA2=TV zvi8qB5pJPJzBrCgKbN&s=TM2L4XTFc%#q8N^Uywj=SQR+w(yIR2C#>}zQ)_gKC=4c zS1l3llC__Y%C8;R=lls3+G(M856b4GvHN2%Fg+TZSIqq7c$8S*H(&78WQWEdYyN9B zu;HH}C24pkpp#rf1KT^ya+VsIv6;HzKlrKukrudt`Nz;2Yv=JEsR2KaRJR#rCGdkW z^)mEol3WrGL?c&KYuzG2Ci{AQ=Qc5$K*y1ZSleg-?Y^`ovO4z&qoj66hUNH`cM5um zf|M<^!I-0-_Z~=ZVH=IMdt@G&6L7?vmJ+Q!$-g{9dFC5kLV0mea*-|9SGpUDVP#Ck zQf-vAgQvtrIRLTi3n8xa94Ai_qf^`7=jb&#&()M0mU(vea*yw?r&+pRg+bEbDP`xN z&Eg6Qc4d5>Ci??ii=E?9u|ABK$Z6o`mI)kjS6HVWsV>1xm49rW2-Kb-&*1c+t(pM+ znHG4=Qh(5E;snMAN5-1bQw#$jP+t=0n(yd7G47sU=0_&LH4Im885#vCGQ4mqhjRO8 z11|%etoDsT@(5xVg&avgq2JJ|a<%MoKGlmRe#ZfA)l3ZKzdYqX!%MY*Z|F$H*nH|F z_F4BNT5L7^GhN#?qsg&BC?`K|^9RTk5c9J|VMD*&gs6fpH0_;;enUte4hB znutWhgLQFj8TeOZNF(g7tRdco1#?cc=Nu-a=$~`v-e4-o_M)5eq89INT7WQK4M7ld z=uU-#0X_AFcO7EM&3)7A zQ%>Ryk)(S-LbU6=JCS3@JUru`@k#k>0x@a{NS7so?E6})?Q8So9kR}N%BhwtRx!WH3{GSF;WhOOn8f{= z4(Q!T36YU9>F*Z+OOoJnyaZj78R6Ul#)f z{zO;A9a2S`ZY)$^24)@3E8m|JjUlaIM95L1unRwz?J@F90Yzl5od{z$nGh?l(+00G zLJ8!DvJ%?vaG-Gv$($n*fFEIS%Pt0Q3t+wlhNM7CG;K4yW(X?2{S1Y_Dy_n8+$Pb}Hq&*G-|i+~ zI6@pD!P+-AzpYa#8Lf(4N_f{7*0Me4`E@gNs?w#uZc?nKUSS4VzVKTbTV$4v=eI}5 zz7NFx&nb+7mv`*6iSY|CqvpZ&!Ln0PMli;e_Lm4_9*#)m*MIQO*u{slX}=?K>$?DA z{vSr`B>e8tQuQ-q@zn~_#>G;m`+New|zQx0r{ZVqaUPB(K-grsLoiH%X z6V{zVTp`j2Jvv&-Ug<{ZH(hEAFOL3nZs-?ZhKgBIF{3ygGweFfWgZ7HYGwMMd37J!BgQ!&`AiF2yoFSDiL@9jO z8N^O`T#!Ci$Y5%)_fQU>cOENG8A+?2P+Z6JSC1(o_yx)z#7;R85RG;R79FjmA8(U- zf@UC9#|no4?URpHU3`yRj7P{fZ*e{k`Pa^)tvIGB_>!57Nlr7VAt@N$P1y>7ls(Ah^$62Aw?-p1_>2us6~PZ&?Ei=h5OSU+6Oh z3`oeJ4HvR-rFqH5H^{hJ<*YC>RFz1jutqQ#IExVhKACx-MbrC0fscLxyJPy-n&tkr zRbvRN*J4u2bWFnGdySE5i0%cU#!S|z^4e<%8B5lab6DsNZ3EQ>W(p{4Hqvp^%%@{V zUYeP7DycYSA25FMEE*2&cj$7qPD4Ay!Y;8 zlRhgs`4t4W(a*Uy;s`_hWMNqO!14K;^>W7wZxtALMf!MnFljpB!#6W1tJ)dTQ)95@ zT&4HZIcD@nB-i~<82p}GBD!$ueB0nRKTam)hGyJt%3-GF!z0iN{q(yP_+z&S#-b1S zi>&n5`=)S$pV~31Lezn{)piut_7qzK>Z|p#fB45>>}J|i@TXL$Ix+Sl0ua;J1!A_c zStF6nQL0Qcwk-^i+2tl^f6;|g?is+q3n_1A8#)}kxu*kOg2P(0Y3*=r4>aSux$o!d zv#4KLXu{7v0940KLxWAO8)jSV_pC`7jZoN zhguouZK7SlcML9r{Y!?>+Rm89-sayF^^EMkn^k9PJ9CofW^erH!tg?ziFZzs7zAit5(L!YH4S*5++ew8TBysah-}(T|Ua0AHMTHPx(O;R_lw=O%|XP#YR;4mQ&2LaBN`&2E7T+XAYVYlIX)bVPa3zU+}pRzks zU1T2iTCIIP$Kp$s>|x@)sGWOQ!3eWO1K_#yD32PZW{35Rp1^dye-}@A;9rN7DHG*O z#g~vI&&rcc#o+c#Yw$Fu?9TTZ{6N_Gj?35^kD%AAgN?+6p4Qpqyq@NepCDq0zNxn< z8eE;1W%Pp(HMV1o?@)Lgx7BP*+Y^e$O2mkRJW!?vkUKFN1V4J`$nNz4x*Pe1V@+yd z46~jj!!!&h$?2KfgsPXM1fT5(h~#n7z4#;+$!fd7>h1>Xd4Xz3{4OKig-q|@izr%y z6cWB3T|}u`=#ac&gLZSa7Dj=0q85Ua-4MFZF-#!3Q4IHT!}&+^Hb>-?caf+Uco_?_8=R?HO!2sk_gOWmb&5NaN(*e*A!Zw5kt-~F zQ1-m96jJ8dp#p>I=*osW!~yT{7=s6jDlt%A>8VtFUT9 zC}0TuNuOnV>_vDM-ch<3@baT&okMN?iHLouFcabGP!dXF&Li$Ah>;$*Q zs0(FjjIv8&fJ1byQ)|yU;tk2sEXbrFGe~W9Ko_pZl81qoysM0fc}?5Bsu^5FqS90} zH)@IP^DD5^V~0F2^u5EsqikU4J|{nJ7pHK+SljpvZLzqb#$$(mkh*fC4|#f}kGslT zp~tHOr`tdC$HEtj4Z_GjOXC#F;mo=3VSfw;5D?XOBK{v<0{;>3%I4o*lc=AQ8A}-{ z;z-0AIs#%m)3gkDNQS-y{=a_*-jYMgXr+o8{RWOpp@rAtCdbOEutv$jmzl0XV?q-N zR;j}2aM&mJVv?o#U`$X)mOR`eZ~vK_cuLL3Jk*w(VnQt`bCfPX9%GJBtthQcpraif zIlxt|TOTM(YR{i7=Le>k?O}?Ks-1ad5oWBGYdO-q&a#0cSs7x4WM@Hk(Gn@3r1Lt9 zI2a&YF+2!6QLTTnkn~D8btGkAni6I#msF#A)gvHbxAO}fWG#I`CSc@er2skFR)ZeH zl-dSkM+hz^@(4~`BE7_S7nGPCDSsSp0` zQlNjEA|T#gM}avp0DebEA%DWB!Z*^Uojhz)TkC&T$QxvuExJ~?OdW>n3-hQ_Dp-=t zwnfKyRTDUv9tWIjqv%_7@E4gXL$k1*F>@6kxhG@75X{igo;@pcCRDu9&Xaj-5QGsF zCsOgG7r(mAyc%J=l^hMqqCGSWlWst>Sw8zvtYAb#2bC0_IY&{c?|32BD8k<)i7_10 zF|ohe(C}O%!>^&^G4$Zpmw`@VZ?DZR#iWgnge_SF6?*SHreL{%9K8`TyiLVZojWFc zgw7K-EZx7b%A%nG5Ql-5N9CA7zPm za7J(;j)Ty6P4pQVWN8BUnA(%ea*xw@F63zLg<|hJ0tapmD}wH@>mz zR3gr3+Oj@lB!#vG{EY_IeZdjpGD=AI03S92k9$d`AoR>7Kd*KQ%r|78L%EXsufM89SpkrlgGv)#EP|$HBa=*Sfvb*8Y6-KQ-C9|Wu zLOrPDALWM78NJ8YQpG!>S9x&Be{xTmK5sIkh3{Bn_H;jm1MVOYd?sUzQuQeZZ^rDV zA|#3jGzzZOaUedCDs_HDhHY~W-v8{SX3QQ;Jw%I-XWZ-mxuoL@+B*LefLji6zpHit zG3tkUCo!VSq5DTxz!?i%ofF2@1JRYUP-R$Rd)F2a=zhsVYk=O7>_j)u0$WTzR}675 z=m0DxhNKWkBZD-r1m!RQ!FzH0GHE@nf*ZU2csH+P=VDB11J$WD4^nZZiwUJ~1I8kR zox?j~3f=Y|Y5%CA(h#uWRTR$&I{yl2Eu-Fj2>9648s`Qw{xJvaRkc;pcJ}_rJ2}3kfT>PqFNFh*^RMS|e^%-Q0gLSuqWB+-b6&o{3EVFo zgR?u_u7Pj)a1QQZVlVec6xLP#9j#-VSc_22fktW>4GF?a`?InesnblRZ!8R3!V8x~@tw585E_Lg+J`3IB{ZKMt#b-Qq){60v2TNV!NKk%{ZZ z*{?z8xFL1gp^B8+wMrlCcm~!6_wN6Aj<3tw`Qah;0?p}9b3+TZ`~`}G%>DRD=b|Rj z&7g;siMp^%VzlRq*yBZqP7^A`Nt9SeP&Fv7M*tTBvUbBf>WYoZaTB`S*ZBGyYS*-# z__0R(^5~gVDtPIp&;{5!1ScKkgOzAU$z@I!oR_C@jj1NB!dy@rzEf8Rx}_ksTE`xZz*`yOQrZOS0Msdkk_>K&X@5d& zcwvNj`u-l;r50xtT~p6-0^oj%bW@LJs8;3O2nW8He%ODIwg>>ZQdoPzu1OjH0(I}A~@aX745-fgICa&6-v!y!-iCk zSx%eTBmm&jaG1WXpQ=%DTA4)CB(Q2v?n*aiSHr8<$q?Za|{+gOdlyQ25ZUZlveIow=}+n z$vj913Xht5@`x(2@pqF*AXw)2cB}dNI}hp!9`4jkxPKQ-0ZyyPj!{3;cD1J8!Ri4v zbZikkB1@}zPG+ei3FcY#%jLn(MIZJKIwG(nU(wjsb^zwKMHin#OkZY_5y#(2k*6_) zQ?(ywzo`2u#OIfiqas_lEnZsXsH(Au7c}DSCUPjP9HN{$H;RkL!qlPgrtrE~kivpU zf_N!5V$}M=6?4;rdpT8D$~6$Kx{f$0vM5@KR5&`B2ElAHWvflba%A+dPT+8^*8Vi9 z({FO8J#JeT9K@&Ui}fIVN@!z2mdUW7YabVotYG1r78i}>0c1X8=}@to@Z{f_sBr`K z_`e@RRCht?)X&lF`+wB%VWU{?68RZycsRtt`4Q$h^b%qgu)xIDfbK{d`9!odMMTI2 zWEe!yRVlCv{B>|ki;cUm&LmoharjfXk7RFCMkJ{t%SD#vr_uwyPj#rc;q;8O@o6xlGnb&kEl7ucs> zFqWuHd>3sfM88e66rZNQQWBZzLn2OG!r9GBdvg7v$z$uOtt+kT{R!S1#0J+3z{|tidYVZ8 zkZR6Rz_z4OJ*l)IpAu-SOwS+5qU&}bDt#W2s+D8Wf>;d2el)>gRH(;ZF#deru6T`d zENr*eM?w-` z+D=+f6OTBAN~Ja!0M@JJjFhnIsKqy%27J8vi*}{IRh~35IrUo`+0<(WgYzaimkeU+ z&Tuj;Q|iSdPna~sdo-_>ah5SYfF!M~n;*Z2XJyHmOc&tUcj}8OQK?Kg>up{I5p9n@ z>V5bIoGh+@Z2OVt{8{9vkW9k;_rYlnGAtM>rXY|8ii zo)K2a6wu9_0(jC&xXTIrtAR{87FG0h7ww8btng$Tbd;1_uF?B|y*@oH z@hux`N7MhNfBk{kBIpS@A@vPDYldDU5Rsd1sO2as&qeqX3bOmtO>KyI9bX6&0GRGS z<_3USh1uQzjpXuOkNh?^#qpTzPvHi%W=lMbGLI3&xoba#8diI9)g75rIT0*3;Xhz$ z^ue~t)vuGjBBG<(@(lfkle-T{{A1LbI1^KQBBfUJD^b3BRirCc0Hx1`)i;K@;Q)8W z79t4M-vv)odeK~I`ZhR{66fIcL})>uw|{LoWrCQQ8VZOFkhgsSpVp9ifU?z~#Ul4R zE_3<@65H@SR^4)*)V5uc5>_56zK68%W(2}$@u6lB5fHV9fs7|_6oBtkA(_8$`bZQR zl75GOM1tZlB+NV|(I*NfVMdDz;`Tyi+i1u&zegFB})cN$yG zUXX`h&R9!m*^gi4j_QwHlacFa3Y3gM=TK({|a0mr8J>5jw(|> zO5K%-SV;@n^MWIHhXd;Ozbu(piNlsmaJV)XhMy^eVab+@D zhMnoW-cxzNEzjj-FnID?+(MvwHQZPe(PCxV1Ju{@z#zi@7h~@-o)&VX)9;@VW$LVO z(enKD5^P3!2TKSQNpBf;7fO>WPRd73b76th7DuB14beLauSN{#&Oks{U**=YKCVwR zMYs3W;myW-K)Mfn_Xc)D`UZifM;v77`=u21Uf#%3jEe^**HVmFVPzgmN@t{d+(@S3 zx;MZ*;4a&tlmF1;5A59dgX$@tW9$EJSFXaXO~;3(Vj zH+L{D(3Uaq!T^~U3PkA2O*g>DxP{Jr)AGVx|7VR(R_k{lj$~3ZZS+smM>5{rV8RW( z@edkM&iCtw9g8?VGTV9>K~7+|NTI@ z29oo*f3=D3>T^LMNZvhD7}QN4L`)wbu#i*b48yjbBo%juS)z?Jl-QPh9O$~a-#R(V zIye6630I)r(sNgAY4SK=%zTFGBo8~R&-oM}cv%~B7g%rzI zWYypT{0CwiRwC-bLH^N85nFU<{+A0|a7xiP*IqJ7%kvHQbYXj8!6UBSi6_Km%wXt{ zE5(>7i!ZQB2^Xz+ij%20=Bu^8wkRPcO0dYv&mhs7{AzKEC=tfGpC*__aK;+<) z#;{-e;~#shw=)J23y5#W4>TYkqW?BQ+J9@*IQ&OSRIzkHQAYK$Mp~A{kW=9%_nC!6 zgGif(K+Vsu=MiJX;9CRn7x?Zh`iyiL>M}A4rs2iS8yXfC;nhIP627&o(9BVlvgf5` zzRvcnKThscK6bRv+>MCe=s4PRTydN(Cp(_FuG}YEjxr~*KHYcd|2j4!@yGQ}G{#*{ z9HoaRa35pL9riWaH#cn?)po4iy3X0^o5&_R53}ms8^Ka+w7Ks_r`VwyZN=2kUuHl} zXqrEg*Wa(j8U0F~Db+$D=bS3P0EC8ySAuHVorP7@=^0 z)ASR37{SwT(yKwrqMIo$T@U($v$4;GNdSic7*y=Q}$rl_JRI{xIU&A71Qgb*We5gFaR zT|wI+sLKy1EW9K*720k=QV*N=zaWPlvt`K8TdACm(2wBr_S_-*9SOM0;TxnQdApYY zl86?&wt_7KZFd|UhEGvi&46+xn8rDXV7}MWgu#_9r!owpQbDYCz$Lwu*psY%?--+I!vm9fhAAet~8oQc_S&nSeKdveTe3l0S zFtXRfnM`puJgXzWz)=}x>CB>%1LO3N>JOojU9Fh|GoV-kpDbt$YU2u#hoXBYzvfJL zbK3WwBfZ_qXIMocvAsJHVs ziR{H;Awm!{7bVKKHuoZilH zQdueH2L)-6rs~F0=bIP&eu|lFmuYKo6<*y+*4b$5(%&A z(YC+@`hvuY(sIZTRf4RmFmC863Lcxz{2kTy?CKLYW+7*wIyu!n#6epx*q<8%ZJd!+ zG0Vp_*jJ$H(vm49eXTKt^&a!E??|0EecyiK5E6YXHnEt>i|R#f7;&p#lCV|V>XgL7 z;TAcI3=HPxpaVDL3D0+}o-)!QmL@!l4?3? zz#(SX9(el{Rh9A!B7DD(oV31*8}T&3VLs=V3e<-*-$MuWUdk)=$4||3LlAlDxW;!l zXT!ekR~o`ARIkDv%1tAF8vsWxgO9R7KH31ZK|V_PA(Ck4EQoUnj)7N9Qcz-3@xNHe)*qwdx4>H?I1D zPdLh5h|Oamk6;(yHp1?WZYDj3#h7DKJyp!=iM95y`#_4~fuGe%CoO&RvC3F7Yr;{-K87>M5z2rXXS8 zJPuLA5PnHb6Wnhn(D_4>u;vC?iEo1u;}?pX7AU7X+h1%wzb2~BdU}D}#8Wne!kUqMtmH3nwEEfYRDd=D-nR5A~5mxga2%&XT?25PHL)e1C7@iChN$>l8D=A^lZF$=go2QtZuYQ+!j{pQT@$uGd5X)9yKyPf z8|n@0Om%7%)rNyvJzfp`Sl?5|zIs{T8_401MFMtd2k+$L#*7e8Y^c8?KEK=(zC6Fb zAv-Vx%k>wO5>SWh7-p;2%IhfdlS72pARk|V^fTJEwPl!F^0;hV0n|fPu zvoFER9KPD~-_Wti;4dzKE?lzR^QzKT4}%}=i>k@VJnrl`Z%EeRDOu`-}6 ze~Du=gJBym=3U5jOzr_ho1D#OFCgoS_maypTZN8n$x82@6%o52+s;8}z36i9WS%pc zZlAvXA=y4e>-X2;Tk_fW8+OC@-<2!;))p3q`v0c5`0towLP0CXZ^tR!e|sVNz4`wy zEC2s(PN3PUY1N>Cf+7&Vfj?hrf-i|Y7w?~+7{rI{xt3T%Y2}=@LbdCC%Zm&vi|qL% zj5%dNGYt(13Ey@!&bH-o#P0p|@ecdjFA0hdMpb!!PD@@z>Z619*LxlXcfNY3VbNWs ztj zx_&ZXg&3AXB_D0NfTeO9G>xTsPd){a zWLxA^$kqm$bU4{chE?=arjMX}_NU1Ax0sN+4s;h|Dha5=vK|%5^hN1=1zpM6Yeu^2%tEW!AYQ!> z&hAZ%SgRA$iq?v$1?Q)-4=I@KaUf}*pa{i&#u4^7xb=hSQ3j~iPBhFA9{KQ?3#%UA zZCt)6+|KOv;eQymZ){WUdGhaqCt`3v?FtqIS%TTtGnXP8=S<<=%r+r5a$Jz}|{X zFT%Ut3kV#sjZax$rHf9(3Am5WH_kUEGDDCFz+V^ue~GJ4{k_z#B#svijyCm4 zo)xp(hw3HTl)IN!naQ&sNQNSQdlbX;McMh3;?2O#!J5Dne;7iZER zSR2dLMWvbg3{PL&hCqUh-*?Z~a}i8Wv*#zHVh*lG`pZNt{FsNBcT@GRL23wnL-g5R zo^9vpV8K6W^Bj0EJ;>)}H$_pA{brcS->NFs^Zm{*l6xH&u^X0C7Hq{fOnr+0KqZ3JH8f0g}sDws#yKb`~GtMwHA- z1G5dlpw)UG>)GC(pc5NjvWgcMMQ4Ot2~Xq;{RPfrP_NUp~DC?B9rZ5e3SV%o=TFQah>CnKZel7z&DgUExwf&lqeISzkb zPLyuH_2wd84E|t-C91t}uI>$4@7BqlmL}ZpP2a=V1(n+k+`&Fpo@miNr((I`3auZi z+(bX%0_j5e=QDu>p`qm$xQL)%Z7_sw;-QNeG@9EC;5L!W5O87k_-iK=084W>2BS9p z+09;LPOa5z&At>eM%6%z@en{G8H`3y(4#BtInrk#Fl7~bl%^}KrZeJc96?}~kZ}^O zmVSVV{t+N41oxLvS|s|))bO%%F&GCViJ1iY5x8UI!S0gqOc8gMG`Y>-)I==M;u%^W z(RGJ+I@5NSxy4~a#e-z4h_t=d3D~Bl#OSd$R(_#Pf6-)l^J%fQR-!e<`u?5WjyN+9 zN|;}`#uCs_LxLRfcQeLxE*UHV+FrS!c-LgER*Is=#(l}ru%yj|K#tmMx@vpw;|i;h zXOGLaK5w6YaJ4>4#PlLZ<5xN8=out6^_mt7{^S(RZMr0YkBf>oF_7VJY%$DstQS5p z-?$42>2=gFbNjiVWx;QAuAr^>-+&gxo`jYem02p#>`{!>Y=`o39Hq)#U8DyLH}ObA zjtW}~BddyOC;4O~wCp(+mM(h}gcn`2EjHy(=`2x#PdTOfCAx;r*j<|HPTn7d3DDk+ zNlb!Y>~G6uIL4D_Af;emVKysnYmjmg0MpCh$gI%(Xy<{ne)_q*%Qv|LVvD(z6!ZuW zf+c?Wt=q_9H5i?XEu);kRT%DS8MAj`M+OS0rz9uCMeIDP0&xZC|I~@Dez+a+P{UM7AZ7pTUTn@KBOTd4}j&% z@~i@pTTkhG*m4)tj39HTc3;h|c$1sQzKw&W*7r{83n;T+qi6LQeKV0|$K-uEb*aU3 zr|(Ht?@Tm1V4x^Lfx4FtxJvqetZU)t7Q8m+g-~K3x@Iw3Q4!f$Fsdq7aDR%YLoCt~OiFE-6P$RVK=HMn_ zbXq3pF6N;S`Pgq{mc1ZW7T!FJa8%5tFytre;_Z`=hn%eWWbZBEIH_5hZR(^eBjS#1 z%h4e%?*@`Q zslawKrzQ>bx*rszq!+oamNt(~>;aA_#X5_+uRLujD@l}b>Y_7P(IuqzJv`*vK5&Pj^Hw!hJfbJ;cafvdmj z$7bo1$gSI?a;ROwLhV2VfD&?%@DTf<5PPu@h2m6vCiI9JgUJO1nVf>L&Uc$|WRFf` zT69EgX=-_1jH#Vi$rQ#kHT2SMb3*pqGjLu29?oPHokdPeJkYMbik+cjL9RC1BgVn( zhy7qnbjm07=|@mTUd7v9`I+|5bX&JV&M9BszT5xYyy@;?IQ4yR-g4l8fWFnT|KC-O zkg0_szqO6)f8hpZD4oeG7-D>NR9BC+;^$^VKxs`I{+MYu*!1aEYDp#yPHu(<=WM?0 z*{CB|H8L_nr<#yx8)uY{(0-5B?(SzSvQ4*5?_6Sx*qcx4RQTd~aNnwDcv0+AYCFM z2rB+B?z%2MF00S;{r~R1K9qasJu_!!&YZdDp83*f2j8yvcvm>EU66D_7oG6w_Ucuu z_==D7T=0H*NRoSDz5=q@`<|6CB!+BR4v1qYupltjEdCd5`K%n7?-RjdcAZ(+*ev&~ zPY%sdP`rHm--~jXLvBwaCr7FC_+`QHJj9 zSMHnVDA4P>-@|u+NY(4I3<(ef3wyI~nWSy7Xm+1`Dml~{djP_Cq7C)_BrFG$T&C+& zXYG=5xiHffFNru9jTIksc=2VThJ&&23pJ|ZO7TbLl65o-ONn7{Zo8zuM@oyHcn=iF z<)bAtAKDQbR3x4s%$+H*Kd&4Mm!ykJPe%g|n=q_bdJGZo5%~-gER1sVB(a#zDUb-O zPX;M!z)(@$*+x~{{2jwPSLf{gj=M^<@WLd%cRk+D&I=WYl(L8q9BNob+F4=rWuwnS z;c7d9G4NQb!wi|Zqk&1R;~2pEc7}i(GD`H@u%n^u=S{ggPxnJy@|bpS=CV*?))bEf zP)OO8j|Qf7I-l9ay8hxsy1yXWSNn6F(OUYagOVr zWz$rM_P+Uu$C}%z6kijMt3az*)umwNHgCxIL5EK5Bsz0;a?K7FRpLGQ&4)8JuY&`M zeD*WZtRLTRlyRe}8zhkl)2x&etsV~ng(EKw?8lo$jb?rXNvMNaj@0!;fM9)asz!Bq zwKVdQN(Ng*vSaJntX$PJ$=bqUWPiB)dxq{rg_(h>3hbi_r$dMW(_X66sP7 z!7t822R4F;v^tGiVTSx;c3#8sAJE$bt@}0&2aC9~%)fd{vV;FZO~-C1Ps}Uyf=&>t z>H%lNfDe4MRD`?i8(BoL4yHkNuu)c{=s}aZg_2GTUY>YRzCEP}oA*M^YLZ79o=`%< zQFP+t5@3HkHqjDOF!G|#$Vps$5PFg3&v3`r1tU&N#YH6|(-=ak%wT@nzfJHB_+D^T z`W0Iy4*u#Ihe#T=VM+I-PjcxSX)21*T&4#yWI^k12X(Css#L1fmQy>k@}4KNaQ3XF zi$Jv-^VUa-p);i@L|}PkYhYq$1jsPdhDtq5l>#-+M0zhwZIYcK0v?mmm2i;H;+4`T zw^`jcpez|tw$@ONX84NcT^iY>8LhAaH!AZd%%XStuv=9V0=idNm|piYlJ@d9SM!U> z4f59Dj%kYT!xMCw(o@^+Yi|`3^+b%sMF7nVuS)H4w8?3!J-g-{AR~|%!0qY!S{pfO zovNw!*ud3??WZRk2!-A|oZ1#7z1Ey}KG1T>g!kakINH~z_66;!&WMM8flcA@qzK>e z4YEFwQBClP(LG$fr)omNe3GXI!h9oD-N9ao+uweTuuhe~P%jh4F!b_!&LMzR;G5J> zuKx^e+wp33o7|Yf^D@(JH0yXSK_y@6Rn+G-!kDNb1M=!IZ^(vW1NFj29=0Y?3uGoT zNl**rPLrZfL2<#ad)>iIwomBjmvc7U(zP=;M6P(6h4R>iS=&L?*Kng~v{B zva~L4>n>nN2p$^NidD4rt5Uy|30$?4*?3;ayOqW`H=?`1joEX;7Si^x#DDtHI3@Lv za?*oXc{P=)&ImG$v*Q}AqR&uqR&I)^Bqxw4nZFL|<;DKEik_CI0-w4}?=6~SVhi6(c- z@=55~P#jZXo;hpjQKG|fUFc$*fqPzw4`!HN+#e;HI7Y=hgD<@^afy2WokeKp2nB|- zR=l-Fys&Hxp*00t$dP8NijRhZHR5=Rm@0xHr*n3 z^+VqX`}?R?jVK@>Zzw=OXl|Pf<@C*gs@317!cuk5N6OQ2eCI8&_Yq?M3Z4orH2# z7uc!?8iZ*P$(#5p(~c!*WCVVSd!Je#^=-hHI=DfU#loV6Yhd!3 zEWAwTZao}cIWE4&9z6?WzIO1WN;DF@40`S>xIGM>iiWJbtlE>nh(K1>1J*RF1FQid zVK?7QJ1HJsInxH>+FVCMmC}>*7p1w1S>eY?9o@#yMwd9pW;c)=8ylOgDOL}i-DVrW zh=}$?l}y7ZsR|1p;HDKbg#fQHyj*G-UYfLZsBhw1Kl%tEL(jB5*+9Os+!3RiV9gSv zJywIN`_YGSeaE3!hgIo8WW)!2Fi>w0h$VLT0a=cM%pLxf!#$S(Zk+OS|2lD#ijh4$ z7{5p!Cai*v(6L7-+a==5-1wMEu<-TmqVPqMk$JO((Wrh^l9G&W!;)d9AxT)zI_b69 zp6BNk3dvPa;GCXbx-Rwjw8@R-Mne<}4HCK3&tl#a4`IE}C=x1o1jB6bn!mjkeE_Fm za)NZ8E}Ij-G}B!jJyG|)ixr`ElY2#KNmeAb;(!*Fs3sxw>4qC>%bXTsRLY9f5fh+?*IW~TB!j{W(3VT${hEZLE@_m`0u zjkA$m*ZxfpTK>sU3@9kR!)N8v|7QaJEFm8 z-z)fN>fW>V-acq_BosrKGvzt}AyxHmTZD!*q13nSU*z;NPX|+P2^brozuUICe&D%7 z8@wb6S{Aivby|OFLl19$*=3+li z{nBpph1A(R#39Fl^dnM5dAuj|yo>myd0Op0S7$5d8P8B_&V=e#iNUhn*>v?G{=SFs zj6Ui;_n(y!wI~v{KJIPe3aVxcltT){%&pce%#>H#Z(si=!t0p)m;G}aLryH%_ zfHW(bremz!Xs($ui}yAfq@7SKSHB9UFPD(YF?M@Gznp*-Wb770&lej{F?@`r=|x9R zXsNJ6$>tv96^b{XeG&;BjBteuo#QIAAIg@BG)f=6`|;E3(N(%}v&Zd$$n%+`pUCmO zUP2MBcvq|%uz?_YHGcA{f%3J#K>R!+-9|XQxBD5KL(u9}_tay~W4&;4dA~RC)ZcG` zS*Cqq@}K){9@1R5a@3PnwBz2*H?o`JnZC|iGai1Qbz;L>OHd}QNS@ifWE%;7 zfvXV1{Uq1eHOoggvETFFxUpnz3ySIySM@s7E7zn*5+v&QyR`|h)Eg*G2t`fO;tzs` z;_tpsfGt{&e88N0#C-RJ!>|=WB9|>EF77qdP0|Kou zIJ`6L0PbEcI_--qTS;j~iOd|PiU{z%2lqgqm}Ul?$5U;7ct~)#@&RH3k5XsYcbFiN z|B=BXTIf2vM_@_ezO#0ZxS%QInel>=1rL(Px1(GnyRhXU+YFLJ@HUY}9+xY?g|8ii zMUnKbAsW#3p!Z?n7wB`3-;?d-n7lXA$+37Z{ppc%7YFp3R+lTMcDTvox2rawbaCBH zVN@@@;*EK!g~~dY?IzTOtKZG$L$16e`4qAB?9S(njmyE9{ZWOTyH#%r_KB0G1(=gY zx`%6r?#+@V%V646Q4Jl+?o$Ey+YA;h&*V* zWNNYe@ZqK0R21tzN`xtYv*ChXo#GWQ#k zbT?uJV-8jMnLAoaIi)9^C75PI<*5iNtf}kRJW7&4oT5@MgJ8DGw>V8wWQv*QeJU|^ zKS8{9{+Y4$F=#r*bSGS(6nKPEQAR*XKbzxJPbHi7tn=#?TPjU3{eijyILCZ zkRQ4stK5&>M1k=`v8y+pl|U+NDtFDpt<#1PYM3AvT^G(Rk5MpV4qw~XOggwXA^ zj_G6DAZq*2G*3E|kV6nc1htn_7`Qg~QMXse8)BZ*R}fEF-3z_s4rKi#)ye%2+m8X8 z=5XZ^{fxmzh3exRUKLrKNvx_)+k7rgJ|oo6vr;}Gx;^l6RB}a0Q%UeKJQJLk!+{ZH zLw+Q)Lz0SX-+oKgh`z_0>Z|nMe8rx13pe!HOG=pimD(1?EfPQ!rs~R5Pw; z5UtX(wTy zmzt+|o1ZqB8(%(sMSs@phU$LallMxo;7;3z#aF0(0UR$SFrp+d!0oBSv7M_zmPWV5FR}QaYpo^hpHe4 zQ9*np1zLjF9^VVm{#vBM8SrVS%mo-_+008c`3Jt{N(9eIC9>Sf z`^iSa#~6FW-xz~*xsh{&)M2*QfhJ;0yb2_{d=u@;T}0LzPgd~&_0kmK(ITiNw9f%V zg(k?p3P=-TyESCR;+jvIG~C>I%#guL9Jglt!ndH$J$!e0GZ)~M&q<$oMD;?yIdfcyv=WS`iF5UipL#2Lb#Fi;D*w;xkhvg{5e^=v28Iw!316aM#9 z@@ZhtC;6SA?9&3Zp7r*>cSN&4iptB<$i2gBHrdY6bqb}@f3F48Werm(a3)nWW6XPi z^>v4D!LVYOsm`(nMwXlf9Pv>ff{Ggil2RxKyFFRwCG@2YiCfsmJC`}lm90W;plT{#&zD^_9bxD6JEB8Z{VD9;LH2oL$151 zA0?v-?UIW0T6qVA)PsZXt>Pt-_aKMBo&}3{A-|0wW$$EZO$dYUoAEHj;$x>%#^V|L zkYT6K&l-;<9fyh<(`m=gM+C`oc~vv_aeS031qowvy~p4JLG22H&YNw>C~P?HPD-&x z2CdNR53F@hVxyCYpe31bDF%XNVzJX;C=(-hGomvmy3V$QLz^?gVk?dWNsax(vGEje z*mO+0r}fqXL}S1Hjs^TKEHdYsh3e4N10Sx2a{ceDA2?B@k_SH|40oA zOL8W~NlPkKQAzdZn++J!DCa8{MGHB^X=&t27hp>AmMXtHcs`WtBzf0L(Kt%8A^9>^ zAC8*bF-5JTL_-o!WyWfnQQmfL}oFYd%hJn=)6CLFKkYx>btI-Z;XC)iN` z*o_qr`VTXa4~rnTI0xkMsKm^29~+UomS@`=u@0+hm_D!!m&C87vOth2&~Ce@euP=- z*}OicUy0y?4QW+Kx8V386>e_n<2G1T4{mmtgc6Q1-wo ziBKG#%o(HXK~|O$&xlP|OjCQAD_$aYFPy?BV1|UE6^EkIGNI76>UW#R+^vJ}wuY`` zd@`rXzmJ5nh^X)4JGVsaj2yfKt$+SxPMi1)B$x+BY@c7Td!Mti-bsIiDdZsqMLap) z3*Ak695mY6EvkO@USc;0vNot_F@a+oaU$q`8=rMjVmB}{IluKBVmG|Scc_+Ky%mVz zCRs{tU>ZA(IQn@Az~hE?YX!Jg3Ffdcyk!94K#%ixt;0{f6C9;n?q zP?f4tEn877vym;cYgI1XMf<}I%-x#^A@PR6E%5q$;Fa*iXGFm*$og#{mB{@2LMR_$ zy1fwfGkoTtiO;BmKT|}^_2&i;w=s9qM8C4}2CWuC&f#VhsKpu}oH$Uz0X2X)`2TQh#sy6re+bFy;XmwgB=+Q%b! zByT5u_j!8y<>l1}2-~Oh$e003Pf5Kat0i(w@`c-sKD|MH*?om5Q7(jb#^RBvYI?d8 z_bG9rukG!b6BQim{R*n_RGONzata@Qg4Ows96?q)0yq!y^9{oH*`z4?w3VgH0n`}m z!%w2pC3-^(s+q1BsP~_$9nQVlC3_}u%2SzTT>=e9>3x^Mc{=M=)eIPV9+}V#oZOdH zj*PqltGMK-_;DhJDl$rneznz#edK&H3bn!UbX+awc>GTI>Rb!Ok8|#kh!3U`DC#5( z1~|mZ>;we#klwn^h&`lhzv%DMN43aN>s3TesMJ3y#?tOcJ|Udxy$Bp;Cmc~p7Rh`6 z!^SBZXS{oh5<%=_C=2YnG@cibc7~Ym@)D}C{Pn(yP zGn9IImb-m%c$<{M6@xGH@g%`xlxOk$OZ*AF$-5)(B|dRs_zNROGwEvmqqGzBr6cj# z5yGRfx9?u7eQLho=@)nOl2UZE7QVkq{)Bq#)mZx2C(}ZUtxryiqlhkKBO?U&%;|YM0#Kr%Vf#rpfG=reqOq>>TE4st;N#%{mybSRtK34Yh`Q zN%}_939nx}3Sx4l4=paFK(IRGOz5nPTtc#Ps#ilip807>V zw1Pi{U@U-!x9MDl=W+du}Iz}b0d2y?urG3i$Oo>TT&KPVM&90BpU>)2s zo0DMjJM9d#Svol-de&(fG-go=vVl)0clXv;~V;QNAbk{lU*(I*lGlemw{?h_zVb~#DXkVg&#lbf&MRa(cp z4xvADq9`r6uh-L`$Qo{@m;`T`=&aABv|6~xEQ5ijjvLMy@Fv93De&AEl4%A9$w@!J zp_%`*zDFp^w5Oe{7fdrw+CfWLVGE9(l2hNVH6}6VPP^EtjNkoWN_4BJ^|HV;?Ml}d z46!gxlP>HlRy9jfSu7cb;mK114oRQ7AiCGp-&A(xrukRLq;1cq%P&w-S=cHVhbMZK zNo>I`g-i9|8F+NrfhwFHvK58t-?JvDmS>65CVuJM>6*f5~8i2y{6C4=e2>#M{q)5%|h>1Mbd!GL_z8=CT!TmT=@;?WfraEplDk z*04cmT5if7jnR9YobGSzm?G8c4TheZqabLRPi$?2JPv13t!!*Ja(c2c?rw|39Zk~O zXb@RWv;!gb+Vuq&P5AjKQxs87Q(+DX=usO)H)Hr41ibDV3+cxAvL`h{OG{%&N-q<+ zC*Faci8Lzmw%-YJE<+}_!&t%pti9TDCZ^&-Ma^Rzzu}M=|5Rp-wCS;9WQe~|^LQ@p zwq$Sxmk7n;f~V1}SH~yrBMv$;+pvuj@~(Q=z&7evX<_g<#um*mSRpfW<^c&@nQbQ? z`V#&ZHfs(@`F*2-gw$syO@xV2+F+MU6iWiMkH9Mrw(_^I%+XwTcF>@istnrH-g(Bn z&2pAdIu+?m8x9`z>+p(+fP?B45ehLB8bGT?U$uUbXNa&hxs19SK~}jBh8q@2+)|4X_ab?Rwh_U5McbkzTZc*XLHl7qqA$9dM6< zy_gsGrU# z8^D?Jq-s1*x!$SMJHGRX(aFS43Vl=&wFL7hEj&uN>Y>PF+>t9xgx$_uMBhB=$L3S! zT+$|^vp~9c++qG1I@#HFr+A+`q{@YIM;?UaN_gk8KZ?s5k;N6#a$P1{`O=?TziqYd zMObNyv4m2@O^rocbRu8;Zt!4lKgob=6D4)b-NG{GUV@#8)zf+~!K_r>pONFdx3H@>*Sk%~~nO$1{R42`5GRd;W>Tj?u*g z_m?6PRP!%3^a@}ShMXwMH{C1EOekqcretzBRmHVkV<**sJDV|o1 zuTxmZ_Yx1^hY(ww(hfed&8CEdk`wQK(_a%l@Tz9bI*0X@K5%B6|03q%Q)B0fi2e9J zSsXz*g5E7dbG9>~SyJ9vy?WrkX9yIpdwY)@fxPK1W2pxPVhAWzNxP39&{gEtY9b)aeG% zwK#VAWHg5c>;d2ZBKKUZsf@-ph>|-slHqvvQdx4l{yjuj1L)OUmNjNa={oJ(t-XuP zKA%?JOk;Ld`CPD`*8a^fd&A`DfQ{)$F;Dk=y2xy(ycnmg-vJaC;n-u5ZPcz5yz zm|(IcyNz2cn@t^cQD_f7Gt?pu*I+KN)_~aPmG;t_YkE;*6EBQ_YNVHT4AKcSc}`u2 z(%ODwrkwK%`Fy)XbZ^3v^r0ezsFc?$%Xb#rmguPZzjDyp4{_Uy=*Ss>-n} zpe^VnSZBY(g0)K@e9JKg7tUqiz)SIEsN_KB-i5jsQbaEK4EiBV*dl7C-KWm`a&-5N zGea@??z=@+im zndlsn0q1?xFI|oMM_wxX6`09nDkg`z)O`pMqc2kkql6;LhxIjJd4ej)-II2ihKp}y zZ^;t1DW9}p`W6NQ9HUQ*KvIYax<%ivA^eT~P<&fo$V=${oMkhCqUnV93SOD(I1f!( z_~DV^OrcpAsCl_hO`yBc?~7lZK!mF5JM@wLyD!e zQiIIumvyvK1ruhLme4w38@i;P!`^#r{FsiZSYzP#Uai&m zLXoe7!N>chO1;N11KqYXukG*#UkS)H7xlx&qlSxDd*t4aFnp2IknH)IWhH%joUf;h(bTEofoe#Bs~&n&JRe>jO1P&OobPR%Kn#r1R^>b2DB zR!fIiE}x%uo#Z+Cc7g0;$JZoHPUHIpwtOPVV^3KUR8N&0=hTOKdb+FodmZ{l9Y7iQ zV_u}@+d&e%dYs$~zip^PB>+X2&DNJUMV~gzE!=W4KCx}cz4qY=9+h6#=X}2=IzsCS zNb6nr$a635bq#(UsJ;TQV>o^t$UY~Z=0KVY7L6eb!pMaA$b`EQFnw`s>n~k(3W>dw z85ARJI_sei$uEz2;V=@ci49)Y;1{fpFgj2YKEWCoaHtBeK;Ght z*98@D7JbOPPq&dl&!Tnv6nbbplUDS>2p+ZG<*cVihLHNW6MaS_#Km&zERk+nr89qCFEaWi*F>#zujs?<4C&5Km8>@>eP44j)u9WEO)e63IRH zWX@#8n8fBpTgcVC$96`DrzrGrmB1?kQ;HF&tArNr9w&s&lv;J>2QUH0cRX0iQ+GZ_ zO!o2P2}15rK~kb#7OeiD;`(%PWd>;y?yUokYYSp^x^=?60%Aw?vQn6j^l{G2@bjj3 z2r?=nxb`b*u}B4TmGo9#g1Nq}UkL`?-+g7X3To(SXqz8-NeDZp%msRhv{dA*onKYZ z-2Ti|lQA5bTYM2}o52#Z@71nYMCozl1HvfHB?EA+;CcNa{Jtc1{^dcfs}}|h*h%v7 z8tHIsw6TrD{FyH@-rle4P`-ceI+A6tbZ}P#oLSnCG(*x?J+s{q@+oK|pF>6hfm)Si z5kh0hjJ8VKM%4nN7r$z;%|pFv(Bxxix-U6`l)MoW$SI*7)aBeh_q?piOG+qFlM}uw(so0o)b-!xOQZ z@u9iT=J(Tcg!x!ORJ+8$8d|;Fo9on?aL?rFFr%!I8%WYkVN8+*)HSfeXPc2;N{gIP z6-ET%e$jG2vRn_(86QZ3HZqxbBdvihK#N^N;j3~*RgDLEWLY zR2)O@FYa%{YiNu4;i|{f`7|#GGS^BDOv>h?S)tO8Juj5i+zo#F9xmPVvt-=DVBROz z)EUTA3(O_&m}n#E8@iy?Slj(Vd&ALox-%w(en*^HP>E zuCWrGWhxfby>)>@ma(I)RqI-%DkWKkJ;f$x-0j&n7&t;*Tg)Uy>2N6xYBzmwtnwEL_U^ykj$#q*BI$iJ? z|GRuNs>G>0j;3xUO>o2vC`9%#*ac3Su^FW-X9}5VwlRXzfK3Y+$ps4YsRh#~bxCX% zCQ3nd0nVmd^7VCbXXcCBXr)ieCOREU>%v;|)1=tVwH>*74rihr%V&h1xbi(eh}oUL z3ty}n>n@vVvOTKE19=M3LOQJ!oHI{9U5%S{#CXbpG3jf#)uy20T5%;9i$%imRU_&(*O(FmP^oL1r)h#fA5e2BX?DD-jR! zeRRs8p`bbBiEt3=Vv!FS(QQiaAgxnvnD&~6I`a*WMF?pibAXB9?xwip)eRc12!}Z3&^@70%QM!_uvV!rW5l9E2O+n(o(vbR?Jp&sx7<+}@etLgkIz3na zfI2ykN9LqPmjnKxPOdHeic)S}r~*sA?Zf#OI^Ff+0`*V3ol>#u?`-7BY~Vciic}?7 zdx%#Hxma8cRlE|9K;{*oej!S}TWruQn)8H3wg&Isj!y?kC6JLxUVvmU?TZNKi7iO2 ztQx(0N8{>>$ojcTg@-YuKL#8{Pq1T}EN!1?%+YprcbYfVk6lrF}8$d$^5pkscbjWy-iB~fR+HJ1_hXMw32MU)n)%UFv3e~z5LFdOOHR%VT zhCwn_O3}^Y4f(jC>mWgQa%b_LbQnBNCm|drroWgxnmXa<%%IqYL|SHj;^L41kr)(u zP!94=U_ot&=%f4x*0*&=i^TxvW>tjUO0Nqsp(JTgp=cv#9-f|Dbl#~A_84hjSG?})7KQR`^!G3M)gfc02*vC|1RtQ*eher?R=2-sbxft^(KNu8$kKT#WR~?A z=>^8i(W=v3_+%`n{il)(8{3G=nHjPo zm$=H=?BmicNt=6n1emkTu@$=$;3CDCE?b$Yn4M`M16PXFuPzE#c_}}8vfWu3RoV@L zp!Gb3^5bq#FygTKOc2!XW(B?b(6C!Hp*Z}ta?%W29%Eo@nNMq(d0=bvlZWc=aboKt zuOG{igDrQll#TfeUSz{O9h*&f?itW329xI{Ad)3l?!SY1iEy;LWwC(ds;2xgD9B5Z z>1hSpB{2_D3q|HE(Y6zETJB+9!zHgqp)SAFdw8>kD>IEEUFlLBF0n5qq~g}q4fFXg z1f;M^-V~%bHAl38ji=^Dqkz|G4C%gvJM!kLEIrqFT6np{kIEKH-NsljeOM& z*kEQ#)>{>uls-O)V`R1-+D{BuJ>dB5G>UG;*!C8FaW#t9=KysSStk`UMzSRG6Bx4S z0QGoH>=SEVj#JAl$^$Ajk|uQC4TcY~hk}M;k5td)i>`Q*^Sm<#PCfKAKP%^uKF?{B zXj`_s7}vi)mW_i_su?wJR^^1R!RcQg+SXtHB#lHPR9bc2rFtdiZF?wP&@#4x3e>qD z{fMK*CzX7bI}RE-h&^?pM?$RwA4zH4_MWiNBV#`%i&KQqPy|Jn(3Ia?$7B}A8kC|C zQUU8^Aw->M#CNMj4kR;{tuD_A+}ao%e7*`_bVl>c*>t-ev?y88B23dPx-k<^M>Q%x zi#77jPTP~f^dN;c{AbVqKGSomdZ(b7>SnhI z&F&sf&|i8e%HyxwD0tRoURnwrDh2Y!l|@FW8$PL?3NWB$EgmdpqgmxL(s4yi%hjO% ztWL`pEBle5Rdc6YQA9 zaCa++rh6mk!{b3zy(Yi>IG11`?%p4B#%pNe1qR7R^y*6^T-(SxV;_^{{A! z9~!R-2jy67P#R{FXz(dr+Qii+QfOj}UmeT4gh-)-$HpIzUP!nxFK5?d1`WpLoP>o9 zym}4lMI%%%8n9-2X_f3HazDkpWAue)e@YV91Mg2~MQK$pZO+XlmNuHS~ z_%O3<&_=4j$y18wo##b8oI#MKo6GNP$m@$S>nBk-N@xplIjCpCP1wFfWVpnEeBo6B zJ1|45a5nK$NRLdoy7T=ZB)&W|HytEZQ9iK!8UuI;3A}6#A|s+KKrbOH$|xZ#ETYCB zEuo|w9>s*zc@IJ4Jk<|AvV8z?1!UiPFP?i^2%pv@|$>8aR%tY2ZXM01@>+2C99#8I2`@dsCzUk{F^7n@`U_k zzOUIbG2%Sq;?!n#h_Y=I93Pdx@QRRX-@W^|77!(Lq4g1KIQ>x7=PUN^=qy#?cZ;e5s;M-6;V=VkP-b(0l4D_@Ndu{ zAlKj*09^wcE1+$|H_ZRM1NAS=>pSp)b`IBf{L#k2!N$qn!06W7ac|r%`Lo;gubaHu z*xyR#?hP`&w~=vhvbD9bcf6I{^+{TPT-QRi{|Y%hhuigZJsRIhf&+^F4?TSo^c#l; zmO$G^TcGj9t-M|zIq;pZ^e+(xT1wfQ={o^^GaPQEeeWCTujY{WE3~cjtj&y#92{Nj z&46<{Zl%t2gZk#LPzSnwIGX8MegnCc{PkOle_Ypt$O@b|@~;}VwYRYaPDwK}x?L^T z4THW@_WljZZVpcR4vuDyPS*#S+{!)CH;AvQpS%qNAZB?hEkLt>Ue}sH2HxttKBM9` zul^oMuJ2&_^Nv5f`g?Ph+bG<0Y=eKG@B`~GUjvePBh%&tz_1Ch--PNL=fL+|-(-Ny zKMvy8E~nSqPyX0<@}0Rqs17oaz{~0c8I4MX_tj-;d1sk-CFVYkmnpeHZxL)XWGlsr)N-)vuoZbItIyo2>5v zWNiV)uiJTlyK;SB0zE(ek@U9+C;<4Pv7UjWfVG~boBKa$$MLeHgbkRgtN@-#5f>A{xYJBk^Nsy+kS+wHGE`I2#{U{ zJ~wT2;?D0t*ch4_oBgAW4mesh0|1bKBixi@l=wG56pi!@{}JNzN2O~wJ_0^`z~|eQ z>-+ldZ$Ky;0o^C{9F1gdmFL}<1_B`UJ)S(2>%VaaLIoGOUY5s+ECBl@S9+N zS^CfYDT_yWl^dAT#Lz%Mcy6H40%87Nt@}r`+pJuwKQpEWfItP52<##J>&o@*1k#y* zh5BX{;$IE$Rx=FD|NIPyg#^ILK;p0R&#(_1Tl;lpS21%i z17h&c70KHJwqgKG0Wm;ux(PZBxWa!0Dr#nAX?QEBjV=-^69C8z%rfFPBux|iFF|FD z98GO*N6pNBj+_OE`Vv3}VE(#teOUk|eoa&dD`huZqaW4$bJZp)q>GmU(KjC$)0^Ru zRq7Y<{?y{%Hl_X;gV`0#p5+3fYy%&GzeKt=8Vr=`(F`n$&)4d+D7^SSPLNJY21Ll)ch@2Nj>|o$Ie_Ykgqd- zvLF9&yTVhIp7_=PeB1~4xM^*iy8ja&Ki4*sdy#Yp0QUmWw&)G9W%U0ixLZ^`N!&#z z1z=_XR(^AY?Tvm5^V=Nrmwn&rSRy%6_SHbJpoRef@w_1_ndz^<{w?KZ6aZGr_P{Kl zW@QQFiN7HA#{)J+V4V~K#)*{**cdj6x=MJ8?6T+dS#z}%~K zgH?OW|G!xMxqbAYfEnil<5UFX9jZ4t@o@YfI1#onaI!M8cKo$4&o7bNnhU7o9GJFc zZZHw=_Pb07S~?kB_i??3{)P3MkhRWv3t%*BfYF5AfX?&%ZRqP_q0wK)`Xd9^fkMLC z*2xigO~Od;Z$bMX{(gHLp=?Q&@By3*42UBZHyDQx{C~vw&n@Z$+8`wuU{O|pMs05} zh7t1rh_PE@(;Zovhw*@^i2$Cbbc4Ix@c(1(ey*NN=ng7mKs6jdnG1-(e_gr0#c{vO zfQYMsrIVqNp@h|SRawB=P{j56hu>P@gfoD#v_Cuh(yS zwzfbkHpUvlO9Rt1I*=HO{bd)|c_?AsZ{s`I z{uq9KZjJ{-`wyFeFoFsUz@rCq3!-%xFCT8;XHpajb;YV(6cLH2?QG8io1VDjx<;~1w zZ|ZlMQ2N?WUBK4X(#+uN>FIywM86gmW<7i~1%R2^5*U@6?pVF>+nhK8_y*Uucl}WC z*YI;8hn6k@&-e&v<7QG~`1*J8m2GS+fn?Uo_S<0GJ_vG6bvao8EH%Q9qW7=qr?svZcVs-Ob-}i;@Hx=LZXh67Ky4(vC1Ox`KFVh>?$EUxK{pSMkCNP<-jkS=a zjRPGHJ&}yv#qYW^?{vS>r2>xF% z@U7qAATNdgUp#S4(wBC)X_Rj~}u8+Tu8o<*BM84^B zvC#ho=5;AnPv6q$hlKOz*wH8SBBMY+V<7@z?N%W$J~D0VzX(Nlp9)9v{{3;Q>U&o>drvG)+n>$h@41t0XutZR{ z*Rysowy_6#?)==Cvy|;~-vLVQ16B$8e?ebo4hD?>Ex5cTP_r|&u>_uQew#jk_4Kz4 z{`Pb&39r+?``V)cW!%hECt3bmeiV&>2cZT=*EO_%)yE)j>Siclc)Ng3ByZ>gn*G1U zS8}rYSKRfgE;S`UW_F;Sax-nX05*&Ks)OA$0%aQuBWtp+U!}~f4S#L`^paH{+yRB3 z140Yj5V)4-e**qFT(P(DN+SS+3_#wD*b#jHHQc`$x%m+u&oMBd?0}KqRBkE%e+#N| zU6Qb|2C78Blj48!t^*HIspo*CaKOj{Pe%T_a(!V$|1W^AIS>WBTh9?FUm4k6Z$|sM z+S@rna$SL~w)=EHx)rVX{}m%Z_5eKN{W-p^q-2Z;VA@1LsqkiL99`@G3jbey>~(#C z!USLjNPrpKT#5}F+``1yy={VD>(SrB*)2~%pM6xFIR%DX9~g4xzXtp|pq`rk8_3sk z_w`ecTj)GLLp3_4>YL^qM}0#lO-2+E4u!+V(H76gdID3xSd1yuo`8u<`33 zgV0w6DVYJ=P5vs7e63DcJO0CFAWo^i%zFUNG9U-r4IEa-U&Hys)__{rKkf$NK90A~ z12E=*l84|8j0P9bf9`@IU=5Uf9Zmo2JWuw=ufPUaYatseTfJK63tAMFAVA z=x^Y)di*lp&z(ozT`GSJ5Tg&_$8CwPg8rTK9|_Q(0{tA|$L7P|*w6L-9B~`K-&zs> zSdsX#LEv|iB?-5X{GqklKer3~5%0(5ZQt>Hl7AiV=j!>fh01r@Dmk~%{`zG5WGVI+{qdBy?{tltZlU`(%m2A1emuSGJKc@uTj>5_g8vYB oe)dAhce=Z?px@t{`2Ko`yc8th5Ws>T_|J_AScJ|2As6KT13sfRkpKVy diff --git a/bundlor/dist/com.springsource.bundlor.ant-1.0.0.RELEASE.jar b/bundlor/dist/com.springsource.bundlor.ant-1.0.0.RELEASE.jar deleted file mode 100644 index f56eb8e38ca54ab37243721d54c274522dfe7dd9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17007 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 diff --git a/bundlor/dist/com.springsource.bundlor.blint-1.0.0.RELEASE.jar b/bundlor/dist/com.springsource.bundlor.blint-1.0.0.RELEASE.jar deleted file mode 100644 index 39232af1c046a0d09dc2982076d7d4efef051e4d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13577 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�xF6E9vT~ zTD-H^S6R~gNkH-CiBMlA{GAszkv#W`M7SSvy;(lv@g)5bpF?y&@29Sb67M@3D;;xR zro>}4kF8hC!BLv)LnSXtiM44H%`9gNpUw4Kp5~hN>-oNRx^G6>+PCH5S)!rs1stFJ z&5WeryeVZSXV_e4fPcvC(9O-F_#O@WUHPO@U(y`66ux+hPxW&%CY-ZA#;T_V30EJR z<4B2mxjJoaH0nOW*Ym;~V>o>k*`Axt&M=G6^IH&ZaD2P`j!_VCS!&SGL+xje8;Q;I zP|9vy;SK!Dp5i=WCxX2d-oz*~Gnmbxd^s3OBZ^73#mgF^GK)+XpoG3D=S74!+T#%NFXr49XE!In|6by1E(q;Q6u& z^Qj!yC$TG?_exx;x{FLDu0a>i@Ko3(3TZkz-0Tom_N<;x*WN1 zsDklUAD&p?oc1ZaN<{1Tvn4%klI_AJk@3uZ<%+kw*cKbVXk?B)1HJyrl5o%7m%M0w zXQdMeR@{a{9;Drv_~E0JqRQ?0`6ki;wPBJ}mL9OG;lY^-cWG8AK4&6XKrgM*Kil6C z15M0lf$31jCXMO~5y0^s7d}&#`Fbv=@LEO5D92Bq0yW&AI_^NS@y7E(fpk)?TlTF2 zAyfcMb((EguHV|-^tIzd?IY-+ zc+SkJlmucT4H-7Ao~mdk-jl^}Xr#5II#BDdEQtV7USy-!xEv#rm6q|LUMS(mn?|d+ z#NOH=i;-2BdP1>%F>=y{t+oMga@SHqV%Dk1rWjiJ!~L$yieFV(FOuqq`*zjlnrsc; z08OX8M^3vvx2?zXoeIL_^7aWL+$WRCBwG};g_&OYoU36Vy7v70!RFz~?Jx2zx>yq4 z^AlxDe{wWECNn)SHJN@@uSdkzr~HMCns;m}B$u50^;b6HCd!c@0!81K(&S*`4~4lN z$;d3m1VSp5+!qM}Wj?uwo{~%3;mu%f)RI$WukEeJ4Gm>?+L4oDn*F-FBWW#PNEn`e ztn%D_u{A{x)}ISv>UMIktZA-=%#RID4p*atO++GM)f}KUg`7TW0*bCY{QrpH9GvVO z5Kb;u2xm<XjU=c{PYi>zKxBYdgMR7&W++8Vt@0KmI%%d=k$ zz~^$)1$`fw2qBd)&O3nlJm7WkKJq9r5Y%B>0LJeCQsqquf&gPk;PeW*$L@;_fQN4L zy%zkZA<*}6$<_&BZ04bfutk`+CVM9OfZx8P111jf_qSxB*vOb%h-miBeR%{-aQ_qXuiP5Y<_?%# zoY;mi>$r38TLG@PfVcm}(C;55W-0H3J^Pd7p}0ragvWLrv&1pFCiuSa$o$E~ZxfH$ z1~4m=p$|Omi<{h`27V#`zELm>-yCdg7Wf|k50p2yx`@1jePDcP9wi6f|9&;i2U{|2NbvQisZYpe4%%uN8)U!T^ zqW;g4G&U+`!Wq3_urKXFhob&*`2gDrW^xi3MKI)9$l+H0O=Y9u4vW#y8O?ne3&R-m z|H*G2u8hub?h8fu|0wT``Fr`!!-3El&wWuk8VDN{Gn~PUtPc*q_x?NRUOp82DPV@Z l2gd_={E>H#=`b35KT?OQ5CZE^I5=#;pA-;(l0QJd`#+*$@ZkUe diff --git a/bundlor/lib/com.springsource.org.objectweb.asm-3.1.0.jar b/bundlor/lib/com.springsource.org.objectweb.asm-3.1.0.jar deleted file mode 100644 index da07fa03764f3729efd412e0f6aa80fdb2f372d7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 43557 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

jxaj&?l6xFD6u#qf>LNroaV}Q5lXxo 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 diff --git a/bundlor/lib/com.springsource.org.objectweb.asm.commons-3.1.0.jar b/bundlor/lib/com.springsource.org.objectweb.asm.commons-3.1.0.jar deleted file mode 100644 index 14d55b708302f2aac366ad46e6fc03049ca776b6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33255 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

ln_){k#*LVDz&pLX|5>-QFLV~p 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

ono4UDN>rwu3OU25`CWowlP0%s#lIB$xI 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 EKhOFjz5oCK diff --git a/bundlor/lib/com.springsource.org.objectweb.asm.tree-3.1.0.jar b/bundlor/lib/com.springsource.org.objectweb.asm.tree-3.1.0.jar deleted file mode 100644 index 7b5440b94339b36f18dc613222ec48a8dc9fdd39..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22502 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 diff --git a/bundlor/lib/com.springsource.util.common-2.0.0.RELEASE.jar b/bundlor/lib/com.springsource.util.common-2.0.0.RELEASE.jar deleted file mode 100644 index 22d4559778fdf6a8d49b1445e96f458d489a791a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 42376 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 MfWN`)5)QxnKTqRJEdT%j diff --git a/bundlor/lib/com.springsource.util.math-2.0.0.RELEASE.jar b/bundlor/lib/com.springsource.util.math-2.0.0.RELEASE.jar deleted file mode 100644 index 16ca6996162fe534f37c45d4d570bee7dc860db4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8384 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 diff --git a/bundlor/lib/com.springsource.util.osgi-2.0.0.RELEASE.jar b/bundlor/lib/com.springsource.util.osgi-2.0.0.RELEASE.jar deleted file mode 100644 index b63f391ab0191a04832fada32cae965bd38bbc43..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 94153 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%0AJ2MwqWdW~h^WJpeqRp&!6(0OrHIcZ{$ArID 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 diff --git a/bundlor/lib/com.springsource.util.parser.manifest-2.0.0.RELEASE.jar b/bundlor/lib/com.springsource.util.parser.manifest-2.0.0.RELEASE.jar deleted file mode 100644 index 0119f91e7096fb0c6c9d12b10e06cdd1f660cdfe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24242 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 diff --git a/bundlor/lib/org.osgi.core-4.1.0.jar b/bundlor/lib/org.osgi.core-4.1.0.jar deleted file mode 100644 index 2d652ac647c1a97f1ea35183a1674c4075c26ffd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 163485 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'`Pm@Z}( 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 H(2Mk!w8|VU`{4^-ZN-N>w0YU#U*K1- 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 edFKBT8{e^?v~S{1Y(% diff --git a/lib/commons-io-1.2.jar b/lib/commons-io-1.2.jar deleted file mode 100644 index b2867cdde4284228f2adc51e8a0358972bccaaf1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 65621 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 diff --git a/lib/hamcrest-core.jar b/lib/hamcrest-core.jar deleted file mode 100644 index 9d5fe16e3dd37ebe79a36f61f5d0e1a69a653a8a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 45024 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 UgpPtD2z>DYYp}SJr5?)v0beu;=l}o! diff --git a/lib/junit.jar b/lib/junit.jar deleted file mode 100644 index 3a7fc266c3e32283a2b21fe12166ebdcc33a1da1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 314932 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

&R7;REBZd0NaNVcN6Eoy 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

?@Ib4$R$ZbA6MIsF(ZEk4Ii=sfRBa)&Yo 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�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 TY(h;@!?}i$7z!3V8^-w`q)kqw From c2cd9f3fc342077b963bc2a0a9b5f5948e1ec1db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Wed, 27 Jul 2016 15:08:48 +0200 Subject: [PATCH 0187/2114] pom.xml: Unify indentation [#127354185] --- pom.xml | 510 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 255 insertions(+), 255 deletions(-) diff --git a/pom.xml b/pom.xml index c2080cce1b..b14d5c3fc4 100644 --- a/pom.xml +++ b/pom.xml @@ -1,34 +1,34 @@ - 4.0.0 + xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + 4.0.0 - com.rabbitmq - amqp-client - 3.7.0-SNAPSHOT - jar + com.rabbitmq + amqp-client + 3.7.0-SNAPSHOT + jar - RabbitMQ Java Client - RabbitMQ Java client - http://www.rabbitmq.com + RabbitMQ Java Client + RabbitMQ Java client + http://www.rabbitmq.com - - - ASL 2.0 - http://www.apache.org/licenses/LICENSE-2.0.html - repo - - - GPL v2 - http://www.gnu.org/licenses/gpl-2.0.txt - repo - - - MPL 1.1 - http://www.mozilla.org/MPL/MPL-1.1.txt - repo - - + + + ASL 2.0 + http://www.apache.org/licenses/LICENSE-2.0.html + repo + + + GPL v2 + http://www.gnu.org/licenses/gpl-2.0.txt + repo + + + MPL 1.1 + http://www.mozilla.org/MPL/MPL-1.1.txt + repo + + @@ -40,237 +40,237 @@ - https://github.com/rabbitmq/rabbitmq-java-client.git - scm:git:https://github.com/rabbitmq/rabbitmq-java-client.git - + https://github.com/rabbitmq/rabbitmq-java-client.git + scm:git:https://github.com/rabbitmq/rabbitmq-java-client.git + - - UTF-8 - + + UTF-8 + - - - commons-cli - commons-cli - 1.1 - test - - - commons-io - commons-io - 1.2 - test - - - junit - junit - 4.12 - test - - + + + commons-cli + commons-cli + 1.1 + test + + + commons-io + commons-io + 1.2 + test + + + junit + junit + 4.12 + test + + - - - - - maven-clean-plugin - 3.0.0 - - - - ${basedir}/build - - **/* - - false - - - - - - maven-antrun-plugin - 1.7 - - - generate-sources - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - run - - - - - - org.codehaus.mojo - build-helper-maven-plugin - 1.10 - - - add-source - generate-sources - - add-source - - - - build/gensrc - - - - - - - maven-compiler-plugin - 3.2 - - 1.6 - 1.6 - - -Xlint:deprecation - -Xlint:unchecked - - - - - org.apache.maven.plugins - maven-surefire-plugin - 2.9 - - - ${project.build.directory} - - true - - **/ClientTests.* - **/FunctionalTests.* - **/SSLTests.* - **/ServerTests.* - **/FunctionalTests.* - **/HATests.* - **/TestMain.* - - - - - org.apache.maven.plugins - maven-jar-plugin - 2.6 - - true - - true - true - - true - - - - - - - jar - test-jar - - - - - - org.apache.maven.plugins - maven-source-plugin - 2.4 - - - - jar - test-jar - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - 2.10.3 - - -Xdoclint:none - - - - - jar - test-jar - - - - - - org.codehaus.mojo - versions-maven-plugin - 2.2 - - - + + + + + maven-clean-plugin + 3.0.0 + + + + ${basedir}/build + + **/* + + false + + + + + + maven-antrun-plugin + 1.7 + + + generate-sources + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + run + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 1.10 + + + add-source + generate-sources + + add-source + + + + build/gensrc + + + + + + + maven-compiler-plugin + 3.2 + + 1.6 + 1.6 + + -Xlint:deprecation + -Xlint:unchecked + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.9 + + + ${project.build.directory} + + true + + **/ClientTests.* + **/FunctionalTests.* + **/SSLTests.* + **/ServerTests.* + **/FunctionalTests.* + **/HATests.* + **/TestMain.* + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.6 + + true + + true + true + + true + + + + + + + jar + test-jar + + + + + + org.apache.maven.plugins + maven-source-plugin + 2.4 + + + + jar + test-jar + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.10.3 + + -Xdoclint:none + + + + + jar + test-jar + + + + + + org.codehaus.mojo + versions-maven-plugin + 2.2 + + + - - - sonatype-nexus-staging - Nexus Release Repository - http://oss.sonatype.org/service/local/staging/deploy/maven2/ - - + + + sonatype-nexus-staging + Nexus Release Repository + http://oss.sonatype.org/service/local/staging/deploy/maven2/ + + From bad1cc2d086f57e2c71fe63b303cf55cab385664 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Thu, 4 Aug 2016 16:21:27 +0200 Subject: [PATCH 0188/2114] codegen.py: Do not implicitely add possible locations for rabbitmq-codegen Maven sets `PYTHONPATH` appropriately. [#127354185] --- codegen.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/codegen.py b/codegen.py index b9e1af0c99..7ef06b4141 100755 --- a/codegen.py +++ b/codegen.py @@ -21,9 +21,6 @@ import re import sys -sys.path.append("../rabbitmq_codegen") # in case we're next to an experimental revision -sys.path.append("codegen") # in case we're building from a distribution package - from amqp_codegen import * class BogusDefaultValue(Exception): From 274565c7cd9d75c59d822b504ebe587c5417dc01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Thu, 4 Aug 2016 16:15:18 +0200 Subject: [PATCH 0189/2114] Finish the switch from Ant to Maven Now, Maven is used as the only build tool. All files and archives related to Ant were removed. Because Maven doesn't provide several features Ant provided, all non-basic tasks are now inside Groovy scripts. All tests are considered integration tests, not unit tests now. `mvn verify` takes care of starting and stopping the required RabbitMQ nodes. To run only a single test, use: mvn verify -Dit.test=DeadLetterExchange [#127354185] --- .gitignore | 13 +- Makefile | 93 +-- README.md | 4 +- RUNNING_TESTS.md | 181 +++--- build.xml | 542 ------------------ bundlorTemplate.mf | 7 - bundlorTestTemplate.mf | 11 - nexus-upload.sh | 28 - pom.xml | 519 ++++++++++++----- ...ientVersion.java.in => ClientVersion.java} | 18 +- src/main/resources/version.properties | 1 + src/main/scripts/generate_amqp_sources.groovy | 60 ++ src/main/scripts/manage_test_broker.groovy | 65 +++ .../scripts/query_test_tls_certs_dir.groovy | 25 + .../scripts/remove_old_test_keystores.groovy | 8 + .../client/test/AbstractRMQTestSuite.java | 19 +- .../rabbitmq/client/test/BrokerTestCase.java | 3 +- .../test/functional/ClusteredTestBase.java | 4 +- .../server/DeadLetterExchangeDurable.java | 4 +- .../test/server/DurableBindingLifecycle.java | 8 +- .../rabbitmq/client/test/server/HATests.java | 4 +- .../test/ssl/BadVerifiedConnection.java | 8 +- .../rabbitmq/client/test/ssl/SSLTests.java | 2 +- .../client/test/ssl/VerifiedConnection.java | 8 +- src/test/java/com/rabbitmq/tools/Host.java | 49 +- src/test/resources/build.properties | 24 - src/test/resources/hare@localhost.config | 15 + src/test/resources/rabbit@localhost.config | 15 + 28 files changed, 806 insertions(+), 932 deletions(-) delete mode 100644 build.xml delete mode 100644 bundlorTemplate.mf delete mode 100644 bundlorTestTemplate.mf delete mode 100755 nexus-upload.sh rename src/main/java/com/rabbitmq/client/impl/{ClientVersion.java.in => ClientVersion.java} (63%) create mode 100644 src/main/resources/version.properties create mode 100644 src/main/scripts/generate_amqp_sources.groovy create mode 100644 src/main/scripts/manage_test_broker.groovy create mode 100644 src/main/scripts/query_test_tls_certs_dir.groovy create mode 100644 src/main/scripts/remove_old_test_keystores.groovy delete mode 100644 src/test/resources/build.properties create mode 100644 src/test/resources/hare@localhost.config create mode 100644 src/test/resources/rabbit@localhost.config diff --git a/.gitignore b/.gitignore index 9bfe0ec81b..f52592ac2c 100644 --- a/.gitignore +++ b/.gitignore @@ -8,18 +8,11 @@ *.iml *.ipr *.iws +.DS_Store \#~ -.idea/ -build/ -cover/ -debug/ -dist/ -ebin/ -out/ -tmp/ -junit*.properties +/.idea/ +/deps/ /target/ -/.DS_Store /.classpath /.project /.settings diff --git a/Makefile b/Makefile index 3e3f8d0631..710cc894b4 100644 --- a/Makefile +++ b/Makefile @@ -1,77 +1,36 @@ -VERSION=0.0.0 -PACKAGE_NAME=rabbitmq-java-client -JAVADOC_ARCHIVE=$(PACKAGE_NAME)-javadoc-$(VERSION) -SRC_ARCHIVE=$(PACKAGE_NAME)-$(VERSION) -SIGNING_KEY=056E8E56 -GNUPG_PATH=~ +MVN ?= mvn +MVN_FLAGS ?= -WEB_URL=http://www.rabbitmq.com/ -NEXUS_STAGE_URL=http://oss.sonatype.org/service/local/staging/deploy/maven2 -MAVEN_NEXUS_VERSION=1.7 +ifndef DEPS_DIR +ifneq ($(wildcard ../../UMBRELLA.md),) +DEPS_DIR = .. +else +DEPS_DIR = deps +endif +endif -AMQP_CODEGEN_DIR=$(shell fgrep sibling.codegen.dir src/test/resources/build.properties | sed -e 's:sibling\.codegen\.dir=::') +MVN_FLAGS += -Ddeps.dir="$(abspath $(DEPS_DIR))" -MAVEN_RSYNC_DESTINATION=maven@195.224.125.254:/home/maven/rabbitmq-java-client/ +.PHONY: all deps tests clean distclean -ANT ?= ant -ANT_FLAGS ?= +all: deps + $(MVN) $(MVN_FLAGS) compile -all: - $(ANT) $(ANT_FLAGS) build +deps: $(DEPS_DIR)/rabbit + @: -clean: - $(ANT) $(ANT_FLAGS) clean - -distclean: clean - $(MAKE) -C $(AMQP_CODEGEN_DIR) clean - -dist: distclean srcdist dist_all maven-bundle - -dist_all: dist1.5 javadoc-archive - -jar: - $(ANT) $(ANT_FLAGS) jar +$(DEPS_DIR)/rabbit: + git clone https://github.com/rabbitmq/rabbitmq-server.git $@ + $(MAKE) -C $@ fetch-deps DEPS_DIR="$(abspath $(DEPS_DIR))" -maven-bundle: - $(ANT) $(ANT_FLAGS) -Dimpl.version=$(VERSION) maven-bundle +tests: deps + $(MVN) $(MVN_FLAGS) verify -dist1.5: - $(ANT) $(ANT_FLAGS) -Ddist.out=build/$(PACKAGE_NAME)-bin-$(VERSION) -Dimpl.version=$(VERSION) dist - $(MAKE) post-dist TARBALL_NAME=$(PACKAGE_NAME)-bin-$(VERSION) +deploy: + $(MVN) $(MVN_FLAGS) deploy -javadoc-archive: - $(ANT) $(ANT_FLAGS) javadoc - cp -Rp build/doc/api build/$(JAVADOC_ARCHIVE) - (cd build; tar -zcf $(JAVADOC_ARCHIVE).tar.gz $(JAVADOC_ARCHIVE)) - (cd build; zip -q -r $(JAVADOC_ARCHIVE).zip $(JAVADOC_ARCHIVE)) - (cd build; rm -rf $(JAVADOC_ARCHIVE)) - -post-dist: - @[ -n "$(TARBALL_NAME)" ] || (echo "Please set TARBALL_NAME."; false) - chmod a+x build/$(TARBALL_NAME)/*.sh - cp LICENSE* build/$(TARBALL_NAME) - (cd build; tar -zcf $(TARBALL_NAME).tar.gz $(TARBALL_NAME)) - (cd build; zip -q -r $(TARBALL_NAME).zip $(TARBALL_NAME)) - (cd build; rm -rf $(TARBALL_NAME)) - -srcdist: distclean - mkdir -p build/$(SRC_ARCHIVE) - cp -Rp `ls | grep -v '^\(build\|README.in\)$$'` build/$(SRC_ARCHIVE) - - mkdir -p build/$(SRC_ARCHIVE)/codegen - cp -r $(AMQP_CODEGEN_DIR)/* build/$(SRC_ARCHIVE)/codegen/. +clean: + $(MVN) $(MVN_FLAGS) clean - if [ -f README.in ]; then \ - cp README.in build/$(SRC_ARCHIVE)/README; \ - if [ -f "$(BUILD_DOC)" ]; then \ - cat "$(BUILD_DOC)" \ - >> build/$(SRC_ARCHIVE)/README; \ - else \ - elinks -dump -no-references -no-numbering \ - $(WEB_URL)build-java-client.html \ - >> build/$(SRC_ARCHIVE)/README; \ - fi; \ - fi - (cd build; tar -zcf $(SRC_ARCHIVE).tar.gz $(SRC_ARCHIVE)) - (cd build; zip -q -r $(SRC_ARCHIVE).zip $(SRC_ARCHIVE)) - (cd build; rm -rf $(SRC_ARCHIVE)) +distclean: clean + $(MAKE) -C $(DEPS_DIR)/rabbitmq_codegen clean diff --git a/README.md b/README.md index dc223b6568..82a4e899fc 100644 --- a/README.md +++ b/README.md @@ -14,14 +14,14 @@ Maven artifacts are [released to Maven Central](http://search.maven.org/#search% com.rabbitmq amqp-client - 3.6.2 + 3.6.5 ``` ### Gradle ``` groovy -compile 'com.rabbitmq:amqp-client:3.6.2' +compile 'com.rabbitmq:amqp-client:3.6.5' ``` diff --git a/RUNNING_TESTS.md b/RUNNING_TESTS.md index 2eb0b79567..41600500cb 100644 --- a/RUNNING_TESTS.md +++ b/RUNNING_TESTS.md @@ -1,101 +1,150 @@ ## Overview There are multiple test suites in the RabbitMQ Java client library; -the source for all of the suites can be found in the [test/src](./test/src) +the source for all of the suites can be found in the [src/test/java](src/test/java) directory. The suites are: * Client tests - * Functional tests * Server tests * SSL tests + * Functional tests + * HA tests All of them assume a RabbitMQ node listening on localhost:5672 (the default settings). SSL tests require a broker listening on the default -SSL port. Connection recovery tests assume `rabbitmqctl` at `../rabbitmq-server/scripts/rabbitmqctl` -can control the running node: this is the case when all repositories are cloned using -the [umbrella repository](https://github.com/rabbitmq/rabbitmq-public-umbrella). +SSL port. HA tests expect a second node listening on localhost:5673. -For details on running specific tests, see below. +Connection recovery tests need `rabbitmqctl` to control the running nodes. +can control the running node. +`mvn verify` will start those nodes with the appropriate configuration. -## Running a Specific Test Suite +To easily fullfil all those requirements, you can use `make deps` to +fetch the dependencies. You can also fetch them yourself and use the +same layout: -To run a specific test suite you should execute one of the following in the -top-level directory of the source tree: - - # runs unit tests - ant test-client - # runs integration/functional tests - ant test-functional - # runs TLS tests - ant test-ssl - # run all test suites - ant test-suite - -For example, to run the client tests: +``` +deps +|-- rabbitmq_codegen +`-- rabbit +``` +You then run Maven with the `deps.dir` property set like this: +``` +mvn -Ddeps.dir=/path/to/deps verify ``` ------------------ Example shell session ------------------------------------- -rabbitmq-java-client$ ant test-client -Buildfile: build.xml -test-prepare: +For details on running specific tests, see below. -test-build: -amqp-generate-check: +## Running a Specific Test Suite -amqp-generate: +To run a specific test suite you should execute one of the following in the +top-level directory of the source tree: -build: +* To run the client unit tests: -test-build-param: + ``` +mvn -Ddeps.dir=/path/to/deps verify -Dit.test=ClientTests +``` -test-client: - [junit] Running com.rabbitmq.client.test.ClientTests - [junit] Tests run: 31, Failures: 0, Errors: 0, Time elapsed: 2.388 sec +* To run the functional tests: -BUILD SUCCESSFUL ------------------------------------------------------------------------------ + ``` +mvn -Ddeps.dir=/path/to/deps verify -Dit.test=FunctionalTests ``` -Test failures and errors are logged to `build/TEST-*`. - +* To run a single test: -## SSL Test Setup + ``` +mvn -Ddeps.dir=/path/to/deps verify -Dit.test=DeadLetterExchange +``` -To run the SSL tests, the RabbitMQ server and Java client should be configured -as per the SSL instructions on the RabbitMQ website. The `SSL_CERTS_DIR` -environment variable must point to a certificate folder with the following -minimal structure: +For example, to run the client tests: ``` - $SSL_CERTS_DIR - |-- client - | |-- keycert.p12 - | |-- cert.pem - | \-- key.pem - |-- server - | |-- cert.pem - | \-- key.pem - \-- testca - \-- cacert.pem +rabbitmq-java-client$ mvn -Ddeps.dir=/path/to/deps verify -Dit.test=ClientTests +[INFO] Scanning for projects... +[INFO] Inspecting build with total of 1 modules... +[INFO] Installing Nexus Staging features: +[INFO] ... total of 1 executions of maven-deploy-plugin replaced with nexus-staging-maven-plugin +[INFO] +[INFO] ------------------------------------------------------------------------ +[INFO] Building RabbitMQ Java Client 3.7.0-SNAPSHOT +[INFO] ------------------------------------------------------------------------ +[INFO] +[INFO] --- groovy-maven-plugin:2.0:execute (generate-amqp-sources) @ amqp-client --- +[INFO] +[INFO] --- build-helper-maven-plugin:1.12:add-source (add-generated-sources-dir) @ amqp-client --- +[INFO] Source directory: .../rabbitmq_java_client/target/generated-sources/src/main/java added. +[INFO] +[INFO] --- maven-resources-plugin:2.5:resources (default-resources) @ amqp-client --- +[debug] execute contextualize +[INFO] Using 'UTF-8' encoding to copy filtered resources. +[INFO] Copying 1 resource +[INFO] +[INFO] --- maven-compiler-plugin:3.5.1:compile (default-compile) @ amqp-client --- +[INFO] Nothing to compile - all classes are up to date +[INFO] +[INFO] --- groovy-maven-plugin:2.0:execute (remove-old-test-keystores) @ amqp-client --- +[INFO] +[INFO] --- groovy-maven-plugin:2.0:execute (query-test-tls-certs-dir) @ amqp-client --- +[INFO] +[INFO] --- keytool-maven-plugin:1.5:importCertificate (generate-test-ca-keystore) @ amqp-client --- +[WARNING] Certificate was added to keystore +[INFO] +[INFO] --- keytool-maven-plugin:1.5:importCertificate (generate-test-empty-keystore) @ amqp-client --- +[WARNING] Certificate was added to keystore +[INFO] +[INFO] --- keytool-maven-plugin:1.5:deleteAlias (generate-test-empty-keystore) @ amqp-client --- +[INFO] +[INFO] --- maven-resources-plugin:2.5:testResources (default-testResources) @ amqp-client --- +[debug] execute contextualize +[INFO] Using 'UTF-8' encoding to copy filtered resources. +[INFO] Copying 3 resources +[INFO] +[INFO] --- maven-compiler-plugin:3.5.1:testCompile (default-testCompile) @ amqp-client --- +[INFO] Nothing to compile - all classes are up to date +[INFO] +[INFO] --- maven-surefire-plugin:2.19.1:test (default-test) @ amqp-client --- +[INFO] Tests are skipped. +[INFO] +[INFO] --- maven-jar-plugin:3.0.2:jar (default-jar) @ amqp-client --- +[INFO] Building jar: .../rabbitmq_java_client/target/amqp-client-3.7.0-SNAPSHOT.jar +[INFO] +[INFO] --- groovy-maven-plugin:2.0:execute (start-test-broker-A) @ amqp-client --- +[INFO] +[INFO] --- groovy-maven-plugin:2.0:execute (start-test-broker-B) @ amqp-client --- +[INFO] +[INFO] --- groovy-maven-plugin:2.0:execute (create-test-cluster) @ amqp-client --- +[INFO] +[INFO] --- maven-failsafe-plugin:2.19.1:integration-test (integration-test) @ amqp-client --- + +------------------------------------------------------- + T E S T S +------------------------------------------------------- +Running com.rabbitmq.client.test.ClientTests +Tests run: 50, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.732 sec - in com.rabbitmq.client.test.ClientTests + +Results : + +Tests run: 50, Failures: 0, Errors: 0, Skipped: 0 + +[INFO] +[INFO] --- groovy-maven-plugin:2.0:execute (stop-test-broker-B) @ amqp-client --- +[INFO] +[INFO] --- groovy-maven-plugin:2.0:execute (stop-test-broker-A) @ amqp-client --- +[INFO] +[INFO] --- maven-failsafe-plugin:2.19.1:verify (verify) @ amqp-client --- +[INFO] ------------------------------------------------------------------------ +[INFO] BUILD SUCCESS +[INFO] ------------------------------------------------------------------------ +[INFO] Total time: 33.707s +[INFO] Finished at: Mon Aug 08 16:22:26 CEST 2016 +[INFO] Final Memory: 21M/256M +[INFO] ------------------------------------------------------------------------ ``` -The `PASSWORD` environment variable must be set to the password of the keycert.p12 -PKCS12 keystore. The broker must be configured to validate client certificates. -This will become minimal broker configuration file if `$SSL_CERTS_DIR` is replaced -with the certificate folder: - -``` erlang -%%%%% begin sample test broker configuration -[{rabbit, [{ssl_listeners, [5671]}, - {ssl_options, [{cacertfile,"$SSL_CERTS_DIR/testca/cacert.pem"}, - {certfile,"$SSL_CERTS_DIR/server/cert.pem"}, - {keyfile,"$SSL_CERTS_DIR/server/key.pem"}, - {verify,verify_peer}, - {fail_if_no_peer_cert, false}]}]}]. -%%%%% end sample test broker configuration -``` +Test reports can be found in `target/failsafe-reports`. diff --git a/build.xml b/build.xml deleted file mode 100644 index 847bfef516..0000000000 --- a/build.xml +++ /dev/null @@ -1,542 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/bundlorTemplate.mf b/bundlorTemplate.mf deleted file mode 100644 index 7647d07d9e..0000000000 --- a/bundlorTemplate.mf +++ /dev/null @@ -1,7 +0,0 @@ -Bundle-ManifestVersion: 2 -Bundle-SymbolicName: ${bundle.symbolicName} -Bundle-Name: ${bundle.name} -Bundle-Vendor: SpringSource -Bundle-Version: ${impl.version} -Import-Template: - javax.*;version=0 diff --git a/bundlorTestTemplate.mf b/bundlorTestTemplate.mf deleted file mode 100644 index 98b6d800f3..0000000000 --- a/bundlorTestTemplate.mf +++ /dev/null @@ -1,11 +0,0 @@ -Bundle-ManifestVersion: 2 -Bundle-SymbolicName: ${bundle.symbolicName} -Bundle-Name: ${bundle.name} -Bundle-Vendor: SpringSource -Bundle-Version: ${impl.version} -Import-Template: - org.apache.commons.io.*;version="[1.2,2)", - org.apache.commons.cli.*;version="[1.1,2)", - com.rabbitmq.*;version="${impl.version:[=.=.=,=.+1)}", - junit.*;version="[4,5)", - javax.*;version=0 diff --git a/nexus-upload.sh b/nexus-upload.sh deleted file mode 100755 index 40ee9a9b89..0000000000 --- a/nexus-upload.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh - -set -e - -# Required flags: -# CREDS -- basic auth credentials, in form username:password -# VERSION -- the version of the bundle -# SIGNING_KEY -- the signing key to use -# GNUPG_PATH -- the path to the home directory for gnupg - -NEXUS_ROOT="https://$CREDS@oss.sonatype.org/service/local/staging/deploy/maven2/com/rabbitmq/amqp-client/$VERSION" -unset http_proxy -unset https_proxy -unset no_proxy - -for artifact in $@; do - echo "Uploading $artifact" - - rm -f $artifact.asc - gpg --homedir $GNUPG_PATH/.gnupg --local-user $SIGNING_KEY --no-tty --armor --detach-sign --output $artifact.asc $artifact - for ext in '' .asc ; do - curl --upload-file $artifact$ext $NEXUS_ROOT/$(basename "$artifact")$ext - for sum in md5 sha1 ; do - ${sum}sum $artifact$ext | (read a rest ; echo -n "$a") >$artifact$ext.$sum - curl --upload-file $artifact$ext.$sum $NEXUS_ROOT/$(basename "$artifact")$ext.$sum - done - done -done diff --git a/pom.xml b/pom.xml index b14d5c3fc4..bb77efeffb 100644 --- a/pom.xml +++ b/pom.xml @@ -46,8 +46,323 @@ UTF-8 + UTF-8 + + ${basedir}/src/main/scripts + ${basedir}/.. + ${deps.dir}/rabbitmq_codegen + 0.9.1 + + + make + ${deps.dir}/rabbit + ${rabbitmq.dir}/scripts/rabbitmqctl + + ${project.build.directory}/ca.keystore + ${project.build.directory}/empty.keystore + bunnies + + rabbit@localhost + 5672 + ${project.build.directory}/test-classes/${test-broker.A.nodename} + hare@localhost + 5673 + ${project.build.directory}/test-classes/${test-broker.B.nodename} + + + use-gmake + + FreeBSD + + + gmake + + + + use-rabbitmqctl.bat + + Windows + + + ${rabbitmq.dir}/scripts/rabbitmqctl.bat + + + + disable-java8-doclint + + [1.8,) + + + -Xdoclint:none + + + + + integration-tests + + + !skipTests + + + + + + org.codehaus.gmaven + groovy-maven-plugin + 2.0 + + + generate-test-resources + remove-old-test-keystores + + execute + + + + ${groovy-scripts.dir}/remove_old_test_keystores.groovy + + + + + generate-test-resources + query-test-tls-certs-dir + + execute + + + + ${groovy-scripts.dir}/query_test_tls_certs_dir.groovy + + + + + + pre-integration-test + start-test-broker-A + + execute + + + + ${test-broker.A.nodename} + ${test-broker.A.node_port} + + + ${groovy-scripts.dir}/manage_test_broker.groovy + + + + + pre-integration-test + start-test-broker-B + + execute + + + + ${test-broker.B.nodename} + ${test-broker.B.node_port} + + + ${groovy-scripts.dir}/manage_test_broker.groovy + + + + + pre-integration-test + create-test-cluster + + execute + + + + ${test-broker.B.nodename} + ${test-broker.A.nodename} + + + ${groovy-scripts.dir}/manage_test_broker.groovy + + + + + + post-integration-test + stop-test-broker-B + + execute + + + + ${test-broker.B.nodename} + + + ${groovy-scripts.dir}/manage_test_broker.groovy + + + + + post-integration-test + stop-test-broker-A + + execute + + + + ${test-broker.A.nodename} + + + ${groovy-scripts.dir}/manage_test_broker.groovy + + + + + + + + org.codehaus.mojo + keytool-maven-plugin + 1.5 + + + generate-test-ca-keystore + generate-test-resources + + importCertificate + + + ${test-tls-certs.dir}/testca/cacert.pem + ${test-keystore.ca} + ${test-keystore.password} + true + server1 + + + + generate-test-empty-keystore + generate-test-resources + + importCertificate + deleteAlias + + + ${test-tls-certs.dir}/testca/cacert.pem + ${test-keystore.empty} + ${test-keystore.password} + true + server1 + + + + + + + org.apache.maven.plugins + maven-failsafe-plugin + 2.19.1 + + + ${make.bin} + ${rabbitmq.dir} + ${rabbitmqctl.bin} + + ${test-keystore.ca} + ${test-keystore.empty} + ${test-keystore.password} + ${test-tls-certs.dir}/client/keycert.p12 + changeme + + ${test-broker.A.nodename} + ${test-broker.A.node_port} + ${test-broker.A.config_file} + ${test-broker.B.nodename} + ${test-broker.B.node_port} + ${test-broker.B.config_file} + + + ${deps.dir} + + true + + **/ClientTests.* + **/FunctionalTests.* + **/SSLTests.* + **/ServerTests.* + **/HATests.* + **/TestMain.* + + + + + integration-test + + integration-test + + + + verify + + verify + + + + + + + + + + release + + + + org.apache.maven.plugins + maven-source-plugin + 3.0.1 + + + + jar + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.10.4 + + ${javadoc.opts} + + + + + jar + + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.6 + + + sign-artifacts + verify + + sign + + + + + + + + + commons-cli @@ -70,113 +385,76 @@ + + + ${basedir}/src/main/resources + true + + + + + ${basedir}/src/test/resources + true + + + - - - maven-clean-plugin - 3.0.0 - - - - ${basedir}/build - - **/* - - false - - - - + - maven-antrun-plugin - 1.7 + org.codehaus.gmaven + groovy-maven-plugin + 2.0 generate-sources - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + generate-amqp-sources - run + execute + + + + + ${codegen.dir}/amqp-rabbitmq-${codegen.spec_version}.json + +
+ ${project.build.directory}/generated-sources/src/main/java/com/rabbitmq/client/AMQP.java +
+ + ${project.build.directory}/generated-sources/src/main/java/com/rabbitmq/client/impl/AMQImpl.java + +
+ + ${groovy-scripts.dir}/generate_amqp_sources.groovy + +
+ org.codehaus.mojo build-helper-maven-plugin - 1.10 + 1.12 - add-source + add-generated-sources-dir generate-sources add-source - build/gensrc + ${project.build.directory}/generated-sources/src/main/java + maven-compiler-plugin - 3.2 + 3.5.1 1.6 1.6 @@ -186,91 +464,50 @@ + org.apache.maven.plugins maven-surefire-plugin - 2.9 + 2.19.1 - - ${project.build.directory} - - true - - **/ClientTests.* - **/FunctionalTests.* - **/SSLTests.* - **/ServerTests.* - **/FunctionalTests.* - **/HATests.* - **/TestMain.* - + true + org.apache.maven.plugins maven-jar-plugin - 2.6 - - true - - true - true - - true - - - - - - - jar - test-jar - - - - - - org.apache.maven.plugins - maven-source-plugin - 2.4 - - - - jar - test-jar - - - + 3.0.2 + - org.apache.maven.plugins - maven-javadoc-plugin - 2.10.3 + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.7 + true - -Xdoclint:none + ossrh + https://oss.sonatype.org/ + false - - - - jar - test-jar - - - + org.codehaus.mojo versions-maven-plugin - 2.2 + 2.3
+ + ossrh + https://oss.sonatype.org/content/repositories/snapshots + - sonatype-nexus-staging - Nexus Release Repository - http://oss.sonatype.org/service/local/staging/deploy/maven2/ + ossrh + https://oss.sonatype.org/service/local/staging/deploy/maven2/ diff --git a/src/main/java/com/rabbitmq/client/impl/ClientVersion.java.in b/src/main/java/com/rabbitmq/client/impl/ClientVersion.java similarity index 63% rename from src/main/java/com/rabbitmq/client/impl/ClientVersion.java.in rename to src/main/java/com/rabbitmq/client/impl/ClientVersion.java index f9b2a800eb..33ba8d61fa 100644 --- a/src/main/java/com/rabbitmq/client/impl/ClientVersion.java.in +++ b/src/main/java/com/rabbitmq/client/impl/ClientVersion.java @@ -15,10 +15,26 @@ package com.rabbitmq.client.impl; +import java.io.IOException; +import java.util.Properties; + /** * Publicly available Client Version information */ public class ClientVersion { /** Full version string */ - public static final String VERSION = "@VERSION@"; + private static final Properties version; + public static final String VERSION; + + static { + version = new Properties(); + try { + version.load(ClientVersion.class.getClassLoader() + .getResourceAsStream("version.properties")); + } catch (IOException e) { + } + + VERSION = version.getProperty("com.rabbitmq.client.version", + ClientVersion.class.getPackage().getImplementationVersion()); + } } diff --git a/src/main/resources/version.properties b/src/main/resources/version.properties new file mode 100644 index 0000000000..3562d483ec --- /dev/null +++ b/src/main/resources/version.properties @@ -0,0 +1 @@ +com.rabbitmq.client.version = ${project.version} diff --git a/src/main/scripts/generate_amqp_sources.groovy b/src/main/scripts/generate_amqp_sources.groovy new file mode 100644 index 0000000000..4a58e196ec --- /dev/null +++ b/src/main/scripts/generate_amqp_sources.groovy @@ -0,0 +1,60 @@ +import java.security.MessageDigest + +def md5(final file) { + MessageDigest digest = MessageDigest.getInstance("MD5") + file.withInputStream() { is -> + byte[] buffer = new byte[8192] + int read = 0 + while ((read = is.read(buffer)) > 0) { + digest.update(buffer, 0, read); + } + } + byte[] md5sum = digest.digest() + BigInteger bigInt = new BigInteger(1, md5sum) + return bigInt.toString(16) +} + +def generate_source(final type, final filename) { + String[] command = [ + 'python', + properties['script'], type, + properties['spec'], + filename + ] + + def pb = new ProcessBuilder(command) + pb.environment().put('PYTHONPATH', properties['codegen.dir']) + pb.redirectErrorStream(true) + + def process = pb.start() + process.waitFor() + if (process.exitValue() != 0) { + println(process.in.text.trim()) + fail("Failed to generate ${filename} with command: ${command.join(' ')}") + } +} + +def maybe_regen_source(final type, final filename) { + def file = new File(filename) + + if (file.exists()) { + def tmp_filename = filename + '.new' + def tmp_file = new File(tmp_filename) + + generate_source(type, tmp_filename) + old_md5 = md5(file) + new_md5 = md5(tmp_file) + + if (old_md5 == new_md5) { + tmp_file.delete() + } else { + tmp_file.renameTo(file) + } + } else { + generate_source(type, filename) + } + +} + +maybe_regen_source('header', properties['header']) +maybe_regen_source('body', properties['body']) diff --git a/src/main/scripts/manage_test_broker.groovy b/src/main/scripts/manage_test_broker.groovy new file mode 100644 index 0000000000..943e56170e --- /dev/null +++ b/src/main/scripts/manage_test_broker.groovy @@ -0,0 +1,65 @@ +String[] command + +def nodename = properties['nodename'] +if (nodename == null || nodename.length() == 0) { + fail("Node name required") +} + +switch (mojo.getExecutionId()) { +case ~/^start-test-broker-.*/: + def node_port = properties['node_port'] + if (node_port == null || node_port.length() == 0) { + fail("Node TCP port required") + } + + command = [ + properties['make.bin'], + '-C', properties['rabbitmq.dir'], + '--no-print-directory', + 'virgin-node-tmpdir', + 'start-background-broker', + "DEPS_DIR=${properties['deps.dir']}", + "RABBITMQ_NODENAME=${nodename}", + "RABBITMQ_NODE_PORT=${node_port}", + "RABBITMQ_CONFIG_FILE=${project.build.directory}/test-classes/${nodename}" + ] + break + +case ~/^create-test-cluster$/: + def target = properties['target'] + if (target == null || target.length() == 0) { + fail("Target node name required") + } + + command = [ + properties['make.bin'], + '-C', properties['rabbitmq.dir'], + '--no-print-directory', + 'cluster-other-node', + "DEPS_DIR=${properties['deps.dir']}", + "OTHER_NODE=${nodename}", + "MAIN_NODE=${target}" + ] + break + +case ~/^stop-test-broker-.*/: + command = [ + properties['make.bin'], + '-C', properties['rabbitmq.dir'], + '--no-print-directory', + 'stop-node', + "DEPS_DIR=${properties['deps.dir']}", + "RABBITMQ_NODENAME=${nodename}" + ] + break +} + +def pb = new ProcessBuilder(command) +pb.redirectErrorStream(true) + +def process = pb.start() +process.waitFor() +if (process.exitValue() != 0) { + println(process.in.text.trim()) + fail("Failed to manage broker '${nodename}' with command: ${command.join(' ')}") +} diff --git a/src/main/scripts/query_test_tls_certs_dir.groovy b/src/main/scripts/query_test_tls_certs_dir.groovy new file mode 100644 index 0000000000..2c86bb8c10 --- /dev/null +++ b/src/main/scripts/query_test_tls_certs_dir.groovy @@ -0,0 +1,25 @@ +String[] command = [ + properties['make.bin'], + '-C', properties['rabbitmq.dir'], + '--no-print-directory', + 'show-test-tls-certs-dir', + "DEPS_DIR=${properties['deps.dir']}", +] + +def pb = new ProcessBuilder(command) +pb.redirectErrorStream(true) + +def process = pb.start() + +// We are only interested in the last line of output. Previous lines, if +// any, are related to the generation of the test certificates. +def whole_output = "" +process.inputStream.eachLine { + whole_output += it + project.properties['test-tls-certs.dir'] = it.trim() +} +process.waitFor() +if (process.exitValue() != 0) { + println(whole_output.trim()) + fail("Failed to query test TLS certs directory with command: ${command.join(' ')}") +} diff --git a/src/main/scripts/remove_old_test_keystores.groovy b/src/main/scripts/remove_old_test_keystores.groovy new file mode 100644 index 0000000000..e08775e4e0 --- /dev/null +++ b/src/main/scripts/remove_old_test_keystores.groovy @@ -0,0 +1,8 @@ +def dir = new File(project.build.directory) + +// This pattern starts with `.*`. This is normally useless and even +// inefficient but the matching doesn't work without it... +def pattern = ~/.*\.keystore$/ +dir.eachFileMatch(pattern) { file -> + file.delete() +} diff --git a/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java b/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java index 48c15f45e4..1937e074c5 100644 --- a/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java +++ b/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java @@ -34,10 +34,10 @@ public abstract class AbstractRMQTestSuite extends TestSuite { static { Properties TESTS_PROPS = new Properties(System.getProperties()); - TESTS_PROPS.setProperty("make.bin", - System.getenv("MAKE") == null ? "make" : System.getenv("MAKE")); + String make = System.getenv("MAKE"); + if (make != null) + TESTS_PROPS.setProperty("make.bin", make); try { - TESTS_PROPS.load(Host.class.getClassLoader().getResourceAsStream("build.properties")); TESTS_PROPS.load(Host.class.getClassLoader().getResourceAsStream("config.properties")); } catch (Exception e) { System.out.println( @@ -68,11 +68,11 @@ public static boolean requiredProperties() { return false; } - /* Path to rabbitmq_test. */ - String rabbitmq_test = Host.rabbitmqTestDir(); - if (rabbitmq_test == null || !new File(rabbitmq_test).isDirectory()) { + /* Path to RabbitMQ. */ + String rabbitmq = Host.rabbitmqDir(); + if (rabbitmq == null || !new File(rabbitmq).isDirectory()) { System.err.println( - "rabbitmq_test required; please set \"sibling.rabbitmq_test.dir\" system" + + "RabbitMQ required; please set \"rabbitmq.dir\" system" + " property"); return false; } @@ -94,13 +94,12 @@ public static boolean isUnderUmbrella() { } public static boolean isSSLAvailable() { - String SSL_CERTS_DIR = System.getenv("SSL_CERTS_DIR"); + String sslClientCertsDir = System.getProperty("test-client-cert.path"); String hostname = System.getProperty("broker.hostname"); String port = System.getProperty("broker.sslport"); - if (SSL_CERTS_DIR == null || hostname == null || port == null) + if (sslClientCertsDir == null || hostname == null || port == null) return false; - String sslClientCertsDir = SSL_CERTS_DIR + File.separator + "client"; // If certificate is present and some server is listening on port 5671 if (new File(sslClientCertsDir).exists() && checkServerListening(hostname, Integer.parseInt(port))) { diff --git a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java index 21448f8cc8..81c412d700 100644 --- a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java +++ b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java @@ -97,7 +97,8 @@ protected void restart() protected void bareRestart() throws IOException { - Host.invokeMakeTarget("restart-app"); + Host.invokeMakeTarget( + "stop-rabbit-on-node start-rabbit-on-node"); } public void openConnection() diff --git a/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java b/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java index 6f71533679..c198db8bd0 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java @@ -124,10 +124,10 @@ public void closeConnection() throws IOException { } protected void stopSecondary() throws IOException { - Host.invokeMakeTarget("stop-secondary-app"); + Host.invokeMakeTarget("stop-rabbit-on-node RABBITMQ_NODENAME=\'" + Host.nodenameB() + "\'"); } protected void startSecondary() throws IOException { - Host.invokeMakeTarget("start-secondary-app"); + Host.invokeMakeTarget("start-rabbit-on-node RABBITMQ_NODENAME=\'" + Host.nodenameB() + "\'"); } } diff --git a/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java b/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java index 510fb403ea..5c1c65d939 100644 --- a/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java +++ b/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java @@ -54,9 +54,9 @@ public void testDeadLetterQueueTTLExpiredWhileDown() throws Exception { } closeConnection(); - Host.invokeMakeTarget("stop-app"); + Host.invokeMakeTarget("stop-rabbit-on-node"); Thread.sleep(5000); - Host.invokeMakeTarget("start-app"); + Host.invokeMakeTarget("start-rabbit-on-node"); openConnection(); openChannel(); diff --git a/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java b/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java index 64507360b6..f484d1f49e 100644 --- a/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java +++ b/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java @@ -44,7 +44,13 @@ protected void restart() throws IOException, TimeoutException { alternateConnection = null; alternateChannel = null; - Host.invokeMakeTarget("restart-secondary-node"); + Host.invokeMakeTarget( + "stop-node" + + " start-background-broker" + + " RABBITMQ_NODENAME=\'" + Host.nodenameB() + "\'" + + " RABBITMQ_NODE_PORT=" + Host.node_portB() + + " RABBITMQ_CONFIG_FILE=\'" + Host.config_fileB() + "\'" + ); } restartPrimary(); } diff --git a/src/test/java/com/rabbitmq/client/test/server/HATests.java b/src/test/java/com/rabbitmq/client/test/server/HATests.java index 31f4373017..9d97ad7b8f 100644 --- a/src/test/java/com/rabbitmq/client/test/server/HATests.java +++ b/src/test/java/com/rabbitmq/client/test/server/HATests.java @@ -42,7 +42,7 @@ public static TestSuite suite() { public static class SetUp extends TestCase { @Override protected void setUp() throws Exception { - Host.invokeMakeTarget("enable-ha"); + Host.rabbitmqctl("set_policy HA '.*' '{\"ha-mode\":\"all\"}'"); HA_TESTS_RUNNING = true; } @@ -52,7 +52,7 @@ public void testNothing() {} public static class TearDown extends TestCase { @Override protected void tearDown() throws Exception { - Host.invokeMakeTarget("disable-ha"); + Host.rabbitmqctl("clear_policy HA"); HA_TESTS_RUNNING = false; } diff --git a/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java index 957e384881..3026fe547a 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java @@ -40,9 +40,9 @@ public class BadVerifiedConnection extends UnverifiedConnection { public void openConnection() throws IOException, TimeoutException { try { - String keystorePath = System.getProperty("keystore.empty.path"); + String keystorePath = System.getProperty("test-keystore.empty"); assertNotNull(keystorePath); - String keystorePasswd = System.getProperty("keystore.passwd"); + String keystorePasswd = System.getProperty("test-keystore.password"); assertNotNull(keystorePasswd); char [] keystorePassword = keystorePasswd.toCharArray(); @@ -52,9 +52,9 @@ public void openConnection() TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); tmf.init(tks); - String p12Path = System.getProperty("p12.path"); + String p12Path = System.getProperty("test-client-cert.path"); assertNotNull(p12Path); - String p12Passwd = System.getProperty("p12.passwd"); + String p12Passwd = System.getProperty("test-client-cert.password"); assertNotNull(p12Passwd); KeyStore ks = KeyStore.getInstance("PKCS12"); char [] p12Password = p12Passwd.toCharArray(); diff --git a/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java index 71d59f95a3..2be30e1d72 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java @@ -24,7 +24,7 @@ public class SSLTests extends AbstractRMQTestSuite { public static TestSuite suite() { TestSuite suite = new TestSuite("ssl"); suite.addTestSuite(ConnectionFactoryDefaultTlsVersion.class); - // Skip the tests if not under umbrella and no TLS setup available + // Skip the tests if not under umbrella if (!requiredProperties()) return suite; if (!isSSLAvailable()) return suite; suite.addTestSuite(UnverifiedConnection.class); diff --git a/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java index c12a3a2e66..645dec1104 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java @@ -41,9 +41,9 @@ public class VerifiedConnection extends UnverifiedConnection { public void openConnection() throws IOException, TimeoutException { try { - String keystorePath = System.getProperty("keystore.path"); + String keystorePath = System.getProperty("test-keystore.ca"); assertNotNull(keystorePath); - String keystorePasswd = System.getProperty("keystore.passwd"); + String keystorePasswd = System.getProperty("test-keystore.password"); assertNotNull(keystorePasswd); char [] keystorePassword = keystorePasswd.toCharArray(); @@ -53,9 +53,9 @@ public void openConnection() TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); tmf.init(tks); - String p12Path = System.getProperty("p12.path"); + String p12Path = System.getProperty("test-client-cert.path"); assertNotNull(p12Path); - String p12Passwd = System.getProperty("p12.passwd"); + String p12Passwd = System.getProperty("test-client-cert.password"); assertNotNull(p12Passwd); KeyStore ks = KeyStore.getInstance("PKCS12"); char [] p12Password = p12Passwd.toCharArray(); diff --git a/src/test/java/com/rabbitmq/tools/Host.java b/src/test/java/com/rabbitmq/tools/Host.java index ba7462b3cd..95d74e8108 100644 --- a/src/test/java/com/rabbitmq/tools/Host.java +++ b/src/test/java/com/rabbitmq/tools/Host.java @@ -92,24 +92,61 @@ private static Process executeCommandProcess(String command) throws IOException } public static Process rabbitmqctl(String command) throws IOException { - return executeCommand(rabbitmqctlCommand() + " " + command); + return executeCommand(rabbitmqctlCommand() + + " -n \'" + nodenameA() + "\'" + + " " + command); } public static Process rabbitmqctlIgnoreErrors(String command) throws IOException { - return executeCommandIgnoringErrors(rabbitmqctlCommand() + " " + command); + return executeCommandIgnoringErrors(rabbitmqctlCommand() + + " -n \'" + nodenameA() + "\'" + + " " + command); } public static Process invokeMakeTarget(String command) throws IOException { File rabbitmqctl = new File(rabbitmqctlCommand()); return executeCommand(makeCommand() + - " -C \'" + rabbitmqTestDir() + "\'" + + " -C \'" + rabbitmqDir() + "\'" + " RABBITMQCTL=\'" + rabbitmqctl.getAbsolutePath() + "\'" + + " RABBITMQ_NODENAME=\'" + nodenameA() + "\'" + + " RABBITMQ_NODE_PORT=" + node_portA() + + " RABBITMQ_CONFIG_FILE=\'" + config_fileA() + "\'" + " " + command); } public static String makeCommand() { - return System.getProperty("make.bin"); + return System.getProperty("make.bin", "make"); + } + + public static String nodenameA() + { + return System.getProperty("test-broker.A.nodename"); + } + + public static String node_portA() + { + return System.getProperty("test-broker.A.node_port"); + } + + public static String config_fileA() + { + return System.getProperty("test-broker.A.config_file"); + } + + public static String nodenameB() + { + return System.getProperty("test-broker.B.nodename"); + } + + public static String node_portB() + { + return System.getProperty("test-broker.B.node_port"); + } + + public static String config_fileB() + { + return System.getProperty("test-broker.B.config_file"); } public static String rabbitmqctlCommand() @@ -117,9 +154,9 @@ public static String rabbitmqctlCommand() return System.getProperty("rabbitmqctl.bin"); } - public static String rabbitmqTestDir() + public static String rabbitmqDir() { - return System.getProperty("sibling.rabbitmq_test.dir"); + return System.getProperty("rabbitmq.dir"); } public static void closeConnection(String pid) throws IOException { diff --git a/src/test/resources/build.properties b/src/test/resources/build.properties deleted file mode 100644 index acfbd12a33..0000000000 --- a/src/test/resources/build.properties +++ /dev/null @@ -1,24 +0,0 @@ -alt.javac.source=1.6 -alt.javac.target=1.6 -build.out=build -bundle.name=RabbitMQ client library -bundle.out=${build.out}/bundle -bundle.symbolicName=com.rabbitmq.client -bundlor.home=bundlor -dist.out=${build.out}/dist -impl.version=0.0.0 -javac.debug=false -javac.out=${build.out}/classes -javadoc.out=build/doc/api -lib.out=${build.out}/lib -python.bin=python -sibling.codegen.dir=../rabbitmq_codegen -sibling.rabbitmq_test.dir=../rabbitmq_test -rabbitmqctl.bin=../rabbit/scripts/rabbitmqctl -spec.version=0.9.1 -src.generated=${build.out}/gensrc -standard.javac.source=1.6 -standard.javac.target=1.6 -test.javac.out=${build.out}/test/classes -test.src.home=${basedir}/src/test/java -maven.src.home=${basedir}/src/main/java diff --git a/src/test/resources/hare@localhost.config b/src/test/resources/hare@localhost.config new file mode 100644 index 0000000000..a321e2848b --- /dev/null +++ b/src/test/resources/hare@localhost.config @@ -0,0 +1,15 @@ +% vim:ft=erlang: + +[ + {rabbit, [ + {ssl_listeners, [5670]}, + {ssl_options, [ + {cacertfile, "${test-tls-certs.dir}/testca/cacert.pem"}, + {certfile, "${test-tls-certs.dir}/server/cert.pem"}, + {keyfile, "${test-tls-certs.dir}/server/key.pem"}, + {verify, verify_peer}, + {fail_if_no_peer_cert, false}, + {honor_cipher_order, true}]}, + {auth_mechanisms, ['PLAIN', 'AMQPLAIN', 'EXTERNAL', 'RABBIT-CR-DEMO']} + ]} +]. diff --git a/src/test/resources/rabbit@localhost.config b/src/test/resources/rabbit@localhost.config new file mode 100644 index 0000000000..6d233b5b9f --- /dev/null +++ b/src/test/resources/rabbit@localhost.config @@ -0,0 +1,15 @@ +% vim:ft=erlang: + +[ + {rabbit, [ + {ssl_listeners, [5671]}, + {ssl_options, [ + {cacertfile, "${test-tls-certs.dir}/testca/cacert.pem"}, + {certfile, "${test-tls-certs.dir}/server/cert.pem"}, + {keyfile, "${test-tls-certs.dir}/server/key.pem"}, + {verify, verify_peer}, + {fail_if_no_peer_cert, false}, + {honor_cipher_order, true}]}, + {auth_mechanisms, ['PLAIN', 'AMQPLAIN', 'EXTERNAL', 'RABBIT-CR-DEMO']} + ]} +]. From 14f2166cdaba7fff4dc9a3f0f5111d61cdb7211d Mon Sep 17 00:00:00 2001 From: ayoub Date: Tue, 9 Aug 2016 07:38:21 -0500 Subject: [PATCH 0190/2114] Add config manager for openstack perf utility --- .../examples/perf/openstack/Consumer.java | 5 ++ .../examples/perf/openstack/Producer.java | 14 ++++ .../perf/openstack/samples/Configuration.java | 66 +++++++++++++++++++ 3 files changed, 85 insertions(+) create mode 100644 src/test/java/com/rabbitmq/examples/perf/openstack/Consumer.java create mode 100644 src/test/java/com/rabbitmq/examples/perf/openstack/Producer.java create mode 100644 src/test/java/com/rabbitmq/examples/perf/openstack/samples/Configuration.java diff --git a/src/test/java/com/rabbitmq/examples/perf/openstack/Consumer.java b/src/test/java/com/rabbitmq/examples/perf/openstack/Consumer.java new file mode 100644 index 0000000000..b372182a79 --- /dev/null +++ b/src/test/java/com/rabbitmq/examples/perf/openstack/Consumer.java @@ -0,0 +1,5 @@ +package com.rabbitmq.examples.perf.openstack; + +public class Consumer { + +} diff --git a/src/test/java/com/rabbitmq/examples/perf/openstack/Producer.java b/src/test/java/com/rabbitmq/examples/perf/openstack/Producer.java new file mode 100644 index 0000000000..4ecaa536cc --- /dev/null +++ b/src/test/java/com/rabbitmq/examples/perf/openstack/Producer.java @@ -0,0 +1,14 @@ +package com.rabbitmq.examples.perf.openstack; + +import com.rabbitmq.examples.perf.ProducerConsumerBase; + +/* + * This producer will publish OpenStack-alike messages to the RabbitMQ server. + * These messages simulate the OpenStack heartbeats, in particular, those that + * are used by Nova and Neutron modules to update N-CPU, L2, L3 and DHCP agents' + * status. + */ + +public class Producer extends ProducerConsumerBase { + +} diff --git a/src/test/java/com/rabbitmq/examples/perf/openstack/samples/Configuration.java b/src/test/java/com/rabbitmq/examples/perf/openstack/samples/Configuration.java new file mode 100644 index 0000000000..249023dae1 --- /dev/null +++ b/src/test/java/com/rabbitmq/examples/perf/openstack/samples/Configuration.java @@ -0,0 +1,66 @@ +package com.rabbitmq.examples.perf.openstack.samples; + +public class Configuration { + + //------------------------------------- + //AMQP messages sizes in Bytes + //Note: VN: Virtual Network, VM: Virtual Machine + //compute node published heartbeats (0 VN 0 VM): exchange originated + public static final int RPC_NOVA_OA_MEAN_SIZE = 1890; + public static final int RPC_NOVA_OCAV_MEAN_SIZE = 1890; + public static final int RPC_NOVA_SII_MEAN_SIZE = 1000; + public static final int RPC_NEUTRON_RS_MEAN_SIZE = 1530; + + //compute node consumed heartbeats: queue originated + public static final int RPC_NOVA_REPLY_MEAN_SIZE = 640; + public static final int RPC_NEUTRON_REPLY_MEAN_SIZE = 200; + + private static final int NBR_OF_VARIABLES = 6; + + //additional size when resources are deployed (1 VN 1 VM): exchange + public static final int RPC_NOVA_OA_ADD_SIZE = 110; + public static final int RPC_NOVA_OCAV_ADD_SIZE = 110; + public static final int RPC_NOVA_SII_ADD_SIZE = 210; + public static final int RPC_NEUTRON_RS_ADD_SIZE = 0; + + //additional size of queue originated messages + public static final int RPC_NOVA_REPLY_ADD_SIZE = 480; + public static final int RPC_NEUTRON_REPLY_ADD_SIZE = 40; + + //------------------------------------- + //POP (Point of Presence; i.e. Datacenter) simulation variables + //For example: the number of compute nodes in a POP. + private int nbr_cpun; + private int nbr_vn; + private int nbr_vm_cpun; +// private int nbr_vm_vn; +// private int nbr_cross_vn; + + public Configuration(int nbr_cpu_nodes_per_pop, int nbr_vn_per_pop, + int nbr_vm_per_cpu_node, int nbr_vm_per_vn, int nbr_cross_pop_vn) { + + nbr_cpun = nbr_cpu_nodes_per_pop; + nbr_vn = nbr_vn_per_pop; + nbr_vm_cpun = nbr_vm_per_cpu_node; +// nbr_vm_vn = nbr_vm_per_vn; +// nbr_cross_vn = nbr_cross_pop_vn; + + } + + public int[] getPopConfigMatrix() { + int[] config = new int[NBR_OF_VARIABLES]; + config[0] = RPC_NOVA_OA_MEAN_SIZE + RPC_NOVA_OA_ADD_SIZE * nbr_vm_cpun; + config[1] = RPC_NOVA_OCAV_MEAN_SIZE + RPC_NOVA_OCAV_ADD_SIZE * nbr_vm_cpun; + config[2] = RPC_NOVA_SII_MEAN_SIZE + RPC_NOVA_SII_ADD_SIZE * nbr_vm_cpun; + config[3] = RPC_NEUTRON_RS_MEAN_SIZE + RPC_NEUTRON_RS_ADD_SIZE * nbr_vn; + config[4] = RPC_NOVA_REPLY_MEAN_SIZE + RPC_NOVA_REPLY_ADD_SIZE * nbr_vm_cpun; + config[5] = RPC_NEUTRON_REPLY_MEAN_SIZE + RPC_NEUTRON_REPLY_ADD_SIZE * nbr_vn; + + for (int i = 0; i < config.length; i++) { + config[i] = config[i] * nbr_cpun; + } + + return config; + } + +} From 9fd23be829d4e4ca1ef942fba250967175585c93 Mon Sep 17 00:00:00 2001 From: ayoub Date: Tue, 9 Aug 2016 10:49:53 -0500 Subject: [PATCH 0191/2114] Remove Configuration and empty P/C classes. --- .../examples/perf/openstack/Consumer.java | 5 -- .../examples/perf/openstack/Producer.java | 14 ---- .../perf/openstack/samples/Configuration.java | 66 ------------------- 3 files changed, 85 deletions(-) delete mode 100644 src/test/java/com/rabbitmq/examples/perf/openstack/Consumer.java delete mode 100644 src/test/java/com/rabbitmq/examples/perf/openstack/Producer.java delete mode 100644 src/test/java/com/rabbitmq/examples/perf/openstack/samples/Configuration.java diff --git a/src/test/java/com/rabbitmq/examples/perf/openstack/Consumer.java b/src/test/java/com/rabbitmq/examples/perf/openstack/Consumer.java deleted file mode 100644 index b372182a79..0000000000 --- a/src/test/java/com/rabbitmq/examples/perf/openstack/Consumer.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.rabbitmq.examples.perf.openstack; - -public class Consumer { - -} diff --git a/src/test/java/com/rabbitmq/examples/perf/openstack/Producer.java b/src/test/java/com/rabbitmq/examples/perf/openstack/Producer.java deleted file mode 100644 index 4ecaa536cc..0000000000 --- a/src/test/java/com/rabbitmq/examples/perf/openstack/Producer.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.rabbitmq.examples.perf.openstack; - -import com.rabbitmq.examples.perf.ProducerConsumerBase; - -/* - * This producer will publish OpenStack-alike messages to the RabbitMQ server. - * These messages simulate the OpenStack heartbeats, in particular, those that - * are used by Nova and Neutron modules to update N-CPU, L2, L3 and DHCP agents' - * status. - */ - -public class Producer extends ProducerConsumerBase { - -} diff --git a/src/test/java/com/rabbitmq/examples/perf/openstack/samples/Configuration.java b/src/test/java/com/rabbitmq/examples/perf/openstack/samples/Configuration.java deleted file mode 100644 index 249023dae1..0000000000 --- a/src/test/java/com/rabbitmq/examples/perf/openstack/samples/Configuration.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.rabbitmq.examples.perf.openstack.samples; - -public class Configuration { - - //------------------------------------- - //AMQP messages sizes in Bytes - //Note: VN: Virtual Network, VM: Virtual Machine - //compute node published heartbeats (0 VN 0 VM): exchange originated - public static final int RPC_NOVA_OA_MEAN_SIZE = 1890; - public static final int RPC_NOVA_OCAV_MEAN_SIZE = 1890; - public static final int RPC_NOVA_SII_MEAN_SIZE = 1000; - public static final int RPC_NEUTRON_RS_MEAN_SIZE = 1530; - - //compute node consumed heartbeats: queue originated - public static final int RPC_NOVA_REPLY_MEAN_SIZE = 640; - public static final int RPC_NEUTRON_REPLY_MEAN_SIZE = 200; - - private static final int NBR_OF_VARIABLES = 6; - - //additional size when resources are deployed (1 VN 1 VM): exchange - public static final int RPC_NOVA_OA_ADD_SIZE = 110; - public static final int RPC_NOVA_OCAV_ADD_SIZE = 110; - public static final int RPC_NOVA_SII_ADD_SIZE = 210; - public static final int RPC_NEUTRON_RS_ADD_SIZE = 0; - - //additional size of queue originated messages - public static final int RPC_NOVA_REPLY_ADD_SIZE = 480; - public static final int RPC_NEUTRON_REPLY_ADD_SIZE = 40; - - //------------------------------------- - //POP (Point of Presence; i.e. Datacenter) simulation variables - //For example: the number of compute nodes in a POP. - private int nbr_cpun; - private int nbr_vn; - private int nbr_vm_cpun; -// private int nbr_vm_vn; -// private int nbr_cross_vn; - - public Configuration(int nbr_cpu_nodes_per_pop, int nbr_vn_per_pop, - int nbr_vm_per_cpu_node, int nbr_vm_per_vn, int nbr_cross_pop_vn) { - - nbr_cpun = nbr_cpu_nodes_per_pop; - nbr_vn = nbr_vn_per_pop; - nbr_vm_cpun = nbr_vm_per_cpu_node; -// nbr_vm_vn = nbr_vm_per_vn; -// nbr_cross_vn = nbr_cross_pop_vn; - - } - - public int[] getPopConfigMatrix() { - int[] config = new int[NBR_OF_VARIABLES]; - config[0] = RPC_NOVA_OA_MEAN_SIZE + RPC_NOVA_OA_ADD_SIZE * nbr_vm_cpun; - config[1] = RPC_NOVA_OCAV_MEAN_SIZE + RPC_NOVA_OCAV_ADD_SIZE * nbr_vm_cpun; - config[2] = RPC_NOVA_SII_MEAN_SIZE + RPC_NOVA_SII_ADD_SIZE * nbr_vm_cpun; - config[3] = RPC_NEUTRON_RS_MEAN_SIZE + RPC_NEUTRON_RS_ADD_SIZE * nbr_vn; - config[4] = RPC_NOVA_REPLY_MEAN_SIZE + RPC_NOVA_REPLY_ADD_SIZE * nbr_vm_cpun; - config[5] = RPC_NEUTRON_REPLY_MEAN_SIZE + RPC_NEUTRON_REPLY_ADD_SIZE * nbr_vn; - - for (int i = 0; i < config.length; i++) { - config[i] = config[i] * nbr_cpun; - } - - return config; - } - -} From b07840663bdaf586bbb3de38423c2681ad6f6929 Mon Sep 17 00:00:00 2001 From: Christoph Fiehe Date: Wed, 10 Aug 2016 08:50:42 +0200 Subject: [PATCH 0192/2114] Restoring OSGi compatibility after migration to a fully Maven-based build process. This commit also fixes issue #162. --- pom.xml | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index bb77efeffb..e47d15ce9c 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ jar RabbitMQ Java Client - RabbitMQ Java client + The RabbitMQ Java client library allows Java code to interface to RabbitMQ. http://www.rabbitmq.com @@ -43,6 +43,11 @@ https://github.com/rabbitmq/rabbitmq-java-client.git scm:git:https://github.com/rabbitmq/rabbitmq-java-client.git + + + Pivotal Software, Inc. + http://www.rabbitmq.com + UTF-8 @@ -478,6 +483,39 @@ org.apache.maven.plugins maven-jar-plugin 3.0.2 + + + ${project.build.outputDirectory}/META-INF/MANIFEST.MF + + + + + + org.apache.felix + maven-bundle-plugin + 2.3.7 + + + bundle-manifest + process-classes + + manifest + + + + com.rabbitmq* + com.rabbitmq.client + AMQP + 0.9.1 + AMQP Working Group (www.amqp.org) + ${project.name} + ${project.version} + ${project.organization.name} + ${project.url} + + + + From 8ffe0b76d44a3c339adee14c9919971bd4ebbaf7 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 10 Aug 2016 10:25:31 +0300 Subject: [PATCH 0193/2114] Cosmetics --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index e47d15ce9c..be10d1c3a1 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ jar RabbitMQ Java Client - The RabbitMQ Java client library allows Java code to interface to RabbitMQ. + The RabbitMQ Java client library allows Java applications to interface with RabbitMQ. http://www.rabbitmq.com @@ -43,7 +43,7 @@ https://github.com/rabbitmq/rabbitmq-java-client.git scm:git:https://github.com/rabbitmq/rabbitmq-java-client.git - + Pivotal Software, Inc. http://www.rabbitmq.com From 73110afabe190b5673ce4b5d8c25946f4332b490 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Wed, 10 Aug 2016 19:22:48 +0200 Subject: [PATCH 0194/2114] pom.xml: Restore the ability to test against a provided broker To do this, one needs to prevent the automatic test cluster setup by disabling the `setup-test-cluster` profile: `mvn verify -P '!setup-test-cluster' While here, add several comments to the POM so it's easier to understand. --- pom.xml | 243 +++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 197 insertions(+), 46 deletions(-) diff --git a/pom.xml b/pom.xml index be10d1c3a1..55988736dd 100644 --- a/pom.xml +++ b/pom.xml @@ -53,7 +53,24 @@ UTF-8 UTF-8 + ${basedir}/src/main/scripts + + ${basedir}/.. ${deps.dir}/rabbitmq_codegen 0.9.1 @@ -77,6 +94,7 @@ + use-gmake FreeBSD @@ -85,7 +103,9 @@ gmake + + use-rabbitmqctl.bat Windows @@ -94,7 +114,12 @@ ${rabbitmq.dir}/scripts/rabbitmqctl.bat + + disable-java8-doclint [1.8,) @@ -105,11 +130,29 @@ - integration-tests + + setup-test-cluster !skipTests + + ${rabbitmq.dir} + @@ -118,18 +161,10 @@ groovy-maven-plugin 2.0 - - generate-test-resources - remove-old-test-keystores - - execute - - - - ${groovy-scripts.dir}/remove_old_test_keystores.groovy - - - + generate-test-resources query-test-tls-certs-dir @@ -143,6 +178,14 @@ + pre-integration-test start-test-broker-A @@ -192,6 +235,9 @@ + post-integration-test stop-test-broker-B @@ -225,43 +271,70 @@ + org.codehaus.mojo keytool-maven-plugin - 1.5 - - - generate-test-ca-keystore - generate-test-resources - - importCertificate - - - ${test-tls-certs.dir}/testca/cacert.pem - ${test-keystore.ca} - ${test-keystore.password} - true - server1 - - - - generate-test-empty-keystore - generate-test-resources - - importCertificate - deleteAlias - - - ${test-tls-certs.dir}/testca/cacert.pem - ${test-keystore.empty} - ${test-keystore.password} - true - server1 - - - + + false + + + + + + + + + use-provided-test-keystores + + + ${test-tls-certs.dir}/testca/cacert.pem + + + + + + org.codehaus.mojo + keytool-maven-plugin + + false + + + + + + + integration-tests + + + !skipTests + + + + org.apache.maven.plugins maven-failsafe-plugin @@ -318,6 +391,10 @@ + release @@ -390,12 +467,18 @@ + ${basedir}/src/main/resources true + + ${basedir}/src/test/resources @@ -404,12 +487,17 @@ - org.codehaus.gmaven groovy-maven-plugin 2.0 + generate-sources generate-amqp-sources @@ -434,6 +522,24 @@ + + + + generate-test-resources + remove-old-test-keystores + + execute + + + + ${groovy-scripts.dir}/remove_old_test_keystores.groovy + + + @@ -470,6 +576,10 @@ + org.apache.maven.plugins maven-surefire-plugin @@ -479,6 +589,47 @@ + + + org.codehaus.mojo + keytool-maven-plugin + 1.5 + + true + + + + generate-test-ca-keystore + generate-test-resources + + importCertificate + + + ${test-tls-certs.dir}/testca/cacert.pem + ${test-keystore.ca} + ${test-keystore.password} + true + server1 + + + + generate-test-empty-keystore + generate-test-resources + + importCertificate + deleteAlias + + + ${test-tls-certs.dir}/testca/cacert.pem + ${test-keystore.empty} + ${test-keystore.password} + true + server1 + + + + + org.apache.maven.plugins maven-jar-plugin From 3a78547ef14849440a4b93f4fe701f0a885b1774 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Thu, 11 Aug 2016 12:41:53 +0200 Subject: [PATCH 0195/2114] pom.xml: The testsuite doesn't depend on commons-io anymore [#127354185] --- pom.xml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/pom.xml b/pom.xml index 55988736dd..e9c3bb6a84 100644 --- a/pom.xml +++ b/pom.xml @@ -452,12 +452,6 @@ 1.1 test - - commons-io - commons-io - 1.2 - test - junit junit From b3618ab253dfc8f684b49d7439c30e4688f47b43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Thu, 11 Aug 2016 12:43:07 +0200 Subject: [PATCH 0196/2114] pom.xml: Use maven-resources-plugin 3.0.1 The "[debug] execute contextualize" message is annoying and useless. We need at least version 2.6 to get rid of it. [#127354185] --- pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pom.xml b/pom.xml index e9c3bb6a84..f4b868c3f1 100644 --- a/pom.xml +++ b/pom.xml @@ -481,6 +481,11 @@ + + org.apache.maven.plugins + maven-resources-plugin + 3.0.1 + org.codehaus.gmaven groovy-maven-plugin From d51045332ef6eb6a57f02ccb22d1c291af52350b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Thu, 11 Aug 2016 12:46:22 +0200 Subject: [PATCH 0197/2114] pom.xml: `${deps.dir}` defaults to `./deps` And we try to detect the Umbrella and use its dependencies directory. [#127354185] --- pom.xml | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f4b868c3f1..ac12cf481f 100644 --- a/pom.xml +++ b/pom.xml @@ -71,7 +71,7 @@ "rabbit" is used to automatically setup a RabbitMQ cluster for the testsuite. --> - ${basedir}/.. + ${basedir}/deps ${deps.dir}/rabbitmq_codegen 0.9.1 @@ -93,6 +93,22 @@ + + + in-umbrella + + + ../../UMBRELLA.md + + + + ${basedir}/.. + + + use-gmake From 4cc97e58f01c5e0d1529309df102e80b1544e8f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Thu, 11 Aug 2016 12:50:07 +0200 Subject: [PATCH 0198/2114] scripts/PerfTest: New script to run the PerfTest tool `mvn test-compile` is run before to make sure the tool is ready and up-to-date. --- scripts/PerfTest | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100755 scripts/PerfTest diff --git a/scripts/PerfTest b/scripts/PerfTest new file mode 100755 index 0000000000..044588115f --- /dev/null +++ b/scripts/PerfTest @@ -0,0 +1,14 @@ +#!/bin/sh + +set -e + +SCRIPTDIR=$(dirname "$0") +SRCDIR=$(cd "$SCRIPTDIR"/.. && pwd) + +( + cd "$SRCDIR" + mvn -q test-compile -P '!setup-test-cluster' + mvn -q exec:java \ + -Dexec.classpathScope=test \ + -Dexec.mainClass="com.rabbitmq.examples.PerfTest" "$@" +) From bbc58cb261315f02bb8d3781836451c02eaf6e36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Thu, 11 Aug 2016 14:12:10 +0200 Subject: [PATCH 0199/2114] SSLTests.java: Restore comment about "SSL unavailable" --- src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java index 2be30e1d72..71d59f95a3 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java @@ -24,7 +24,7 @@ public class SSLTests extends AbstractRMQTestSuite { public static TestSuite suite() { TestSuite suite = new TestSuite("ssl"); suite.addTestSuite(ConnectionFactoryDefaultTlsVersion.class); - // Skip the tests if not under umbrella + // Skip the tests if not under umbrella and no TLS setup available if (!requiredProperties()) return suite; if (!isSSLAvailable()) return suite; suite.addTestSuite(UnverifiedConnection.class); From 47deb742ec3b7cef54e4c1d0624f91a3a9dc48f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Thu, 11 Aug 2016 14:19:14 +0200 Subject: [PATCH 0200/2114] Host.java: Fix indentation Tabs were not expanded to spaces. --- src/test/java/com/rabbitmq/tools/Host.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/java/com/rabbitmq/tools/Host.java b/src/test/java/com/rabbitmq/tools/Host.java index 95d74e8108..a8484737a6 100644 --- a/src/test/java/com/rabbitmq/tools/Host.java +++ b/src/test/java/com/rabbitmq/tools/Host.java @@ -100,7 +100,7 @@ public static Process rabbitmqctl(String command) throws IOException { public static Process rabbitmqctlIgnoreErrors(String command) throws IOException { return executeCommandIgnoringErrors(rabbitmqctlCommand() + " -n \'" + nodenameA() + "\'" + - " " + command); + " " + command); } public static Process invokeMakeTarget(String command) throws IOException { @@ -109,8 +109,8 @@ public static Process invokeMakeTarget(String command) throws IOException { " -C \'" + rabbitmqDir() + "\'" + " RABBITMQCTL=\'" + rabbitmqctl.getAbsolutePath() + "\'" + " RABBITMQ_NODENAME=\'" + nodenameA() + "\'" + - " RABBITMQ_NODE_PORT=" + node_portA() + - " RABBITMQ_CONFIG_FILE=\'" + config_fileA() + "\'" + + " RABBITMQ_NODE_PORT=" + node_portA() + + " RABBITMQ_CONFIG_FILE=\'" + config_fileA() + "\'" + " " + command); } From cefaef7335e07abcf0bdcdfc1d7b984b1bcce43c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Thu, 11 Aug 2016 16:42:24 +0200 Subject: [PATCH 0201/2114] RUNNING_TESTS.md: Document how to provide an external test broker [#127354185] --- RUNNING_TESTS.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/RUNNING_TESTS.md b/RUNNING_TESTS.md index 41600500cb..157b2e1ff9 100644 --- a/RUNNING_TESTS.md +++ b/RUNNING_TESTS.md @@ -148,3 +148,18 @@ Tests run: 50, Failures: 0, Errors: 0, Skipped: 0 ``` Test reports can be found in `target/failsafe-reports`. + + +## Running tests against an externally provided broker or cluster + +By default, if the RabbitMQ broker sources are available, the testsuite +starts automatically a cluster of two RabbitMQ nodes and runs the tests +against it. + +You can also provide your own broker or cluster. To disable the +automatic test cluster setup, disable the `setup-test-cluster` Maven +profile: + +``` +mvn verify -P '!setup-test-cluster' +``` From b08c8074d16b50bf0a2bf565592af0d6d57e2b90 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Mon, 15 Aug 2016 15:16:28 +0300 Subject: [PATCH 0202/2114] Nightly build script expects `make dist` to be available --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index 710cc894b4..849d5e0fc7 100644 --- a/Makefile +++ b/Makefile @@ -19,6 +19,9 @@ all: deps deps: $(DEPS_DIR)/rabbit @: +dist: + $(MVN) $(MVN_FLAGS) -DskipTests=true package + $(DEPS_DIR)/rabbit: git clone https://github.com/rabbitmq/rabbitmq-server.git $@ $(MAKE) -C $@ fetch-deps DEPS_DIR="$(abspath $(DEPS_DIR))" From bd83e848237dcdf5e55a279581b5c8345db0ff83 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Thu, 18 Aug 2016 17:02:30 +0300 Subject: [PATCH 0203/2114] Allow for higher delivery latency for CI containers --- .../com/rabbitmq/client/test/functional/DeadLetterExchange.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/src/com/rabbitmq/client/test/functional/DeadLetterExchange.java b/test/src/com/rabbitmq/client/test/functional/DeadLetterExchange.java index 354e51a8e2..5e3fb55d4a 100644 --- a/test/src/com/rabbitmq/client/test/functional/DeadLetterExchange.java +++ b/test/src/com/rabbitmq/client/test/functional/DeadLetterExchange.java @@ -575,7 +575,7 @@ private void sleep(long millis) { publication time + TTL + latency */ private void checkPromptArrival(QueueingConsumer c, int count, long latency) throws Exception { - long epsilon = TTL / 50; + long epsilon = TTL / 25; for (int i = 0; i < count; i++) { Delivery d = c.nextDelivery(TTL + TTL + latency + epsilon); assertNotNull("message #" + i + " did not expire", d); From d1c4b17a3837f32c665efc767c195a9e4f8f3267 Mon Sep 17 00:00:00 2001 From: ayoub Date: Mon, 22 Aug 2016 07:23:42 -0500 Subject: [PATCH 0204/2114] Add an ID to PerfTest output. --- src/test/java/com/rabbitmq/examples/PerfTest.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/examples/PerfTest.java b/src/test/java/com/rabbitmq/examples/PerfTest.java index e65c057ed4..1244044500 100644 --- a/src/test/java/com/rabbitmq/examples/PerfTest.java +++ b/src/test/java/com/rabbitmq/examples/PerfTest.java @@ -15,7 +15,9 @@ package com.rabbitmq.examples; +import java.text.SimpleDateFormat; import java.util.Arrays; +import java.util.Calendar; import java.util.List; import com.rabbitmq.examples.perf.MulticastParams; @@ -33,6 +35,9 @@ public class PerfTest { + + private static String testID; + public static void main(String[] args) { Options options = getOptions(); CommandLineParser parser = new GnuParser(); @@ -43,7 +48,9 @@ public static void main(String[] args) { usage(options); System.exit(0); } - + testID = new SimpleDateFormat("HH:mm:ss.SSS").format(Calendar. + getInstance().getTime()); + testID = strArg(cmd, 'd', "test-" + testID); String exchangeType = strArg(cmd, 't', "direct"); String exchangeName = strArg(cmd, 'e', exchangeType); String queueName = strArg(cmd, 'u', ""); @@ -135,6 +142,7 @@ private static void usage(Options options) { private static Options getOptions() { Options options = new Options(); options.addOption(new Option("?", "help", false,"show usage")); + options.addOption(new Option("d", "id", true, "Test ID")); options.addOption(new Option("h", "uri", true, "connection URI")); options.addOption(new Option("t", "type", true, "exchange type")); options.addOption(new Option("e", "exchange", true, "exchange name")); @@ -204,6 +212,7 @@ public PrintlnStats(long interval, @Override protected void report(long now) { + System.out.print("id: " + testID + ", "); System.out.print("time: " + String.format("%.3f", (now - startTime)/1000.0) + "s"); showRate("sent", sendCountInterval, sendStatsEnabled, elapsedInterval); From d7980da089a7717ff120d5584b4fe2138e74c13c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 22 Aug 2016 16:08:35 +0200 Subject: [PATCH 0205/2114] Add strategy interface to resolve list of hosts Issue #153. Could help for #104 and #138. --- .../com/rabbitmq/client/AddressResolver.java | 12 +++++++++ .../rabbitmq/client/ConnectionFactory.java | 27 ++++++++++++++++++- .../rabbitmq/client/ListAddressResolver.java | 20 ++++++++++++++ .../recovery/AutorecoveringConnection.java | 20 +++++--------- .../RecoveryAwareAMQConnectionFactory.java | 12 ++++++--- 5 files changed, 73 insertions(+), 18 deletions(-) create mode 100644 src/main/java/com/rabbitmq/client/AddressResolver.java create mode 100644 src/main/java/com/rabbitmq/client/ListAddressResolver.java diff --git a/src/main/java/com/rabbitmq/client/AddressResolver.java b/src/main/java/com/rabbitmq/client/AddressResolver.java new file mode 100644 index 0000000000..f16672e4b9 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/AddressResolver.java @@ -0,0 +1,12 @@ +package com.rabbitmq.client; + +import java.util.List; + +/** + * Strategy interface to get the potential servers to connect to. + */ +public interface AddressResolver { + + List
getAddresses(); + +} diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index a0251f1b7c..868768b7be 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -801,6 +801,30 @@ public Connection newConnection(ExecutorService executor, List
addrs) t */ public Connection newConnection(ExecutorService executor, List
addrs, String clientProvidedName) throws IOException, TimeoutException { + return newConnection(executor, new ListAddressResolver(addrs), clientProvidedName); + } + + /** + * Create a new broker connection with a client-provided name, picking the first available address from + * the list provided by the {@link AddressResolver}. + * + * If automatic connection recovery + * is enabled, the connection returned by this method will be {@link Recoverable}. Future + * reconnection attempts will pick a random accessible address provided by the {@link AddressResolver}. + * + * @param executor thread execution service for consumers on the connection + * @param addressResolver discovery service to list potential addresses (hostname/port pairs) to connect to + * @param clientProvidedName application-specific connection name, will be displayed + * in the management UI if RabbitMQ server supports it. + * This value doesn't have to be unique and cannot be used + * as a connection identifier e.g. in HTTP API requests. + * This value is supposed to be human-readable. + * @return + * @throws IOException + * @throws TimeoutException + */ + public Connection newConnection(ExecutorService executor, AddressResolver addressResolver, String clientProvidedName) + throws IOException, TimeoutException { // make sure we respect the provided thread factory FrameHandlerFactory fhFactory = createFrameHandlerFactory(); ConnectionParams params = params(executor); @@ -813,11 +837,12 @@ public Connection newConnection(ExecutorService executor, List
addrs, S if (isAutomaticRecoveryEnabled()) { // see com.rabbitmq.client.impl.recovery.RecoveryAwareAMQConnectionFactory#newConnection - AutorecoveringConnection conn = new AutorecoveringConnection(params, fhFactory, addrs); + AutorecoveringConnection conn = new AutorecoveringConnection(params, fhFactory, addressResolver); conn.init(); return conn; } else { + List
addrs = addressResolver.getAddresses(); IOException lastException = null; for (Address addr : addrs) { try { diff --git a/src/main/java/com/rabbitmq/client/ListAddressResolver.java b/src/main/java/com/rabbitmq/client/ListAddressResolver.java new file mode 100644 index 0000000000..5dc0c70a58 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/ListAddressResolver.java @@ -0,0 +1,20 @@ +package com.rabbitmq.client; + +import java.util.List; + +/** + * Simple implementation of {@link AddressResolver} that returns a fixed list. + */ +public class ListAddressResolver implements AddressResolver { + + private final List
addresses; + + public ListAddressResolver(List
addresses) { + this.addresses = addresses; + } + + @Override + public List
getAddresses() { + return addresses; + } +} diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index 99c331e699..aac212b683 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -15,21 +15,9 @@ package com.rabbitmq.client.impl.recovery; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.Address; -import com.rabbitmq.client.BlockedListener; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.ConnectionFactory; -import com.rabbitmq.client.MissedHeartbeatException; -import com.rabbitmq.client.Recoverable; -import com.rabbitmq.client.RecoveryListener; -import com.rabbitmq.client.ShutdownListener; -import com.rabbitmq.client.ShutdownSignalException; -import com.rabbitmq.client.TopologyRecoveryException; +import com.rabbitmq.client.*; import com.rabbitmq.client.impl.AMQConnection; import com.rabbitmq.client.impl.ConnectionParams; -import com.rabbitmq.client.ExceptionHandler; import com.rabbitmq.client.impl.FrameHandlerFactory; import com.rabbitmq.client.impl.NetworkConnection; @@ -94,7 +82,11 @@ public class AutorecoveringConnection implements Connection, Recoverable, Networ private final Object recoveryLock = new Object(); public AutorecoveringConnection(ConnectionParams params, FrameHandlerFactory f, List
addrs) { - this.cf = new RecoveryAwareAMQConnectionFactory(params, f, addrs); + this(params, f, new ListAddressResolver(addrs)); + } + + public AutorecoveringConnection(ConnectionParams params, FrameHandlerFactory f, AddressResolver addressResolver) { + this.cf = new RecoveryAwareAMQConnectionFactory(params, f, addressResolver); this.params = params; this.channels = new ConcurrentHashMap(); diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java index d4e87fbf1c..5c8c6250dd 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java @@ -16,6 +16,8 @@ package com.rabbitmq.client.impl.recovery; import com.rabbitmq.client.Address; +import com.rabbitmq.client.AddressResolver; +import com.rabbitmq.client.ListAddressResolver; import com.rabbitmq.client.impl.ConnectionParams; import com.rabbitmq.client.impl.FrameHandler; import com.rabbitmq.client.impl.FrameHandlerFactory; @@ -29,12 +31,16 @@ public class RecoveryAwareAMQConnectionFactory { private final ConnectionParams params; private final FrameHandlerFactory factory; - private final List
addrs; + private final AddressResolver addressResolver; public RecoveryAwareAMQConnectionFactory(ConnectionParams params, FrameHandlerFactory factory, List
addrs) { + this(params, factory, new ListAddressResolver(addrs)); + } + + public RecoveryAwareAMQConnectionFactory(ConnectionParams params, FrameHandlerFactory factory, AddressResolver addressResolver) { this.params = params; this.factory = factory; - this.addrs = addrs; + this.addressResolver = addressResolver; } /** @@ -43,7 +49,7 @@ public RecoveryAwareAMQConnectionFactory(ConnectionParams params, FrameHandlerFa */ RecoveryAwareAMQConnection newConnection() throws IOException, TimeoutException { IOException lastException = null; - List
shuffled = shuffle(addrs); + List
shuffled = shuffle(addressResolver.getAddresses()); for (Address addr : shuffled) { try { From 7fa68ec2c34ad63eb9e9c089d6c1a680aace18bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 22 Aug 2016 16:49:40 +0200 Subject: [PATCH 0206/2114] Add 2 constructors with AddressResolver parameter Issue #153 --- .../rabbitmq/client/ConnectionFactory.java | 41 +++++++++++++++++-- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 868768b7be..3743d200ba 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -661,6 +661,23 @@ public Connection newConnection(Address[] addrs) throws IOException, TimeoutExce return newConnection(this.sharedExecutor, Arrays.asList(addrs), null); } + /** + * Create a new broker connection, picking the first available address from + * the list provided by the {@link AddressResolver}. + * + * If automatic connection recovery + * is enabled, the connection returned by this method will be {@link Recoverable}. Future + * reconnection attempts will pick a random accessible address provided by the {@link AddressResolver}. + * + * @param addressResolver discovery service to list potential addresses (hostname/port pairs) to connect to + * @return an interface to the connection + * @throws IOException if it encounters a problem + * @see Automatic Recovery + */ + public Connection newConnection(AddressResolver addressResolver) throws IOException, TimeoutException { + return newConnection(this.sharedExecutor, addressResolver, null); + } + /** * Create a new broker connection with a client-provided name, picking the first available address from @@ -780,6 +797,24 @@ public Connection newConnection(ExecutorService executor, List
addrs) t return newConnection(executor, addrs, null); } + /** + * Create a new broker connection, picking the first available address from + * the list provided by the {@link AddressResolver}. + * + * If automatic connection recovery + * is enabled, the connection returned by this method will be {@link Recoverable}. Future + * reconnection attempts will pick a random accessible address provided by the {@link AddressResolver}. + * + * @param executor thread execution service for consumers on the connection + * @param addressResolver discovery service to list potential addresses (hostname/port pairs) to connect to + * @return an interface to the connection + * @throws java.io.IOException if it encounters a problem + * @see Automatic Recovery + */ + public Connection newConnection(ExecutorService executor, AddressResolver addressResolver) throws IOException, TimeoutException { + return newConnection(executor, addressResolver, null); + } + /** * Create a new broker connection with a client-provided name, picking the first available address from * the list. @@ -819,9 +854,9 @@ public Connection newConnection(ExecutorService executor, List
addrs, S * This value doesn't have to be unique and cannot be used * as a connection identifier e.g. in HTTP API requests. * This value is supposed to be human-readable. - * @return - * @throws IOException - * @throws TimeoutException + * @return an interface to the connection + * @throws java.io.IOException if it encounters a problem + * @see Automatic Recovery */ public Connection newConnection(ExecutorService executor, AddressResolver addressResolver, String clientProvidedName) throws IOException, TimeoutException { From 6d44cbf4553b2f2dccb5d6019d5c245ac1ae56ce Mon Sep 17 00:00:00 2001 From: ayoub Date: Mon, 22 Aug 2016 11:22:23 -0500 Subject: [PATCH 0207/2114] Update test ID declaration. --- .../java/com/rabbitmq/examples/PerfTest.java | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/test/java/com/rabbitmq/examples/PerfTest.java b/src/test/java/com/rabbitmq/examples/PerfTest.java index 1244044500..5a177a2aac 100644 --- a/src/test/java/com/rabbitmq/examples/PerfTest.java +++ b/src/test/java/com/rabbitmq/examples/PerfTest.java @@ -36,8 +36,6 @@ public class PerfTest { - private static String testID; - public static void main(String[] args) { Options options = getOptions(); CommandLineParser parser = new GnuParser(); @@ -48,9 +46,9 @@ public static void main(String[] args) { usage(options); System.exit(0); } - testID = new SimpleDateFormat("HH:mm:ss.SSS").format(Calendar. + String testID = new SimpleDateFormat("HHmmss-SSS").format(Calendar. getInstance().getTime()); - testID = strArg(cmd, 'd', "test-" + testID); + testID = strArg(cmd, 'd', "test-"+testID); String exchangeType = strArg(cmd, 't', "direct"); String exchangeName = strArg(cmd, 'e', exchangeType); String queueName = strArg(cmd, 'u', ""); @@ -80,12 +78,13 @@ public static void main(String[] args) { String uri = strArg(cmd, 'h', "amqp://localhost"); //setup - PrintlnStats stats = new PrintlnStats(1000L * samplingInterval, - producerCount > 0, - consumerCount > 0, - (flags.contains("mandatory") || - flags.contains("immediate")), - confirm != -1); + PrintlnStats stats = new PrintlnStats(testID, + 1000L * samplingInterval, + producerCount > 0, + consumerCount > 0, + (flags.contains("mandatory") || + flags.contains("immediate")), + confirm != -1); ConnectionFactory factory = new ConnectionFactory(); factory.setShutdownTimeout(0); // So we still shut down even with slow consumers @@ -199,8 +198,10 @@ private static class PrintlnStats extends Stats { private final boolean recvStatsEnabled; private final boolean returnStatsEnabled; private final boolean confirmStatsEnabled; + + private final String testID; - public PrintlnStats(long interval, + public PrintlnStats(String testID, long interval, boolean sendStatsEnabled, boolean recvStatsEnabled, boolean returnStatsEnabled, boolean confirmStatsEnabled) { super(interval); @@ -208,11 +209,13 @@ public PrintlnStats(long interval, this.recvStatsEnabled = recvStatsEnabled; this.returnStatsEnabled = returnStatsEnabled; this.confirmStatsEnabled = confirmStatsEnabled; + this.testID = testID; } @Override protected void report(long now) { System.out.print("id: " + testID + ", "); + System.out.print("time: " + String.format("%.3f", (now - startTime)/1000.0) + "s"); showRate("sent", sendCountInterval, sendStatsEnabled, elapsedInterval); From e57d3f039b55eca2748e7509699e19e8a5a1a740 Mon Sep 17 00:00:00 2001 From: ayoub Date: Mon, 22 Aug 2016 11:46:44 -0500 Subject: [PATCH 0208/2114] Update PerfTest System.out. --- .../java/com/rabbitmq/examples/PerfTest.java | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/test/java/com/rabbitmq/examples/PerfTest.java b/src/test/java/com/rabbitmq/examples/PerfTest.java index 5a177a2aac..4e44c2bf89 100644 --- a/src/test/java/com/rabbitmq/examples/PerfTest.java +++ b/src/test/java/com/rabbitmq/examples/PerfTest.java @@ -214,31 +214,32 @@ public PrintlnStats(String testID, long interval, @Override protected void report(long now) { - System.out.print("id: " + testID + ", "); + String output = "id: " + testID + ", "; - System.out.print("time: " + String.format("%.3f", (now - startTime)/1000.0) + "s"); + output += "time: " + String.format("%.3f", (now - startTime)/1000.0) + "s"; + output += + showRate("sent", sendCountInterval, sendStatsEnabled, elapsedInterval) + + showRate("returned", returnCountInterval, sendStatsEnabled && returnStatsEnabled, elapsedInterval) + + showRate("confirmed", confirmCountInterval, sendStatsEnabled && confirmStatsEnabled, elapsedInterval) + + showRate("nacked", nackCountInterval, sendStatsEnabled && confirmStatsEnabled, elapsedInterval) + + showRate("received", recvCountInterval, recvStatsEnabled, elapsedInterval); - showRate("sent", sendCountInterval, sendStatsEnabled, elapsedInterval); - showRate("returned", returnCountInterval, sendStatsEnabled && returnStatsEnabled, elapsedInterval); - showRate("confirmed", confirmCountInterval, sendStatsEnabled && confirmStatsEnabled, elapsedInterval); - showRate("nacked", nackCountInterval, sendStatsEnabled && confirmStatsEnabled, elapsedInterval); - showRate("received", recvCountInterval, recvStatsEnabled, elapsedInterval); - - System.out.print((latencyCountInterval > 0 ? + output += (latencyCountInterval > 0 ? ", min/avg/max latency: " + minLatency/1000L + "/" + cumulativeLatencyInterval / (1000L * latencyCountInterval) + "/" + maxLatency/1000L + " microseconds" : - "")); + ""); - System.out.println(); + System.out.println(output); } - private void showRate(String descr, long count, boolean display, + private String showRate(String descr, long count, boolean display, long elapsed) { - if (display) { - System.out.print(", " + descr + ": " + formatRate(1000.0 * count / elapsed) + " msg/s"); - } + if (display) + return ", " + descr + ": " + formatRate(1000.0 * count / elapsed) + " msg/s"; + else + return ""; } public void printFinal() { From 686a033ef88b3f4b95176e1f610950852835b093 Mon Sep 17 00:00:00 2001 From: ayoub Date: Tue, 23 Aug 2016 04:55:30 -0500 Subject: [PATCH 0209/2114] Correction of an identation mistake. --- src/test/java/com/rabbitmq/examples/PerfTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/examples/PerfTest.java b/src/test/java/com/rabbitmq/examples/PerfTest.java index 4e44c2bf89..dec52632bb 100644 --- a/src/test/java/com/rabbitmq/examples/PerfTest.java +++ b/src/test/java/com/rabbitmq/examples/PerfTest.java @@ -48,7 +48,7 @@ public static void main(String[] args) { } String testID = new SimpleDateFormat("HHmmss-SSS").format(Calendar. getInstance().getTime()); - testID = strArg(cmd, 'd', "test-"+testID); + testID = strArg(cmd, 'd', "test-"+testID); String exchangeType = strArg(cmd, 't', "direct"); String exchangeName = strArg(cmd, 'e', exchangeType); String queueName = strArg(cmd, 'u', ""); From a39953f4242bf76e1ebf34b88f98138c9eeea66b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Thu, 11 Aug 2016 16:32:50 +0200 Subject: [PATCH 0210/2114] Switch from Ant to Maven This is a backport of what was done in the `master` branch, starting with commit c2cd9f3fc342077b963bc2a0a9b5f5948e1ec1db. Fixes #166. [#128048833] --- .gitignore | 16 +- Makefile | 93 +-- README.md | 4 +- RUNNING_TESTS.md | 190 +++-- build.properties | 23 - build.xml | 530 -------------- ...com.springsource.bundlor-1.0.0.RELEASE.jar | Bin 133712 -> 0 bytes ...springsource.bundlor.ant-1.0.0.RELEASE.jar | Bin 17007 -> 0 bytes ...ringsource.bundlor.blint-1.0.0.RELEASE.jar | Bin 13577 -> 0 bytes ...urce.bundlor.commandline-1.0.0.RELEASE.jar | Bin 13838 -> 0 bytes ...ingsource.org.apache.commons.cli-1.2.0.jar | Bin 41571 -> 0 bytes ...m.springsource.org.objectweb.asm-3.1.0.jar | Bin 43557 -> 0 bytes ...source.org.objectweb.asm.commons-3.1.0.jar | Bin 33255 -> 0 bytes ...ingsource.org.objectweb.asm.tree-3.1.0.jar | Bin 22502 -> 0 bytes ...springsource.util.common-2.0.0.RELEASE.jar | Bin 42376 -> 0 bytes ...m.springsource.util.math-2.0.0.RELEASE.jar | Bin 8384 -> 0 bytes ...m.springsource.util.osgi-2.0.0.RELEASE.jar | Bin 94153 -> 0 bytes ...rce.util.parser.manifest-2.0.0.RELEASE.jar | Bin 24242 -> 0 bytes bundlor/lib/org.osgi.core-4.1.0.jar | Bin 163485 -> 0 bytes bundlorTemplate.mf | 7 - bundlorTestTemplate.mf | 11 - lib/commons-cli-1.1.jar | Bin 36174 -> 0 bytes lib/commons-io-1.2.jar | Bin 65621 -> 0 bytes lib/hamcrest-core.jar | Bin 45024 -> 0 bytes lib/junit.jar | Bin 314932 -> 0 bytes nexus-upload.sh | 28 - pom.xml | 683 +++++++++++++++++- scripts/PerfTest | 14 + .../java}/com/rabbitmq/client/Address.java | 0 .../client/AlreadyClosedException.java | 0 .../AuthenticationFailureException.java | 0 .../com/rabbitmq/client/BasicProperties.java | 0 .../com/rabbitmq/client/BlockedListener.java | 0 .../java}/com/rabbitmq/client/Channel.java | 0 .../java}/com/rabbitmq/client/Command.java | 0 .../com/rabbitmq/client/ConfirmListener.java | 0 .../java}/com/rabbitmq/client/Connection.java | 0 .../rabbitmq/client/ConnectionFactory.java | 0 .../java}/com/rabbitmq/client/Consumer.java | 0 .../client/ConsumerCancelledException.java | 0 .../com/rabbitmq/client/ContentHeader.java | 0 .../com/rabbitmq/client/DefaultConsumer.java | 0 .../rabbitmq/client/DefaultSaslConfig.java | 0 .../client/DefaultSocketConfigurator.java | 0 .../java}/com/rabbitmq/client/Envelope.java | 0 .../com/rabbitmq/client/ExceptionHandler.java | 0 .../com/rabbitmq/client/FlowListener.java | 0 .../com/rabbitmq/client/GetResponse.java | 0 .../com/rabbitmq/client/JDKSaslConfig.java | 0 .../java}/com/rabbitmq/client/LongString.java | 0 .../client/MalformedFrameException.java | 0 .../com/rabbitmq/client/MapRpcServer.java | 0 .../rabbitmq/client/MessageProperties.java | 0 .../java}/com/rabbitmq/client/Method.java | 0 .../client/MissedHeartbeatException.java | 0 .../com/rabbitmq/client/NullTrustManager.java | 0 ...ossibleAuthenticationFailureException.java | 0 .../ProtocolVersionMismatchException.java | 0 .../com/rabbitmq/client/QueueingConsumer.java | 0 .../com/rabbitmq/client/Recoverable.java | 0 .../com/rabbitmq/client/RecoveryListener.java | 0 .../com/rabbitmq/client/ReturnListener.java | 0 .../java}/com/rabbitmq/client/RpcClient.java | 0 .../java}/com/rabbitmq/client/RpcServer.java | 0 .../java}/com/rabbitmq/client/SaslConfig.java | 0 .../com/rabbitmq/client/SaslMechanism.java | 0 .../com/rabbitmq/client/ShutdownListener.java | 0 .../com/rabbitmq/client/ShutdownNotifier.java | 0 .../client/ShutdownSignalException.java | 0 .../rabbitmq/client/SocketConfigurator.java | 0 .../com/rabbitmq/client/StringRpcServer.java | 0 .../client/TopologyRecoveryException.java | 0 .../rabbitmq/client/UnexpectedFrameError.java | 0 .../client/UnexpectedMethodError.java | 0 .../client/UnknownClassOrMethodId.java | 0 .../client/impl/AMQBasicProperties.java | 0 .../com/rabbitmq/client/impl/AMQChannel.java | 0 .../com/rabbitmq/client/impl/AMQCommand.java | 0 .../rabbitmq/client/impl/AMQConnection.java | 0 .../client/impl/AMQContentHeader.java | 0 .../rabbitmq/client/impl/CRDemoMechanism.java | 0 .../rabbitmq/client/impl/ChannelManager.java | 0 .../com/rabbitmq/client/impl/ChannelN.java | 0 .../rabbitmq/client/impl/ClientVersion.java} | 18 +- .../client/impl/CommandAssembler.java | 0 .../client/impl/ConnectionParams.java | 0 .../client/impl/ConsumerDispatcher.java | 0 .../client/impl/ConsumerWorkService.java | 0 .../impl/ContentHeaderPropertyReader.java | 0 .../impl/ContentHeaderPropertyWriter.java | 0 .../client/impl/DefaultExceptionHandler.java | 0 .../com/rabbitmq/client/impl/Environment.java | 0 .../client/impl/ExternalMechanism.java | 0 .../impl/ForgivingExceptionHandler.java | 0 .../java}/com/rabbitmq/client/impl/Frame.java | 0 .../rabbitmq/client/impl/FrameHandler.java | 0 .../client/impl/FrameHandlerFactory.java | 0 .../rabbitmq/client/impl/HeartbeatSender.java | 0 .../client/impl/LongStringHelper.java | 0 .../com/rabbitmq/client/impl/Method.java | 0 .../client/impl/MethodArgumentReader.java | 0 .../client/impl/MethodArgumentWriter.java | 0 .../client/impl/NetworkConnection.java | 0 .../rabbitmq/client/impl/PlainMechanism.java | 0 .../com/rabbitmq/client/impl/SetQueue.java | 0 .../impl/ShutdownNotifierComponent.java | 0 .../client/impl/SocketFrameHandler.java | 0 .../client/impl/StrictExceptionHandler.java | 0 .../client/impl/TruncatedInputStream.java | 0 .../client/impl/UnknownChannelException.java | 0 .../com/rabbitmq/client/impl/ValueReader.java | 0 .../com/rabbitmq/client/impl/ValueWriter.java | 0 .../impl/VariableLinkedBlockingQueue.java | 0 .../com/rabbitmq/client/impl/Version.java | 0 .../com/rabbitmq/client/impl/WorkPool.java | 0 .../com/rabbitmq/client/impl/package.html | 0 .../impl/recovery/AutorecoveringChannel.java | 0 .../recovery/AutorecoveringConnection.java | 0 .../recovery/ConsumerRecoveryListener.java | 0 .../impl/recovery/QueueRecoveryListener.java | 0 .../client/impl/recovery/RecordedBinding.java | 0 .../impl/recovery/RecordedConsumer.java | 0 .../client/impl/recovery/RecordedEntity.java | 0 .../impl/recovery/RecordedExchange.java | 0 .../recovery/RecordedExchangeBinding.java | 0 .../impl/recovery/RecordedNamedEntity.java | 0 .../client/impl/recovery/RecordedQueue.java | 0 .../impl/recovery/RecordedQueueBinding.java | 0 .../recovery/RecoveryAwareAMQConnection.java | 0 .../RecoveryAwareAMQConnectionFactory.java | 0 .../recovery/RecoveryAwareChannelManager.java | 0 .../impl/recovery/RecoveryAwareChannelN.java | 0 .../java}/com/rabbitmq/client/package.html | 0 .../java}/com/rabbitmq/tools/Tracer.java | 0 .../com/rabbitmq/tools/json/JSONReader.java | 0 .../rabbitmq/tools/json/JSONSerializable.java | 0 .../com/rabbitmq/tools/json/JSONUtil.java | 0 .../com/rabbitmq/tools/json/JSONWriter.java | 0 .../com/rabbitmq/tools/json/package.html | 0 .../rabbitmq/tools/jsonrpc/JsonRpcClient.java | 0 .../tools/jsonrpc/JsonRpcException.java | 0 .../rabbitmq/tools/jsonrpc/JsonRpcServer.java | 0 .../tools/jsonrpc/ParameterDescription.java | 0 .../tools/jsonrpc/ProcedureDescription.java | 0 .../tools/jsonrpc/ServiceDescription.java | 0 .../com/rabbitmq/tools/jsonrpc/package.html | 0 .../java}/com/rabbitmq/tools/package.html | 0 .../com/rabbitmq/utility/BlockingCell.java | 0 .../utility/BlockingValueOrException.java | 0 .../com/rabbitmq/utility/IntAllocator.java | 0 .../com/rabbitmq/utility/SensibleClone.java | 0 .../utility/SingleShotLinearTimer.java | 0 .../java}/com/rabbitmq/utility/Utility.java | 0 .../rabbitmq/utility/ValueOrException.java | 0 .../java}/com/rabbitmq/utility/package.html | 0 src/main/resources/version.properties | 1 + src/main/scripts/generate_amqp_sources.groovy | 60 ++ src/main/scripts/manage_test_broker.groovy | 65 ++ .../scripts/query_test_tls_certs_dir.groovy | 25 + .../scripts/remove_old_test_keystores.groovy | 8 + .../rabbitmq/client/impl/WorkPoolTests.java | 0 .../client/test/AMQBuilderApiTest.java | 0 .../client/test/AMQConnectionTest.java | 0 .../client/test/AbstractRMQTestSuite.java | 126 ++++ .../com/rabbitmq/client/test/AmqpUriTest.java | 0 .../client/test/BlockingCellTest.java | 0 .../client/test/BrokenFramesTest.java | 0 .../rabbitmq/client/test/BrokerTestCase.java | 3 +- .../rabbitmq/client/test/Bug20004Test.java | 0 .../test/ChannelNumberAllocationTests.java | 0 .../com/rabbitmq/client/test/ClientTests.java | 4 +- .../client/test/ClonePropertiesTest.java | 0 .../rabbitmq/client/test/CloseInMainLoop.java | 0 .../com/rabbitmq/client/test/ConfirmBase.java | 0 .../client/test/JSONReadWriteTest.java | 0 .../rabbitmq/client/test/LongStringTest.java | 0 .../client/test/MultiThreadedChannel.java | 0 .../test/QueueingConsumerShutdownTests.java | 0 .../client/test/SharedThreadPoolTest.java | 0 .../com/rabbitmq/client/test/TableTest.java | 0 .../client/test/TruncatedInputStreamTest.java | 0 .../client/test/ValueOrExceptionTest.java | 0 .../test/functional/AbstractRejectTest.java | 0 .../test/functional/AlternateExchange.java | 0 .../client/test/functional/BasicGet.java | 0 .../test/functional/BindingLifecycle.java | 0 .../test/functional/BindingLifecycleBase.java | 0 .../client/test/functional/CcRoutes.java | 0 .../test/functional/ClusteredTestBase.java | 4 +- .../client/test/functional/Confirm.java | 0 .../test/functional/ConnectionOpen.java | 0 .../test/functional/ConnectionRecovery.java | 0 .../ConsumerCancelNotification.java | 0 .../client/test/functional/ConsumerCount.java | 0 .../test/functional/ConsumerPriorities.java | 0 .../test/functional/DeadLetterExchange.java | 0 .../test/functional/DefaultExchange.java | 0 .../client/test/functional/DirectReplyTo.java | 0 .../test/functional/DoubleDeletion.java | 0 .../test/functional/DurableOnTransient.java | 0 .../test/functional/ExceptionHandling.java | 0 .../test/functional/ExceptionMessages.java | 0 .../test/functional/ExchangeDeclare.java | 0 .../functional/ExchangeDeleteIfUnused.java | 0 .../functional/ExchangeDeletePredeclared.java | 0 .../functional/ExchangeEquivalenceBase.java | 0 .../functional/ExchangeExchangeBindings.java | 0 .../ExchangeExchangeBindingsAutoDelete.java | 0 .../client/test/functional/FrameMax.java | 0 .../test/functional/FunctionalTests.java | 4 +- .../functional/HeadersExchangeValidation.java | 0 .../client/test/functional/Heartbeat.java | 0 .../test/functional/InternalExchange.java | 0 .../client/test/functional/InvalidAcks.java | 0 .../test/functional/InvalidAcksBase.java | 0 .../client/test/functional/InvalidAcksTx.java | 0 .../client/test/functional/MessageCount.java | 0 .../rabbitmq/client/test/functional/Nack.java | 0 .../test/functional/NoRequeueOnCancel.java | 0 .../client/test/functional/Nowait.java | 0 .../test/functional/PerConsumerPrefetch.java | 0 .../client/test/functional/PerMessageTTL.java | 0 .../client/test/functional/PerQueueTTL.java | 0 .../functional/PerQueueVsPerMessageTTL.java | 0 .../client/test/functional/Policies.java | 0 .../client/test/functional/QosTests.java | 0 .../test/functional/QueueExclusivity.java | 0 .../client/test/functional/QueueLease.java | 0 .../test/functional/QueueLifecycle.java | 0 .../test/functional/QueueSizeLimit.java | 0 .../client/test/functional/Recover.java | 0 .../client/test/functional/Reject.java | 0 .../functional/RequeueOnChannelClose.java | 0 .../test/functional/RequeueOnClose.java | 0 .../functional/RequeueOnConnectionClose.java | 0 .../client/test/functional/Routing.java | 0 .../test/functional/SaslMechanisms.java | 0 .../client/test/functional/TTLHandling.java | 0 .../client/test/functional/Tables.java | 0 .../client/test/functional/Transactions.java | 0 .../functional/UnbindAutoDeleteExchange.java | 0 .../test/functional/UnexpectedFrames.java | 0 .../client/test/functional/UserIDHeader.java | 0 .../client/test/performance/CLIHelper.java | 0 .../client/test/performance/QosScaling.java | 0 .../test/performance/ScalabilityTest.java | 0 .../test/performance/StressManagement.java | 0 .../client/test/server/AbsentQueue.java | 0 .../server/AlternateExchangeEquivalence.java | 0 .../client/test/server/BlockedConnection.java | 0 .../client/test/server/Bug19219Test.java | 0 .../test/server/ChannelLimitNegotiation.java | 0 .../server/DeadLetterExchangeDurable.java | 4 +- .../test/server/DurableBindingLifecycle.java | 8 +- .../server/EffectVisibilityCrossNodeTest.java | 0 .../test/server/ExclusiveQueueDurability.java | 0 .../rabbitmq/client/test/server/Firehose.java | 0 .../rabbitmq/client/test/server/HATests.java | 13 +- .../client/test/server/LoopbackUsers.java | 0 .../client/test/server/MemoryAlarms.java | 0 .../client/test/server/MessageRecovery.java | 0 .../client/test/server/Permissions.java | 0 .../test/server/PersistenceGuarantees.java | 0 .../client/test/server/PriorityQueues.java | 0 .../client/test/server/ServerTests.java | 7 +- .../rabbitmq/client/test/server/Shutdown.java | 0 .../test/server/XDeathHeaderGrowth.java | 0 .../test/ssl/BadVerifiedConnection.java | 8 +- .../rabbitmq/client/test/ssl/SSLTests.java | 8 +- .../client/test/ssl/UnverifiedConnection.java | 0 .../client/test/ssl/VerifiedConnection.java | 8 +- .../examples/BufferPerformanceMetrics.java | 0 .../examples/ChannelCreationPerformance.java | 0 .../examples/ConfirmDontLoseMessages.java | 0 .../com/rabbitmq/examples/ConsumerMain.java | 0 .../examples/DirectReplyToPerformance.java | 0 .../com/rabbitmq/examples/FileConsumer.java | 0 .../com/rabbitmq/examples/FileProducer.java | 0 .../com/rabbitmq/examples/HelloClient.java | 0 .../rabbitmq/examples/HelloJsonClient.java | 0 .../rabbitmq/examples/HelloJsonServer.java | 0 .../rabbitmq/examples/HelloJsonService.java | 0 .../com/rabbitmq/examples/HelloServer.java | 0 .../java}/com/rabbitmq/examples/LogTail.java | 0 .../com/rabbitmq/examples/MulticastMain.java | 0 .../rabbitmq/examples/PerQueueTTLGetter.java | 0 .../examples/PerQueueTTLPublisher.java | 0 .../java}/com/rabbitmq/examples/PerfTest.java | 0 .../com/rabbitmq/examples/PerfTestMulti.java | 0 .../com/rabbitmq/examples/ProducerMain.java | 0 .../com/rabbitmq/examples/SendString.java | 0 .../com/rabbitmq/examples/SimpleConsumer.java | 0 .../com/rabbitmq/examples/SimpleProducer.java | 0 .../examples/SimpleTopicConsumer.java | 0 .../examples/SimpleTopicProducer.java | 0 .../examples/SpammyTopicProducer.java | 0 .../rabbitmq/examples/StressPersister.java | 0 .../java}/com/rabbitmq/examples/TestMain.java | 46 +- .../examples/TracerConcurrencyTest.java | 0 .../com/rabbitmq/examples/perf/Broker.java | 0 .../rabbitmq/examples/perf/BrokerValue.java | 0 .../examples/perf/BrokerVariable.java | 0 .../com/rabbitmq/examples/perf/Consumer.java | 0 .../examples/perf/MulticastParams.java | 0 .../rabbitmq/examples/perf/MulticastSet.java | 0 .../examples/perf/MulticastValue.java | 0 .../examples/perf/MulticastVariable.java | 0 .../com/rabbitmq/examples/perf/PerfUtil.java | 0 .../com/rabbitmq/examples/perf/Producer.java | 0 .../examples/perf/ProducerConsumerBase.java | 0 .../examples/perf/RateVsLatencyScenario.java | 0 .../com/rabbitmq/examples/perf/Scenario.java | 0 .../examples/perf/ScenarioFactory.java | 0 .../rabbitmq/examples/perf/ScenarioStats.java | 0 .../examples/perf/SimpleScenario.java | 0 .../examples/perf/SimpleScenarioStats.java | 0 .../com/rabbitmq/examples/perf/Stats.java | 0 .../com/rabbitmq/examples/perf/Variable.java | 0 .../rabbitmq/examples/perf/VariableValue.java | 0 .../examples/perf/VaryingScenario.java | 0 .../examples/perf/VaryingScenarioStats.java | 0 .../test/java}/com/rabbitmq/tools/Host.java | 55 +- .../rabbitmq/utility/IntAllocatorTests.java | 0 .../test/resources/config.properties | 1 + src/test/resources/hare@localhost.config | 15 + src/test/resources/rabbit@localhost.config | 15 + 326 files changed, 1300 insertions(+), 805 deletions(-) delete mode 100644 build.properties delete mode 100644 build.xml delete mode 100644 bundlor/dist/com.springsource.bundlor-1.0.0.RELEASE.jar delete mode 100644 bundlor/dist/com.springsource.bundlor.ant-1.0.0.RELEASE.jar delete mode 100644 bundlor/dist/com.springsource.bundlor.blint-1.0.0.RELEASE.jar delete mode 100644 bundlor/dist/com.springsource.bundlor.commandline-1.0.0.RELEASE.jar delete mode 100644 bundlor/lib/com.springsource.org.apache.commons.cli-1.2.0.jar delete mode 100644 bundlor/lib/com.springsource.org.objectweb.asm-3.1.0.jar delete mode 100644 bundlor/lib/com.springsource.org.objectweb.asm.commons-3.1.0.jar delete mode 100644 bundlor/lib/com.springsource.org.objectweb.asm.tree-3.1.0.jar delete mode 100644 bundlor/lib/com.springsource.util.common-2.0.0.RELEASE.jar delete mode 100644 bundlor/lib/com.springsource.util.math-2.0.0.RELEASE.jar delete mode 100644 bundlor/lib/com.springsource.util.osgi-2.0.0.RELEASE.jar delete mode 100644 bundlor/lib/com.springsource.util.parser.manifest-2.0.0.RELEASE.jar delete mode 100644 bundlor/lib/org.osgi.core-4.1.0.jar delete mode 100644 bundlorTemplate.mf delete mode 100644 bundlorTestTemplate.mf delete mode 100644 lib/commons-cli-1.1.jar delete mode 100644 lib/commons-io-1.2.jar delete mode 100644 lib/hamcrest-core.jar delete mode 100644 lib/junit.jar delete mode 100755 nexus-upload.sh create mode 100755 scripts/PerfTest rename src/{ => main/java}/com/rabbitmq/client/Address.java (100%) rename src/{ => main/java}/com/rabbitmq/client/AlreadyClosedException.java (100%) rename src/{ => main/java}/com/rabbitmq/client/AuthenticationFailureException.java (100%) rename src/{ => main/java}/com/rabbitmq/client/BasicProperties.java (100%) rename src/{ => main/java}/com/rabbitmq/client/BlockedListener.java (100%) rename src/{ => main/java}/com/rabbitmq/client/Channel.java (100%) rename src/{ => main/java}/com/rabbitmq/client/Command.java (100%) rename src/{ => main/java}/com/rabbitmq/client/ConfirmListener.java (100%) rename src/{ => main/java}/com/rabbitmq/client/Connection.java (100%) rename src/{ => main/java}/com/rabbitmq/client/ConnectionFactory.java (100%) rename src/{ => main/java}/com/rabbitmq/client/Consumer.java (100%) rename src/{ => main/java}/com/rabbitmq/client/ConsumerCancelledException.java (100%) rename src/{ => main/java}/com/rabbitmq/client/ContentHeader.java (100%) rename src/{ => main/java}/com/rabbitmq/client/DefaultConsumer.java (100%) rename src/{ => main/java}/com/rabbitmq/client/DefaultSaslConfig.java (100%) rename src/{ => main/java}/com/rabbitmq/client/DefaultSocketConfigurator.java (100%) rename src/{ => main/java}/com/rabbitmq/client/Envelope.java (100%) rename src/{ => main/java}/com/rabbitmq/client/ExceptionHandler.java (100%) rename src/{ => main/java}/com/rabbitmq/client/FlowListener.java (100%) rename src/{ => main/java}/com/rabbitmq/client/GetResponse.java (100%) rename src/{ => main/java}/com/rabbitmq/client/JDKSaslConfig.java (100%) rename src/{ => main/java}/com/rabbitmq/client/LongString.java (100%) rename src/{ => main/java}/com/rabbitmq/client/MalformedFrameException.java (100%) rename src/{ => main/java}/com/rabbitmq/client/MapRpcServer.java (100%) rename src/{ => main/java}/com/rabbitmq/client/MessageProperties.java (100%) rename src/{ => main/java}/com/rabbitmq/client/Method.java (100%) rename src/{ => main/java}/com/rabbitmq/client/MissedHeartbeatException.java (100%) rename src/{ => main/java}/com/rabbitmq/client/NullTrustManager.java (100%) rename src/{ => main/java}/com/rabbitmq/client/PossibleAuthenticationFailureException.java (100%) rename src/{ => main/java}/com/rabbitmq/client/ProtocolVersionMismatchException.java (100%) rename src/{ => main/java}/com/rabbitmq/client/QueueingConsumer.java (100%) rename src/{ => main/java}/com/rabbitmq/client/Recoverable.java (100%) rename src/{ => main/java}/com/rabbitmq/client/RecoveryListener.java (100%) rename src/{ => main/java}/com/rabbitmq/client/ReturnListener.java (100%) rename src/{ => main/java}/com/rabbitmq/client/RpcClient.java (100%) rename src/{ => main/java}/com/rabbitmq/client/RpcServer.java (100%) rename src/{ => main/java}/com/rabbitmq/client/SaslConfig.java (100%) rename src/{ => main/java}/com/rabbitmq/client/SaslMechanism.java (100%) rename src/{ => main/java}/com/rabbitmq/client/ShutdownListener.java (100%) rename src/{ => main/java}/com/rabbitmq/client/ShutdownNotifier.java (100%) rename src/{ => main/java}/com/rabbitmq/client/ShutdownSignalException.java (100%) rename src/{ => main/java}/com/rabbitmq/client/SocketConfigurator.java (100%) rename src/{ => main/java}/com/rabbitmq/client/StringRpcServer.java (100%) rename src/{ => main/java}/com/rabbitmq/client/TopologyRecoveryException.java (100%) rename src/{ => main/java}/com/rabbitmq/client/UnexpectedFrameError.java (100%) rename src/{ => main/java}/com/rabbitmq/client/UnexpectedMethodError.java (100%) rename src/{ => main/java}/com/rabbitmq/client/UnknownClassOrMethodId.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/AMQBasicProperties.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/AMQChannel.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/AMQCommand.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/AMQConnection.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/AMQContentHeader.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/CRDemoMechanism.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/ChannelManager.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/ChannelN.java (100%) rename src/{com/rabbitmq/client/impl/ClientVersion.java.in => main/java/com/rabbitmq/client/impl/ClientVersion.java} (63%) rename src/{ => main/java}/com/rabbitmq/client/impl/CommandAssembler.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/ConnectionParams.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/ConsumerDispatcher.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/ConsumerWorkService.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/DefaultExceptionHandler.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/Environment.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/ExternalMechanism.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/ForgivingExceptionHandler.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/Frame.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/FrameHandler.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/FrameHandlerFactory.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/HeartbeatSender.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/LongStringHelper.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/Method.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/MethodArgumentReader.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/MethodArgumentWriter.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/NetworkConnection.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/PlainMechanism.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/SetQueue.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/ShutdownNotifierComponent.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/SocketFrameHandler.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/StrictExceptionHandler.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/TruncatedInputStream.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/UnknownChannelException.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/ValueReader.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/ValueWriter.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/Version.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/WorkPool.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/package.html (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/recovery/ConsumerRecoveryListener.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/recovery/QueueRecoveryListener.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/recovery/RecordedBinding.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/recovery/RecordedConsumer.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/recovery/RecordedEntity.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/recovery/RecordedExchange.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/recovery/RecordedExchangeBinding.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/recovery/RecordedNamedEntity.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/recovery/RecordedQueue.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnection.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelManager.java (100%) rename src/{ => main/java}/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java (100%) rename src/{ => main/java}/com/rabbitmq/client/package.html (100%) rename src/{ => main/java}/com/rabbitmq/tools/Tracer.java (100%) rename src/{ => main/java}/com/rabbitmq/tools/json/JSONReader.java (100%) rename src/{ => main/java}/com/rabbitmq/tools/json/JSONSerializable.java (100%) rename src/{ => main/java}/com/rabbitmq/tools/json/JSONUtil.java (100%) rename src/{ => main/java}/com/rabbitmq/tools/json/JSONWriter.java (100%) rename src/{ => main/java}/com/rabbitmq/tools/json/package.html (100%) rename src/{ => main/java}/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java (100%) rename src/{ => main/java}/com/rabbitmq/tools/jsonrpc/JsonRpcException.java (100%) rename src/{ => main/java}/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java (100%) rename src/{ => main/java}/com/rabbitmq/tools/jsonrpc/ParameterDescription.java (100%) rename src/{ => main/java}/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java (100%) rename src/{ => main/java}/com/rabbitmq/tools/jsonrpc/ServiceDescription.java (100%) rename src/{ => main/java}/com/rabbitmq/tools/jsonrpc/package.html (100%) rename src/{ => main/java}/com/rabbitmq/tools/package.html (100%) rename src/{ => main/java}/com/rabbitmq/utility/BlockingCell.java (100%) rename src/{ => main/java}/com/rabbitmq/utility/BlockingValueOrException.java (100%) rename src/{ => main/java}/com/rabbitmq/utility/IntAllocator.java (100%) rename src/{ => main/java}/com/rabbitmq/utility/SensibleClone.java (100%) rename src/{ => main/java}/com/rabbitmq/utility/SingleShotLinearTimer.java (100%) rename src/{ => main/java}/com/rabbitmq/utility/Utility.java (100%) rename src/{ => main/java}/com/rabbitmq/utility/ValueOrException.java (100%) rename src/{ => main/java}/com/rabbitmq/utility/package.html (100%) create mode 100644 src/main/resources/version.properties create mode 100644 src/main/scripts/generate_amqp_sources.groovy create mode 100644 src/main/scripts/manage_test_broker.groovy create mode 100644 src/main/scripts/query_test_tls_certs_dir.groovy create mode 100644 src/main/scripts/remove_old_test_keystores.groovy rename {test/src => src/test/java}/com/rabbitmq/client/impl/WorkPoolTests.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/AMQBuilderApiTest.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/AMQConnectionTest.java (100%) create mode 100644 src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java rename {test/src => src/test/java}/com/rabbitmq/client/test/AmqpUriTest.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/BlockingCellTest.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/BrokenFramesTest.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/BrokerTestCase.java (99%) rename {test/src => src/test/java}/com/rabbitmq/client/test/Bug20004Test.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/ChannelNumberAllocationTests.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/ClientTests.java (96%) rename {test/src => src/test/java}/com/rabbitmq/client/test/ClonePropertiesTest.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/CloseInMainLoop.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/ConfirmBase.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/JSONReadWriteTest.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/LongStringTest.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/MultiThreadedChannel.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/QueueingConsumerShutdownTests.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/SharedThreadPoolTest.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/TableTest.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/TruncatedInputStreamTest.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/ValueOrExceptionTest.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/AbstractRejectTest.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/AlternateExchange.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/BasicGet.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/BindingLifecycle.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/BindingLifecycleBase.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/CcRoutes.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/ClusteredTestBase.java (95%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/Confirm.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/ConnectionOpen.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/ConnectionRecovery.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/ConsumerCount.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/ConsumerPriorities.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/DeadLetterExchange.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/DefaultExchange.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/DirectReplyTo.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/DoubleDeletion.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/DurableOnTransient.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/ExceptionHandling.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/ExceptionMessages.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/ExchangeDeclare.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/ExchangeDeletePredeclared.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/FrameMax.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/FunctionalTests.java (95%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/Heartbeat.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/InternalExchange.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/InvalidAcks.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/InvalidAcksBase.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/InvalidAcksTx.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/MessageCount.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/Nack.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/Nowait.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/PerMessageTTL.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/PerQueueTTL.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/Policies.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/QosTests.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/QueueExclusivity.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/QueueLease.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/QueueLifecycle.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/QueueSizeLimit.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/Recover.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/Reject.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/RequeueOnClose.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/Routing.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/SaslMechanisms.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/TTLHandling.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/Tables.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/Transactions.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/UnexpectedFrames.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/functional/UserIDHeader.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/performance/CLIHelper.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/performance/QosScaling.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/performance/ScalabilityTest.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/performance/StressManagement.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/server/AbsentQueue.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/server/BlockedConnection.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/server/Bug19219Test.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java (96%) rename {test/src => src/test/java}/com/rabbitmq/client/test/server/DurableBindingLifecycle.java (94%) rename {test/src => src/test/java}/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/server/Firehose.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/server/HATests.java (87%) rename {test/src => src/test/java}/com/rabbitmq/client/test/server/LoopbackUsers.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/server/MemoryAlarms.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/server/MessageRecovery.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/server/Permissions.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/server/PersistenceGuarantees.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/server/PriorityQueues.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/server/ServerTests.java (92%) rename {test/src => src/test/java}/com/rabbitmq/client/test/server/Shutdown.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java (91%) rename {test/src => src/test/java}/com/rabbitmq/client/test/ssl/SSLTests.java (80%) rename {test/src => src/test/java}/com/rabbitmq/client/test/ssl/UnverifiedConnection.java (100%) rename {test/src => src/test/java}/com/rabbitmq/client/test/ssl/VerifiedConnection.java (91%) rename {test/src => src/test/java}/com/rabbitmq/examples/BufferPerformanceMetrics.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/ChannelCreationPerformance.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/ConfirmDontLoseMessages.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/ConsumerMain.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/DirectReplyToPerformance.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/FileConsumer.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/FileProducer.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/HelloClient.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/HelloJsonClient.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/HelloJsonServer.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/HelloJsonService.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/HelloServer.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/LogTail.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/MulticastMain.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/PerQueueTTLGetter.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/PerQueueTTLPublisher.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/PerfTest.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/PerfTestMulti.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/ProducerMain.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/SendString.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/SimpleConsumer.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/SimpleProducer.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/SimpleTopicConsumer.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/SimpleTopicProducer.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/SpammyTopicProducer.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/StressPersister.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/TestMain.java (94%) rename {test/src => src/test/java}/com/rabbitmq/examples/TracerConcurrencyTest.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/perf/Broker.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/perf/BrokerValue.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/perf/BrokerVariable.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/perf/Consumer.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/perf/MulticastParams.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/perf/MulticastSet.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/perf/MulticastValue.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/perf/MulticastVariable.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/perf/PerfUtil.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/perf/Producer.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/perf/ProducerConsumerBase.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/perf/RateVsLatencyScenario.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/perf/Scenario.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/perf/ScenarioFactory.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/perf/ScenarioStats.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/perf/SimpleScenario.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/perf/SimpleScenarioStats.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/perf/Stats.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/perf/Variable.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/perf/VariableValue.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/perf/VaryingScenario.java (100%) rename {test/src => src/test/java}/com/rabbitmq/examples/perf/VaryingScenarioStats.java (100%) rename {test/src => src/test/java}/com/rabbitmq/tools/Host.java (77%) rename {test/src => src/test/java}/com/rabbitmq/utility/IntAllocatorTests.java (100%) rename config.properties => src/test/resources/config.properties (91%) create mode 100644 src/test/resources/hare@localhost.config create mode 100644 src/test/resources/rabbit@localhost.config diff --git a/.gitignore b/.gitignore index c80df7d958..f52592ac2c 100644 --- a/.gitignore +++ b/.gitignore @@ -8,13 +8,11 @@ *.iml *.ipr *.iws +.DS_Store \#~ -.idea/ -build/ -cover/ -debug/ -dist/ -ebin/ -out/ -tmp/ -junit*.properties +/.idea/ +/deps/ +/target/ +/.classpath +/.project +/.settings diff --git a/Makefile b/Makefile index 867f7f7f69..710cc894b4 100644 --- a/Makefile +++ b/Makefile @@ -1,77 +1,36 @@ -VERSION=0.0.0 -PACKAGE_NAME=rabbitmq-java-client -JAVADOC_ARCHIVE=$(PACKAGE_NAME)-javadoc-$(VERSION) -SRC_ARCHIVE=$(PACKAGE_NAME)-$(VERSION) -SIGNING_KEY=056E8E56 -GNUPG_PATH=~ +MVN ?= mvn +MVN_FLAGS ?= -WEB_URL=http://www.rabbitmq.com/ -NEXUS_STAGE_URL=http://oss.sonatype.org/service/local/staging/deploy/maven2 -MAVEN_NEXUS_VERSION=1.7 +ifndef DEPS_DIR +ifneq ($(wildcard ../../UMBRELLA.md),) +DEPS_DIR = .. +else +DEPS_DIR = deps +endif +endif -AMQP_CODEGEN_DIR=$(shell fgrep sibling.codegen.dir build.properties | sed -e 's:sibling\.codegen\.dir=::') +MVN_FLAGS += -Ddeps.dir="$(abspath $(DEPS_DIR))" -MAVEN_RSYNC_DESTINATION=maven@195.224.125.254:/home/maven/rabbitmq-java-client/ +.PHONY: all deps tests clean distclean -ANT ?= ant -ANT_FLAGS ?= +all: deps + $(MVN) $(MVN_FLAGS) compile -all: - $(ANT) $(ANT_FLAGS) build +deps: $(DEPS_DIR)/rabbit + @: -clean: - $(ANT) $(ANT_FLAGS) clean - -distclean: clean - $(MAKE) -C $(AMQP_CODEGEN_DIR) clean - -dist: distclean srcdist dist_all maven-bundle - -dist_all: dist1.5 javadoc-archive - -jar: - $(ANT) $(ANT_FLAGS) jar +$(DEPS_DIR)/rabbit: + git clone https://github.com/rabbitmq/rabbitmq-server.git $@ + $(MAKE) -C $@ fetch-deps DEPS_DIR="$(abspath $(DEPS_DIR))" -maven-bundle: - $(ANT) $(ANT_FLAGS) -Dimpl.version=$(VERSION) maven-bundle +tests: deps + $(MVN) $(MVN_FLAGS) verify -dist1.5: - $(ANT) $(ANT_FLAGS) -Ddist.out=build/$(PACKAGE_NAME)-bin-$(VERSION) -Dimpl.version=$(VERSION) dist - $(MAKE) post-dist TARBALL_NAME=$(PACKAGE_NAME)-bin-$(VERSION) +deploy: + $(MVN) $(MVN_FLAGS) deploy -javadoc-archive: - $(ANT) $(ANT_FLAGS) javadoc - cp -Rp build/doc/api build/$(JAVADOC_ARCHIVE) - (cd build; tar -zcf $(JAVADOC_ARCHIVE).tar.gz $(JAVADOC_ARCHIVE)) - (cd build; zip -q -r $(JAVADOC_ARCHIVE).zip $(JAVADOC_ARCHIVE)) - (cd build; rm -rf $(JAVADOC_ARCHIVE)) - -post-dist: - @[ -n "$(TARBALL_NAME)" ] || (echo "Please set TARBALL_NAME."; false) - chmod a+x build/$(TARBALL_NAME)/*.sh - cp LICENSE* build/$(TARBALL_NAME) - (cd build; tar -zcf $(TARBALL_NAME).tar.gz $(TARBALL_NAME)) - (cd build; zip -q -r $(TARBALL_NAME).zip $(TARBALL_NAME)) - (cd build; rm -rf $(TARBALL_NAME)) - -srcdist: distclean - mkdir -p build/$(SRC_ARCHIVE) - cp -Rp `ls | grep -v '^\(build\|README.in\)$$'` build/$(SRC_ARCHIVE) - - mkdir -p build/$(SRC_ARCHIVE)/codegen - cp -r $(AMQP_CODEGEN_DIR)/* build/$(SRC_ARCHIVE)/codegen/. +clean: + $(MVN) $(MVN_FLAGS) clean - if [ -f README.in ]; then \ - cp README.in build/$(SRC_ARCHIVE)/README; \ - if [ -f "$(BUILD_DOC)" ]; then \ - cat "$(BUILD_DOC)" \ - >> build/$(SRC_ARCHIVE)/README; \ - else \ - elinks -dump -no-references -no-numbering \ - $(WEB_URL)build-java-client.html \ - >> build/$(SRC_ARCHIVE)/README; \ - fi; \ - fi - (cd build; tar -zcf $(SRC_ARCHIVE).tar.gz $(SRC_ARCHIVE)) - (cd build; zip -q -r $(SRC_ARCHIVE).zip $(SRC_ARCHIVE)) - (cd build; rm -rf $(SRC_ARCHIVE)) +distclean: clean + $(MAKE) -C $(DEPS_DIR)/rabbitmq_codegen clean diff --git a/README.md b/README.md index fb712fa298..82a4e899fc 100644 --- a/README.md +++ b/README.md @@ -14,14 +14,14 @@ Maven artifacts are [released to Maven Central](http://search.maven.org/#search% com.rabbitmq amqp-client - 3.5.5 + 3.6.5 ``` ### Gradle ``` groovy -compile 'com.rabbitmq:amqp-client:3.5.5' +compile 'com.rabbitmq:amqp-client:3.6.5' ``` diff --git a/RUNNING_TESTS.md b/RUNNING_TESTS.md index 2eb0b79567..157b2e1ff9 100644 --- a/RUNNING_TESTS.md +++ b/RUNNING_TESTS.md @@ -1,21 +1,40 @@ ## Overview There are multiple test suites in the RabbitMQ Java client library; -the source for all of the suites can be found in the [test/src](./test/src) +the source for all of the suites can be found in the [src/test/java](src/test/java) directory. The suites are: * Client tests - * Functional tests * Server tests * SSL tests + * Functional tests + * HA tests All of them assume a RabbitMQ node listening on localhost:5672 (the default settings). SSL tests require a broker listening on the default -SSL port. Connection recovery tests assume `rabbitmqctl` at `../rabbitmq-server/scripts/rabbitmqctl` -can control the running node: this is the case when all repositories are cloned using -the [umbrella repository](https://github.com/rabbitmq/rabbitmq-public-umbrella). +SSL port. HA tests expect a second node listening on localhost:5673. + +Connection recovery tests need `rabbitmqctl` to control the running nodes. +can control the running node. + +`mvn verify` will start those nodes with the appropriate configuration. + +To easily fullfil all those requirements, you can use `make deps` to +fetch the dependencies. You can also fetch them yourself and use the +same layout: + +``` +deps +|-- rabbitmq_codegen +`-- rabbit +``` + +You then run Maven with the `deps.dir` property set like this: +``` +mvn -Ddeps.dir=/path/to/deps verify +``` For details on running specific tests, see below. @@ -25,77 +44,122 @@ For details on running specific tests, see below. To run a specific test suite you should execute one of the following in the top-level directory of the source tree: - # runs unit tests - ant test-client - # runs integration/functional tests - ant test-functional - # runs TLS tests - ant test-ssl - # run all test suites - ant test-suite - -For example, to run the client tests: +* To run the client unit tests: + ``` +mvn -Ddeps.dir=/path/to/deps verify -Dit.test=ClientTests ``` ------------------ Example shell session ------------------------------------- -rabbitmq-java-client$ ant test-client -Buildfile: build.xml - -test-prepare: -test-build: +* To run the functional tests: -amqp-generate-check: - -amqp-generate: + ``` +mvn -Ddeps.dir=/path/to/deps verify -Dit.test=FunctionalTests +``` -build: +* To run a single test: -test-build-param: + ``` +mvn -Ddeps.dir=/path/to/deps verify -Dit.test=DeadLetterExchange +``` -test-client: - [junit] Running com.rabbitmq.client.test.ClientTests - [junit] Tests run: 31, Failures: 0, Errors: 0, Time elapsed: 2.388 sec +For example, to run the client tests: -BUILD SUCCESSFUL ------------------------------------------------------------------------------ +``` +rabbitmq-java-client$ mvn -Ddeps.dir=/path/to/deps verify -Dit.test=ClientTests +[INFO] Scanning for projects... +[INFO] Inspecting build with total of 1 modules... +[INFO] Installing Nexus Staging features: +[INFO] ... total of 1 executions of maven-deploy-plugin replaced with nexus-staging-maven-plugin +[INFO] +[INFO] ------------------------------------------------------------------------ +[INFO] Building RabbitMQ Java Client 3.7.0-SNAPSHOT +[INFO] ------------------------------------------------------------------------ +[INFO] +[INFO] --- groovy-maven-plugin:2.0:execute (generate-amqp-sources) @ amqp-client --- +[INFO] +[INFO] --- build-helper-maven-plugin:1.12:add-source (add-generated-sources-dir) @ amqp-client --- +[INFO] Source directory: .../rabbitmq_java_client/target/generated-sources/src/main/java added. +[INFO] +[INFO] --- maven-resources-plugin:2.5:resources (default-resources) @ amqp-client --- +[debug] execute contextualize +[INFO] Using 'UTF-8' encoding to copy filtered resources. +[INFO] Copying 1 resource +[INFO] +[INFO] --- maven-compiler-plugin:3.5.1:compile (default-compile) @ amqp-client --- +[INFO] Nothing to compile - all classes are up to date +[INFO] +[INFO] --- groovy-maven-plugin:2.0:execute (remove-old-test-keystores) @ amqp-client --- +[INFO] +[INFO] --- groovy-maven-plugin:2.0:execute (query-test-tls-certs-dir) @ amqp-client --- +[INFO] +[INFO] --- keytool-maven-plugin:1.5:importCertificate (generate-test-ca-keystore) @ amqp-client --- +[WARNING] Certificate was added to keystore +[INFO] +[INFO] --- keytool-maven-plugin:1.5:importCertificate (generate-test-empty-keystore) @ amqp-client --- +[WARNING] Certificate was added to keystore +[INFO] +[INFO] --- keytool-maven-plugin:1.5:deleteAlias (generate-test-empty-keystore) @ amqp-client --- +[INFO] +[INFO] --- maven-resources-plugin:2.5:testResources (default-testResources) @ amqp-client --- +[debug] execute contextualize +[INFO] Using 'UTF-8' encoding to copy filtered resources. +[INFO] Copying 3 resources +[INFO] +[INFO] --- maven-compiler-plugin:3.5.1:testCompile (default-testCompile) @ amqp-client --- +[INFO] Nothing to compile - all classes are up to date +[INFO] +[INFO] --- maven-surefire-plugin:2.19.1:test (default-test) @ amqp-client --- +[INFO] Tests are skipped. +[INFO] +[INFO] --- maven-jar-plugin:3.0.2:jar (default-jar) @ amqp-client --- +[INFO] Building jar: .../rabbitmq_java_client/target/amqp-client-3.7.0-SNAPSHOT.jar +[INFO] +[INFO] --- groovy-maven-plugin:2.0:execute (start-test-broker-A) @ amqp-client --- +[INFO] +[INFO] --- groovy-maven-plugin:2.0:execute (start-test-broker-B) @ amqp-client --- +[INFO] +[INFO] --- groovy-maven-plugin:2.0:execute (create-test-cluster) @ amqp-client --- +[INFO] +[INFO] --- maven-failsafe-plugin:2.19.1:integration-test (integration-test) @ amqp-client --- + +------------------------------------------------------- + T E S T S +------------------------------------------------------- +Running com.rabbitmq.client.test.ClientTests +Tests run: 50, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.732 sec - in com.rabbitmq.client.test.ClientTests + +Results : + +Tests run: 50, Failures: 0, Errors: 0, Skipped: 0 + +[INFO] +[INFO] --- groovy-maven-plugin:2.0:execute (stop-test-broker-B) @ amqp-client --- +[INFO] +[INFO] --- groovy-maven-plugin:2.0:execute (stop-test-broker-A) @ amqp-client --- +[INFO] +[INFO] --- maven-failsafe-plugin:2.19.1:verify (verify) @ amqp-client --- +[INFO] ------------------------------------------------------------------------ +[INFO] BUILD SUCCESS +[INFO] ------------------------------------------------------------------------ +[INFO] Total time: 33.707s +[INFO] Finished at: Mon Aug 08 16:22:26 CEST 2016 +[INFO] Final Memory: 21M/256M +[INFO] ------------------------------------------------------------------------ ``` -Test failures and errors are logged to `build/TEST-*`. +Test reports can be found in `target/failsafe-reports`. -## SSL Test Setup +## Running tests against an externally provided broker or cluster -To run the SSL tests, the RabbitMQ server and Java client should be configured -as per the SSL instructions on the RabbitMQ website. The `SSL_CERTS_DIR` -environment variable must point to a certificate folder with the following -minimal structure: +By default, if the RabbitMQ broker sources are available, the testsuite +starts automatically a cluster of two RabbitMQ nodes and runs the tests +against it. -``` - $SSL_CERTS_DIR - |-- client - | |-- keycert.p12 - | |-- cert.pem - | \-- key.pem - |-- server - | |-- cert.pem - | \-- key.pem - \-- testca - \-- cacert.pem -``` +You can also provide your own broker or cluster. To disable the +automatic test cluster setup, disable the `setup-test-cluster` Maven +profile: -The `PASSWORD` environment variable must be set to the password of the keycert.p12 -PKCS12 keystore. The broker must be configured to validate client certificates. -This will become minimal broker configuration file if `$SSL_CERTS_DIR` is replaced -with the certificate folder: - -``` erlang -%%%%% begin sample test broker configuration -[{rabbit, [{ssl_listeners, [5671]}, - {ssl_options, [{cacertfile,"$SSL_CERTS_DIR/testca/cacert.pem"}, - {certfile,"$SSL_CERTS_DIR/server/cert.pem"}, - {keyfile,"$SSL_CERTS_DIR/server/key.pem"}, - {verify,verify_peer}, - {fail_if_no_peer_cert, false}]}]}]. -%%%%% end sample test broker configuration +``` +mvn verify -P '!setup-test-cluster' ``` diff --git a/build.properties b/build.properties deleted file mode 100644 index 21ba4ff08a..0000000000 --- a/build.properties +++ /dev/null @@ -1,23 +0,0 @@ -alt.javac.source=1.6 -alt.javac.target=1.6 -build.out=build -bundle.name=RabbitMQ client library -bundle.out=${build.out}/bundle -bundle.symbolicName=com.rabbitmq.client -bundlor.home=bundlor -dist.out=${build.out}/dist -impl.version=0.0.0 -javac.debug=true -javac.out=${build.out}/classes -javadoc.out=build/doc/api -lib.out=${build.out}/lib -python.bin=python -sibling.codegen.dir=../rabbitmq_codegen -sibling.rabbitmq_test.dir=../rabbitmq_test -rabbitmqctl.bin=../rabbit/scripts/rabbitmqctl -spec.version=0.9.1 -src.generated=${build.out}/gensrc -standard.javac.source=1.6 -standard.javac.target=1.6 -test.javac.out=${build.out}/test/classes -test.src.home=test/src diff --git a/build.xml b/build.xml deleted file mode 100644 index b0e0fe931f..0000000000 --- a/build.xml +++ /dev/null @@ -1,530 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - -
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/bundlor/dist/com.springsource.bundlor-1.0.0.RELEASE.jar b/bundlor/dist/com.springsource.bundlor-1.0.0.RELEASE.jar deleted file mode 100644 index e8a8fa37ef201751101159168e7611b23daf4ac8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 133712 zcmb?@1yH5Qk}gf-+PJ&BySux)9^BpC-QC@xacJBdcN%Nly>Wlcojdz>CU)n|ZagB2 z{}54`@#lBGl*+0?Ug|Rl6wq%!*z%0r|N8LnUywi`Kr$lA0yGk`qI7SgKtS^Uo(chk z^)VG!dfYDy7zk+jLmK%*b!*pU@`qDdS`m2wKg?^&& z5D&lxuIjHt?mQ*tvf5rufswFT^W_`WQ!wOe<^mZJAjZob5gV0D0dspQ4Mo4)5C#02andR3-|%~c|DZllT#m=~>> zre^SZOqtqnbmlNNRwwU6K6ushph26a2A|f)ofS8LRo38mhG&wa(bK(Y^0lT=A689o#rl@ zD``7@EvhX%CJ1v}Zzb4Lq288n$p0)*A*$AH2HL7#`)I@SEGx;iZI+6y#>%c7`Ovp` zBa11$4+6^6MVB_8HHOwi0Bj$HuT!t)e

eu>^r!D|n`@w0JG1G^Y$n|7OrKZLFRM)o(a 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 diff --git a/bundlor/dist/com.springsource.bundlor.ant-1.0.0.RELEASE.jar b/bundlor/dist/com.springsource.bundlor.ant-1.0.0.RELEASE.jar deleted file mode 100644 index f56eb8e38ca54ab37243721d54c274522dfe7dd9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17007 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 diff --git a/bundlor/dist/com.springsource.bundlor.blint-1.0.0.RELEASE.jar b/bundlor/dist/com.springsource.bundlor.blint-1.0.0.RELEASE.jar deleted file mode 100644 index 39232af1c046a0d09dc2982076d7d4efef051e4d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13577 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�xF6E9vT~ zTD-H^S6R~gNkH-CiBMlA{GAszkv#W`M7SSvy;(lv@g)5bpF?y&@29Sb67M@3D;;xR zro>}4kF8hC!BLv)LnSXtiM44H%`9gNpUw4Kp5~hN>-oNRx^G6>+PCH5S)!rs1stFJ z&5WeryeVZSXV_e4fPcvC(9O-F_#O@WUHPO@U(y`66ux+hPxW&%CY-ZA#;T_V30EJR z<4B2mxjJoaH0nOW*Ym;~V>o>k*`Axt&M=G6^IH&ZaD2P`j!_VCS!&SGL+xje8;Q;I zP|9vy;SK!Dp5i=WCxX2d-oz*~Gnmbxd^s3OBZ^73#mgF^GK)+XpoG3D=S74!+T#%NFXr49XE!In|6by1E(q;Q6u& z^Qj!yC$TG?_exx;x{FLDu0a>i@Ko3(3TZkz-0Tom_N<;x*WN1 zsDklUAD&p?oc1ZaN<{1Tvn4%klI_AJk@3uZ<%+kw*cKbVXk?B)1HJyrl5o%7m%M0w zXQdMeR@{a{9;Drv_~E0JqRQ?0`6ki;wPBJ}mL9OG;lY^-cWG8AK4&6XKrgM*Kil6C z15M0lf$31jCXMO~5y0^s7d}&#`Fbv=@LEO5D92Bq0yW&AI_^NS@y7E(fpk)?TlTF2 zAyfcMb((EguHV|-^tIzd?IY-+ zc+SkJlmucT4H-7Ao~mdk-jl^}Xr#5II#BDdEQtV7USy-!xEv#rm6q|LUMS(mn?|d+ z#NOH=i;-2BdP1>%F>=y{t+oMga@SHqV%Dk1rWjiJ!~L$yieFV(FOuqq`*zjlnrsc; z08OX8M^3vvx2?zXoeIL_^7aWL+$WRCBwG};g_&OYoU36Vy7v70!RFz~?Jx2zx>yq4 z^AlxDe{wWECNn)SHJN@@uSdkzr~HMCns;m}B$u50^;b6HCd!c@0!81K(&S*`4~4lN z$;d3m1VSp5+!qM}Wj?uwo{~%3;mu%f)RI$WukEeJ4Gm>?+L4oDn*F-FBWW#PNEn`e ztn%D_u{A{x)}ISv>UMIktZA-=%#RID4p*atO++GM)f}KUg`7TW0*bCY{QrpH9GvVO z5Kb;u2xm<XjU=c{PYi>zKxBYdgMR7&W++8Vt@0KmI%%d=k$ zz~^$)1$`fw2qBd)&O3nlJm7WkKJq9r5Y%B>0LJeCQsqquf&gPk;PeW*$L@;_fQN4L zy%zkZA<*}6$<_&BZ04bfutk`+CVM9OfZx8P111jf_qSxB*vOb%h-miBeR%{-aQ_qXuiP5Y<_?%# zoY;mi>$r38TLG@PfVcm}(C;55W-0H3J^Pd7p}0ragvWLrv&1pFCiuSa$o$E~ZxfH$ z1~4m=p$|Omi<{h`27V#`zELm>-yCdg7Wf|k50p2yx`@1jePDcP9wi6f|9&;i2U{|2NbvQisZYpe4%%uN8)U!T^ zqW;g4G&U+`!Wq3_urKXFhob&*`2gDrW^xi3MKI)9$l+H0O=Y9u4vW#y8O?ne3&R-m z|H*G2u8hub?h8fu|0wT``Fr`!!-3El&wWuk8VDN{Gn~PUtPc*q_x?NRUOp82DPV@Z l2gd_={E>H#=`b35KT?OQ5CZE^I5=#;pA-;(l0QJd`#+*$@ZkUe diff --git a/bundlor/lib/com.springsource.org.objectweb.asm-3.1.0.jar b/bundlor/lib/com.springsource.org.objectweb.asm-3.1.0.jar deleted file mode 100644 index da07fa03764f3729efd412e0f6aa80fdb2f372d7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 43557 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

jxaj&?l6xFD6u#qf>LNroaV}Q5lXxo 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 diff --git a/bundlor/lib/com.springsource.org.objectweb.asm.commons-3.1.0.jar b/bundlor/lib/com.springsource.org.objectweb.asm.commons-3.1.0.jar deleted file mode 100644 index 14d55b708302f2aac366ad46e6fc03049ca776b6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33255 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

ln_){k#*LVDz&pLX|5>-QFLV~p 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

ono4UDN>rwu3OU25`CWowlP0%s#lIB$xI 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 EKhOFjz5oCK diff --git a/bundlor/lib/com.springsource.org.objectweb.asm.tree-3.1.0.jar b/bundlor/lib/com.springsource.org.objectweb.asm.tree-3.1.0.jar deleted file mode 100644 index 7b5440b94339b36f18dc613222ec48a8dc9fdd39..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22502 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 diff --git a/bundlor/lib/com.springsource.util.common-2.0.0.RELEASE.jar b/bundlor/lib/com.springsource.util.common-2.0.0.RELEASE.jar deleted file mode 100644 index 22d4559778fdf6a8d49b1445e96f458d489a791a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 42376 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 MfWN`)5)QxnKTqRJEdT%j diff --git a/bundlor/lib/com.springsource.util.math-2.0.0.RELEASE.jar b/bundlor/lib/com.springsource.util.math-2.0.0.RELEASE.jar deleted file mode 100644 index 16ca6996162fe534f37c45d4d570bee7dc860db4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8384 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 diff --git a/bundlor/lib/com.springsource.util.osgi-2.0.0.RELEASE.jar b/bundlor/lib/com.springsource.util.osgi-2.0.0.RELEASE.jar deleted file mode 100644 index b63f391ab0191a04832fada32cae965bd38bbc43..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 94153 zcmbrmWmsI<)-_6ipoP1;ySux)YXOD3dxARzcXxMpcMAkdaF^f&OW@L{`<&WQe}*cED9T7msHrn5NX8@@CUOZ<=H>`EJY#!K$6%C)c6B-kz_DzvnIXT%;9*zy!mnz^UX*t!mFI zap`GOE%9cj_Jk?mzS1{!5hXi zu`GSlkCCei*1d~9QMtT%^IXBU1~W-pUfDzb;TH;% zueRph`gUTu2121V3|GY1CWp@u9_Agn%1C%T>t3zb)RxQd0_b9)G_u*~WEnk@@Dv%` zb+ltt=Y$+3r=)7LvrN3@l}@q>L^`R?sW#jBs&uwz9Wyad2}s1^vx%%>S?9Zmw3ge{&4p z|M3_H7YnPuIgtGC545s(1v%RT|L(8UX{vK*6njJZKC>0?N{A0~EB^qzK`;p}35P!ste+ zVqLg|w8`(^&S$1>rq~u<9v&a*J_0lW!Pp0Ot>#{C6xor7oJkB-p-h!2ry51gGLyTZ zYBiA@UsF53c_arg5B70x?rSFVVc0Y_G1zYQQH0WHX~gbsP#dCM=r@}-ORxca1U)A7 zlXG2s!nB5T+bOfPg2(D~xx*q|ee>}Rnr4X_4o*)&}NO79gB%9+_i{H z8r%XKJ;!C3tW01D+j&b za~MuK5NG?SQS9y>_aw2H%?qGWAkYAhug5x&yJ?>rqOsF}(z%JJu1EN&Q1t7c@6yF)L&%-BD_TQ{`V1BQOpfBid3xkF_XPYvhPmc%-SIxwm zxzM##0~GmF-jyMEq!oHi6D5ilMs3*Zih27UGm#gS64wpIR`rykls4zOd+}PBk(G-9 zidF+z;xxLLIZ|o%&(CHuEl+zuQCc2qF82pNZ0T$9bNh znQXG8J_TMaAB)MOibu}u)E`4koyfTdyJA0&HGLWl=Nneb0gy1F%3`W%7g&v{W~M?= zij86`P(H~mj~|V@Zw(!bKSR6r0JSqA=;O!nf$90xw2IE>U*k--^f4y_GbBeCr}2O+5jy;B4&10_8M=I@plg}i0MXrCxSn8 zc(IF!5MwAq&S{MiB1%p!TBz&eV{>5xx{vix^8`bpI9EdtRCfd26R?8H~a zH~$~){fZge0$u&H;Uir5lA#{Ae>e;Sv2irzd$cI*pBK~?JeC(@8yI)*d|{0~_R5e$ zDJ)8pM#Sxil{J0^mtZF;k+JZwa6e$%%zl2k8KeRuOHF?5LLZ}^32pwxIF^L&ER*5#o+`$})*QB%n0rN>Qve1MBxgM8TsBm*S5i^dOQrJCU|0K^@Mv{3H zvfLpYO+5=}g=H56EzRoNe`)drRtRV!vhaL94Ff|^Eypg7LdmN0hs_`d1<+huP?O5l zEkLG;Aeqlc`Ct#?Q;yH<_CQ`F(lRXe`F*A{w2H>fDZmuZshH6)lIBcKu3zYV_h*OU zD-=A7fB*xlg$4uT{%;({OWE1M-OB7g-l8GrvLKE8GNM^Eq=L%a;w1!5vJ#6X0w!jH zwt_t{2?^IJ`d%?o06T!8n4Cv==G#5jnN_VE26?lbMlAjV!B51MoOqMO74*2EVil$P zWup)4Y%jO_y$oQ7m%mru(I%PxjO zj%OT=BLo<5gE@yI8Tnj*%9>3hubIl6NEopSE?k|=775P{PN>1U(?Tu$!Y5Je5xEw% zd$dX7+07Mml!tvBsIKM8t`+8`Wt<-=y!>N(9VWfDOALcHJXs{|KE2B2dxv8*s>}=v znWkgKyk5Dyl8L=d*;r4$lNB7E^DX=@6O$ekGE6LcAIRor84HpN40ct5Q5Kkk{Q%qQ z-d11$SOkdhij`UBA8di*PRL;z_$Jt^$?}6J_#oxeZ+hh3fGhPUJW-HR6Ah6B>gfA0 zG{Bt^9gXlqc@KtOjRn`V+ex0$p$r1;lf(}egwhc3$nFUS+Cnp3-}*25+ls^5R>&9H z<2AT36oV|o9>(fj7A2F8`M0MK^52PcA6uwRZgvN7o+@7EC_Jw7tpME9KcUip2&-lu zeVmha@Q?{jh~P}@wDV6=zUT^tZyRH#-UY!WP{hj$(R>#y@WM!i>4k8ebj(H3M&}tC z!k@MtD->SSL`Y4GF6|)syj~(QwVe@JS#*LJi~G{YkIDX*cui&0Nya zLQup_X7Ks8wxu>nyY|78Y1@p+E*1Wr9PWAeRa6RS6jOeFoNV)WDGAKfQ@w1;ohtK` z)6asqgGoFWOY+z(_;@)C*<|PAoCX0J7WgWZ6+s~7eHgR6%_eK0!0ihf%Gx_c3(k73 zM87!C1Bir4v~-Vfhb^$LL-qIA#kKPYS>AH7z~}`wnevY~)M>@+UicF4Oxpt4%mlU} zNJH3(wQ%H>o$Du1i;*cQM5!+`;JO;bS;hT%XIf-(63JU(REqDrW=%V8-?i^6==X44 zp*#&;+nUiWW6jWf*uCtR7EL#tg8Pw(m-dLICF*%A352DXzh7RSUH!0zfu9&Ik#NGh z-xk1)8U9NlIFSZ7E#ML$?;``YFK|I`m=lM z%2&?U!-9cjp@D(@FVg}|kh9BM4par&TY!Gg|H)c5j!706{u_I8?v1~|CsQ0{z=NO7 zxju=Kh%=T0@s0)(=DvL_(ih|;8i&qYcV!Bw&~C=WXf9}$MW*gvDJ#Y(BiAsmk|%J) zCvY(RrFA-nWKr=UOXVtV_oinvb=n*@K#}q}=iYhdx$BVsFl*iD<$_A+eI1-bhca;; zf5uU*0s?uprvq)gjO6s1{95D}O4V*nyV7)doe0lLlnV}nImoWC7?DEG5ih&R{y}qg zhCC0B=9aSyTWdS`R(5!GNz`#ey=UdmM_h4~2~s0xw#aFO_J|U^YXjK|&twdp8M^Pq zrSsU6!b?9(@~>MBv6_?2yD4$6)w@`zRqAg{?w72i(T{;%gZIyltpn1hW4;qq$Hf1d zCg9`bYCdBKA<+#^kDJ;WPRL~&?6 zA0!G{{Jov9O1K)Hjw*Pavuc;5YG<8=Z6otsZ5DnqlW^&ZII_4&b5veWx3mz@Sai!m z(8wZ}v7Tp2#yKzCG%L-SAdw-YPmsVDcl5xGdu&IyVM=JjW9ATIK&*fnGYB(kVqS}4 zBmcwvY1*^nSbGs)dO?bjxufxB+kQs7o{;T$M3cAw%3MQrq}93|I?km2=SqnwAL)=8 z0FZV?7=V$;a~n%B`U8qaK!Cp|&6oI>0toC>kz;x=97)oR1rmX&lHo)5dMXr`=s((21wX^rdM=H5{T90$)A+aRRb z&=K0GWm&uNN(OlbO|0BxxOE*PdYbz*z~{j7&4v8|m8Hz9v1aoftIEx(gBUy|Saf{e zz5cu+AcbJ@F1Mfp?q@W!gw>p}N@n+8o66J3ozK;tWwX(Q@dZv(CLy$$ z5)7LM`7D@f_9i2iOX<*HR0)!Op@MIOytE@=Dw{}QS4-E{HFs3@_m#p7YqWKEnOm3p z$nR-L=*v>;8T~G|z_UyIep$W!3T_nA&mcqbED6>&H*wCL6{FfSgQS>2qH*`-`QX@( z=qI(;z9vNzg?((qcc}>9j+5AS!kq1jwhMmq&z~DJuLUH^5Cq|L8mry4?k2AU}KH50o>1 zy!C6vj9#!*PC&J?AwK;=6NG82SzI;jWyh82-JrHdoDKfz3CoGjiG+>=L6JuQrRB;1 zj9u|8k=XlzvH?zS8@`l$91cqn0e8}&gVjLIGf})8VZIy_2mbL@WcOXxA6o{lyAWrC zn{`C5eeZsvLA?Z(MfTx--TZb{4zqF4({H)Br8TrgnSnfWRh2paH3Zw+7*#ExYG3h8 zXfVA=h0zqV?9)YgJd+*?kw%Gvr$+luLX%^7^eF|^(->P6KW|o034c_He!U{K%yqr6 zOhSB!Y=Zt`Qn4WPG^!i!T#fN+@mcq=Q@D`&HKb2$GK(lIROg7hozRMxncGG^Y|(Q)si?IiFUKcR znWcJuK$T1ubLeN>!$melh3rzB(=c}Rd*4xBJd2_3%23l7&AZ27KPpjb*B6=rKlf zKYK|lr6BVOS|*vvE4wtgv_R&wylE%#)b`2Y3kttgLwIG{LOG_0yu(T(y_Jr+hPyDN z%yvq|o#5JUi83F{m-IR=YN(DGY(zUT!2Fe)xX6{J%(V*nq5rm{oLFnMt|9hhc=-w; zFlVIUl7G2~PZ6|!Lx0FBu(ZbPnT(#5W>>`>wCY|}x-YKNsqMr$YZ0Z*(D$@GPz!s) zHMPCTI{0DqV!PL3^a+A+gb1Te=LZO}jWzHWB^f2nW8jG`s_IBU(*&QXsqo|cg@Nw8 zh3V5$K+H_AB?WGr0%eWX9@?>=_s*ie^942=C+>)ZU8kOo0PJQjSD-`DA8wQl%*`il8oi5eV# zWhebYKIOJQ36~hl?F8ghX7Y3b&yH;C@}2DeS$b+P9i5GX9wsk_#RZ2nWK|I!-w0+7VeN| z$rES6X7Fow63t6c&)rdh)^o$&)pa$N*rR*C-6ON!Jk5bRwT>KHRW0LIb2Xf9HLS~C z50n+vj4s*JS{Xuu&H0OQBIR@m2&RV9`qfpIqLb3B5G1Zik*W_v>{FNv^}?R@;+HmY zmse3Y@{19ywrDPwZD~>K1^DX);Gt<@hAc!71(CgCm^*FS!DuG1IaqQ|y7Yry_4tDW zaZv@hTH;{K;s`ZS7@kU1s!pCpek`3K7d-9$@SCMWL{HHH>-?3CssvFL3>pb{4db%s zaWY>WN8&rYBwO@ik_(68V=anrbdF^;J7R}po8q1tF?ydHKeOo^f2q24*Yu9#Z!A{* z2`gkwiP+}9Wn^-Ai}wosXYJP*72Z?+RtqV6tA&XF{nYM1m0-0$DzASn2$8e= zyC|xswjhlDl7b0NAzb}2Qn($RejhcG+7cxME)vrfGCjVPT}PByA&p$(7g5i{LFVj~ z=Q|=-$&H^Xu@8s@pTLzP9=O7EUr`66iFiKslGVQDC|u6QPwsc zqbx!oHgQvJnx$aGbaj~1TgdRz1m}+IocauK+fE@U8i|m}$ED>F&8Rov%L1jzX+d)| z%^*+vP&$B#CBnVGV-cS#D0t@-Dy<9Igl?N!nG~|dv0LRF3`@*I_402_q#za~+Ja;a4qY1UY zrIu!$QYRCYV0ywnaU0wU=(?i%vZ1zZySop$oD}&EkYhf z+*A^_#{fBVu-Bq_NgwsxE*Whs-%lMgvg$y~{^{17uWd34WYdpfXEGt`uowh}mb@nt zH_PQmXzQfbr%=%rdJ1SR;U1Ywd6D>OP3=0~Q@uYrJ^xD7-H)u7+^pRsQR)6m<|S=R zoS=6LHx^5|1Vm`>Re~L+2Y~3c8+>fA;pM+ju`&uyNblJD+;>PI0OR@53AY-iTDQ(q zUmp8cqO~OlvE+tiLx~j=fBn>@Pg#1LvZ+%#L^~2s zU`|-(aLA9tF%X(pL37M8g zx*1a!kD8dh2}b%oQyY1h>sK?bb9>9v=8X#@{NAHzqwiD};vijD$?T`;4_iu?N@cS= zI-+e&?x9m=v!L1Mu2~;}=R+Z(SGYX1Tq$JKqiODtA}v=2zC#`gF0w?5%?T<3CJPFN zuckb+n?EN|ljTwDk-tfUe)GAsqhmvUqhM1J&Nix50XFzKyQ*q*kQ=-I zUBLROfPkg>(OxAK;x5tDu5P%NBi+_N(gHBg)Ef(-2x(_? znCBt|5Ij)@Q1G$B-{N3^VV1GZ+<8pB4{J|7ICdY z4|s0$!B6z8*U)prJENg#(efIL!kb(jIv7z1kW~mm8gd$wQr1bW8IC8L*67z|C2;k$ z2(WLlvqBj{b{=f-4Wy_XBJ4SeZ1qf*>?85ogK-^K{m69m75Cy(JvS`+>P@BH!m~*$ zUAh;i``ES5kq1Tv?tWHs7c(r3QVYYbyJ5wnHG!~F;bG>cm01pf@qM|3wW{94*pB|v zfL^V>^w zIVG9EMITDQRrS(WbFO1J|5D*i%qt6Z#;UEWP=^QyXVW?)Mav@*xpgQX`>>__wuX&R zJI&CZ4@IN3G$mlK9Ay?BF?q2!)IwCE-gd@5p!G2h2MU41n0%=XEc{Fjx<#_Du^Se- zOEwz>_|J=W1NAvaJ}6{6f;EKuW&ZQ#PH4{`#C=twC~y0bb7cq}#5yTZuiF-71bUX7x&qr%F-VxNA@2*rU0m( z9a~Mr(F2oe2@gNG;v9-<7snH$Y|+r34heWhFXiO>P&Y8>57{>b9Wd!5q6PY=}1 zff+!5`-ax5cZAj_yZH_(y(>bB`(lJcwrAS6E0oQ%l@{t)7VvrPri;vKA1{k0w^z5` zB8kpTu;ZR`qbv6EQNqqUjpo)}xIl&I;S(PbOSfRT?46~AOwvSoQ90tp_AjufJVn1e z$@E`-!zH@itL>^Q=#L+_K=EQCZi|$JMPZoB<5^`1k1#~gtk8jisOH#9HZq!PQsF~i zZq$5B@S?Z0QeS@kMG6XMyY1+|NkOSMDJb>#`R_m70e@N)e=7_sJJ?#8dXfMB^?MSm zR?~Z1B1eA-wd=IgVbr7%y^8$|?_M1txDu*t!xHm8IyvKHp^n~d%surir07+4`&~i& z!&w|_jt;Jfs!>zsS&oZ&k4w+RRLbM+7w_U*K`< zGKP2DSCi#i-(OzF7ux1uE{EUUhnV)d(*tj@W}_ov2KNYswmOEt*BG`25sEb#`ssWa zRJM8H5=kfdT-9^I9KFodvV`^Z%YkP1@a4{+wDl-mD245IEi?71e&(3*lrH zq?t4aL6Dx^IUG({lniwmDeQ~XHp=O{R`A5EW?OsoX-X$N4~=iYw4OQf&70|*P#o|!vvLw71%zVzbJi|AXVLcfaIH^Y9Eo^BsjzsgG4H#s znLi7KCA_#bU?kMSdi_k__LWGNpqfWD$b1fv8>^N}rX{nq2-&kl_{zDi+ zWJ+|-TF5-ne~aPX;tmUl?j> zd7dRw0byu5Fx25CJ3Do`)B;QZ-?NPQcGq^~yI+mGbt7pU1yj~%{>JhhHsE4*Q>+mt z<-9X89|x8q$UMOcL&&>~mA%x2u?>@Qf4Nl+hYyJ(bVI2OEj}vUl~qfV67XHUqm~Ri zG~52cCt_3%3wgb!AddGH>|%rYf!zNA`IIys!0=hWrdT{=f)`aePTe|~&e@v#amf+W z|BS^Mo}=IEt!-hNZz)bTfUKB?N4NUeH2`QC9TWeUjJYIx3XB6@9(u4Yro8*bG>E&( zyRMRK-!}+_*{U37^rXOE)*=`TUFYD{W=@lR8-XKhMv}fFmev{oHI>Q=0{S`5X}&nKrG=T!%x7r_U%78hEov9fIHZ!A3q-aiEw2al)oj`4qRP_^fxaebjZC#Ctk3 z!vpNIK9ZRbD1ppJ`SG!HtcAz#w&+hqqk>ghNAmMcHf5i`Q=FZRKYVm;yUK>gA*55= zCTuf@bC-o|thVbMkY6-ZAdguZbxw{`Kz!IahTHCv971v}sK5$Vv)-MAa*bj2ZSsMtZ*5k+>5^oW5gPw?3cNw{;o9V)%j>kr!%*+PdIr%7}^K zU2Z&P=C9`bfi#WoIsS7xe3W|nv47~-A$}52m1psAZ=;$a89Ih8HIuzf)tp#)?~CjON-N1OBxpQPJbemM zjhu#l0zA})Jdr0&;BGCld74=AHKSnXx_b1tjPhZV8nPSY_?<7m3N~h=tw+fr_Ku{> z|BNH;-BRSY3`!6?8RI~6z8b`oqUt4A2>Uc}FBMnEHkFhr(|tYPr`j1!-)X~1kKS-M zaBuvaJ_s56VU8|#^~vMdNu9)C)g`e4G)i`f(TK~_-bK`3Rp706D&I5Ozh#)29F2(J zc(YB^h%k~zz>6$_ydFTkQ$zVJhI=X42W2$VQ7C%%g9~z~@QYB`Hld`Xx*7Tv_BX8; zXy%$Tu{33OR6?5Pl_;UB9i{E`hFPHOs+BZ#W-!)7Pq5a+OkY(4Z1pEY} zcZY+(x(A{E#Wqr1(HUzM^)rfQ@-N8TWP_lj2CK1$UuGz^gIGg&*7mr2myabTBSL?U zgzx-ZKU}{>K}C2lFroh{68_r*C4r`IO>SPlJ7RZ=!EY%%bThxWSS}e(6+@`MRy7Gj z8B))Nbj7kNaPgBPkL_qf(Yl>`tE7F`b*txgvLTTC3i_?n&7uX~wbhPX?sNCbBky54 z+eHrB_uSrIe~7ffMs6tV6pqH4H3T`Xik8(T_Iyr)?vf054Xx8}b3!m*RdTsvWEHxu zLM3W=N}92xl1Q2-g`As5Vk$aXy6M=%NK%#&)@hiNak^XBcBMq~q4wIm@M*ITE1TbEz_odsi;FQ`lKxEMB#+F3y?ezcWQF{UZg(;p>M3s6H#c-J;3Uz zz`*yd%&~HZibi@j;b#sSx%2~@vNt)N9UDLnr~@dLA6JlE_Saa(UuWkAiBK0~qk_7v z9ZRiL7*jhea>MRbC+4a=1vB6TkD7^;;_I z6zj@12*yjDM!kYC?Ym#+&(zV&)k)!Xb*^u$M;>=HOoCPgBy9b$yCj1vKygaD!4!kq0>+Ejh??H>MrS4Y1U1NO zoC3mMy?Gv4lC;gyYyD?}q5jGiU~t{0=Vq9Lw~8%*G66BWKu*G|EQ>K+!9i$gyYHsA zR3kmm$Ty58eJ=R-_*m4K?HSy{-cjy7*shbU-?REa`d46D<0lz5KI`whZ-vLtRA9Ks z={}Fpw$vxIMd&SV{FwfBb)+VB+sWuhpu*)U5y~UxWFB~ikeY3;<7K;=h|<_%kkn#e z&W{2o^3)3=DPyJo%AM4_>`Z=>#EL*W5V@o?(83O6?<(Tz3N*F+?bjbV zKw%op84)ifaQzk*(#b6pGCH(A`X;LkYM>E$eY0EIGg_WmvmMh~Q zt8neMj}sh5qVggjiU@qE@Q1K5mkf4^&H?g+BblO%Np8J0DYg%Jh>9ZZ>as0~Y1)kV zj9FQvJ&7uWUZx4MsZ8=%8}*T6T3wl6l6y~V-r}99rAjlW(qkT$&R*SChyT0RJNP%ntqj4<0Sb`c>LE3L~CkFLShEHQ-|5o0hJg z5}iEa$hOcOR*RQKatobN?SiQZk$G76r7=Cs?`M93-|ZfY7#`QxX*af{`s`O~aTGF` z$>FyL*Wp6jBm^H+r_1GQY)Ol!QdK+&7}Vs>VrhyzcWWS=iJbTt8s`#U^tny$Q2eL5 zIH0v@;B}Fw{PX;Iz%RcU_HSEhJ0kw-3DL=veotR|7DSmo+$47n` zA8964uy`R8(j>Vshq%&m|{thxLCK$pvsB}cXu%?))JKLeN2Y3vyUNi-9UPAhSQA z8WX=MJIIVaqI8fuQ_*p@D|z{x*3AI)W&Y3tY6*9; z0eRS-?_+kH?*&n<0~m8Cdmv$eoT1eTre?-xjpqHpB|}=>c2(8sXkXNsh0_sc1|GGF z_AgNr-YW9gAIyuxjT41gEtsNd&1IjMGvUw4Rw$Vb!}x(IR@))Tis+C~#g_rTarcm+ zt4HTiInOEX0lfEOspgdp^XSzimld2LsA|CMDnNjm_=_pS5g`h>qw0<(n8oVag&zFz zXVHx#onmsNl=X{ymXp**llxzvJO=HHL|4Z*^Rrrw0$`C>`kF(m?pcaqp5{uLA)K^4 zfVGv+%tt38M^yPAu%D#thKqe27*r#!gX zY8_^oz%aQLn2G5p+zWp$t&TjjxD;y|)HPdo*IN(9bT12*otE024kS!MbMp3oa%?$} z(&XThT(4g00Kg)`G#VJoxf|Y8ECst14npf`<+>_KGnIJ7U4*%uib-N)EV1MBQkk}X zz-7EyH}%y4X$>f}SNMM^6nV+6g^ABlcm;`IWBJ|0!~`r5WoAjC>EHpCHhT0y#FYw; z)Yj-2BL!642}0X#wOL&de}*m!6>QY_4Yrgw-tzoc(EXLHstQWrEa<)xuJ2G#`e((_ zkf0bjhYClAASlVp$i>gyXcU006n0uywO*IMDR~Dh^ak<~v4t6*h4C&$q23K4usqmN zLNgfsC*C4=lOj}2sgXl=XV$zmI2o~$y-#{ldJ7Spu}B?LL~Q*6W2n?|EAWNy)B*(s zEqTqo|A}KU3^bxXvGrP;NmISdy9dgw=o5vKw*TkYak@IV4#9 zDiKTIMg3ydPNDpm&ft|A+l2V#T7U-KCB8p@Mhj-SQf*_anACcMjl)yZTssQpru`zXoTym`5ogD+V5$+Kq@*ushvNz#~@Z!x7P&@)J;&7XGCu!n)ZZYW`+2oHq?A{146cZ^0<-;NnUy;pqyp z|E>A*j{vT=`P{PmA7rkt=Jxg&f{ksrN0NkUF_aeigwmqgQBu|j z5KzQvG=`fbn!m21*=Jwq1d^yY>3*|zTuySY!wCv>D%kqKE>Ph;R9!>7ufWTuoXYZT zR15tO>poBf>a_- zbaP-+=;#=8*O5|>xzp_Aruz3;nxd~UI3i!%)CeEMKjc$H6ptV@+PUss>^Qj9C5e=-Hm|;$1N~S^lmht>|I$4|gY;Bwf2zqx+81%TOEdMYE=;gQ!D@l`5F%UDAsl`q80 zQ!lb=N^X+!tk%;;&$l%OXF)fD|IF{uVpXL~()vXL<*SE2_Y$$x+(0WCriq3KxhUp3 zT8<;W;urlaQxqiUkEv|a!YG*OYCzdB>-v;q=%Co3C-4pg6WR)ULaZofx%@<$)unV}7H>%8{qmCG_NI$MH+$NQZtp zAo{Cz3hO;e4NlH1&=2mkNLw>uTScZ$_aSut{HI%H3B;=G(@a9|q9pN3Ib}B!QeGjv^P4=ktZtl5Hdy z&>@1y@9d9fna{F13I3cy8>Vqy4&Q+5|1Z?X@4(4hnK%RgT^9RIeY_DlM9JFC?vyAB zY2MKC=q@rxsi86*`-ZPl)_3G&dQ8(lk7~j`$ zhI{OuqPN?zk)rz}$7YphupvK%Yt5_O+CBR&5?;hs+!R+kS(Co z)Ogk`yQE+VyjAiULQe~t*M{oT43_m4(n4hREF>jQW{R)F;I|W{!6072(bQ!@AHcVy ziW4mX+_H<0?Qx5?S4{8$R)Xw8PV!kV+WUU&us&$quovuEAawW4E&ehY^)x7fL5T-= zeZ=HSr9WdgjKwdw_lDhnquhSS?oUejjdijRBFG^|!?`S1O!ACC%r!HC9aR_rIWtw+ zRFlH!BkWu0YbFHxQrYB=IsPR-^+vRagl8T#LzV+u&#lce97xT)=Pg`k@-AK06Gd3HG8O&_F zzIASQGWWr^);UNIK<-vSvtTEn!eqV&Ys=3C$IJ_&-AUR`H2VpSyGlZY>kD6r@I~7f zCisCO?2HRLK-SC3o&tM(GYaA!!MKKG!x|)2!H5cw^ac68;9< z)*I$&AU@414-^O z__r?g?t*iqqI&tgta^nmYUWROrV>`+j^)feQis!?YRbe8>6ma%l0e0rYB~(bpl!LJ z5kf9BJ#Tc{*Zf#$3$`$q5OG_JAx12Di4T_UFA5*_q(25LNtDFkyeyOz3|(+sj~|dH zgk@Y*h8C-Zz^BLhRx)%;wTXUt<=A=J$kW?|YzY>Nm9F=i}=r#cR?EQ4q|S+y zUza(3V4hak-rMV%qSSr5#9mXoB5uRf8E_bRTf!q!2pyDI#P*JGWt%>tA;7ENv5A)r zwMRCbz9Z8*&PG{(QM`CBw7Sh8cDloo(ym6?D9DM8cujDKyqjTa`=`yuz_RHy8|-(Gu0JX_A8vYH-48>ygZ$M}9b9GDCDbNDh)W!*zP zwL?9lZsvZUK!Yt$As#;)^aQK0RuYGyu4f<-HOC<;5P2GGYf|ZNW!f3bceGd^MOcsR zer#`i@t26HsO7K>_htyFH$(i>Nyonp@u!%Xtnyp(N6%V3IeF4(euCh)6N%oLPlOH; zogWOmKf^VZZRjM|ssAt?B-BSl(L+BRNxCA2nl?3+dB5>IdW!ea1%P&o%{Z~ODGQ&1694`*p391w?Uv9G`D*q5U~JG_4(6{(6fF&u<|Aw*dbs zuqOYju!B5GrO~O|Ttnm+#(){*dAk%uEKSFFn^R&cJuS6r_TFeZ=(n;?B1pwj;`S53 z?B!qbfhVeXyD@uTeoXjw?>|OOWZD7Pj7zxVD+2Cg7r{A0(e=^ErfLJ#Qrm!D27+ zGkj8-*(mZP(|oeuVAfIG=|VQg(t$UKM;Loe)(2d0@!z`@COn zPy1HhFg1L`^q&?Pl!4A~rTVw$Z&SqJrKf7``_^=)qCrQH#n(``~33CeR}vt1ZMnB3-%U3A6e1>JZ*Q+xAGHd z!Ca#P*M^fS}lZxIkfaiHpY1tdW>^NF8PQZa!Kf0dxLIGLnlC>Gg3o^U${{@ute+ z9$wt~GrL}$5Gy9QePmTG8f-4}4K&f#Zj9PCpy4DM@=7nV*#T|$y)~E|4br|(b<~f^ zjgegM`OJ#P7=Y#)7ez}1C@CskueuH$r*)W;E8>+;qlOZ%&c392r%Ivf`9uG9l_DGz2#DOc-I=_Sf;>K*#uH>S?12y|< zSC_-#C_>h}fcvP=BO`em?oe6OLv8`@YmwGVgdt z!@j;(OmzP7m$`>R=UlVVTQZ<|D`$wk;rCC}%pbU!{SF+trj?78iIuID>mRGk#s6*; zV_0vY$BII4_Y@KN8dya!pQ=g!DT6&F%3x*Xp~)_c*Q|56`_ruv4ZkouYVI$U5w=W8 z#&V>R-#f)_vVZFoyLy=>Yx|Py_Zv~ z^>`@U*42)~t&qu-F@WXFnm z`?qYIbMy-v9cw$yY?NRnKm~92cQ%4UsIhlz7|BngM&Vb_nB1ZJA?Ttk(|$rp%<{m* zizrp2F}tWTX-y~C^vRf^i7*2x0+T>deNuG<}m5$yA#~vS-i) z+tev!#V3NrDHmm@B@>BqBGf}f!OIkk6sqx5Z1-A>${%7Inu>+=Zi=Bx!F=b6u?x?Y z3d_(NXX(FD8bj-cbQ$V5kwg(js#DESx*kZn7OE17qK7LqjNc!pwM)bx{^}&Aeo&r} ztRsHl!F`z1l_z50c8)k*<0SD^rxX)jAKL)It@dgi9Qu+7OROy6j-jd=*%V4JroFi! zTj{<>7Lc^Xpv?1*QBD^J2gPaKoA@`+b0VZ`j^WRlkNwdp{ZA*$|6afU31%cp%l^#d zA*QzlVfe~?gRz-lVM8z;Or#Ov;o={YLaJ>0@(7eocqi-rAN;-l3{ovPY zY(bg0>`NyCoh{9fX`cNVA{Di^O?|3YC^Z;*-wC^~;q)q2ZN&`4mSJgi=4C*z%tEj% zpkOOG?-H9R!Z@-G3?QO9Cl8qn(hfcKt;|7!<2ysgsFvF#6iXrrWXq45(5vg8HLE;= zMctDzOSmGktlw`2F(yJ;D;@-GmF|sIUdX<8HM7=U>ho_RKL&{Q2Iil}V-Ea(Ol|tt zlR&}P(bnoG&FR0e(`-d~+c`PpFB%ZYN+6+O?Dd6HCA~z6s4l*g-4F?@j` z*mh{z=)^adlKd819b-qRS5zUQZd3-51nm882Oe*H zeMnaG$V$WVq8Z*i1|!o?ix=6a8LH)z^ouVL;XE}*zx#Ky_D86vl=xKo6c5mKrb)Tz zl$WU|D{h{H^M4O%_!PN<@~#Xpx%(59EvC%=RkA&ad%mnXxy$!@mUtJ&tmLZ^Skc`V z1QUzUB4zYiJAg=t(hs*oG{>2HReb?nlBR}I4bvq&q9eO z&c)l^;J?B7O^k^q0zYNw{Zoejhuoxpm7$`U{y(zl{@FN^6}SJR2CpEI+u8^eNe#dL zKpGeH3+duJ2I&#+iyHU`y(rZhYD=h_wFiAmtoEZuNB#r7cg!5x4S-|%sX@-?tZSd+ zKc2pyUoJ4Ye#?X^=njFmV$M^f#oSIqTSj`Ne=If5RxmQo#Qshi_S-983LOIw3P4+y zytP(qv~ep{G_x9nC39Y?6l_#0qd%QV&Y)oQt%cqVQ>;pKE)utESi4|yZaQ=-E~4M% zq!dP`fToydUI7Hgjk;h6B;T46MbrX^v_!Rw(FsZLi!ms6mkB$1$7nQT6|8tN^o0o# zIMn_YJis68O^G5W^lGLi0u9&iv{@6G$9jww*SyvQ70lua@f2bF$eTs^c%strsf)RAL%Tq}vOj56vF2wBUMC4F)6q&mmEW`r6h{v4q?5wLXmXM+9Q1PtwCW{ocple%KQ*J^kbjyFBO}_ zUTZs-Hap#{T9{LifQtwPu_)$~C3H&L(*_%f@Q-%D+TP1PLI_eNQ2f9V0M-9W?hbrJ zwCp2UqOIKxd?&yo_P)Wt2vj-%BhU|lsY1&jD0}Q_!}g#GNCL2Vp5o6z96@ z{3x-+vQo#-(<(1LXr{e=A*B}p08cRTrP+g6mKn?0Q;+*fIom%S#hB|P;%~i5ZYd6l z>*~ATr2V_Hq63g|l;3)=pu1b#B^#EkWS0(*pQoc;xK%Kw8Wg!c{xF+$_NU3c3dH?!(U zuiV9#;L7dQYe8!^n6yc4Y$yGqf*Tt6$Ftq|0@ZdXjLDpn(fj^r@?rn}5~qj0Sz-hs zD|SEZtPIg1e_tt@T^b2tPE8g#It|%Xi%e-Gh;mfGV~FW`V3tY7*ltw4XE9i6K@kF$ z|9xA^yI5^Nn$HXu9$7XRSv+&cqMH?NIqCQ0sgwwBL-Mw#UTjo|l*|eKX#M9=T+itM zfNQ*HYXG1Ypzki=q&^04GGvN8^T6B*S?M>Gq}(~gXwAIYz#=tPFe+-SI-8M%(U#UC_C1( z23U=n1x{CwCyNa%v!lx8e6#;`&mfIT)N)#HT|`^aeQk)dP8)S2XjZs9O^*(!Y|r9+(-u37tsstjXp}oQiqN=i3wL1L!d3Z^gE> zpZ+*rwYs8x-(O$b{@M^y7J%#Tj8K+khgqj{#i=k?bt^x`Y)U%3z$|OC!Q{0Ymc}R^ zw^pnvGI0(yJ%<^0VGj<)IFiNTF_rh4ucWc>9J>UWZ}Lrm*B5gMbn2O;tEx_I7;G&X z9-OeU;V;r-Mz4&}QwFX8>pjDCt;DR-Bo&-iNg-gcP7CqO(I@$H9@3e&4lDcGr#iSI zbNuIwnp=5(a&w`LGJjqpoPf(zxit#@4dsE~1bqa9bei>?bA#rLlX(h$TpguTWzJe~ zVm(s-IeeF{uwB8?Kz=SMnQY!9?X6op9$vA=lW)^Lsiorb(6 zEY_>Vz5fVh+00(TCv1mH1aO0)IXGhVcbml_W~xB0d_jdY3~m>=(w+9>8UA zc1cjq(w26@4MhLWEmc8FFMJbbfOO5MT;6YV(SV6VUY1A9Q7&J^FB3c-VTnHA{((~} zdAjh-0d+NM6R20I82!7(V#up?$Sd%yu4E}69!083Yr2Q#2aUvt--)y&Hk>-Mh}X0l zp4*rt!<`nJiZ_G&O$;>Yjq^^eNP|p)3wNxNxrsk&H8~8%7X|E?33^JPlG1JVHM76% zoJ9bVjR_~oARv+X^n@%mn$$FN>I(S&Hhy+m>tka^8-gJ0m2wOz+RUX#3nKQ^l=)DQ zDz{-r(WFg_3lPTF<+CHcWIMihovqk)x|9$NT`F<{=~DL8*GX?Y^jVRXWH<^%D1Le; zT`S%PQz>?26jrY?z0Yn^OYYnUVVGu`B~<~y*}HprBOOg!m0apfZdGl1>!_PbcWt2! zW?_!00&tsEjUFK)>TjN5T}8J-cO*&2Oc%Xi4=JZu zEfVWB`hFq>Uo6lD;5Q=lStRiE9HIA(nfmB>&H8`MY4${ib@hl{PMND8c4$jmSJd`E z_IL%?L>+AL{yuSd(FdL4kkP;pIhkq+%mn9?tcd>2J`WxZepg1t^W=YD*kbmcpxkoi1f z%X6cCv!7o_Mt6$v1l=)0V?$h=U=WGuWjN#zz&wi!hipv9T{$}0PRySXCY$}vb#7Jk zH`XfFB@#HtTw2$tu&%P$qYm+A71O6L?PEMCh1`DU>V#726>X7m3yrb}l^nI{%c)bXvq#bS8|_k>3)omx*C zMpyQ3uOi*s)xJdr_X)wVReFW{@2$yZ&&w_F#|rKIV}%y_zqw5QH!xb!j~NzRo#Tjz53$0ZE#)%pKFxmp4?8sb`!a9$7pNXg*K;q?3{#wxP?r39 zV@Q_K7%m;*@8u}bgsC_T@skwy6}ycv^VSgS)7uf1P5L$`O<8p0v>5u6Kvlh~FdwPd z0cT6{`gY#|bUSZyL^VdFN%k?|4pdV>|0nTidR2=sNaX0VX2TUgtaa0T^~;zGx(ELL zD+RK${+f2BA8Vi^F+Y=G^RZ3 z^OLhJU%I8vzg3RyJr_rXhb?V~PbarY@=>pVxrQ*s#%2FLCvY=X&}-uDFu^>lS24V^vILfKUO7>D5=aNakXK z=*)n@5s3bjvQj%tsJNQSk@WB-qSfh*`3<#@72aWVrLuV*eeB=S*jU-ZHPn-l^g-8QN$lq!e_4K>k zEXSf0bMUN7<6>c9vR9<7-cCyO>);k;QXLe9FqmfzE)d|O8Hfxq+in>IT{c*>0}E%S z^>C$Q7Z|lO&?f%j5+-r2AdmEtbq!G=X}_&TM0Y zy;0wKu?+m`#_EcCd-U7%)vCQ2NE;YgQ^^fzU}vYn6UY?Oh;)L2}ZdnrrFn1 z;uZaaTa zdmeYhx*eUpHNnol>WR9phIu97-cKBKGFQ{#8!KVKc&)(P>TUP2>QiPISo#w&Z#X*? zZqHOSoZT_?XScIWc1u6U>;*Ze=+!dj9F}!@Iy?bUq$v9wlc#TZZps-`_9^zjhu3H! zVZM-)s`YVLsll9?ME6kfDo^>2-1drPoWaUixVc6^xbSbpqf(DAfv?Ug{woPe++UJy zT=zr=>t@WN3zh_XG06l9Z+2AWDQ`$rjS5eU4h8nBq}JIi3L+k;mqBe%EbsC#F9P7K&NV{{3-a$8I_l@hA?1xv5YWzM z@?Y=adRQ8}w*p&RaXEZeau`a-3|y5Yr6+>O5$n&hB7iPUp+yHYYo4z& zAwb;N2wz?6NVO^SOng8&(N12BzqbWEG9W5~^)wsEH8TBKV}ZK@R8fSzk@PrTQ`#j2 zUF~zZKj4M^doFJZvww}IwnNrsy0oERb*i^XGPXgry3p-&(1KMLDelG9--3xI45*nw zPqfq5vM+nu61I(Sh6L%MXHD7R3lCfVSg5C1?X~)Sca${TJhV!IJMT8w{jt8kX!e!j zKpN2`Yh$M#5lwOcF%|C6X%IOU$fX0YwF!;jWEb|NwTl1zCB;sBmwc6}>8zp%Nc{>j zR82BO5GLJBmCrb+6oY^xzt`{(3?U=vX8aNzo%14jYm``VV%X&z-$b=X2Ey(-g{PiM&Jwk!OJ{ z@;wmn&>^D#B~ax_rvJCx#W89pwgFS7UO1buyF}ifu`rt07kftPoQJ2>BN$r6i0v8qoXvR?CriMkT>gbH~nv zn@s!sKwLX>-g-GQ8xj1Fginz*n?c`LOY3SiO5UY(o6dS7Gefb?eY;ut%wLO!SqzJr zn?9M-)t32YcD+vcSCn249gL|Q{^ET;!GH-c zAkk75t^j2|1xKBBZW9?xga22%61kb`O*vm-jQ2`&lQ0G!I469vOHIX!UtCXdl>XVO zguTjNN8I6T49Xf56Q=bzPhE67ROmV8Mw*Ff8jv|eYo~5CjV{8^gsxOaB&XjxaQw~BA)HT z>@k80*ikhZ)*2F;?REd0^&k`?KQz>4G*N)sB`q4CvEtE7}3_|D4XILBWu+BZu#)73^+6 z5zSwj^D_{jEF#`e#7XPJ04Z_L<*zWnWM>DZoU+Tq4^(s3Fmc3Yq?n@FcIm4XFR<69 zm7KPzpRRa8&#^Nxb9AhT=p*BH(J8(Rh=^<<&ZROttjr{kNxuigDM}VDqH2j^Ok=Sn zv3n?b6J7!e-zTn?wn*86avnMO-WsX0@wIlU3>mVh)aq^^UKBxp_ywor9XR$WKQp1!72S4^x<^|a z9cL9sXZPIqk6=+6|3_f zIEM2atsU{{vE1ai$&->7TZ=;PDZ@mf7uWcxp)TZ~>VC8J`n1sk#s6Ryh! zBd=USqvO;=1mwJ8GPX$f)f(Q1A7b2_s!0&+=pQdMx2hV!`;spli7!aj*_n8xXCobJ zonol8w~Zn}uP9AePYA%;+AVo5{a>8`UEK5V3tK!n?{I%JX={{wh?v8qrscTM~);8_W zRhkB4ccG>8rg~9m1wIwso7}s|I4g5Qe0Te!-1ZZ2{(XqKo3VeMl7}>YhuPvITL@hx zVL)k5c!d7hqKl=Z>y^2tw6^ADdE=SOyWJw~n@Sp%iz+sOm zIeSb~wbc+Ah17Nekj3rkEo+6ii&I6rumDHE`|pZoF5ks!OWaP98@3^Pou`L@9;Gum z=6CU;WrH+$_*J&4z5Iw}dJ=g1%VK^CRZt~X@9u3kO}TqgqoFa6BJ$gUI0TD>XtTWmUaVfg~o;4rmDIHX8D8DcQ~#b^U{Oew2-qp zpwsVTG+vf<8M6B>E4WdLm;ZvyCkXx+{W1EOu1_8Yn+h2XIyjzgIcodXl(Uu7`xmt{VT6h#HAiK5jud z$0GSVayi^5C_BA~df{TmGaPz<8~+Y4ee=L3$a5zV`%DNG1LGz21kccL+oQMr z;{GdIw?1pU@Uyw+IV@~gwyxzC_%9{XCW4xK(5RFP+%=SXlD1dN)FAgM=JZIyMUAi9 zm#7KaIapH3C;f2!6#N(SSK!25@SlG7zDf8e7y%l4@5q8e9)w@Lpw_vr0GTbafcsQK zh&&`SKn`;i1MDmBQ7rz`-Ws|e|E5Ijb8ul+`xzEGQ*BtOG8S^Xr^ACr?ypR9k2KP zpxu9cqy46Wim(~g=I6eL9A2o3{>UGW(dk`m);T#6q=6$*C|i__ls) zl690Qt~W3QGk!w~l0C|_!+H+aJJ~w%O$Z5Qnb{o4ATIwVR)EV9BE~2<4uR;TRUmU_ zV9rMrt$^LBKdO0n$$Yx8yeu_ZRu45&6GOHCy;D2sY0wftddyomCnjmj{bExl0KXV1 z%rDAF08r&XoMY}30gAu;(_D?feF)%H65%x5BHcLf_4JM zZ@=xH+JG8COa6?zQ|d!fPA7U#O#^r5l)w#Q=h>Uo)=#F0seMTJvuDftTC95cLXPoQ zg-_M2bK7bm0x_oyW7?yLAn_m=&5z(c%I^=n%cmb0ym*_m>%Nod%!;S;Wz<6CoO(b= z#Vof5veQTd<%jcrWd;Xv2dqYZGFzUmg0o=Ntm^}}N2k&dAr{o>L0qvVkHG^N_M0Go zp#J`hR}kXmjn076%d4U{=S)6pL-N}hCik8UG6=B_Ydqecysi`#$gO!8s2i*9ym+Jc zQc8rI)tOc(+ZgKTKXI#Oj&gpX*y;?AfUY63MRnM?xWRu)!9BitPY z_J354H_tW&LkZr=L{G@KG~@E!T#cVgSu;Hay;pZx7rr4yNw<09w3Mn5@d%FIpO_z_z`=xS&4ha2NJ`tK?XEf{)(EC^7*>#1Up2jb1rV;51vp7 zj4jYvD2qhb@AM}0=*EQTkG>EAd}*6C_=q<9y2XlMd@BQe&_Rp-;?)4!mJhz}xlXtr z`-Bx9xKS%z{Lofn8eF66+JGa{=y!zWI_`DM6Gk_5YNd(#9Jt+7rLb3vQ$DgEv;qp1 zOjH1nkz#lZ7dewOi=hX$Q&NAPdH7HS*{PjU$8AC`fw_Y`IqPWpA; zRJ$SLXMyPLu8i=`7w)HavjNN}x%hRyU4Z2~!wMC}@=*_P#SvAqI~tAJc|08N_uRl= zRyzk2vFJxQNs^I?{*t~2vw8IV5>+oVhs}0u={BeQhiM8;sVrgUKtcFrSfJ+~c@3dM zw7z?;>UAT>iRvA5{~_b;bq8lNc5ck^tQxzkU=h6P;uUea&QjC^MW2fg9}eNF0Cl$-Bs;xOK+yC~TizWX z?n$q+3Cxm@=2ts7+!AjO(8Yc(aBN_@SVj7Z5a*`BQT&k08t@jXQG*GUg*v5SJS-_M z1Y9$L@Vw&3IE~&oC?zQbi(Ds(Wp@U>F)cEWMacyP40|DFXee39gaj=tUH`KxCCBk0 zfXjGxXo#Ik89)z5@ zAiv!sdIRxM5w$lA_mdap(6MSlAz%#2kWHM~?mEqVyp_5BW5xUaWrq=oDFE#Xb?7|5 zX;-N2Fpg4!KM_Gj-Efgo*g9qXD%JAmx3w%A%ijs(*mdD6R+JNzILl${NUH1l=ZJK_*=qJIi3sIbXP_$t}lI1}YZh z_TGVFvE=+yx+pv)WWmUKh7N8!gFDL)5>{%P)UY~V4wP-yg(z}0C3{`%a+prG;$8Co z$3S`pJ8b$8o~HYn7&khvl@5%x1r?Nu>mY3a^ft-9b!k%84YiXugDDUggkEzC=E!dM zO~?>N(5d`bXcliVjwyYye)kX}PH~JDKm9Y3+x$Lii@B}K@Ye1&Qb-+&uSOJzC^Inz zqp!?T|44KagV%|9GU!!7xvPeDqnQuFl@u)#n&&u%%cb!LD?{rp*Or$E8Gz6aI6A+@ zvdUIfkP3wd(O=4nMREYgMd$LnnyJR4M>>N9p?TV{iS3>w(vO9X8Kr$^N^_c^b1joI zGP5RyL|z^N5=)P0TZG$Urz7|k`WYhqT_Q3~6?loEmU^JmI!B6j7sN>zYJehOl~BdA9)*4rTU$Dz9}*L z9Sk>tS7}~w@^P*JX6f5P93gWdxJ+)W3|-bhnRVKij%*|EEd-Dzx)+!=(k)yj-S>_w z`2=uPVvvjcAbt6902{O_9jYD=1k*4$S!-~`wH|T)XAb=hZai?oaSoHvtkkn*Qp`EA zW7g2oK(o_;1);$Kqr?qUynW!)5K5mk%9RB^f2<5~GuNessH>CNK%g=eXJxE}H5`@Fo?WID~RG6e2#UQkG>8 z0`LaRQJX<^>PpkSFl5tU?7caKI5M>@YH-DY2TuU1Et%oDm7tlk4f zWw(kP4wR~`{Ti&Ud$c_7<-+Z7qko~TOy(>ZQW=EvdE;7(l&ISjU3X#b*UJ)|rG#$F zZE5ab4|nXR2eni+F;z*aQNEJ1LR9(20StRFfN1UGDIT^Dm49<~l;3giWgo{?z$m={ za|X2u0l z;_pBZB*OCp6PPpc`JEiZ@zI6t5W90HfnO$aP=Yj-XAJ9G{6wAAQgz1&WpG2CcIbyH^MXJKPzuCck&%TOexq4&KBX~_6g*{gEFFmRMaL2C+d}luju0negRg1P#lcw=|YDI z4q~a|LFA!Gmk&nNRccFyeg+mFe%ZB^%gO=2l#bc3smq#i>7mE*?qm!1Vt6)&Yfpt~ zeIG*9_IJF7(!t%iE0c=NMh+I=-n%Rf^>YWS2)yX5Pn{LA0@c#+fgAfT6Og`eFZHrA@zywJ`MO<67b`Yja-MxuV0skU^4K&RUr1DvnW9+Wc0!3Jt+?3ZNY8hJ za~eBUIDP7yOUo>|hBIQ}1O~3$Z|(8bz+^XD>Jc+r`k2p|d+F zakd7`t}UQ}O-ljhmpe;Q5@<+n--JmtO+NKbv+D3sD@wuhS`W(1;KCs>?bH|YrNx3Y zcaMODKuB{hCefS6TCqIsV=uvbNBohT+D{Azd6Pg&mLJ=3BXmSRm(%z`bI!CJY}PXd z&!k!|D&{3##kHC7=MrbeFX<%%BB5Cv6(G#SN2m&Dd93k%uVU{ zAEGiJ(VO61}@Svs7rePr5DScIuMpfsUntwesG?&C) zJ;Vz7nSdEZ1Vx6Vc+Dob&hp`L;*}T^L`JgE;5tGLFuhejCc`hb03#)sD+c&cM^v;5 z41i5PQ#?^iILXM<8%hy}OJwz!ih51jfP63$vY2gEqbg`#D^M0zw`~vO*vn_>Jzzjj zM7m;!XhF+kHsU8+?=fhB9Hc$83s_IU?4XR!ZuHubS<8k2LgE~@k_sOSk~lz-WIQ+z zU0`Muu|P`vw({{TAF2=XxkmBcau)8o`FvL0Ba7S&Jd{I&{o%^qA4 zc@q0M5Z})1$a9PL^;0JYS%qW8UL?@KrDCJa7`hc#Oxk*Ewx$Fde1TezYmPxz+wFKh zkt`(kC-d3>hL2>FX_|vSx~}-iK2b^bOx*^>z?^1nPk_XezY`84<;pcU2G+l&DXx8G zD_TX5<0qJ1c|O6owvao$>1If%n%#ix_P(+A6$L=+5_`2CIN$JdzOZOoEa*;PUfMDN zKlAJw+a}jL``4iiz5|&!X$*e5k!D5mAUb@9B30SDQe=OdYS7bgfW`^$7!ur=9>gx{ z+tzHzl`n@7%99acutY)e#t_lbyaC^20l6v4hDc;*aq74M4g1;G3GUqI;UaDApF{5B zo*ON@EgJqxXQTN;4h)F|y!Uo2o)gWd^{qt=EWxjbGlr$B_Lqsty#rV(wlNmN5VJw-*KMn3& zX4btsZV-#R45n#@4R!3Y_7Pc_SM|VV|3(7K@g9ZF&cWGBLF`^F1mW&pg*{9T&EpR> zM(S=*M{Si!w`DAf*80ma7*#U?{QgyHqfAQ2=vQVH$S4MqO?k{0%JMJ{gDYV8yd+#4V;-JrPkbMSl*{AdSx3hhAg_JwIBR*}xt%aEg`nAz*gaJ0axq(nfpCHlL>dYCA; zG*pw$SaXG%g_xi0TJu|U46!YcH*2X9)AmXH9IvIQY_B_-I9*boO(CYR3= zDG* zgoIWBQ0U(Zumg3H@%1nYR#*kd<_DyrR`tBF(og0c+PKyCeIEFYNR*OobE&&@VMc7w z#Jgb391{fM$I>jc7&9`&?8c0(Z3!Ingz5E$;=&dQ0>M*{T)DS0?tH%^LNHyiL=P>D zxWHG8BNdRv>u{lw#I8_85~#tp0L5{rF(tf`{16q!{E}oDA2EuDUa+ZAeTDaH?x^Kja8F`k zHHc-|aQW#lFa{5@BKEBj;MOEV^&YDitdR(=H13VPtF`3~j+bDu)$V3`TrE3vwd(0G zCEWGxGP)Q1n%<;tGN`WS>{JacLvQotIG4~sG%IAHhzGJ{ue)AJbBH>{ufpb;g;&yT6q zx9m8*RxTax1%5Op<_NqPuT|VKdWk`f`r{F@vitOoP7m`Y6j#l>2#ce&ZhpxD6CVGjEb_u& zr~;lGXbnN+ej4hdNM$`uoQ|4E=^Oh~SgF=#nN+yMdf}9p^&yhL6fy-vqy52=1;TSv zd~(QtitAAS=uv8wq&0(iN_&e{0o-e(wA-YeZr3CW+nfG0q=D}l@0}6A&s|AllOHfQ zOB&RsJTNN`j5gS<^}!pMl@$9VM3})xLy@eTmaAL%mN-KzbCx>8)hJm8{Vh8rM#N4h zp`>;iGn+J}pTQ!<_(ws~bk{dE!;0{gmY{(!(kPNYGN!*E{E`STb5j0*A`5`)j zo6z-;E?WbmVBU}Cnod~>H$S4Bpu93kBns83E%fw(sPTl38ljIp;zr4e^v21C8T>Yf$HaDJ=8tQPgWB5a+(Kyi>;jsOKcQ4Ryzjj3+ukz<_AJn{3;cKY{)lbAZnDwWg`j41 zBr;LflR@bR^J`V5dC0*BVU%ZH8*!{ALp(41fDXw4py^Y81MHorYMy@<69T6FKbzTe!r|sHR;NyD-@pTa@AEaoUwk zbMr}#JBps18#KMAaE{>!KJ?5#+`x0!<(Q;*29~q_7Ri%Yc}UmC^x=QvqI~jdqR^j~ zxDiTwX@}^r5p2gp46BS(4hu@20&j1gcYNR?&JaNp(1>@& zC42_4O9}i$c|h!h4&S%2nCJ{(PyIlgaG1aT?cEWZa#Aqq9i(F|(&*zGF5 z+K>EFl_GJni&Kp7HVSONe%N~0D*Ceyo;UgRS!kj=o3EZ<{9Qx2?fEJIx_uV65VH;0 zODn`~8zxgXo>)H<(n6u?_~cr7jZ>C{`F5-I0d9u{?7d`$HZORCnAb+JSN7-)(ekq< zX<_(;S@O&mxr`l*axmwLE-`sn`|TY4vlt2DA}91jm$gljH){5}@LgBr`I-JrtnJ&< z=^MTvw&-27;JpOhJAkI)Eaf%`owG2<^eLPE5BVoxL(O1|*xR5^w(O=8kd_gxiEW{`lcK_2m*8)?tV5G~rLguudIiF= ztdct>#+Q_Gy`=eFc^j)>3%c{i<@jrlj#0v1o0_@mRl#nIXPf8^MV`rn?5yJllz2A$}OPL-S z_%QH1f?H+i4oY3iI1n^WXqe+SXeL#kY9bvuG*RIGaVau7L%<*pw{$gFq)p#qEqI0`PWG}#296<^?}{%>R-~%R8lZGfo|8x~N*2+vrkuV`=CYhS zbRSmvL&~#^dH@G`(BTyKY{j3^I*5883t7mFbKtERckiAZ9iNJSfFj|^F=lHW-Qmx9 zA)f_lY{)Sd+Dx9^F^Vg!NRC!q;AIr)AW!;t)8M+hg1rU#xnz_nvxJmn zkzJ*UKGd~TA!}9EzDC0mk&;Dma)Jn3Ojwl}+TnosPjZlkRUT@ldT{Hv8zGepf__~U zcnM#SB0-;4m|Q%6kfansA2xlsbNYac415J+SaJsUGrZ{K3H7f|%o)uvVmlGU&O~Yt zvU{3j>@-(A*%s>Geb#j-HW*>lV09eesyX~E{E97-v7!^10uz>!Rw!Z20V|mBmScPu z42dhaT^k&bHF84lGpUP;_HDki9j@*h0=8i_QXHo+8dbT@Jmw?xiSFKrRb`~q(OO<8 zy4g+{SVYU@XUliar}>xx+O`9^!`?}9?iYj1QMMc}Oxs>`(hE>!VXT4+k!GZ}O$bfk z#{IO?^0tTTBJ7j$83u?!nHNaLxM3y!=fd-+<(I)N-b~4V`^`TvvW{H3glF3WuN(KQ z0x(SF%5vN16{8SL^>alT23D7okdY1u7Wf9wu${lUE3FJwdRxkyR0l2f*!fahlrbv7 zyOtHalTcM-Z?qL?QaNK3TK7b%e(^f|hKETa77>O}HVOYo>mfnVh!+@Hqx(#=z%p*m zCow81lq*LSu-{PIv(SuP2f3xm@Q-sOBD8>qk=(6x?g(A#<)30A2uc9KRoa58q8CWk<6CFhAS(Z2|p!R6W{h!me>O4sGp3aK$cs%4p= zAA`Mr`-a}}pR<|JnyU}m%?Pe#+sJ6^z4YTxp%_dSs2maeLX4&+h&&BG z#F!>KtqR zw727DXYhxrFP<}E1i>%LJdkU~H@Sujzp@wP8a&KLf~S*8Q$x6J)TU}~pJyZ9{p);! zo3>&fsd$x{KlLQJ^oL%Y&7Q&jNThv)mh<84;o&H0A@{Y}78xb55xNi+~|J%AZx03l4;vYtT?nnM9{r?6D z{%`V*|AX8|=VlEe4r=0KqR>FG9smw9Yf_2M?*NvDfWXW^Hmi_y@Ndf0-qa&kBc4T)pt-o_3#de7gF2-_EJ|r8V^I3f)yQPH$wH|TKTH`@JS^?09hs^usJY*avjk~c(Q6hxEf;nGSvGk39*as=GB*m|E0m#6 z2uMn(N9dd;Mk!^qq_8}`VMmH1N^KK{8fZ!~xYJ&Qk-^v-7go%f*HWgz61#nD5v~c9 zZ%tz04tm|FzQ^yh8yA2JjPW*?(aV^8NAVYRQ8^nCqG&R|{8(8M$=h}2+{%nau)JUe zXMvI*Lp%bt|It-CEKf6r;p1j1zc8m%nYp@Rh@%dr9jWebNXD*kcGQ7cas0_3J@lJ> zhag!KgMu9(8Ai-#x{HV>Jh#~tbf-f(C@J;~q8~xWRJO}iR;&wZ2T=oAfF4`L4mOV- zn-GF2QzRNr)!3*P5VAO8;>rD)38CLTbm+2H8hw-hd?ZxZD*{Q}vI{wSFS#HZ0V6ak zRJyjefInj05&`cJ`r9)lB45^p=?%r-fR?avNS*-{24-Ikd1pc_8?dg8z}TBQyyX*d z4!TKXtznqG1o5LpIE*9MT1)`BU6jc6Vx2?77?mSJ|8+=GA)!NkhE(a}#8_0tdvSVu z)!xFi8|h-GL`n8NCFMs*_2$?IpUnZ${5qAyN4Z;5l#Tx19CpyH)v67SOht~vOrB8KNK1brXpKgk!6pzdE^Z?+{KN5spqIU(>MN5oz1^kYXsRCeijGI`} zYKjn>*LgwHr(|-coMI0L9dFVBc~it9%&bUIh`m*jy<%v|3Faxxow_9W75dI&k-0)7 zJ|`jVTepThan!Z>P*9Qv821`}vc@Bxdo?nhP!jUW=(bMkcevoBdy%{b;q4~g%n^%Q zUBDnUNex%tqY-RW^E<#-8l}(=%jC%Ljp|U?O5qLFO*Iz?n;rZXZ}u%ikUT3HOsW+& z(iU5EBs5aQZEN*pLedroD()sSw>|a&gB-*$K>rpyFE)d0%2`T5%ZF$?IR`$13Fkjd zE)db~M(J2c_XzU#urj=XCFzzP_If_xB^8*OAG1HmpPN~uywU#}Q2`Hy0AdTMjbxUz zY&*e4?|eZNH_x)Cr=;nwi^qWuCZwgm=-qBf zgN=^8+L?>JvE4sYIWZ}4w6w%>eFDtMooP%5jNND3L*DtxX*M;4R?V2hbR2z<-}#-- zSKY^Cq6KNc3f3m-Bk15O0|8O6fZ9R_{T%PWx*h-eOMmn`k>gvt(Dml#*jrCgT5lJ0 zrDUXCZ(5wAm$f|-(71!^D^Ural?1l%f06bUY;|s1vTza{7A{#pf&~li?(XjH?(PJ4 z*We!9-QC^Y-CYBGYoFbxzux=yeQuxAf8iZ(%{gY(7*&-6N1=1Qun`@-Nt&dsozd(z zHC&U*N%nJo-CA?fal$;SK{Ud?`J#mY!)PKs#KHvgSc;WGZHzC>c>?At&LIUFIbe0A z(&u`)7_J>%iO@z(Fiu$?*?G_$VAKPr%;q;@R-^8cVYAx1N(&0jym`|6;q@Iw)2*%b z?T>I>8em&0wO-NFu<^lS>eo-c*!l7FP+Py#TRg#b`Ro7K-`O ze&mfp5BuF2iM1Tp&q8n9Jq@uexpBX+H`c!X{+m!Q1c}}@4BB1J1_|~5(~O1x9I*PQ zQ2&4TJ1=*y@q;XtJoZ4 zfYzO*aD@wzI<>uN2U14G%Jk>*-N^PmdsEv5wT+}!i&X5rw$Kx6yBkL85SAQ3K)H=M z`X`0_x*<*JOU)o4ZQ!01undi+SIN@!1p@M$`l)~QXO?+f7%Ld%5SxgfUjq--`cOn~ z@$>N`KL&Q?Q1;E3xhglV_(%nA>Gkc7BRHRJwpoQgQ(H!D*$TI_ixujNsg4t(+%I zgQCNduM0gO&*E2O8%|4chfx}657ceUQc^Rlt^bLi?=<@fmdjW^8nCnad?(wubGks& z4O?Q_VrbS}xQ?OlO|+@8a0`VF;7RynOLxMGl&F=WaMVIt#bM(Ydu!I2FHX%eMFus@ z`$f=^8NgUQe#I%Ss>atWu1`&J%&gIuH82m80qc97G)iC!1VH5KzWsLXl?4Ns@j7y5 ziBBBjN&y+Mi`5gC@gf(71;K%eN*s3FR~yMZ8j%*z{rWGQY)WZnpZp z=ht!IrLl7_c)+@FZsyyx9z&t}jJmH8gutQjyv7^S&;vslPp+|?D!qdqtZ7QbywesC z@*`s|lK?;m_^sB7FP)<(x#46~;T%lp2G^F&*BPIs0AUQrr-07{c85j!WHvc|_k&Xj zg81$=RPyh@BB9xBWCa2NBAcejVLjs6BzY0dB_FTpBgLq&B|wx z3baJ72uk`<{CB&U|CgqL|D!-cok z3s@&vJ52XLr8d2qYKf(pTMr$Zk>r?@McGfr(!fMZTg?}#y3^8vmExisqx;T%xAfGz zvy5?dwFu_awl$>{8p}GZ{kjWRet5l5-4~542&*D>$S#N5XUl{I#hXN{)Hb|NfG5%D zH+6V^9sU_c_KC_Q3Mt>Y{epa>ub76m*88CYts^y(<;;cNvgzWAz=HblW~@M5WC&h= zpq`+lvUs|ZBICuCSzM!W7-UGXjXdgvmCZ2MG({jgY7uMD73;BLC^P1~R;^;J@T1(b z$P8en+IMT?tfdVH4gZ6~U1v>M_W-sRfA6$zHc@*}p(J zRN}TB!FlxJ(#UT=tvqE6QliS?pf@!&@>)uyKmm>)udN`HpaoW^MB|n~8P(lyJQMP_ zxDyoVcw79YOWwZB9*?LO90ipfQ3Qf&)3F3+@h)h#Q3O(a;DXS|vG(c5pT8GRrl5)r zpUe4gP8uI+&r1IC=H0JakmrF^Ci=Ne*k}M4QLzoXiKq03nEt69gXv@tVKz_1*FAK- z3mMEr6|!;TUn(ED8Iqr=<9MHo>OsM=2u!?H&CE+C`7Uh>WfYf&Y#y>v^(4cGE|s03 z=MJ>|g-E%Tedc0fXeTa`nIw{#Nq`RFV)S9c)HMo8%#(7WC7G6Q#Zmq3lXml=<7ZF& zo6jf+{QEGWB#RF_mm~`?1e}*!mp_|o?Cu|q)Uu_o!8Ceux%wd{b|KWb*8^($ zQS#Ri=w3Gg-RmO%?g91RL_g#ws9U4(q7A%*p}|6^7b%rFyXWe()SHy8B`&5egGFPG$4aLpGnwgm-1B2jj9V?hntb4QqIWkMztA|i+&M_H{(vDPhSyyw zTXmc=Qz@zHSX!WotTw}Fp0cMPSvH>kq`^{dB&NI=yHLxSB<{D;f4>rF*wWH^9jYw& zi8fG9It}!&uS}U<+^hfg$QuE)4GgdXdM6tNSENikhy&cpS0mhdY6>|~R*~wftxjrQ z09BGBNZ$o$lmZs+n=IWnd}#LDX}$)Qm0P^CN3cQU zw$@-KzC;A*@`z#*+wUd)W?V4SP#Ve-o;LQ3;Y*Ml$ln>_tRZV!sTIwi4j49@$gm6% zi&$A@q%2ChB?OM=)B4W%HFnwzOLu8R`{8T!?txQ*ZuO)e4CR|-b7E)UGTxcdU%OAp zg!x1FFWfyR3;6l0z~|6}7E{^3-Yj{>1(9+Js-}wRW6=X->H01!t(k~I7a$ySj-dIa zbrQ1|gQOh<1xgHR$yO8f9ayWI5LnktQJof4%YI(5i;3@GU;yRNtt&60FqwmjsM9SF_JKKk` zAnr99oI9zVumMB$2{ZQz8}isfira`W7etrNip3`j@%TX&U8RqBfF>tzr}Kj&&AP9Q zRAZSNX&Zyzdmj0w?Jabh9(^16yq1sY4Q0LhU}n&>dkh?OpQE$%wkaXVrv#1=NmB&6%{r;34X1}nLv^0NI;Y!zVVkZ{9+}G5+)D1dnXX+Y z>zfL>EzOkX?4ucHBw7yW_Ysv<<|ZVE&)*P8no*@zk5!+k_XSCi(;4?)r*UGQp`2$x z6cIzfoar~`yYHavqb}8ah-VxyJo@1tQUP*)P+ysw4m3(Al*38K92PZ6uMU&o1y3h4 z5FolWa15h-G|FHlS6jzBSDB|W5t6cZc>B_BaaZr4+v!Dj5G<5-@k;98Eeyrson7{atU)&c^rJ^Io&9}Zaq4L_K;ivURWz?wF%*Y|_Gvj#f7)fA`+3-9F-2 zodaY#D6NtWl@m+BVGUpT!;*z2$0OaH;=z|s7KEbIA5xIM%(CUe3$VsXd@)n+Lr|_? z(=BKd$8>5TQR9asa(iWQ7^hJYr6*2{wWbS`CL+IKjmVK8h>rr>DY$U69l76j#c1&8 zkgznA506n{3ZC)ZJtpOXD8SN8^?d=HdN z##A*#v5k5534E>ow zyI^w4M=-w^gJ6Xi!b2`Xkyu`tfV>L6>7Z0!0bY{z>|kiYA2fNFl5(?2-84_(!30(z z0_Rhq1LRc>*R1EieIM@0iR$4-EW1h}weaaZVWfDm%zbaO@TVWYi{LWyVp#_>_zcOc zGpse0Q9hv-nE4qO`>v36(f`V$T_KFH=wZN-n*leqh(7cH+d+FbwRl4c^YB)#F5=E^ z=dt2+{6YQT-K#v%NL$r4;$O?R(j?~naUNXQ`v|$tkBDvUbvET$D`)7QEV&9~??qLAx{BEeq#ou~}Z#!$fL?Eg*8FVQAPm{_2 z4{qSUhUxsr=>DG@SYB4py8(){u)%YDmb3naUCU|=XwV|CjL|%Da(R?ivEnMLr~PY^ z%WwW~{$3a1^soN)cll>5ue0N~!j5j|=fwV>(}TYnF}q)6+@u|(-K^I9zPYfb{-`0` z1BJ+6ou|BGG$vCUTC@;>616}n7;$1G7@}+_xwKn=uFMdIol@FwpIDk;n43noE0$nB z-)g1C<$_7P0c|A2cF1zG*a~)P)IUN)hs+ zRBInZ%qIJP@CA@ehxR8O&k-jG;xYLiB3^;9B%Z=_+mohc(EAHMp00KB4Gjm_3o58H1jhBX(*Cmwpxq(urKra*OG zX86OgNasvhu!sC!+2z1I3cuMJz(>yekVL2<P-;f1pRmVe;xMo<;Rc~SJsdY!m z27a)1d)S68f3iu?cvut-)(_7PyM%6Q8~wS>)J2j5)!^~?Biq{hA_b(uV^}=Zp4U_qSq?xFxz65`U|s zjnl@Aa+>`-KK1DEb#hR2_+9Q_YhoSMRpRCc2SF)%iO-J`A+Ye-H-4)Asn6O7ar zeQb6Wi^V{1QE6yA8t@F<5lkJJ3*15JBLX|UbHA6U~usXlFgH?1VLW#&3g zD(bGkD!3q;bCda-Upp$QrU znr5?03a)IR{!3kq(3ez<*p7hR0oF7U#6V}-Q@#Ep<<=9NSBP&fA1hXV#OiN;q9gd? zlrG8Kw0J150T9&2+waP3%s^NR=Ij&Z?tB1maN?6M6SNCD3uF=J{b37h3ui3y@gTZW zPy$bkaivUT6yDu;eFOjA_w0+}Hjkrs-{9NvIP%dfdGSk87-JN~=M&-L)Jl*~sE{^& z_5=qhhgYPa7{2=%$;v~4Cir4Kax>)DmC1OJ5EV}3iUs9W< z=0|;$=*3A}ObnUdY4&iuikErJf}ii=ky)bx&XK4BdjrpBIef zc!l!4pq^w#H`QmL9q?k+U9HHwp))Pu>2}Ed*Y=bOZMeMw^qNBkz2^SyllV{H!vAWY zo}Xa;XTbFL{QR@T5?>cVtNR=aUO|WKV3)2uEL1=UZqT{PKy8hIbIBF%lPoHjEb5N2 zcl_0KI0ANs2R9 zWYeX#MA~o@%=y;=B`$NTcTLqz=G@k9b=a0YJ(DDi7ia*D!lK3gOR`IrajrR}AWixuOjShx>( zp_?3_(XtzEZ646XYz+#NeUG>W*0+SdP7tcqex@8ZR5@`b2k5UNRCRNWPe~QrCU)!? zC6vJSArvarmmradDxm<3;Uz${){jrL97ouap{|lLe0d}m#l5D13F}0(fRXxuD=EQR z734QjX|}p6iF)0Vp7^|jI72;UCA5c=aw(0LE;nvday1ySRYkCxWPOoDzhz~0z=GSP z`Dbe&ZQgBCzYs7m-sN57={$%fv1sfqcO+8!TgWFXNJ+1-E!7R@{_m`aR>*=xUm1qJ zf)NuRmO3-uRsmq`pKI&2VR-d)le0aQ1rEJAF=#yKcnRGHW0NDnJ5YP zd)20l;Nn01G(ra6N*vFrUMKUX7{$SZz7_Z+JsE|b48I}Z8G&7OpCTUYNCfoZ}ll~NDgGPnqg3;zr z6@x;Pk~`O0fqHq-ojf6kT|;eUmK=;#hGnQVfh=UUi?#GZNt28 zyo2YQ5N6VXam=4xnOB$E{)P=>d`jL{5H|4sH%!N$*!W9iO8#G^3p@g@E5bx2RB8>86UFuqu7fh@1H2*k!5{FDB#hA^b?RZ!O~J3CO1KpVD1oSsXI`Bt4}wNY z4a>DUj0fPhdL-pEkf)yqg&#z96!q2!d1^OOe}cjk8j%7~9gXCE7c#&HZSg4G7V?#M zE}<~rsr4p+`D=eSO<_LZrs*2{Eisj`yx4#SPc=+3MkpcwVCH_dyp-&mSwpVKA-j6L z#&{)1Zinh2KeseC;Zu()*f*B+F4i<@5Pa%7bl^2QfjxOzthVuEngGnU*>FM;9d!r7 zU8iJ7U17nxnJc{Jig9Se{O_x(VD`zzKsju!XAL=yGsMUYNbOwHT)oez8{f!rxgdXh-d@ z1CC)FBKnx*U5*_?m$et?Q~0U8+_Le-cux)R$;kzePK>uPfaZRM0mw?UXdu_^y!f)3 zX~)tb?^zUz5oz}y2oVMu=go_1e@{t3$_>hU>PDWm=B~mkP3_qIea>u7g zp#Gw_4^>{96FMMM1f9@5hm_Exx2vu7O_CA{a;Srk+)8pMd_NG{Smn5@lh}ejFijTlkU4`|)S|VKa2v&b|e+yEv+@l!_IjSnyaPAg4e}nw%?QwMlMmg}m zq6Fr-Fs8!6pL)zSM*>(K;f(uT&;f*UIzG z7~aI+@TlHwb8uEj73wZPhXP(gxZ%!uE4Z&-$ZQWS;SiO(e8mLsrBFKg7roC zVf_H#6vabH%J$oBGM*vnc8i@NnC~0)pEkPmy4`h~0P37aZ_Yq?J0aBrn$o)yxSvB~ zKgdUE#8#e;#otm+;HggX)&{TwG8_bCgdhRN4B`5|_)^6{ocl52R9AT!2@2(8A=m?8 z;!9;ntf8Q?T{;tO_*}qeR`I5hJvd9<{35d^oR9+NvgTc_5!tRV*!UM%%{~$N%K}D_ zpHra3SO=J#NR$QetX7A|FiE$-+=ac@oHO{&=>DpB8Kn-AXsE^lGdXjCCRE;!ln&7F zH4X7McDEx%9?eAMvi6nPq^;j|w$mpQ_snR`)syd3{Gs#f#=!XPG0!7bYk8Gy^%vYE zCJA%M5tX~teo7D%_>e`_{-`NB{d#G=`W0Rrn47btI0==w;ZEFA9|MuudwFi~wI~-f z1hh@Ua({wUFx0~m@$s3O$W#Wbpn_qHEO?5)q;DFT4i|(Lp^I>}^n6tN!D)+D$^hN) z4`xDwVt``eaEQ{o9|=^62)57I>8lg^WFou1(uanAmSiE`LPDUgB~jEARTOjW z8y$AlLiC;{9aM|#-m0!Stp5!1foab*dCQ$COrs>wiQD=eRv?UjWEVnUj*$x3c+ZqL zTb@gnn>3Jj5Hq0W172ojZmot166zxH1E6}P5?aXY6^R0QY+920Vn2u!Crax2+YbB1 z0bZESMOY%}0g`Z`W0l;=(2OkN2i9Z|?Au+~0ML}IPoVIrf?uvLHCy%zQ;?`%UDcM- za9x48^>o{%oMDrQ3@7LVWgd~${X8CJg5a;wqS1)IL|D()4>-h>m(=6eR4Tk<_l*EZ z4;m7~ylCcx`HC&gUqq!lh{$irN0!P@?!P&63Zu3PTkp(v9t zoP!)HjlYJ>PeRF^LI+r$#c{^#t96^37+%KezHY)mInUomeqX+b&=mYgKR z6Qh=;ksZR)0YAcCOz7;$-~EZ&E37C!-0;&;Vy54?%U0IK4POsR2b9%RQHNsYbC20! zR2)0Ij(HvI-XjC0_+gjjxT6WxR=!@D2*`$S@~cI%V8S^xtqaV0e5T!;pT>bbjP|BD zfh^k8_GEUGrjPq2V^6kYv7AtWoJwmRnHsHC3S>I}dbo|9=pNMA)){rN?)ir{Ge%FekxY>#!_r>JaF!P|G zluluPfWssE3+}e1_XAcA6-RGA?#WXfbU^Tj#NuHD8h#Yi$XuGXCoTJTYLPN4Ivh(H zt8#4VZO?&5zGaRcd}KfA-b+AIoY%#N06WACsARRfhPeRq5=5E?1iN4z7oX)Llk+Zg zyPt#wB!~UdaGU4F_E3#q2QIToS$a6Q?Dz&zku^##E;$_(i!PnZd9Au{J!=;lWi^tu zDq6MUbyG4H3ImLW-tQn=+udBBE1?xP*Lo?Ts82Q>;eQ9zlS~@@e*PB!eu(>sUNi>n z>V{E?2%GRA1jeWQH5;xVE(T(S*JT@T6xFvvs8nQ=mP}wTeGAwBESSgda2f9vLBa9W zvhLJ99pXZW%_H>)SbzYQu4NT(GVEX$M+9pDL-M^a3{44bL?L=5xf>RJ(~6(q=1yRL z$P8=7Cp z#SLggW<+TU%9v5984Fb08Vbxk5}nbSiDjId#IaiuH4E&ai8b0g^Lp>ZY5OD!H-Aw_8g>;&0vpeE_ka3^UgU|1#eGWQ@2bICE!=9Oca3n=}_ zA2eBJu+Te4Q*7(<1nL~tEGULKKS>+g!(rk^#uVqILKgX2&V^Se|D+-nl!L+~+!Ae! zw;}8(MJqTE3%DJ#Am;o1ZSD6rUvGiSsM;stYs-xc#egn%NqPq3P+hJRPKkTRxoTIt z$Pz`XHFR_GI_@=I=9MUU_+?LhMXB)Q++RHAR@eX^86@)#xZ5rn*(<^n^w&)PC;WZz2 z$jU=r>;kqPKOz9U#LDgc;--4OW+w6vOE(o5uJ$rWe*Kg(MREM2zU!zPB6m$QUHN2o z7GNcsOthj2$_ii&gqwP8#dpWWeK>STOqIr!s#II?GxA~cM zN-ZbID?-FRRta|NE_BUhdm1jyZ6B+H-I4J3_+_Y@E4i^Y!oGH0s1~Y2-=YS!^MsA0rPJ^0r4AHF@CX%4Zig6dLucGAdUN}u zG;jmXr4J%L6_S!CP};QPNFz(e_rzvf8qnT7moT{tm**8m;?@5sb&pR*W0Srv&k~5O z&{!MhUVXHJ&nCgdl{AjVWi4nD9Z`uD!95Tmqk~OPU{8d7O_H%Q{t#Usy#j!D^3NZm z^k|Cf#}or^6kJQ~F+HAuw%Xx1pPU%+_#7~W5rAJjV;0t}{ManGrAR)6LWF5D)41Wc zXH1?^pUy?=QIgJxX+7}FbgXO8C4|Q3<63XOPm;7hmTu_+=mG4OEx%ek2P&J(Ic=8ta9sk6R;(5#-B;<_QObW|Cz5;# zOMUhkC_`{&YiVmgbIF<6JhOID?nN?G@y4HKa_*xS1K0x=e%a!NjLs zAtw(a$!}YHo&9H`&3~zRk480F*_DXziC&mh4I#BzItzS4CS>eIGFBc8mg>O&^z}Vwn>Bw%G z$}^ui+P*I5wnR&;GtapjjcgVzu}=UZc*9bf(YT#N;g>QW5)+%5fGxfUm&|9|2o_2R zZAY-@;x9#n>jO}W6Q?@Qixe4hVp!#k zfXw60`dB0(V@kGWlA?~v)_xc{RDZqd{E}wYS3vOs2k(ehSeCH{%%D4S8BElDHj0)z zXU*4ZoUnNU4MfeLXTBeIpiCoO(rO)uhVh|JO&|r&POv7c)V>j@a{;wz;Yw8F5UPB1gl0Xq>D+q5 z57d)tN(#JOLdt}{Qq@p&!E!+R^t;&&5<^T{X0$YeFX<3bc*-2M?5W^mN;#hgiVhR9 zqOrKNtZSZ3CKrGDW#>LVpevKZdcV-7M(%UI|M!lZ z>+e>=HVn&=Sh8I5c|;p*v*dy=stKK%$49Ex`HIWbWxv5QrTfog7GL-m9fBoimfE}5 z;p901l}*>U$=;#;xubrlU*43+-owY}?E-5P>SaAdYrlz|Z^`&;0P%$nytXCx+;5rx z`uw*Q&@5{Nab=(XH*E5MlT-_uoBKm*8F-fm4Z>3@L-dj>yUSw8RH>Ch7jh`*_eMXm zI1I2Ar1!0r^+)Zd5<}(?_ZxHnLuqM4nwe*)`I*jn;QVI4pLSFMG8_G%BFGhr)T1<1 zo^qZI^4hI4ml928lva{hp%kwfPVgYon1~-njoe1JpV%4Rj=a-oEfW>Cn2T3Lmi5Pk z<+QCoJI*kRrxTuxjKpzB9N9(qlB)J%7{^3uD(X(!TM0e_d{<2{@I%8DJ7KFcW zp#|)3bnLE^imgp0Yu~zPRNX3;=<+nyR+t!3;ERC;taJn3b!=uA4A&?<1cMhwA3-L?)CMw_o; zfSG4;aj@AkAj-46CkX(=BYPKe9Pp!+09M{-jJs@mt9-G&Qa21-rXR{|#in1~1!N^( zH0@S?gut+!a>9EOz7D6c)?FoeqVx=`pGQZM*G>$d_L19kQ&`&k=*N4F5ipsI5VfXF zK}X8LEieg@)wZadV91*pJCuGFXG{0e-vg>an*X}4Wj2B`v*ube+@FX(qdS#LG zMwcvAhy+bW4l{liXOMxRFgI+EjFaTzQBf!A(BI34#L+MN+OXs=&SWFHdTpDV3es9^ z#6en%|J@&2OEeDaYb)yM={fFS(b1WnYij}uC>lokUyx(}U7l;1(uwkn(HAc*9yK$C z!a;{r)H-=skv0pdvO#H7hpDN zlI&N5%@b*l_!)cd?V^pybr!L)fKmV_94=PiiAX;`IPx{0Ke&JhkADF^pQ+U`8Rr6H zVCWP$|HO=ri=lrYn*0!Hv7RKI!i6Hp;dEefC7xm+*LI1%_hMp{y10R~@DPVy4|>g-_m2i*imAzI9B z!y;F{;oRL!%0->UyV~;@Ldo$Jy93tYO0#fvgr!acuG|u_`U$3TYuE|qijO@vC`#Er zx|o)?`%dhZq!oDu4+3D|53&A^CJvj;gEyu55;mdQYYZLmQ{+*?uZx{XG@&a=1pbm- ztrG6Wm|~0J#DQX;3>Ig1uLu%Y#UH0Ge+zRl(9e$FEkr3nc5qQG8ZiE#Stb;yOsM8F zja7_oDn@&|!m=13=Q`CfQP&V5YzxcZ)|9xJ*qW>#;fT(XMOrcXy+e3gaP95@I^wY(n50ex#p& zYUDuF-LGjsz)PlVgN&03A7AJ5^GrzgqD~r}S)x_2>QAb17+g0@rqNcBLNeUAxnx?U zLHn^#?LoU1kKZD+7Nes*mZP5~N@Qos`T^Fnuw;s=D8jwHN7;et*3wV(#t&@V6XWd8ei#()cKOH0RKyg4cc# z4h~Mfy7)9(D2GsymRx*sZrxjyEoX-_WaJ>!V5Q848~}^oLREOaS1@S2_x2*dfS>ED zDYh7Nf=%51a?K^fT2(6RN~*4j~& z)F=V+Pv1UCZYtR?X&EbYTNW^z1d-7^_8Fb?0~j+Do;ifn+x#%fRVgBrZ5t=83|m!( zq#Kr3jBf(9rP{a0#wc6^pJylT)0q2oprfdq7#=UtJ-3We)_) zL-bW#Miv_>`{SY7xAN%2EN)geawVARlDv|Nru;jc#I*uL2&F}0bcgjHW)=dJWmsS7 zXYrvIOA-o6kg9UH@vDto5K1%`p*8zjh{if}#uSiim%SQ?AmhJ)eU47+3p?MJH=rEE zPQB2xw0Q-yDDBKtK<-LRY+1AeYiD0%a)hcF+k})AJfN(#`UZo{w`^q3z`{Z`0NZ>H zn)Omca~H3!o2WdauI>vyo7AXZt6k@}kkvEy{-nBzH)gbnG7)J3~C{+h>>!DK+!$hsPXfhajWH~ znfafBR=nwFIO%B)k(60AoQ>Y~#o^s0mrR4XbU)LR8c0UnoUV;(Iwwk*Hhke@} zS?PKxfV;$@nlMbhWsu^pvIX_iRBGe!ri1WB5&QlQ`S#+nZQH$8R#logH-^)00ne|+ zBrMrEB={cwQC()Q+Yg0{90~O)WzII1yVMGj@EZfaqP!4q8RWg?@)h%~vdxmM>Zis~ z4vcn|CgsS%ME zXE%tCQyD%CbEX1oES39z8y#rn$mxv*xt(@_8a|2t;gW=nuARLh^`BET|Fk&$M;ei! zi@u@F{~vY@O5l+KHGG^6wVKs3g*;(OIE93TeT`cIpCxchQE2Co3OzHef}BRrEo$h= ze+Oi4GDk-n0L8;eGZ?<<|JE@pB(4e7oQJ{=s$vEjm z69ef6OGABo!xfO=%B1qEx&-osAS>uO!*_!)U3M!Q4zkl!5=;;U`F3g^34BEkWo^<- zOSW5_`Q`={LJFznd+vVqFoU~E7doI=mQL1F=SU=4-A8t4DYcIw4_Cx1)k_v~o~&PG zsQhwxcg>VJCFDQSM-UIYtm08QC!^#xy5cF|qzxw2%}@1jmAlj{H`bYoOu%nFdBZ(; z0jEyv50-7eq%QKG=Y;g)ciUlLwVz&0sHr(WorTVqF$iQef4E2a9j9^UV^@&!9{V_r zoCTxjWMh%#Pq%@i3^96x|KRuKGp4D%=4Q+4^3NQ*m39Ia3)z^AB#L7>* zOJwuOJ+^a38bPg7XSZtX)CGm_qV;3^()QJ3EA`q2>*1q@h*zXZi-W&#|E}}l@Y>ee zfNDPisy*+&RC@tOOH0>(l-y3j+Su68?oWL$KZaephX%CjijW^5M_O@>0!CAZ-mRzm zJ<4YQ4d+vDcRVDj2BYmR3v@fWgb2Xn0~gx%7lJ}DC_>1M^oa*{P*?x%;t5t6l8^Ew zFtLI!qgPFcH%IOaE(2?6j|_$ou}x$>wD)pxCS()J6v&maB-26$?N626Nwaiy&bfY< z^CPpKy_=Z`4YU4jy}scazpc8^^eG)+4qF)z;OY2n7}%`>K@?7-potk0$6x{Hc~sZp ztGle&zR-4ETl>PHO5;qYyJ-84U(qLntVZrhrI!z1S2Bmaa2~Y|r~e|iPJbCX`$@}t)Kra1dNrWO%d;A0N<5rrTEx@_>{LLxPtsPHsd#tY+npkO7eo48uf z?a}-UdF8OtJA=eIKHOW<-t+t;Ib|nB}(Aiy~{^r2lxby|*npiDt{dmDRaLqvkVOZH8`U^ZA;FSJgd$6jJ<_nz8ZHYY3Jr z_(zNk5t^eZKitquqZO6hHrHh4i#FGb2V*bJRq2nXTlqm>K#p(UHY8B;g^8u&c%F+C zvvE^nuD@l^1u)EK2KS1*3#cG_*&SUe;*luzE%RqgwxVeV;KFiVbN^Z{Ho1~21pXvN zMljTCe6xGb;K7C7vnq{1Uq%p29`3HScYnRv7tWOND5=u$XeWHyRH=si@&L&iFx9yDg4Qa|?zHurAY-wI}0C167MX%Sl%U+EZQ)2Q4bKLn5v&n zm%DSjoW9^(_zqt`ApU~6ShBQeO=FF)Uk#aIjFP%^A13_QN>hC4Bsc|CI2u&#e+{^Q z<_HNG>RagAfl@)Nt^NeAV>G)I7%w1@6UHEp2T#TZ931`|S*W0h2y%`})*>oP7$)m- zl2I$`7YL|L8R!WN4wU5Kjls9ul?&Vo>kl?CK`;P7o}m2Fq+7YB37dBGnZNi7_&|Mk ziZ*Gmn{-cX`;e|_?5`j)X6(X;jkDn->Z#fSLxVqj@OznO`A@q=SY@#~Ra`&KP_N6czYnR6Js)rW4K!{9d2_Cy z&$tcZMLGT@(ERx+|2zc$R$G4)?2*)ehmZ*VtBb)EC~9w@De>m*>KXFGugM~wp&#_y?xX{$|HvLFS#&Frk+oH}rbs4!IMGM%a8gTN^7 z3%^5K^m0-KU&VkDnba*6 zZSqaW#UGCyOA-@8yw(^t{m&r!e7O;^9#GW6jIf?wU0wU}ykf~D?<(|F6;g3n7GM6RT}rsESW3KT@uPAx z3fk`v++wYwEu`CgClu#R6QI4d^{9yj=MV0Sbh0`u*W38gLTZA%C{cAJPb`Y~QE@z1 z*}=1A5^`K9Y%#wzV6~4+Bo@AIQf!WE%5q(M;3o7NB1tC`a$ zP4927mGxKT#f0RaQ;cZ^BEHCJhk21=9$TG;RFc#VpBB}`uNV1m^}Z^{A*_8K3R;5p zvwHJ!klXF&#jBf1slguTh3#3o2#Zq?XrJV|kV;Tx!e%Tr>S*fU9DT>YibURL>*;Ex z05~yETohWEMc^7ujyw4$MlyX``W`Km3Q8LbL#6A!9*4uoxT%z!9!y_RAyoZIh(v{~ zrXu91)+!yZI_k!M76^STy#eiH3{6q0?-#90KVjzaH(jEwL0+o|ggt0b(f&0I{+}&~ zVI-~9Ct4)I_h^53LOz*Y1RkFRVt7V{EP+x1{=HJjk&?AK#(RQsp{|cC3TSD>A`-NH zGuUG-zthG)tY5`u^FNYml=*&MN#0cZu2MIpGz_7yScctlfRwO+qT-oPNp1`f4;1dM zoP{bQTLa!bY1$#ffGr4Z^aljTInwwax!hS(Mnb%pXwrB1xJpbM#8GY~%&Y~r#Q~wM zcZSZj2ybsXrt`~^X`07Uh+4$)IPfG7)SmpQXVUCGhr6C!w;#`VNx%5rND}q_`h@%g#{-4uD?f*_S}3NWCiysaerSfgKDs=4 zuULO8hPqtna++CkRdo)w*(gndp4QY&6@K5O-GKs8#qrW~jvAnIVA4ZURY?ybp9L2? zwXI-(^aB=foCB;C>}OX)A^Hs<<3IAa@Vxm%W+-^9vKgep$U zP~7*sV4W{AulUJ;mfL8>qb9{P`UI&bQo_lGBUNHlqM-V~XnM$kiFJGujT)U5%AW7L z!mJw^lRh+}QO!lpQ2hr z#KNeFrnpmBIO4wsh`(P>&W79U<3b+po0b*+GzJRg%v>GFRx1?S`^rToU7JDQEmCg@ ze$gq6a*|^3-9m?nfVMrV1nop=9LHC}qa-yGGVtmxX3U2kn;4oVMkg%!4kL*s*@@}$ zO)-|Q2xT^9$?C>UbhkJW7A<&9scsive>BsO!%%cDIOpit=J;HWUp!~4wUkr{?b@dh z{F^TGt6XmSjO|;SG#|GVJ$S@$Y0k+oEF-%Z_#*&nOs;Ky z#uyhuSwyk7QN%og7=h8|W4Pp@()(M(@64#1+xC$_qn0BG;O|b$=ujI*JfGqro-TTl z0B0T_fR`4s0h8&IwdNtnrl;YnW}`d)W}H20iBRfLM`uT86^qB4Agj#ni>Ecy&gDf3$^mmN_EkgbS};-zO=c5$D8^f*dtPQ-Plk`o|~zQSE%oSLliBF=;P zP_E=+T2<<4YW9q?VF_(T!5FHn=Xii2dVh&~AAy#Er4Ox5E{#Wi*DB zejL{LZ{89M1(^8*tb=((^;^|b128fkH@e|^F7=~;w~?x6P&Pm6+Tv3c_vYf zN#YiT6+H0>bUXPJjuWT=coe$biX1n_J;X}}$cF>Oi-f!H zKh3gi`Ikzrzkt=u7l%Of{|PVupX*4(#L&e|&BDpz3t#;UI4Ak2p)Hf6t+ZklNAEn?Y8acO7)& ziB%ha0JDXdb3JR;Zwc=Nuu%~s&)p_qn{wQ)Z?@15yW%dn-gDNBl89leeL#68thro> zTLT#}XvgP{ToVl13tfWD&hgUW;D1E)eX#)zC^9M-;A=cwYz?9JC?osu1}$XB91fFM z#-aT8C(-8^C??nOnt*TC`~|mT(SV+8$DgcLMzJz_giSOL8(nr;6;s zFawFYnyK-{o3Rua%AEKmc71?ld>GO@&12kUYeNnvkvbh^(=|{7_Lf_&LYtJficbrz zhB>&cYh_Z_;{c7qg4T`!hO(_hq;%D3lqT9f+*WZ|-a{H;s$(s;T(9aUzWwvxtd?Ux z#9*2G-4|!QWLzo~_Zs{8E{(Y%vzUjN2b=qzd^}DAC za>}r`TKoBk%GG#l!%i11NxR7jvb#uv$4jwmVInLi=gGrdJaEu_gwW@U*VoEyC>9r= zXUHd~n;^v`^OhV-mY#)PoT5*j5EnQ^s*M|) zjd8ukXXh|pQy2T@yMWHK$SJVI4l`6IJmO7>U0d>m+}>4aU=c4tijp2LFI0LH#)}qa zpgTw>Of`4?h)?g5#F=A{jBuwmsnYeo;cj{(Cj$U!9wyouReKzp}Ne)O3|`P0)Rly{+S`W0e95 zi<_H#_X}8jRbUGn1wbS-Kw*JG)UFAgFyka0X&b>~Sy|UZ++7aE>XGW3?s?4dTwFI` zZ|oo6?mI7S`_xZ4e#18${q>k0ZkXo0gz@`$UnBVSsE{;EYS3xCFt66Xa93_(olcs( z+1RA@r?y8)KPhY$!sIt7cBnlBNM?^ zBR%`EmR`N;Mp8LA4XHr4oF|w6y*Gn(j0PO34;DQ$Wjl-ZMXUtw*(%L=P9PP9wSr-Zr@gvcdOq~JY~TW=ZwEy}fMwU_?7 zEKhK@mTe2e&+@e0$!JtfiG>!+Ma3~xZZlPnU>EiBoHDePErtdmiyL{CxXF-Yy=!LPz5nEDX}%dEJUu##?R->UI|w!$??MNiOd&LgstoD*8j!BZS{4 z^uXoyn?}0oCYM+_>}|}n$|k%U9W5$dmC2GM6}h|QY{Gbof=k;jIW~KC6HakX$Er%yohY{YqizW~abr+|&hvTBGPSFTJ>3mkF?j8V|L0RCyy)9Y{IsrZckI ztckKJ3xf4*o9*VtNXzqQ3O23e-f+dtdb602);h3+Lj#dS6(($kIcsv)#%#7AV4WKlvf`3#*u6t2-eUt*7ytL?;C z2tEZQuS*Ukeug8NF3*95AkTqEkE^8OJYN&}$zS6J>#q2Cc6mTmy<6BYH*87=UmVz(Eu`b46{!MoG=Tb2 z16au7>%@I#@1UBv{+8B|qgHxoufGbjWY)u^G@+LaKhhTi?I>)M(--OU&B{1aEPh@n zLJ}@+31q*$sl37v#F8l=Of!gU39z{Qu{o_ZXPTMJIKA#HjDiDA+I4R)C7DRr7>&oA z1o!3{pWQA3>+N>E8h#o;po>+NA*Anqgu=Ylxh@1x?b5%tu;e#tNu3H28GwZhoqIpA zlyyZux(+o>0rQl}@y7eP6(bH(?E>Dq#Mt_2ZeM4_P=(Fz9@)v+o!iPPTPlvGg6J($ zyK((piXx(2=1KkIA0|!H_+@vPupl7O=>PvIod1{x{9CD%wy-t+-x#b)-NPGq5aWX^ zxvHsCGEvr^0enR%eS|pruK={93_vv52u0JevmR~GWwEKT8Ou3!LlsY$awbA=CZW0U zE+Dy?#YT`wJP$88`>y*kaPtwN%VH~1Eg22&gW~#kQt+a1H< zAS$rix(vDAjHZFZBxOu(2|5X%nUHE#*|anlYf`e`RfxIW1ea)SHiC0wEEp1=*GxlL z&4Snt-8Ew{6N><7l5zrdr=UkK7o0!n=>O}uJI|a1<9xg@zM}vJ`0-T6&>UrOz~fX& zpDr=@Vl-<2RQ(a=!NY`1fH)tz-GDkO0u&3Z6XC#+{yX*;NAiYJ%Q7_^TTVZ>7$Nw_ z?8N4ky-=qXAY!?a~d6Xn44F>5F zfJ4I1T(I*5Eqjy06PCxDoSRbDE$WmKLqa?nB&MNXOrHr0N3PVrBf`R&4?}`>QF6>A zjDGb~MWk|JFAQ;rc+@>U-tW*b_LV>q5fRlQL?d5@BvXP!In6wuzJWa%Fmgw#3~zN5 zxXAQo!$BZ_L7MHWB#$uAI3d8YK777}wQi!TI{|GGJc(;pZ!M z)8*t##vwcdAi0*KnTTi6Bt>w#Y_wOj*XXrWV|)YeIyPQ;V2LN)^LCC^p558muSJ5_ zWn%k2Ff(@sWWd$P99%Ih{dVKLRO{53lz9?28;J>{2ZPm~wnni-3>4sX5?!3Y5gpEC zL8wqn#->Z&IiQITvY{J?K&9JRt2bY8ub*!(nja~*DEF`MtiITPnNB8hcvpkr)_sQ~ zoq1SqEz#L+Z-&;GOyg|Qa8x0tOcmW=T!1mEH^wO!{FtdfbQVAIerM9+%#jzGI9MYw zV7GaM_*h})!UzlvuDQ#N1lOmiSqtWvj)f;YvPj5n~q3)rKuEcU`SwB*~n|9C{RhjgfN@6x&@g%g)s8jli^nfPOPR# z&FDTvkQ#?|5or3#HJQ&!6`p)swb3kH&LZw;+q(# z)gH^l(Njg`WdFtF*ubPB%6^@A-&tpJX8{v~{AJi{RZm%$4#@P`a(jkV6w52V)#h+=AYm-XU$AYhmKdQW6KB0bgFIm zPLFevt~q%GR(IbQLg=@p^}OS3{mIWpo|w9YlApd|6ua~IYnTPSUa?;EFPFVS5X;+2 z_OV-#HcLIRZMY4YJC&)J?`f;jcY6g??GKo!WbkW+3GST4h_Z1|% z&yvL_baENOowv_ZH0Nxa>Af{3OAT`z2SHZ2Rr}VFF%b+*<218Kto8+$w=bCIx!?69 zUQ=iDjZ#|JMtK}Bi9+-qE8MT3Q*l~h+Vne?Vym-Jd~45E^q8Z4lxz^UsBskqYUJLc z>mvI+Q4>7w)}bwXPPs+~ME2}l!dJDMoH(t{!JjAn{OKTNh>(ljV}4<$5nM8IM)nr5 z{JRH-jg|#1Z_|jq^@CQ2{o_D<^vhCQaGdi%OftVoQ>wtAs4| ze9iSvq2Dr}e)9nz|1BCO_O4yY(WHXfr`p=7=*Dh)UI zGo%9TpSZkZ5M#xFX3d}4=}A>mb_i>9wfMAB8et2yrN3Q0lD-|x!R~@e!&=7_!c&+1 z=~VPTzipwgFsX!$hGW=!q?%SHv-~OdE5TPXO=$w)-Ub5qp;lBnu^=G*D|)LWF=-XR zLH@hq&1UR232WiE6~vQJPi3csha^I$-j}Nyy{cYbXF231#qZ^(6v`S^J$*1c)a{J7 z@g#O?yE6Y4=&N(zo*TpiUDhkMZ{5Q^LT$Pp`UsuLz z1XZNHs3j~d$^sN=&&ka*!3{W3!S&?wn?NIiY63V>Z7_7Cg{rqbQKhL{;|A(sZHenT z1GFWcs9U23!eK9F5cg(u^LhA0KFLK#D~sl|#Lc8Zx{e2s14d>aHv}t(5sv$+oIUY{ zp^;`T4V>q%=L5y-;$Du$-XO8I9bQH(`^k#uu$IWIO;cv*BO_LeR{EG$#_%#jkl-TT z#P!1#Q3v2{Nc37upr-Ym;N2iQqPOj9`<=kW1Mnxs?JF-#xNTU=ozwA)CmR#kB!a@b zWcpe~2%ZtcVyjuhteJR)dW z;8sX!8r6>`wUL)GJg4pX4+_UHQKto%>+rj8Nzyk0#H!`&EvgIp{~A@_@CIFhC_nDz z-7$K5SCsVkdqnRhthW`o7oJe?`JwBpb_>pIva%Nx^cQ%KI}vs#*lIc9ZOupT4ZlSx zaL=)RI-~cLzB&SHxrH_?5;48$No@&94fuTsqhUVjDqk1~O<{YA4@?a2v;njz1zS6h ziR)_NCrD2}NLw)c`f@fn=!hX_aj7{HH#g8b`8USTylYP;_MXOH5*qprBl44?L;PCt z1cjcobNT{?ucx7UvvurXK7M@g`+qu)Uj2hCHn2CVWAwG8^ZR0$i2P3)_5W)PRTMWa z2g-;Jlt;n7z#8m80>Q;yCL@C+LJgxCYMoI{<77q;L9~E-v8M9|AskyNQw`HLo27rA zPW$99@%az7&@X0=>+j;*#1dF4w4_*dQtC_s?Q=YNW#OE<481>8(&^GvB$7;tjhPCU zM}!jHPS9YHZosvinoU^@h>H_W@W5n$M<{ODqo88DdhLCh81o&01BT|7Wlkm0DOqr| zH#S2BCP%r%r zB0O?&P2x2Fpi8=#PQ@!@w2X=uNT`susVt$6YO(fLYulY$htuaS8c6Cf7EJz1xaEuU zd-=m$477+ZoHkW@h4R0VFUDV@(Y!vdLi8{ktBT6to=m1iWr&LPk-gP`pb&a6CrG3j zkH#p~TFSLu{Z(u-zPMK1eSU{O9KBb)m%Z1$_YE)IxS@p8$^H%I-xrF>?WCSyU(ycw zuTW}<|M5@!zZwWN4>z=BjL)d1sQo%#0{C8k)Oe6M69L9NjzPBX<4kHa+Q7K1k;1${ zmS(6%j&zh>o4NRAiv&8!6zATJxj{*+bkQJzcwq53CvS=0-H-o#?z-8HBwfXh?(p71 zoVRp0FE`yTeI6(IKVN(CLBO88Kx{z8oDK{ZbgHq7L>qLf_V3IWnP6w@+ss8Gv_>^% zWU1RLRb_ZBwY0v<-pwqG?)X`f%yYb6I*ZgZNGB*4y=6+1xga&I7+R5~;x9i>S4$QL zwci@27rO8$dNi!eD9R8L-h#(r4Wq3f(;8eqz6*R>l8Ie-r`;JFrcX>w6f=i0vO2MG z`e+GIa3-ftkqjr$6y~OCmudeCH2y z(oP_A;816f0=fh+pu2`B^cmCMc_X4*^wX0c`G#U zwxg3+Lz1}ar6>NLAA?a++gX?J_*M$q^)H&mPgDMXVZ z$21QQ4f*4fxE9P^MJV=Lu*gi^8lrfry@*gK%$jJXVbyQc{`~^fKWRFsaX+gRX_Z;6 zIg0sc1r1LTQDW-UM$bscH5l$-m5WK78B9vPc7r?v#%3hWOqwasmVwQCKV&$_^CDnO zP&Ao%MvRY0Mr4*~cPZl?I;JI$O_@YRqK$d%bp!g0*F-wy) z<;~q4Sp#{6@s0cfQMwQA2@r+I^{s;kbcphUwk?Qny!)`^;-Qhp<6$Eo<%}k4O(YKY z?8`(QRbIUblseX6Xgt`_BCAAq@?5SL=TKucAIK!5N)O;Pov2#~Fr~Xz?bM;Mbe4y2 zaKHfnyUsBNpi+w?lzKw(rOEZ`ElpMPmaHI|OtjUs{((TO*Q5%=-z#5ccFLxMg|u_z zPWwxLrqQ|)N!g0?5B*NcQ_`<<;4?NQuAZuN#SCNTjys{OvVU?18)Ry$;Ym^FSMGtK z)1k}KnEL8z3#wkPs#LO?W@SC@!M>u!m}L8Ip8VQY{7yG*+B;Ea$lAAc)bH%NeHim|5vX5$XY>xWGIQ#- zo15@o61N-j`mLo$l?V;4x{1bi62FGi^^mWE#z$7-rTY)(@L>pdr|$?@xWkmy(}ivI z*nJ&lbYaTYUt4=k^{2^@LeevS8@KZyiqB=6;{A|Tj%HHn8 zKTmM%xY3--IqD>n9)p-V;_UhEMiG(8&fzC{p#qypKdMU@H=x|_%X(HtlyB<8DzaGF z0~BP%Ej7@X3}+o!sFcZfASTHm5$eMs?gf~J1zDz&&*}Ah5Gx^g5aY9Ai*Q*{l(E;o zA=U^6e~6bk=2nic1a`F|AXlLK2@_@hcDAN&KtgLEP*0#e7;MU>3dlY z@(g=pZ+v>k%oMFXk#&dNYK|@QC^VO0&hzlw$t4a(w@gX(OuMEb&dcZo*TH93t4vKd zyhV(ogC&l=3yzqM-Of3H*$nwv`YeuS`1_qAZcRfwSY$tHl5tf+Jv|ov zZA$RP2mb_Kv*CHsYB>J13;6`Zoc(2SCLuBh*(UWM{YUq zn!+Rt-SzuHp?wg+Z-C2JdbwX9U;yz0n-^)qR~%t{RZ@Om&NY?yLOENv#o>1Q&`h+H zKTq&w?kyn@#Q_yZ37l(AoKV=js|JDa_OoZZCiCOm@85yOIi8aBD-;OG=>K$9`JZS} z+1b&=;J;Qo8efL;%NQGhBqR}GL`*{tAj2^naY3PTKr(QKCR!O8&=pq1Xre}f!f!*+ zQRO%Wdxf%Vg;V3Qb3?91>@H~R2tFKP^N^k9OQ)wP55j&Deqw7rW@7!{N8f*SYM5WF z5Az-UZJ7RYJz4hqcwq6y#U>D8_ zISi~4g!9y3p3sBQ9%@|8G{l4}4?;8P_vvr)SX`3_)1GvJ3R%nqw~**#lRt9Un30h^ zlAzF^DQP$b<>mFb)Zw%Z)S6m1tC2n7ROXd8MYMx-orn;edEuiiNqa|a77tk-HM0jl zkBXAMD!GdU0Ffq{(ra}C=mEG$hEN_FF*gc%xin!4{pP)LjMswIk%)ssEdoLrkszm{ zRwOBiPZSuH1)Vn_Ni7bz=M zN&M%STsmm;H~|%zD5fAAOxa>FL9ent3iLD-#bu^a5zXS{<(0%2m6pYKhEt94QYP%R zM!K^fnY7I5m34_CdPt)jk?6FuKzoakvv}RVU4nRVGx`~fVg~L7<|AcCJd6jbE_&$H zg#F=y@=ARPfITD7`!pP3@Wb&lG2{YN*F-em)>4x;;z$&hkSqM925~UnSCOypNN~?K zm*T5AWJ2Ytz%UU_3ACQ|mKuUPHp&IM3Sy+9fjY&Dw#HpYQ46OMQ+AwJHIoNjI+SFf z+lNP56mk})Sqd_`NHrFb2u2hTmE;VmPCzmWBdAA@9S`fYd1e)c*e5Tc5*d>&$jXIR zk&*9dyVrjM8ySD%GiRwSHIB%?%C8$ugdRsXz#wfDCs+QYuXX~@N=Kcd9c}%ULIQq- zZnU7pCd!Y}hh**}C7?urWZvf7oT?}tzzB344ma%{8Jz=71T70?xV@M!FqtFOfKEr>~2JGM{>ZhLw7F6?A z>heuxKtTEu9L`a0f_))SK)R%eqb1-Ob+>qGH0qZz$s{s5tr>?d@cV6fq`p@CT;vZp z52rB6t;9#8(|oO&2~tPGf%{2(TUll-3@FQ+1x}iEZh7PW z>h1OEA!@G6Syc)Jg|@YDr%N{`$U&1I6s~uIb^N-OO-kAGj%k}-_J;`DNK7B0{Ii@& zqzWEJrOymaoksT)+U{VFkg|sU?8b|?ls-f`sBR2MWcVU31JXxn>O z{vf9V2r+ho-HSv6ew(+Iu7S6SynBz=3Cpy;%~v_<4ACMh?V$YP{=(PXE0~`E+LDa) z%WZ#*#-TH{8G^^EZK8@-#D~hCc5l>;)jI|-MgA)%(cH%xf=4OIX(arFc|U#^fNu&j zds)~MYF#tD7U0F?!8zcGKoPWL))~t?Qk8x*IZv#jon(z~6mN!#AkM*sM>3 zxx_Cf&`ygTnPWN~^a)R?)8EVWh7WdTVAFK7Hcs=vX!TC;<5l-ZCI7Glzxtx)ej}<4 zFN{G2yC@bUkH~U|$nqXeP}OmCJ0hW5=%(t)mAc#G9ge4GVm9B|wR6hZNo<7guZF=D zHmKT-oU)+CH2ix38>hVJxgZ3W=msBBQ|)OybEhnu*V=tYZPKT}ASk(7;vtPMlc}kr zI{dwr-q#F<)-^~M&Ob3nG|>T(W-Ep&yHPz#$=y`--gV_P&py3+v@TA~SBHno*akNE zxRN5#HM>E&`aII=4qP|H+;XJETNp_CJ-p6hLh?Ux=>Ni3`e&f*on5zV32>my4m7&< zj)?EN=yf*h2`d|tkDCg1(iX(gTg^ap?xb~4i0R)-g5GrooqfKOpm?k@b%zsHi$7Fi zJmOri!nUQGhLvbe;gri1!J4KvbJmv`z}{xYiAMWjxu?Csz`CQ6(K%eG(%eMynAOdT zy2O7=xy*2f;3wuM(ix6vD~~>wcE{NDP0x?l>z8jU1Hrm(PYC=b{$BsR#0bG|VMoOS zp;N@C`)}E|)h2T7(0oX`9Wzy`?gpN+8kMRiH}k%)8S0O)A*F8{BES8{)w>-!PyH>N z4K|A~r5Rj{STtUPnq(89?zwX8+NqxBjQl1`VBPB--~^X4wX=sh)ttmwTXws<7c z#Cl*Ffrj#2oo|I-26B92g_K z%h()3yP#(GuLq%lwop+jj1br$u|y{>G_mU9w0L8x-V%rZ6mcX_3Yl|!j~h?O$vMY* zec!uB0Fm3yg(ro?GT=Hg%~KpCn{=k|FlF2+3yYf$?i075(TBDnVOJ}aI1bg9Mv>$d z3}jn0(J-4y4=dUZQ()}Lnld)WVM(Ur7m-DwBMmIreA33yV0Tb3eo3gAla`)fX;AqS zRWuobXp#y|OH(|?aD4aT0d?sSIfRI<0v4H6n^xS{5wPw2_K1WfhB#IFNtA|@$0jNc zKV`A$_rhGN9E;;oM2y3zan|P3_|6w_^voj5(23&I60hHU(kNTgrT&ySs*|S9{}VOX zxihmu0>dL+5CKCA9i|&uAFlHNg$&);ydMO8J&yiqD%oVPzOtRSuC;Slr{f4s0D17!HpOn$5zb(5q>fdbS+hlw2JzXq<{T(Ztw^Y=|T^Cd4kScA~Zi^0}n%8Q(fcM{> zL7UD;YEG0?pQ+5f9N?ideJn3ml8riKt-2mmmI66|;1`(zwPfeOJ7ODu|1nP!(Vx!^ zH)oa@5I{FB<(%T8_5vLY8ffe^>m-5kb0D7oZ(OonY)ougYIU_fHCaz>*U320GRF>E zZq+sA&SL(T%4C`=nXAf74xkEI>dVrr@q-9NjS9|!=lp8d zgK6l{S2wxIiWy|fW`UQG{w0&!tyvV5aCDZuP2|X^ajS%M^*#8*`(7J>`Ge z54#F^fV7wJlp8nwcz*FBbM*F+A++(GFK@zEtue2D349N0HD=`S^SGOXpZokLKuJ5Yo=Au_oOmE>Zz zNGc)s14i*PJTXtbm2Tk`F$&5n4DGfCG9WwAG1#$HAlec+xsM9K!^q58l1X) z&~W+b;eeNP#6=`RV4*>uNA?3<{D&;Hn4;kPOZ;Y6Wty4&1;xt`Ly>PTDeWsWG|rcYzV9(uyIY;yYnE*>!zCN8^J+-MR$2o zLqq=&_Amu$V{;WI>w59UE*@@UcJuvs@%;8Z1dHkr`{vwt`bth`{KWI!e+_f!cZ+qw zr3-DrF#ef@d$&WMt~_@3bQYo;H;@w8*YppsCvyHce-zQ_*0qtvBW!90;t9s+e1wJ~NeYE0pqStrmq(@Z;j69F&9HUE9r>peP@ zxYD1fdJhs6KCW+oG_6{P&GMz*ygSokVC3;@AVI8Hin_j(Cxx8!Q&k)trL5{CRM1GH zTqC*^(UW$k`-oPXfrRRvtp#_zi3BkcfIbiw^ErAG+84V9CO9U?#jHIISh`jjM6|C#fy(C!937&n%u!n>n!lHJRron7^#0h|tAGOE=^dEaky+*$|Fdk^a!l(fJjY zw{>PJ91rbRAy=FtdF5wc6W?axvh%tGRGt-0V8#Z9@fsOF){L^95}XYNWjyq zAJL`ltv_0M`}XkJ%4rQ%;eX^m@%|5!`Cmy2?OOpd9vB!&ff$iKNoXW(NbwZ|fq@k%kpRl@IF{t$NK+N& zDs;n1tXk9la9K%QfatmU&%XvG#I_}Y&v@coM-7Yt)l`PukN3;^MFSI zo`CJeDK;XMsIHe2rXoz`eqCovyz@^(X3*!S@G#wW56U>E)cuiESbwSEXI01Ro&f!6 z6DNDtQAA3v8N~q%#VRDR#?WT(y`i%cXxPxAv1zVh#iHNtFg~ z+Gscxo3x^PI|%B`shKbYuR#$J^bmI1N@1<b*Zypw9TU-5BT@6=C3 zLx6%eWs_QZ@>4Ad(t2e_yUMJ28*_AyA=ptk_wNuKh;4N7>bGX*j?`PZts!>7byWXE zBOJ6p(&%wE(4}}#J$_0RtkRC&xi2r?VJ&qjNYjlM_mz7IIKpOIcNmRV$+h3Oe0(pH zM$k)er^+c?8A61)>2To>l{33b2~L2fr>NHV>vK*Yo{;KkV5fby9{SVyJ=Q+X8+P7K zF7)HLX%vT79bn`f|Le*jUJdD(MPzSvUAeUF4Xw}-O?<3h;scpkTfX+HVnV0zl7{$h za{iI(K))aKeuug-;o`^$2Jqc1Amk6yk$v`*UJ^7G$r@53t%~mSLCzj=f1D8d&fK)d z#5)jzwuX23jOfjOov7N@htN=q|8I%k2P#*el6X2g8mP+pZ+P2Xrl|2&(k7kb0;EQr zk`-b~$z9aV!cye(Urd_zuEM9CVJ)ES7f`kmob=I&;n@ApwK{zLRd4iQ-0|_2fl?bJ z)EAK&b=Wh*lABbT^b}GWa1?3>Ni!CZD*mlDS^$XfB=eK-xS)>P?4yAeTJ(M`|54e@%D>JzM?op z$+Hkz2}k>?^L!5qN$taG{BR7i^8L*!A51$wl_4VP$mkv3@hwG`0#rOfC(bmFgglrP zp!BCr;ucw(yo&#OC0p^1RJRVl-|vzB>s9mBI<_ph3rFx4oUxjQ) z8zpK{`8^VJ`j|2{Cc2&X&7S0)#Q?)o$Kqyh3 z_u(86+uab7A#5quj68>YZsV#gdH11>k%1S#^xVx`OPhxsA1jA zwG^-?P&=+>K!GnCIb`PSy2Ws_5J3N+?bJ^hRDDLB==86s%EE%Uz^OT9Cst#q<;Bvria*iEd?MO3vc z1CIsR0hz3Nuwy&Yfjx=Cv_)rT44%0AJ2MwqWdW~h^WJpeqRp&!6(0OrHIcZ{$ArID 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 diff --git a/bundlor/lib/com.springsource.util.parser.manifest-2.0.0.RELEASE.jar b/bundlor/lib/com.springsource.util.parser.manifest-2.0.0.RELEASE.jar deleted file mode 100644 index 0119f91e7096fb0c6c9d12b10e06cdd1f660cdfe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24242 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 diff --git a/bundlor/lib/org.osgi.core-4.1.0.jar b/bundlor/lib/org.osgi.core-4.1.0.jar deleted file mode 100644 index 2d652ac647c1a97f1ea35183a1674c4075c26ffd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 163485 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'`Pm@Z}( zP_?Q%o%S23U{~Cl1^rk{R7y7{rqh$^)eEGZWPxXxp@DLgXcK2q=!2|Gw!W z$j;Ky%;ASDd#a3)l;Nb{{8FmLWx=nKNcB@v-~drOu$7$83|z<*%8^hwH<|{MF7^m4 zL9K&x2sa##jL3|FQD97uLsoKu^j+%@Y=m4fbloDafm|85;3d7ExINxF8o{}r*gZG5 zwPWV#Ax}{`yu9C^x;1un1J2ow?;EN)+!=^q_XzYK^F{2MuwMikG&GgF8n%$4A(r_| zhB9M1Nd6mSDc%fOjw-DfHk~3DdCc2RHKoGf%0*e>c9{TrmBTyE}*@Xe`_rTK8%mDj|`>M9& z>G@|#%mB?s9`=rw_D(7W93k)X)zWSV!3@1j%Hjt^erZ?`hCm2Y%G~mxLQKQ=Yc{hC z$wwdTn^|7Nf{Kb`-))OQl6cQNvPR^r%5EV8xdLwgeVGQtCXp#qaCB_LsM(K)NlDU? zB{Iw{7ahDXgySVVwLw00K{&*cq4_xthETtvawzzb3tE!Gd?CtH~ByEh1hWY8)%E!kl)v3R9 z%_jlKMQOW(RUD~9?Yx+%x#4kX^l4b~D#djojSwcO@jta}{A6Dp-S2DsYdka9vuQ51 zLp)YUCd(7F#z`<-s5(}RcDLVMhssONC4jFtnR4~2EAg`xXKbPtq>KIgeNDB!LMnWY zTnKLqyqd5u9vKeM5h*EJ)<;C#v+~fwjDkq%Q514BkX^!IcqckFq_>$D^P?5lb07;W zXH9SikPW|y!>Da~h7G_oO@|~I6xr2tP#Zd5c^57aY~K(ORoZTql>}6cfO{c5Batk| zZ+TSQGRIymkRKJZSWnwHAO^79G>Joyu%tj=+y*pvWTG>f3FPFoszt_#EyAJSXr#bs zLp1Jb*KU2_mqM`M>Og)+RI5lbrG*_X5B0OdfVaZJs7f*{E52@UjhLbd1vPbh_@ORK z_|15pDw|miG7Cv7)DQBgi_R_6Nugfd<_{19AT^e}q~0t&p)R`*o6Ywl%ddk0UokKs z6V#5#d0YV_l^Q@s(M7n+qEIf7;l?1r&`qXX1G|9#q@O@fl;qPA9-aB;E z+8z^ZsJAB*8u5!mt5_o*)~e@ z*Ko_SD&M;)C-gPPmE6 z!4|XF!0hJcV~gDGC+HTo-yzCQ&fuBfjc=FN#H1uhl%wpr^>=Nb@!Z-`d-FU})OnjI z-ctu$TlieTt6b%me@7K`SNu$%ZYVPX<>PM^ExJ6?!`mMI+Ld5T=O8{WZYc__3JJ0j z-VOHNMZg}p;K+K<`w%{Gy{c-v=_SA!A$Wy7%k7TE)=Yh+>%9FJ+?jVVs6t_6FcdLO zwCMCtiIaqO4wC5yOFuEQR&Vj8INDnQNvc0}msvlw=r~A0IrTEd-v;?hxy#aAXgE1M zR!!)$Pb73s#!i7;uZlOA>|62FncCOs{A(+^-&0?TRrTlOEPLG)cyrehnhGRy35Y>` zdiZOrZ0n98GiP;gcola#gE0QN0PCaUNfgch%K624tWJ5}2ns6E{K#WwR0GJL{id3Z z|NB->sMwyXZeht}^P&P?vP;ie4UO|<{lTPH2VKy z>>axUftD@6j&0kvZQHhO+qRu_Y}>YN+vu2+`$lU%%v<;ThdNcYYojW#5vPM#mPq4? zH4S${)F~C&eowX!!(Z|bltgJjxf~90L4@H+`Nt^%`#UcUaS&(Vr((Gkcy??t468#e zUYQhnt=Qu-NUq?Ki~{F7(u^AH3@b<^)>V!YgVZQwhJy>@GvuEUW5Ou_B`@wJh$;io zaqSgfLr^Mc&KsV1Db1GWU@JwvnX=-HiA;#}Eq`&Lr3AVA;9_!%{4%Q6k8e-@Gi(tl zA%)cu84NSP5?^W6Il%b<>O^2VVo-3|54va}Ri#@d+pbtPd zoJ#C$s6LzOS4yO|VTyGU|=M@#2SOSfD&ZwdA(@vzuq9vd{2W4Ll_7%E`!(R&)} z@R3PIEhQbKTq#%9R0W+&3d!EHqAAvAJ-3zxWEyqk(SzMHYVU)z9#o9miN%&>*4MZh zLJDD+jN4Ab?7t)Kmu%>>q|df6P60(92>+$6_BT>#4t1Mov#Lof!>ElK2X^Gd6A0cv zId5@YYOxL6teq*lP-8i(7+tSXLT!}6l#2bweIOd{H@7!Y$ipKF&wdl9kOuBZOty(j7@2W>-5d-211Ve)SbBI0 z4W`dx5+fg)tLp{xWS-@RlDh|zBu51ANj^lRcv|DUJ)zLJ?QDp8vM2Cql~yZ*6tAn) zshd1PJ?7$r(sPLNgmV@V5jfF`CfJRuSpui(hjT@JUp1oqnkZ=70Zwj};s;fnJ&KUU zSVuhiimK%gmcf$h?;1f$JwO}?_$f?nSzVB)XThsQ0Gzhn4KK_xV802fX#*#+B$Wu- zs4A`;z&%rjVGs4k&X;*$9dvm~AcmRzR+~}@DBsacfDOOkkA`KlTa#L=qrMlR*lw7= zB{B7!JTtd(GD{HQp5wtuuB0!p0TbL?Ur7X;WRC4$m1)4uqiO-PbAKQ+;27~eZH@F7 za~ZO3#zkwU(e>5)qiCfWeNh^(WJ4~XZ>@kova{Xc)niUWayvHh{aSeKJcc_-bxW0n zpw+W0b7AUEwP6((?Yb4?-%>Nc%lF`^QA;Lx!~nLo-S-a>wsFjp%!q`nh5OuP+=+c) z366#JX`z-NQmWxu%U)CnJBr9;tza%*WmoNVRjLxqlK_x_I4<>V)F>C}Y9SYgCIk(F z+EN+dw;PgRWHXgQ7OlE+>mfxU_O`n13&w@Xk${;C5%^8w8U;)%{?!DylSaw|!7Zbh zWf2b@01=fLU>(TEZS_iS3};-n5A=H`YgayGA9mZM9-ONj8l6qP0_W}d#+v^I=-01; zc^pGey2Xb#k&W-Ooj``3)`hej;r!&VsU~=r=9(8&D3m=;x4pl9hI>%DMTrRN4xF8e zM}3Gcxp|A4o+F#H+Z_JvvKL5WUA!Im+@j_n8|l)sx_)2x{Q09F#R2xOa-rutdVZbs z%jz;_7EiDH3a^`;-TUd`?l=nVtI$s+k5AGa(zRCIb+D82;|OhFGUIf?$A)%tFr{lC zFaEi)MKhu!dE+s-Fd=Ja8{u&9;9Y3t;cU&s6?C5#-VL5}Huy((X!qpC?NrTd>mhZeE|E#f||br|1@hSFdLiO7P#P9@TDOv#gY$b^L7J65KHgn7|>s8gdsqP;e<}f!jAY$zp66apkv#GfYB0GBfyAOs<8A3Fo6GX8|jnN2yHA>)on*6=1^A45&Wl>ytdrX-i z={a5YPor5lXJltATC2{&V>MyA=XFz)TAnF7JKK(jqA|plm(h|9F;4m zrV32oTE2OuKz4sNj}U_0G3nq`#+f~LWBXo8=mp5C&n(AS2HGLnLinzmW7LQzlsl2l zBxA74E^0}~i}TMEYx^3|qJzx3vYK7ez^F}6xJ(96OI7TIgc(DJ_DyF-ka1;2cXZ2S zMe&WTwZa;6O9tW38GyCv@%!dV+dCXkKT!z^P32y&kn)SY;X0Lib42{R!hiKik3Qc% zE?R`$2-R-Y>X{H`XihmsmPW2H-`-7PjIV`&{=^LWI09hM%KZL8Y%Xptf_)YL{?*<-db07{1AhXP^H|fJw~t9D+F($s8#NS?66Y zTxofps(Y?tPxx5j%RCd`mbJ#QDS?`E)4Lmu1gYJ*EFlsIZ}$0Vx|1d0%@mB)<{kHo zrG}`p(z20^Y-*xdSX-lFq?MbSi9}S_!__w?rWxtR#!bG6-YTnV)zi?wQ(`h$?y+{{ z^ci#eBE*s18$%!7JAWE-X7K+9NDZR*tJ+J1xO>@A_Nr{y`u#vcRUWbeH5AD6Nd{2* zqs0KOI1fzJor;23IGbQf<^hfi6U%T)%naP$M%C`tsD>lk3FFU-j^ng3WS&Y(qCzU?mz%J#J^ zkbpbn@!8#YcWsHoR*MZW;9>ZswsSr0cUxN?UDBJA;r8u&5!A2i$F~ZV6o%akKBXav z1~9oW)JWhM^#YS!x{Fnc8Yfl&6W1Z@YGOQ4m?6g~C_7u-DV z1@7&|U3~Tb-o|`8vPatqW+Zh~M3dCkhj&k6q%?g+F8Dd^R9?8Wi66{^Rp}<_%u9YuhWX^dt_ubl z&?u~}cGaPJ0poU(I~&IufTQ9B4~53kwx>ufYme|HbgnH&g9A_OfZo7%;co~4yXC#O zBSPFuPW?LKkd)VGEOvSZm`I2z&%%nHX`|)*;++Ezb&-*l!ffnNSTQH{rBC3xPDd#7 zm($EhEKrmNQng1Ylu$sv5~xs*eF!)@%5{D$*o!cdF+qv&29)qE0soYn0k}9N>Afs4 z_$O@62OUf4>UHaFD|6|;%Z(5hMlPVS*t9u2IA-eK!{|d>PQc?aaQaDzn8O`5izG3x z|K>N$1H?t)Ecd*+Vc0i=_qd|xqB1_0cYU5(d*<^zd#CrGzW~w51ho1WWIg;}K~~!T z?k{k1Hn4Se`X8f+V;vi(P0_?}>z_ypGM5A;WD=_KZLW1$8kzxCHs*373X+{_Dim>8 zi7Ekq0Dg(7)SnO6*^j-LKg48-v*pCh9A_Elz8$5%&*AY)>4E3%naAannUh4U@zNco z=6v4y^6g(Cy=Kdx`*|~3LT3q^!Q(l3tm*3$g0D|eFE3OOyF(DM?aySltJdm~$VV8G zqoeodYT;p0VUm%fx3}l#>S7X7gJYq|k*?CgmhD*U92e{!_0|=kUAyF1{}l&D?5;=A z;YTjk6gkHq%2688OAoAGQX*@NB!n0XXPHwQfuh@KbNEG$bx?YY#47T0>n)5=xz7c{ zH0H=|dVI2LBS(Lj+=#qf9=`};*ZtJ0Z5)V!U~3~t=B{*V?mR?KuEMNf_g|RzG6sDk zCap@HFAy>|*c+L7z~VsA2@Q9xZx_{6=z!F4?rN4&g0)mkjE#-WCM~8dhWgoK^R;Z3 z%L&xz6ke1jw*%Z8bCkHC*QOiXlzSV&4X7})T?xJNb|;>m@P@JAP7Cp%%#M)mKF}m; zXrHj%fhf}WL^oS_$2m(~I>{)wJPXF(#+E^Q6$7+=tg*Mv?o{i7opDg~c)tcUr?`?Kiv)m}b z1n}rLAzz2?38ex0b0kJsV4Ua#lLR`0EW<(m}#@MFZxnr(O44NynBa(Vb_d4CH+nMkn@ zrUR_-)zZ7>;6@hIcH{z+l;Uy!ye}t!6?SWQG@=NRAWde^13Jr5yw&cu7(6&m;du_? z9_TgK&(ANC8R|0>7=mKrwDImwxifyV=d$C~>}W%G_?%YoabMzF=k4XK9%YF9!{8U1 zE&vkcHzL@nE+udcfM4g!Vm%LFh`=CVz_FtIjCf||K^gci41N&WK9Aw^b!P(hVm$M< zAA+u~slq4$@bq`eib8OV#m)uLO#NkQ>hY!#Zs(fd!y+i6r&%8ZyTt> z$-kt?nGM+62=b2CwS4_Jp}W%`KA@f>!FC)VwDONNm<(Y|tGkv7sewz-!~ ztY&85--9IfgWOgJAF9}#jH-I?Sr5am=1u2u^jv%yJuBMn)C`HC&FZd_H4F4w@uwv+ zCK{dhqm6@HjV;S#%pX)+s>{j~ba1SBI@>^teqbsjV0s!m$7+%4$Q9EJgI;qZY?umEmGa=%u;?02mET(l}<09AJ_lX{9}?{ z5_YydPtUY&SQUT9o==-vpYtqzKh5qKG(aja!EZ|2&6fu+mQ?LDr!kM~7Q333_0W>Z zd&-Slq{OuT=?jPGc@s67h5g6r#wC0@h5pKLH#r5Ofw4f!KBCU=(F~mdIih}IfSPU7 z9BD+H;m&OqujOyB7GG%{mFWlFf?IYgmO-OJ`88MZZq?UiI4(Q)LMw48qB(p=pxt5|u4b9r;kmv4y& zYWP`=`}zwUS5=$)@XjvTWtPg7yQ>L#E=9Bc>v=C=8$bsDaKnCJSG&!znO$Na&RZ@Xup*MqW zM^q3e2VI*P?B_r&+Nf;xC=b!;2<%-gTWQ)s1R?;GHxn_bi~vsD%%iHV%)#JUwzmxa z*DLTZufu#z0Z+g>7aGj)UoqweHFhbW|O%tr}4%E^A-pL>4ma*W*^?YCPP%UlAvMFaDJ zeEl0>UPr`iVfsKIl@kqZ!QQRa!{zO=R%{uy>h(!z$OO1^M+;h|;5MtP@$yjXFgSj^ z=CL?*PSsAY0DWl9?ANhi!0@vBhaNpA>+tZ3YLhgY*v;I!afW&NgCA1Q$yZB+m`nCx9 znAbsR=$F5C+qV$2=NMKgqV!Z#!>IDfvtE`tBcw3_TzKg}@`)1UqyZ`z0ifP(~*SO*Mw0;J?$(yw=7=oDbF~#3s)=^=HxbJ!rCe zJd=4WVf_!0bg5QM>OR8CP+bL)F?D@3b*=ao*lB6D1 zBIKlHK;dej8>Ao4Xitt)B>qf{32%vu5=k`N_!=YLv5ohsFYbVViB$d0LK#*DB!SO0|2R7D3QhhR@_>9KcCgFFj01d_+Z-f!gTkZu!H z>^TY^&!N+%#izg^A@m5f8izuON7G<$A-|d{?R*?q$^WP~McH3!5Nw$)g3Y$-CjU%{hUOzEUQctV@)hLe?&r-f@cd0- zXsG~wk+>1%m_yf7K9{2ea`S0FtC!2ndzk)a5~HeNsXM#h5ZcBr*Dp%rla?0a!Qf$w z)Fa@AUzv8St`e`J0E7jo2DdVGk0vPF$2-+yWDFfh>0*ikK*T@zWmDC4g6WUJ;JK)j zY1Y=CePUEx&+CxQwcT@va7tM1YDFSPl~~+M?oD>X*0qgILwW7@R(vWQ+6CU#Q397cdCI~Pe_Rh zzzmcR<6G^zgwLI{h0tc4QVbTwu?X2-ft#Xg;jFU5OT4ZP;P4?zN**p06wKC={OU5L zq5CG!y$WPSM)ZYxoig>i^Zd1De#c)!xzPw*4?YUZuIxz8PcsZ4+JBKluj@pp#>2$$ z?S`L39sVhQpr6bbLX@`pYX-v|x$r<;Q$;8dv`;tb!wO95Xto7lTbE&iQd+h1)y(O| zXDa=R9ZRja@3~?G9qp%_WjGktf+{s3(n8?m{j0w6|6MMdl=|(L0lT{Hn~gd;^?4S* zPN}5MCj`NFH^0I_vaxoTQT}?QK7iH1IEKaN-OUaWpzvFSPRI^K>NVIW;tD2AG|$!5 zNeVkpKN*COOg{>v>(EYu9D2hXGF?FX-oWgbT*u+>^ns$7VHe5BO9TplL>1VK<29eD z8vQnq?CCU6=p3`C)MSTc^Y7+*)>=&o*fh)1@fZ<->cj?;=u}71DoAa(7GH_C+)O9+ zx=mRMDYYBM#W88!6vj-oxB*}VtmU~lxuh=zz123UBg7|lU*~4}hD@F6rMhS1s7xfA zY&uIsj$y}G8#mB!jj(?-;&cF!bWcmNdPd%2?r4#kHUzQ#e_wLO?d_MZW3apOi$coY zEeSa>(zt-VI~!Fr5GkY{vL|(FBh3m3@51J_+o(VAlSDM}wRTc2ciXrSR6MK$XZCl? z#o^%W3y1hn$MP^iV0#n#mAmp6IlN~1p8d|fvDIvN97hJfi??Q~?P+rqY?x0J z7#$$~PVGyHxI2z(;NkcWr|y@f@AK)oh7xhgEf_>V|J)P)B}|jJPShuc3Xcm`fBx0o0mQM z4VuLi7yL;)OwBVbG@bFs&aKyNx7;>+t^R-;Lni_qh5wa(tIB@QT3#0y5QmQua`4T| zcfXyiTTW|E)c4VajM>$mXw|vt3~}bpR0ehH(Q>o5J;ntqnHi6kXNflN>_@t4s2cn5 z{;SSy9h$Tb&qbJ4Ogg8+LCzf9vL%bWIRQSew;L_mOGWqjh8l`qC2hlHDWZ6 z?I7Q=*TR>Yic(=kcgNZ+8Vxn8+;HMU!PkJg{Ehfk9^J-hb<*?wzeJXaqi7l8!7>`u zGN=3J(?~-RN_w8IHki-oduP*-S6WKsf}M=?I;w)9cj&q@v6>A?rkYrR^2Zz&mvw;d zj=dSqL$b&Isofck^~aq3^NNzm@Qw)X-ci6>^<6nn+K$yLnNdy%M%N4mohc#n5}u!n z)cJ+@iO>X_Y@kI(#;0V6=M2dq&(?p<8j{D{-FUHN8}gdgHp)q%@5wUv_WN%U`?>#+ zWN*@eCRMnysqG>ag=#HjTd-bv|5+x8u29=>S?$)obe}W6EyWI|5%aJa7{l5gtj-Cq zrFTt0!W5Ls;&mI!r?+;04`G-*lJcZ(_|{k}X+OndHKZuq$jGOF_DdVU^AUU>XW1fF z9>f=*-UbeJFSB63wii^b{xOFSU8IILIc2E$-UUAe^?Ve1Zo&HoOq`FSX)@#0Y)!q2 zFC~>MwB8t;8iHI2krsL)L_%*qLw~oqUvyM49eZ)3$@p=ASZLizDTsR?HPs+A9&b!C z)5}^$i0TiU`TMehA*aZO{4ZgB2vVgCez6W!wE`BENTqAH?9_$jylN|VeKzl;`#mDL zUC)idpq+|0=^xI-5V)HF?M2uK%%yZ$B39Pp1)WPq_46mDY867fV_UF3gk6gnnM}M>ZUmQLweVJGw4RVK0I?Y0@`!n4hVE)4iH{KW{*ALEj z#)@h)8X(vG(A7=brr`=p8XD!Kw4*u~Wmv2|i1O>x|YRJhkr6yixGUJ76Ix3l9Gxf1*ML?@ix|J5N350vr%5mVJ~s2rS7sE?Vd*yB8DQ; z9avHPe|DLBR7l6Ho4#R?s0O{qBpb^M0nV60B+YW=*R30~SbcxS->!)RZ!I1ZV-zA7 zf^xhbl<7uh*mLqj1qWubz{Q8OL!uWFfS&^m-n1#td%fBEbS;6>!@Ed!qW^90hBPUwsbpx=kGz|<`Oi^cX@}11 zNzZ!*{aR+Oj*o+)5SbU)Jhqg#q-@rCEwI)*mpZ1EG_{PZ7gomw2u4|%XYUmQ54`*> zHmN)jQe-=7l;`Mq|I=_;iS6aQt9~nVteE|6NO}6HS>$L4ETddwy*QZ!ht47or%Ig0 zLB@!PTAE5&&Apgon~U@~3)4`k%KZ$viDft0AU`xyEZHGoWbna^V#_xzqMivU)4StD6&d zr$gI*ekWR)FsK)xfdvm5BP}gGTjas7kCZ=7<>69it}iGwG6?A_X{I+}9lAtIwlG5xAUkXi!(JVf<*I(p!$pr$kI&+V~l)x3j7wGpD^bScZ&H%e+?TW-!W~jyUQ9S zO&bwg(?NJ0t)XMs>s%po$xEP)g%yhXar~d|CpKyl6G#$C<8KZ&iH4fZTG>zcIE9I-Od=}?85P^bkmQLhjgVc;wvj~HT&HX`)S6TmNd|nrYSBmz zu_1KKS>Nhh`6G<#rHAx5%po8;O#cs38%ksfg#yvr>YF`x9>gM+R#*;ml{*C?OIW;0 zX#)*UAtUg6{$Le>28w9p+!)WnI8Z*0?C(Pc;|xX!A}izO#*c;ku&;BUca{S3TNtm4 z{#{Lkt#1Z7(Sz#ru|3~YymkrDjCA9kDkn@8Nxyj__EBndmm5udBB`-~>4|XSua&CZ z6!TN$y@DDZ*%%=%jMvkqDWUNYwBeGO0@{Y@1jNGj{rQldV7>B*ry@XG$EpU|Y;TB4 z>)Eok;>MAr8FNGXtH{P^WbYr1>}N(vYEbt>Lqdu?RoL^LJ)8tQ-hb|h>w%Q7nQ-M# zbkjhHGp1S|Z-NYcX25_^y<2S;Mw+sVO{%jb>V6k`n}rBH#*sB!aUNGtai%x&SP*2q z1(AgSi_D)L9SM7VdWnr%6Hup8EuN37%|a&|JFMruaVumVW-)oGQP(mt^-EO7%jG5v z;tg2i1vbNAB%2${m7*@~!(+{MZxW_3(l_#v0?yE&qdgGpo7*4NO};7|+`j&(LOng) zYre32dLW_^@U#~WZiCfNn=^0ABmJ|#i8li_A8rs&)JcNH;3$FXwVrj`!D;!!si>Of z^U?KbQ}Q(?krRe+kRtW|ScFSX2@7)GiXnXS>g6cdq#yDIK{>DHW-sXkB^~|=>46Kd zkWs+|G>;~s{x1|KutkB&aSvlQgxhl;5x=^4%0)xO#lq^ z;*9#l-7Pq~w9ov>l=!c$l z51)@3pxeu8)vuDpF6%)XD9lziv}xIY&!IOpe|`S}e4FoRD+5rN9D&_B4I;qHjGsrF zSQF7IoL%ydpQKOpNK-JgkPrPa_&aKjECS4tnb4%IDh2EXoiv`{Jn&YW(zd2xleOSI z%3g`%+tn?T+~m+VosBGOIvyg8A(KwQQ+@r0xrEYGgK2;FF#J8M)9-_3=8u^E50bUGAqeVTwk;Lat42Kv{Oa?9b-QTUg1(PWFt!+T`ed>kC~1a4og& zeJ-!1yj9W!t4+_MPOPxYZ!}V%|6PHeKOX`@CT8C5;CaU08JXGtLN^!_EEUG@B)u{b zqSZo5Durw=!k!L})dxXym$%O?YnkAkH5A?G@lZ11d&s1dj zv{7&y<-!^}@m3UKG_EElaFiEpLD@mfTf`K+fi}dHjKXVYci&`w@BDM&f>RwdP42PmiitTP&W`VgVAAK6$(hI&JI?&9Q6qL_(cBJG(fdQpo&!SNW|<8d z4Z}&W+}?kq@nATIC^(pBQ`oaI8qlwXVu+={)r+7p#2$jLpk?F~TBx2z7^iF<4A>4& z{07a&7Yz`pZuDzd;huAwa*E>7c-X5+o(JW>jCX2Mw24th^bG?LbZ^$1-^`X_lNvF`|k#bj^saFC_!mUQ;AoH<k zHhIYKX;8%0mY2Z_LD8`cN7q_~w8n=;m~I0S~vE1Ht#rs$E1($vOraCqu1L3 zIXT{o!x4Uw8Hd3P#ND=GK{b*pCCe(dz$oHEC9}vBTtm|Nf=hBu|DF9k>Qa)vCM~ zECdsm{kocHJt>)>0@Ro@{lrd+W)iOJ+W~ENgmTEbe>z3O~*Z%8==FpH}*fVF3m_4BHO!F5hG*AQ} z3`yB(g?>VoM>CW_f)d?v_&8FoTY9n@+`Z@(c>&xAuzPP#LfzkQOBRUNv0NBiVAE;< z0s_0ex^NM#$PlTt&KN7)5T^W~Oo%)^A|9w0&b>fD7=CDS=&c3S)8LAoW+Y`+R*ZWd zdKd#&{BE_199+7PTq0{$@bYNuW%aUoGVRpIQ68M6RV#|7@DmvMd+FMYqastvBWyu%Mz2d4uv}jbwOoPy@U);`zw;^E*#GkT1)#H%JSR>x(To)Bl;LHfq&vPTVc%SV$HWQt$$jJ`I8k8mWU)MO zr65>o5h=1%eg>ae5tx6KC4$bYQEVTPrCPUz=+LHgg`!! z6RyL!;9e6969!#Ov5kUt`x~Q&%{TCUaxd-bl+-RYp`JL`2tJ3j2RS`&knV81R&WS) zXCdSYl&myWClZ(dWeNcW;-4=ARONc~kR4)daU_9U%Fzspo5=MMU}F?a zjzHtoizUYJ-9jQIR)qYytZnnj5Nexl%ECESuFQH!>M?DljH8w%)%~m;#|%rt*0*AJ zf>8~|shJ6s*ZcTdU>~m5?z6RkT-iEtd~giMTIisE!U6!6ue!Aqgo^$$_ya?s4$QU7 z^sxPct5Up=v{tosJUmvsHU_1h8@A0qHv4g#Xiu2;MWMFcB8Z{M0r3`D+ct_kh_%g)c$WscHirXIB`_=Gx@2!zE>A_Yc9 zYX0SknUonV(|*FhR8dn6eVL(>Q>@v`aTEZoi|Vb^#FuTTq289t>)G&8>8#BS#t$^w4#wdh(fHR_`-RE6YlI)>gkz7>j&5|T!RiT zjFqO)jUKyAd8z_I`!@+(f~>aV!CWrMCc6tuq`L_5^!BWluO2G$dcws>0BML;$%ITe z{JeqSEokaY7a2FeE5g{|LX=MR3~85x2e+_cK?W+1Hn(I78A)6W%~A~gUYk{1i^bvG z<7R78sJD%vv1tD1Po&09T>tn?_f=!ARaXexxP&ll+I0{R%$hpG2=Es=8a@LKAyc*K z4#fJ_Wo|!ahC63m+#XHVx-nhF*p{Was2F7AH*Gwwc@DnDDuK$|Zsibq8X3Jg=6S3i z-fDlaI`sn%0jI%yPRPQw6Ryl@JQ zyTKR#F-o(eW=34xt<>{8m~{h*jr!L5=_I79Hc~SDd=guh)@~_jPUrAa5N4aChWc)1 zoU3)1F2C_j3f20tl!*&|v?lUTOkkL&G1>>bhiup??sb9zg+FH(M|{GI_M3T zLq{Uo_Qy8m((GL6gtRuruu2X_kH~H&{|2|yuV0c&Laq37;p|cWCMlSEGVBc!rwy&U zj;OXpKTwdG**c@}DNojWxFR=OsdfqW;%{r2Tro#!uBKA)^Q{)R-tvgAhUGq zc;bS$JK3Qol!!wyklZBW5eP3@Abg<|h2B@pR81?O%1iWC)bsOD&UYN(aaMHcD+p3cv< z?|ie@W7vzrI`|~2$hU)?%pyUxArYMknb>N2QFP`qYhyeMh|@arcrP1{>AO> z?cmG0p1gtsl^vPI-jVW31@ACw%c*80wQ-U`5hWI!$N65<^eE$7`uQIx6w!pWmA+pm z6ffletwFN>H=ES|-5~!z;{F&F8@o+b_;2j5NTF0Xi9Lzfde?L;WCtZT7SuKWW7;#Z zNKPqhVg(`!4$=9a9xly?t0Hy8zIqYfmo2B-NLrw_;Ko^UMP{RLV=E^e!(`?PaUz=r z`Az8%Dcv#(AwukCeHLymp7*g7Egb=h*7*yt zm{CLd)Kw}0{&9#_U=@JnlO2mK3bZf2oTzliR-^eyWZ<-8e@jZA2;hT>$P2&pZnSw~ z3#LtxAZyu=jM2ENVs1=Z7d^PYQk30P^(p|XL4tmmC*+65QH5nHip0gO2w4BZgiqmb zb4*vTiE^lz0M&V3vku@d7Adn9CXV2cRIiHX;{lS}6a+3xKsUZ3^GY9RaO)?2tY7>) zn1s9`n>;q|$&@itr`~sE_+i(YMs@Oh2TpoZd$nTyVgFN89Nicp^azIf*b`dban6ZW> z-;bTy9G?xd@6APW#uP%raYhLX0V4J!TR$wgdUeJtMv2t;l}Eq3w8RD^ABz{ft;)#O zu@FPkGNeX6aZ}^wEBY+#2Tmn<``yyoN;f_?&X&wPesv6jCM}{<1%sAU0c~QGgQrwZ zwT>>-RHO~L0Y~R>jW*))^<66Bt(lu6E1TROeap`BvA&zdpk~xg^7i^6lV1V$x+mpa zS#BP8gO*S-+x6*>s8izxbVo^|OdrI%qB|Oeatp(@g(p_g&uNg2hvRq2b^jOdPt1HM zsfuFeOL=F#d*8m!+hMzF<<^`R3941Eq3wq4aV|~0%BNMA7gx56(He163oPch##Iy5 z8CSDCbI=_RxU4&*+}JoGiQ=e+Ex0a{@1w^tp!D^I9%PXzQ8|#|CxNVYnRJheyOE#|0}ihzsVu{erl8DPNfP9RJbVQ$`ECl&`KE_m_V)o z6as8brl%AM#4|7f_mebAq21GP2J~S(3n|{&%f@f%2uxWM%*RnyB@AtdFV_zI%pO|^ zpv0fAWVGKTZ#Cuv2r2i5MEAS_&V<^MKTuj>2Hu}bu6naN*Y-di&6*}foMJB!KHXUv zu^UZOOFCbM8{@osmp@w2q<`3z#E5q90Z|~V6rM`3qWw>Kha|L}FxT&(AOFsLfy)`2 z;6xClDk~T)wc1n`EMm~z7XB7UAdjL-=yG0no93Lkun#vrO zzcG^@OddSBF?OV{&M<}JWUoft9z4Ji6heFtP8Q^VMdjo<`O!)gTF8vo6zhtllu8hx zs??PA@pW@n7Ld{4k`}5HiW)SC(h#I-RL8-GYI?&Wu?Mzj|GdTcf9+bkHbrDN*zsA! zju;skCru6t4*#uWrbvWDY>O5W_uJFD>_^WyS>Q5w*)3r%H^rZm6L_9c@}5NAY=D== z&7mf0t9K&3L_MJROo_*L1vXHM>!Ta2)g{`ND?w!yOQzzdD*&-oMh=w@(S#61Ans`= z&NWh!_nWYY@qpG; z69DLSX9X!z3IxZN88@tI&k;B0o;D|IuR+LAuUDPSCCppq6qH1t0WD?LV zM^eoNYPGm_B<*RUma}@1tY{IojW~;ELx-E-%;MsbvqTV3=H+ipB61%DRi(3~^7R)e z`Wf9a!(+tAC`JT|ME#``7tYnH7%qHeiO^Y)Oy(g_mo%-8U?6>snJMRTYj3e%BOp#4 z{K}vdhE<|=u0IP#?qndDqf{qQu7@pG%O`Ch^1hr@9EKt5pnxi`^Nhtr;=O25)?Ut2t%JJEDvsh-^ zoBqU0=1#8wkHX1o)6_zmf?3G0txlrSj742oUcbUKPV0742K`#ONt0Lhz}@4rwRi*# ze-+kKEZ3X7(mXV8XB5p665m-k_lDykAEe^-t#;K zLl>kXu87%PzGZn@!V2{d2i5w1V)MSYC9-Y(s0GS8vq+)l*+Oz)fzE@B9J=4;$~ka| z(fs9>(9FHu)Bn_&I$XBC8V0F0xkS}aUYZBK(Q+wACDbsA5OuZ*#t1NN!QDSEEo_my zy8RT+hnE&JsRSM}0P;<_%B*fkSG(*6_ZWA$69k||$R1P4eTq!M^{X76&K`nB3p;-j zOsln{tk#6)9KfL4v9vNKi5?8u+@4C|2f1IaMv7I?ZvqioAHv*c3gj92c^mWYMvx1N zN*ct2!|NW6KF6@I+CLzpq8y1C)fRi^yy2v4@Fq{{YnrnbG) zCC}15Wz0WUL^(>9#^R>C%TZrWZTup=WVwwA1Qz{CGU{uJKqMhN^W1XY6+8gHBI;Lc z=?belHgFSy3Um4@=9b({=>3ar+Hvh0sPx=@(m9zlqoBc@oW;@T-ucW?)_fHgZZ8>f zV(F^MmyLq!IajUqG%qdBbsMVgl<7e5j_WeVUSCksNk2p=9p97WbHI00z6ZyUX^}e) zv(h6w zwrRV`4)2rNYZyNrgw&RpBjYJS7k*i!WdsCPw@C9YE@c!^Eo~t&5vlOF>lRvI7qd9& zinq#d7=fLe!Qm8IRCtJrJ-Dxh3~}KUeh@Mq$sxKZc_N{F#!M|uIhcX!R0Z`#!N_^C zA0AdXeJ4*NOq(>WsNvw|f@Wl4l0OhZ`B-t1xp6KwZqM`~EZ8?!D&H`ewcnWw_KN(-0KKs|fB|y}N_qfg zqB&XtL;9~`GS(V&zFuT{&!;rlx1bHVG&@A+oM{jcpNsutHbJTgh*LeVih3C|Vkk3x z5(i)hvH)dxl*hSIW$|=2UfhA;+a5z?If^l@xqyUSqm2-Js`UDX52MxOKk|x8PGs7H zc#K&rEhHT{Ftx(*WunN9TF+8PW>DsD9SIo>xioyqNJ> z@&(v*LsP5#1Or5is?^1aoA{Q<1jSue{Egtipl{&NBp~vC zhu>$e?koXW4A8csX@i^l)8RWi{CiosZ~dK$PN2vo#+*JFWZ_%{Q<0>^ zN`};Cj3rCTni0qZzqAPy6JU~yc4lo=Aplb7q{;TCfsTAHkNU#0Wx`xOhB=>cKD*`u zBQYnuohs1oKkD2m8ugj*`>8~zsTb0m^+%Byg>{Vm`|$~vNTN(NYAcRD3O$az$X(%4 zzb*EOhqOBY^a3|-@x%Skrec`Xm4AP&|@T} z+{l6ns1#6uYgWZ0Uoa20E@<6>!o?&rvu?A}QnKyR?$Od&Pr1Bo9X>k{>byP$f2(&l zawrc@OOWDJC{_7GvxAes5l1M~;7|*#qz1nyo06!^558~^iDcz2P;_(WOa#kHeC-L7 z2)+W|Q}``DTHCq`+H-0uaapX_ym&^tTv*G>eu_yB8>p?cs>Kh*N+t|5U0PX549;jB z+e~>nZK}Slq8fNy_O0B1d%Lwtg@s=p%~>7wg|W5yVjPAPASDGf6*7&^BftQ76!~rs zh%3#uBRa?C>M9_U~qRXdsz66EVbg$QVZGodKm?KAVUYaN0pC|IBOi7{O#j-BZrK&Qt zy|^S*A7rfd{nvA;wZ=-~;kUl;7XJVClCNNBY-#w*^na6ioqx-`P`>Cs(8DNDrE6qH zC9_!7Hp=%nqpwhSjCoRBt{m{gf=m|BMp5!in@7KVI^5!Rgj2G-I9r^_d0j9g2W<)c zAUmuZqzV3*vKpKcV?T53(dgCnvhEu)h0V8NMshuwQR~*3X6Ye{oEhH%WkQPHL7wT) zbG`M?$3H=K<$vHdTwneqj}7hr1^Vpzg}v(Q@@(>D_a*KiI`1xJi^bI@J0hF} z^2HOAs5*A6p5XLBz}4{_oM?~bfb$aNixJjRB1j zM;Bm<>^?Zcna}?|eSbgNtr20AFuWD#WG^u6Xd-#EXVI6k^c?d2&vRN5WyD<`M_1Pz)DOz4tX)Cz)>Sjaue zuE(T?Vu)cGFVg45zt2xcpYhAU!GvJDjx_*1o~(r*7z9Fs;sBPRTt&9onYd7}BinqP z+}V<_d7Vf(ODbUL;$|f?E4%CxGN4c?*T4rNLf5_H@KNS=h9|rMTpHk=a^@{Pm^^R^ z;u5IaTxrY<4iNqg3OjnB8kMy8c-mI4gzHl?;d}Cdfga( zjrMjZb_AO(g8Z=GG>aaBxL<2x(|p*O5$sS+ScS67H*0QM5`frQolWF1=)!$5f7{H7 zU25Acq@?AS9JB377N~_%numHtj4@B6T#_uXvRtEsv9H&N*~sNsjAOg_vkDdoTtv zkriDk43Upl&2^pN($%UIQ_A}gQ9nwC#AOHol7FTGJiUSn zIIKn)2BLp|4H?L@*b2)Zki008KcaOQ8Yq2Qa=4)cYB!3=b1vuc@<>oGtnfh&hsq(d z0z1jbOv|xDJxf|A{RCj2+KYJ1r+~$iZ3q~Ai`Pg&nA_e5TWUA{70bg|U@xd(H>&V_ z%#S~Ur2f4j`y>uyOWo#}NP>1mcBB>+`X)jkYg^{}aQ>n={Uw1hO(B8l#_6f}CHLO}Y>Hms_xl`M zftQT$9=5;tVfL6cZ$h@U!EHgcG=NR zqfswUR#+Ut<7HY5OIAoHiOEg5+>c6QKhX zF81#u4f+!{AbkkIjf8kV$k`Y&UxT#5rQ)fKBHo3Yb(E~`bWDe|W#CfI;?oH-5e-;W zd;NY00X8``pwnj66pg^~6j0%x_=m@s^cRBs8x~pu&+sVe^i9S;k8yXEXIABWL-8_1 zJK%a-m>YQlb#Eay)(+S28e_XVRT1*iLG`sX0>6REoSSwOAq+jhGJ&yRM{3yNRlE;& zDu^Qt6gG2h*=NUS&;l!dzH5zbk;x5%#Y}G~;W6Vd^duBMifGUrlMDRrB@^p#sj5UJZt5 zW2ysvbQPWyUt3(#Twz(XM6l{)r4?f z<3m8khdMVzy295m8!OSXg$bZ-Ob~Xhx!{&EWA|1+Y6vJePS>Z@aHe#^!+sCP6PKiz zLJyd)Ni%4$)i?G2{!v+zNJS~ipV%Wr>=Ek)L77KUELi4|JzsVa=7f7hwkE7ib>^~} zbr_$1&J|5_Wo-fBTEZ*@f1IN$HCG9mqa=lXGo@O}uOuouK_*JwZwcF@i8C zfDrnv{#18ME?mWV)t)157b=08Gzy|hQc{J-8Q+&JhUBPc$>7@Z*?elyRAl2!yy>Ml zBU5sMWwDgox{p#{wSqXID>0Be0pDDzd7S=^hLtRo8ykmEiy-inYp~Il(O`WrPpG3h z$#B7kSpdnc#eF`3w|iMh>AnLKc=NO#0@n{~gPSjyoN(qmZU;pd#Hn1Iug(Rc#4zUu zRiR$CvKFqUghac16B$~J#%PyRmW|G~^lKi_> z+&^22Fq6v)>giqZ&RAIfGyePuqk&1rHJb_zyikqRjuPc3wTq+|Y>g-@GW$c$gx38W zo!DG`>ql&GmO^0(7 z4p{sAPxZ~lx#E)?06pj|2&+Bh%#Q%3WD87-3Uw(Og0flH*IStA4MPhOXTsbn`|BR_ zgFQKDbiu8nqyAp8%{>6~jt(zS6+lzvj^tU|pQ9gG<(8 zGs~sp<{zlDfF8qWR*?`ooIn9i_dXhsx-GZ8PilXq%P_m=n~)Tw9&ZP5UJE6q5Phg? z5!sjAY2rSXC2x?I`(vtl4)S#M87R<-ZjM-h>Ih(!p%LxPotVgO1l_hjh7PN{l?d!v zX|=TH*KOqieiEaAb^kGx{sriyx;AV6)L-`x&^HC8m^J%&8vSAM$eLoiM+al^=72CD z+hmorGCUn$D6kkB>4@&62c@dR$flp~JxO@0ljpO8HE0ARX`XxL#1(@ zYB(~MVWbHAMrw^Cy(>iaSjy(H4fo3^W)1xU@+kFZJESKbn0eOWUho8=xHX(I@+4Zm zzZ2l%fGKzf6st?l=BDrxfcqIZ2r1LzKB)<388d7-;tSaoRqQmhf zaFl!&krTYG%Q!fH)24(j5%rr@?+I1zd!EW&j~yLC;L~ftI>PNOl(h+@Kl3CJeffIy zsDJ*=&PYtt1B5!=-{zxY31bYaS2%h{z%4oD3hfokP4`|+b-L)FLd3>^;EzghbG05L z6c8X=M@L;TUhSZlS9%U?BUwq^70mG?6NgMc3e|&^FwdBJG_26ru^%|^TNiHYXl)d~ zeVC$bt2DIw2;yaB(UfnohJFdDD~Gq~gnyi}p&5E#3T)Vf|8P@qfNQNbkgi1f zJC58|ofpDjh#^d{x>zw+{81&Cr)JJXWROC46MyLCT-Hr+j41Q>qpi&>^G4;wvIEMt zyOuawN)VAYft)+DKOH8bpYxAcmI#Oi1M1l|YG--N`WD>!xq5E~$Vb`gH9lfQM=SN$%ErgNXavTb?RGVb&W_%er_K0<%Pp5EQtfqK^$&j%N+h|(083DsP1*DRc5K=-c6X4=#k((u`T zp@!z4Kp^btG*BE)^3wH|v3PFHu_>ICdV^>?)5Y}+44klZSqm5w?3TO-C`ui653r7URuzd{gcl3<3 zV{D^Qo|gmrT)LTC)-ELWpUHDbe*mvk>15*qH_zS2q}l$Dz!lOQV^6ggj^0H(R{YPP zvQ2eY$%$l;(XXjsk=S3_2G|8Kt8n#0R-olzzvJ+poTSP)l+5Gl+VkexwwOjoWyrqK zx|DMW0JxY_mk$uY7#a_*1W5*Q=h6U2ro-gG*zV2H%N3RoGI7+v2^X%EDW_-A%?W=4 zVjuZWS77f6>N`$UO-D~Wb7$!GuLNF!w15*Q!z_m_KPGv4vg8|u3DK|`^2jWDPP#d^ zRA>({>{Qx(swx;@F%t?5+JBLCKC_}e9nrkL#KLbvzMD3rB`Ov~Y@Tfx^}iPQa=ef7 zzsb7b@IE47xpSt}(=nZ!nmS-)bz)|5AZ)5kk}%7ue(Nw|nADT7#c_8Rz-KUEfbo3P z=_->P4MjI{N;1aG*gqz-?#kOaaCQ$m^-5Scl*ixwZY6&*fzl*`OCc`AkO4h>Xk^>p zw}$39Ei|tMyWO8cg0js)C=#h9&32UF#_;rqICavU&T)bRG_r^lg;9Qs=_@xu#ww$A z0U`$%B?fd&a4UsZOfRKT9QgSk)f7GE=s~u%a1wCE6OV(DsBIflrKBDLu0~@VdZ&{*1vk!``DslV|?4 zEdu`eQ{Xt?R<&-=Zl@bn%VPL`E;hHHsvRC{1*uG? zZ4jW7X@hIUWVh2TqLX>GmH7karil}&m*nV~I%WvfN(*7&ep~b}(nQw*ebw5R@48=X zT?g;C+&KSbaO1@K*fdD0plm4yU{2R%z3cToGb|1|%ND%Fp6Rq!ShOO_eq|PBE|A?G zbkBZ98Rs9uCqyTERHQ?Pte5C-L|_r*aT4iHM44Ns+di@=JKJq0_;Sz`VMc9rKsiYR zO~Fj1x#Q(88BLiF&6K#K?JF9ld7xbF*2lqWf5M`4f?#F4iWQ>8&P+T8nnjn7Ik}dG z+Jebt(k-7x7)=?Gb++cUzq{KfvZ!@OLx_vBBdc%IrM0w!CS<)l@MUvI*qpo_P`}oI zd}=6;)hC<-l2g7ifZ$o9$vDd?dy@}Vkn9NjgKVW>s!A@Ml!tSEMET+4*x<4Rsc$oC zqfL=SQ1jR)Uw_Tm5d$oJpC z+5c%FVur>}whr$9VpImz4gX>h^BQ%O5#C#6*z$ z^Xu^a_(xUHXmlBJ&9xNg5z_OqRH`=VU2%()9LzFYYXXv5VnqE`)K zB)KSPlEDFp6Tv~Y$Thg*U{JakgspH-)jqTQ_Jm)snC|DGwHVBWC373DgpguVZY{pF zxYTooZ_FCQgJL<2iX+Xcqqk*iYiy5}e=05*E_nQLCZU!X;I_W*}M(3Md@KE4d?eV@sDm{uU!L z>2`K`cl#kGu39-Xrs+-ZxHx=q%kFB-h#R($q=S3MUM09gn*HsiU2|K zcpA>BdqE#A^oE6zMKyCvqfRzjJEeiOJ%w6GNwakM78V-yPf3t(Ul2^jg)TH?2KGSa+P?EYA^K)LgRV@33WFr<+vKZ?$qhL*vr97>`{ z$7+v=PL4O2JS)~(vO*!hNW(Z^QUEbYxs6$+Aep7zT-v47n-HliHret_y23IfJO- zn+7C9GbGQ7lnzQ@-!9(=Z+sruuB~hFC|_8LCv6x~Z-DA~r0I;R7+dzMgo!mLnN%PD zOid_+J? zfQ0q2mql>H!7yZI>Ifq3VhU$TX`wi(a(QjZkhBsSemA1kpUv+ve+a8$65BS#6D#?; zpF#M=yJbeWK%fl9mRvbi6GwH3U2U)D<|S&kuqkT}=z^T2X_*p!_B0xS?InI!YRW|2 zGT6_H!5df%+KNRdhK3_!{E+nPtcs< zKadja3f}^-!;#v*-JHPhTZOWa3$HAhP;kxLkVvqY%bQ|^AKZ>wqQ1inB3!A z=Yug_aG#C3&sFYOk8yNReK{vMp+`rDOn;1mH&`V;&I|)!y`(9&x3^02FhqkrBRR`6 zP8qtA*)LR7(TK0+PD+}d@0X!lxrc{GTCoPN;QT^vTF z&cTZ~9=-(6w@B8nITZuJw0{=adW);OJO_Yq%<`T|gFa>m{>@moQ(oaPZe%>+3V>`n z9hGRg?V_Drqjo)kly4xLc8+Z#DUrUPypji8Eo_GPm{&D+dq!&9nno0F|7PaXlbodf zl4oOkrcbohQ3Km_17w|y{ob;N`mD9l(5KJ8I=IGEtS0|*y}c(P>BfT-qJ}6@QTIjs zcZRT3FQtj&cTETVA8Y!5ldSlkn*P7g#9jZn8Q}f9sP9P1g;)#VpxMtmJz#JKUVhWW z8QhxRMVBlXabs?D^?XhB^EPuGzJuauDoKN6gD=_nAwszLYW+E0%`BunLfr7A&O z#Ae|>1q26GlAY{LkWKK6VfK1be=rFK6(q6X6zIX(1q2&_=xR ziG$G0jweedWPkPKn>j>n?ZocJpA_RT_V9r0zY%}-Wc68xBpW>;=&Ypk{8wUFh zFfm8`Kb~71Ne5X*i+TZ#G>B@7*gT;Qm6-msFoPkcVl5g*FAa|aO#P%skD|L@5FT0Q zwH|zXCRLDAM@5enGBr30f5sh{C1Qo~LhKl1Lu%KVq12868YC#zvKMPkMA_KobR@^E za=o|aj>MYKyTUY+Kgxon1HKms937&JvJC@^%bzpWL7WF(f0V~fCH?SL$RXU&8t=og zwotEuu2Lbhl*t&DKrEwVB30dXZU8T#@0%x^ct@40F!*x-u$P&1?i)0w3yt5yt%(;K zU(@O%TT)U`&ci>GS3#zW_Xd8cvCLAh?M59H7XdL0R*8`sYkk%-+X?u;$nw z5FU#g#6kil%M02`4^D*fbIE7SMluS&l5&Z!sw?ZE#b>Es(&fFba6m14Vs55N;?#`R z+XS4@I{xabEHjlit4n8yv@5Cr>uB$sMZj)bb0qT<5>GbB*oz~RgASf^&1{fI4;_HN zOd+$p3TFRUL$F5Y`u)&FlSFqSP{Z1;+Yj~D2&xGaAw%59zduV?SJEKmwo&{rJyaco zD{AP^&%Vk|X#^4q4NeYo9M0+jDx+NT>qhJ%!}6dN{s#Z_D;BTZ8jB%Q2U$sJ8|u(J z&+>U{Aw>y0%qWSi5bsw}EoSjtZhn_V0GHuR(wAf#vE=U=UhQ8;OiPZ0B{}=P_tyKH z!G)*Imy7*_o)7&~Rdx5TZ0PP`tD^INGVx^U6yMM3{)pi>-Bskwdu?YRAd=f(KyDIC z7zRDa>_c*6DA=`HTer+Mj~Z*oWdwC|Y4zqLnWtTC+4>i#wspUZ5c7>zl*9Z_W03!5 zf8sy&?*ETg-~g0y#UC4=(WA$}Ndv?|);VE^OtDe5n-PkTv29$|23}16$5B(^W9FPDqfOx~vU>q=X z2&N@(GeVhZ1f1k~fhnPkmXOK&(HGcYVVkiAd|gcNzobKxCE|sEqU;3JWS>3CAq~(> zj^gXalc|!W!Wq~}n(>+iZHm(=2T_tqT{BCsCsg7_4-3r}y;~R-p^6%E1;b-|Wxl{d ztJa~ZpXcHhH|+cPw&{eZDB~5>88@mu{*0NLVjMb__qXUcS4Lr>4ma>U&;c4wM9;@o zK%a%4!I>wQ1kZQuHIOTocu=w%Onl*wKb4^`H-Iu5D@O53sEnAwi|%Rf1{x4Uox_hA zHQyk&4c(u0BlLe~ZvV7Cj zQgXNn?vv0Xy^X)T9<_0s%{=p8UAh}Z)zVLXMFmc$xU zYWheMtAGAw{P~Kr;)PzU{Mde)p?-WVzJGpKsqWq7Hv>gY${I6IPSn&2Ob9}&fYGY( zl|$1*gc6qu$07Lf`R+klrCg$Ma1;8vfahrX_ny9%+$u?4l*0UXu)g1JsnGdP=bqI7 za+uVK^0a^tBF@QFbn536ls1t_jwVTv-XF20+*C4tCE+E@z5QM0<8Yut+`@LqsA~`O z5>0}aHFZwl$aaQScz9|>={qU_eH~IBN{(@}L2NJDo^1|T+^rm)dhlWSVG5L=KPZ0g zLq|)d$P+2VQI!ZNffBlv7>%kVw5Z&U;C?w)lFpWr81)PQn6I6<1wc#dqbqa8uDMGO zPR9!i`vZ@+3HjcJcMfMG0|PM`bA5SN&+?L8{bZWZEFrLTdxGJwdvf>LpVNoh)J!qO zI=YZJ9$UCmT!j6}e^nVe^$c-8J6im<@|#|DgH_^aMm9UvfN-xze{Tmp)AjSITz4zr z?q`XL?#3>VAKmdW@IjCx*jCxQV<)hwvwyxR98x3MK2!1i4or%H&(qV<%fhA5GG!pf z9$OcR!bn45jmP6v6h2EU?%tKk6#|PkvI>kyPy3ER<6<1*wJ%jf`Z$iRAH$KWtcek( zjBX=y$9t2Q0_$H)BC}e(M?@U2yl@so9}-I4?-EdfkdElJfhbcuh|L-@n|UU>s`f*l z0OIdIg$?rZ@{)2fa#pfgNv}k`EoPVKah&}l$j;+?P|gkgH1XBC26T-%^N@Sz33Hk{ zy3hVDYT@J$ah~)S^u6B5-C$AgElcKVLnj+eJ_}?3vD+d&feyUhc%Ye^#|8pc<~5rn zV5yUv%+%=iF-bH~S~QPK_?Ed>hKHqD|2ua@RPtEG3Rb`-IjnUlaW1B5!cT8*Q2-A` zy;nh%Bbfs`xL~mCPZNmmn7gzt(3_=@!LAZc*vBk&)346*upszps3>0m%42mS*E^pK zAwHUlL5Y6?Vecv^2jZdYapiH)&(*Vu7aOohB6@KcsXU#Gh!(-#?{qX7(02-K!v%Y2 zke};yH&B5{E%z4v854qS87%}u2?+A7F!xT;^(-@;#M{P_m^CKu{U~KLG8cPag9)uu zgE&grNf^|_8ITI<<@+os<`yFW^52gmsf;#ep-Gwr;=ko5T^b2lDd&n2!bpjH<@WQ_ zgzYoS3K$UDc{PDn=PfD*9aY6)dtz?}1Z+=qMm$O&_?2>ZOC+*_5kI`mR&je(7!rnj zrk1jD5)u(g?|?gaA=jJGm`_66~Tu0 zeZ485Hf>;3Js<*wiBD)w&{sHXpo~){h(CGBHQ3BmvN}lu^+0*y=xqO@!NLkO$|KUj zhsBC`{F%Q-bsuM`6RJrInn&(e?5JM(1rw5uj};LY;(IgAXJUo<=}#~Ede-Z#@QC%OpPL{YZ~$ydl-56u zGpJKo3D>p#;P!(B(k#S1@^Z%Ax*l8ACjZ5w>%6mgp9&P3kEfp0fI$C!Zd~C5{fmi- zj1*|NUph846{7R+NQ1C?3|(w^AqA>98%5_LW5%t!Vq$E|Yg_u>mIV*1h33bEjHGQd zK2A#&f7NIcUb~HEmw!b?JBq5VZgTr=^20|sZiRUzUC2YzQo33ODDY#(>CRw~L@@SS zN}MJJ#BkAh=V1p4Shhyf65G`YJy;DMOc6P$GQX?~`U}2X)ev!0w?I0IF}(07NdoF7Fc zd&{FE@q1Xng3FWZXuavWIMiyqX7v5j2x44X%}*U&ACE7=(7z5m)W0*Yv3x5)CA|&Q z2o=boQ8|G&v^tg93*DDc^pGK77z#M%=N5U|C>TzN;y zB~cY1M5Mx|wE#qC%8cAvd00AUuP@_bTKhtzWoE2D8@r8RI4I#_tj&{R@44qjuU9lr zGp6z`Fq+-nv&Oy+Hor+moJMQQdO{?d{gyS0weYaCW)|=~_$%4kd9f5u*L}#7?0llF zeM7U*7_W9-S|?g=(d^56!SDBNxl)ExGdFQjhV*9c2WT; zeCg2UYDj`e&*W<{o46i<+>0&nf!F6SD=R)H8lxWY=TJ=wXR0^JIjqO|w<@-l0=+W6 zvZ{DJ=n_bOQk=-yunc=w9(-znS|*fuorxv93jhSdx675%gawlSYep5EU5=l?genLNof-Sh+#0;~LEH zb~6LjVo9H`P;RMW-gt*AxuW1EAW1)pQGSp?N4Db8x_Car_WFC}d9XJ?XSkdM*Ro5q zUJ@F^SW`}DRrLv}_DLe(jupeRk!E#|rU?%gg=~kY9_i>4TSfiZ9?;J)#uX|mwcgOG zKsB?hoY2?BY)nO-`HA&7kkm%5T|%!5$Tivz{)IJG42Vq1UxPUc!D(&qI9ndJas?%J z9@!GmnS=w?XnNAN(qQ`mh!SuN;1ELZDu^}E>y6go&j5a6%TEcHO3|E-tFk-rVP_8d z?WO9kG_CuvP@JC9TZ{||M8A*a5G4r;RY~9lnj~4Plx=mshUq3 z;IteHJAh&0M4ulHIp2vrv_ z$PSa3G7z6+lrHE3|0*}Zvpwpq%7RraQJI$}&b6XMz~tTeEU9geS$9?k_mM9dORmkp z8SRFuNoy8H(lBYa-pQNO?Jyh;tvIj&AZ$c8zIdcp(y1HEqQ-X>7^Mz$#4i>2g9e&q7qwNS zh%aX<0EqIMc-IBOlYYrkLPIs)s4VwFtE&-MT3{3{bFkejW3Q1WmzL+%i0-(qm57v8 z5smT{45v$6>p*rbn0*n$Cw=eOVUfp<`)+T|7oCN&%9p@*=>XfQ`{O`g?jH}J=H&<< zc>(JtivUJX|JZnLzgyk}8ARR2zlI3K|AspInM%bNv#X=wIiqmp=H&0?6pRVe8F|9S zF{5|0dsU!Ksm)lVT~invgAj|LhsQ_A>-mEBNq|qF!cge^0hUlPau}aEuy-joyneV% z{KxsjsC`cN0{isJIeLC&-g8}6l$IgWIKM7>fBU`}Ig`DX_6EYgu0y6-C$efB7ZJm1 z&Eun#?Wj!A&c*s;dN7NQ}ZvjR)kJDM$^b#2MU5qnG)2juL3MCUncAf}iPr(2t4P zy%bs6I;I&u*+e(h7I1tBK@365BC7GW%bs5!y;7I952?ScU>6GWTleF*nL$tm@g;@x z1XF2(Z46c6Q=XOS_c6=bsqm6yEn81B##2j-4%<;0$?&P4t`Kg_&(LEncN#nyZU(ms zXUGF?YY7C!29GYK-hiYlSaUwjuPQbQ>dG4AHb{_4bWNxpO6$v7n10J|O1b(xjRq_L zY(2GOLtUo&8g%Cw!3A7PIJ!++y6}Z3<;F;ZG4r#K3^ayewTFdGem}`CnjgL5=o4O< zu8Ew7O09oZh{Bu_@SV8=w%S-KA-lUVM*r&4BstTgyI4j#!rM6V4yFQDChz2PUIrSp z!jIVVdlxuzNjT2@K0mNje$sx@Gul{nGG3XK%A9e8%I5ZJvS%6+Y34m4-V=1%b@g)O zBV#H~C7<&c7w-^j?2YH2HqkZULU?x@h6xBW>OB9!z~LtM*Owdho;;ORuhnVTZ(Z!- zeOi6C+xN1~UTLTTOQOA7tbg%P)4AJQr}7MB+ZUqoc98u0d4_?&269kG;%DCjw>tZ`-_Ng%95+Y*Er7t|ByD@a#msnmoz{*vhY0rQEtPq@R$Ql zViN%gf@y4srPUuuqAi$|Jvk$4pZXH^fCnLX7Xoy~_Yq-G*?BYUJxKD*D^+sw>44$X zUjw>)o?HtZCqrx21>PSF=t6j8gFoN_f$bK)A6lzAR*L!XBmcpji{i5OGgu95D3IbOG}cUjI_+0Mp4CqDD4w46{}xLmSK<%U5;n0uZE zKlR|Yc*$nbStu0{yOm}xNq2lHL144(;lI5-Z4?rmU-jVOjwy2OoNOJHaB%?c>TiXY=OVQ_SAVnJu1P^V;H;}lRdp(2Jld2CdCFKp!$5NrIc1&)OjVl*XrH6m#m zK|%hQO6}}2Ii4NF?%?EkW8m)yW1L!jX-VCFf4jZVw;Fm-xhpnsjfH*0iSGGov8Z2i z;BKr+&T4q;g&gGu&~TZX&?`7DQJ9t@^P71mu~sp{T`&wO<{ygJk+B#}+`@Glxlm~Q z>P2B6mh4c;b7$pDhs8EyVrL#=INjvGc#vR!y(m({nf(#4;r5rFdgU_$q}6)fUS zk~-fnJ{dUB*r=Kf7Dku!T`BE$@!2I)r%VQCm)D1bKypK3OV<$yvgbu0JN4BBjjV*Z zFa+iTNeNJKAb9S@Pn#aiwa>sbn36-idHe+)Y^H)U3yoFGUgu_gL}2b_P`CI29tXn; zWng2Oo@QSMgGBT-68M}Vw1VBpN7mmsQAB?L>P_Q&pV=u`0dc?U;$%Mc*;=z3T|Usj>VM) z`+#w*|>dQ^s|&ui{DtC12ql?yuC2uo4XBN3i3=KY$&6@N0z|Dz^j>x zAKq9(Q*@l0lS~Cm}(7<3PA*V1e~Q{Bbn+*>wtPFdPqGD(X@)Je0-lI>I{Ao zOB|QKSS59eJW@mpR3cZgD^>vr0cUv&KSDoWS~>8+7;erXK#OT2(nuvBm5j<9M}b-O zbkdJ^NH7eRb}tc=;Oz-PT0u;7NE=l89}{&*%W=6TzWh$&uK))2H1(dAVe zxN(SG!G*H-^7l@9Xo(OaO0i*T@YoQ6bbbXWXUv6$e*?G^H3vI-<(F6H*o9#sB3k^D z;sep=wC_5?jx}$vDAxde#Ur=31JYdZScuKjSW+_Z5x;7pk?IYBOm-eaUjqj&y1E9& z(uO#aC7T-V(41@{0~v5%PAxuU&@|~6Jwa_WBQSK^&0$*mDpv4t-<~FTh#?o3!nDgl z=$Cp_#4>Tc#f~9UXGsVhRM!r54B2^z%Td-!4uBta+&PXb80yCpfUwnT*En|?9{yM# zO2?}12ebOfZK%*3x>iF5b)eafBCDdi*+)7@7%i25BCl%^eAsL5jD@`9)%@0h4SoGE zoJuCd5?X%!q(I-6E&;y%!5CZ2{%N}mObeUp;ckZmK3H$)-AN}jQj9ZyKJ$}7pmRu{ z!0}D-v+FDZzLlkN{r0FXW1HFDYu1>vlCFEw6KZ1ggCvY>KuESZWi0S?Ku#Ozhe&a` zmZ3yqx&*;Qv37}4%N2Jr2jP2L#|m0=DhKMMr~YtVjmqCG?GM-B`eN@)5U375x!M&G zj9z+S^`+D&vc5!eph@W+Yl0-;>M@sGWqgWvqPlvD4*&q1`9Qd&UJHt}Cu zkmDnx%xI)nQoDE%+j{vgJ(i8K*;W@=k7;h-!=WH}%*QlBOaqu$a32mUja~Fb2zS31 zuyHCKDb90ZD0}DNcG*)tY&sb`$Y?X(C90zn(qhJIZh1cSv+2|q1U|vl`Zs2lb!vN8 zavKNhg3;P@RxTx)U@j~*=cxF3IQe(s#oNmT?CnQVo#X_Z(Dq7@vocR()vc7&7<`3i zEXv|xAr2WEl^>xcCuO>pg+832{R>8PD*5hgt><4GU0rY0Z#5PR`;KIEg}P)gra)uX7xpxg0t+h9o?cp}o!O$JA6_w|xjB)IRjzPn zrnnN)q1vsaNW0$Wz-*S-*U0+n7{MOa3`H^f<^<`U3w0UDiPFS4u(w0a4=rPiGa*|6(ov|2?bx0ysK37&-xL zZT@v!nf!Jd{>#_&eO!UBEBaeRcEUaZAJG~!Z*hLn>!5|!&oqNV-WV?$U3B0k`uTPx z(X}Rb=B@2F5bxyiys_^1>&Y~>lZ^5j8$KNmiGylEsVc2w#2uwwXedVEhbxJsx)uFF zSEY$xi*Dy7dy6*(EI}Q1WZPVV1%uKtEWLR*5$4n&t%JMIXQHRish(b3Bq3z24?)(K zK#Iyx0!CC6A+tjO?_XE4hUkMErNsH2D47q}EV#s=c~*l1G=r%(h>MBdb(4^kh>0{1 z5IQHCBt!uURXQ?vm>A?P6O*)AApS8*@7s7uaMsacM>)CKomMX=uSXnWb`nb3cH;6G zGIcnnRuW`+EJH-#an@aG=m8qqw(2&$3`Z$6;X}u8VvLLcu3${&)`+!`APXi@%e!v^ z6Swusqsyht@WP-K)v|H}am$?dW_TO){I`;O(a~Rw%h~?)oAaTWH~!e6|eWhwk z%>JqpCPqm~7}Mw>CGfKZWX-3=YoN)L>>!V(>DUJYR0Wts(t>JR*}=u4~ftB9I#N z!g~CSXjBQnkZ!2tvm#dV$?71-L`)JeRaoZneitEE?fIW-V1=YXgES;iekVMEA0T-U zf|z=UrIFN?jIBm2=Qq`jVuVCc-}1u7Yf4flg1`tnmQ*a!vILQbE&)W_KkDSRn**dS zz}^Pc>g2tnKR<7N`C6RZXQFViK;0FC1wQ~xo^>#b@3ST}dT+Y@RYwyW@b18y7!Tm& z!l-68_J6*t@${|nfOM`Z7o!PsmB`X3)%U&6a)ZG_Ou)-1_r|mhvEp4$_xtQHL-UNX zQ8@?P^u4z&NmDP4xnQt2?vq1D0``Qv8|slY?-wGY9y44ka)r;0zM&9k2*UFECeXQq zE{B&jmqWp;433R0#q?@xV-yx${j5F-z^(JI3gu*3m1PQ5DX^?F8keT>0dBL)EUzv( zHxEQm7S)Urt**2`AEvw+vHWn}U$d;6F~L7`yn}#mQ(f;Qu2zSJSn~j@DYVD|4Qtp& zL)of`kg~@sLS{QNFDUj4_s6+d**m8Q8avO5wX@W#!uq)%i!4ULi56zX=hdjhr z0X>STvTJ6?H=qqYUkuvL<6bY}3ipho#JJ5H+6>O9>5CDkSlis$1Zy0M0yDz)!;N0j z{rnxd!R`riBc5W8q=an~YGqu}OI%3aM2xpk=8OwV3-%}y)oG~sh!w5C1q!2$V^X2b zflqBCcsVI@z8C?F7v2*GiPI0!EY6p+7-f4VB953d6Xnf4%jZS4k2l`x_=m6EzE&v~ z$PB7=Zn4oX<1+ydRYRWIoK6N#ayOU0jT&s2?rhugectS(DPRpfXAOB#2{Vn5b|nvC zTf_=my8i6ZS6Af`sjZ&&wNc9=kM67nh#;w#ol=3hOfvzB%4l^9a)PS3Rao`oqqE6J z+D!{r7=QSfZTO66h>MrZsV*ZByxGRSYn$abk4u%&3ZjyG#HVo;l?F?@`ZBMX`9kEf zn`U>@gx%-(ZI{IqD1X_$(7%2!Ryx+1e?{X6h z#<=@-^cp={Rb1vUGxP^{Xm(YqnjAv-f;`<<1&ZR1YRC+bv)ZmrNp<7f@WPj!?Yi#l z`i;3&yWskdwYlXZBAp!q&wm@nxPZ~#DZd>p49NdeGvfbmnvuJWvAKh-jjgkzkh6`6 zmFfQi{bZ~Co8;vEhJL;kf_eWyKYrT(Q3wVfGW@d+P~JGGMWUL}V2t*0-BoBZY;!!R z>(?_E@8$J$byIdw0jh5I2_YKt8!}v{Z6hgd!a~&~ygqWJH8|o}Evc2=C7qL&E6a}4 z9i|kQ-qEtDd~;mu7x>mc@K5y5u;ef`JAC~w5RT0&TgfMiwo{>&^^VWxCr3;NLrk?Q zB#2n_EEe3)ZkENN3el@wA-z7%4_(1-s-zi|-2j7{LLe7xM=T27`Cc&mHFUEZj6*%i z1q2o%Df8ZAs1GTLSAaOlGitT6SikH>Fl>(95<<2vzj0V}c|IEM%#iS998*$Y8x7K5 zMWaJOKwL?cmW}1%U7dU+N?GUk=w<>ou^yiFx)T1j#)BvyX zM3iNj{HedAmkR$~q-tID+R1;)e=xSWA?d~nw17lSX(G&$c*%e+ELarhE=04o`c{gO z#Lnz$xsRmZM1{T5tobLB_4v1^C0C#U8vfS@TF5DO=S68ht5IC&?)~KRCK|zOqNFb? zK7taK{EiK;2U`}xFsX+p{Ku^4voWU!I&gwX6XJg|t`Duo(?|#u(lSH-VSn1bGp_X( zjQs1EXqz&a17NJn@lqF&d!r0tRKM9DDDOl}+axFMqPqnD@9Acv9Az5}^HVP$7k-X( z;%?;7-#~PWFJ5TmwHoK2wE#1GKH_yYvYHk8A`tf`M`A9|-9T@%d?7l7lqPj;lQeMF z5xd~v`~_pTk$7E~q-+N`)?c|IdA!%1sjBtFRYLJ;(W(QdTmwwxs`|F3uvOYslySa9 zCT4^RbHJZ}HhUKSAJ)DxO15sxGHuBac3K>P1n19Og0b1O01q3sXXHj}*1Gi=HOrLBM^&GLe#s`4I=RPnE*TCZUYHwF_uw z(bo8TC3V6w%nu_hk8lu17AmJPnlm_kqeP8{g4B)-?qjhk5m!<^%I*aHb|%mrB<$eJYW z6(7k9MMq*eD3e&)NS-WkwdOXb^&}{Fzh^JYJ5Q%cTNK_GEO{iR)~|G@PntH)+eI;E zm4&<00&DtmICzO5F#;6eIy;bETDM0zb2xSXb}k_>#0-4?b}_Vt{8urC>i;0ds2Dpq z{(F+UsNv~~#ESa0{)t>JD`ObQ=%Ucn5H4shsL=r$I+RDXSzjWGOWCA{D>AnN3BB!o zy=bVDEpD(w)h=Vsm2kD_{pnOg(&;Jf5PQL8>@+lhfBHh%8YZ}uLBf^#U_k$5z<#_{ zl#8!9yk{*7^)u9yZDTy-OHber+n=o&l*{UouI8^e?E5!(&yT<@{+#=_(2vkiaBw63 zL9H1S!V*=SwP!vGwb?`q7$9m_Wbz5z|6gD_ke$`k2uE18h|ZhbbZ? zN|rn96w?jUcq7IHp5QDBjkr0L{{Z;KN9mWH~jR*e&HDm3ab%W=YN3aD{%1ghOrhVD2yP)Ym7PpV%U zxQ`y^4{HS)2Jq6@sf~3{R!$Ba*_l`V3(053$aLRwnrlQFzWr0?JjuAR62&;?TuVe~ zf#ZPQ%n13j#+?Y!JDT|0A`QjfxXCC<;%6p#&;oW0{)cxUI;?0hOE&xh@yK_s%qS9V zqdyi-xA))1o$kzBygy@TMM{tyTx4XXhGa$13hL>(J_JJcmk*j}pT$$?=rAt&tCNA4 z0qEJ&=iBW2)cAwOSHg%=CXQ1!z!&q~1&*U8_EC_2mFvH-%j=1ag^ zp9Et)q)Y$4(==+p*cY8789{~?rc3V>y6wRlP8`t91fw#F=UA)-*ob98lj+f!eJAi4 zC-}^U+*xcd(LNH0o%RDh0TRe_QH+E43Qs_yOpqe<`0b@6O@SY;VwNp*;ub}iO79fN zHX{`1$Lk@p-GfS*kzoX3k8>$(1y>AcflJO}+K0tgXiUVlmOX%W>q68`$}|(P<1ko_ z9KU9h9pmT!b9#la!g*b-f$`*29u08>vMWTXb;0AX?o#dnIDa!}574&tqT-If3HDbS65IBI7Wi5f+i1Zd1ia+NSi9i?p z7YGPUiqgr&hiiQ;vX?N*bBZVvA2bVQG=jIg5@V=LMHcY2)dWTX3uf7@10_*$jII_N zyEi@8Po2yxR?OkT!^RlQ=hFw5A=CZN+xpS1Pnr7F9ywb-W||%xDy?!$G?c={r=60+ zctyTS6j(lU5Rx3A2~kIBBQC_+#(LTI?ckrsZt!Rid=iGE0ddK>c~4I8!-XS}JH7yS zX{n?E{#`p)N)uiV5o{BN@OXN^f}{Y3z=AUcWkdkOs7kz1qx|v{%#D>TP_S|_P7R%W z#2RA5N7tO7(Y7-fJU}(FT1dQ`O9o+B+`U{i8WC6WubP&L_)g8EK>E; z!{69i$lO=m;RROFOC;}A7v{V{^EgwPV7V&SU6Qo(Oxy7U5d4m@e)7(~?7T_De(APN z&X@qE8{B5O`KjK;)QdwuI-^J2UNIC$YULwx)UYquDTb)WA1h_xP|4!7a(414RfvP+ioPO` z!#zBJ18jr5zn9tq+!J;5G#2P9cn*UxTP^czHA~(Bcmtb;$5;R@sRcXTkFKy7#K8(y z|A#y%V}s4)Zk}>i=lP|D_avI!k8UH8FGydevRVwpsprg!Hxs!GD? ze+(LR?f}TjAsRp?sivJVdY>K!zv^Z%Tssvy#N+ zXF#BzirNGPJQiPN(F>W-E2v398^ED*XYT5hrk{XIf~v$53p($JND?g+O#lf6KY}7| z2be~`*+-X$#-X@jJ+JA~`PKw$ddqp`xjv+Mq2)J#n6`Pbw28^l(inTb*S=Y&X4~Ji zxC)~C?qzl4bNc0LmF~-<{29|AJKb~wsfj*ZN=r6ynDqXm7yc8btyQm{dT63!Lat|ie>oUErS0ay`S@ryogOx& z_2JFY>UiH@GiZ@yUqK)JKX)Kfg5Xb zadyE#S;ghcKPcD8jt8iu?)mmxS6Ie2F`oQd!tJ+MoNN+WSfZ;fr6qK6`&RHT8i9z1 zg%nDR5k?WyYR%@K9Zd=W4i|fO#F3PLUa$ogQGpL?^(cP)z}RwnOBfBLa?D5m)3Fl2 zfJ&ZmDNY6DHAWq3t_Gw2$0vIVRh&bB+m4UpWP~xPsCi+TXQyG}lOB zpo(3wEu}fszsT9tx=K%(`duXe1!DoCSTj3c@3Ex@t#Z#tkFysF<_x4CwUQ{cjO`4> zQ`PnMceEXflmyV46adD2MofO@%WH{@ih68Pvv@`~Y6oPg;sn!4?*8P0Q*lT=Tb?`r z7K#lztKLMP7Hmc3yQKb)?Xk*MBW9CNq7PQDT!Xv8we1+0GNbBL;-~s9=&p=Rve;FD zCcC0KK;8_}MrH73&bmVwXd+6yq~xL&-8`;OH5`Ipd{}jOW|Eb}i5HVe>uG*~AB4uxggJP4V2nG! z=WZ*|nG3a@B7~~=iExy%Q12ibqz*>R=lX#6`hAl3DI+K)(RSpzDb(v>_Lyv}0T;*Yuz$jKP z(svGa8sL@|30Q3XLX8kg8fRZ%u7ZmDgC#ni*E)c9>Bp#2B~$x*X0N!R8iB#yL250A zOtIzHPrOVWD~>a`mq*PM@>Lj~bZq+iwyY_WhjZ}M(YfLDL8=iOqHY_S({405=o<}f z276-1r=rz(7#KzaSabI=ZFQ29HIj}9b@m_n)6sop9^LQMH&+@HpczETjt6CGq z?PwJR>y6ZiPRz~kSDHHrsy%ek2$SZ};^k+gz#6Uf+dwIU>5(l!?M*}bUl?p%;uW-^ zBZ3N_h9NZW(>KcS<)X>82QT7=;mF4Pfk0EmJeS3}l^Bx`mZM}x=1U|rJn{!A|4n@xbrg^|#HFsJ%!-1ZqfRdJCJl*MBQS!C#CPfr2 zNE|Lp_lx>nXyLzddZB@RX?@kKrYlwojreuF`@F0^!T*AMtxZ&hO25VB3#9+A8L-_y zy!&X(oUE;k0m;xUrr%W8l(@oQEp8TXi|jQk7l((SO@U)U5N;iLyq?xIJp0ox5f~c`mLq26 z&AEHPRC~Q%#~)H}Y`BgY5SslX;G08)>v_P=tu=%IQ&nDZq1o0tCKsaIo-hrpIXbd0 z)@5YdT!Ug4v%djxo2|B_!+}LO+M^{1{^Iq(MqQUJu#PWtr&JtI+r#?nFbxDK-tNAO z1v|ihb(sGrbL0N)FwJdDY$+wFDW)c-73mfjcY*${T6#6C$KbxVf%*RYb4da2Kdo9E z|KW&03;g$L-#-HY`s?fa_0L!P=QYs3uV!d#V`OLSV6AUtZEo}5T3hUUXIVv2acWsP zC0a)ZLt0x0Q(9X`Q*+w?dhLG$acm9$<`o3L_ci|yf+0)A_wT;k@7jyCK&@~fF#+y8 zq>%r->B^!~GJUc`|vE1cIJ-Iww8*zHz7ijynttvs7xXDmBxUf?#2`u8o$*k z#w{AHW&;9q`5Kbidm;nkWiX+OetJ`M!5ZY}4D((-v@X9M-)3Hbfj>N{weH_`RLvzb zSAUOULbOVYsDr(Zcve*8$Gz^2o76OD5PG6A{4|z2o~f)Y7t?{LZ@_NKs)(7>icH#2 zdKGkt+Pr^WL6an7iK$Ei6F+sVfLI)9B{4gqKu$A@mz4{#(5EJnJW2A^qiP-}aHy<6 zbWbx*nsN{B1&lZdrMJh_tF2##Mf_dSF?=qk`ebvUaXa5?3;2||Y&4IuESHkzG+h-S%Psg>r^ zMiWfj5^N>cySZvEAIJ;UOZYQQ#x4}){w!c-?2=`ZH`dbMt;xSNxK=bj%}D%E0~xkD zhxBc!JX3Y5sl7Kyb%)w=l(U=ju{3QUi?2f1e-cOId3D-P1s2f^%#Z;OkU__GjS9sE z=PV{zZOl8jeR%_t81=+sC=u$(G8*aCImPzP?2GWhOv&c-eNx#z%j4AXhH}F|M z)JchCRQLo=Pno`4Z!~ujrnY*VrdeKo>qChlap9lMkxBl zITi%Vl!wKOP9czWo?%!V6xa@$>?@)?Ed#s)z(vGq=&E~B*u2j37^peaZc$Hs>l zmV8^da|(Z7`P8szM7(VqON>E#nDcDyGYi3@jTsOeTl@(58K(;o!gkYo9ow5jn0-hH zwpT;CTqKVB$Y8)F`XEp496#Ibm-o)XWay2w5p_EIEh#8<8oW2w6sJdBa=1RYq)CgA zi#;94Qb$a;Kco$z9mAxhtB*)G5$_^WuBQIL5`Qd~-wBJITv3I1pq_(Mb>6gQCbv{* zjiR2W7#d(Yke|IBe0f@zkGqTn4z>0YgnQ3bY`G1Z?>ca(Yuq7>HS+JC=V$RO=0EC? z220$JGnhR*Uulk726?Qc2pw_o(tnv5Q{>o4Qu4UWCBigID1K=N)6Nx-{GgG7_d;K4 zqzY{z3n4U(qF~fN&{wiepDRz=h%I(Sv56uJh)*QnAiipGc3eVxqSRi@)P`BN7JkZl znZhf>!h+Rc2kYll->DP~;tCwdigtmZ=Uzk6bMU%*vs$F4;#N&Vg4}w`#WugHldbeG&ACDKBN&rA+dCJZ7A&Hye9==c(vldQpzN zufGnJYjIUzt!%r~nN?RtQMkyZHIKn1(=H)r|1k^m`$Q&a2;mhWa#OAQauS!PupU|> zw*Q=d)AeTt8SF?j*3HWVGh&j91FQE?7i=eio0!sLaoyF?@b|@ zzM|bQG`GSZ!dxFL5~5+`5Xo0?66{V7lIfrktJdYb{zE3H3BV5A@XdCZ{>#Q@k^ieF zrJ}j1jj_XjeojWK{X;iM^$}5qkV~oB9I<%>wQ?+oqS*?uJmO!Zg|LBhRjMsv(5Yb~ zUTxGk;(I+2*S?l?$OL93d~lQY6xt6n-DU?yyCo4X;RxApWV!4?7#gWyd@7frTzM%m zsFGeKVU&5oMP0ZW=2Y+}j~Ox?M%)NpD8xE`**M$8p;)DriM6F5bI$!eawVb{b!z|a zdUx+|yc=#>7mn7)@9rn9?uVWGEn#J_I!0|0oe$LxsJd7;YugG|qXuVK0?)?eXP(|K zV~K#;p^}C$t8RjQ0qmIW_u= zWf_b|$4VgC%(th-%#zf_x2FXqq5ZUZorftM|BD5H3hky0x;R}~-BhXYsRnqCPzP#yEr27~foBflU_bv=M8`8JySm@Hc zy}YFJ>wsb~7-#XZ!T9hqQo_41=9%KF4EklA;!Sbk8s#9`&yqGa8r-2wm5>2D;YejNDv~I7ytaiQat6sV>8wSj@wwC+mzsgO_11_?)cn9*%S=%zjd1xsU|!>v7VhN>l6}T z*8H*PrN}Ra-kK8;IPVEm-eAVe^W7)jXdeJ069s) zPd3@T1zhghcy8tE!DZxn2?TglTNzX3@EG&y*r0Yzks~7D6Pgg8e@bIc7W$okc(gs6 zW0{1aJvmgI=%)Bgxc5GZ%hTMv27_Qt_l>SX_*}b$m~O(&E^m5yg%7GVbH`y$<3S6t%=$%preX%DMh#wyd=~zFT6e;drd98MXUy5;C&u6 zA8Qa}4=y287xoh_kK__XQxJjXQq(QbOenx%uf#U@|JP)Wmefv^0CX7lmDRXn& zIeSvD?pmGqGzf5Cjqn@vK4$ZrN!w;5?sExOOYk7}e%I|FT+!POZ|tyo*LdL?>EhU? zKktaf@=tqL$rWn19=$*L-S1UMM*+LEP=CwR%c?}IwV2rn3bnYE)kxQ zI)H6^%fJIk6WIq?;!_oxZL^7+6?E$u{1>s3JDmGm2+4Q9-*XQgZPWLmJ{XnNbe}^& zQx}0}OSm3`IrMYbtE&w!xy(H3p3;ku^*RG;ikBUf@43777nGaHweviG@Pom-y>Rek zR~Q^cabJX;iViUkM{*)OCdn&Il8|%05sv?ibF>vXe&F z&R>yAumXIK=#^(!ubm_a%fpkh>{Eoc)Lm#U)VW@n+X7TOk)jlJExJ%*Bge#uRyuxo zZM=8|*l0M(cTaz^e%u>y0QKO(*r^wz{uX<7G zow{?ZrK9w!roo_oZz1K=r}O-i&yKlLUfT(o%(Bhqm9{!|F1XR>d2~{wy4kf$$`tv; zi9B2ykMKp*Tg&YJ8p(fR0B@gxyM??Mu|9(7fe(?pXoV!hs9#q zfXa7}G&Nc*4AVTO0PjJrd66$MYJ>Z(8eAForlmE$|Ni`{Oh%QT+R#ZE8CzjS41#?y;MJJ&YpIqt~e^eJ1 zEwe&olE{`ipq*&=Dy>l#aT2K((TfOI&@Xy(v$JC_^#%8{e|Nt?G*mR!C-hsgObFha;!1=E;!hy4&F48ml&pADuRIj1Zm6`IJEKSt>NF3c^J^72t{_jY{OLb z>4MAgXnSc8LcSfmMA5Bm~rs3}x z2NZ#-^X30xu+tQ8w|n{v88GaTQ>6She1RtZV6nss_}%OL)cCuJD`J1q0tIrI&7hOf z)^d-vU_WtwbhKuGqvN4#WCnfaxiKM~E4!Ni*8s&2#l7@!6f#(Y>iDTjgC$DoTk<1d zItvq30mA;mIW_8%q|30TU9sxF3}57XuIzvcMrk_GWkeDI1HI6*x_LZ(;eLkf-`?DN zIWhRx(_`mkbzx`4PRX1$tI~0OK=?+>=)wVrGqi!zN>1V;NRK*%(8(ZhBAa{z1H>c_ zBuEZbsj3DsbgGgIpza`cKydW3y!e9}HL} z#JeI|c!|MJo?bD&z5W5UB-N~YHj^H&8yHep4rLXyc;qE3;NF}(NIJpG!4;)Dvc6X=jU>_n=U4#qftjkuh) z9E~Sq{`q?1@#+DFbN)d9QZ)7`q-xQE!#lSuQqtZ}s+IW_ZV_%n9MA})vh&W@dy=(PR3d#*nGN*+|}meG%A{%Y^Fr%qo=1D?6~e$gj+Dkuo$Vh!ke!Ap-8fG-X^`8_GpUM97N7(B*>5e{K})z;_WB zos@!DWERTU(;(By32aLkrO(kdFdKu(AL=B+e|jhRSh z9_M2E9UF25elii1lvYae5^a1(`YHh>pz0ykPTEn3G0hOw{`b5fHEN@}6DEOIqR67Q z6BR-7hLKidtC5=_yav?sYK2*5N6F1_5#9P@Clg)jh`FJ|aLr%tLh~YvGT=)P%^og- zNk&tZ2Rx?6G4CzOrLgnqK+^pfOcqUMHUn__D?81z8_GVe>3RyYDjhzQP#Pd*XG~D9 z?S1jq{!luU{7HM3i~LaOcG$3%bs<53Giio8Ys|2zV8IjE)cx#6%A%zf7G{a0;#o}M zD_Z267Qtu7JXP)lRtDalq<8@F#>;P;ja64AuQ(5PoKhqW;c3i_Vu%V?X9nv07^*Fja^qf=@&;u`aR4}F#G zpfULlKS)=Wfz4|>eMt76>rjI~)mB;C6i8b)PD60Z43zqSP3H#B5i+wtA4JzL;0I0E z$#-04JzmXu9EZ9tR=vQnE>`=#UI^IQM707RIhWG5GKl#FlHTu^`4W%)PF)A(cE9P# zcqHS0>u%|n{o}Y`Z=Ew;Q%{usz*vnX`)+ak^Dmfx&OjcA>;FNS_+O*i|M83x{|5d4 z7Rz^Pc-pRuAbx3nB4cSINQMinPU3?<$5-sNsO|!_|K5a#8V9c|O=@5kX4oh~);_=X zxl`j2enH9Q$Bx`sU3GsqaWVPzd5&|d(ebW68ZH4Rw5^-&-XQm3UmhsVD`BEzWU|Ic zp>Cn;?t?62kVJK0l-J)S?nQJ;D83zkUqM8AQ&<(#r_UDMv3;oUm~61U?n~;kvhKMZ z+WmGt`1uy-`UZaeiGRe9M(j{FaN4Za0WvDrl1QdQ>cP^SzwbKua@gH~4&tAjS0e=8 z^4=-h(T3ZFiY8`05G>%nFdzu`e1~BK9i1M=1R@=rMM)o41mC?OA^R>$3`T^)>*kps z2x8s5aD__{>HI4qSSymQj({1;&5W>^Lr%c^PT49LF8C+40qMHLI(ycBOB`7@JMQd? z1YXK-{E!m!G&!+zr4n98%l$wf-$o7h1fs{8Bf$Ce&*R4H!Dj( zU_uNNvYx2|1Ifh8;G=CwO4j+-7J)ywy7WvnkDPo0ux+dYzT^);fi$IP;J5`6#h*{> zVW?eny8yV*1JLjfDvb;ihK+E#`N$9f-%8Rnpzp8~aB>6R$-e{oYU2ZZ@CB49os6#( z`ZtV0v_}Y4Cc*y%RL3NM2NBr<2WSyUC;aHGHgsNC9;oWi6lj&(%vPIhIJH|UJI&odMd7c77ob?kOaNvBr+)(y0^Cs86`jzA*^h7$<-->`M&ihh zusl7Sxo6a4I7H+Z;%H>nIG|02o?YqB%_TDj!jCWc8v#M?(>m6ON`^!ckCmYZUBH3d zneUcSIv=#(#=262&YbGfYo4=wDt?uI3_gqrHtdmX<|hw%t~jzpN({b6Fn{W^%xPMk zb9-cP-5mrqZPo8Ts2kMb7*#$XR^Swb(L>#o+X>uP%!VSS6kYdx7;ODnq7p=7#gL$# z>jDY~a`YIu>G;4pbrfk5J@-Ef>o&mpu`SGYLmv}3keCh^Ie?33X zK+Uwp>usRxZ(tkzJ#^&rgt~K>8GZ{XDraF;JIqh~F7)+|J}yL)3bM;39jHg$Rm`x{ zDLgb%{d;JKSmz49h*L~+J@|f1w1CgaDPFa%A?I4yi9(U27pv0AUXvfT{|$BR^S-E?C*>!YJ{v$h$0jEltc(VyY<|+NCqNDUHH_4Qq>vnU z(HX!Ce2I+hR6E>Mu~!@+gudr0t~UT6VTnN<9AN<0!uT$~$~i%{hM8sTyDJrT>N5_; zW9sGGp4yK4Ue3Fl-{WZN<>n45cW^{l3mrM5ZTynZW}!`qv}Vt03ut7i%DD~rCl5|D z%^#LsNv)kfz~!UfFfiu(;k1s{_M9g0Eo$*8>(ZIH2YzcO>gdE4br_^EivA@P0U!N- zta4j;T{4n?toAI>K`clD{rf#YHJK;c2+tKzS_&jsWC&Vd@v&PZe#_K?1E`vg`SGP% zq3@c<Nkh+yOnPfy2e~ zrb{cCOvxl+9A>_0JLS04ytz4o#c@oz73q+526}4Fp&ygX+&tHIRT=FW_<;mcY2x+M zc*zzaZ$%M;4~}@;Y>Mj*Tw}a*wKaL`e%Fn*E=K9dAiQV&YaC#TC!;8I4bQnsBp+M$W<*2ci+CI z&&j9rXK%4v6t^~l5T)w%zVU!J#M0oDvs$ULcS^HXLmL?enFb(@3J4i1Ug zuFBYLuLX&VRGS;_9gqp+q;m??30OlXUu7~+#eSs6%okZ$f7Yavm+hpVg-J;A;9V*9 zIIPKOVzsWWpdc=e12)_X_Dx3t3Nlyv>-WDpo*x4t%C{yLB6zzR5Lj>+cIh%pZI8>i zb9|z5ALxZAbF=N_1;Pc<>IawD53W2i3u|GQqKh^`nZrWH8x>~xT>I|xNB|-k#l3!0 z{UBLPZnquTm{H*~9Tt8i-*K#EU@#c9vvPsl0ZCg4oFg3Py($yPXTci;u!Qc|$xoxN#(xMMB?4fLp?m69hG;L?)2Mg-77NP@sH4m^Y7!R+byu|q{f@ZZ=2O5+uW%pT zcQY5$PlKB%LL!SsHWqV62F$dsuci#b zPLBjjQH_B>q_elm7JePk&p1V~h;rU!zbC=A6P5<%b`0F7RUCEQR7~CBx~qghvf@h3 z8E~ae!uWSEwZ+3GW)~|ytN5(Y#lrj~z0V^|8|yJjP+1XrMj4jaN3%d-iY|btzKe@C z;W)OE(bIs5n^~A)&BMDo8YTEqnV^d$_7Y(B0{v4Lu#N)JwW3{o!OPS6kIb9_tAeqg z1I|%s-YOR!I7)rX)~HMI%L^=jtKkKykJ6xwYhrUtB96 zZ$uHy+{L(ZPoIepTS%bj<>~c7m#DJ+IOK)h3!&#>@w`s$yAt$|l&?R0SkX#HO0~c= z3m1GZ!4>E%V9}T`Osg{*7%d@3&va1i$s*z`>@KV<%M;jfFK}>l6c$paoS~IdEUVPi zMnxgx{e#~7`(40VA|3=3&dKd{ezLMmze0oEdzJLKa>qprLp7bl{2>B>{0o)gj>cSG;r~3mrt@{Dxxuz0Rb@P1At%^aY;uLrpDH+ZH)WN1Q z161veTXB<9@6$sR_j{i7!@k-OB6&3n#w4-*k1|#yP!dfGx3mkEu^R zr-UeI6<>@BO%yP)FLgpBOAPC=<3{@dPe8n%d5#fjDi9(fYJ`{|ej?phJW9O9atL>wFtNU1YJ*rH_K;T?HN0ID=k{Js-*lg(gzh_4XF* zkSi~N<<}B;n!O?49c}Oo`t1RRT1+JY3x72RCBL~|_)&`qN-YhuiWG@9orQ&DF?;Vo zpBgnuur-l&?+?KmEWNeVpn@&**L}k0M%Js?c91`{zF#)aySO}$A_ZGJUB0X#yAU>^ zfvg{IpLTw(wt1}2Al*;kwrxH1#wVe?hv@`-=>c=6<7`JA{QBh-5+uj*sSyx@iQ?aY zV0gMCH9f&d3L=vj9Z9OxM3C_k_gYvacJL+3(F-HsrETcB3)Ty{wg0bZ7J2`0FE|hR zp!?b%l`0tCH>94Mbkvn20i5a+EiO_jVpzDUKiG15%gbIJ%5Mg57L-4#Oc-@2J}}-h zlr*29k|6^tABZdIq~vt*GS@JL)aD`2=wq^!+DgeQ*@n9U%2euUijZ?A7xuy>51o3A zR=rpqw>5?ddC;7km8Ja+Q?5Evb2;S0MjXfDUal~JzUPWSwFn3DJDSAfi0NEGz>|sk z*SmaODRxaGdZLO#h-8Mbmt0X5J}c~)#i7>^iPc^jf)mjXU|va2(V5{nrxqgxlIx=a zmYWD#1){Jj%5OTJrX$WD*}cmaGO_TGR z^-pqu6d;F>ltWIxJ^&ZS--w=);Vv80#mr z!JsUPVP|F$g6_Ra!Lz}tOdeq_dx>INHpf;aj}uOQ8EMa`+C^C6o`NzIPetimVSadG z4j?VUfv3tlnlovT$Bl8ydpF_IEd5z1Z3kz;$PEY+u0w8?(F|_dBcmaiBaBPyjl1*_ zvURR~VOQ3=5zGsDvAZlxyjavN|G4uNE@bSa!#bRxsA}lM1pW9EM!sy|}(8h&J1y zoi*K;E$3aTEWth3xI1!Da?MCL`^>sd@qTd@=Y19DeYcb1#zG4Ns*b;YjY^2%Hn%-Z zuzROZS8LvkLh(mY(BXXG@Z}{)fOGI`eBEJWNDdXs;V)(V#Sjg_f(dk#@W!f%A6k+x zEV92Yt*5>7f8wIm8Z>n`eu4cJgC8E2wV=PP-`x=YRScH+{}F@#1A!@0Ubk5nLGW(s zGSGYOWkH^kfI^cCAgC;05dtPhNCM-Z2}NNqY$A3|+axy5JLxtx5f=Z2avXrz7S~>H zI+cdie-5bCKWK@Jkxn0EZmHVVXSX`S0NqFqWDSj>##ALmFV;9_!IU&YQ6^xizyi5S zbRpGen8@joAY(y1*4#i=RrIEI$nmV%V6f6hh913hIyq@AmNQEoWivc2vTw@UFOk|8 zhN|zN+Yef6l<(TMg|1$StyQc_C+U-dkW}-Bp!-v(L9&?7I?3?pCk1Bi^VeZ(AaW5F zSsjh8?ikate4N2Ei21$WWto;@y^Mh7Xhpmo-CXtEORB^wSzeYsF8YT1iIZ8o#R!yD zUZ=6XRkBXm*4-&Y*c3s`^A9>7vSf}0}C$U6R|?c*;j1nb)s+P zUDfA)VE57zwSwv!_7Uxy(N55vxZ5WemLCE>EDPbR~!$P20z8O;cpPP*Q*XZg0sy_FY8@CChL+H3eQ6yKO9RyP% zMl2GO{%IjQi66000E}gYVrYbwK3(H~A16uMzBYR?afQrkAGOFCo^A!F6D@-&{mxd} zbTq^=(IP@G>Y{{FJLcpps}iYE5yPn|jm#te9Nbq!-dWluEGXr%xfLz8im9GZ>0Y;M z9zr#lD4o3_2(_+8kEk=vtrE7+K+%*#tDE<5=qRV8lP1%!0&0Ayg?__?q1TMQ!{;KR znEcz^oYTo!5{`FFe3AJEERfKx44X!jAAYJpInPbp*9=*xq;}%Ys4M369bw9db9ags3cX=Y@8$_F0Qz4m)p!1(R3FR%tp49C)&IF5{@?%Wf7|50FD>W&-(Jms zT3Xo6&ep-n*huc*dKoPAUGxW4<^N8@t9=LYCj}MU6tYl2lR@}5STv(iWb{iYBlO`L zoSIf8@#~mY`J$U_3ipSvyWXxw2532MfMT}43F92WOsWa3Z^D@3 zFT%K9EG_MuFb?B%1LFvj|JAP=1 zSMxR;h&}}}(e~+$wLe@jDdWaO*!yA1(_WR~yf9l^FvG0f2Fa5GQ%Q%U*Xht7As)tW-mTWk5wRCx25d?dTPTNCdhl~ zu`|nSFvx4tLoWt2WgJTm74<(ESShFB2aB2` zQd~h+#llR3!Ljm)&WstQw%wJ2qKpFxbbPOX5lZ?Mm`wT)Qp&nmwZdN;U<<$tg_YG7 zS?!!bUfgDlwiRG^(hGRDLe|KCQ0$$&?c|NsH9OCRQ@@4@wZuNRTY1Z4Hl@faAfsoh zTrAx|x?HpE33&-iTfa{A#!fzG-(S6NnNJW$WfAjIj?#oRMwj8@Q@)&S{`k z`bpDtq;rq?%GL4NCsn??#KUkSoQ3@$)>5Ag8rB{e3@E$ep2O?%Sty|aM#8k%&Y0Jm;>vdJL^TJOZCsYNusASSN0G&ga z>O|^EV07w16Y8MZk{Xf92QnMi%S;Jf@qC{wyN+%$9fX8s(9_Ggxg1fsrQ5d0~sp~f0LGK{pm=-}WKsm>$DK5$-eZ}mhD!@fm znekqOq^;=&3*7=%IeBj&E9`&Pn!~(5u1!Z1sXLvi9lL=R3W7`00@qyW%TAUitmAI8 zJWBw;&24A3w*%2Lvuc}D)`NV6hSkVahUF)EPy`gyX_crNzqP&Kfz_aFq0MG?M1WQ%CR46dV$~m zC2}K#EW66KbsD`Eaa*2X{#|BS7v5JzHITV5pvq6}Prsw0+8VPg2}e;5wHR2bMg^i= zPh>!Lh5PJt@~qWHp6r1?KF=1A8a}tW_0eQ=eH;(Y`+oGWbhJ=E%ltk~$=noey4fxo zgAeZ5{B^D!ndX4f!^sGM$em#B-(6$U|3L z(S(htRE2ZvaWEf4_<}LMsxk)IhhjF)eB2szH#DPd4@TMu%=) z4(Z*?fd_jA&B|n^_Lf$6I<+b5^37F*bTw~Xj>&S3h?L*h4)!fEtsIb^Vm?O|2ATi} zRb`UC_%T7UB}Smxsx_#YVY3Bk1PqZuD_N65fjTo?DqfnBjq#|Y$3i?bJZ4UoI!t}R zjjxLf*hN{sRdN+{7mBB{SBwtOsZvkEtsui#(p!+af>n3?ZOAQ?vgf2qL*`*H5d4Y_ zVE7OdnWi|*T4MZ?4k}p&7&(Z+u+@^8xYjE6AoDu39n^D`Sp7LgWb{F>m_92x2wb1F z{TTmoSsz;ugFGgbCMfADu!X5d_E%W9iDgI#qB^?()c;`Z9fK_Gwr$sk)$OMS%RQDtZkm`Gm34-wV*YM5U=62lt->m=*AW9IQ&CLY1 z!Du_laS`T4|J;bo2tdN2NvT_ZZP_JX7eUHKg=!ZlPF9WyGXm|0r~2^3sSx>2RWkeV zmhxq26Tiz6p}i)XUg$nEkj*^+uQeaz5>bTBl|vFe7sy3d(;`2spqzUf-!`BgiIP6s z%Se0D=C7YfUoj09$W@|&5b1^`Kr}-XLl!VbEm9%|=y^DE_rnktb>h*n{a~LnuUh*a zX9vW=7F6)K)k!o1zeuIsY6iJITQXA=N71t9j5OdijqY6oF?3L{m!!hoB%=INFvnSM zwF7&bT|p~hXyENS+9^7@?E9Ls9ohIK&qq&dA|d4a5fyvDoEG5Pc^xD-?r{pAWzuE* zmd{&0uZuLOIjx+(biMDgWED(gJBKZ7Q8)?Dezykr3!pA1W$B@7^k!154B3dHjs-T2j4kt`&k5)HP zPAsP2W~>d-^#4<4%s`5L*RP%n^m73=3bfUl+dsq;1ewa8cF*)xOKpl{U{M~kVI!VMbp#q~BE4^{+X}{vOvqm>0 z=W|gzB?5B3Bm9JL%qnOK#c4#RKmiBDn=Awmcsy1+Z6yZV&Ad4ol+@LIENOA2qLkJx z1`-bp9PYV9cwZ<}g&Pau?Z?xlXG3igu_H&KQoKR#y2~RfS_y{`r64hB$_OeQmzh>!Tim(Ht)78^(m!4uKVx5^W{ZS72=s(W1=wE=Ies-Rs;uSp%SF^Mj026u zek>&H!gCV^UHFD9jZa2b4n6O9k;?x)Yox(ESFK(0_I1sqo*+ke|B;$&tpFcZ>0BIK z0)cC>m~p_g)@W`3GZ6m%D82rDlV$Ps-E`+T&U}qM8a(6IN}~}{h$?Ebo9q{wCOb!8 z5da#tN=XEhKD~$&rt~_b3jbC+ZA>hY)&Z*PQ$C^A8f3N^*(%6Jc<%0}=oTB%qo z&3@|w*eQSh!pQanVMH{yP!RH!jO-(1QIcwgxgP5un5B=g@SB+r=H8}W`a*bHTP_#jaKMF(ckU%CV z4AG{KKUaz!R>(dSd44Fga9`B|FK6~ym5RDBpC__1B(P}kz)YFb*{_z`l~;`$sr;P0 zXbohO;U{KLa8e{r?yf8x|E%HfYx{A=^vNZy$Z0e1wAU~BFiw-xKiYF>B zPJsqP6F!Y-%_dH3*5D`>dne%89LuUcJH$#Wg$9ZHD{cIY?EY|V`^S}q~7jYL~}s^Xcfd!88gg^Ot?ihisJmM zys0T}M4P8+7;hU6lczhL;bG=hgXj8jc^NuzfeyB_C``Vl)U_U~%}87==HOUX(!OXS zP>2HeN%|+&?5MC%^W0Ueg8{=5bTa~*Jr2CaDKN3l(yL{D@=3dS$*es7>6Q;?{{(Iq z_-g;kTZHCV0;F=PjbO7EI=LijME&Yoz%M4t0pZmA7F-ien36)o5XBs70G9z{iEI^79#;TrYw8h`0H zgG-1hd!AqQ>g)h1s|73R-+{5_071gXGLK(1^n9QtHtPvDx&ZQ!C_Z0Eu-3JlgD#3B zk}&fXpD9$BE5WmeTPnZsJKyGFyQD9k**4@_yza*R$;CJ=0tom1*ccmHI%mt?emm#) zHF7E<6I60fTiC4_Nn$)a(}Xa`jL8m6B}?FKFLn~g22{Qj#PXLMd&-9hyWbIBy=x`g z=cgH3jI<=+%4S1dzdz_YE30}veDW(>m6|n=>*Z#wi^`w5K!>=2+*{TBH6(6&l*9YW z?ehu|*Ab!-6M-;6#m_a)J8Mx8X?hJ%F`>i7N7n%)rIAg9U)B^|%@v5(x0h*CPQ!T$E&OoaC_+5&$ ziN~p3nFp0SF*?8hTIHnX93LLcQj5fUOE11lWDYVBqocZ4!BcB%OlR+!S-+AXd0**W zIH~n@@EqUlKX4sNM+UsR-`s~>ntvvq{?Aa%|5i{_G;wgTa5ORg2Up?m-gAnoj@>3Z zf_JRnFi~0`~w^%N~?-pd}2>`s1qK}RsV&U(oVgREr6w4n`JLMt?;1~XNLp>p_Rle)Y;t%|kG z#6J|TYhmeIDGJyb-Bim|gGY&KVL#9yb9#R>xjfyWN1k^7{^6sWpve=zKE?D9M5^G; zI?!x-hEI=@sF;MPlAy&$nCntM2@KPW@2&?sY5Iu|yerzBQM!F`2qYt6wg}6F7Eu}X zjDLAPV4E-olG-0+)jzlJSX3>6X7ftyNB#%(&fc!W2-rG;w5<8fK?_6%;?PdtGZL#P z(BO&!l@CPrT2gI~Cm<+t-!l?(5y&XtA?E^l$5;Fav4R{Mel$5$vOrgoXkZr87N$L{3lc4-LCa2U zXkeJ8WHn5T6gp+*EMk&9xcnx_P_bc37&3ADNA{eV&zOgUr=Qc?Z(hIY|BA$Yo4-Q2 zCc8biefM%?9x<1=9Ygz$?SseAKRX5<9_i5AL4keN7%X`D^uN{g>YLBipYz4ILll#j}6-Rv%dV$x~PkyA3uAJK;bx zYgWPJwF;ala2tY@_oWk7D^UejDeHyyHJG9!vnqgt60NE+PZ@4nJAPZ7MI07NjbetQ z2U-IrgJy|hDSves_N$|ee_(81bLTSK4|fv#7xRxoYZQSmt(=-n7fxaJb4^Mb;*c=c zq#v1EV3CYRg-vShW+3wS(53kE70pT;ygb%M4pt;PJ~l6wH<6Sx_qsqZUEXvVr8LNu z0v0g12{u>|vo`2Q{HVo5Vn;ie1V}oZc@AYn@)$jdO`StSLS7c!0nQSiLRdn0Y|BjD zXK;NNYkbu&B;t!eH0nPfG-f)2#{L+i57^?~G>%D_02xv@oKPtln zb(kioqo-C+;mD;c&n+oO(RAp;-^7N~Q#fPht}iz6KUY^QneU9Z5BAD6Tl?$eXMsUS zj|0LgZu`k7oBP}F$J$nyrJ53PbqllR2&iEVgT{v@CP7ySgHa`;(p!XZo^0txZjW ztR?w!)7TFD;k$)mGVsxObyRD!r*#u9HiSqhb8em56;m3-?Zp(__Nqq*bn&LQf&CH- z^t0kXvoE)oxgYKxIuv!~T-nnpl82iyr2PZCNkww6oG^tt-XFEfI#) zuH$>m%bKPAxpZcB;jqJL>AZ4VV9|G|v=|wc$72BoqIWqZ&jPP3qYyTmHk%>O;sMD&a@T86gaYPW1U(>^UpWKv%IeZY)-f*Wvi zMaG{meC%t-e2Lw*2YMGRd6yei{cY&XWqhl3ML!L6+hu;==1dki1F!csx@rdOw3v+8 zd2?l~+I3t3dXw)~?r^hkNpi2Pq%`4g25oCq6~C~kQXaJR^l*O0!=fss*7R}!Y*R>G zVDPB{O&y54#cy19LIF4>tY7ik&a^alL6K;hk*n8lb6r%v^t^mGvcMr!m*RR6zD2A= z*nhV7{_Fn9|EJ^dA7B2aCi%oqOAgVah~^R8*oOeJv06~E$5()Yqw1VV+GkkYF!z^I zbXeq!vVCYxjmQk7;lRCg4a+3BJixjwVaT3}DG}bNJQZa^ zXe~nCFAIl9AW#w3hO^k?T6?hxj@%H+ErKUpi=+zWjyuyW!ZhEJgBWy1HwV0%e6x-G002+QwI=@d<{6Hj78TD3 zR5g5EKD>nW4fwAG7T1l~dH>b`Q~zm$>VFP9{%;Sr|5)JvLQ?wmkN%X{2V3^P?oZMF zYhCi2dt~AC7XbF(Z&3;U+fV=R%wo&`VHT79j1)r9m)O^oQGFzY4eXTpHj5<^eVfGw zzs+K;?c&9vik|@n-)1p!$x>>rtNOHQ^CZn;Uf-APZ8z)tON8A1JMbCCS~>y=bTTzk zxzZN$M&Ywp`HT(>tXg!Uqru1vMGWF(V+{&pLubh>q>bcYnepdRxvLjMANK~Wb$ge~!*OQlbb5j_kJ?S3VOc7mqeF3@y-LfPQ6ArYDxQ$8aXBDS z5yEt7j%WMOomNZ1FqmwR~^kz=c~F%Lu@rX^v>h)L(V=jQ)DPyHZP*PVfSDBR_o|ZB(1L@NQ&jd^QCQu+4{fm{tM9?a zNqeqAbjo+uC^n#`_7vAHIa?c-1d_=k$1$7(LP)*eJ!G%!zHUxj9UigOgIake{V{;k zU*#bq;bm6(sEv~AC>?0lkdnYzR{v4T+#G>zMdR*_1o3nSVeoEw_hs%Zw>=BQwMqm^td!vj??l+EXzQttA%- z`lI!s6rd)ny_TY);3VPT6;8x}{;1-2^Kwh)a?Il+7%AQCebe)``XU8sV99ie%*RVa zUhm2XUq6I?@zXQtRYy`F4H?5h>T=CzgeYQ01@bxIjfedP374bbUS-v$4OUHrU>BgP zqWZ%ksicVAu~rt?H%L`OEmu=lp=`ljs>mo*fU8}}=*x1q$wr?R;l&%wup*ucsmOcj z0{-awO9Etdg$~K6qDEneC9$DF)W$1JeuuNCQ$uXKdqjOC)G|=yLcfAyjx%tH4})C! zyfWxEJAxq8VS)Re<^0Tg-Xb`yg&fMa!hT)ROI_{Vx(Cx7QcV5U@ma+0AS zR@D6gMM3tC6}MBxiifn<1tI^*zq_5BXR>3n`-F5>V((j5C#|6XUma zs85jfTv4?X&eQV^X0Y5Dl6dBaB7YD~?$8{2tWOJ}`H!P*6S=8EsXt)w#u_ZL3yiZdE*z zx|E=&tNkZV9d?V8QK5xPjwYMJEzAUVE01<0)j4gu^bqP?a}fjrxX=jcvEl(I*G~Me z^QANg>!!S4g#`_%P*Dl2pg4cpuBh1yUPshm+I}4wEBS1~N?o7AXsaWeps$n5B!NB| zmI+6C0(!hA&Ujk{Ysg7u&O+H;_av512G_JaGWTpb^)~r^MBB7oUOl${-k~07x%iz+ z2l8<-u!|74Oq*`V8BSphhnc>EF9BoB_t8xwy=_^C0=^)t&OdUpX^-tQ0hSSR_$ zI_Co_UZ3Nmh93H<$aDZMH`(fTgcrXB$0=Neo?nnHPqwr-9kcZVm{nd8js zj3oU)w(Fmy%@&tJau(rM*-=}~NexNX@4;Cb3XgX7giqfy1)U?@3Da5CwGc%d*Y+8LPL@OuT*wz#@qm`}hQoLJ(>T|Lda?7(ny zUfPahvp`Y->8P?T1pMk+>^kCLOOj&CYml$oxkdWtjX7`ISOT36#jWU8)S~;_H_uoqfx(jeP;E1et75t|2a@sRyX_U>-jtgZ#}ZCd>5jx zric8DvOMT_^UJv8(79BD%DgG7%THnjUTD0CzaFig;|ih46+LX7MzQo#HDA_n%SGE4 z@S{*US_7@$HzOBvMa~_7?@~JKLyTNGrRO}i9u0~4O1a4=mRi+e1=E##?ZNC7y`oBf}ym`^j_i zsBu!_fOdn2x!K|-t-q`4qN^$`zeVRs3nh}-MACb_I1o2ZHTp-sN}pK1)mR#}YP4L6 zKL>8niWF%}bSZA?2y)M%Btce#bW389bXxSWb8yWYh(0S`gXvc+>~-d)&6lnHssI^2 z*bCq8yX!3Pqn+K`>Pt`+m#fp{&bIbX{4IFf+WoU1D?dMTKD_KddIv$$VGhIVA_j2% zGm)k(w%vaSON2;RD@!6Hjzz%eTg@{ce5W4X36?{+4nYZ*=I>#w2RqWTtTHQaqC=hI z;s)gK5f|wg*!wy!dC7{><->)FJ&70x6DW^?lMff2A9x=B=1kWmvAZ4R5u}3Pzz`4y zlv|)a)GY1;?jAv+0CERd5{IB-`N3fZKo<8A;$5T$$#Gx!W0(IDp)Gt?q-!vh33F$rBPjMbmkJtM%ULUA@@%9sB2d&A95T_pm~_;n zoNOYM003{aUcz5W0xDSZwnIqMGnABzuxrZ`npOy^CL;0#ETKv{s)JC5y%=zdKe#;> z6{_v_JTWgKZ4c2i%}P_xJQAsYR?AJ#-MR;me%C+O2=N|uxG|M5!hsx|OP^H`xX+Zz zoV7ju4#ge94&L|$5ky`+|7A2pra;baSgeK;-)InsYC9lqz=|x6fK|Xb%rJys_PsismS@h7k4*cH z12KrW|3d?#b}cPBEK~~7fwsTSjfkPik6e!b(oUgWY5?ZJ6Xb1*|6Dggx}U###E^(s z|HR4TX<@h)zZ$Ljy@}xM4<^AfSt?O9W1dn1n)g7bNW`+wx-PRQV;WNIYl6K;aGCK& zgmV7R#icZ;yEu^E>lIuTVlF3)O+izCaRE719OKl2%^WdHF8j@D>j7B1b#QlzSV<(O z3qD6;-a11$E;b-BnQm!J0dV-0YnHyZRdpc4Wz=P^c4CeSr+|&VG>P1@2nhCMlI0MX z0eNYUwKgwZ;<2@Qgpi{(S%+g~#v%X`yC=_S&v*mrM#?b#$wTZcg3F+BT zfP$@(cl&W`P9~$^V=2?53{0oJc4H4#D`x#onn8ea0g1sj0av30^+p$63lZVl0t9Bl*5lz`!WG?ljhH;7-G6v!|;YID4L8C@{?mtQ(o;r-7KoI28;?@WH zO^|Q&Nm#270Pu>2t{BkF+1a8E1D#Cp5PaPA96JlbOFdUC zi~5p)^{I{{bZt_~mM7|=_Z0u!Dam?iunDV;-uRc-q3E@Q3jn*0McWPoRax`q4Pl)B zc#Qt?oYnYtrKx8MmB^inlrdw`1GJbxoA4JyEvKA?WshJU5!b&R614%s)9HSvn8x`y zNQ1?y>GFR&)oa*i7lu$4fu=ZDywcN7v0})QBM}x(HTbnbPO^a-GsI0SFRhcCI(>g2 zw|7GX+>%C}9alP@XaWnHCr}i}N;xldl=UU~Fz07$HtD~)Cs~@?0}Ym-zOCxX7R52& zLYBp5g|+uJ@z}1nwfT_|!Xxj>?#Ip-2;F*H;BD+87nP^?)Jy-Ok4`I9E(jXg((LzH zad9tK^Hu}3TXzhZ5?vm&g=QH=ty*=$hl2*v^IuoBIPLGOBL`>{FShSN&&tt{z7d10 za0oA9>$*~i)#{qmj<0|?hjSJgvBkfBG}H*_{PA*s#Jf`s;pkNZ(={)N*w$t>IkSCU zGumNQ(+LksbYUhuH0WX`yqSZ@J{tJTnmFP_j8s8YMbZZSnYnoDH>^Y;)LP$>l63MA zUM|hoXvr8sv{J*q_kbVZs{cA#&TWu6b?=VxAJco*nL-CmWs_h2Kp@5n<3$aT;nG5u z#f`#YRV^luHFFt}m$36xW2g2xm)4l{mMlj7Vp|K+mW%a)gK`llwu!}4wIf0b;6`D! z0zMOkmn=^t!Ot0TWx)l-TGE>^&-V&{=v1-M>&?>1W*92ccYAY!aO(p)V=f%Yly|nY z7dM-IWKIyhYDNKPNruLkwx&FLCaVKYM@z3aDR}B|Sx_C$x%?D|V@sj2yJLsBH(x>sWB6y@O zMfW1NR=Y6v66Q7pK5DnOY1=YC6r&o8OQIR^w)Vn<5$%R!$MZq?6`|M183_2`oU+OnOrBB0n@V0C0$ zUoa{7D&v4pyUU@*LQUi2_r*znse5z@UgDzOW`mv_q1`y>?b(G^l7=>N6hJJSZbO}P zkK1YbvW(mLxd|g)7hvO{=3HX))ALw&bMB(zy~W_Erof}CsYslS`hqS=KbzZHteXWND}|Sd##SR+O3p?{bdMWwXZMzZ_L%}t6b3Z?{PtSj~sNil|RMED35A98sS{2Llm zukI}sXKCuXf0Nl1L|dt_=Ns0NdkV5-FK402gU@dHQ<-exPbnsc%Iu3Bwm8!2DdeoT zM!~jhq-IV^r5x4Fu~DpH+V4iEPc%v&?o^?IrUTeK8|rjUqF0^gZYTEw{$vVWGla%7 zy&fbE5Aqz+EdA(NL75xMWvX=thqi8X5_(=XXiMKwq+AT-n~EBqh_tD7nAE1w(>Sv> zV+(6aIh1-`K$#gaUfK?7^cW&^6C7q53@hkqhD-5cFuM?Pl48-rJ*1NM%*WbLCHW4~ zNbXuMttAPzKGgGboZO%jR;1;^!`wg;L!Qp0J6;%p9C zOw>K-gFkodr=!ztj&c)QA{%V^J-13@A)P5WFp{gdr;T9WcjWMpp5qZWSm0Hw!xlPP z>!Y3vxpfOM@iBYC%hVE};l!>yJv~|Y{c)KbF&t=;uhVN5?FsX|-OieoEbLB^-+Jd@ z-G{(33UH!8LB!yN2>M0V4G6Mwl(JIoGc3kGruUhyCvX&0yTh;NX{87R35%T%uuYcl zot$@X4_nD&arUR3-3s$4W(O*Wg`le68g@>y*ZE;0OZ0oR^MU43A%=H@Ur!*47$5EM z{%EpAstWhgg?}(YN9`u8=*kA1P|EvN2XJt1ezW-a< zMF`Eyzqy5m*0o+hb0}B|jEcn!hKzlAtzG;lS$9cafV;ek4 zRgz{2s}fq8NZf)ftj@fNao9xZU+0xcJnvWNu~#cLGG!awPwknWo~L5$hPIqxfrJG>3Sf^|Ag%=fYci$epK-^Koo)55@4O=9eRy`jZ27)! z(L7s)s^qLAgCq8^!*hP?yUB9U?vzD8BXQDZ+~e-je|=|@qB3D)KD$^z0ffqt)JDi*{YbIV6Jl=l^x{c^ zlc`IJRz%U&(ZU~ihTl+2duFE2?l?;aJ`bny$K||LKXO4{qd_-qswHV?lVa(({Fz8` zWJokr!RoiO)u5fVLOse^{S+e){_b^-2On&fibOtyLywZ+wi^!GFS_H}C_SuC;B>!n(n(37O5yJ6>duDOk#Co(A!1$vrK z4M|wE+1BWje3dD)e5(mIX^Rnb%|50g`HPrTQPU_us--RKb~JLbgpheh)y&Yv?pS@# zc7UxBre}R-lcY1?XUA{6JvjN{_TllIt+NkLXM09;+2ws^j*f13=9V-q-Ci61 z`spv8w}-=D%l?q|n3u%1PBCcTMep|606S`7!GN|#N~HFXBdrlVjaITZ;hJDg$V?wm zD)hJQHnar*6d5IHB87QtPK>6@zG#1+@b@b*)JD>8J{-J2N69SDdF_XkHS!MzPsl(e zK&enUauT+BAy|;(VusvOOC^3m|Y2zc0#2v9rsXHP~Yc;`h7p(JzlDU^ND)kpSsMW{G4@T zQ{kWh>jUuq?{o#rM#(J5=?Ka6#RH+^Up}2KCnh1Aa4uLW=P|~w6GDepp*h!fR0EW zdu`1C!rXHfafiMlgidEFn1U3i9S*cNcF-i-)0Mo;kSF7}N|*uhLRb@+8fV2Dyc&Td{X$ zCD(TByRLsSFA5|F0Dh?tcadj>7(bb^(8^eFZg6zvj;Km$y;Gv_Y(W_9u$JUMfMMNq z+!+ZAQzeb;T=GJDt@sgL(iC3Muc-2XX_8>^7Ih^GmugKqrAVs0=@ui>Jywm ze&akpYn~_wF>DD1mZTqz0Oi3f3w);%E&9%bxd&5cH(Jl*C!uSTbjsK|!Oyu!O<)Ug z(k#iYo@?A@3?c{E8+RRCX{tj6Aw?|6Fgxw08hEStb{TKYYpD=w6cG#H(aqR~ouFQo*=UiODR@ZMLboJVf@RTpt`6qCn z4)tmN*>StEvwYb-cslRRX;J#qlGR}6y7XOk>*CADRLU{J@1B*SC#peYG^bQJO8Lw$ zp`Pe&cEAuCitwCT@?G6f{t}Hi>|gLHS8Ttxz{alCX*ca zb%4+ULS0!HPD*icShb%rZ0~p0Tu`S-8u`@&XUXATIHJRmBpNICVES4_>Do26L8K?p z?&A56ahgq@94No1K4n#xf8#d306`$<=F0j9(71Ctp5PmCMva0wn*jz#lSzC=SrS^S zhNR9gV`a&JB5+u=*683MN+;Kgg-i9K!R~*HV}4n-{aY!6ulaE6yFQX!rt1h#KYEYd z;|&ibgUuQ~32GqXdfe1sG{-?K#Q3`s!dC;#<8SRN@5=D6HoBY;;H`AQuGpj7xL*6z zxuDQluk9;Oaes8O-QD$5l|tMA7QU5*C_%~L3)0Qn1JE*M1W*!Co#E+KBL%QsfyP?j~_23z9W>M&VTAm-YEjwZ^MZ0D4Psw!v6{pLz{-Tj%A zm{j~Z@>NxK_!*slXyKDvwzV&G`llE36}rh{S6MpI(+;w80Pe7^$-F(&!EDJZL)Q!i z+nO%g<4WAC?|T~E3q+ZtX)z&BA(qR_Iq&3U^@y%wL^%MPl%ssanZr8{Y`6Nyw5uKV zyMGIHc~dxV8;|FT!OChWuxniZ@4AB~HnsyDB>tG6gh%L!{vXp;eb=Kffty*|t*wX7 z2FR{x*Y|_lN*dIvFVfSto4nSSyU-7}C0we7jM=^m0 zeM337pxz25eYyB1aQ$`$Bk|I#)Fo^a9u&O9ET%vM$%GeSN<1dG-8MO1we#=kc{m-9Keyv8kSR}t!ik)`_?CFsNbHw4F`j5h?C@+zB3|9)^?PgEi3Bz0X&*+`mR+j7GnicW zLb=wRnNB2CSdm7kB8_NCyGCScP|+kol>w88QFsR-!GL*Hv|-IVy*CSUc>O%|NMdAp z3f#}s3axsd`yG;2x7!_afA&?1-OuCoySn6`SW;|Y3A<|pk_|`u&>c6d8e(LjkCxlF zeeUvCNQF!t#R-LQLR7C`jK>>H=4O%RxceocUeG=Gomc z5;C<<!e0O=fH#OlM--NAU-p*Sp`|w$_LqOP&r%ro zfo9MzJ*fivgI6^5fNDclv0BVcf91Z^$f9X+!ybi!aBociROlvyNMvcE`V2$eOx1bH z*mTcDz{wFujA&E(4A^f5vo#|$#Nol==kfI*k2j7?S<&X(xI37eQhR4tPwtl7^|v<& z``a57*p{?;0l=OLv%0?vC4xyHBXIO+lkKomSRWsoNb63GMl`Z?Z!(^Wlj=CF5{oI& zzbt8PStS|>*>7w}3d8g~AJlDLP`*3L=|`CFbMLo&Lrhfx6Q4bpoplS7Ct}w6dl^Fg zyQl2bro8-XwL$tf9r*Eqi*d~w;^1=NuqOgh&DCT0hsT$c5TGfO(tiP6G2C3`4Bb}CI15$*}0{|1zwuD)Go*F{vzC}=Wok5S+ zd*`#);CON!=!ctyTLUsxT4DBqvkM1bBc|av>}-Raj@QrCs+Na2O_8tVn}lDU!msa$?W;*<+~S&BlS7R%|_*x^0`D!xe_T`=0AK02gkS9D8X~=!7L?T zz^Rhz~*dn?X-9Zim}ia`NMB^gCSS?@CU# z+U_YEg2Q16+oZh{tvRv{cO`EW9WLsoY^bw;WjOsrB;CGRdm{Hv6s(fw+|ZUv=p#gu$EGwNOm_I%K;BChEf>p@S*sqOolBIjQ>)Vh!<#1NKyiNELE^R5 z?Nx2nQ(=(eju0dsWq+hJTgR?Y_40fa&)K-kv3!l*DGOAfV&26}zM|;p`cr7dES;Lgg(- zm-*atX%%MVVKm_>P3aAG#`)Zba*2bN7aV%yR4QOl}T@$L@Ra)SKI z1~)V^gWI`S<-yDij3Z}#Dj6Pb5>t2W{F|?-#Rb8clB>F__s!A>+JORRvx2lV7DQT@B#DF zFqlXO$$@ozTjfV0R|;`+L#&`llIr{!3e7WsSA*O3b_-kzNJ{fLY zE0Y}g8L+Pi%||PC=ov73UW{(2*_pw9Oc-5QzgM5%7k2fCrZ&Pc^d98<;S#rQ)ss01 z7coHxk08h6T98HDX@VsXqaaQ@FZw?K@r9-`&cmn&zZ^6#+EI*GftKEC0n_w z!A>b^(Z5w9g{9EF=KqeYK$ZHH8AW3bY-kg2D9dzFlOS8^f?uuMQS<*$sE%^eTTjFn z;E~5z3-Z|{2_!vlzbRCSyg}a4XsZudpx!vccjm3(WRO!v7_(+-^F*1mr)RLyrfs)w z%w6Zei6+Y6_>zA?sEoNbS;@lX$g7=&##7TLQlup^HPsAb>Q`8>L?ZKrmBc4)T7>D1 z(zVeRAW!0Y7l%UzY}34Z&GJt|KMFTt<$C7T+7qE@Zr#lWjPr#B;-;#YGbOulw+><{ zwW^f9_0wFa-nUm5+GU)nDu_R`fUV4poX_rvH`xOu<9sa08`3}|x#z%z_ z%klM5gP+tNuYu0XM0K}ZVAL5n)?=8D!0l9b^+Z{i2yBjbd4BMb3GF9M8#ueqm6!t4 zS6h;J=qdB>9YG=9I&BxOC`L4|yY(JSIIn2Q%ZX&E*Bs1L0vFD|$pU7#;a>6&$_Apo z&e>T4xMpQan97uLHhV;-8Gn1xvE#e1KI`+XkMQHU`AKmb{xN-%DV%2${Y~SGRP5`l zE?Ks0=y9&-X+)kNbf6KYzNHgqsu>w{*WdOYkZ6XC<4IPgs1k<|-5F6i zzWIE#g(uy{y3WoGRzT(JZMqsAf2JX`(M*cLF0w(yU;f0b7tYcn6_z-`A6?2}{J6IFdw&=RrVkSkXDn9<4j% zLHDMu{>97P6|84xI7^Rir#mEMt^!Rec;5)}2TYhBc%`;g1}$~-0i3j{pX8}o28u}Z zTq*O3PFgkctxv_YWY6x5h0!jX1 z^*e_cNTl-W$_r^Z62Yidt>R}N0(8ni2;o9Q&UtLoyQWE zC^tkzT#>Hkw?L>6ZPXYpSJTwgDE@|b+J48)lt~mfXo{w66WatOX!@P=H%9BN>9dA!2S&(?MbjknuX6kC0+k%#R{3SfTlhp5Wvb_Vzz%~0lUC~RE74WZS5?tiU)+~hU)YfGW>J3@qd+JsjurdR+NaRb#* z!OA5pg3<9qXW3}@m-HNgIN~8~^`JI5Ml(uNT!e5xrigL8{%@?EpC}u94-iy%5G8x{ zcKD1M+hpWr?xs3OCG*F*4} z3d27il!`V$Jgl*dlAWF1OJZGTIM|#~M;1Cv7`nAd*G5GrDN`lMSoB=RU=AW%-FTdT zgf}1Mw1wRS6||g*HCGa~iordstX?3?mbNFqpAFz%Ah)6F4sx-^83)--gV_lgDfPH0 zF9uLHV3ZdU{3+LrG8!-)R3o~{fqmB5G!Cv5;;@jV99~GXK#=&wCGZx}hk~ zzbTlxM!7Ox(3{wmfvW+Y7UlZvuj=kzs3nmFDFI)eCK# zyKP!DPoSo&!+Rm!1Zou0`XuJo%_S%HM*N+ci(jEm*l1Pq0G!^t)Ek$!Vih@8rD_}s ztV5g=#F(Inx$x$20=ArC_xi39qS&m)j;>55;eh4i#;tg4Z_q9si}8bapmz{QCydqTFx$JsirTrN?l491o&7K3=G^ z1RLp@bSb*o2S#lcg=b+w-H;%WQhbOZ^3}tXe7RxnxQRti;t*=L!`*A(jn~JKy;U$a zA5A!;sddgWGAXL+Q7waLp*1#EXkiknU{tx584b(;{)-pEY0tnnk2A>7=ZCUxfy6uq z^Ss%7WPM1~DXey^Xx+hl-rX>0wCI7FU$kCNfZ|^;%>CzzP-N4=FDo6p7-~uIvUSX< z1wRt$N=c{`!fd1|lhghgBHd69GtG43#eVLMf-Phg6NWHR1+P8HUW(?^|iE#ByzX;Z{E471@-CC%#K?eLFl=FX>V^_vcSrJz;+ zUYaP@xqAobHw;ty8-_{B`Zo-7INNjun>a^V1VXiLOBBO6U0c)au+c%R@QPjWA`Frw zOP)TvIKEiuw^bsU#TWs8((v}B0pNF3=&Nz3xUEw9^u8x+j|AGdwWOZkpz$9_UXsNu zgm{u7&fm(|*Z$^`sZD$%D0krll5WY?F&Wz9(V9vk#8AP4ZRRL0AS{_J&ED0i5XUe| z<1NkuuO)eZehE4t#LvXRJZ4|)f&n%xi~w$OD4r5Ea@CCdFUr0FNY-u1`m}A^Jl&^l z+qP}nwr$(CZQJH)^K|!V{eACy^JZfHckj$pL{&vaMb%eXvG>}!GIM2~XnzRCEvfip z&#p?pS4f^bU!A1g#H!TA#1nBF2u~LwjR9kPNmtZcR`LrjI~JMR);2SU%ru(yXvk0#BB;NQg7re@ z{Pg3C*>Dvj?q-eN$Q>i}B39|uAwVj6g)oeXm}GLq)JQM(zli3P@vh~_6#%>7b#5;7 zmo{l%ulVS`q)AO+YmVO;{-ET%&92BG`D%&Z~LT1b=wks2%cdcL|#GDifxaq`8hu-ge%~HE-m^4LU-ts8K{b* z$tPq{_QIvll^|mwOIYjH$-Iz0V$(d&Y~c4NJRMBN4FTWkSDQYUKb)2QJ2e{TFK1=` zZ+mC{&w8~#oR$9?RJ4lKkr<#w9@=@Oh^D<6BDGqAXu8t-(DUDwMfRL*?;u?zCJ{U5 z?lx=T0`Dfye4XHWI#f0>3ttN#OxA?ZhSOG;@?5BJo~W`&eT>r2-pn=E@3Lrfc?5q3 ze@3`LaLoTeg`vZ6^q|8xNg=PdoNmC%MkBwY&q!HOiS1{Sh7KI@3c;9nj8mLg38`^) ziil}J>jV?w7f7YPs)8^CRF-Qz)MwvgYTHztTLW_}q8(#bh?|zd}5D}x6kyWH|us5Kw zu{WWyaWFBX`41i9fBBdHTU_z~)E*P^>q2_^HcpOzibSK7=B(Gn;k}+zB;}Nf5Pui~dLmW1@mk0K4r?H(}Os*L{U;JKhyuG}K z=BDD_?ms!&*vO!8SWHgPfK;c+_@)E}2LYZc2m83#8#N^Jl|jt9l<3SuV%pIt`jO0H zC%_!>TjY)GlL$onEjS>>15T1XQ&6R~-^inSew$wi+&|C*s-8h-0Uanbava4{BBDsd zKvdE)bo^K%vW0<{)SFT!LB0p2RNyZg`{H9F842K7v`+b*^y#uI*ifWFkrYK+VrbpD zPRJqNivdVKtPdM+1DYZ9P?RF-X-qIgJRWI@b<{Lt*e|Lj2%I~#h%JUkSEEML>B&w# zC$EkhVpTZ~dS-AS*|;%BvThR(aYyVD&@he{&Brv1tLW5e%C1){uRCg8NTMq8m;Jx1 z?9lz%6ibhl%8gxC@yjoyD&VDHuy)}yMOhSf(!!L^ObVOFTBXRT-(yIs2=0&oXW~nM zCaWe+88>h|hK;NuF+ETV4#d7kfvHn^8B}Ks+_@ZPP!8N#oTH^$) zRy9&YrmkbAtRxF8xzx@&*Y$Os+nYhe_C5DUP@(_~8s^S+2DV6_32UyMKAxUI{(xab zpUiaMFBqQvTh939h<*D56M(*aF|ecCJGOej&$&TVUfP%KZzzqWHDKYMAsof``nqVI+< zG%x_7yk2%Cvp&d28rsCbkukF-FSfV5rq>*@?=P&g-|k0%zR?{Doc0UC+XUO9BtRDX zr^5EdSU^^XGw^ki*fkI|>Pz=+Kw6Wh+Vle=@@+!P^^m7nkEOZzi&C~$?QX$O zi}FYiIEwOI?|FfwWSGXrPk})uqj-+arms9WQBR-+Wu5eI8G_H$m|>}JE>>D{{)8MD zkEUak*+@PxPwps81DT#RRt-L{a;FwhiOSl=NI19dG$es+w}_~#pHu7;&*;=gMo)1- zg6{7AAOZbs%p$$6x(^;g3fhE3YiUABn8>x%Vn|`s8?|$rzploF6)^pg!eU~@Fa;98 zZlb0snUQ{As~$14L5S6oRf#YIPCdfYFy!t@pT$rq^us>*0KFMytEB|rD_@sR@b_ zw7}7cKI8_YM2p_~b`8aVXn1gME6F~VCmBw_7+ayX~`V;W908)Kdo91k^}&A zfkmL5Ie{lG(4P{Iyy*Oy?!hTH^(Ve<;Pad}#GAEXJ8!!NjA(l@L0B#buBw6Y>q54+ zU{ZVVOdPCrU`~2aRuB-F#dU#9+aePBt1NKS-q1O5EN>R{71XZ`*)2quO3B^~i4xc@VG(Y{1|7u9@Zv}-UrWu1kbi2}5pRFXO8&osxPRbUma>Hl(g=pPaB`ysL8M$Q1SoVd{VL)x zbE_;qnxPt~9D#xadgeoO^71eCyXppYj0FvM3H5o8jP3bX>P8AH0;!9}%;X1!nV%uQ z&>mzSGPAX%7k;HBQPo62mvAMU9A~+mbaCEKa=eE4eEx3v7Ol$`NRJJI0un*+Y|9i# zN>$d1%1^e9#*Zv9bvpct;)x#!w=V#hZFW2!g5pUWi0Y}>H-hY`+1Ef2c%uovQAh0J z&2Rm?(Eps^V(^}lo8(o-rqAR?jqP`4_{{fbesDccIcA;sDX99Fddu$o-3rKVQh4zh zn#5_fqI_$pz=h(njj?#;ALmAX%k|b+>Sp{c6TwE>;xXW%_kbD+$!gAw3u&|BC|tXE z9}e?8Pj^m!yz~j9N5F(>Y*upTG-k(=KGStD4#$n*HBjVb-^&h*JjI716veg1O6uDl zRGAZSrAWvUFs6M3a@UBw6?mr#9Tp{`DxOh`pvpY;iQ{BSpP4VCO6(2NASk^x_g@vM&q%z49UT3l%}b5CWb0r~)IWu`vRTII zw-x{|LBa$T%>|9<=gjE=H@G0$P379yT&5h2okqyPFDk4XFVaetvgz^{nwe{Knl4K6 z2T&SR^LKWMg3VZCAQ&GXq`{vPl;avU=!45lzTYdfXRQ<$Y7-lvxB_C%_}N>{Ur%Ck zW}61X{w@mmXb<=hwA-d#F|sQ?**<7>5f&ye?U-pWJYOK`+I=XQ5)$5<)zoe zXAvW0RSIx@@@kI92hkt{s@H@+?a9g5_IL+>9#;T_+i9TJOv_#-0p@%E8Lq4kYNh=! zQhXeG@^hQa^=f%>^LK{4#vvV5Y<`2fTeCPMJ@J%ln1?<}G7c9^fIRfJk-+w57gxr; zy89FL?1;2NPdjr?qxfAd8zO6~c~9R56IYsX(kb8;jOg;lZt`<7CL-2yV3q}?+JqA3TuFs^e7oKo_<~;M zfCOh?Dt2U$9T1N($)>9$q&MR5#509hErzTfG!X^-C*G9;I?F9XvLB2}xRLoi6v>Tj zz&Y~pj1i^G?ij5%0fVWHq*5C3+R-&#cucSzR0~Qc;xNr^IkGkpbQfneSV|i0cGOd# z94{TT7JGJ|CAx!axT0pvOsz6Aqy?6mEv_ZknO6bek0ViMuP|mKn3z+EXlwDINV+Pt zY7}C%bO{TCCd0%s0+)*W_5u_pkpch>8jT{MwjUz#CdAly%o`LxBizF}Ce|an_u4(m)>d-o+i5DaC|Ip=wmft|{HQy7&7LTd z^YG5x>iNpd6mJpSYxDT8)*JWf z>4KGUN+PTQ4pm03vhOq02k?19^WWCZ`vy+=Xn^$-Jwpx9em}!BQ$8u+-i!t$#<(9E zB!+O_X;9!jjgpb~OcCW2dX5w26u*UvcqiT&;J(<6n{e6#BB+tDD%1HRpNIgcu%E~A zW8bFNbIJS!=D`DbJys<~hp6UlyG(cQs5muv6|w$AqQ?%Z2ygYJ@-Q>3G(MC9-ZSxG zM*ZYk6ukj`yG1FjQ<=qnhT%_;y4@`Nw6(_2*yep^vh4CZw%nm_-s6Y@rljx0}t4JJ)TqZ+%+=N`XPY=yb(Ydw%18pz#i6h}uke8=^G0Qj7GzMg#{ z1e9Vqu*tpWzfiK|n*21n=umT6>$~@N#Rjkg4HwN9ip*8Y6v`0ouzpg3Sw_0<_sE;m z!qQ9I&*b#tR&4qf-3~z4nR;&WnVyrIiFS}3QTWxKWv6xcwZqzKRmZY5XU4$Frw){N z#5fI4HG-VbjWXM4c_vRy)8u%@gZ`@2WV4Smp>c=5N0{26dnk&?dtx|L#}vLU9Pzk} zFvfq&2B6pjgblzsJ8<%Oxf!@y3lho~yzUe7+iDA}dPQk5RB{_~oW?W4#h` zDSSn$A6xLW=Z_;Cr65nk>MO7%`nOHu{}>kX?^ueZ|7-5svN8r z6b4;-%XfT#+kcRJZ_FRuT)cbBxAc-6ii8HlKl;rU=JxaVhnQN~7)d0wxN2kmPXhx( zT|-?!ePdAguV;XGN$AQynO|amYP8SSude^P|Fvs^_wVicXHUjInO2aZg~9?aa@Y5u z=EM|0z^!+@KWw_Ug!5w`6uLDELYH^-Aq zuBYq{7rdU&w>OY)8MRr#E@rEQu^SAG1>59j?rtI9=D;IUI9Ya!Co+nW<_Qv!0M{Ji z@T=iR7snsNw3*zWrr*l#Mh+&KGYu;M3x^j4FH=D^O6tm&!(le%%dLzH2lQ$V ziYnFRDMbdD3$2LjKuCs)i3_QC@J|_>FXf4<$SshyJTth!nW@?Lmw30JK1A6;~ zKV^~>=yG(Es@@s96Qf=^*9+wZ)u5dC0eeuaHNMo99&LRdAoOmKhFq291j`ko25Jou za_(BJWk31tsg=1kv9Pc*HW&_g7%@u!c-SYMyhAVKxBXqJ&Y+*J_uA2i+R~v2pJNzt zwENRE1(R1w&X6wpo+(t&UqP+m!21HPccSnlFp)2 z>Ohj)t&W~%>|_+Kah*)VYDt?LghNG0+g6F1ztP$dj%wWPkIL~@(5J5gArX)}`s#t; zNQoQX;gC9Sq(#9akx|ZIGKgae`k7dS^%J`&w7L@sSCRt@SE6nw@==Pecc?%1zeD^k z_r_O<1odyDDu3a^|6`x<8916b>p9x|Gc@58%?H^}3orC(+N6#G%;krFTFmDA9YqV` z2k=wfaJ+g#eDT?urt3F2l49_1D6rr?o{yW)1Gf$!@VQ%rXHx|8wxeOh;DRJ(x&=3? zwZ5B#R#OMV2L4M0x|Q+pimb?%KwY~iLE|FjwixEViK=Pr?XNh6K7|6`Y0pk^T#|`( z69kg?abVw$Z%o20br;nUrSZ8IA)!julTgkLyPqr{8%m69(23(z+1)bEtxwp7@K2%p zKO;=DA7rLVQOjn57MTloYrH+mN~`6ri4N2e z0uQFfRE9T=Q4vD0h^v+?!Cg-HOtD&Hy=NGR#}_ZCHtQi^@!d67-YMQ=hHJ#R`uduO z#|NNv-wBuI-c_g;f%Zjh(2DfXH+O&0#x%wq;mB_#mhiAIjRS{JRmJGKy%U4ZUtpwa zgz#ox8s2@yzj-xA)$=L7ao;+qlgJDi<|TW{Fq?l*V8_G?W4JRxBq`TePLxpZLhHs^ zr5wMY3Z!0SdIY4qK+BnNqbq&l$GmYvpCHYH8rOyBa2mer!KyiZBg2HB=J6gv<`1PS zZNv+xO3vY?i4$Skq6LQllxOE+jHQrS+;?K(Ej?*EA zy|#27U#B_YqhG4MNfrEX`A)4JRJZRRji=JKKqgVUc9bAL9WSqw zz@}UfpB>^pm^qnkV9swE&3wNU87tW(w&fxbQ&h-n(}Ca;G=n&yZ!fkzqFLWvX-?sP zkhVf~gm7UP!&l{PykrVnK4DCtb%Pt#Z*0&@av9TV0Sx?owkH6)kNWUiP=zW(>WEd6 zj>=kQzkiseAz{TT<0kbcU29Yp#Bg;OvXn8+5aKTw+(Ol1t$-)_&KNKXZbsM8g2?@X zvQau*tSg9YbkA@T(C@5Fr@dK~vY#hsZXh%te{$=gedhtTuZ{Wiw;PlA?-rwwvyt^b zm!em^h7BSgdhpI3G)RPL6Uv7CIRJdeBRW!)IKWi;6#qCuvvz7wbZgR8x>4EfbkBYl zT6!pxcB<<+-i^#NR^-lPzM9mLv2(Ud_rPSwPD@Ts&o|Y9DByn87^1)l{Wip*CGu*z z!jMh6D83L5fraLE^CUkmLs2D5i&MZ6mpBCy)URoPEz0&DISXrj+z9p^X90KQxhi z(;bXM&@#(Gi2B*#tM>bYTLua5(JuHoH6{jW=H(gqRt#?jiRSqkS#EixBn-`~Q?T>m z0Q)vPW(HsMRVlOR5u0M8aBS>*GHh>n5gp*r1$y5T{qIgsmC$9nt`8za*4!1Zeh|70 zZQMKZZ}utiUW3xCgvQmO5eeMk*i!hKZ@#@9JVQkCZ^Zo@BTa~<^j3kc)k`S;a9-tuhH>uPYNMd10!3cfYQe$FFn#<1t8 zz8=>K7PcxcAQD({X;xr*{2@?`@c_ZTV(&E<9TGywDQg0Kq&!>jlXXh;E9Wxmhec=E z=s#N*Flu+1LVy=ufbVI=6Z+mwhTC->#u5)bCwNS2k9@kwXh>)z%p|>rP)|)r@!J4i zph=l$ph4(zYOZ0D{7I}+P2$M|v}hJ$zm^QQV_g3zFowE_B0ta^L1>b`QWD=In+*HP zi8uwx@2qRO_T!pNUp2M1xZJpEdkFJA4f~w{2rV`Q#J;ovaNHa=yg~81Ui7lt_^+Rn zh3}dN$8@R&_Y9FS>bBX-@!aiF@f^Ud65zT{i_sv8-*Bk)!*nU-(a29PHIWPrs5nf4!i{{tn^(igs9k z5f0}+$j1+1(Cxzc&csZ`lgPo&hec#zP$QU}f5R}yY6(~B7dsIxrfB~gQ_%~plrgpw zGuJkc(^l43BP0qSls3?X#J~XN6@PT_RX%?uGb$oYp`{NE2ojf|cX;Sq?n7>%qo<{( z1)yV?g^Hw#gr$?b-eebm7a1XN+t2H;V(a3uC%YU zBBh8duG7*SrYBh(jE}KD&w6;?;d|W;yKV?5dFW`C@wNFW33x<`sLBYB_|~CN>}cpy z73q$K5V7xfTd{jChM-vU_J!J9)&o)sZ;ar&_xr@)y36-bXp;9*6(7qr-Nn7N6E0Rd zS)*3ESOaP*Tm^bl=;QUc=naV#_FOG#TNQXYNo3bCVv6S7skjP7=z}ZDs*D^a463RC z&$9hK@^+_x_>E@|{4U(ao-;U@dYvD$wS0q+hI72cfrhnJU)$=j>G3V`$Td*0QNbIl zkDh+-`{)(`fgwCKqzdFRuu7H>=|z;FL=lT4l(h~!P86>b>9q*saCa{(+}z$+*)b^x z5^^V(LW2`}Ttonza-aZk@nA)jwn1_&ywZ-jN?L@QYngs7sEA-mI zTT}rCSA05J!$;hJrk?w8gP-$ zQW~Qd-9u@bguk=JRZHmJ89ORHqH(KYCW*|;X=c#UJvFd_3s!0OOlP=*Vhc^SSa9T3 zt)%kjTcjq9i^VB_OYqcbY>tiTY9J^~j6qhgbgfZk6A_Z3?#QF4h&?9~lm1UY$8y*a z(nnF(MrIxNCW?DrB~OKcmK#zAuf2w3)ENe;V`nnR+2%#_R^Jvy&BYrlXh_ZnHcCkW zo?o<8NMp~2u8Xml#-pTZKzoIi%VDnJdXKULt&Y68KOIb)?!^X3pv_%T!I-f7?=gQF z$PR5_ZuhyNT${VfxHp_#4Q}R@^b=@g^a44UpkB~~>sI09O^0TSKMpNy*%4B}-timF zP~A+W&?_w5PD605#Yvux7y*@~kjxMto3~_(qSwj!4F@e!YbSQUp!D+=A2@(koU>my zs5Do5PH42bGSxzgMA2~}iNT?ztc43HXy*2>)5?-#TJ8$92B+{-DCeWX-Px;tufgUF zL~%twhx8M$ex`SCC#;#p+OhJ0URlt+26C4NVB zu;t5U&IIFIyG7O(42@?me@(c|*p@7o+1Y1+K^RtV%WA6>`siM{MEtO-Li79YbucpH zuW^gc3rJ#OTlP%nTl3h2G%K$_Ff6;!tTlWPp%%6v=GMJdSY`eZJ7~{1`RO!y*ktI9 zXc5rAp+Mh30=zGB6<|N=(o{j=?3)5*6}SROmb&kLo>7V0@N>!jZ1aoP@G~c@y;SDk zdr}HMK&HzSX3}P{Qa*A*wp>n4UcEEqnb43oZdC!vv|-)I(g14ND^G*b3~8zPDPYtn zb^HBVG)%|NFsth>0!GTa=#e*LLM3Aevu8pjeaIemn~IXvRLzww@lf_I{BCV&#`{3U z^J=1Xo_J(VS%)yre;}f&gQ%KEmTWp+GX3-nM=Lcp%=ayL)%z_?=^^_r+sGF0t%K^w>C&&dtcQ?x|d zD)CG@bZ!|!!_Fi^8O7WiAHj^nY7YTed`RA`7&iF47c1))F)ga<;(DBm-amd#sl}eiGg8wr4(asgdd9_? zfxD&H9>LKxuzBG%w3F~e!wb7UIDrLe!J+j2Nj^}6)6;v6jd$=Ay|WJ&?Xw#bEptOQ z@-^^&ExL!jWzS|B_HD}zK8IE0hQvQ!^~u?`TRu6#C;sd8AG zSv15g)uE~$0ccfZgP&XX4!xBuW)J$Z-TI)=$^DDwG}cHW`7g_=jX7W|OU7BOCk@o6 zW4K~@My=fT+6o-WdnjiqpUnKeRLe10KN;)uS@BHDgkz+YIy@3U=AmqThVI}JB+|0n z_whZKBfu4ETJ>$p2hoAYs?%=F6SC|#zGZEWm|7)RpCf9%qicm3*cam@Yd&zB3kzKh z3q0*lJRNQX-%mWH2rS1|kgU}UF7W?M@`)264{#oaOz#EAAH`FFGCABjZVNMtoU_L& z(HI|!EmN4Np}07ym|OQ5hjg+K*oD*_ujG7`uw^s3W_Jk=QEKq-Q?tYQ4h5!D+azC{ zmFg=Ih>-$5E{Mz>=c|Lv1E>xavOUi6%0_r|@5ZQG92gs;3blYbL8jB&s4|roJTSKA z)}2LuH>EPWr8K)>S&T9XqrNc1M><&URs&#{ zjjN+u-y;-5gW3g32^mWHT!~S{9?(eDOoxd%5@=L9;u$v!M5%)lyF5vzG-pvFDJ*lC z8#*!BdX2nR+x2Tsc(s1-coQ8qfkXc+^bPJ0hm1h!eu(`mjSc%hs>l8p4w-IxlZhL%4o0u7)#K0&A6?_F@!_QBK`NJZQn_HJ~MWSA*98cS9 zC!5!vJ8TX%@9%pe-_q^2V`$rz9-ayEI)LGFRiMEXAIexu^LOCz+P%=>uLbm7=VJ!Y z9|VRFc+_x}=ne;J@lf=ub}0}{1t+7!_F7f5Z}!ag9wYI{?8d>gIz@(PNx4UqY*8SB zAwx`{x3KpyMrx}HxL(m!X#~_ttk|lp+XULvj<$=JtEe{&I9%uxi`__#So>G?z<*^e zlRcO&GfkSdTt#;LE*;w#6K9!9cvwx~lm>{QBkzEouzjL+Jv$3QKa}Q}#u$Hvj(9Rr zDByGuY^4YOeL?46fJCm2#$x2MnY)nhl=-E&B0&ad zrC_GK3}Mbrd=(8<0mK7+TE)y|ThLVZS4!Os3loK!T~@knHfv8eq!>J`FfBGl-Wx+*rM>um3!FPD>s1J zi?wjC80jA>aWio(l2%mA@(+&b8j3hkPA(~0?^+rl<{K%gaFN-?uAfHQb&ILu(@jvq z#EM&6)rZKMu!v1XJGQV$GeCn5A1!=I)ue43IoG%{@{9M$uf5-`QLv$;r2I<9DpJ@Q zM6l1qOen0+>Frcpmm{EbM) zafa+waqjM(oQI!6RFGgMucW?sDC*u9kJ-oaeXec~Z1J#AQ69S0vy_*&O6 zc-#qfeiWMXS|ECM*Nf(QS_kw!;Rc?yf074d@yz+_PBBFnL2UE9Ta(n(2!`ZJ*b}r44wenYU;q* z$Eeb%6r19la0Yg~jlPBGGy(cObGRIYd%!qJ;GJ@VtZ@3^@C%0GNv-iS{rDXo=Aggv zc0{QqWaSirBS3ekr--*!DeMvX{VTz0F*Ix4`#T+>SN4QzIUI-}gX*UkuW< zI<&*yLu|jWwDo!pn0|q6>-y|V{Zh$JupajaJ+9wE zt?ck@1l~2{}=eyE0x}j>JrrD5*fW zoHsx*tQ48Iq7f5E9_5!9*6jBsT~)|~R>g?cMu_A_3^NLUvoeGl@u^lSAv>k@V7S7| z)*nr~4rXB8vHH*Q<}((_zB%fIfg_)j=VjI%wFXXWA4-r*l>_Uz)GO|emQyurvWg~aFRYC^utvr06$pC)Kqx_f4tBHAz8*p1^(P-BA55iH zxmYe9Zz`{HTvvQ;+?_-)jyS50WuXvPqnIoC&fmBfaU{vk&1_5CH04?$K`Pl}GasMu zD-j;6BCw5;+Wz~DC(AElZ;QaOPhnnsS5qNwy>C5xdLy|0(*xOm>X&E*p!L$fOqu%I zPz2#$8v9R`^qBjZ+o36AzxZ^EnNru zU6Hzj5iJu&JE339emI%Vy3{n(=+sinMI=gwHfXEWk^nvC3$!UhzhM0?r-P`+>eu7D z$m?AY%jUG1n~w9T>s<)qB+E;aEzPa6vqrb6YjM&zqaJYmw3NUtt18BW0dGA(niaUV zm?b+_k`EK)k?Nn4=p~ps(xKO0L7KJfM)EdX^j*FIS(*JVfCIP8sgG1m_iQ^0D017o z7ARFpmR4Cp89-hO(NhkU{LVHkBF-=r%V8{Gh$obr58F;X)?7$lY_3N5s;Wj9+Ei`m z(1S3DP!tn~Z|O={S{Co!LqRp^?7vRWr;Q|{u(sGzjCP`{NFKQ}D=1VRqgtZpESceR#?trBkkmACe z#fRe2?g*UGAh(+C5X6)EGMrCtmp0C3nl*xwG=-VWj7}URXtppOl~?hCCEVCmpNv(}vWaWxdfV zVi)L$GAY<|iL?6&Wp+O*gLg+s}klyC(wTCKF#)_*nG=fwW ztxYU`(6q9L7F*qUpx*WL!^LHo{|*eju#rWE65)FH5|^t?9{nJwwGba#JPW_bk(JiD zqcy+hFOdH1mrs({v^2qgW6>GXMf|lD%wjKB`xX~{_69K`gcvyRf{*EbUy;{vtPS3O ze;)*MHFKB8qCDO9j-Fs>C0N(t?5MX7*E-QgzV};vxINyv(f zTSBnUmFOYZ#NZ>jgm5V8cOFZ0SMLd&8|7jgmd}twc$bq3Ea;oy*^nLla8vUF&oy*d zul;~i%?!x;dgBnc(SXZx=f~0AX6>{6kBAkgcRu(#7WNZb@%agu#M~ILbe`syy0_Jz zBlEiO?Q)8^DrZD?WXIk13)8N?{7rywc5$tnXi;0;EoViV8Z!b@(F3_~CT|;7e1~Kp zX)yWyyoXxp#9(a6FU(sUWZI{&ixJj7{aa-p?P#DM>E{KzU~|9OZM?cny}E9kbLG>L z_hf^rp|y{gL(k0mMaq+eRtHer?Qb%^FIs!Err=%$Lrx^&hk{*=;usfo*Y%TP9ow-Z znQlo1$uVNw--Z_Jk5uOvdrug1;MUBTct@s{G>?4d$h=_|o0QtBr3abW+*fTN5TB=2 zqC0boi?m+tT`%FVMY3IvQ#iieKTqH&WJ%n8T#bPMwTFAu=hZVWEBnW-$f(#e`^Us# zk)gVsF_8^F=Sa!aO<`!+GRH0^tp@2fUM=g#__zgK=U*1-bORDy%P(hi1urd{r*Eg? zZ8=x)mK}f;g(QqngRXs`T zpV*$XO2lbSj=uhN2%f+=w8k`ocVje+LIx_9lo{9CEKSJG!jQd#C-n@&bf7)yZKd-> zXfuT6M#r6o5%TuKR~1@|rLAE%L2}G;&N9>7Jo%Y{)+w*IdukzYql)Ncewf)0!V>C( z$;BT>_eoEKPsO*n)@m1{pU^e=#`y-eU&a3f{2KV0uoKG@Wv`;o1N<7~ny3@c6UJ3y zc*Xz42W*v3-wE6^^#9FEFq9z)#0;`t=ksFj-`kC~`3t|Vl8*fje_lfN7+YOM| zqB=s8bmehh3t~6S8-70=C{N&xKpz~@o9zt|I1l0*d4Eg5mo0R=BZ%JE&$odjH-LH= zmGH`aF#S?DgnBTZ{x@Q_5jTjcWR|`gf!E(M0;y}IT7j+*xk0$4TroU@Z;*Orh~J2B z5+I&>We6^ORluM6fck&9Cf&e$Cf9;-i#&6>3cA8vAi?$;^t<>A^dqp6ast#Kb${y? zbp`SayHV(qA$oJXVF2F&@h06f@yn5VX4^eM^u~RD3Do)Ky=U~HE%-dNn*#4m@oW^R z1M3a4r{b?8^t`mY0`E=z>=dX2=MA*Svi}L_p>X#)^^X>5^4;(-sb7^|iGRy*|DqyF z*v#?|A@ZMxyj8S>^uSkN?N17;d9WD5K7TCMjNjk1PzeZ>$_1Ub+Kkg%3+rq%39E+hGMs4WOb6c<@w0`ZAHjmq^N}d zLlE>|^6){58`4N}$Xg{Url1r;kfG$EDb0WfAT$ueg^6Zm%tMkEUc?LZ$$iejk|ppw zeQ>f5T65@lv~j67yI?oFG^Z)(D{Mfjdb5)CGup2gT`S$0liM|0HiC>&E=0)r=Ud2y zSel!M`lOOA{f-%OjYS*5%cZBz6Sb2gFK)sY00r5RM$On$j+E*JRbXB`%umhU-kyEr zidGpDFj;e=ef8({OXXO13K|w?Sjq2_*+?l3k?mP18|$;>n-00PP0Es`diraTzDPM)xh0__AiRRr0>@)L_L9V8MUo22B9IkoUn~SASxRv| ziiX%9$D0{H4n5+PBVP2Q2gp5Nx$Drt4@?w zwCJX~*KJjvIj>m}E7zK%Ck6WfTw?)EhtKIV?lDDQ_!U>47Y8H@P*+&32$mZxMiSot zPOn;F6wxte47iidu00WTyOq~+8TT>fNfpheeYa+vzPz?a*8W^KP9;N`xFd^KRVgH1 zAI0Qs{k;BB!j>g?avCitca|WUj~gZ}M^kY784VsIq`2W68B9fWWveUWN*ytLn=GJe z85m41sTJ7$TmcYmr+-Q}O)ae$;DD~alc&RT^Ancy8}@Z?K(7FfEBa0vEGM96Gf+%E zZt(Gp0A4^*Z~{-K-{PT)epwvOUC}D+OB=W+D#1alT_8eNpl8th*IYP@#K+(tH!SC* zxe)E5#Eqr+hwCKmkcALlf$FE zqrJd`le{yu^|bW0w6*@K(3ZUMVSYG&CS_d_IWaQ7Ec#=||Fz9@|AWm+j%JqsMz3d~ zfTe`)4GXbWt7VMh631zrhSccqOxEe@~NSv%~4TQrpVfZU$)cu_)AD?nxez>$`X{$d8iq1YC zG8@PQrF&6*h^pL8X&7n@${`A;o@v$TFhkd1N}$4C|Auksl+Brj`}+K)Jo^d6!Ve?# z^b+iiN5>6~xhhJNS?E5en3?qC5fA~JtjJxV2rO-PKMyQvKSLseVk`Fp=sdqeNCDSz zirC;~w}s<1bGNJrBd@Lf`C5b1?LR`EMq1ZrhXcof_X1z z80+V}AEi}W zF!Bw8l?tS$*p&1{t4YLcfRp3RnKpYppt%P5#p`3&_nrF?%82NZE6txFbr>|OTn1b` z($Rogf^0+A`y7%6zc)dLZA7EFw2@6!(>Z2MCXbodjRpnV+$83aJO=k*I#ycH%Ib#d z2;v`&LWBZV=Y?iKTip?p$jJLC!H^&`TJ{>AcKBKbPn_TrLtrxVCC1el!8i7BFB}-* zq0y*l(R5EAC?aN?(L%q+Kr8N=mhNfY5UI18!qnW$U>km6RGzmh&O_JnfwjV{d%quOdYoy-?TgV()MbT&8cF zkP0718i%lQ0ej)2&ha)_oR++FJkT=D>a$^RmJ`Cj%Kb=%xemS8By==DPY3;jbc?ZhiS1RLiLGg#SuCyZH;DQ#Vo0_Ws2k_x1~tiuV2)RL;$T z#8@tj0psgpPo*4UB3WYWLxUdr*`Gn2LUr2-&9B0&h%d?WUqjbll&<~@uK$3pfB1Mw zN)|FmYUtk58XUCI`QVgPl=J1tfw$fQa%g;W@-#w72PJu2Rw5x73^>Rz*g&SG$&m=*J<9r@Aim%^&~S`!wo>Au~_v8{SrvyS&i~R zN;KyD7(j(3Gl$rK3P7hbRzsmce_%du^``nsjN5JsVo779(%P!^W@dVwYC&|?LxWU` z?WF9bo-Cf%|ETRMY`yS0iA#9I?n$Q>&O28DX+BPxR%X}Ghyiaz&3TrS61En@_ga43 zGF8N1%jqDB#e^D{&!xWpT~EuxK{Q}yGF(v1g_nqZ9gWm3t}S1jpFVNu^@3ly&ewIe zo-~`56ccdc$8{UkfzyVYpk5@)9+zp`CAwtuGy-XX%n@&aDZ)YPtJ|NKszCldn@Z?c z;b&-(koB$%hn|w~!9B@~Y}f;aC2AaO^hxp(eCA85lc(~59(rjd7u{AB8;`w-(Pj~Y zGp80*z=%2RV##+2ujU%-1W|9ezMn-{vk(^+?D0!CB*$sD@JTkf9Z?s zPQaC%GdzW*`S}N(w-U@Yk?sRuqt!OsBDDb9^T4pUc!I0~ZdnLW*H%HyqK3B)w^g-# zTo`eE%}lj#srts>TMDe_cN~~tB{Sx}RVIIWI>WS4Gi{tPxUsc$_*-(U6gBZ@qeB%# zb?HPKk8bzEZ7&R!$W@i{k#a?=JC!GhIUq+e6MPRJwcKoJCP!n`HNP+WMX&Vyk5ZX< z8l@i?N4Vn5W%ygPwZ0En^bi;O3{^=?7sm_c=(=$3Vj38&G0NjF|BthGjLx)Mw}ev_ z+qSKWok}XUZQIEc+h)bKZQHhOqvGVte$VdH-KY1vyT3EWeg9qKS!=9kt$ELDUUM>C zAW;o#U=Tgvt6!3Vhh0s-@Qp7$_qbG}-T7~Ie&$}#DQTcjcMcQqbDgafo1wGDUd<|w z@GO@b2_?1%S2>VUm+tdg&eY~c+6O!37tMe4e1@2CyHDcjF!V}fcI6&r(R|Rmy+y)& z%veR%KEX96{!D^(W|9Yc9ln@d_pII7BQ%_@0@ouB{xMzcDPxQ+AO9{vJ^@;ZP|6uxm4L-!Io%Jlu3>93h9rXbJRb?r!C4>AEg=cQV zOFdr^ih^nz{Q_+TUw0t5R7@;Szb2H77v`e6+}dU0GHEyZhR>9UaORhe$E^tB)ws1d zZP|{|;U?G7y2Itf8}Iuc;BK;0P(wTFXc+6UJ!v!-=xICp@CTYwm;(MMR+rXZc*`lz z1-J3;Moi<>OzePl*tT`du=}dcgWI_a8JHB$HORmzS?jL7;C07li{FVEr?W7%vSyiVy>Yn1?2oO4KT71nsLc09}@ z!>rrp;$U#+Zdn`mP9ry8qqJ9E{E*nAE;fxzLYH%|qde@}JaQ498^Zk9kwjJqnxMfz z8d5ki&qG>7-bfcFoeEMba*-J0`s{%&gm~)FG1!6PNb}ltzT&_rwtII!O#~MX*L5i| zT79?%B4gW@5VZshkY91+#^lK^fMgCr7+uNt0B;?AhrSg1Lv-iW=sdc)!Xmgh9h zyE?4IFd=+uNG%Fo4o!!=W|H%X^xPVb5sBamcCV@9?}!)3b) zge$^_^<27W*_=`H{=V;M-%x2|;S^#OB`Gt?YNWI5J;jf_{3ab{U4L?N<=@GlU?5)c zasG&_GgIscI#8X-*T|h6RLSR!Hu_Qeq})I!?9RN73+aa&DiqO^n~gW z_vH*Z-&^`dB&-WTZ_wdj9!B0-X=mxK9bqZvPeZQEkWtQs6xT|5cT7_NQSZ15FdQ@Ihqhj|dlhN2(6xLq_6@N&XcW@HFAA>N@!ld692c&o|uq z4^X^$=hby}lg0b;fD7c=eBz7Vs%gw^D$*V_U9Jfu*0$f9jtvQ~8R8!EYc#MPoGZp| zuXeo-Z$HK*hu~_mt%e{p+*;Fa2NT|7Sd?%|ypVqEfEuaew8x?Out&viBk%~corA~1 zG}OV3)g)iRq>mh=pVD`A$C2vylKiuSdTut?rj_?63o1S2x1-_b(3`pV?~$<*UrGjX z(-Oe3B(FvOZuB)Xw>oD9E>FQF4)09~E%vJdO2;n_SxmIYDjM_|US^PTOyd-1Lq|WFEBi{Q#(l>l8!aOOqqDQl`XeqqhelqVlR)za01_4O@k+ zJl&JpCugqA&HZLgDs>uWm^5!$k;h$bGxTtwkxkU*L|?WLW1d}1yb<747@kAdl1LRI zDQ>djA`7xGWGpoqw{5ZYXFsWNf^}!LfGA?6y0&q+>|LU`lx&TOJSB%!E0}mp)X!?K z+@**rVGrrEcl{{@0j}tQ^s311_tSS$+_X2sQd0uPXfH57bM&{B2_SO5J&8ddx1jKB zI0e&b=Zvb;*GB$vaU=;#$1tOOYcfHKYqrPC&!*+NHcW+qs`_g0J}GQ!5BkShc#0z{ zJ!!jmgpssl_SIfUaYA&Mje+6-retYyuPZ8IL~A$YBd50G4lL?cY-5v6dEcJ;WQcM; zhL{_ zY+i1+ABdNDi%}qpg*GuJfwpBOBWa()ZsZCYWJwo(c`FDB!KM$;mN%~qJWNCPF4AIFtOw4AilL24 zi>vBCcwWJYJr{{7&u$xvKeB1O6{mXFqB^V!G`;Q)82~BEWi*9L+lS?Uw#mvq+h~Ta zYH)0FV7Elb!;-tRV~BCQ zSH-eJd1_&e)6Q?hJa}p`C_bN(`^eq+VW)lJiKl0)#~u3Bzbnv%`I?%7=dE(IAjFLW z1RMK1oy$~8@BF-cMp_+H^VhCdje`o zG}}&fmE|zRhH>O&?p&MljJ&j%no1cB1S3c=yR^56EV*;;iHgLvheWB)jEdU{jU>-{8gfH29Ao{2iQie3t>@Kr zF1z0|34XV~vC9}vV~a2BBneA0&U{E+0k4gd%F7C+;+d3g1_#v&!Fo7%irVQA(X4G# zQniK@(F!5nh30~zY@)@ijLc{J?LGoyC0=HblrI#jd$Ek6^sF4+0ythtfKq^zRs?Ic+As+;X-kwST4zC z0^(bJJ4U*)X5>chrn?8p)^+ird89ag$fNg>uSvQohnS}~b|0vgp?Q40NxydE^#Nu- z4kp_K)(;7tvIEup>6bIV(^!ewvF_|RwvN0p+P#V?u1-5=$1-=Z5CQY(`E0+qNUiVy zGhk+2eR^pOW~1ap z?>}!oz|pr0x3Qm*G7r?`0<98M3r8(%%luvFthaCdygn1;MW1gSA;mpF+B z9xYD03CjSqhT_xB;lFPQ?^46a8} zpJk&wL)@b%Yv|5!01+Vu2HHGk>K@X&GSQB$N&p)mER7BnR!M0p#wIOA%ua*)8tu5| zhjWC@66iasgS{z&7nQl}ShZs&l57ncd`YnYOJ8bWOmDSYYB&XC@_YoX^AF-|YwXCI z`ZT7}WGPjNAo&K&Q6~pgrh5QDy{51_j09{To0>geA0o&nU0$zOzc?MSjQ=bmp4Fmq zOu>xpTwSj;ry4C2ENu;XO*34hkP$7j>RvH_z${p=%yv7>fr%=JQ9ym67-JyW4_&bx zA})ZXnBDKUBF?}VRii$(VBaV8z1W{a%IFl~+9YX*c&PkJbL#`8sg+TOHSV!?i*1B~ zSNglzl|eSr+BS{DSlKq7#m&zuGF>Ug zJj&AwZSy6$7m_yarhHOX6w14s4s&wU2soL&(dWSHHfP`#rG{Ue7Q{_WQ;46{$hDcD zWL}&x2X|#~1Gg9~(I($M!4H1?o{xp)ab$1(z?>9|y$mUOPJ&jaKw)At_YPLwSz-`S5^ z(mjec`B%vO3@0_3i*gS565eq8Rns_uS*LPnF*OiuPbd8Z|ITa=teo@(ko^z08aqoI zR5hA2F8{doVD*~plq-;=`QNltM2gnLHCpBqQTvyQg?KGumA+3E8t?>AtM z2So?X>@P=*MpnQ^C^~`^s0pPzCu5Gsxo}Le$>$-QC$prxc8%0WjXkR1&f>jV5lixm zjBA=9N8*k$kF6P&V^~!4#vSwL-K7VV&xp*6iuliRU5lB3Hc8c1!;U=GqM}jf1M>Jt zek*~!tF13>6$7O6+OmyB|A3*M=%P`JDcLzPj7u^ITIXgV=<&s~c4Y^?hgF=j%^tbj*YH(GzlXBFLX*8>n>k|} z-~}!5Xs6$ZvR}p8&E##D4n?PB5_#-U4yt6%rW-?o6q5=7;sB3ONks{*O0wpN)+h<5 zebk_B_L_YP`4s_1&0(}09cwqn(ju5ux!|<*MY<97Rs|_pyVE*d({8y6zrGwAmDI{# zbi=->ox4++I3|0S_B9@rXMX(U>?(>LVo>o_Ml$^GsOkRcFY>>XP$T6xtdV}Ad<1Fn z+t#4`DpS%ZZ-6#yh0nezoHmA)2Tlmzq&-WJZaYt10aeKAR$;smK*mO<_W;5l2xiE{ z?2aj%(LR5Eo}6--OnHBPeT4_&s=gE5vx6gJO#s9V7^BHxhB5x`g?`Z-B!Yt900VX( zkzJ1LWxwgozXCPL^vZgEYDIdZV%jI+JB$nFHCeV4vOoTHBg;NCi+$q~%k9vrDIGAy zbysf!V{HGCG@CLObH)6)VO_Oi#tM@f&bSV6nznshFUcZ0?EAw#WOYS7Z8*%0o+GNw zFmL&&p5MSbb17^S;#@*1u!$E9runD+C%T`XqNO(LS@WlSFewYRCdK+m#@-*)O zp$r|<56hJXi%nvQ2OdwPzRHq3$Gn>R=S*1#8v3}4bT{NF0Z)u+~ZrY%R&xm1J zIj2c>MBltv{~pRmRO=>3lIz|aCeRbb;#vIILJ5;<0Ufk^s#C@oL9v-QE&1{ME4|Qr zZfz28*B<&<9qntIK7uwsE|M!G`(Md!Gy0yd*s7kd-%DOjK_lon-G%OwNv2Fwfm|a( zX!A3>U+Uo=YoJWavRxAj$RuOmf#6NJ;mlAamb!=@o^9?Tz^0r8Em9dQhOZ$kR8X+9 z=uo|zYXMp&N}qqx5jDVqGbdlgcdP$SkLW-5j__AZmyNyae-PUh(f`n5A_#ZQm@=zF zWOhrZoqwBEQ-$>NTdh26Egz&QPYY40y9UA&U+0IqDRM~lwK<$HxQsr7<&TgKaSjPV zpgcjFMN=2;HD_m0W^|BGy`bS6t*ZfNovgE>inqxNOP45+nY1sGN{T3S*S1Z%m8@AY zrVo^W*x+_Yt@tE-xsOQt$O#;&h(XS9lj+(e(_}ZGw-ZAE>jGUM%6ar^7bBRLRi-7F zM+E9*o4$u6q;aUv{0FK^6w2QJhdYJdzttlAP5<@3wCQn*?)b-A1eh2|GW)4Q{L#;m zy8K2XROTbp{Sjf&j)C0#_GFF5>jO`!ol8k;tY*yToV@gU1F~(fufMH-+)Eq*z1R>2 zaEMhKC-2qA+~-7dMWnV{yd8Yh{1T%SG_sf+xH%C3^t4YxT&RqC?_J;&?hB;~30TV^bY#_{eY)1Jo>(3dDu5mwVuRbuk|#VQV2-UnanYB%v?=f|U7O>mNm5 zli&Gz|DGNF8(Qk0lmD-@RHTZ9t)dFQ zKlNbpahy^-xLj^}A_x@5w;a8Fe%^WWO|HDXOitMVA9t^P1IZaPqVky#RYXWl3MVup z_hdg1`SF!p^esQ;4|I`D90h7OC;6FZ#lxp=oS9+;%y>LK(QRk!t^q$Ih0V##j_*C{@)*m8918U^&S)H( z67{tun9MTunZ7?f9vS5fFRF;Xy(BFzq;@A}AS?r>MmpE$6RdC7_t@JBE3zmluck=i zTPsph=qR)YLXq&lEav7oXj8Oe>vlrp_p6B=Ovt1+H_9dn=h!QZitaqOtz)0HT!ISk z-&*+N^Ja$GiTXG!$V?c~v?NxfNKBjTXvqpKwkKg&XjGSLX9bu&n|y;< zCOx0179x%9jWzjnhv_QXicq=oo5QrZbM?uc#}158GnR99=avig>D@pYljM<&jFHuA zrzH2~-BzhyChxIM)M(8lS&xD%IV@D>gR4papgKht3*of1+PYaN`6gkN7iP*gRN8kt zPN?XN6xA2;<4IxuPv6G|$P#vKszVAh8ETWPp&UJsU<)qg>>&NAgc%F>fk}ib%i)@_rqdqAqb`cBl=1od^9j0qc&! zvU0ygD4$|bl?YFxfe4}v;ih^}aHz=WHS6w$5deI0jIl;f8pZ8^W0F`|{yM9P_1*bXL(dL(U;LdFzeZa|Gf``b9}VzV*n&jwAC>sKkdXdo7I1 z@;h8YH2^%*cJD_!DY4VF?S$<`LF#+)pc$A|5+)2PY)}}O;BsHK=G)#r7g%(>M(gyn zEvPTpm1Z9|)mNH8`C?Z@*kdoOW42)<8q|`>6Y`!KRhq$KW}VdHff9-o>v9l)Z={Xf zCPb#S7oX9V=lIg@F^JEn$d0i+pj-CU%BWTYl5#6HA!auf-8+fexiL7Q(qJP~_l`SN zAXE2%o7EnAJTEAXGa9HV3{|V9L_Yrd}!; z9kVNG86A;Z+65+74$hu*E5@yf*e4_S)FPu6C%r_>Va|qtkZTy@;f@i}azc!q9Cs+Cv`uh1%)8qIJUH zZ>Vn&y@)@2x5B)41^--$(1Ci}vg|}VOGHnnwtwfH$_EtB1oP@^pE?k%j7}bG=g#xq z*Ug|V8Ji52YBi*feUnxhF4zS!gPMBw;Ba6&gK^W?M~Bev`7`_q0T<*ARuH+Bu8Af~ zOYfUXeND-h-Hg6bFuo6dLw|ozMKiet$a(Kzf2FD#r2wBXLN8{BvtkbzGSwJ%nY__k zx%s*J;NkNwEu^0=v#N4R-unb#}sA~Ra0_U4w+SVT$5Hqi>ah_HA;V~5o6L%;F&*xmX^ju=cVF6Wr zc{HPLnt?+d02Lt&R(D5W|IO-v$bmQ%tA(*31o$4}#y)a&InrK;Fz0|@CMyN&N;D$q zcqVPPCO|q3g3dJoZ>YOZ^+TbQ7>yTJyUJ4+Z@Xd3&c6rHXihI_PfzNh;o2BR#dkh_ z=tUE^qYhnzwB%nSW)9~s?YH&OXJDA*U@NzS>n9`P2T?^a?8eqUW)~jI!Dgk9mt0cz z+QVcP<{&@C8BiGWiADH~V)xCaz85C(xG4Q_$1xG&4mH0~Oo^1A|G7GigRPy(6A7tr zr!lnu`IqEV1FZ@f=}Sdn{of(4{tu+_cjT3{i?eZ?R(685-cMVh{tsESpVadFX5ZTW z*$3+Qc=^MKvu*sV5A^x&s}J-olnlcQ1wUe8*q^Lf$sB|zwCzu? zc{!WZ2*Ep^;eM6waOu){mEQ9EljD`rr+|G|1Vaid*9#@51j8j)4K9tj-gLPo!r(wM`y(3tJUtnLcYlm4ZG3h+4SEPA)y90UhkdNP1GX$>H z*>->spS6b-5CoDlkJy-#hTH2Lk-^fmo`wZfT)SN^VNI)$H<+e1U!!#}@pjmX&HyThew(`6&TK zWJxo@xG5veOzO!6+8@>vaS98u0gR~0Y=G9X;(7;IR%1D-5jim>x!EtI#!c!Mg+HC5 zZPl+4$;&^W${3AOi4Jcgd;$0Dz{xr(Lnk4sgRJX4!^ut^zw!#kpNuzFhGg^FYkzrr z9pFnOF+3hJLI_ExRzEdf*EHzgsH9lX<(6oSh_+c^E5~&`_xtQLbDIzd+pIDNID~^F zYhmf0HQT~y+-lJvL5}ceAK=(NMdRF`KWYH34xu(3#^2Xq=qYqrob9MRViWab25+gDCPSEyV zOgZkpIAm%I8TkH%m zP}RmSaeC|5gRxq+Qy$rk7n3GNh#X-$%@2a!SoO&aydbeUA_DKBJ}0yXpg6-4@39uA z8JXuG>u1Cqr_Yv!YzTylY<)I+9hd{qk8yDdTxY08JQ;t{ydNZB+kXHDV5g4mNeBSqB$f2GU)S@ zCZJzxoAb(~sW}5_L0JS#$%`r7Ym=u+NAo097uR4XGjUvxSJyJ<^3+w6hn~I0)zgI- zJ^fA`qs}h4jps~MySeA5k3yzN7Z0JCr+=%;Y*q7a<;HjRNw@m3d%}lT5=rst#(4GL z-6IDbo22LHTqC}RLEmF{=5F1vy!%q$t4P;@ynX5KxX0VwNyhTTwP-0=aDPLKJME_U zX>ri)A}%WTSZa2+rf*IF7>n}4OlG3MHs=_IS6OezhwPrJbWC|xC~Mt4;!0`I+WAI( zs2)$Q>~IgUFRCLs%0xc@@`YTGq_e2`zY?oA3QVM0G*s}H9)v`z+V}8aUk7x=TStTtXI)c3mE+XOq~MG- zpYl#SbBqMpKOqZcXLf70i*O@cjZt|obQiK9K_L2~eISa30Y zV4V`P_c>^!tRkRq;ak8T?~~O_`9eF0fG`fO!=-epoG`8KV&J7yJagqUQ`Lg03gQ5=`V|QBJ=E*Rk38QA>HQ2)I~FLo?i_?V4SsZVuekR&-YxtkY#+=Z z$QMYk0N;b^9UkbTAjo*f)_eU#`f>&LnJ$k%_KF%w@l0<&CL#O$`qba>C2TbjI%f}l zX4O;qkIgqR^*n2i8S!o)x*5?~Y9XpZOw{99c~S4NUEAtZkee{=-7-@8tPk#%cfBwYg<`w0%D!_pSYHR=?;kTebh9!q4~@)@tc) z7++p#t@jQ{ce4-g@wM{t5*U~$HOW4uk&&^!vA&QYDVY2|vA&?9KNzdO|3&-VCW~wY ze@&w6>-~GWhu~jNQ`yMg;Xkc60+lpmafVQNCMM6}&VCAD`??N>i0Z4w#27^wfhfY4;|NugqF^9AU31?s z2sx5^91KB)0sR-Hqx7M_sIISrFiFqL<8penFyEdTUbG}<&@Ar715^dj%C zP-by@llpu{n`08_0kj6A3fhvC&_>1~*71Hhd5kl@4X#x#UhYxZMUxaW5vB}C+LReg zMV^Lz&5Y@bdc71FC&n@9dbN{)8CDw$%J(oM9rHWqk@&7L2H2wDWLst|t4!UPmvRpK zIws@fml8>H<))#AmHf$ARXbXaoE0z~cYzT#hFKV;^%uGPbseGR=5~?`hWS=^%pp-X z_q|2Z4d%)dR$l{0egoe@N(&lfonx6($_>XCmED)PJz+%E$)GYCg~LPUU>Z+7FBm3@ z#(ZnCbkNa>IOC!RO=~z*|36)K1tg9p!xcEs(Qei-T997qF53@qKSqH@DCrb?bd(ymyL|A1FY*9+DQ6JQ(Ha29uH zW(sTB`D}o~Ox>ShOnLyb`G5kkMui4d90S^vv%>*~nR>)K#&dRG``viO4a2#WO5kUlkkrad)@=0qhYTZ&QXLAUVJQrkFk$62`>c zasf!q@vwL=VY|!aouRta4Gte4%!@PQ)h{UQ+zr{4*92W)!sY1+uLvp0J7E3&&FPD% zeUBMvOK8s@u$1BpVC5qJc=9uT{E8gIvAWC~VH@Z0Gy-g*{(25H#HO5`OG%w_9lJzW+=2VlTVTodFJt2X}O^ivr z!Nti@hB!~3!WfF)(?`xPF4Rd?y9>Ny=Kg#ErswYgib6oQL%k`t?c;#+fs7KQK*Ryx zK^Adz6DgmKlKd$&Z=i#ifTVu)^KSUKA##@#WKWFy6VIo z^jq`{ReTZlysr%9!y+Lw?YI})F|R%JXM3PsyA-7-c%35~h9isSpu6F-*6kZ^?MsNW zikLk#{;vBk8v|JUJ&~tQ(HDvgc@d#w0k#ZRf6hYiDMS&manxO8Zu-^fX#9}4gqVq; zToT@17m0*lL<#tzal`d8E=@}u-h{Z?l`X?ZG1l&(FLA@;M=^DN8=2i%sEPo;ZZN7g zj}4~=zW&YWJx$pr-%?n`-{r2UESh)5kZpHaT}Nw|3>}o+xaL7wy69eERBsXL7e~yF zUD?TtC3=^Ly)ukJQ^kl^gi)}ukzl>6Qm`vW4QuJY{qqc6HJJ@4U+j9rFLINSbY%j- zb`|C;MObBB;zSQ}@~PgGfMm6TiFW3v znOlK3_1b|vWDY~y(;SY`d%I9E#_)`TOyvw*%Wn9>u;9^H{@Ad5n8@wLhoCaTmD@0W zsL1W*q~Cz&PmD3#0?9~P<@yG9`tsy#gJHRnfO1dlWWsuo9zKlI4%41xDnXkWE|^xu z&foG2ya^lf{z?vTCd>1u{H|EwUJXtqurxvWxP>r>g%BuLOd1fLn)4sH)kXc%wBezo(!lkW=TpCsAVo(eCs}Jr;I4s!e_y8th z_TZdaM8#UU`D(`b8pv~#c*VLpQ=_9|kIy$A*%l+-gDB%=-V=a4i4o_x$g}3E0?J8tGYo*~=K3{ZDY4C_nb)p^U=A7G-doP2bHO z=1M;cve4aF46Uvt00mz{5$<@vF36d<7y4GL-XB+`I}#+tCQ1Mj?gf<9D+1&~rtF6h zqP)m`+2SzS;=r@z<-r419md77d|gVhr;dxN>0;a0BL&_BvA{fR_#z+n&DSkpR1kB_ zGDFt-k8*3fWw9^8xQii8=3!o^s5Z!ZNNhnAlz%ZciTn_#>ZG%gc=MLr$h69d>`RI0 zA0vu4*#Z9=QQ;n45`)iJ`B;cuSTG|prFP-svHKSBx|%R2N@a%vlj;jKSEUr*k-E?s zV}~PeJf@pT?P~ldS2AL6g&-`bxIPvu{^8ab~kfNxceKG<#qH? zO?LPWy1`v>?x1Lfiw4CF_`G`7&x!*X3eWB00I(^CY5-pCARQCQr2W3Mw1YJs16PH( zuy@ULyM?}TO;n*es{b$HJjM|;to&C6hIc=+Cf?k8a@RNPmCU%QjBeJ~;EQL!6ejh< zg}TL#KQ~;>R#!dfssT-3E^2IO9iPt~+{jK+@bFKY!Iqy;=zy+>rNR6G0a8ulah8p{ z!i-y6#NU#Tct=&&l=?}F?Js{Ba;rzx*FAoH2aNyQ+Bon3!_IQDHncR7v@!VWqv=04 z7zyKll*}{aH6(BtQ9f!bqqw-VOO?+y(D0Q(!Fz(`E2ilndUJcju2xdmg-w`9hf18M_koF-^4XQqBF|kwIVAD{iPt`^UhkcM6(Kxi0_mov$fw*(=EtMyPo6st9BR;1^b(z4L$i`$=Jx^_h$@@1;&po_E z4HuJu{0UHJMsfSracp8{_6y8-JtPIv#l||?MO>;b#%|lW;D-%8(5WWzawuL-j!5`P z3BGtC%Ke}C$6|F`$TKX-!inG3QK!lzZ;NTD7jDFRFVwCc}z zc`W<}eP~k+b;zW~S$WIwUe=XD=(LUM6~)qB@LpFz_&90A+3n(8}5Bz>6!t)_f2zXt^9$$h%ffzekge)ZnJOKpc zpORrWF~^z6=~L9~I0CqZ0;0ru{P6mm0k5&J`eY!$BB(eDx?r);J9Mgq>yiFY=LlFa z@Vm_z8A=r06+(!0x$ZxUGa&S6r9-Tx9qFk6Vm)I>r*6SuE=9r$g8soGL&2{k0pL;Q zb?UQUX{7f3PB7GKq_p2_gpCa+?HiCi$!Fa$UbIZ z{F5Y1+jwLsi#S&N0-WL(2&$;BXmKe0agtdjRa~rfCA*qLTV$mj=9v1TGKx+`)f{G6 z#`p0m81|q@0t~pmycS)=t_P3}nENvrhdbUsagJLC^Alr>=b+7KyLwk&_dcDdc&WYak<+g~%(AVM|Th zeLJjrVIXnu8>Iki$~TP{ST<|c1Qpx)VJg?9VN2Jo0f%M01(FI==EhC&w1{m7G?OLl^sQAlkzqDB88IpJHV^#Cl%<3kGP@(daA+2?2@Vb?q7|`n#Mjv%a|07MFic6-hFS)l0ss^Hyna z7gsbn9*((+wFCi9$;y5%X^+N9v9)OjM5b}mf@Uan+aASjoYZSmAP_Fqr2L_QHXp=u zj!;t$EH9?GKo$H=T1n?z)Df2SL@$b@zi@gvdk$0=f?a^C)0k&Pc0+XL&{=#$S~G%E0K3-@hdM#1p^QLzAg-D`1H3c!HE6 z78~J_6}9R02S9lF!s8XP0_vQ(N8hooi63|e-@&$J9sGvjdItB_e->7fIqHEMS@feS z2&ZAG_Hw*HD&Ns-^9R%rMs*Vm1a(X-{6Nmk&e2aS=t8ReChwo0@o-^Exzm{uc^j&Q z?fvL7O4~VDysp}7tP|W-LyQ1v`Swj+F$!drDBI}ABf(|(l3>-Wtt7@kbytOFMmv?xXjvaBQ5_Td$=+l~vTM`>}Fgm?!k1%~nMDkG54xe7~$~(kh^;up^cOQ7&y!z`Q zzeAn6&{GLztdm(G(@E*ge766}n@c5eNaOp8v?=_;=YM}u3H`rbR0?J$U#WBd6SDl* zoa_Q64TUvfln+)`Q3@g-LF@g)d}*j}=d1-yG1xIN?B9ZS6BeggQD;|`V@O>{xr|=G zZ`X^Y$>)~ZSw~>>M(a;Bj9>CNd8jcN21zoUxfd_-Jdgfl)QNb%zpvo~%>wdwU@D87 zOLwp;sgq?HO9-PVLD`ronu+k)lq4nAX<>PqD+tPV+x@t-n!_#!;~T$_vZrN5fh z7^(=Wb|4Cw(+53avkZO?phI=e+X`UO>dN)VqvLkUUpM&KV7QeAwdf~2rC*n7f|S98 zrUVOb46_GmjP3*LwH4R}T~bax0QbS7!4wT*-Xp<_8m{vMar&X-T7#vi;U(~d zJ95#lRpM$Ig}}nmGV~X5htu4TFVjseP>pG>vnAou;kp;@&|vf?9R)GqC0J$s98)fx zw3@1ECOA@CI?x|w^vIfP3&oU4_>rko%fyTBw6>2KFOcU*6{J+NF>W}~fRouIA#cHS zJl`l3#zDDf?_i*>w`SkjLKZ&OKhG zKw%_k+iL<6W0E5fK>2=(}h+h-vuFm+c(Nak0IS0j#6?5j9!=$Vh8czgbhnv8CxsCv4h~`j=xpM zn0kXa=oLqzPX5FmrQ8nkQmKk3Lk<2zd(snePrKsrcXS-5QwyiPE@4a=mLx#db> z+4mZUJpDMSX+x^tlK7lQ!>WBET{y1O!h|0k@|D5IB_{Ws<7M+QZ%b}vzCL;;lZ>dN zg}(^i)TrKB69D;#CID_uArEzU7W^4b*tAH5AYzwC9dmPNU>GQ^=*kg%#7pd4L&Vbf ziKUedfu4j@JNIq@ETLDTxXn5*L_nj6Dhk zX-IITDnW+NC`p)YP;Q6{j_pTB0Puaf5c#FtqC!7~ye^ssL1G(5zVSYJPU^>y;# zO*F+GqNIJaW&P{=T2Z8BjYZ@-9R<=m$M5x21V2FYtcGf5H_jPowJ2Ue0v`nhmx zG-aWvU_mh}G&7d+_v5v0$lcq0PU-j1IrSL^@E-vWDqGNv9{unUD{xW2A=8J9T8rzPvF5xm)Rf*JOx7J9F zP18M2W{u3P!1@zb`kTE^SAFWD10@ob#99H+bBqR0yHrYN6D$K^DqXr@#mbFl+v31nN z(5<9WWy5Wbk=$fv^1ht8g2?@07xO#^i;303i$Y`5KUP6W{I-GBe+q?{&&XGb*-@A5 zbLA{{TO+ka11t|>5G6CZ|{c14` zaS;YDDA#hqighyIX|Rb5euH=XO4a9Qy&o-2lg1bABovPxg!Vg;-%V_)0&hgzib=6XV^=}W%5@)tL36W ztq;c_lf!shEyb?$6Wpe2MO!JeD{hmS+<$Lkn}FGQ$!rjbGMkrJL)nictEpgtd^AJz z@6;X@e(wpsLG;2Hz}CG@J{rghu!XcidPnQe0{6u#4YWr834_e@ zy;@A5Ei~=1F*1QLamO_v3b>xU!R`11*5A+7Cu*OUvqQ@$9g~M<&k|Gn z+bi&q>e<$@bR*1A{ADZvljk%0(ay3wqBCzf`HqX<+kU)9hutqgBZT-T8(K}}u9BOM zlk(54JRcBR<)1dX-8loNy%a56QPOT+aG*Nb=sHNB)Z#-+0UtpzTVKi=#1HrK9q`#( z;>8J(F5L){qY;0j`q>H^Nk}!~3PR1oCa0qdsE(3+u7I+8;gO!T=0g(tXcyZI zc{U%?_V7oD3nX%N(v*PQEAEPlzE{A7OA%VHn%xR8o?NE4Qv@|C0-5bx$t3MMS%548 zvBUQ>+z;e)yL%v7u~Hv*{0fn%h_rl7r3x!JlfIedGexZ)l1-OpZAm%4Y;`;IOZF)< z@!0DiI_r53-r@hCKcv66#LavioN52I#fa|zesKOLlKhXuGE#0#`a2^Ej}aIK-gjO^ zd}=m-=vG@uM!6VNULsMV%AlOMI6ZM=FeJXQW`>!5`0KogCSpBmt#$WHt1Awki^r)U zbRVp!x#bBzJ$iqV(J$*gIk7#Tp7RYpO~!O*MTSEv90|NIT|%uMt%GP|qGZmzl6%*9 zDonA1CCs>saOvMc_CMMc^q3VoF&HtNoe&;drAhisO58CqwWt2S*1iI&%IEp}5)zWq z-QB4m(%mT{-AH$dg3^+bk_Ig(0)jMxf`~LqcOxOKfW-S?aWB6s;P?Hn$8)ad_b2%!)!SM;jc$?Qsy%nB2kcW@+QDr zP4=Nz$G@1io?>=f#;vkoP3|*Bi+Y(4l^-XdNl4tw=C|x_sYUt zdvXG;%HO*mb+|^D5)yNMjF@>iEA;(Y^|yiVb202bUMRH)Rk#u)jm(AUqbuSM_8yZz z1qJ%9yg@SLL&E6t4udyDxZqDYn=YCnLU*SS#KPac6NQpS)aZA`M=ipppRdSq?*=l( zawBjeZ*|fI(^V}WeX@ujyY{;0+;!whe*T>-^3muR`{tRHPu@azX5kXbv~-QsJJ<}uqlQlZ)o?Ba@yz%rU_67 zAbF)Jy5!Q~!;1yRbUD96eKx~2?s;F3%Z98m(+MM;Rwb@}En^!Cc!| zl+B0|;dceem;4(26c_;o7uW;ui*So`8^{OC4pS9ax$UV4#qg)_vi26pi)IFJ-6K-S zuA6xEsqFe=^A;D9`5O%HDk*uL-H~)0H6A-^T1(TJWNe~}$C7iid?RaZ4lhg*&{t}7 zUx_9kMH@G(qAF}Iqxr;rO|396NWXI*D}YIfG&Pctq$<-YnRZ|2!pI}w*|wY7#}du{gxtq9&SxCm6| zy2umQ5&jSp-OvEZt5BI@^*|#46J544LZ))09^+}@XnZ&==~_B}6nlrZYQmJxn0X9! z#d8*#Cy9bhgx?q~%b#ZJ${yVRyb+d=KR&e)`%J$xqlMV#?&Ijj9n9?<{u#o=D7#lV z+(b*vF^*y z_niVh^()e#VoK_G`h*dAxL#0j!>F_*%PQyYJ;p6T^4fKw;w@5^Dr9^6lI6?0uf48W z-i%$6+v@ug7)ZlZh{zjeE%?<)kW8A{o#_0{Ror42D;h^6-e?&noQT$QB)H49kst~s zS&~dJ!tEf9Wc5TZjzg-vKE=58DZRbU8Bbw{XI?PW6@1{%UE^SV&&qyRpu+9#2yhl?c?ZelkFa4K6UUy4Jccv_$%&J!9EkTyD022 zOfQfy^s!MKRaq=}^BR*UF6d$jEAwrrWH7Ss(5qbg1A^GkWX6TC7vs!7?dh)V;PPA%qI3cPr zw5S>`jJ6 zk?EhL9CXn7$1P(QCB|YsB;9PdkyGQXE>;qI^*r5`uzHJu60FCH{xG*>3EX8v&uc`* z8;y%gz!#`$7{_ScS)%f1Q`OFwAmL&}CK2Q_=G(&vR=Ehi}?yOMK7dn&1#ttY)AfzZ0-K zu+6&`nzw60j`59IOq!=((dcT`Wu|T6fXvnTtTzl=LsuhwtiRst4`E7L=cqCk6r+-h zNh(mMDKOxfyx%8cU|-J}?=Q5BOw4C1%j<(z8{Y!XWv^h~HXM zimxGT64Ui2N`zqsu0R?0tdRX@sg*LXc8#Np04 zLSuToU_C7+HM3l!%hA5 z&-At-z=aaU6EBnq|ATL8WOHuh2EV;}ebz$e$ zQaRSGRsu9{l9lR__r0ZWct82b(sREuEH-4yR=3FbV1jngDMIi0RwRCmf%KVFZVJm> zK(3sT)>vTUjV>%*X|hRWJ&fBU3C>2(E%?(zK@*)9Qnu}}n{r<~8;gtja_?QnNXez{ zxbX=!Jl`>%Bw_UKz`9oHJ@Y#QcOD<~ug-YWl`UXl7Gr8=D;C_nI9BLq7mj?z|9{iwe>_j{`8e`I!y^^t;W#k^N1ra_YcAkF z6kOIPg2(Wc7R3xXe~$g(#1{fJx0vYqeLjpmn0*FE?I&gpe*C6%Q=X3$gkB59gWmD6 zaWFYZ@bRYDRa@H>jSN>_B1e8;w#l_x$3Px_HR|n~o@Z81W=Jj%yYxKOp9yrJdq`hi z!f7XY%_n4rcu~4L@*cB&*>t^sYSB$PoHXx_)RgvSE3S_y&$XArlClg_FL?89En5a;Cd))(WepWsFsf4#xnhzgGAbHTWl2shX*Xiu^cpqe!LqSQI6I>6Y z^sZmZE{4yktG3i}3~q~|o=#Mf!XJZdsja1EL|A_mq`1tx_opbo?<*u}ivw19XT3&Co7mO`K``(wE9K3Xu@9(l9D*DW{XT${m z&US87dRMZvQd z`d0i9*{}!VKDt=Whf6I*;Izi-=O)l?GQunMW}-O7b<(WIUsJW>+HS6Itzq~0UQD6) z6(0U_j=_uO)XsARmpZLG-fH>{rp(^6B9yM|vvwdyOu^)vdhNGQe<&!fq8A_G076o8 zqM&e`%Jg5%1~Yr9G4kqfIB)`#;XN78*Q}OH;=3%BO+0NIGr>$$#Z&TELCI_=mfW*u z+Xd9Dk%!}43Ecd=LNx!V;5RzY1CQHq_v`ct1dJB3o=xSqqfAfeZO#;VT+20$Y!8{e z3hN|?*`6F|rv5fxb=U}IoEpBF>1AlUV9ek%Pg!EpT&~bD7QKt*xe4*PjI2P-k)|n9 z+F1g{RMMqh=^(tx+t2G_M{4Dg^;%VGRwIzke|Ad#`ZP^l{A#{UKH| zA1QXHo{5&51g(bbdXISgiRyeg5^g?1dzGbQhe)c?m!9s}vtd(1s*v1vEo6>@u7iwg z)(<#VF0Je9DazuQ>y~JQGBa*Z9)Q6_r9z)IZJegBZz^6f?hLs7I3pY}lzcQhQU%Jk+m%NAiOmYacbuP!=S_Hevb- z4Fk?wWw04e)A>zbEUeoW)eS#~IHnRT>nkFI#J-!6xZFzoeQ$CTtrqqrCx;ITW18Rfonm=R_QfG(py~t!Pj>33o+upWp+H3CC zwixn|>7z%b6{Q27)VG6ycQ!gP>|rli_waYSEpA$c;7;dj_OtfK`oVvFGZ)cVpTCBz zmuTMYS&Epc_aV(Qv3C30l3JX{S|09tX{!?xchY z)n2YG=mvd%9>HO^2?|m;PqI4vcJ+rEnMY&Ee?QgULR>|HY6*Yw`PdQ4iJ#_Hdhb%o z>E@Oas;&a3A1$2^uV4JT#l3hIK&YNi>it$LSWc4q+2vmC5-ZVBqiO<-uTxJcLJB&3 zJ3_Nvh{a76X|CTcBijK9#U>2<%ImNvi6gveiA*F>HW&p3dYtb-?w~Eslo|COW}1!d zjNm{?M-z64cVO-3Dv@h$GQ=fhPIOe`q+b+m@Lgh~+%LbHgnK_gKlvVgrSQ}??%L8= zoxqc6d1<IJ@MZq>~FV<{eqnMLN+h#6aPgGW`8cGJH1R+mJ9nh=6^pB4R_2zm1}qMh z%UtSH{~W+6?h^xNP|uSd9!&+GoFiTyc`b*rGwfO1{fLqxQ%aHe3oxkl7yakWTe>kh z*v3SRtx)05^Ihb$_GE2-&rJE8AyA~O0S#G!m`)KcBY?wpSSeAd3r}1;sF}rCI+6}5n(VifF zJ{EPQtSbEY$2e7dR8Fs{gVM=Ro5m9q8UtG8^;1?RG7#CZd8`?%F@0^}b}m#?K2L56 z9M)trqw8HyeTuP`Dy^*bG%S%m_EKg`Y`22P1Qab&Dutl(UG|q`t^78S$8g4;eB&vS{5Hsf+C| zaNZrV`f8@Nr-Do?2@`2Vrxlzi@Pst{dnqFB6;mHRmkNFw`AWAaM5{c@~M58oKEzO zW7YEK#~8L_+t?)Jf48blNc<+Aqgjy2yU6-lCl+V&J2-O^wz#5fd$5@a1|!BW zZ0H~(sk)RF2c@!?nI$C|$-03}LK{nMI8MkW)^ckZR!&c3aJYLSrEDy)!|R^$YOL+^w0Su6L^^u}@DobEB*7VvYa%jN)NC)D@}_3b z~%8CZLAM868<_i=s!>8MwQw`9OD^4eyK6>0yfhEOXt8R){7#`O}IsxH-kAU zU8W>smUmW}+L||rt{Ez(k_!~Xm}t`v;@NCWCiltQ*h)IL-1yR?E%Ktxw@FuB!yY~U z#1>if!k0Q`T(e_5%pbd60Cj6pddGt|{Bo&Y={l{)Fs)>-ecw@!k7}Pswv->oV2^u*31B}o2;cywEyb1QWEl@aYgVOU|>t1B#x=S7wzl+^?} zixrk6u07~-$$W0vkH4~lc=H+$={4J=96aKHgOK!om(DO4?pKY=yp=>H9x^(vh}`Vy z6Dd;E2DjN}MYfXsNHJ|{5<+mhh=$P@&-;eZIklGW@?-=I^^Qdb4dubQ_L3^ayD5~^)~lc7 z`dDY*IW?Hqp=l_V@3Ux-1?x(mGl<~lpfQguDDD1?EWnBsI)}9fdYQVh#oV(t)O2@w z;!z^pZgOXMIbX1(jKhi-e;-0n*`q?W8}BISBk$?)wdggy31#4ThdE02)^T5H5`Lss zR=0t1_q>H;(BPP$9RY>|8TmNx?mgz+_Od&#$EfxLm&dW+?ZZA;F{qL?^9bGDqCDpq zm%ED2S|6E%E}TV>-^rw#&08i)yn=1jp!^g~IJ)G3z zvD}E{Nd=-qigIG(XK@zjcds!_JMOd1xWHF+j;4iiA5gr=M_ehB8jE4| z^XLr0RJ>oDj%aUUr^A9t)=+huGx^ocN0>v>;w*eVi#U~j=fqsd>$Du6z;(kDp?qQ- z5RqU__gJf5MK6H$#+`HB61X^SVq;?FKCZslD9qP!Ac6JBQRN_jdg~J6iZDrWdt9^m zAOgSni%IX-$jSY>(QeBL!;jnU2wV>A6xh&W+5Y=nez`_xQrIWl3Vic&Wwch&jmBy4Qnp2=Ohs*#LLZJKT0+OWh&vQK;?W z9n8S(POZ8jSu)$kM|h8DuTQvrVY4bKG0?K5-%I0Gd`0>(Zz;t>#8tJ?bJ3$i$-@%g zylXu{zEV}(3p4XJHWufXxrqj2@BE$u(?`3$d_=pEjzd*5{1^6!bz4zpMn#w^3~@q< zOYVP_H+!o@wpP3CVKdE{Dvcd^nT(T6ujn1DUar4b5(~8!0g4c9+(qB(g=1J=v(9$y z4kyR!z|898Y?+V}jMNunO|3P)++^fU*gS_* zF~?Hz8JFe;!R?{Cs91|lu6}s!Ay#Wpzj|I= zcHmV3`jWxCE4<<4jH?fKs~6QPmJWWrb5m@uC728Z)7DN5ra{~g|KtB2^M3vhTwoGt z9xL!3vXhIAnVXr-KivR=+Gj8<^+Q;NL)f1ip@3hh>4qp#9MMKxqG7_m4h)A(lo(kV z8p;ZXYe5ScS{Bi-!p3{GwqU$t3t4jr(A+v>hSn>ZZhIM2!4ixyyfX^(e-al%s`F&& zK9d@%PPO-Z*32x=eCD1&VEw%p<_!{^mpuoF<1f!FA<;MG|0Z5JDuYihpvP(%yOUX#2cW z?kEy>-r9bGdv^nVNR)f*OUS6sD(fPmjhBlo>9<~ol^;cWkTpKvLPgHvPrU(}r30J3o69uRTybeJ`jSnjun7CY3Q&4wtGBdK3F*>}tSZ$oA<&go5cwTKPR1Q=hJQUh~5R7-@ zlJYt2R_|J$7!t%S(Nv1qgyG_VUDm3Hj``uDw;E;!w+svJiY zl;WO5A(P;0@C$bDoLkRy)cx4!6-JkqC&xl{Rp-5HVS9Rh)eJjDWwTLU zVMZ=NwS_+AzRPffjiHyQnonIB?S;XYa;Dd9hR@A;qWfBVRPI4)=d_8BUR6OH zz6V@bsK;Ft{~(MDmlB!}sr)9q|Yin3WkKcyYYV-FVVwUzdFM?<-0SxbIKR{G58jA9ZS zZH4B#tkyX_=Q;Ho@jXI*@gI|@1d;2nwvMm=2n7sycRZQ_Vr-vIJT3~=>K$4Wz={AV z3}A_|b8-G@Ius*+1=mn`o~Z2C2h!pfVAP%upkT^$j6!6m)R?eh;R6MU zCFBO%Nv(&EBwt!TeA)NT1W%o+uZeGSW9|(yyXH!&7fII}tRJrWj-_b@ml#U*#kczP zzN)4quxN7=?OUNyc%c?n`ZervH?DdBe{)Rm6)eq+Ni6tG#%zS1d_Vek= z+-l77t$7z>4XmGPEu#(MVx{aE)EVH(1tt(&-B9eimVQOg6FAQQc{F|BDhluXSTBZgyp*Q_Q%!r~dI2>;`HORZx4+@4 zipoG~pH#^V6x;RuXm6drQ9nf{c>GAKgg9|1Y!D-ps5W;)74ASdop?3 z1j$Ac+LiPs-3IqVM-wwWd$0r$E*${XAWT%WX+L?AbzbAj$;ecx@V3}~!jFK;bw5Qc z-suj@s;x2dOpdYWLnJ@gKE^M#b|GFW3XbG*jPc_X4Id`^$9m@7OU@2l_3`3sv;pFurBtPB1I*< zH{T?A*!Tv{gTe6<-bF?Uhg{Etc8mQ<&q}z2$Fu1R)D#}L3$2%F76Zpc^)nc>P^c9~ zW1FdPqcpEaU1VsskC4(4h-z3qxkf@G5m4M|sCV%}Ov zTZcW25XR4vyH)|hoqwWmQ~b?Sf$jyJn2Fnv(-8pR{xlrmm!hPGD66cJ6uY9RlB|@Z zx(1t~R9uXr^`Ho5;45 z`({U8Bc3gDspg=Y`+<1nc&ChkR&Jl4=x0oG-E)*fy<|`Cr%*0bt(S3h@w?bK7HUh4 zdS1J~r$>rjXf-^bN$}dHxM?!qYqc;Sjp-e$fq&%fZAY$q*`=i1vfSPuae&*?(X6ne z*kzXo^uOfdTNm$GPz4n|yGa*QH}IVDu)nWRsb>;{v)je z1B(N~0U-f@#?r4IhVDUtCjMy1AmAh}MEfHP`yUR|#E_pB7f%G*0^2!#USd#{;wl?VBdg70Vrj4X<1ff6%F8|DI_iM&(OfX0uf+>edg?Ba^k0l z)gzAD)#INY7AHH2GTza*z^`~{pW8cISe}SM0f8~}R}AytkI?@Q8fH9M1vjvxkq4H! z!?$>j8VfMKKP)`t1(a%QKN7G<2?RDPBR8YtW2WFuSa|`+f*=a;tmP3r@T(3epK&S$ z8=GJInm=XApb^CEUJCT0#likU#8Q0uLU77ZAi8-Q6j zJdSbHuDG9-!ilmoGiNRR6;K^jz|tIM%#Iqn*I5aiq61haW(d!LF-!tuIP^x2T5#Cu zB!Jm9x3q9|GBUO?gF3~F15Lg|1b~djgFtLY*ubyY`)7jx<^DrszhRYCdDW@1HisS+G+?QyzMfh@F1-Lh0dih9Uz`E>w?+HAXr{dA&T$2p9tkl0$I|qN zGkB%{K;T5#dD?qpQ6Ct@3Sb@}m3O(~A87n|avK_xY_()7Hvg96H4o!_{LSqy^49+e+pcQO@3&HnC z>kfa^gJ8}&3^g;b60XpwP?-?l+<4Rm3w;`D+%Yzk3OZ{Hsjv@yb|GSG6760sUA&yApsLfD{-_5J;Hfzfe6^+5#%gE@M^FE5Fq3 zFl%tsq#6H>Cg5rODk}#~RBzdEZw8_Oemm`Pg z872RX?nyQQ{0ueZW-LwWKT$c&K0q2CT` z!@mI^KeP=^5Y(rQgho+8pogp=&|%56qeiOuZ=?9>9Q|G7G(SbwU;@L62An*|h0I+0 zpC}zWDhq8?GWz#Mc7dV917Zd#022oPMC&9e13x+n>Bfiy@76(gV}6@n2m$!@kJE$< za?ew8I*nt80FKLgju|XiQqj?8@VFS_TQ~G}#`_I4sE&w3+^;K0s)KCCX z6NR9+edE8=`>UzJEbozq1Li*s_zSsSl)L^bxwDD^Kg6(T-2Wq;(-?|}P@~F@Vq&Z)FW(e#atpJ&VwDM(~VKR;^zvHy+MkHi=>QlD+hFwXmLZ@lMXhpqaGe3@bk36an#s12@yU3S`qLU(s>ligO2*Y83Gd< zBWLI1z|PTQLW96W-~lrZBp$#T(KD#P;1`aLgY7Z(!@L3@4wq5Lv5UPp0qiIf0JVz^ z6K-$$fi8Xnx=07sK@dm@*cL#^zx?bXuxtAf{fCO#1uKLh3}8|LqCf+IIaqW8=Fc!2 zRKzbb&F{YhNiSk25eI9=AARFi(5UK;wL-ez{^aRvD;WVhAlvmdq zE(7w94lE>)u0eU(37|(x09{6<Z`3*aaNk^rer zES*sCex(ASg4vSD_-6t_$_y|Sa`Fwkpo2k%|Dl3Xvda_Vu zXgf6P0@@S`gn1yt*h)Po;~s|jPc^GjlQPS8fNEU=CJWLCAP=4n4_#ozCa*Ry0sIXH zy3G#3islihn19I}K;^SakMzeyptE;@bpVpjYU5DBRsJVi02NmTKiK3sAP}a2mO=Wh z@t@CzdzzYozbg-^W|_-SDg27CpI{v0z}{zvl;rW%lOTWR9iVao{M~a%i@UgX66nct z4F1L`j?f(9^|~K@170!w0Q%6Ar8{4o5R9FTPJ_b+fmj6Dx1NdRfCL0 zx5J$b3zn&XiVXge85e~9t-?b`{%dvuDn9r_Dijd-ednO!|ISE2MFUS9K*smW(V(LJ z^5LQR*@vA049|}SWP`vOHaZyA@959*h4AqI|Nb0umC=CqIb_`aI2ia-8IXJJ^wYth zKfH3B1o#UKkej?cOen*J?C)Rl48LFCI8F<^h&E(^5*hoy(t^HxfLElI1e-#@OD8-d zrDJ)FQ&&OoT8@x0s&=yfMiTnaz$*|!h7plyPNf5QUEr_q9G@WYnm>?QUqO3zY}r2* z4Ugl4*RT16>t}F4%x*4l>;He406{Wf2JOu!`M6X^v4gc3rPFqeWA(*0h2^#F5;5+n51TUii znW)G<6Wky8AE6EC76$yXBIK&G&UcnB|Do}BeF0}Sq~o$GdIl0_0a&|E+TMfTtbnu+d~$yWg&LrS+G+6X36PuU9r-ikAKlhC zE^Xi|2nE>Wfk3#5e}VstFdW`$06+7N1A*oUp#3@54tB>uMgANR!vlf*fj>mRj@wrG H(2Mk!w8|VU`{4^-ZN-N>w0YU#U*K1- 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 edFKBT8{e^?v~S{1Y(% diff --git a/lib/commons-io-1.2.jar b/lib/commons-io-1.2.jar deleted file mode 100644 index b2867cdde4284228f2adc51e8a0358972bccaaf1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 65621 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 diff --git a/lib/hamcrest-core.jar b/lib/hamcrest-core.jar deleted file mode 100644 index 9d5fe16e3dd37ebe79a36f61f5d0e1a69a653a8a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 45024 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 UgpPtD2z>DYYp}SJr5?)v0beu;=l}o! diff --git a/lib/junit.jar b/lib/junit.jar deleted file mode 100644 index 3a7fc266c3e32283a2b21fe12166ebdcc33a1da1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 314932 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

&R7;REBZd0NaNVcN6Eoy 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

?@Ib4$R$ZbA6MIsF(ZEk4Ii=sfRBa)&Yo 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�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 TY(h;@!?}i$7z!3V8^-w`q)kqw diff --git a/nexus-upload.sh b/nexus-upload.sh deleted file mode 100755 index 40ee9a9b89..0000000000 --- a/nexus-upload.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh - -set -e - -# Required flags: -# CREDS -- basic auth credentials, in form username:password -# VERSION -- the version of the bundle -# SIGNING_KEY -- the signing key to use -# GNUPG_PATH -- the path to the home directory for gnupg - -NEXUS_ROOT="https://$CREDS@oss.sonatype.org/service/local/staging/deploy/maven2/com/rabbitmq/amqp-client/$VERSION" -unset http_proxy -unset https_proxy -unset no_proxy - -for artifact in $@; do - echo "Uploading $artifact" - - rm -f $artifact.asc - gpg --homedir $GNUPG_PATH/.gnupg --local-user $SIGNING_KEY --no-tty --armor --detach-sign --output $artifact.asc $artifact - for ext in '' .asc ; do - curl --upload-file $artifact$ext $NEXUS_ROOT/$(basename "$artifact")$ext - for sum in md5 sha1 ; do - ${sum}sum $artifact$ext | (read a rest ; echo -n "$a") >$artifact$ext.$sum - curl --upload-file $artifact$ext.$sum $NEXUS_ROOT/$(basename "$artifact")$ext.$sum - done - done -done diff --git a/pom.xml b/pom.xml index c784b1d4cd..4a077b3728 100644 --- a/pom.xml +++ b/pom.xml @@ -1,12 +1,15 @@ - + 4.0.0 + com.rabbitmq amqp-client - VERSION + 3.6.6-SNAPSHOT jar + RabbitMQ Java Client - RabbitMQ Java client + The RabbitMQ Java client library allows Java applications to interface with RabbitMQ. http://www.rabbitmq.com @@ -27,11 +30,6 @@ - - https://github.com/rabbitmq/rabbitmq-java-client.git - scm:git:https://github.com/rabbitmq/rabbitmq-java-client.git - - info@rabbitmq.com @@ -41,36 +39,679 @@ - + + https://github.com/rabbitmq/rabbitmq-java-client.git + scm:git:https://github.com/rabbitmq/rabbitmq-java-client.git + + + + Pivotal Software, Inc. + http://www.rabbitmq.com + + + + UTF-8 + UTF-8 + + + ${basedir}/src/main/scripts + + + ${basedir}/deps + ${deps.dir}/rabbitmq_codegen + 0.9.1 + + + make + ${deps.dir}/rabbit + ${rabbitmq.dir}/scripts/rabbitmqctl + + ${project.build.directory}/ca.keystore + ${project.build.directory}/empty.keystore + bunnies + + rabbit@localhost + 5672 + ${project.build.directory}/test-classes/${test-broker.A.nodename} + hare@localhost + 5673 + ${project.build.directory}/test-classes/${test-broker.B.nodename} + + + + + + in-umbrella + + + ../../UMBRELLA.md + + + + ${basedir}/.. + + + + + + use-gmake + + FreeBSD + + + gmake + + + + + + use-rabbitmqctl.bat + + Windows + + + ${rabbitmq.dir}/scripts/rabbitmqctl.bat + + + + + + disable-java8-doclint + + [1.8,) + + + -Xdoclint:none + + + + + + setup-test-cluster + + + !skipTests + + + ${rabbitmq.dir} + + + + + + org.codehaus.gmaven + groovy-maven-plugin + 2.0 + + + + generate-test-resources + query-test-tls-certs-dir + + execute + + + + ${groovy-scripts.dir}/query_test_tls_certs_dir.groovy + + + + + + + pre-integration-test + start-test-broker-A + + execute + + + + ${test-broker.A.nodename} + ${test-broker.A.node_port} + + + ${groovy-scripts.dir}/manage_test_broker.groovy + + + + + pre-integration-test + start-test-broker-B + + execute + + + + ${test-broker.B.nodename} + ${test-broker.B.node_port} + + + ${groovy-scripts.dir}/manage_test_broker.groovy + + + + + pre-integration-test + create-test-cluster + + execute + + + + ${test-broker.B.nodename} + ${test-broker.A.nodename} + + + ${groovy-scripts.dir}/manage_test_broker.groovy + + + + + + post-integration-test + stop-test-broker-B + + execute + + + + ${test-broker.B.nodename} + + + ${groovy-scripts.dir}/manage_test_broker.groovy + + + + + post-integration-test + stop-test-broker-A + + execute + + + + ${test-broker.A.nodename} + + + ${groovy-scripts.dir}/manage_test_broker.groovy + + + + + + + + + org.codehaus.mojo + keytool-maven-plugin + + false + + + + + + + + + use-provided-test-keystores + + + ${test-tls-certs.dir}/testca/cacert.pem + + + + + + org.codehaus.mojo + keytool-maven-plugin + + false + + + + + + + + + integration-tests + + + !skipTests + + + + + + org.apache.maven.plugins + maven-failsafe-plugin + 2.19.1 + + + ${make.bin} + ${rabbitmq.dir} + ${rabbitmqctl.bin} + + ${test-keystore.ca} + ${test-keystore.empty} + ${test-keystore.password} + ${test-tls-certs.dir}/client/keycert.p12 + changeme + + ${test-broker.A.nodename} + ${test-broker.A.node_port} + ${test-broker.A.config_file} + ${test-broker.B.nodename} + ${test-broker.B.node_port} + ${test-broker.B.config_file} + + + ${deps.dir} + + true + + **/ClientTests.* + **/FunctionalTests.* + **/SSLTests.* + **/ServerTests.* + **/HATests.* + **/TestMain.* + + + + + integration-test + + integration-test + + + + verify + + verify + + + + + + + + + + + release + + + + org.apache.maven.plugins + maven-source-plugin + 3.0.1 + + + + jar + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.10.4 + + ${javadoc.opts} + + + + + jar + + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.6 + + + sign-artifacts + verify + + sign + + + + + + + + + + commons-cli commons-cli 1.1 test - - - commons-io - commons-io - 1.2 - test - - junit junit 4.12 test - + + + + + ${basedir}/src/main/resources + true + + + + + + + ${basedir}/src/test/resources + true + + + + + + org.apache.maven.plugins + maven-resources-plugin + 3.0.1 + + + org.codehaus.gmaven + groovy-maven-plugin + 2.0 + + + + generate-sources + generate-amqp-sources + + execute + + + + + + ${codegen.dir}/amqp-rabbitmq-${codegen.spec_version}.json + +

+ ${project.build.directory}/generated-sources/src/main/java/com/rabbitmq/client/AMQP.java +
+ + ${project.build.directory}/generated-sources/src/main/java/com/rabbitmq/client/impl/AMQImpl.java + + + + ${groovy-scripts.dir}/generate_amqp_sources.groovy + + + + + + + generate-test-resources + remove-old-test-keystores + + execute + + + + ${groovy-scripts.dir}/remove_old_test_keystores.groovy + + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 1.12 + + + add-generated-sources-dir + generate-sources + + add-source + + + + ${project.build.directory}/generated-sources/src/main/java + + + + + + + + maven-compiler-plugin + 3.5.1 + + 1.6 + 1.6 + + -Xlint:deprecation + -Xlint:unchecked + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.19.1 + + true + + + + + + org.codehaus.mojo + keytool-maven-plugin + 1.5 + + true + + + + generate-test-ca-keystore + generate-test-resources + + importCertificate + + + ${test-tls-certs.dir}/testca/cacert.pem + ${test-keystore.ca} + ${test-keystore.password} + true + server1 + + + + generate-test-empty-keystore + generate-test-resources + + importCertificate + deleteAlias + + + ${test-tls-certs.dir}/testca/cacert.pem + ${test-keystore.empty} + ${test-keystore.password} + true + server1 + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.0.2 + + + ${project.build.outputDirectory}/META-INF/MANIFEST.MF + + + + + + org.apache.felix + maven-bundle-plugin + 2.3.7 + + + bundle-manifest + process-classes + + manifest + + + + com.rabbitmq* + com.rabbitmq.client + AMQP + 0.9.1 + AMQP Working Group (www.amqp.org) + ${project.name} + ${project.version} + ${project.organization.name} + ${project.url} + + + + + + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.7 + true + + ossrh + https://oss.sonatype.org/ + false + + + + + org.codehaus.mojo + versions-maven-plugin + 2.3 + + + + + + ossrh + https://oss.sonatype.org/content/repositories/snapshots + - sonatype-nexus-staging - Nexus Release Repository - http://oss.sonatype.org/service/local/staging/deploy/maven2/ + ossrh + https://oss.sonatype.org/service/local/staging/deploy/maven2/ diff --git a/scripts/PerfTest b/scripts/PerfTest new file mode 100755 index 0000000000..044588115f --- /dev/null +++ b/scripts/PerfTest @@ -0,0 +1,14 @@ +#!/bin/sh + +set -e + +SCRIPTDIR=$(dirname "$0") +SRCDIR=$(cd "$SCRIPTDIR"/.. && pwd) + +( + cd "$SRCDIR" + mvn -q test-compile -P '!setup-test-cluster' + mvn -q exec:java \ + -Dexec.classpathScope=test \ + -Dexec.mainClass="com.rabbitmq.examples.PerfTest" "$@" +) diff --git a/src/com/rabbitmq/client/Address.java b/src/main/java/com/rabbitmq/client/Address.java similarity index 100% rename from src/com/rabbitmq/client/Address.java rename to src/main/java/com/rabbitmq/client/Address.java diff --git a/src/com/rabbitmq/client/AlreadyClosedException.java b/src/main/java/com/rabbitmq/client/AlreadyClosedException.java similarity index 100% rename from src/com/rabbitmq/client/AlreadyClosedException.java rename to src/main/java/com/rabbitmq/client/AlreadyClosedException.java diff --git a/src/com/rabbitmq/client/AuthenticationFailureException.java b/src/main/java/com/rabbitmq/client/AuthenticationFailureException.java similarity index 100% rename from src/com/rabbitmq/client/AuthenticationFailureException.java rename to src/main/java/com/rabbitmq/client/AuthenticationFailureException.java diff --git a/src/com/rabbitmq/client/BasicProperties.java b/src/main/java/com/rabbitmq/client/BasicProperties.java similarity index 100% rename from src/com/rabbitmq/client/BasicProperties.java rename to src/main/java/com/rabbitmq/client/BasicProperties.java diff --git a/src/com/rabbitmq/client/BlockedListener.java b/src/main/java/com/rabbitmq/client/BlockedListener.java similarity index 100% rename from src/com/rabbitmq/client/BlockedListener.java rename to src/main/java/com/rabbitmq/client/BlockedListener.java diff --git a/src/com/rabbitmq/client/Channel.java b/src/main/java/com/rabbitmq/client/Channel.java similarity index 100% rename from src/com/rabbitmq/client/Channel.java rename to src/main/java/com/rabbitmq/client/Channel.java diff --git a/src/com/rabbitmq/client/Command.java b/src/main/java/com/rabbitmq/client/Command.java similarity index 100% rename from src/com/rabbitmq/client/Command.java rename to src/main/java/com/rabbitmq/client/Command.java diff --git a/src/com/rabbitmq/client/ConfirmListener.java b/src/main/java/com/rabbitmq/client/ConfirmListener.java similarity index 100% rename from src/com/rabbitmq/client/ConfirmListener.java rename to src/main/java/com/rabbitmq/client/ConfirmListener.java diff --git a/src/com/rabbitmq/client/Connection.java b/src/main/java/com/rabbitmq/client/Connection.java similarity index 100% rename from src/com/rabbitmq/client/Connection.java rename to src/main/java/com/rabbitmq/client/Connection.java diff --git a/src/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java similarity index 100% rename from src/com/rabbitmq/client/ConnectionFactory.java rename to src/main/java/com/rabbitmq/client/ConnectionFactory.java diff --git a/src/com/rabbitmq/client/Consumer.java b/src/main/java/com/rabbitmq/client/Consumer.java similarity index 100% rename from src/com/rabbitmq/client/Consumer.java rename to src/main/java/com/rabbitmq/client/Consumer.java diff --git a/src/com/rabbitmq/client/ConsumerCancelledException.java b/src/main/java/com/rabbitmq/client/ConsumerCancelledException.java similarity index 100% rename from src/com/rabbitmq/client/ConsumerCancelledException.java rename to src/main/java/com/rabbitmq/client/ConsumerCancelledException.java diff --git a/src/com/rabbitmq/client/ContentHeader.java b/src/main/java/com/rabbitmq/client/ContentHeader.java similarity index 100% rename from src/com/rabbitmq/client/ContentHeader.java rename to src/main/java/com/rabbitmq/client/ContentHeader.java diff --git a/src/com/rabbitmq/client/DefaultConsumer.java b/src/main/java/com/rabbitmq/client/DefaultConsumer.java similarity index 100% rename from src/com/rabbitmq/client/DefaultConsumer.java rename to src/main/java/com/rabbitmq/client/DefaultConsumer.java diff --git a/src/com/rabbitmq/client/DefaultSaslConfig.java b/src/main/java/com/rabbitmq/client/DefaultSaslConfig.java similarity index 100% rename from src/com/rabbitmq/client/DefaultSaslConfig.java rename to src/main/java/com/rabbitmq/client/DefaultSaslConfig.java diff --git a/src/com/rabbitmq/client/DefaultSocketConfigurator.java b/src/main/java/com/rabbitmq/client/DefaultSocketConfigurator.java similarity index 100% rename from src/com/rabbitmq/client/DefaultSocketConfigurator.java rename to src/main/java/com/rabbitmq/client/DefaultSocketConfigurator.java diff --git a/src/com/rabbitmq/client/Envelope.java b/src/main/java/com/rabbitmq/client/Envelope.java similarity index 100% rename from src/com/rabbitmq/client/Envelope.java rename to src/main/java/com/rabbitmq/client/Envelope.java diff --git a/src/com/rabbitmq/client/ExceptionHandler.java b/src/main/java/com/rabbitmq/client/ExceptionHandler.java similarity index 100% rename from src/com/rabbitmq/client/ExceptionHandler.java rename to src/main/java/com/rabbitmq/client/ExceptionHandler.java diff --git a/src/com/rabbitmq/client/FlowListener.java b/src/main/java/com/rabbitmq/client/FlowListener.java similarity index 100% rename from src/com/rabbitmq/client/FlowListener.java rename to src/main/java/com/rabbitmq/client/FlowListener.java diff --git a/src/com/rabbitmq/client/GetResponse.java b/src/main/java/com/rabbitmq/client/GetResponse.java similarity index 100% rename from src/com/rabbitmq/client/GetResponse.java rename to src/main/java/com/rabbitmq/client/GetResponse.java diff --git a/src/com/rabbitmq/client/JDKSaslConfig.java b/src/main/java/com/rabbitmq/client/JDKSaslConfig.java similarity index 100% rename from src/com/rabbitmq/client/JDKSaslConfig.java rename to src/main/java/com/rabbitmq/client/JDKSaslConfig.java diff --git a/src/com/rabbitmq/client/LongString.java b/src/main/java/com/rabbitmq/client/LongString.java similarity index 100% rename from src/com/rabbitmq/client/LongString.java rename to src/main/java/com/rabbitmq/client/LongString.java diff --git a/src/com/rabbitmq/client/MalformedFrameException.java b/src/main/java/com/rabbitmq/client/MalformedFrameException.java similarity index 100% rename from src/com/rabbitmq/client/MalformedFrameException.java rename to src/main/java/com/rabbitmq/client/MalformedFrameException.java diff --git a/src/com/rabbitmq/client/MapRpcServer.java b/src/main/java/com/rabbitmq/client/MapRpcServer.java similarity index 100% rename from src/com/rabbitmq/client/MapRpcServer.java rename to src/main/java/com/rabbitmq/client/MapRpcServer.java diff --git a/src/com/rabbitmq/client/MessageProperties.java b/src/main/java/com/rabbitmq/client/MessageProperties.java similarity index 100% rename from src/com/rabbitmq/client/MessageProperties.java rename to src/main/java/com/rabbitmq/client/MessageProperties.java diff --git a/src/com/rabbitmq/client/Method.java b/src/main/java/com/rabbitmq/client/Method.java similarity index 100% rename from src/com/rabbitmq/client/Method.java rename to src/main/java/com/rabbitmq/client/Method.java diff --git a/src/com/rabbitmq/client/MissedHeartbeatException.java b/src/main/java/com/rabbitmq/client/MissedHeartbeatException.java similarity index 100% rename from src/com/rabbitmq/client/MissedHeartbeatException.java rename to src/main/java/com/rabbitmq/client/MissedHeartbeatException.java diff --git a/src/com/rabbitmq/client/NullTrustManager.java b/src/main/java/com/rabbitmq/client/NullTrustManager.java similarity index 100% rename from src/com/rabbitmq/client/NullTrustManager.java rename to src/main/java/com/rabbitmq/client/NullTrustManager.java diff --git a/src/com/rabbitmq/client/PossibleAuthenticationFailureException.java b/src/main/java/com/rabbitmq/client/PossibleAuthenticationFailureException.java similarity index 100% rename from src/com/rabbitmq/client/PossibleAuthenticationFailureException.java rename to src/main/java/com/rabbitmq/client/PossibleAuthenticationFailureException.java diff --git a/src/com/rabbitmq/client/ProtocolVersionMismatchException.java b/src/main/java/com/rabbitmq/client/ProtocolVersionMismatchException.java similarity index 100% rename from src/com/rabbitmq/client/ProtocolVersionMismatchException.java rename to src/main/java/com/rabbitmq/client/ProtocolVersionMismatchException.java diff --git a/src/com/rabbitmq/client/QueueingConsumer.java b/src/main/java/com/rabbitmq/client/QueueingConsumer.java similarity index 100% rename from src/com/rabbitmq/client/QueueingConsumer.java rename to src/main/java/com/rabbitmq/client/QueueingConsumer.java diff --git a/src/com/rabbitmq/client/Recoverable.java b/src/main/java/com/rabbitmq/client/Recoverable.java similarity index 100% rename from src/com/rabbitmq/client/Recoverable.java rename to src/main/java/com/rabbitmq/client/Recoverable.java diff --git a/src/com/rabbitmq/client/RecoveryListener.java b/src/main/java/com/rabbitmq/client/RecoveryListener.java similarity index 100% rename from src/com/rabbitmq/client/RecoveryListener.java rename to src/main/java/com/rabbitmq/client/RecoveryListener.java diff --git a/src/com/rabbitmq/client/ReturnListener.java b/src/main/java/com/rabbitmq/client/ReturnListener.java similarity index 100% rename from src/com/rabbitmq/client/ReturnListener.java rename to src/main/java/com/rabbitmq/client/ReturnListener.java diff --git a/src/com/rabbitmq/client/RpcClient.java b/src/main/java/com/rabbitmq/client/RpcClient.java similarity index 100% rename from src/com/rabbitmq/client/RpcClient.java rename to src/main/java/com/rabbitmq/client/RpcClient.java diff --git a/src/com/rabbitmq/client/RpcServer.java b/src/main/java/com/rabbitmq/client/RpcServer.java similarity index 100% rename from src/com/rabbitmq/client/RpcServer.java rename to src/main/java/com/rabbitmq/client/RpcServer.java diff --git a/src/com/rabbitmq/client/SaslConfig.java b/src/main/java/com/rabbitmq/client/SaslConfig.java similarity index 100% rename from src/com/rabbitmq/client/SaslConfig.java rename to src/main/java/com/rabbitmq/client/SaslConfig.java diff --git a/src/com/rabbitmq/client/SaslMechanism.java b/src/main/java/com/rabbitmq/client/SaslMechanism.java similarity index 100% rename from src/com/rabbitmq/client/SaslMechanism.java rename to src/main/java/com/rabbitmq/client/SaslMechanism.java diff --git a/src/com/rabbitmq/client/ShutdownListener.java b/src/main/java/com/rabbitmq/client/ShutdownListener.java similarity index 100% rename from src/com/rabbitmq/client/ShutdownListener.java rename to src/main/java/com/rabbitmq/client/ShutdownListener.java diff --git a/src/com/rabbitmq/client/ShutdownNotifier.java b/src/main/java/com/rabbitmq/client/ShutdownNotifier.java similarity index 100% rename from src/com/rabbitmq/client/ShutdownNotifier.java rename to src/main/java/com/rabbitmq/client/ShutdownNotifier.java diff --git a/src/com/rabbitmq/client/ShutdownSignalException.java b/src/main/java/com/rabbitmq/client/ShutdownSignalException.java similarity index 100% rename from src/com/rabbitmq/client/ShutdownSignalException.java rename to src/main/java/com/rabbitmq/client/ShutdownSignalException.java diff --git a/src/com/rabbitmq/client/SocketConfigurator.java b/src/main/java/com/rabbitmq/client/SocketConfigurator.java similarity index 100% rename from src/com/rabbitmq/client/SocketConfigurator.java rename to src/main/java/com/rabbitmq/client/SocketConfigurator.java diff --git a/src/com/rabbitmq/client/StringRpcServer.java b/src/main/java/com/rabbitmq/client/StringRpcServer.java similarity index 100% rename from src/com/rabbitmq/client/StringRpcServer.java rename to src/main/java/com/rabbitmq/client/StringRpcServer.java diff --git a/src/com/rabbitmq/client/TopologyRecoveryException.java b/src/main/java/com/rabbitmq/client/TopologyRecoveryException.java similarity index 100% rename from src/com/rabbitmq/client/TopologyRecoveryException.java rename to src/main/java/com/rabbitmq/client/TopologyRecoveryException.java diff --git a/src/com/rabbitmq/client/UnexpectedFrameError.java b/src/main/java/com/rabbitmq/client/UnexpectedFrameError.java similarity index 100% rename from src/com/rabbitmq/client/UnexpectedFrameError.java rename to src/main/java/com/rabbitmq/client/UnexpectedFrameError.java diff --git a/src/com/rabbitmq/client/UnexpectedMethodError.java b/src/main/java/com/rabbitmq/client/UnexpectedMethodError.java similarity index 100% rename from src/com/rabbitmq/client/UnexpectedMethodError.java rename to src/main/java/com/rabbitmq/client/UnexpectedMethodError.java diff --git a/src/com/rabbitmq/client/UnknownClassOrMethodId.java b/src/main/java/com/rabbitmq/client/UnknownClassOrMethodId.java similarity index 100% rename from src/com/rabbitmq/client/UnknownClassOrMethodId.java rename to src/main/java/com/rabbitmq/client/UnknownClassOrMethodId.java diff --git a/src/com/rabbitmq/client/impl/AMQBasicProperties.java b/src/main/java/com/rabbitmq/client/impl/AMQBasicProperties.java similarity index 100% rename from src/com/rabbitmq/client/impl/AMQBasicProperties.java rename to src/main/java/com/rabbitmq/client/impl/AMQBasicProperties.java diff --git a/src/com/rabbitmq/client/impl/AMQChannel.java b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java similarity index 100% rename from src/com/rabbitmq/client/impl/AMQChannel.java rename to src/main/java/com/rabbitmq/client/impl/AMQChannel.java diff --git a/src/com/rabbitmq/client/impl/AMQCommand.java b/src/main/java/com/rabbitmq/client/impl/AMQCommand.java similarity index 100% rename from src/com/rabbitmq/client/impl/AMQCommand.java rename to src/main/java/com/rabbitmq/client/impl/AMQCommand.java diff --git a/src/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java similarity index 100% rename from src/com/rabbitmq/client/impl/AMQConnection.java rename to src/main/java/com/rabbitmq/client/impl/AMQConnection.java diff --git a/src/com/rabbitmq/client/impl/AMQContentHeader.java b/src/main/java/com/rabbitmq/client/impl/AMQContentHeader.java similarity index 100% rename from src/com/rabbitmq/client/impl/AMQContentHeader.java rename to src/main/java/com/rabbitmq/client/impl/AMQContentHeader.java diff --git a/src/com/rabbitmq/client/impl/CRDemoMechanism.java b/src/main/java/com/rabbitmq/client/impl/CRDemoMechanism.java similarity index 100% rename from src/com/rabbitmq/client/impl/CRDemoMechanism.java rename to src/main/java/com/rabbitmq/client/impl/CRDemoMechanism.java diff --git a/src/com/rabbitmq/client/impl/ChannelManager.java b/src/main/java/com/rabbitmq/client/impl/ChannelManager.java similarity index 100% rename from src/com/rabbitmq/client/impl/ChannelManager.java rename to src/main/java/com/rabbitmq/client/impl/ChannelManager.java diff --git a/src/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java similarity index 100% rename from src/com/rabbitmq/client/impl/ChannelN.java rename to src/main/java/com/rabbitmq/client/impl/ChannelN.java diff --git a/src/com/rabbitmq/client/impl/ClientVersion.java.in b/src/main/java/com/rabbitmq/client/impl/ClientVersion.java similarity index 63% rename from src/com/rabbitmq/client/impl/ClientVersion.java.in rename to src/main/java/com/rabbitmq/client/impl/ClientVersion.java index f9b2a800eb..33ba8d61fa 100644 --- a/src/com/rabbitmq/client/impl/ClientVersion.java.in +++ b/src/main/java/com/rabbitmq/client/impl/ClientVersion.java @@ -15,10 +15,26 @@ package com.rabbitmq.client.impl; +import java.io.IOException; +import java.util.Properties; + /** * Publicly available Client Version information */ public class ClientVersion { /** Full version string */ - public static final String VERSION = "@VERSION@"; + private static final Properties version; + public static final String VERSION; + + static { + version = new Properties(); + try { + version.load(ClientVersion.class.getClassLoader() + .getResourceAsStream("version.properties")); + } catch (IOException e) { + } + + VERSION = version.getProperty("com.rabbitmq.client.version", + ClientVersion.class.getPackage().getImplementationVersion()); + } } diff --git a/src/com/rabbitmq/client/impl/CommandAssembler.java b/src/main/java/com/rabbitmq/client/impl/CommandAssembler.java similarity index 100% rename from src/com/rabbitmq/client/impl/CommandAssembler.java rename to src/main/java/com/rabbitmq/client/impl/CommandAssembler.java diff --git a/src/com/rabbitmq/client/impl/ConnectionParams.java b/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java similarity index 100% rename from src/com/rabbitmq/client/impl/ConnectionParams.java rename to src/main/java/com/rabbitmq/client/impl/ConnectionParams.java diff --git a/src/com/rabbitmq/client/impl/ConsumerDispatcher.java b/src/main/java/com/rabbitmq/client/impl/ConsumerDispatcher.java similarity index 100% rename from src/com/rabbitmq/client/impl/ConsumerDispatcher.java rename to src/main/java/com/rabbitmq/client/impl/ConsumerDispatcher.java diff --git a/src/com/rabbitmq/client/impl/ConsumerWorkService.java b/src/main/java/com/rabbitmq/client/impl/ConsumerWorkService.java similarity index 100% rename from src/com/rabbitmq/client/impl/ConsumerWorkService.java rename to src/main/java/com/rabbitmq/client/impl/ConsumerWorkService.java diff --git a/src/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java b/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java similarity index 100% rename from src/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java rename to src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java diff --git a/src/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java b/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java similarity index 100% rename from src/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java rename to src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java diff --git a/src/com/rabbitmq/client/impl/DefaultExceptionHandler.java b/src/main/java/com/rabbitmq/client/impl/DefaultExceptionHandler.java similarity index 100% rename from src/com/rabbitmq/client/impl/DefaultExceptionHandler.java rename to src/main/java/com/rabbitmq/client/impl/DefaultExceptionHandler.java diff --git a/src/com/rabbitmq/client/impl/Environment.java b/src/main/java/com/rabbitmq/client/impl/Environment.java similarity index 100% rename from src/com/rabbitmq/client/impl/Environment.java rename to src/main/java/com/rabbitmq/client/impl/Environment.java diff --git a/src/com/rabbitmq/client/impl/ExternalMechanism.java b/src/main/java/com/rabbitmq/client/impl/ExternalMechanism.java similarity index 100% rename from src/com/rabbitmq/client/impl/ExternalMechanism.java rename to src/main/java/com/rabbitmq/client/impl/ExternalMechanism.java diff --git a/src/com/rabbitmq/client/impl/ForgivingExceptionHandler.java b/src/main/java/com/rabbitmq/client/impl/ForgivingExceptionHandler.java similarity index 100% rename from src/com/rabbitmq/client/impl/ForgivingExceptionHandler.java rename to src/main/java/com/rabbitmq/client/impl/ForgivingExceptionHandler.java diff --git a/src/com/rabbitmq/client/impl/Frame.java b/src/main/java/com/rabbitmq/client/impl/Frame.java similarity index 100% rename from src/com/rabbitmq/client/impl/Frame.java rename to src/main/java/com/rabbitmq/client/impl/Frame.java diff --git a/src/com/rabbitmq/client/impl/FrameHandler.java b/src/main/java/com/rabbitmq/client/impl/FrameHandler.java similarity index 100% rename from src/com/rabbitmq/client/impl/FrameHandler.java rename to src/main/java/com/rabbitmq/client/impl/FrameHandler.java diff --git a/src/com/rabbitmq/client/impl/FrameHandlerFactory.java b/src/main/java/com/rabbitmq/client/impl/FrameHandlerFactory.java similarity index 100% rename from src/com/rabbitmq/client/impl/FrameHandlerFactory.java rename to src/main/java/com/rabbitmq/client/impl/FrameHandlerFactory.java diff --git a/src/com/rabbitmq/client/impl/HeartbeatSender.java b/src/main/java/com/rabbitmq/client/impl/HeartbeatSender.java similarity index 100% rename from src/com/rabbitmq/client/impl/HeartbeatSender.java rename to src/main/java/com/rabbitmq/client/impl/HeartbeatSender.java diff --git a/src/com/rabbitmq/client/impl/LongStringHelper.java b/src/main/java/com/rabbitmq/client/impl/LongStringHelper.java similarity index 100% rename from src/com/rabbitmq/client/impl/LongStringHelper.java rename to src/main/java/com/rabbitmq/client/impl/LongStringHelper.java diff --git a/src/com/rabbitmq/client/impl/Method.java b/src/main/java/com/rabbitmq/client/impl/Method.java similarity index 100% rename from src/com/rabbitmq/client/impl/Method.java rename to src/main/java/com/rabbitmq/client/impl/Method.java diff --git a/src/com/rabbitmq/client/impl/MethodArgumentReader.java b/src/main/java/com/rabbitmq/client/impl/MethodArgumentReader.java similarity index 100% rename from src/com/rabbitmq/client/impl/MethodArgumentReader.java rename to src/main/java/com/rabbitmq/client/impl/MethodArgumentReader.java diff --git a/src/com/rabbitmq/client/impl/MethodArgumentWriter.java b/src/main/java/com/rabbitmq/client/impl/MethodArgumentWriter.java similarity index 100% rename from src/com/rabbitmq/client/impl/MethodArgumentWriter.java rename to src/main/java/com/rabbitmq/client/impl/MethodArgumentWriter.java diff --git a/src/com/rabbitmq/client/impl/NetworkConnection.java b/src/main/java/com/rabbitmq/client/impl/NetworkConnection.java similarity index 100% rename from src/com/rabbitmq/client/impl/NetworkConnection.java rename to src/main/java/com/rabbitmq/client/impl/NetworkConnection.java diff --git a/src/com/rabbitmq/client/impl/PlainMechanism.java b/src/main/java/com/rabbitmq/client/impl/PlainMechanism.java similarity index 100% rename from src/com/rabbitmq/client/impl/PlainMechanism.java rename to src/main/java/com/rabbitmq/client/impl/PlainMechanism.java diff --git a/src/com/rabbitmq/client/impl/SetQueue.java b/src/main/java/com/rabbitmq/client/impl/SetQueue.java similarity index 100% rename from src/com/rabbitmq/client/impl/SetQueue.java rename to src/main/java/com/rabbitmq/client/impl/SetQueue.java diff --git a/src/com/rabbitmq/client/impl/ShutdownNotifierComponent.java b/src/main/java/com/rabbitmq/client/impl/ShutdownNotifierComponent.java similarity index 100% rename from src/com/rabbitmq/client/impl/ShutdownNotifierComponent.java rename to src/main/java/com/rabbitmq/client/impl/ShutdownNotifierComponent.java diff --git a/src/com/rabbitmq/client/impl/SocketFrameHandler.java b/src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java similarity index 100% rename from src/com/rabbitmq/client/impl/SocketFrameHandler.java rename to src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java diff --git a/src/com/rabbitmq/client/impl/StrictExceptionHandler.java b/src/main/java/com/rabbitmq/client/impl/StrictExceptionHandler.java similarity index 100% rename from src/com/rabbitmq/client/impl/StrictExceptionHandler.java rename to src/main/java/com/rabbitmq/client/impl/StrictExceptionHandler.java diff --git a/src/com/rabbitmq/client/impl/TruncatedInputStream.java b/src/main/java/com/rabbitmq/client/impl/TruncatedInputStream.java similarity index 100% rename from src/com/rabbitmq/client/impl/TruncatedInputStream.java rename to src/main/java/com/rabbitmq/client/impl/TruncatedInputStream.java diff --git a/src/com/rabbitmq/client/impl/UnknownChannelException.java b/src/main/java/com/rabbitmq/client/impl/UnknownChannelException.java similarity index 100% rename from src/com/rabbitmq/client/impl/UnknownChannelException.java rename to src/main/java/com/rabbitmq/client/impl/UnknownChannelException.java diff --git a/src/com/rabbitmq/client/impl/ValueReader.java b/src/main/java/com/rabbitmq/client/impl/ValueReader.java similarity index 100% rename from src/com/rabbitmq/client/impl/ValueReader.java rename to src/main/java/com/rabbitmq/client/impl/ValueReader.java diff --git a/src/com/rabbitmq/client/impl/ValueWriter.java b/src/main/java/com/rabbitmq/client/impl/ValueWriter.java similarity index 100% rename from src/com/rabbitmq/client/impl/ValueWriter.java rename to src/main/java/com/rabbitmq/client/impl/ValueWriter.java diff --git a/src/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java b/src/main/java/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java similarity index 100% rename from src/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java rename to src/main/java/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java diff --git a/src/com/rabbitmq/client/impl/Version.java b/src/main/java/com/rabbitmq/client/impl/Version.java similarity index 100% rename from src/com/rabbitmq/client/impl/Version.java rename to src/main/java/com/rabbitmq/client/impl/Version.java diff --git a/src/com/rabbitmq/client/impl/WorkPool.java b/src/main/java/com/rabbitmq/client/impl/WorkPool.java similarity index 100% rename from src/com/rabbitmq/client/impl/WorkPool.java rename to src/main/java/com/rabbitmq/client/impl/WorkPool.java diff --git a/src/com/rabbitmq/client/impl/package.html b/src/main/java/com/rabbitmq/client/impl/package.html similarity index 100% rename from src/com/rabbitmq/client/impl/package.html rename to src/main/java/com/rabbitmq/client/impl/package.html diff --git a/src/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java similarity index 100% rename from src/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java rename to src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java diff --git a/src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java similarity index 100% rename from src/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java rename to src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java diff --git a/src/com/rabbitmq/client/impl/recovery/ConsumerRecoveryListener.java b/src/main/java/com/rabbitmq/client/impl/recovery/ConsumerRecoveryListener.java similarity index 100% rename from src/com/rabbitmq/client/impl/recovery/ConsumerRecoveryListener.java rename to src/main/java/com/rabbitmq/client/impl/recovery/ConsumerRecoveryListener.java diff --git a/src/com/rabbitmq/client/impl/recovery/QueueRecoveryListener.java b/src/main/java/com/rabbitmq/client/impl/recovery/QueueRecoveryListener.java similarity index 100% rename from src/com/rabbitmq/client/impl/recovery/QueueRecoveryListener.java rename to src/main/java/com/rabbitmq/client/impl/recovery/QueueRecoveryListener.java diff --git a/src/com/rabbitmq/client/impl/recovery/RecordedBinding.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedBinding.java similarity index 100% rename from src/com/rabbitmq/client/impl/recovery/RecordedBinding.java rename to src/main/java/com/rabbitmq/client/impl/recovery/RecordedBinding.java diff --git a/src/com/rabbitmq/client/impl/recovery/RecordedConsumer.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedConsumer.java similarity index 100% rename from src/com/rabbitmq/client/impl/recovery/RecordedConsumer.java rename to src/main/java/com/rabbitmq/client/impl/recovery/RecordedConsumer.java diff --git a/src/com/rabbitmq/client/impl/recovery/RecordedEntity.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedEntity.java similarity index 100% rename from src/com/rabbitmq/client/impl/recovery/RecordedEntity.java rename to src/main/java/com/rabbitmq/client/impl/recovery/RecordedEntity.java diff --git a/src/com/rabbitmq/client/impl/recovery/RecordedExchange.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchange.java similarity index 100% rename from src/com/rabbitmq/client/impl/recovery/RecordedExchange.java rename to src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchange.java diff --git a/src/com/rabbitmq/client/impl/recovery/RecordedExchangeBinding.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchangeBinding.java similarity index 100% rename from src/com/rabbitmq/client/impl/recovery/RecordedExchangeBinding.java rename to src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchangeBinding.java diff --git a/src/com/rabbitmq/client/impl/recovery/RecordedNamedEntity.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedNamedEntity.java similarity index 100% rename from src/com/rabbitmq/client/impl/recovery/RecordedNamedEntity.java rename to src/main/java/com/rabbitmq/client/impl/recovery/RecordedNamedEntity.java diff --git a/src/com/rabbitmq/client/impl/recovery/RecordedQueue.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java similarity index 100% rename from src/com/rabbitmq/client/impl/recovery/RecordedQueue.java rename to src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java diff --git a/src/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java similarity index 100% rename from src/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java rename to src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java diff --git a/src/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnection.java similarity index 100% rename from src/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnection.java rename to src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnection.java diff --git a/src/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java similarity index 100% rename from src/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java rename to src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java diff --git a/src/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelManager.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelManager.java similarity index 100% rename from src/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelManager.java rename to src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelManager.java diff --git a/src/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java similarity index 100% rename from src/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java rename to src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java diff --git a/src/com/rabbitmq/client/package.html b/src/main/java/com/rabbitmq/client/package.html similarity index 100% rename from src/com/rabbitmq/client/package.html rename to src/main/java/com/rabbitmq/client/package.html diff --git a/src/com/rabbitmq/tools/Tracer.java b/src/main/java/com/rabbitmq/tools/Tracer.java similarity index 100% rename from src/com/rabbitmq/tools/Tracer.java rename to src/main/java/com/rabbitmq/tools/Tracer.java diff --git a/src/com/rabbitmq/tools/json/JSONReader.java b/src/main/java/com/rabbitmq/tools/json/JSONReader.java similarity index 100% rename from src/com/rabbitmq/tools/json/JSONReader.java rename to src/main/java/com/rabbitmq/tools/json/JSONReader.java diff --git a/src/com/rabbitmq/tools/json/JSONSerializable.java b/src/main/java/com/rabbitmq/tools/json/JSONSerializable.java similarity index 100% rename from src/com/rabbitmq/tools/json/JSONSerializable.java rename to src/main/java/com/rabbitmq/tools/json/JSONSerializable.java diff --git a/src/com/rabbitmq/tools/json/JSONUtil.java b/src/main/java/com/rabbitmq/tools/json/JSONUtil.java similarity index 100% rename from src/com/rabbitmq/tools/json/JSONUtil.java rename to src/main/java/com/rabbitmq/tools/json/JSONUtil.java diff --git a/src/com/rabbitmq/tools/json/JSONWriter.java b/src/main/java/com/rabbitmq/tools/json/JSONWriter.java similarity index 100% rename from src/com/rabbitmq/tools/json/JSONWriter.java rename to src/main/java/com/rabbitmq/tools/json/JSONWriter.java diff --git a/src/com/rabbitmq/tools/json/package.html b/src/main/java/com/rabbitmq/tools/json/package.html similarity index 100% rename from src/com/rabbitmq/tools/json/package.html rename to src/main/java/com/rabbitmq/tools/json/package.html diff --git a/src/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java similarity index 100% rename from src/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java rename to src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java diff --git a/src/com/rabbitmq/tools/jsonrpc/JsonRpcException.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java similarity index 100% rename from src/com/rabbitmq/tools/jsonrpc/JsonRpcException.java rename to src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java diff --git a/src/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java similarity index 100% rename from src/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java rename to src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java diff --git a/src/com/rabbitmq/tools/jsonrpc/ParameterDescription.java b/src/main/java/com/rabbitmq/tools/jsonrpc/ParameterDescription.java similarity index 100% rename from src/com/rabbitmq/tools/jsonrpc/ParameterDescription.java rename to src/main/java/com/rabbitmq/tools/jsonrpc/ParameterDescription.java diff --git a/src/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java b/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java similarity index 100% rename from src/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java rename to src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java diff --git a/src/com/rabbitmq/tools/jsonrpc/ServiceDescription.java b/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java similarity index 100% rename from src/com/rabbitmq/tools/jsonrpc/ServiceDescription.java rename to src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java diff --git a/src/com/rabbitmq/tools/jsonrpc/package.html b/src/main/java/com/rabbitmq/tools/jsonrpc/package.html similarity index 100% rename from src/com/rabbitmq/tools/jsonrpc/package.html rename to src/main/java/com/rabbitmq/tools/jsonrpc/package.html diff --git a/src/com/rabbitmq/tools/package.html b/src/main/java/com/rabbitmq/tools/package.html similarity index 100% rename from src/com/rabbitmq/tools/package.html rename to src/main/java/com/rabbitmq/tools/package.html diff --git a/src/com/rabbitmq/utility/BlockingCell.java b/src/main/java/com/rabbitmq/utility/BlockingCell.java similarity index 100% rename from src/com/rabbitmq/utility/BlockingCell.java rename to src/main/java/com/rabbitmq/utility/BlockingCell.java diff --git a/src/com/rabbitmq/utility/BlockingValueOrException.java b/src/main/java/com/rabbitmq/utility/BlockingValueOrException.java similarity index 100% rename from src/com/rabbitmq/utility/BlockingValueOrException.java rename to src/main/java/com/rabbitmq/utility/BlockingValueOrException.java diff --git a/src/com/rabbitmq/utility/IntAllocator.java b/src/main/java/com/rabbitmq/utility/IntAllocator.java similarity index 100% rename from src/com/rabbitmq/utility/IntAllocator.java rename to src/main/java/com/rabbitmq/utility/IntAllocator.java diff --git a/src/com/rabbitmq/utility/SensibleClone.java b/src/main/java/com/rabbitmq/utility/SensibleClone.java similarity index 100% rename from src/com/rabbitmq/utility/SensibleClone.java rename to src/main/java/com/rabbitmq/utility/SensibleClone.java diff --git a/src/com/rabbitmq/utility/SingleShotLinearTimer.java b/src/main/java/com/rabbitmq/utility/SingleShotLinearTimer.java similarity index 100% rename from src/com/rabbitmq/utility/SingleShotLinearTimer.java rename to src/main/java/com/rabbitmq/utility/SingleShotLinearTimer.java diff --git a/src/com/rabbitmq/utility/Utility.java b/src/main/java/com/rabbitmq/utility/Utility.java similarity index 100% rename from src/com/rabbitmq/utility/Utility.java rename to src/main/java/com/rabbitmq/utility/Utility.java diff --git a/src/com/rabbitmq/utility/ValueOrException.java b/src/main/java/com/rabbitmq/utility/ValueOrException.java similarity index 100% rename from src/com/rabbitmq/utility/ValueOrException.java rename to src/main/java/com/rabbitmq/utility/ValueOrException.java diff --git a/src/com/rabbitmq/utility/package.html b/src/main/java/com/rabbitmq/utility/package.html similarity index 100% rename from src/com/rabbitmq/utility/package.html rename to src/main/java/com/rabbitmq/utility/package.html diff --git a/src/main/resources/version.properties b/src/main/resources/version.properties new file mode 100644 index 0000000000..3562d483ec --- /dev/null +++ b/src/main/resources/version.properties @@ -0,0 +1 @@ +com.rabbitmq.client.version = ${project.version} diff --git a/src/main/scripts/generate_amqp_sources.groovy b/src/main/scripts/generate_amqp_sources.groovy new file mode 100644 index 0000000000..4a58e196ec --- /dev/null +++ b/src/main/scripts/generate_amqp_sources.groovy @@ -0,0 +1,60 @@ +import java.security.MessageDigest + +def md5(final file) { + MessageDigest digest = MessageDigest.getInstance("MD5") + file.withInputStream() { is -> + byte[] buffer = new byte[8192] + int read = 0 + while ((read = is.read(buffer)) > 0) { + digest.update(buffer, 0, read); + } + } + byte[] md5sum = digest.digest() + BigInteger bigInt = new BigInteger(1, md5sum) + return bigInt.toString(16) +} + +def generate_source(final type, final filename) { + String[] command = [ + 'python', + properties['script'], type, + properties['spec'], + filename + ] + + def pb = new ProcessBuilder(command) + pb.environment().put('PYTHONPATH', properties['codegen.dir']) + pb.redirectErrorStream(true) + + def process = pb.start() + process.waitFor() + if (process.exitValue() != 0) { + println(process.in.text.trim()) + fail("Failed to generate ${filename} with command: ${command.join(' ')}") + } +} + +def maybe_regen_source(final type, final filename) { + def file = new File(filename) + + if (file.exists()) { + def tmp_filename = filename + '.new' + def tmp_file = new File(tmp_filename) + + generate_source(type, tmp_filename) + old_md5 = md5(file) + new_md5 = md5(tmp_file) + + if (old_md5 == new_md5) { + tmp_file.delete() + } else { + tmp_file.renameTo(file) + } + } else { + generate_source(type, filename) + } + +} + +maybe_regen_source('header', properties['header']) +maybe_regen_source('body', properties['body']) diff --git a/src/main/scripts/manage_test_broker.groovy b/src/main/scripts/manage_test_broker.groovy new file mode 100644 index 0000000000..943e56170e --- /dev/null +++ b/src/main/scripts/manage_test_broker.groovy @@ -0,0 +1,65 @@ +String[] command + +def nodename = properties['nodename'] +if (nodename == null || nodename.length() == 0) { + fail("Node name required") +} + +switch (mojo.getExecutionId()) { +case ~/^start-test-broker-.*/: + def node_port = properties['node_port'] + if (node_port == null || node_port.length() == 0) { + fail("Node TCP port required") + } + + command = [ + properties['make.bin'], + '-C', properties['rabbitmq.dir'], + '--no-print-directory', + 'virgin-node-tmpdir', + 'start-background-broker', + "DEPS_DIR=${properties['deps.dir']}", + "RABBITMQ_NODENAME=${nodename}", + "RABBITMQ_NODE_PORT=${node_port}", + "RABBITMQ_CONFIG_FILE=${project.build.directory}/test-classes/${nodename}" + ] + break + +case ~/^create-test-cluster$/: + def target = properties['target'] + if (target == null || target.length() == 0) { + fail("Target node name required") + } + + command = [ + properties['make.bin'], + '-C', properties['rabbitmq.dir'], + '--no-print-directory', + 'cluster-other-node', + "DEPS_DIR=${properties['deps.dir']}", + "OTHER_NODE=${nodename}", + "MAIN_NODE=${target}" + ] + break + +case ~/^stop-test-broker-.*/: + command = [ + properties['make.bin'], + '-C', properties['rabbitmq.dir'], + '--no-print-directory', + 'stop-node', + "DEPS_DIR=${properties['deps.dir']}", + "RABBITMQ_NODENAME=${nodename}" + ] + break +} + +def pb = new ProcessBuilder(command) +pb.redirectErrorStream(true) + +def process = pb.start() +process.waitFor() +if (process.exitValue() != 0) { + println(process.in.text.trim()) + fail("Failed to manage broker '${nodename}' with command: ${command.join(' ')}") +} diff --git a/src/main/scripts/query_test_tls_certs_dir.groovy b/src/main/scripts/query_test_tls_certs_dir.groovy new file mode 100644 index 0000000000..2c86bb8c10 --- /dev/null +++ b/src/main/scripts/query_test_tls_certs_dir.groovy @@ -0,0 +1,25 @@ +String[] command = [ + properties['make.bin'], + '-C', properties['rabbitmq.dir'], + '--no-print-directory', + 'show-test-tls-certs-dir', + "DEPS_DIR=${properties['deps.dir']}", +] + +def pb = new ProcessBuilder(command) +pb.redirectErrorStream(true) + +def process = pb.start() + +// We are only interested in the last line of output. Previous lines, if +// any, are related to the generation of the test certificates. +def whole_output = "" +process.inputStream.eachLine { + whole_output += it + project.properties['test-tls-certs.dir'] = it.trim() +} +process.waitFor() +if (process.exitValue() != 0) { + println(whole_output.trim()) + fail("Failed to query test TLS certs directory with command: ${command.join(' ')}") +} diff --git a/src/main/scripts/remove_old_test_keystores.groovy b/src/main/scripts/remove_old_test_keystores.groovy new file mode 100644 index 0000000000..e08775e4e0 --- /dev/null +++ b/src/main/scripts/remove_old_test_keystores.groovy @@ -0,0 +1,8 @@ +def dir = new File(project.build.directory) + +// This pattern starts with `.*`. This is normally useless and even +// inefficient but the matching doesn't work without it... +def pattern = ~/.*\.keystore$/ +dir.eachFileMatch(pattern) { file -> + file.delete() +} diff --git a/test/src/com/rabbitmq/client/impl/WorkPoolTests.java b/src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java similarity index 100% rename from test/src/com/rabbitmq/client/impl/WorkPoolTests.java rename to src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java diff --git a/test/src/com/rabbitmq/client/test/AMQBuilderApiTest.java b/src/test/java/com/rabbitmq/client/test/AMQBuilderApiTest.java similarity index 100% rename from test/src/com/rabbitmq/client/test/AMQBuilderApiTest.java rename to src/test/java/com/rabbitmq/client/test/AMQBuilderApiTest.java diff --git a/test/src/com/rabbitmq/client/test/AMQConnectionTest.java b/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java similarity index 100% rename from test/src/com/rabbitmq/client/test/AMQConnectionTest.java rename to src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java diff --git a/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java b/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java new file mode 100644 index 0000000000..1937e074c5 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java @@ -0,0 +1,126 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.test; + +import java.io.File; +import java.io.IOException; +import java.net.Socket; +import java.util.Properties; + +import junit.framework.Test; +import junit.framework.TestResult; +import junit.framework.TestSuite; + +import com.rabbitmq.tools.Host; + +public abstract class AbstractRMQTestSuite extends TestSuite { + private static final String DEFAULT_SSL_HOSTNAME = "localhost"; + private static final int DEFAULT_SSL_PORT = 5671; + + private static boolean buildSSLPropertiesFound = false; + + static { + Properties TESTS_PROPS = new Properties(System.getProperties()); + String make = System.getenv("MAKE"); + if (make != null) + TESTS_PROPS.setProperty("make.bin", make); + try { + TESTS_PROPS.load(Host.class.getClassLoader().getResourceAsStream("config.properties")); + } catch (Exception e) { + System.out.println( + "\"build.properties\" or \"config.properties\" not found" + + " in classpath. Please copy \"build.properties\" and" + + " \"config.properties\" into src/test/resources. Ignore" + + " this message if running with ant."); + } finally { + System.setProperties(TESTS_PROPS); + } + } + + public static boolean requiredProperties() { + /* GNU Make. */ + String make = Host.makeCommand(); + boolean isGNUMake = false; + if (make != null) { + try { + Process makeProc = Host.executeCommandIgnoringErrors(make + " --version"); + String makeVersion = Host.capture(makeProc.getInputStream()); + isGNUMake = makeVersion.startsWith("GNU Make"); + } catch (IOException e) {} + } + if (!isGNUMake) { + System.err.println( + "GNU Make required; please set \"make.bin\" system property" + + " or \"$MAKE\" environment variable"); + return false; + } + + /* Path to RabbitMQ. */ + String rabbitmq = Host.rabbitmqDir(); + if (rabbitmq == null || !new File(rabbitmq).isDirectory()) { + System.err.println( + "RabbitMQ required; please set \"rabbitmq.dir\" system" + + " property"); + return false; + } + + /* Path to rabbitmqctl. */ + String rabbitmqctl = Host.rabbitmqctlCommand(); + if (rabbitmqctl == null || !new File(rabbitmqctl).isFile()) { + System.err.println( + "rabbitmqctl required; please set \"rabbitmqctl.bin\" system" + + " property"); + return false; + } + + return true; + } + + public static boolean isUnderUmbrella() { + return new File("../../UMBRELLA.md").isFile(); + } + + public static boolean isSSLAvailable() { + String sslClientCertsDir = System.getProperty("test-client-cert.path"); + String hostname = System.getProperty("broker.hostname"); + String port = System.getProperty("broker.sslport"); + if (sslClientCertsDir == null || hostname == null || port == null) + return false; + + // If certificate is present and some server is listening on port 5671 + if (new File(sslClientCertsDir).exists() && + checkServerListening(hostname, Integer.parseInt(port))) { + return true; + } else + return false; + } + + private static boolean checkServerListening(String host, int port) { + Socket s = null; + try { + s = new Socket(host, port); + return true; + } catch (Exception e) { + return false; + } finally { + if (s != null) + try { + s.close(); + } catch (Exception e) { + } + } + } +} diff --git a/test/src/com/rabbitmq/client/test/AmqpUriTest.java b/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java similarity index 100% rename from test/src/com/rabbitmq/client/test/AmqpUriTest.java rename to src/test/java/com/rabbitmq/client/test/AmqpUriTest.java diff --git a/test/src/com/rabbitmq/client/test/BlockingCellTest.java b/src/test/java/com/rabbitmq/client/test/BlockingCellTest.java similarity index 100% rename from test/src/com/rabbitmq/client/test/BlockingCellTest.java rename to src/test/java/com/rabbitmq/client/test/BlockingCellTest.java diff --git a/test/src/com/rabbitmq/client/test/BrokenFramesTest.java b/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java similarity index 100% rename from test/src/com/rabbitmq/client/test/BrokenFramesTest.java rename to src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java diff --git a/test/src/com/rabbitmq/client/test/BrokerTestCase.java b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java similarity index 99% rename from test/src/com/rabbitmq/client/test/BrokerTestCase.java rename to src/test/java/com/rabbitmq/client/test/BrokerTestCase.java index 3f8316b4c4..60edba206b 100644 --- a/test/src/com/rabbitmq/client/test/BrokerTestCase.java +++ b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java @@ -99,7 +99,8 @@ protected void restart() protected void bareRestart() throws IOException { - Host.invokeMakeTarget("restart-app"); + Host.invokeMakeTarget( + "stop-rabbit-on-node start-rabbit-on-node"); } public void openConnection() diff --git a/test/src/com/rabbitmq/client/test/Bug20004Test.java b/src/test/java/com/rabbitmq/client/test/Bug20004Test.java similarity index 100% rename from test/src/com/rabbitmq/client/test/Bug20004Test.java rename to src/test/java/com/rabbitmq/client/test/Bug20004Test.java diff --git a/test/src/com/rabbitmq/client/test/ChannelNumberAllocationTests.java b/src/test/java/com/rabbitmq/client/test/ChannelNumberAllocationTests.java similarity index 100% rename from test/src/com/rabbitmq/client/test/ChannelNumberAllocationTests.java rename to src/test/java/com/rabbitmq/client/test/ChannelNumberAllocationTests.java diff --git a/test/src/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java similarity index 96% rename from test/src/com/rabbitmq/client/test/ClientTests.java rename to src/test/java/com/rabbitmq/client/test/ClientTests.java index 077e478ec4..b7d75d0d9b 100644 --- a/test/src/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -16,10 +16,10 @@ package com.rabbitmq.client.test; -import junit.framework.TestCase; import junit.framework.TestSuite; -public class ClientTests extends TestCase { +public class ClientTests extends AbstractRMQTestSuite { + public static TestSuite suite() { TestSuite suite = new TestSuite("client"); suite.addTest(TableTest.suite()); diff --git a/test/src/com/rabbitmq/client/test/ClonePropertiesTest.java b/src/test/java/com/rabbitmq/client/test/ClonePropertiesTest.java similarity index 100% rename from test/src/com/rabbitmq/client/test/ClonePropertiesTest.java rename to src/test/java/com/rabbitmq/client/test/ClonePropertiesTest.java diff --git a/test/src/com/rabbitmq/client/test/CloseInMainLoop.java b/src/test/java/com/rabbitmq/client/test/CloseInMainLoop.java similarity index 100% rename from test/src/com/rabbitmq/client/test/CloseInMainLoop.java rename to src/test/java/com/rabbitmq/client/test/CloseInMainLoop.java diff --git a/test/src/com/rabbitmq/client/test/ConfirmBase.java b/src/test/java/com/rabbitmq/client/test/ConfirmBase.java similarity index 100% rename from test/src/com/rabbitmq/client/test/ConfirmBase.java rename to src/test/java/com/rabbitmq/client/test/ConfirmBase.java diff --git a/test/src/com/rabbitmq/client/test/JSONReadWriteTest.java b/src/test/java/com/rabbitmq/client/test/JSONReadWriteTest.java similarity index 100% rename from test/src/com/rabbitmq/client/test/JSONReadWriteTest.java rename to src/test/java/com/rabbitmq/client/test/JSONReadWriteTest.java diff --git a/test/src/com/rabbitmq/client/test/LongStringTest.java b/src/test/java/com/rabbitmq/client/test/LongStringTest.java similarity index 100% rename from test/src/com/rabbitmq/client/test/LongStringTest.java rename to src/test/java/com/rabbitmq/client/test/LongStringTest.java diff --git a/test/src/com/rabbitmq/client/test/MultiThreadedChannel.java b/src/test/java/com/rabbitmq/client/test/MultiThreadedChannel.java similarity index 100% rename from test/src/com/rabbitmq/client/test/MultiThreadedChannel.java rename to src/test/java/com/rabbitmq/client/test/MultiThreadedChannel.java diff --git a/test/src/com/rabbitmq/client/test/QueueingConsumerShutdownTests.java b/src/test/java/com/rabbitmq/client/test/QueueingConsumerShutdownTests.java similarity index 100% rename from test/src/com/rabbitmq/client/test/QueueingConsumerShutdownTests.java rename to src/test/java/com/rabbitmq/client/test/QueueingConsumerShutdownTests.java diff --git a/test/src/com/rabbitmq/client/test/SharedThreadPoolTest.java b/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java similarity index 100% rename from test/src/com/rabbitmq/client/test/SharedThreadPoolTest.java rename to src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java diff --git a/test/src/com/rabbitmq/client/test/TableTest.java b/src/test/java/com/rabbitmq/client/test/TableTest.java similarity index 100% rename from test/src/com/rabbitmq/client/test/TableTest.java rename to src/test/java/com/rabbitmq/client/test/TableTest.java diff --git a/test/src/com/rabbitmq/client/test/TruncatedInputStreamTest.java b/src/test/java/com/rabbitmq/client/test/TruncatedInputStreamTest.java similarity index 100% rename from test/src/com/rabbitmq/client/test/TruncatedInputStreamTest.java rename to src/test/java/com/rabbitmq/client/test/TruncatedInputStreamTest.java diff --git a/test/src/com/rabbitmq/client/test/ValueOrExceptionTest.java b/src/test/java/com/rabbitmq/client/test/ValueOrExceptionTest.java similarity index 100% rename from test/src/com/rabbitmq/client/test/ValueOrExceptionTest.java rename to src/test/java/com/rabbitmq/client/test/ValueOrExceptionTest.java diff --git a/test/src/com/rabbitmq/client/test/functional/AbstractRejectTest.java b/src/test/java/com/rabbitmq/client/test/functional/AbstractRejectTest.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/AbstractRejectTest.java rename to src/test/java/com/rabbitmq/client/test/functional/AbstractRejectTest.java diff --git a/test/src/com/rabbitmq/client/test/functional/AlternateExchange.java b/src/test/java/com/rabbitmq/client/test/functional/AlternateExchange.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/AlternateExchange.java rename to src/test/java/com/rabbitmq/client/test/functional/AlternateExchange.java diff --git a/test/src/com/rabbitmq/client/test/functional/BasicGet.java b/src/test/java/com/rabbitmq/client/test/functional/BasicGet.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/BasicGet.java rename to src/test/java/com/rabbitmq/client/test/functional/BasicGet.java diff --git a/test/src/com/rabbitmq/client/test/functional/BindingLifecycle.java b/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/BindingLifecycle.java rename to src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java diff --git a/test/src/com/rabbitmq/client/test/functional/BindingLifecycleBase.java b/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycleBase.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/BindingLifecycleBase.java rename to src/test/java/com/rabbitmq/client/test/functional/BindingLifecycleBase.java diff --git a/test/src/com/rabbitmq/client/test/functional/CcRoutes.java b/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/CcRoutes.java rename to src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java diff --git a/test/src/com/rabbitmq/client/test/functional/ClusteredTestBase.java b/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java similarity index 95% rename from test/src/com/rabbitmq/client/test/functional/ClusteredTestBase.java rename to src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java index 6f71533679..c198db8bd0 100644 --- a/test/src/com/rabbitmq/client/test/functional/ClusteredTestBase.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java @@ -124,10 +124,10 @@ public void closeConnection() throws IOException { } protected void stopSecondary() throws IOException { - Host.invokeMakeTarget("stop-secondary-app"); + Host.invokeMakeTarget("stop-rabbit-on-node RABBITMQ_NODENAME=\'" + Host.nodenameB() + "\'"); } protected void startSecondary() throws IOException { - Host.invokeMakeTarget("start-secondary-app"); + Host.invokeMakeTarget("start-rabbit-on-node RABBITMQ_NODENAME=\'" + Host.nodenameB() + "\'"); } } diff --git a/test/src/com/rabbitmq/client/test/functional/Confirm.java b/src/test/java/com/rabbitmq/client/test/functional/Confirm.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/Confirm.java rename to src/test/java/com/rabbitmq/client/test/functional/Confirm.java diff --git a/test/src/com/rabbitmq/client/test/functional/ConnectionOpen.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionOpen.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/ConnectionOpen.java rename to src/test/java/com/rabbitmq/client/test/functional/ConnectionOpen.java diff --git a/test/src/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/ConnectionRecovery.java rename to src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java diff --git a/test/src/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java b/src/test/java/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java rename to src/test/java/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java diff --git a/test/src/com/rabbitmq/client/test/functional/ConsumerCount.java b/src/test/java/com/rabbitmq/client/test/functional/ConsumerCount.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/ConsumerCount.java rename to src/test/java/com/rabbitmq/client/test/functional/ConsumerCount.java diff --git a/test/src/com/rabbitmq/client/test/functional/ConsumerPriorities.java b/src/test/java/com/rabbitmq/client/test/functional/ConsumerPriorities.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/ConsumerPriorities.java rename to src/test/java/com/rabbitmq/client/test/functional/ConsumerPriorities.java diff --git a/test/src/com/rabbitmq/client/test/functional/DeadLetterExchange.java b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/DeadLetterExchange.java rename to src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java diff --git a/test/src/com/rabbitmq/client/test/functional/DefaultExchange.java b/src/test/java/com/rabbitmq/client/test/functional/DefaultExchange.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/DefaultExchange.java rename to src/test/java/com/rabbitmq/client/test/functional/DefaultExchange.java diff --git a/test/src/com/rabbitmq/client/test/functional/DirectReplyTo.java b/src/test/java/com/rabbitmq/client/test/functional/DirectReplyTo.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/DirectReplyTo.java rename to src/test/java/com/rabbitmq/client/test/functional/DirectReplyTo.java diff --git a/test/src/com/rabbitmq/client/test/functional/DoubleDeletion.java b/src/test/java/com/rabbitmq/client/test/functional/DoubleDeletion.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/DoubleDeletion.java rename to src/test/java/com/rabbitmq/client/test/functional/DoubleDeletion.java diff --git a/test/src/com/rabbitmq/client/test/functional/DurableOnTransient.java b/src/test/java/com/rabbitmq/client/test/functional/DurableOnTransient.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/DurableOnTransient.java rename to src/test/java/com/rabbitmq/client/test/functional/DurableOnTransient.java diff --git a/test/src/com/rabbitmq/client/test/functional/ExceptionHandling.java b/src/test/java/com/rabbitmq/client/test/functional/ExceptionHandling.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/ExceptionHandling.java rename to src/test/java/com/rabbitmq/client/test/functional/ExceptionHandling.java diff --git a/test/src/com/rabbitmq/client/test/functional/ExceptionMessages.java b/src/test/java/com/rabbitmq/client/test/functional/ExceptionMessages.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/ExceptionMessages.java rename to src/test/java/com/rabbitmq/client/test/functional/ExceptionMessages.java diff --git a/test/src/com/rabbitmq/client/test/functional/ExchangeDeclare.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/ExchangeDeclare.java rename to src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java diff --git a/test/src/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java rename to src/test/java/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java diff --git a/test/src/com/rabbitmq/client/test/functional/ExchangeDeletePredeclared.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeletePredeclared.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/ExchangeDeletePredeclared.java rename to src/test/java/com/rabbitmq/client/test/functional/ExchangeDeletePredeclared.java diff --git a/test/src/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java rename to src/test/java/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java diff --git a/test/src/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java rename to src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java diff --git a/test/src/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java rename to src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java diff --git a/test/src/com/rabbitmq/client/test/functional/FrameMax.java b/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/FrameMax.java rename to src/test/java/com/rabbitmq/client/test/functional/FrameMax.java diff --git a/test/src/com/rabbitmq/client/test/functional/FunctionalTests.java b/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java similarity index 95% rename from test/src/com/rabbitmq/client/test/functional/FunctionalTests.java rename to src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java index d99927e908..8c785982bd 100644 --- a/test/src/com/rabbitmq/client/test/functional/FunctionalTests.java +++ b/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java @@ -17,14 +17,16 @@ package com.rabbitmq.client.test.functional; import com.rabbitmq.client.impl.WorkPoolTests; +import com.rabbitmq.client.test.AbstractRMQTestSuite; import com.rabbitmq.client.test.Bug20004Test; import junit.framework.TestCase; import junit.framework.TestSuite; -public class FunctionalTests extends TestCase { +public class FunctionalTests extends AbstractRMQTestSuite { public static TestSuite suite() { TestSuite suite = new TestSuite("functional"); + if (!requiredProperties()) return suite; add(suite); return suite; } diff --git a/test/src/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java b/src/test/java/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java rename to src/test/java/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java diff --git a/test/src/com/rabbitmq/client/test/functional/Heartbeat.java b/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/Heartbeat.java rename to src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java diff --git a/test/src/com/rabbitmq/client/test/functional/InternalExchange.java b/src/test/java/com/rabbitmq/client/test/functional/InternalExchange.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/InternalExchange.java rename to src/test/java/com/rabbitmq/client/test/functional/InternalExchange.java diff --git a/test/src/com/rabbitmq/client/test/functional/InvalidAcks.java b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcks.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/InvalidAcks.java rename to src/test/java/com/rabbitmq/client/test/functional/InvalidAcks.java diff --git a/test/src/com/rabbitmq/client/test/functional/InvalidAcksBase.java b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksBase.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/InvalidAcksBase.java rename to src/test/java/com/rabbitmq/client/test/functional/InvalidAcksBase.java diff --git a/test/src/com/rabbitmq/client/test/functional/InvalidAcksTx.java b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksTx.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/InvalidAcksTx.java rename to src/test/java/com/rabbitmq/client/test/functional/InvalidAcksTx.java diff --git a/test/src/com/rabbitmq/client/test/functional/MessageCount.java b/src/test/java/com/rabbitmq/client/test/functional/MessageCount.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/MessageCount.java rename to src/test/java/com/rabbitmq/client/test/functional/MessageCount.java diff --git a/test/src/com/rabbitmq/client/test/functional/Nack.java b/src/test/java/com/rabbitmq/client/test/functional/Nack.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/Nack.java rename to src/test/java/com/rabbitmq/client/test/functional/Nack.java diff --git a/test/src/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java b/src/test/java/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java rename to src/test/java/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java diff --git a/test/src/com/rabbitmq/client/test/functional/Nowait.java b/src/test/java/com/rabbitmq/client/test/functional/Nowait.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/Nowait.java rename to src/test/java/com/rabbitmq/client/test/functional/Nowait.java diff --git a/test/src/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java b/src/test/java/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java rename to src/test/java/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java diff --git a/test/src/com/rabbitmq/client/test/functional/PerMessageTTL.java b/src/test/java/com/rabbitmq/client/test/functional/PerMessageTTL.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/PerMessageTTL.java rename to src/test/java/com/rabbitmq/client/test/functional/PerMessageTTL.java diff --git a/test/src/com/rabbitmq/client/test/functional/PerQueueTTL.java b/src/test/java/com/rabbitmq/client/test/functional/PerQueueTTL.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/PerQueueTTL.java rename to src/test/java/com/rabbitmq/client/test/functional/PerQueueTTL.java diff --git a/test/src/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java b/src/test/java/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java rename to src/test/java/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java diff --git a/test/src/com/rabbitmq/client/test/functional/Policies.java b/src/test/java/com/rabbitmq/client/test/functional/Policies.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/Policies.java rename to src/test/java/com/rabbitmq/client/test/functional/Policies.java diff --git a/test/src/com/rabbitmq/client/test/functional/QosTests.java b/src/test/java/com/rabbitmq/client/test/functional/QosTests.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/QosTests.java rename to src/test/java/com/rabbitmq/client/test/functional/QosTests.java diff --git a/test/src/com/rabbitmq/client/test/functional/QueueExclusivity.java b/src/test/java/com/rabbitmq/client/test/functional/QueueExclusivity.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/QueueExclusivity.java rename to src/test/java/com/rabbitmq/client/test/functional/QueueExclusivity.java diff --git a/test/src/com/rabbitmq/client/test/functional/QueueLease.java b/src/test/java/com/rabbitmq/client/test/functional/QueueLease.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/QueueLease.java rename to src/test/java/com/rabbitmq/client/test/functional/QueueLease.java diff --git a/test/src/com/rabbitmq/client/test/functional/QueueLifecycle.java b/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/QueueLifecycle.java rename to src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java diff --git a/test/src/com/rabbitmq/client/test/functional/QueueSizeLimit.java b/src/test/java/com/rabbitmq/client/test/functional/QueueSizeLimit.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/QueueSizeLimit.java rename to src/test/java/com/rabbitmq/client/test/functional/QueueSizeLimit.java diff --git a/test/src/com/rabbitmq/client/test/functional/Recover.java b/src/test/java/com/rabbitmq/client/test/functional/Recover.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/Recover.java rename to src/test/java/com/rabbitmq/client/test/functional/Recover.java diff --git a/test/src/com/rabbitmq/client/test/functional/Reject.java b/src/test/java/com/rabbitmq/client/test/functional/Reject.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/Reject.java rename to src/test/java/com/rabbitmq/client/test/functional/Reject.java diff --git a/test/src/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java rename to src/test/java/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java diff --git a/test/src/com/rabbitmq/client/test/functional/RequeueOnClose.java b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnClose.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/RequeueOnClose.java rename to src/test/java/com/rabbitmq/client/test/functional/RequeueOnClose.java diff --git a/test/src/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java rename to src/test/java/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java diff --git a/test/src/com/rabbitmq/client/test/functional/Routing.java b/src/test/java/com/rabbitmq/client/test/functional/Routing.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/Routing.java rename to src/test/java/com/rabbitmq/client/test/functional/Routing.java diff --git a/test/src/com/rabbitmq/client/test/functional/SaslMechanisms.java b/src/test/java/com/rabbitmq/client/test/functional/SaslMechanisms.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/SaslMechanisms.java rename to src/test/java/com/rabbitmq/client/test/functional/SaslMechanisms.java diff --git a/test/src/com/rabbitmq/client/test/functional/TTLHandling.java b/src/test/java/com/rabbitmq/client/test/functional/TTLHandling.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/TTLHandling.java rename to src/test/java/com/rabbitmq/client/test/functional/TTLHandling.java diff --git a/test/src/com/rabbitmq/client/test/functional/Tables.java b/src/test/java/com/rabbitmq/client/test/functional/Tables.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/Tables.java rename to src/test/java/com/rabbitmq/client/test/functional/Tables.java diff --git a/test/src/com/rabbitmq/client/test/functional/Transactions.java b/src/test/java/com/rabbitmq/client/test/functional/Transactions.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/Transactions.java rename to src/test/java/com/rabbitmq/client/test/functional/Transactions.java diff --git a/test/src/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java b/src/test/java/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java rename to src/test/java/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java diff --git a/test/src/com/rabbitmq/client/test/functional/UnexpectedFrames.java b/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/UnexpectedFrames.java rename to src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java diff --git a/test/src/com/rabbitmq/client/test/functional/UserIDHeader.java b/src/test/java/com/rabbitmq/client/test/functional/UserIDHeader.java similarity index 100% rename from test/src/com/rabbitmq/client/test/functional/UserIDHeader.java rename to src/test/java/com/rabbitmq/client/test/functional/UserIDHeader.java diff --git a/test/src/com/rabbitmq/client/test/performance/CLIHelper.java b/src/test/java/com/rabbitmq/client/test/performance/CLIHelper.java similarity index 100% rename from test/src/com/rabbitmq/client/test/performance/CLIHelper.java rename to src/test/java/com/rabbitmq/client/test/performance/CLIHelper.java diff --git a/test/src/com/rabbitmq/client/test/performance/QosScaling.java b/src/test/java/com/rabbitmq/client/test/performance/QosScaling.java similarity index 100% rename from test/src/com/rabbitmq/client/test/performance/QosScaling.java rename to src/test/java/com/rabbitmq/client/test/performance/QosScaling.java diff --git a/test/src/com/rabbitmq/client/test/performance/ScalabilityTest.java b/src/test/java/com/rabbitmq/client/test/performance/ScalabilityTest.java similarity index 100% rename from test/src/com/rabbitmq/client/test/performance/ScalabilityTest.java rename to src/test/java/com/rabbitmq/client/test/performance/ScalabilityTest.java diff --git a/test/src/com/rabbitmq/client/test/performance/StressManagement.java b/src/test/java/com/rabbitmq/client/test/performance/StressManagement.java similarity index 100% rename from test/src/com/rabbitmq/client/test/performance/StressManagement.java rename to src/test/java/com/rabbitmq/client/test/performance/StressManagement.java diff --git a/test/src/com/rabbitmq/client/test/server/AbsentQueue.java b/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java similarity index 100% rename from test/src/com/rabbitmq/client/test/server/AbsentQueue.java rename to src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java diff --git a/test/src/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java b/src/test/java/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java similarity index 100% rename from test/src/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java rename to src/test/java/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java diff --git a/test/src/com/rabbitmq/client/test/server/BlockedConnection.java b/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java similarity index 100% rename from test/src/com/rabbitmq/client/test/server/BlockedConnection.java rename to src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java diff --git a/test/src/com/rabbitmq/client/test/server/Bug19219Test.java b/src/test/java/com/rabbitmq/client/test/server/Bug19219Test.java similarity index 100% rename from test/src/com/rabbitmq/client/test/server/Bug19219Test.java rename to src/test/java/com/rabbitmq/client/test/server/Bug19219Test.java diff --git a/test/src/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java b/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java similarity index 100% rename from test/src/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java rename to src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java diff --git a/test/src/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java b/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java similarity index 96% rename from test/src/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java rename to src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java index 510fb403ea..5c1c65d939 100644 --- a/test/src/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java +++ b/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java @@ -54,9 +54,9 @@ public void testDeadLetterQueueTTLExpiredWhileDown() throws Exception { } closeConnection(); - Host.invokeMakeTarget("stop-app"); + Host.invokeMakeTarget("stop-rabbit-on-node"); Thread.sleep(5000); - Host.invokeMakeTarget("start-app"); + Host.invokeMakeTarget("start-rabbit-on-node"); openConnection(); openChannel(); diff --git a/test/src/com/rabbitmq/client/test/server/DurableBindingLifecycle.java b/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java similarity index 94% rename from test/src/com/rabbitmq/client/test/server/DurableBindingLifecycle.java rename to src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java index 64507360b6..f484d1f49e 100644 --- a/test/src/com/rabbitmq/client/test/server/DurableBindingLifecycle.java +++ b/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java @@ -44,7 +44,13 @@ protected void restart() throws IOException, TimeoutException { alternateConnection = null; alternateChannel = null; - Host.invokeMakeTarget("restart-secondary-node"); + Host.invokeMakeTarget( + "stop-node" + + " start-background-broker" + + " RABBITMQ_NODENAME=\'" + Host.nodenameB() + "\'" + + " RABBITMQ_NODE_PORT=" + Host.node_portB() + + " RABBITMQ_CONFIG_FILE=\'" + Host.config_fileB() + "\'" + ); } restartPrimary(); } diff --git a/test/src/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java b/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java similarity index 100% rename from test/src/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java rename to src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java diff --git a/test/src/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java b/src/test/java/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java similarity index 100% rename from test/src/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java rename to src/test/java/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java diff --git a/test/src/com/rabbitmq/client/test/server/Firehose.java b/src/test/java/com/rabbitmq/client/test/server/Firehose.java similarity index 100% rename from test/src/com/rabbitmq/client/test/server/Firehose.java rename to src/test/java/com/rabbitmq/client/test/server/Firehose.java diff --git a/test/src/com/rabbitmq/client/test/server/HATests.java b/src/test/java/com/rabbitmq/client/test/server/HATests.java similarity index 87% rename from test/src/com/rabbitmq/client/test/server/HATests.java rename to src/test/java/com/rabbitmq/client/test/server/HATests.java index c1eaa47d42..bcb6ec6a0d 100644 --- a/test/src/com/rabbitmq/client/test/server/HATests.java +++ b/src/test/java/com/rabbitmq/client/test/server/HATests.java @@ -15,17 +15,20 @@ package com.rabbitmq.client.test.server; -import com.rabbitmq.client.test.functional.FunctionalTests; -import com.rabbitmq.tools.Host; import junit.framework.TestCase; import junit.framework.TestSuite; -public class HATests extends TestSuite { +import com.rabbitmq.client.test.AbstractRMQTestSuite; +import com.rabbitmq.client.test.functional.FunctionalTests; +import com.rabbitmq.tools.Host; + +public class HATests extends AbstractRMQTestSuite { // this is horrific public static boolean HA_TESTS_RUNNING = false; public static TestSuite suite() { TestSuite suite = new TestSuite("server-tests"); + if (!requiredProperties()) return suite; suite.addTestSuite(SetUp.class); FunctionalTests.add(suite); ServerTests.add(suite); @@ -39,7 +42,7 @@ public static TestSuite suite() { public static class SetUp extends TestCase { @Override protected void setUp() throws Exception { - Host.invokeMakeTarget("enable-ha"); + Host.rabbitmqctl("set_policy HA '.*' '{\"ha-mode\":\"all\"}'"); HA_TESTS_RUNNING = true; } @@ -49,7 +52,7 @@ public void testNothing() {} public static class TearDown extends TestCase { @Override protected void tearDown() throws Exception { - Host.invokeMakeTarget("disable-ha"); + Host.rabbitmqctl("clear_policy HA"); HA_TESTS_RUNNING = false; } diff --git a/test/src/com/rabbitmq/client/test/server/LoopbackUsers.java b/src/test/java/com/rabbitmq/client/test/server/LoopbackUsers.java similarity index 100% rename from test/src/com/rabbitmq/client/test/server/LoopbackUsers.java rename to src/test/java/com/rabbitmq/client/test/server/LoopbackUsers.java diff --git a/test/src/com/rabbitmq/client/test/server/MemoryAlarms.java b/src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java similarity index 100% rename from test/src/com/rabbitmq/client/test/server/MemoryAlarms.java rename to src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java diff --git a/test/src/com/rabbitmq/client/test/server/MessageRecovery.java b/src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java similarity index 100% rename from test/src/com/rabbitmq/client/test/server/MessageRecovery.java rename to src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java diff --git a/test/src/com/rabbitmq/client/test/server/Permissions.java b/src/test/java/com/rabbitmq/client/test/server/Permissions.java similarity index 100% rename from test/src/com/rabbitmq/client/test/server/Permissions.java rename to src/test/java/com/rabbitmq/client/test/server/Permissions.java diff --git a/test/src/com/rabbitmq/client/test/server/PersistenceGuarantees.java b/src/test/java/com/rabbitmq/client/test/server/PersistenceGuarantees.java similarity index 100% rename from test/src/com/rabbitmq/client/test/server/PersistenceGuarantees.java rename to src/test/java/com/rabbitmq/client/test/server/PersistenceGuarantees.java diff --git a/test/src/com/rabbitmq/client/test/server/PriorityQueues.java b/src/test/java/com/rabbitmq/client/test/server/PriorityQueues.java similarity index 100% rename from test/src/com/rabbitmq/client/test/server/PriorityQueues.java rename to src/test/java/com/rabbitmq/client/test/server/PriorityQueues.java diff --git a/test/src/com/rabbitmq/client/test/server/ServerTests.java b/src/test/java/com/rabbitmq/client/test/server/ServerTests.java similarity index 92% rename from test/src/com/rabbitmq/client/test/server/ServerTests.java rename to src/test/java/com/rabbitmq/client/test/server/ServerTests.java index 48bec5479b..4250e9bea1 100644 --- a/test/src/com/rabbitmq/client/test/server/ServerTests.java +++ b/src/test/java/com/rabbitmq/client/test/server/ServerTests.java @@ -16,12 +16,15 @@ package com.rabbitmq.client.test.server; -import junit.framework.TestCase; import junit.framework.TestSuite; -public class ServerTests extends TestCase { +import com.rabbitmq.client.test.AbstractRMQTestSuite; + +public class ServerTests extends AbstractRMQTestSuite { + public static TestSuite suite() { TestSuite suite = new TestSuite("server-tests"); + if (!requiredProperties()) return suite; add(suite); return suite; } diff --git a/test/src/com/rabbitmq/client/test/server/Shutdown.java b/src/test/java/com/rabbitmq/client/test/server/Shutdown.java similarity index 100% rename from test/src/com/rabbitmq/client/test/server/Shutdown.java rename to src/test/java/com/rabbitmq/client/test/server/Shutdown.java diff --git a/test/src/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java b/src/test/java/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java similarity index 100% rename from test/src/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java rename to src/test/java/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java diff --git a/test/src/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java similarity index 91% rename from test/src/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java rename to src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java index 957e384881..3026fe547a 100644 --- a/test/src/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java @@ -40,9 +40,9 @@ public class BadVerifiedConnection extends UnverifiedConnection { public void openConnection() throws IOException, TimeoutException { try { - String keystorePath = System.getProperty("keystore.empty.path"); + String keystorePath = System.getProperty("test-keystore.empty"); assertNotNull(keystorePath); - String keystorePasswd = System.getProperty("keystore.passwd"); + String keystorePasswd = System.getProperty("test-keystore.password"); assertNotNull(keystorePasswd); char [] keystorePassword = keystorePasswd.toCharArray(); @@ -52,9 +52,9 @@ public void openConnection() TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); tmf.init(tks); - String p12Path = System.getProperty("p12.path"); + String p12Path = System.getProperty("test-client-cert.path"); assertNotNull(p12Path); - String p12Passwd = System.getProperty("p12.passwd"); + String p12Passwd = System.getProperty("test-client-cert.password"); assertNotNull(p12Passwd); KeyStore ks = KeyStore.getInstance("PKCS12"); char [] p12Password = p12Passwd.toCharArray(); diff --git a/test/src/com/rabbitmq/client/test/ssl/SSLTests.java b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java similarity index 80% rename from test/src/com/rabbitmq/client/test/ssl/SSLTests.java rename to src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java index 184805eb80..71d59f95a3 100644 --- a/test/src/com/rabbitmq/client/test/ssl/SSLTests.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java @@ -16,13 +16,17 @@ package com.rabbitmq.client.test.ssl; -import junit.framework.TestCase; import junit.framework.TestSuite; -public class SSLTests extends TestCase { +import com.rabbitmq.client.test.AbstractRMQTestSuite; + +public class SSLTests extends AbstractRMQTestSuite { public static TestSuite suite() { TestSuite suite = new TestSuite("ssl"); suite.addTestSuite(ConnectionFactoryDefaultTlsVersion.class); + // Skip the tests if not under umbrella and no TLS setup available + if (!requiredProperties()) return suite; + if (!isSSLAvailable()) return suite; suite.addTestSuite(UnverifiedConnection.class); suite.addTestSuite(VerifiedConnection.class); suite.addTestSuite(BadVerifiedConnection.class); diff --git a/test/src/com/rabbitmq/client/test/ssl/UnverifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java similarity index 100% rename from test/src/com/rabbitmq/client/test/ssl/UnverifiedConnection.java rename to src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java diff --git a/test/src/com/rabbitmq/client/test/ssl/VerifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java similarity index 91% rename from test/src/com/rabbitmq/client/test/ssl/VerifiedConnection.java rename to src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java index c12a3a2e66..645dec1104 100644 --- a/test/src/com/rabbitmq/client/test/ssl/VerifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java @@ -41,9 +41,9 @@ public class VerifiedConnection extends UnverifiedConnection { public void openConnection() throws IOException, TimeoutException { try { - String keystorePath = System.getProperty("keystore.path"); + String keystorePath = System.getProperty("test-keystore.ca"); assertNotNull(keystorePath); - String keystorePasswd = System.getProperty("keystore.passwd"); + String keystorePasswd = System.getProperty("test-keystore.password"); assertNotNull(keystorePasswd); char [] keystorePassword = keystorePasswd.toCharArray(); @@ -53,9 +53,9 @@ public void openConnection() TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); tmf.init(tks); - String p12Path = System.getProperty("p12.path"); + String p12Path = System.getProperty("test-client-cert.path"); assertNotNull(p12Path); - String p12Passwd = System.getProperty("p12.passwd"); + String p12Passwd = System.getProperty("test-client-cert.password"); assertNotNull(p12Passwd); KeyStore ks = KeyStore.getInstance("PKCS12"); char [] p12Password = p12Passwd.toCharArray(); diff --git a/test/src/com/rabbitmq/examples/BufferPerformanceMetrics.java b/src/test/java/com/rabbitmq/examples/BufferPerformanceMetrics.java similarity index 100% rename from test/src/com/rabbitmq/examples/BufferPerformanceMetrics.java rename to src/test/java/com/rabbitmq/examples/BufferPerformanceMetrics.java diff --git a/test/src/com/rabbitmq/examples/ChannelCreationPerformance.java b/src/test/java/com/rabbitmq/examples/ChannelCreationPerformance.java similarity index 100% rename from test/src/com/rabbitmq/examples/ChannelCreationPerformance.java rename to src/test/java/com/rabbitmq/examples/ChannelCreationPerformance.java diff --git a/test/src/com/rabbitmq/examples/ConfirmDontLoseMessages.java b/src/test/java/com/rabbitmq/examples/ConfirmDontLoseMessages.java similarity index 100% rename from test/src/com/rabbitmq/examples/ConfirmDontLoseMessages.java rename to src/test/java/com/rabbitmq/examples/ConfirmDontLoseMessages.java diff --git a/test/src/com/rabbitmq/examples/ConsumerMain.java b/src/test/java/com/rabbitmq/examples/ConsumerMain.java similarity index 100% rename from test/src/com/rabbitmq/examples/ConsumerMain.java rename to src/test/java/com/rabbitmq/examples/ConsumerMain.java diff --git a/test/src/com/rabbitmq/examples/DirectReplyToPerformance.java b/src/test/java/com/rabbitmq/examples/DirectReplyToPerformance.java similarity index 100% rename from test/src/com/rabbitmq/examples/DirectReplyToPerformance.java rename to src/test/java/com/rabbitmq/examples/DirectReplyToPerformance.java diff --git a/test/src/com/rabbitmq/examples/FileConsumer.java b/src/test/java/com/rabbitmq/examples/FileConsumer.java similarity index 100% rename from test/src/com/rabbitmq/examples/FileConsumer.java rename to src/test/java/com/rabbitmq/examples/FileConsumer.java diff --git a/test/src/com/rabbitmq/examples/FileProducer.java b/src/test/java/com/rabbitmq/examples/FileProducer.java similarity index 100% rename from test/src/com/rabbitmq/examples/FileProducer.java rename to src/test/java/com/rabbitmq/examples/FileProducer.java diff --git a/test/src/com/rabbitmq/examples/HelloClient.java b/src/test/java/com/rabbitmq/examples/HelloClient.java similarity index 100% rename from test/src/com/rabbitmq/examples/HelloClient.java rename to src/test/java/com/rabbitmq/examples/HelloClient.java diff --git a/test/src/com/rabbitmq/examples/HelloJsonClient.java b/src/test/java/com/rabbitmq/examples/HelloJsonClient.java similarity index 100% rename from test/src/com/rabbitmq/examples/HelloJsonClient.java rename to src/test/java/com/rabbitmq/examples/HelloJsonClient.java diff --git a/test/src/com/rabbitmq/examples/HelloJsonServer.java b/src/test/java/com/rabbitmq/examples/HelloJsonServer.java similarity index 100% rename from test/src/com/rabbitmq/examples/HelloJsonServer.java rename to src/test/java/com/rabbitmq/examples/HelloJsonServer.java diff --git a/test/src/com/rabbitmq/examples/HelloJsonService.java b/src/test/java/com/rabbitmq/examples/HelloJsonService.java similarity index 100% rename from test/src/com/rabbitmq/examples/HelloJsonService.java rename to src/test/java/com/rabbitmq/examples/HelloJsonService.java diff --git a/test/src/com/rabbitmq/examples/HelloServer.java b/src/test/java/com/rabbitmq/examples/HelloServer.java similarity index 100% rename from test/src/com/rabbitmq/examples/HelloServer.java rename to src/test/java/com/rabbitmq/examples/HelloServer.java diff --git a/test/src/com/rabbitmq/examples/LogTail.java b/src/test/java/com/rabbitmq/examples/LogTail.java similarity index 100% rename from test/src/com/rabbitmq/examples/LogTail.java rename to src/test/java/com/rabbitmq/examples/LogTail.java diff --git a/test/src/com/rabbitmq/examples/MulticastMain.java b/src/test/java/com/rabbitmq/examples/MulticastMain.java similarity index 100% rename from test/src/com/rabbitmq/examples/MulticastMain.java rename to src/test/java/com/rabbitmq/examples/MulticastMain.java diff --git a/test/src/com/rabbitmq/examples/PerQueueTTLGetter.java b/src/test/java/com/rabbitmq/examples/PerQueueTTLGetter.java similarity index 100% rename from test/src/com/rabbitmq/examples/PerQueueTTLGetter.java rename to src/test/java/com/rabbitmq/examples/PerQueueTTLGetter.java diff --git a/test/src/com/rabbitmq/examples/PerQueueTTLPublisher.java b/src/test/java/com/rabbitmq/examples/PerQueueTTLPublisher.java similarity index 100% rename from test/src/com/rabbitmq/examples/PerQueueTTLPublisher.java rename to src/test/java/com/rabbitmq/examples/PerQueueTTLPublisher.java diff --git a/test/src/com/rabbitmq/examples/PerfTest.java b/src/test/java/com/rabbitmq/examples/PerfTest.java similarity index 100% rename from test/src/com/rabbitmq/examples/PerfTest.java rename to src/test/java/com/rabbitmq/examples/PerfTest.java diff --git a/test/src/com/rabbitmq/examples/PerfTestMulti.java b/src/test/java/com/rabbitmq/examples/PerfTestMulti.java similarity index 100% rename from test/src/com/rabbitmq/examples/PerfTestMulti.java rename to src/test/java/com/rabbitmq/examples/PerfTestMulti.java diff --git a/test/src/com/rabbitmq/examples/ProducerMain.java b/src/test/java/com/rabbitmq/examples/ProducerMain.java similarity index 100% rename from test/src/com/rabbitmq/examples/ProducerMain.java rename to src/test/java/com/rabbitmq/examples/ProducerMain.java diff --git a/test/src/com/rabbitmq/examples/SendString.java b/src/test/java/com/rabbitmq/examples/SendString.java similarity index 100% rename from test/src/com/rabbitmq/examples/SendString.java rename to src/test/java/com/rabbitmq/examples/SendString.java diff --git a/test/src/com/rabbitmq/examples/SimpleConsumer.java b/src/test/java/com/rabbitmq/examples/SimpleConsumer.java similarity index 100% rename from test/src/com/rabbitmq/examples/SimpleConsumer.java rename to src/test/java/com/rabbitmq/examples/SimpleConsumer.java diff --git a/test/src/com/rabbitmq/examples/SimpleProducer.java b/src/test/java/com/rabbitmq/examples/SimpleProducer.java similarity index 100% rename from test/src/com/rabbitmq/examples/SimpleProducer.java rename to src/test/java/com/rabbitmq/examples/SimpleProducer.java diff --git a/test/src/com/rabbitmq/examples/SimpleTopicConsumer.java b/src/test/java/com/rabbitmq/examples/SimpleTopicConsumer.java similarity index 100% rename from test/src/com/rabbitmq/examples/SimpleTopicConsumer.java rename to src/test/java/com/rabbitmq/examples/SimpleTopicConsumer.java diff --git a/test/src/com/rabbitmq/examples/SimpleTopicProducer.java b/src/test/java/com/rabbitmq/examples/SimpleTopicProducer.java similarity index 100% rename from test/src/com/rabbitmq/examples/SimpleTopicProducer.java rename to src/test/java/com/rabbitmq/examples/SimpleTopicProducer.java diff --git a/test/src/com/rabbitmq/examples/SpammyTopicProducer.java b/src/test/java/com/rabbitmq/examples/SpammyTopicProducer.java similarity index 100% rename from test/src/com/rabbitmq/examples/SpammyTopicProducer.java rename to src/test/java/com/rabbitmq/examples/SpammyTopicProducer.java diff --git a/test/src/com/rabbitmq/examples/StressPersister.java b/src/test/java/com/rabbitmq/examples/StressPersister.java similarity index 100% rename from test/src/com/rabbitmq/examples/StressPersister.java rename to src/test/java/com/rabbitmq/examples/StressPersister.java diff --git a/test/src/com/rabbitmq/examples/TestMain.java b/src/test/java/com/rabbitmq/examples/TestMain.java similarity index 94% rename from test/src/com/rabbitmq/examples/TestMain.java rename to src/test/java/com/rabbitmq/examples/TestMain.java index 411730bc79..fc430d913c 100644 --- a/test/src/com/rabbitmq/examples/TestMain.java +++ b/src/test/java/com/rabbitmq/examples/TestMain.java @@ -41,26 +41,46 @@ import com.rabbitmq.client.impl.FrameHandler; import com.rabbitmq.client.impl.FrameHandlerFactory; import com.rabbitmq.client.impl.SocketFrameHandler; +import com.rabbitmq.client.test.AbstractRMQTestSuite; import com.rabbitmq.utility.BlockingCell; import javax.net.SocketFactory; +import org.junit.Test; +//FIXME needs to get the arguments from System.getProperty +//FIXME this test needs to be transform into Junit public class TestMain { - public static void main(String[] args) throws IOException, URISyntaxException { + //Ugly patch to initialize system properties + static{ + new AbstractRMQTestSuite(){}; + } + + static String URI = "amqp://localhost"; + + public static void main(String[] args) throws IOException, URISyntaxException { + if (args.length > 0) URI = args[0]; + new TestMain().test(); + } + + + @Test + public void test() throws IOException, URISyntaxException { // Show what version this class was compiled with, to check conformance testing Class clazz = TestMain.class; String javaVersion = System.getProperty("java.version"); System.out.println(clazz.getName() + " : javac v" + getCompilerVersion(clazz) + " on " + javaVersion); try { boolean silent = Boolean.getBoolean("silent"); - final String uri = (args.length > 0) ? args[0] : "amqp://localhost"; + final String uri = URI; runConnectionNegotiationTest(uri); final Connection conn = new ConnectionFactory(){{setUri(uri);}}.newConnection(); if (!silent) { System.out.println("Channel 0 fully open."); } - new TestMain(conn, silent).run(); + set_connection(conn); + set_silent(silent); + run(); runProducerConsumerTest(uri, 500); runProducerConsumerTest(uri, 0); @@ -217,19 +237,29 @@ public static void sleep(int ms) { } } - private final Connection _connection; + private Connection _connection; private Channel _ch1; private int _messageId = 0; - private final boolean _silent; + private boolean _silent; private volatile BlockingCell returnCell; - public TestMain(Connection connection, boolean silent) { - _connection = connection; - _silent = silent; + public TestMain() { + } +// public TestMain(Connection connection, boolean silent) { +// _connection = connection; +// _silent = silent; +// } + + public void set_connection(Connection _connection) { + this._connection = _connection; + } + + public void set_silent(boolean _silent) { + this._silent = _silent; } public Channel createChannel() throws IOException { diff --git a/test/src/com/rabbitmq/examples/TracerConcurrencyTest.java b/src/test/java/com/rabbitmq/examples/TracerConcurrencyTest.java similarity index 100% rename from test/src/com/rabbitmq/examples/TracerConcurrencyTest.java rename to src/test/java/com/rabbitmq/examples/TracerConcurrencyTest.java diff --git a/test/src/com/rabbitmq/examples/perf/Broker.java b/src/test/java/com/rabbitmq/examples/perf/Broker.java similarity index 100% rename from test/src/com/rabbitmq/examples/perf/Broker.java rename to src/test/java/com/rabbitmq/examples/perf/Broker.java diff --git a/test/src/com/rabbitmq/examples/perf/BrokerValue.java b/src/test/java/com/rabbitmq/examples/perf/BrokerValue.java similarity index 100% rename from test/src/com/rabbitmq/examples/perf/BrokerValue.java rename to src/test/java/com/rabbitmq/examples/perf/BrokerValue.java diff --git a/test/src/com/rabbitmq/examples/perf/BrokerVariable.java b/src/test/java/com/rabbitmq/examples/perf/BrokerVariable.java similarity index 100% rename from test/src/com/rabbitmq/examples/perf/BrokerVariable.java rename to src/test/java/com/rabbitmq/examples/perf/BrokerVariable.java diff --git a/test/src/com/rabbitmq/examples/perf/Consumer.java b/src/test/java/com/rabbitmq/examples/perf/Consumer.java similarity index 100% rename from test/src/com/rabbitmq/examples/perf/Consumer.java rename to src/test/java/com/rabbitmq/examples/perf/Consumer.java diff --git a/test/src/com/rabbitmq/examples/perf/MulticastParams.java b/src/test/java/com/rabbitmq/examples/perf/MulticastParams.java similarity index 100% rename from test/src/com/rabbitmq/examples/perf/MulticastParams.java rename to src/test/java/com/rabbitmq/examples/perf/MulticastParams.java diff --git a/test/src/com/rabbitmq/examples/perf/MulticastSet.java b/src/test/java/com/rabbitmq/examples/perf/MulticastSet.java similarity index 100% rename from test/src/com/rabbitmq/examples/perf/MulticastSet.java rename to src/test/java/com/rabbitmq/examples/perf/MulticastSet.java diff --git a/test/src/com/rabbitmq/examples/perf/MulticastValue.java b/src/test/java/com/rabbitmq/examples/perf/MulticastValue.java similarity index 100% rename from test/src/com/rabbitmq/examples/perf/MulticastValue.java rename to src/test/java/com/rabbitmq/examples/perf/MulticastValue.java diff --git a/test/src/com/rabbitmq/examples/perf/MulticastVariable.java b/src/test/java/com/rabbitmq/examples/perf/MulticastVariable.java similarity index 100% rename from test/src/com/rabbitmq/examples/perf/MulticastVariable.java rename to src/test/java/com/rabbitmq/examples/perf/MulticastVariable.java diff --git a/test/src/com/rabbitmq/examples/perf/PerfUtil.java b/src/test/java/com/rabbitmq/examples/perf/PerfUtil.java similarity index 100% rename from test/src/com/rabbitmq/examples/perf/PerfUtil.java rename to src/test/java/com/rabbitmq/examples/perf/PerfUtil.java diff --git a/test/src/com/rabbitmq/examples/perf/Producer.java b/src/test/java/com/rabbitmq/examples/perf/Producer.java similarity index 100% rename from test/src/com/rabbitmq/examples/perf/Producer.java rename to src/test/java/com/rabbitmq/examples/perf/Producer.java diff --git a/test/src/com/rabbitmq/examples/perf/ProducerConsumerBase.java b/src/test/java/com/rabbitmq/examples/perf/ProducerConsumerBase.java similarity index 100% rename from test/src/com/rabbitmq/examples/perf/ProducerConsumerBase.java rename to src/test/java/com/rabbitmq/examples/perf/ProducerConsumerBase.java diff --git a/test/src/com/rabbitmq/examples/perf/RateVsLatencyScenario.java b/src/test/java/com/rabbitmq/examples/perf/RateVsLatencyScenario.java similarity index 100% rename from test/src/com/rabbitmq/examples/perf/RateVsLatencyScenario.java rename to src/test/java/com/rabbitmq/examples/perf/RateVsLatencyScenario.java diff --git a/test/src/com/rabbitmq/examples/perf/Scenario.java b/src/test/java/com/rabbitmq/examples/perf/Scenario.java similarity index 100% rename from test/src/com/rabbitmq/examples/perf/Scenario.java rename to src/test/java/com/rabbitmq/examples/perf/Scenario.java diff --git a/test/src/com/rabbitmq/examples/perf/ScenarioFactory.java b/src/test/java/com/rabbitmq/examples/perf/ScenarioFactory.java similarity index 100% rename from test/src/com/rabbitmq/examples/perf/ScenarioFactory.java rename to src/test/java/com/rabbitmq/examples/perf/ScenarioFactory.java diff --git a/test/src/com/rabbitmq/examples/perf/ScenarioStats.java b/src/test/java/com/rabbitmq/examples/perf/ScenarioStats.java similarity index 100% rename from test/src/com/rabbitmq/examples/perf/ScenarioStats.java rename to src/test/java/com/rabbitmq/examples/perf/ScenarioStats.java diff --git a/test/src/com/rabbitmq/examples/perf/SimpleScenario.java b/src/test/java/com/rabbitmq/examples/perf/SimpleScenario.java similarity index 100% rename from test/src/com/rabbitmq/examples/perf/SimpleScenario.java rename to src/test/java/com/rabbitmq/examples/perf/SimpleScenario.java diff --git a/test/src/com/rabbitmq/examples/perf/SimpleScenarioStats.java b/src/test/java/com/rabbitmq/examples/perf/SimpleScenarioStats.java similarity index 100% rename from test/src/com/rabbitmq/examples/perf/SimpleScenarioStats.java rename to src/test/java/com/rabbitmq/examples/perf/SimpleScenarioStats.java diff --git a/test/src/com/rabbitmq/examples/perf/Stats.java b/src/test/java/com/rabbitmq/examples/perf/Stats.java similarity index 100% rename from test/src/com/rabbitmq/examples/perf/Stats.java rename to src/test/java/com/rabbitmq/examples/perf/Stats.java diff --git a/test/src/com/rabbitmq/examples/perf/Variable.java b/src/test/java/com/rabbitmq/examples/perf/Variable.java similarity index 100% rename from test/src/com/rabbitmq/examples/perf/Variable.java rename to src/test/java/com/rabbitmq/examples/perf/Variable.java diff --git a/test/src/com/rabbitmq/examples/perf/VariableValue.java b/src/test/java/com/rabbitmq/examples/perf/VariableValue.java similarity index 100% rename from test/src/com/rabbitmq/examples/perf/VariableValue.java rename to src/test/java/com/rabbitmq/examples/perf/VariableValue.java diff --git a/test/src/com/rabbitmq/examples/perf/VaryingScenario.java b/src/test/java/com/rabbitmq/examples/perf/VaryingScenario.java similarity index 100% rename from test/src/com/rabbitmq/examples/perf/VaryingScenario.java rename to src/test/java/com/rabbitmq/examples/perf/VaryingScenario.java diff --git a/test/src/com/rabbitmq/examples/perf/VaryingScenarioStats.java b/src/test/java/com/rabbitmq/examples/perf/VaryingScenarioStats.java similarity index 100% rename from test/src/com/rabbitmq/examples/perf/VaryingScenarioStats.java rename to src/test/java/com/rabbitmq/examples/perf/VaryingScenarioStats.java diff --git a/test/src/com/rabbitmq/tools/Host.java b/src/test/java/com/rabbitmq/tools/Host.java similarity index 77% rename from test/src/com/rabbitmq/tools/Host.java rename to src/test/java/com/rabbitmq/tools/Host.java index 8db1de8501..728fceb834 100644 --- a/test/src/com/rabbitmq/tools/Host.java +++ b/src/test/java/com/rabbitmq/tools/Host.java @@ -29,7 +29,7 @@ public class Host { - private static String capture(InputStream is) + public static String capture(InputStream is) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(is)); @@ -93,34 +93,71 @@ private static Process executeCommandProcess(String command) throws IOException } public static Process rabbitmqctl(String command) throws IOException { - return executeCommand(rabbitmqctlCommand() + " " + command); + return executeCommand(rabbitmqctlCommand() + + " -n \'" + nodenameA() + "\'" + + " " + command); } public static Process rabbitmqctlIgnoreErrors(String command) throws IOException { - return executeCommandIgnoringErrors(rabbitmqctlCommand() + " " + command); + return executeCommandIgnoringErrors(rabbitmqctlCommand() + + " -n \'" + nodenameA() + "\'" + + " " + command); } public static Process invokeMakeTarget(String command) throws IOException { File rabbitmqctl = new File(rabbitmqctlCommand()); return executeCommand(makeCommand() + - " -C \'" + rabbitmqTestDir() + "\'" + + " -C \'" + rabbitmqDir() + "\'" + " RABBITMQCTL=\'" + rabbitmqctl.getAbsolutePath() + "\'" + + " RABBITMQ_NODENAME=\'" + nodenameA() + "\'" + + " RABBITMQ_NODE_PORT=" + node_portA() + + " RABBITMQ_CONFIG_FILE=\'" + config_fileA() + "\'" + " " + command); } - private static String makeCommand() + public static String makeCommand() + { + return System.getProperty("make.bin", "make"); + } + + public static String nodenameA() + { + return System.getProperty("test-broker.A.nodename"); + } + + public static String node_portA() + { + return System.getProperty("test-broker.A.node_port"); + } + + public static String config_fileA() + { + return System.getProperty("test-broker.A.config_file"); + } + + public static String nodenameB() + { + return System.getProperty("test-broker.B.nodename"); + } + + public static String node_portB() + { + return System.getProperty("test-broker.B.node_port"); + } + + public static String config_fileB() { - return System.getProperty("make.bin"); + return System.getProperty("test-broker.B.config_file"); } - private static String rabbitmqctlCommand() + public static String rabbitmqctlCommand() { return System.getProperty("rabbitmqctl.bin"); } - private static String rabbitmqTestDir() + public static String rabbitmqDir() { - return System.getProperty("sibling.rabbitmq_test.dir"); + return System.getProperty("rabbitmq.dir"); } public static void closeConnection(String pid) throws IOException { diff --git a/test/src/com/rabbitmq/utility/IntAllocatorTests.java b/src/test/java/com/rabbitmq/utility/IntAllocatorTests.java similarity index 100% rename from test/src/com/rabbitmq/utility/IntAllocatorTests.java rename to src/test/java/com/rabbitmq/utility/IntAllocatorTests.java diff --git a/config.properties b/src/test/resources/config.properties similarity index 91% rename from config.properties rename to src/test/resources/config.properties index c9851fb271..1f2f6018a1 100644 --- a/config.properties +++ b/src/test/resources/config.properties @@ -1,5 +1,6 @@ broker.hostname=localhost broker.port=5672 +broker.sslport=5671 test.main=com.rabbitmq.examples.TestMain test.producer.rate-limit=100000 test.producer.message-count=30000 diff --git a/src/test/resources/hare@localhost.config b/src/test/resources/hare@localhost.config new file mode 100644 index 0000000000..a321e2848b --- /dev/null +++ b/src/test/resources/hare@localhost.config @@ -0,0 +1,15 @@ +% vim:ft=erlang: + +[ + {rabbit, [ + {ssl_listeners, [5670]}, + {ssl_options, [ + {cacertfile, "${test-tls-certs.dir}/testca/cacert.pem"}, + {certfile, "${test-tls-certs.dir}/server/cert.pem"}, + {keyfile, "${test-tls-certs.dir}/server/key.pem"}, + {verify, verify_peer}, + {fail_if_no_peer_cert, false}, + {honor_cipher_order, true}]}, + {auth_mechanisms, ['PLAIN', 'AMQPLAIN', 'EXTERNAL', 'RABBIT-CR-DEMO']} + ]} +]. diff --git a/src/test/resources/rabbit@localhost.config b/src/test/resources/rabbit@localhost.config new file mode 100644 index 0000000000..6d233b5b9f --- /dev/null +++ b/src/test/resources/rabbit@localhost.config @@ -0,0 +1,15 @@ +% vim:ft=erlang: + +[ + {rabbit, [ + {ssl_listeners, [5671]}, + {ssl_options, [ + {cacertfile, "${test-tls-certs.dir}/testca/cacert.pem"}, + {certfile, "${test-tls-certs.dir}/server/cert.pem"}, + {keyfile, "${test-tls-certs.dir}/server/key.pem"}, + {verify, verify_peer}, + {fail_if_no_peer_cert, false}, + {honor_cipher_order, true}]}, + {auth_mechanisms, ['PLAIN', 'AMQPLAIN', 'EXTERNAL', 'RABBIT-CR-DEMO']} + ]} +]. From 5aaac815171a21e90f6e46eb38283ba5c4a2fb69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 23 Aug 2016 13:44:22 +0200 Subject: [PATCH 0211/2114] Activate by default the setup-test-cluster profile As the activation cannot use properties in the file tag. Issue #122 --- pom.xml | 3 --- 1 file changed, 3 deletions(-) diff --git a/pom.xml b/pom.xml index ac12cf481f..b179b742e6 100644 --- a/pom.xml +++ b/pom.xml @@ -166,9 +166,6 @@ !skipTests - - ${rabbitmq.dir} - From cec6fd5b590e852f459535eb068491bfec90a346 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 23 Aug 2016 13:57:51 +0200 Subject: [PATCH 0212/2114] Activate by default the setup-test-cluster profile As the activation cannot use properties in the file tag. Issue #166 --- pom.xml | 3 --- 1 file changed, 3 deletions(-) diff --git a/pom.xml b/pom.xml index 4a077b3728..86d72e8aa4 100644 --- a/pom.xml +++ b/pom.xml @@ -166,9 +166,6 @@ !skipTests - - ${rabbitmq.dir} - From 87350ab92c33d7cc5642ac0fb0568f1e8f1f8109 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 22 Aug 2016 16:08:35 +0200 Subject: [PATCH 0213/2114] Add strategy interface to resolve list of hosts Issue #153. Could help for #104 and #138. Conflicts: src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java --- .../com/rabbitmq/client/AddressResolver.java | 12 +++++++++ .../rabbitmq/client/ConnectionFactory.java | 27 ++++++++++++++++++- .../rabbitmq/client/ListAddressResolver.java | 20 ++++++++++++++ .../recovery/AutorecoveringConnection.java | 21 +++++---------- .../RecoveryAwareAMQConnectionFactory.java | 12 ++++++--- 5 files changed, 74 insertions(+), 18 deletions(-) create mode 100644 src/main/java/com/rabbitmq/client/AddressResolver.java create mode 100644 src/main/java/com/rabbitmq/client/ListAddressResolver.java diff --git a/src/main/java/com/rabbitmq/client/AddressResolver.java b/src/main/java/com/rabbitmq/client/AddressResolver.java new file mode 100644 index 0000000000..f16672e4b9 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/AddressResolver.java @@ -0,0 +1,12 @@ +package com.rabbitmq.client; + +import java.util.List; + +/** + * Strategy interface to get the potential servers to connect to. + */ +public interface AddressResolver { + + List
getAddresses(); + +} diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index a0251f1b7c..868768b7be 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -801,6 +801,30 @@ public Connection newConnection(ExecutorService executor, List
addrs) t */ public Connection newConnection(ExecutorService executor, List
addrs, String clientProvidedName) throws IOException, TimeoutException { + return newConnection(executor, new ListAddressResolver(addrs), clientProvidedName); + } + + /** + * Create a new broker connection with a client-provided name, picking the first available address from + * the list provided by the {@link AddressResolver}. + * + * If automatic connection recovery + * is enabled, the connection returned by this method will be {@link Recoverable}. Future + * reconnection attempts will pick a random accessible address provided by the {@link AddressResolver}. + * + * @param executor thread execution service for consumers on the connection + * @param addressResolver discovery service to list potential addresses (hostname/port pairs) to connect to + * @param clientProvidedName application-specific connection name, will be displayed + * in the management UI if RabbitMQ server supports it. + * This value doesn't have to be unique and cannot be used + * as a connection identifier e.g. in HTTP API requests. + * This value is supposed to be human-readable. + * @return + * @throws IOException + * @throws TimeoutException + */ + public Connection newConnection(ExecutorService executor, AddressResolver addressResolver, String clientProvidedName) + throws IOException, TimeoutException { // make sure we respect the provided thread factory FrameHandlerFactory fhFactory = createFrameHandlerFactory(); ConnectionParams params = params(executor); @@ -813,11 +837,12 @@ public Connection newConnection(ExecutorService executor, List
addrs, S if (isAutomaticRecoveryEnabled()) { // see com.rabbitmq.client.impl.recovery.RecoveryAwareAMQConnectionFactory#newConnection - AutorecoveringConnection conn = new AutorecoveringConnection(params, fhFactory, addrs); + AutorecoveringConnection conn = new AutorecoveringConnection(params, fhFactory, addressResolver); conn.init(); return conn; } else { + List
addrs = addressResolver.getAddresses(); IOException lastException = null; for (Address addr : addrs) { try { diff --git a/src/main/java/com/rabbitmq/client/ListAddressResolver.java b/src/main/java/com/rabbitmq/client/ListAddressResolver.java new file mode 100644 index 0000000000..5dc0c70a58 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/ListAddressResolver.java @@ -0,0 +1,20 @@ +package com.rabbitmq.client; + +import java.util.List; + +/** + * Simple implementation of {@link AddressResolver} that returns a fixed list. + */ +public class ListAddressResolver implements AddressResolver { + + private final List
addresses; + + public ListAddressResolver(List
addresses) { + this.addresses = addresses; + } + + @Override + public List
getAddresses() { + return addresses; + } +} diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index e72988ebca..19f4feea04 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -15,20 +15,9 @@ package com.rabbitmq.client.impl.recovery; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.Address; -import com.rabbitmq.client.BlockedListener; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.ConnectionFactory; -import com.rabbitmq.client.MissedHeartbeatException; -import com.rabbitmq.client.Recoverable; -import com.rabbitmq.client.RecoveryListener; -import com.rabbitmq.client.ShutdownListener; -import com.rabbitmq.client.ShutdownSignalException; -import com.rabbitmq.client.TopologyRecoveryException; +import com.rabbitmq.client.*; + import com.rabbitmq.client.impl.ConnectionParams; -import com.rabbitmq.client.ExceptionHandler; import com.rabbitmq.client.impl.FrameHandlerFactory; import com.rabbitmq.client.impl.NetworkConnection; @@ -93,7 +82,11 @@ public class AutorecoveringConnection implements Connection, Recoverable, Networ private final Object recoveryLock = new Object(); public AutorecoveringConnection(ConnectionParams params, FrameHandlerFactory f, List
addrs) { - this.cf = new RecoveryAwareAMQConnectionFactory(params, f, addrs); + this(params, f, new ListAddressResolver(addrs)); + } + + public AutorecoveringConnection(ConnectionParams params, FrameHandlerFactory f, AddressResolver addressResolver) { + this.cf = new RecoveryAwareAMQConnectionFactory(params, f, addressResolver); this.params = params; this.channels = new ConcurrentHashMap(); diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java index d4e87fbf1c..5c8c6250dd 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java @@ -16,6 +16,8 @@ package com.rabbitmq.client.impl.recovery; import com.rabbitmq.client.Address; +import com.rabbitmq.client.AddressResolver; +import com.rabbitmq.client.ListAddressResolver; import com.rabbitmq.client.impl.ConnectionParams; import com.rabbitmq.client.impl.FrameHandler; import com.rabbitmq.client.impl.FrameHandlerFactory; @@ -29,12 +31,16 @@ public class RecoveryAwareAMQConnectionFactory { private final ConnectionParams params; private final FrameHandlerFactory factory; - private final List
addrs; + private final AddressResolver addressResolver; public RecoveryAwareAMQConnectionFactory(ConnectionParams params, FrameHandlerFactory factory, List
addrs) { + this(params, factory, new ListAddressResolver(addrs)); + } + + public RecoveryAwareAMQConnectionFactory(ConnectionParams params, FrameHandlerFactory factory, AddressResolver addressResolver) { this.params = params; this.factory = factory; - this.addrs = addrs; + this.addressResolver = addressResolver; } /** @@ -43,7 +49,7 @@ public RecoveryAwareAMQConnectionFactory(ConnectionParams params, FrameHandlerFa */ RecoveryAwareAMQConnection newConnection() throws IOException, TimeoutException { IOException lastException = null; - List
shuffled = shuffle(addrs); + List
shuffled = shuffle(addressResolver.getAddresses()); for (Address addr : shuffled) { try { From 49a7fcb5172a14b9bc60fd40bc77d115586da8f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 22 Aug 2016 16:49:40 +0200 Subject: [PATCH 0214/2114] Add 2 constructors with AddressResolver parameter Issue #153 --- .../rabbitmq/client/ConnectionFactory.java | 41 +++++++++++++++++-- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 868768b7be..3743d200ba 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -661,6 +661,23 @@ public Connection newConnection(Address[] addrs) throws IOException, TimeoutExce return newConnection(this.sharedExecutor, Arrays.asList(addrs), null); } + /** + * Create a new broker connection, picking the first available address from + * the list provided by the {@link AddressResolver}. + * + * If automatic connection recovery + * is enabled, the connection returned by this method will be {@link Recoverable}. Future + * reconnection attempts will pick a random accessible address provided by the {@link AddressResolver}. + * + * @param addressResolver discovery service to list potential addresses (hostname/port pairs) to connect to + * @return an interface to the connection + * @throws IOException if it encounters a problem + * @see Automatic Recovery + */ + public Connection newConnection(AddressResolver addressResolver) throws IOException, TimeoutException { + return newConnection(this.sharedExecutor, addressResolver, null); + } + /** * Create a new broker connection with a client-provided name, picking the first available address from @@ -780,6 +797,24 @@ public Connection newConnection(ExecutorService executor, List
addrs) t return newConnection(executor, addrs, null); } + /** + * Create a new broker connection, picking the first available address from + * the list provided by the {@link AddressResolver}. + * + * If automatic connection recovery + * is enabled, the connection returned by this method will be {@link Recoverable}. Future + * reconnection attempts will pick a random accessible address provided by the {@link AddressResolver}. + * + * @param executor thread execution service for consumers on the connection + * @param addressResolver discovery service to list potential addresses (hostname/port pairs) to connect to + * @return an interface to the connection + * @throws java.io.IOException if it encounters a problem + * @see Automatic Recovery + */ + public Connection newConnection(ExecutorService executor, AddressResolver addressResolver) throws IOException, TimeoutException { + return newConnection(executor, addressResolver, null); + } + /** * Create a new broker connection with a client-provided name, picking the first available address from * the list. @@ -819,9 +854,9 @@ public Connection newConnection(ExecutorService executor, List
addrs, S * This value doesn't have to be unique and cannot be used * as a connection identifier e.g. in HTTP API requests. * This value is supposed to be human-readable. - * @return - * @throws IOException - * @throws TimeoutException + * @return an interface to the connection + * @throws java.io.IOException if it encounters a problem + * @see Automatic Recovery */ public Connection newConnection(ExecutorService executor, AddressResolver addressResolver, String clientProvidedName) throws IOException, TimeoutException { From 4995878ff147b8e02eb2b6960b786ef46a64ce01 Mon Sep 17 00:00:00 2001 From: ayoub Date: Tue, 23 Aug 2016 11:25:25 -0500 Subject: [PATCH 0215/2114] Change showRate to getRate. --- src/test/java/com/rabbitmq/examples/PerfTest.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/test/java/com/rabbitmq/examples/PerfTest.java b/src/test/java/com/rabbitmq/examples/PerfTest.java index dec52632bb..25add55314 100644 --- a/src/test/java/com/rabbitmq/examples/PerfTest.java +++ b/src/test/java/com/rabbitmq/examples/PerfTest.java @@ -218,11 +218,11 @@ protected void report(long now) { output += "time: " + String.format("%.3f", (now - startTime)/1000.0) + "s"; output += - showRate("sent", sendCountInterval, sendStatsEnabled, elapsedInterval) + - showRate("returned", returnCountInterval, sendStatsEnabled && returnStatsEnabled, elapsedInterval) + - showRate("confirmed", confirmCountInterval, sendStatsEnabled && confirmStatsEnabled, elapsedInterval) + - showRate("nacked", nackCountInterval, sendStatsEnabled && confirmStatsEnabled, elapsedInterval) + - showRate("received", recvCountInterval, recvStatsEnabled, elapsedInterval); + getRate("sent", sendCountInterval, sendStatsEnabled, elapsedInterval) + + getRate("returned", returnCountInterval, sendStatsEnabled && returnStatsEnabled, elapsedInterval) + + getRate("confirmed", confirmCountInterval, sendStatsEnabled && confirmStatsEnabled, elapsedInterval) + + getRate("nacked", nackCountInterval, sendStatsEnabled && confirmStatsEnabled, elapsedInterval) + + getRate("received", recvCountInterval, recvStatsEnabled, elapsedInterval); output += (latencyCountInterval > 0 ? ", min/avg/max latency: " + @@ -234,7 +234,7 @@ protected void report(long now) { System.out.println(output); } - private String showRate(String descr, long count, boolean display, + private String getRate(String descr, long count, boolean display, long elapsed) { if (display) return ", " + descr + ": " + formatRate(1000.0 * count / elapsed) + " msg/s"; From 56686aea51bbe9d729a36b4c2142dbcc4aa3449b Mon Sep 17 00:00:00 2001 From: ayoub Date: Tue, 23 Aug 2016 11:28:35 -0500 Subject: [PATCH 0216/2114] Correct indentation mistake. --- src/test/java/com/rabbitmq/examples/PerfTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/examples/PerfTest.java b/src/test/java/com/rabbitmq/examples/PerfTest.java index 25add55314..99a93ce267 100644 --- a/src/test/java/com/rabbitmq/examples/PerfTest.java +++ b/src/test/java/com/rabbitmq/examples/PerfTest.java @@ -218,7 +218,7 @@ protected void report(long now) { output += "time: " + String.format("%.3f", (now - startTime)/1000.0) + "s"; output += - getRate("sent", sendCountInterval, sendStatsEnabled, elapsedInterval) + + getRate("sent", sendCountInterval, sendStatsEnabled, elapsedInterval) + getRate("returned", returnCountInterval, sendStatsEnabled && returnStatsEnabled, elapsedInterval) + getRate("confirmed", confirmCountInterval, sendStatsEnabled && confirmStatsEnabled, elapsedInterval) + getRate("nacked", nackCountInterval, sendStatsEnabled && confirmStatsEnabled, elapsedInterval) + From 14acaf4be5823b91448de472111ecb6b8e324680 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 24 Aug 2016 09:27:00 +0200 Subject: [PATCH 0217/2114] Create enum for exchange types Fixes #150 --- .../java/com/rabbitmq/client/Channel.java | 81 +++++++++++++++++++ .../com/rabbitmq/client/ExchangeType.java | 19 +++++ .../com/rabbitmq/client/impl/ChannelN.java | 66 ++++++++++++--- .../impl/recovery/AutorecoveringChannel.java | 36 +++++---- .../test/functional/ExchangeDeclare.java | 52 +++++++++++- 5 files changed, 226 insertions(+), 28 deletions(-) create mode 100644 src/main/java/com/rabbitmq/client/ExchangeType.java diff --git a/src/main/java/com/rabbitmq/client/Channel.java b/src/main/java/com/rabbitmq/client/Channel.java index d9220868d7..c5bb9e852f 100644 --- a/src/main/java/com/rabbitmq/client/Channel.java +++ b/src/main/java/com/rabbitmq/client/Channel.java @@ -320,6 +320,17 @@ void basicPublish(String exchange, String routingKey, boolean mandatory, boolean */ Exchange.DeclareOk exchangeDeclare(String exchange, String type) throws IOException; + /** + * Actively declare a non-autodelete, non-durable exchange with no extra arguments + * @see com.rabbitmq.client.AMQP.Exchange.Declare + * @see com.rabbitmq.client.AMQP.Exchange.DeclareOk + * @param exchange the name of the exchange + * @param type the exchange type + * @return a declaration-confirm method to indicate the exchange was successfully declared + * @throws java.io.IOException if an error is encountered + */ + Exchange.DeclareOk exchangeDeclare(String exchange, ExchangeType type) throws IOException; + /** * Actively declare a non-autodelete exchange with no extra arguments * @see com.rabbitmq.client.AMQP.Exchange.Declare @@ -332,6 +343,18 @@ void basicPublish(String exchange, String routingKey, boolean mandatory, boolean */ Exchange.DeclareOk exchangeDeclare(String exchange, String type, boolean durable) throws IOException; + /** + * Actively declare a non-autodelete exchange with no extra arguments + * @see com.rabbitmq.client.AMQP.Exchange.Declare + * @see com.rabbitmq.client.AMQP.Exchange.DeclareOk + * @param exchange the name of the exchange + * @param type the exchange type + * @param durable true if we are declaring a durable exchange (the exchange will survive a server restart) + * @throws java.io.IOException if an error is encountered + * @return a declaration-confirm method to indicate the exchange was successfully declared + */ + Exchange.DeclareOk exchangeDeclare(String exchange, ExchangeType type, boolean durable) throws IOException; + /** * Declare an exchange. * @see com.rabbitmq.client.AMQP.Exchange.Declare @@ -347,6 +370,21 @@ void basicPublish(String exchange, String routingKey, boolean mandatory, boolean Exchange.DeclareOk exchangeDeclare(String exchange, String type, boolean durable, boolean autoDelete, Map arguments) throws IOException; + /** + * Declare an exchange. + * @see com.rabbitmq.client.AMQP.Exchange.Declare + * @see com.rabbitmq.client.AMQP.Exchange.DeclareOk + * @param exchange the name of the exchange + * @param type the exchange type + * @param durable true if we are declaring a durable exchange (the exchange will survive a server restart) + * @param autoDelete true if the server should delete the exchange when it is no longer in use + * @param arguments other properties (construction arguments) for the exchange + * @return a declaration-confirm method to indicate the exchange was successfully declared + * @throws java.io.IOException if an error is encountered + */ + Exchange.DeclareOk exchangeDeclare(String exchange, ExchangeType type, boolean durable, boolean autoDelete, + Map arguments) throws IOException; + /** * Declare an exchange, via an interface that allows the complete set of * arguments. @@ -369,6 +407,28 @@ Exchange.DeclareOk exchangeDeclare(String exchange, boolean internal, Map arguments) throws IOException; + /** + * Declare an exchange, via an interface that allows the complete set of + * arguments. + * @see com.rabbitmq.client.AMQP.Exchange.Declare + * @see com.rabbitmq.client.AMQP.Exchange.DeclareOk + * @param exchange the name of the exchange + * @param type the exchange type + * @param durable true if we are declaring a durable exchange (the exchange will survive a server restart) + * @param autoDelete true if the server should delete the exchange when it is no longer in use + * @param internal true if the exchange is internal, i.e. can't be directly + * published to by a client. + * @param arguments other properties (construction arguments) for the exchange + * @return a declaration-confirm method to indicate the exchange was successfully declared + * @throws java.io.IOException if an error is encountered + */ + Exchange.DeclareOk exchangeDeclare(String exchange, + ExchangeType type, + boolean durable, + boolean autoDelete, + boolean internal, + Map arguments) throws IOException; + /** * Like {@link Channel#exchangeDeclare(String, String, boolean, boolean, java.util.Map)} but * sets nowait parameter to true and returns nothing (as there will be no response from @@ -390,6 +450,27 @@ void exchangeDeclareNoWait(String exchange, boolean internal, Map arguments) throws IOException; + /** + * Like {@link Channel#exchangeDeclare(String, String, boolean, boolean, java.util.Map)} but + * sets nowait parameter to true and returns nothing (as there will be no response from + * the server). + * + * @param exchange the name of the exchange + * @param type the exchange type + * @param durable true if we are declaring a durable exchange (the exchange will survive a server restart) + * @param autoDelete true if the server should delete the exchange when it is no longer in use + * @param internal true if the exchange is internal, i.e. can't be directly + * published to by a client. + * @param arguments other properties (construction arguments) for the exchange + * @throws java.io.IOException if an error is encountered + */ + void exchangeDeclareNoWait(String exchange, + ExchangeType type, + boolean durable, + boolean autoDelete, + boolean internal, + Map arguments) throws IOException; + /** * Declare an exchange passively; that is, check if the named exchange exists. * @param name check the existence of an exchange named this diff --git a/src/main/java/com/rabbitmq/client/ExchangeType.java b/src/main/java/com/rabbitmq/client/ExchangeType.java new file mode 100644 index 0000000000..693fb01f32 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/ExchangeType.java @@ -0,0 +1,19 @@ +package com.rabbitmq.client; + +/** + * + */ +public enum ExchangeType { + + DIRECT("direct"), FANOUT("fanout"), TOPIC("topic"), HEADERS("headers"); + + private final String type; + + ExchangeType(String type) { + this.type = type; + } + + public String getType() { + return type; + } +} diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java index 86f59f7df0..4ebec7cc2f 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelN.java @@ -25,20 +25,10 @@ import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeoutException; -import com.rabbitmq.client.AMQP; + +import com.rabbitmq.client.*; import com.rabbitmq.client.AMQP.BasicProperties; -import com.rabbitmq.client.Command; -import com.rabbitmq.client.ConfirmListener; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.Consumer; -import com.rabbitmq.client.Envelope; -import com.rabbitmq.client.FlowListener; -import com.rabbitmq.client.GetResponse; import com.rabbitmq.client.Method; -import com.rabbitmq.client.MessageProperties; -import com.rabbitmq.client.ReturnListener; -import com.rabbitmq.client.ShutdownSignalException; -import com.rabbitmq.client.UnexpectedMethodError; import com.rabbitmq.client.impl.AMQImpl.Basic; import com.rabbitmq.client.impl.AMQImpl.Channel; import com.rabbitmq.client.impl.AMQImpl.Confirm; @@ -662,6 +652,8 @@ public void basicPublish(String exchange, String routingKey, useProps, body)); } + + /** Public API - {@inheritDoc} */ public Exchange.DeclareOk exchangeDeclare(String exchange, String type, boolean durable, boolean autoDelete, @@ -673,6 +665,17 @@ public Exchange.DeclareOk exchangeDeclare(String exchange, String type, arguments); } + /** Public API - {@inheritDoc} */ + public Exchange.DeclareOk exchangeDeclare(String exchange, ExchangeType type, + boolean durable, boolean autoDelete, + Map arguments) + throws IOException + { + return exchangeDeclare(exchange, type.getType(), + durable, autoDelete, + arguments); + } + public void exchangeDeclareNoWait(String exchange, String type, boolean durable, @@ -691,6 +694,17 @@ public void exchangeDeclareNoWait(String exchange, .build())); } + public void exchangeDeclareNoWait(String exchange, + ExchangeType type, + boolean durable, + boolean autoDelete, + boolean internal, + Map arguments) throws IOException { + exchangeDeclareNoWait(exchange, type.getType(), + durable, autoDelete, internal, + arguments); + } + /** Public API - {@inheritDoc} */ public Exchange.DeclareOk exchangeDeclare(String exchange, String type, boolean durable, @@ -711,6 +725,19 @@ public Exchange.DeclareOk exchangeDeclare(String exchange, String type, .getMethod(); } + /** Public API - {@inheritDoc} */ + public Exchange.DeclareOk exchangeDeclare(String exchange, ExchangeType type, + boolean durable, + boolean autoDelete, + boolean internal, + Map arguments) + throws IOException + { + return exchangeDeclare(exchange, type.getType(), + durable, autoDelete, internal, + arguments); + } + /** Public API - {@inheritDoc} */ public Exchange.DeclareOk exchangeDeclare(String exchange, String type, boolean durable) @@ -719,6 +746,14 @@ public Exchange.DeclareOk exchangeDeclare(String exchange, String type, return exchangeDeclare(exchange, type, durable, false, null); } + /** Public API - {@inheritDoc} */ + public Exchange.DeclareOk exchangeDeclare(String exchange, ExchangeType type, + boolean durable) + throws IOException + { + return exchangeDeclare(exchange, type.getType(), durable); + } + /** Public API - {@inheritDoc} */ public Exchange.DeclareOk exchangeDeclare(String exchange, String type) throws IOException @@ -726,6 +761,13 @@ public Exchange.DeclareOk exchangeDeclare(String exchange, String type) return exchangeDeclare(exchange, type, false, false, null); } + /** Public API - {@inheritDoc} */ + public Exchange.DeclareOk exchangeDeclare(String exchange, ExchangeType type) + throws IOException + { + return exchangeDeclare(exchange, type.getType()); + } + /** Public API - {@inheritDoc} */ public Exchange.DeclareOk exchangeDeclarePassive(String exchange) throws IOException diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java index 10445d697a..b53cbfaa09 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java @@ -15,20 +15,7 @@ package com.rabbitmq.client.impl.recovery; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.Command; -import com.rabbitmq.client.ConfirmListener; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.Consumer; -import com.rabbitmq.client.FlowListener; -import com.rabbitmq.client.GetResponse; -import com.rabbitmq.client.Method; -import com.rabbitmq.client.Recoverable; -import com.rabbitmq.client.RecoveryListener; -import com.rabbitmq.client.ReturnListener; -import com.rabbitmq.client.ShutdownListener; -import com.rabbitmq.client.ShutdownSignalException; +import com.rabbitmq.client.*; import java.io.IOException; import java.util.ArrayList; @@ -195,14 +182,26 @@ public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, String type) thr return exchangeDeclare(exchange, type, false, false, null); } + public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, ExchangeType type) throws IOException { + return exchangeDeclare(exchange, type.getType()); + } + public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, String type, boolean durable) throws IOException { return exchangeDeclare(exchange, type, durable, false, null); } + public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, ExchangeType type, boolean durable) throws IOException { + return exchangeDeclare(exchange, type.getType(), durable); + } + public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, String type, boolean durable, boolean autoDelete, Map arguments) throws IOException { return exchangeDeclare(exchange, type, durable, autoDelete, false, arguments); } + public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, ExchangeType type, boolean durable, boolean autoDelete, Map arguments) throws IOException { + return exchangeDeclare(exchange, type.getType(), durable, autoDelete, arguments); + } + public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, String type, boolean durable, boolean autoDelete, boolean internal, Map arguments) throws IOException { final AMQP.Exchange.DeclareOk ok = delegate.exchangeDeclare(exchange, type, durable, autoDelete, internal, arguments); RecordedExchange x = new RecordedExchange(this, exchange). @@ -214,6 +213,10 @@ public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, String type, boo return ok; } + public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, ExchangeType type, boolean durable, boolean autoDelete, boolean internal, Map arguments) throws IOException { + return exchangeDeclare(exchange, type.getType(), durable, autoDelete, internal, arguments); + } + @Override public void exchangeDeclareNoWait(String exchange, String type, boolean durable, boolean autoDelete, boolean internal, Map arguments) throws IOException { RecordedExchange x = new RecordedExchange(this, exchange). @@ -225,6 +228,11 @@ public void exchangeDeclareNoWait(String exchange, String type, boolean durable, delegate.exchangeDeclareNoWait(exchange, type, durable, autoDelete, internal, arguments); } + @Override + public void exchangeDeclareNoWait(String exchange, ExchangeType type, boolean durable, boolean autoDelete, boolean internal, Map arguments) throws IOException { + exchangeDeclareNoWait(exchange, type.getType(), durable, autoDelete, internal, arguments); + } + public AMQP.Exchange.DeclareOk exchangeDeclarePassive(String name) throws IOException { return delegate.exchangeDeclarePassive(name); } diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java index cffe85181d..7b64f98624 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java @@ -16,9 +16,15 @@ package com.rabbitmq.client.test.functional; -import java.util.Map; -import java.util.HashMap; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.ExchangeType; + import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeoutException; public class ExchangeDeclare extends ExchangeEquivalenceBase { @@ -71,4 +77,46 @@ public void testExchangeAutoDeleteNotEquivalent() throws IOException { channel.exchangeDeclare(NAME, "direct", false, false, null); verifyNotEquivalent(NAME, "direct", false, true, null); } + + public void testExchangeDeclaredWithEnumerationEquivalentOnNonRecoverableConnection() throws IOException, InterruptedException { + doTestExchangeDeclaredWithEnumerationEquivalent(channel); + } + + public void testExchangeDeclaredWithEnumerationEquivalentOnRecoverableConnection() throws IOException, TimeoutException, InterruptedException { + ConnectionFactory connectionFactory = new ConnectionFactory(); + connectionFactory.setAutomaticRecoveryEnabled(true); + connectionFactory.setTopologyRecoveryEnabled(false); + Connection c = connectionFactory.newConnection(); + try { + doTestExchangeDeclaredWithEnumerationEquivalent(c.createChannel()); + } finally { + c.abort(); + } + + } + + private void doTestExchangeDeclaredWithEnumerationEquivalent(Channel channel) throws IOException, InterruptedException { + assertEquals("There are 4 standard exchange types", 4, ExchangeType.values().length); + for (ExchangeType exchangeType : ExchangeType.values()) { + channel.exchangeDeclare(NAME, exchangeType); + verifyEquivalent(NAME, exchangeType.getType(), false, false, null); + channel.exchangeDelete(NAME); + + channel.exchangeDeclare(NAME, exchangeType, false); + verifyEquivalent(NAME, exchangeType.getType(), false, false, null); + channel.exchangeDelete(NAME); + + channel.exchangeDeclare(NAME, exchangeType, false, false, null); + verifyEquivalent(NAME, exchangeType.getType(), false, false, null); + channel.exchangeDelete(NAME); + + channel.exchangeDeclare(NAME, exchangeType, false, false, false, null); + verifyEquivalent(NAME, exchangeType.getType(), false, false, null); + channel.exchangeDelete(NAME); + + channel.exchangeDeclareNoWait(NAME, exchangeType, false, false, false, null); + // no check, this one is asynchronous + channel.exchangeDelete(NAME); + } + } } From 7ed9a60ad43865b8d20e986395b7d5adc409a1fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 24 Aug 2016 11:26:51 +0200 Subject: [PATCH 0218/2114] Rename ExchangeType to BuiltinExchangeType Fixes #150 --- .../{ExchangeType.java => BuiltinExchangeType.java} | 6 +++--- src/main/java/com/rabbitmq/client/Channel.java | 10 +++++----- src/main/java/com/rabbitmq/client/impl/ChannelN.java | 10 +++++----- .../client/impl/recovery/AutorecoveringChannel.java | 10 +++++----- .../client/test/functional/ExchangeDeclare.java | 6 +++--- 5 files changed, 21 insertions(+), 21 deletions(-) rename src/main/java/com/rabbitmq/client/{ExchangeType.java => BuiltinExchangeType.java} (68%) diff --git a/src/main/java/com/rabbitmq/client/ExchangeType.java b/src/main/java/com/rabbitmq/client/BuiltinExchangeType.java similarity index 68% rename from src/main/java/com/rabbitmq/client/ExchangeType.java rename to src/main/java/com/rabbitmq/client/BuiltinExchangeType.java index 693fb01f32..f64bbe66ea 100644 --- a/src/main/java/com/rabbitmq/client/ExchangeType.java +++ b/src/main/java/com/rabbitmq/client/BuiltinExchangeType.java @@ -1,15 +1,15 @@ package com.rabbitmq.client; /** - * + * Enum for built-in exchange types. */ -public enum ExchangeType { +public enum BuiltinExchangeType { DIRECT("direct"), FANOUT("fanout"), TOPIC("topic"), HEADERS("headers"); private final String type; - ExchangeType(String type) { + BuiltinExchangeType(String type) { this.type = type; } diff --git a/src/main/java/com/rabbitmq/client/Channel.java b/src/main/java/com/rabbitmq/client/Channel.java index c5bb9e852f..00c85166f5 100644 --- a/src/main/java/com/rabbitmq/client/Channel.java +++ b/src/main/java/com/rabbitmq/client/Channel.java @@ -329,7 +329,7 @@ void basicPublish(String exchange, String routingKey, boolean mandatory, boolean * @return a declaration-confirm method to indicate the exchange was successfully declared * @throws java.io.IOException if an error is encountered */ - Exchange.DeclareOk exchangeDeclare(String exchange, ExchangeType type) throws IOException; + Exchange.DeclareOk exchangeDeclare(String exchange, BuiltinExchangeType type) throws IOException; /** * Actively declare a non-autodelete exchange with no extra arguments @@ -353,7 +353,7 @@ void basicPublish(String exchange, String routingKey, boolean mandatory, boolean * @throws java.io.IOException if an error is encountered * @return a declaration-confirm method to indicate the exchange was successfully declared */ - Exchange.DeclareOk exchangeDeclare(String exchange, ExchangeType type, boolean durable) throws IOException; + Exchange.DeclareOk exchangeDeclare(String exchange, BuiltinExchangeType type, boolean durable) throws IOException; /** * Declare an exchange. @@ -382,7 +382,7 @@ Exchange.DeclareOk exchangeDeclare(String exchange, String type, boolean durable * @return a declaration-confirm method to indicate the exchange was successfully declared * @throws java.io.IOException if an error is encountered */ - Exchange.DeclareOk exchangeDeclare(String exchange, ExchangeType type, boolean durable, boolean autoDelete, + Exchange.DeclareOk exchangeDeclare(String exchange, BuiltinExchangeType type, boolean durable, boolean autoDelete, Map arguments) throws IOException; /** @@ -423,7 +423,7 @@ Exchange.DeclareOk exchangeDeclare(String exchange, * @throws java.io.IOException if an error is encountered */ Exchange.DeclareOk exchangeDeclare(String exchange, - ExchangeType type, + BuiltinExchangeType type, boolean durable, boolean autoDelete, boolean internal, @@ -465,7 +465,7 @@ void exchangeDeclareNoWait(String exchange, * @throws java.io.IOException if an error is encountered */ void exchangeDeclareNoWait(String exchange, - ExchangeType type, + BuiltinExchangeType type, boolean durable, boolean autoDelete, boolean internal, diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java index 4ebec7cc2f..debe5d9ce8 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelN.java @@ -666,7 +666,7 @@ public Exchange.DeclareOk exchangeDeclare(String exchange, String type, } /** Public API - {@inheritDoc} */ - public Exchange.DeclareOk exchangeDeclare(String exchange, ExchangeType type, + public Exchange.DeclareOk exchangeDeclare(String exchange, BuiltinExchangeType type, boolean durable, boolean autoDelete, Map arguments) throws IOException @@ -695,7 +695,7 @@ public void exchangeDeclareNoWait(String exchange, } public void exchangeDeclareNoWait(String exchange, - ExchangeType type, + BuiltinExchangeType type, boolean durable, boolean autoDelete, boolean internal, @@ -726,7 +726,7 @@ public Exchange.DeclareOk exchangeDeclare(String exchange, String type, } /** Public API - {@inheritDoc} */ - public Exchange.DeclareOk exchangeDeclare(String exchange, ExchangeType type, + public Exchange.DeclareOk exchangeDeclare(String exchange, BuiltinExchangeType type, boolean durable, boolean autoDelete, boolean internal, @@ -747,7 +747,7 @@ public Exchange.DeclareOk exchangeDeclare(String exchange, String type, } /** Public API - {@inheritDoc} */ - public Exchange.DeclareOk exchangeDeclare(String exchange, ExchangeType type, + public Exchange.DeclareOk exchangeDeclare(String exchange, BuiltinExchangeType type, boolean durable) throws IOException { @@ -762,7 +762,7 @@ public Exchange.DeclareOk exchangeDeclare(String exchange, String type) } /** Public API - {@inheritDoc} */ - public Exchange.DeclareOk exchangeDeclare(String exchange, ExchangeType type) + public Exchange.DeclareOk exchangeDeclare(String exchange, BuiltinExchangeType type) throws IOException { return exchangeDeclare(exchange, type.getType()); diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java index b53cbfaa09..4ae30918a2 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java @@ -182,7 +182,7 @@ public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, String type) thr return exchangeDeclare(exchange, type, false, false, null); } - public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, ExchangeType type) throws IOException { + public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, BuiltinExchangeType type) throws IOException { return exchangeDeclare(exchange, type.getType()); } @@ -190,7 +190,7 @@ public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, String type, boo return exchangeDeclare(exchange, type, durable, false, null); } - public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, ExchangeType type, boolean durable) throws IOException { + public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, BuiltinExchangeType type, boolean durable) throws IOException { return exchangeDeclare(exchange, type.getType(), durable); } @@ -198,7 +198,7 @@ public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, String type, boo return exchangeDeclare(exchange, type, durable, autoDelete, false, arguments); } - public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, ExchangeType type, boolean durable, boolean autoDelete, Map arguments) throws IOException { + public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, BuiltinExchangeType type, boolean durable, boolean autoDelete, Map arguments) throws IOException { return exchangeDeclare(exchange, type.getType(), durable, autoDelete, arguments); } @@ -213,7 +213,7 @@ public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, String type, boo return ok; } - public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, ExchangeType type, boolean durable, boolean autoDelete, boolean internal, Map arguments) throws IOException { + public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, BuiltinExchangeType type, boolean durable, boolean autoDelete, boolean internal, Map arguments) throws IOException { return exchangeDeclare(exchange, type.getType(), durable, autoDelete, internal, arguments); } @@ -229,7 +229,7 @@ public void exchangeDeclareNoWait(String exchange, String type, boolean durable, } @Override - public void exchangeDeclareNoWait(String exchange, ExchangeType type, boolean durable, boolean autoDelete, boolean internal, Map arguments) throws IOException { + public void exchangeDeclareNoWait(String exchange, BuiltinExchangeType type, boolean durable, boolean autoDelete, boolean internal, Map arguments) throws IOException { exchangeDeclareNoWait(exchange, type.getType(), durable, autoDelete, internal, arguments); } diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java index 7b64f98624..3b20d75dfb 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java @@ -19,7 +19,7 @@ import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; -import com.rabbitmq.client.ExchangeType; +import com.rabbitmq.client.BuiltinExchangeType; import java.io.IOException; import java.util.HashMap; @@ -96,8 +96,8 @@ public void testExchangeDeclaredWithEnumerationEquivalentOnRecoverableConnection } private void doTestExchangeDeclaredWithEnumerationEquivalent(Channel channel) throws IOException, InterruptedException { - assertEquals("There are 4 standard exchange types", 4, ExchangeType.values().length); - for (ExchangeType exchangeType : ExchangeType.values()) { + assertEquals("There are 4 standard exchange types", 4, BuiltinExchangeType.values().length); + for (BuiltinExchangeType exchangeType : BuiltinExchangeType.values()) { channel.exchangeDeclare(NAME, exchangeType); verifyEquivalent(NAME, exchangeType.getType(), false, false, null); channel.exchangeDelete(NAME); From 3a8737dffcd6cdba70f39943812406d3f04fa075 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 24 Aug 2016 09:27:00 +0200 Subject: [PATCH 0219/2114] Create enum for exchange types Fixes #150 --- .../java/com/rabbitmq/client/Channel.java | 81 +++++++++++++++++++ .../com/rabbitmq/client/ExchangeType.java | 19 +++++ .../com/rabbitmq/client/impl/ChannelN.java | 66 ++++++++++++--- .../impl/recovery/AutorecoveringChannel.java | 36 +++++---- .../test/functional/ExchangeDeclare.java | 52 +++++++++++- 5 files changed, 226 insertions(+), 28 deletions(-) create mode 100644 src/main/java/com/rabbitmq/client/ExchangeType.java diff --git a/src/main/java/com/rabbitmq/client/Channel.java b/src/main/java/com/rabbitmq/client/Channel.java index 20c098ea5f..2110f45755 100644 --- a/src/main/java/com/rabbitmq/client/Channel.java +++ b/src/main/java/com/rabbitmq/client/Channel.java @@ -320,6 +320,17 @@ void basicPublish(String exchange, String routingKey, boolean mandatory, boolean */ Exchange.DeclareOk exchangeDeclare(String exchange, String type) throws IOException; + /** + * Actively declare a non-autodelete, non-durable exchange with no extra arguments + * @see com.rabbitmq.client.AMQP.Exchange.Declare + * @see com.rabbitmq.client.AMQP.Exchange.DeclareOk + * @param exchange the name of the exchange + * @param type the exchange type + * @return a declaration-confirm method to indicate the exchange was successfully declared + * @throws java.io.IOException if an error is encountered + */ + Exchange.DeclareOk exchangeDeclare(String exchange, ExchangeType type) throws IOException; + /** * Actively declare a non-autodelete exchange with no extra arguments * @see com.rabbitmq.client.AMQP.Exchange.Declare @@ -332,6 +343,18 @@ void basicPublish(String exchange, String routingKey, boolean mandatory, boolean */ Exchange.DeclareOk exchangeDeclare(String exchange, String type, boolean durable) throws IOException; + /** + * Actively declare a non-autodelete exchange with no extra arguments + * @see com.rabbitmq.client.AMQP.Exchange.Declare + * @see com.rabbitmq.client.AMQP.Exchange.DeclareOk + * @param exchange the name of the exchange + * @param type the exchange type + * @param durable true if we are declaring a durable exchange (the exchange will survive a server restart) + * @throws java.io.IOException if an error is encountered + * @return a declaration-confirm method to indicate the exchange was successfully declared + */ + Exchange.DeclareOk exchangeDeclare(String exchange, ExchangeType type, boolean durable) throws IOException; + /** * Declare an exchange. * @see com.rabbitmq.client.AMQP.Exchange.Declare @@ -347,6 +370,21 @@ void basicPublish(String exchange, String routingKey, boolean mandatory, boolean Exchange.DeclareOk exchangeDeclare(String exchange, String type, boolean durable, boolean autoDelete, Map arguments) throws IOException; + /** + * Declare an exchange. + * @see com.rabbitmq.client.AMQP.Exchange.Declare + * @see com.rabbitmq.client.AMQP.Exchange.DeclareOk + * @param exchange the name of the exchange + * @param type the exchange type + * @param durable true if we are declaring a durable exchange (the exchange will survive a server restart) + * @param autoDelete true if the server should delete the exchange when it is no longer in use + * @param arguments other properties (construction arguments) for the exchange + * @return a declaration-confirm method to indicate the exchange was successfully declared + * @throws java.io.IOException if an error is encountered + */ + Exchange.DeclareOk exchangeDeclare(String exchange, ExchangeType type, boolean durable, boolean autoDelete, + Map arguments) throws IOException; + /** * Declare an exchange, via an interface that allows the complete set of * arguments. @@ -369,6 +407,28 @@ Exchange.DeclareOk exchangeDeclare(String exchange, boolean internal, Map arguments) throws IOException; + /** + * Declare an exchange, via an interface that allows the complete set of + * arguments. + * @see com.rabbitmq.client.AMQP.Exchange.Declare + * @see com.rabbitmq.client.AMQP.Exchange.DeclareOk + * @param exchange the name of the exchange + * @param type the exchange type + * @param durable true if we are declaring a durable exchange (the exchange will survive a server restart) + * @param autoDelete true if the server should delete the exchange when it is no longer in use + * @param internal true if the exchange is internal, i.e. can't be directly + * published to by a client. + * @param arguments other properties (construction arguments) for the exchange + * @return a declaration-confirm method to indicate the exchange was successfully declared + * @throws java.io.IOException if an error is encountered + */ + Exchange.DeclareOk exchangeDeclare(String exchange, + ExchangeType type, + boolean durable, + boolean autoDelete, + boolean internal, + Map arguments) throws IOException; + /** * Like {@link Channel#exchangeDeclare(String, String, boolean, boolean, java.util.Map)} but * sets nowait parameter to true and returns nothing (as there will be no response from @@ -390,6 +450,27 @@ void exchangeDeclareNoWait(String exchange, boolean internal, Map arguments) throws IOException; + /** + * Like {@link Channel#exchangeDeclare(String, String, boolean, boolean, java.util.Map)} but + * sets nowait parameter to true and returns nothing (as there will be no response from + * the server). + * + * @param exchange the name of the exchange + * @param type the exchange type + * @param durable true if we are declaring a durable exchange (the exchange will survive a server restart) + * @param autoDelete true if the server should delete the exchange when it is no longer in use + * @param internal true if the exchange is internal, i.e. can't be directly + * published to by a client. + * @param arguments other properties (construction arguments) for the exchange + * @throws java.io.IOException if an error is encountered + */ + void exchangeDeclareNoWait(String exchange, + ExchangeType type, + boolean durable, + boolean autoDelete, + boolean internal, + Map arguments) throws IOException; + /** * Declare an exchange passively; that is, check if the named exchange exists. * @param name check the existence of an exchange named this diff --git a/src/main/java/com/rabbitmq/client/ExchangeType.java b/src/main/java/com/rabbitmq/client/ExchangeType.java new file mode 100644 index 0000000000..693fb01f32 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/ExchangeType.java @@ -0,0 +1,19 @@ +package com.rabbitmq.client; + +/** + * + */ +public enum ExchangeType { + + DIRECT("direct"), FANOUT("fanout"), TOPIC("topic"), HEADERS("headers"); + + private final String type; + + ExchangeType(String type) { + this.type = type; + } + + public String getType() { + return type; + } +} diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java index 01151f794e..7ea0019ab6 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelN.java @@ -25,20 +25,10 @@ import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeoutException; -import com.rabbitmq.client.AMQP; + +import com.rabbitmq.client.*; import com.rabbitmq.client.AMQP.BasicProperties; -import com.rabbitmq.client.Command; -import com.rabbitmq.client.ConfirmListener; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.Consumer; -import com.rabbitmq.client.Envelope; -import com.rabbitmq.client.FlowListener; -import com.rabbitmq.client.GetResponse; import com.rabbitmq.client.Method; -import com.rabbitmq.client.MessageProperties; -import com.rabbitmq.client.ReturnListener; -import com.rabbitmq.client.ShutdownSignalException; -import com.rabbitmq.client.UnexpectedMethodError; import com.rabbitmq.client.impl.AMQImpl.Basic; import com.rabbitmq.client.impl.AMQImpl.Channel; import com.rabbitmq.client.impl.AMQImpl.Confirm; @@ -662,6 +652,8 @@ public void basicPublish(String exchange, String routingKey, useProps, body)); } + + /** Public API - {@inheritDoc} */ public Exchange.DeclareOk exchangeDeclare(String exchange, String type, boolean durable, boolean autoDelete, @@ -673,6 +665,17 @@ public Exchange.DeclareOk exchangeDeclare(String exchange, String type, arguments); } + /** Public API - {@inheritDoc} */ + public Exchange.DeclareOk exchangeDeclare(String exchange, ExchangeType type, + boolean durable, boolean autoDelete, + Map arguments) + throws IOException + { + return exchangeDeclare(exchange, type.getType(), + durable, autoDelete, + arguments); + } + public void exchangeDeclareNoWait(String exchange, String type, boolean durable, @@ -691,6 +694,17 @@ public void exchangeDeclareNoWait(String exchange, .build())); } + public void exchangeDeclareNoWait(String exchange, + ExchangeType type, + boolean durable, + boolean autoDelete, + boolean internal, + Map arguments) throws IOException { + exchangeDeclareNoWait(exchange, type.getType(), + durable, autoDelete, internal, + arguments); + } + /** Public API - {@inheritDoc} */ public Exchange.DeclareOk exchangeDeclare(String exchange, String type, boolean durable, @@ -711,6 +725,19 @@ public Exchange.DeclareOk exchangeDeclare(String exchange, String type, .getMethod(); } + /** Public API - {@inheritDoc} */ + public Exchange.DeclareOk exchangeDeclare(String exchange, ExchangeType type, + boolean durable, + boolean autoDelete, + boolean internal, + Map arguments) + throws IOException + { + return exchangeDeclare(exchange, type.getType(), + durable, autoDelete, internal, + arguments); + } + /** Public API - {@inheritDoc} */ public Exchange.DeclareOk exchangeDeclare(String exchange, String type, boolean durable) @@ -719,6 +746,14 @@ public Exchange.DeclareOk exchangeDeclare(String exchange, String type, return exchangeDeclare(exchange, type, durable, false, null); } + /** Public API - {@inheritDoc} */ + public Exchange.DeclareOk exchangeDeclare(String exchange, ExchangeType type, + boolean durable) + throws IOException + { + return exchangeDeclare(exchange, type.getType(), durable); + } + /** Public API - {@inheritDoc} */ public Exchange.DeclareOk exchangeDeclare(String exchange, String type) throws IOException @@ -726,6 +761,13 @@ public Exchange.DeclareOk exchangeDeclare(String exchange, String type) return exchangeDeclare(exchange, type, false, false, null); } + /** Public API - {@inheritDoc} */ + public Exchange.DeclareOk exchangeDeclare(String exchange, ExchangeType type) + throws IOException + { + return exchangeDeclare(exchange, type.getType()); + } + /** Public API - {@inheritDoc} */ public Exchange.DeclareOk exchangeDeclarePassive(String exchange) throws IOException diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java index 10445d697a..b53cbfaa09 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java @@ -15,20 +15,7 @@ package com.rabbitmq.client.impl.recovery; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.Command; -import com.rabbitmq.client.ConfirmListener; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.Consumer; -import com.rabbitmq.client.FlowListener; -import com.rabbitmq.client.GetResponse; -import com.rabbitmq.client.Method; -import com.rabbitmq.client.Recoverable; -import com.rabbitmq.client.RecoveryListener; -import com.rabbitmq.client.ReturnListener; -import com.rabbitmq.client.ShutdownListener; -import com.rabbitmq.client.ShutdownSignalException; +import com.rabbitmq.client.*; import java.io.IOException; import java.util.ArrayList; @@ -195,14 +182,26 @@ public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, String type) thr return exchangeDeclare(exchange, type, false, false, null); } + public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, ExchangeType type) throws IOException { + return exchangeDeclare(exchange, type.getType()); + } + public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, String type, boolean durable) throws IOException { return exchangeDeclare(exchange, type, durable, false, null); } + public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, ExchangeType type, boolean durable) throws IOException { + return exchangeDeclare(exchange, type.getType(), durable); + } + public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, String type, boolean durable, boolean autoDelete, Map arguments) throws IOException { return exchangeDeclare(exchange, type, durable, autoDelete, false, arguments); } + public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, ExchangeType type, boolean durable, boolean autoDelete, Map arguments) throws IOException { + return exchangeDeclare(exchange, type.getType(), durable, autoDelete, arguments); + } + public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, String type, boolean durable, boolean autoDelete, boolean internal, Map arguments) throws IOException { final AMQP.Exchange.DeclareOk ok = delegate.exchangeDeclare(exchange, type, durable, autoDelete, internal, arguments); RecordedExchange x = new RecordedExchange(this, exchange). @@ -214,6 +213,10 @@ public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, String type, boo return ok; } + public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, ExchangeType type, boolean durable, boolean autoDelete, boolean internal, Map arguments) throws IOException { + return exchangeDeclare(exchange, type.getType(), durable, autoDelete, internal, arguments); + } + @Override public void exchangeDeclareNoWait(String exchange, String type, boolean durable, boolean autoDelete, boolean internal, Map arguments) throws IOException { RecordedExchange x = new RecordedExchange(this, exchange). @@ -225,6 +228,11 @@ public void exchangeDeclareNoWait(String exchange, String type, boolean durable, delegate.exchangeDeclareNoWait(exchange, type, durable, autoDelete, internal, arguments); } + @Override + public void exchangeDeclareNoWait(String exchange, ExchangeType type, boolean durable, boolean autoDelete, boolean internal, Map arguments) throws IOException { + exchangeDeclareNoWait(exchange, type.getType(), durable, autoDelete, internal, arguments); + } + public AMQP.Exchange.DeclareOk exchangeDeclarePassive(String name) throws IOException { return delegate.exchangeDeclarePassive(name); } diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java index 14010acb96..61939a7b09 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java @@ -16,9 +16,15 @@ package com.rabbitmq.client.test.functional; -import java.util.Map; -import java.util.HashMap; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.ExchangeType; + import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeoutException; public class ExchangeDeclare extends ExchangeEquivalenceBase { @@ -56,4 +62,46 @@ public void testExchangeAutoDeleteNotEquivalent() throws IOException { channel.exchangeDeclare(NAME, "direct", false, false, null); verifyNotEquivalent(NAME, "direct", false, true, null); } + + public void testExchangeDeclaredWithEnumerationEquivalentOnNonRecoverableConnection() throws IOException, InterruptedException { + doTestExchangeDeclaredWithEnumerationEquivalent(channel); + } + + public void testExchangeDeclaredWithEnumerationEquivalentOnRecoverableConnection() throws IOException, TimeoutException, InterruptedException { + ConnectionFactory connectionFactory = new ConnectionFactory(); + connectionFactory.setAutomaticRecoveryEnabled(true); + connectionFactory.setTopologyRecoveryEnabled(false); + Connection c = connectionFactory.newConnection(); + try { + doTestExchangeDeclaredWithEnumerationEquivalent(c.createChannel()); + } finally { + c.abort(); + } + + } + + private void doTestExchangeDeclaredWithEnumerationEquivalent(Channel channel) throws IOException, InterruptedException { + assertEquals("There are 4 standard exchange types", 4, ExchangeType.values().length); + for (ExchangeType exchangeType : ExchangeType.values()) { + channel.exchangeDeclare(NAME, exchangeType); + verifyEquivalent(NAME, exchangeType.getType(), false, false, null); + channel.exchangeDelete(NAME); + + channel.exchangeDeclare(NAME, exchangeType, false); + verifyEquivalent(NAME, exchangeType.getType(), false, false, null); + channel.exchangeDelete(NAME); + + channel.exchangeDeclare(NAME, exchangeType, false, false, null); + verifyEquivalent(NAME, exchangeType.getType(), false, false, null); + channel.exchangeDelete(NAME); + + channel.exchangeDeclare(NAME, exchangeType, false, false, false, null); + verifyEquivalent(NAME, exchangeType.getType(), false, false, null); + channel.exchangeDelete(NAME); + + channel.exchangeDeclareNoWait(NAME, exchangeType, false, false, false, null); + // no check, this one is asynchronous + channel.exchangeDelete(NAME); + } + } } From 290602ef9161efbcbba22c33280a2cbe40b03dbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 24 Aug 2016 11:26:51 +0200 Subject: [PATCH 0220/2114] Rename ExchangeType to BuiltinExchangeType Fixes #150 --- .../{ExchangeType.java => BuiltinExchangeType.java} | 6 +++--- src/main/java/com/rabbitmq/client/Channel.java | 10 +++++----- src/main/java/com/rabbitmq/client/impl/ChannelN.java | 10 +++++----- .../client/impl/recovery/AutorecoveringChannel.java | 10 +++++----- .../client/test/functional/ExchangeDeclare.java | 6 +++--- 5 files changed, 21 insertions(+), 21 deletions(-) rename src/main/java/com/rabbitmq/client/{ExchangeType.java => BuiltinExchangeType.java} (68%) diff --git a/src/main/java/com/rabbitmq/client/ExchangeType.java b/src/main/java/com/rabbitmq/client/BuiltinExchangeType.java similarity index 68% rename from src/main/java/com/rabbitmq/client/ExchangeType.java rename to src/main/java/com/rabbitmq/client/BuiltinExchangeType.java index 693fb01f32..f64bbe66ea 100644 --- a/src/main/java/com/rabbitmq/client/ExchangeType.java +++ b/src/main/java/com/rabbitmq/client/BuiltinExchangeType.java @@ -1,15 +1,15 @@ package com.rabbitmq.client; /** - * + * Enum for built-in exchange types. */ -public enum ExchangeType { +public enum BuiltinExchangeType { DIRECT("direct"), FANOUT("fanout"), TOPIC("topic"), HEADERS("headers"); private final String type; - ExchangeType(String type) { + BuiltinExchangeType(String type) { this.type = type; } diff --git a/src/main/java/com/rabbitmq/client/Channel.java b/src/main/java/com/rabbitmq/client/Channel.java index 2110f45755..2343644aca 100644 --- a/src/main/java/com/rabbitmq/client/Channel.java +++ b/src/main/java/com/rabbitmq/client/Channel.java @@ -329,7 +329,7 @@ void basicPublish(String exchange, String routingKey, boolean mandatory, boolean * @return a declaration-confirm method to indicate the exchange was successfully declared * @throws java.io.IOException if an error is encountered */ - Exchange.DeclareOk exchangeDeclare(String exchange, ExchangeType type) throws IOException; + Exchange.DeclareOk exchangeDeclare(String exchange, BuiltinExchangeType type) throws IOException; /** * Actively declare a non-autodelete exchange with no extra arguments @@ -353,7 +353,7 @@ void basicPublish(String exchange, String routingKey, boolean mandatory, boolean * @throws java.io.IOException if an error is encountered * @return a declaration-confirm method to indicate the exchange was successfully declared */ - Exchange.DeclareOk exchangeDeclare(String exchange, ExchangeType type, boolean durable) throws IOException; + Exchange.DeclareOk exchangeDeclare(String exchange, BuiltinExchangeType type, boolean durable) throws IOException; /** * Declare an exchange. @@ -382,7 +382,7 @@ Exchange.DeclareOk exchangeDeclare(String exchange, String type, boolean durable * @return a declaration-confirm method to indicate the exchange was successfully declared * @throws java.io.IOException if an error is encountered */ - Exchange.DeclareOk exchangeDeclare(String exchange, ExchangeType type, boolean durable, boolean autoDelete, + Exchange.DeclareOk exchangeDeclare(String exchange, BuiltinExchangeType type, boolean durable, boolean autoDelete, Map arguments) throws IOException; /** @@ -423,7 +423,7 @@ Exchange.DeclareOk exchangeDeclare(String exchange, * @throws java.io.IOException if an error is encountered */ Exchange.DeclareOk exchangeDeclare(String exchange, - ExchangeType type, + BuiltinExchangeType type, boolean durable, boolean autoDelete, boolean internal, @@ -465,7 +465,7 @@ void exchangeDeclareNoWait(String exchange, * @throws java.io.IOException if an error is encountered */ void exchangeDeclareNoWait(String exchange, - ExchangeType type, + BuiltinExchangeType type, boolean durable, boolean autoDelete, boolean internal, diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java index 7ea0019ab6..0d8d8a86d0 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelN.java @@ -666,7 +666,7 @@ public Exchange.DeclareOk exchangeDeclare(String exchange, String type, } /** Public API - {@inheritDoc} */ - public Exchange.DeclareOk exchangeDeclare(String exchange, ExchangeType type, + public Exchange.DeclareOk exchangeDeclare(String exchange, BuiltinExchangeType type, boolean durable, boolean autoDelete, Map arguments) throws IOException @@ -695,7 +695,7 @@ public void exchangeDeclareNoWait(String exchange, } public void exchangeDeclareNoWait(String exchange, - ExchangeType type, + BuiltinExchangeType type, boolean durable, boolean autoDelete, boolean internal, @@ -726,7 +726,7 @@ public Exchange.DeclareOk exchangeDeclare(String exchange, String type, } /** Public API - {@inheritDoc} */ - public Exchange.DeclareOk exchangeDeclare(String exchange, ExchangeType type, + public Exchange.DeclareOk exchangeDeclare(String exchange, BuiltinExchangeType type, boolean durable, boolean autoDelete, boolean internal, @@ -747,7 +747,7 @@ public Exchange.DeclareOk exchangeDeclare(String exchange, String type, } /** Public API - {@inheritDoc} */ - public Exchange.DeclareOk exchangeDeclare(String exchange, ExchangeType type, + public Exchange.DeclareOk exchangeDeclare(String exchange, BuiltinExchangeType type, boolean durable) throws IOException { @@ -762,7 +762,7 @@ public Exchange.DeclareOk exchangeDeclare(String exchange, String type) } /** Public API - {@inheritDoc} */ - public Exchange.DeclareOk exchangeDeclare(String exchange, ExchangeType type) + public Exchange.DeclareOk exchangeDeclare(String exchange, BuiltinExchangeType type) throws IOException { return exchangeDeclare(exchange, type.getType()); diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java index b53cbfaa09..4ae30918a2 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java @@ -182,7 +182,7 @@ public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, String type) thr return exchangeDeclare(exchange, type, false, false, null); } - public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, ExchangeType type) throws IOException { + public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, BuiltinExchangeType type) throws IOException { return exchangeDeclare(exchange, type.getType()); } @@ -190,7 +190,7 @@ public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, String type, boo return exchangeDeclare(exchange, type, durable, false, null); } - public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, ExchangeType type, boolean durable) throws IOException { + public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, BuiltinExchangeType type, boolean durable) throws IOException { return exchangeDeclare(exchange, type.getType(), durable); } @@ -198,7 +198,7 @@ public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, String type, boo return exchangeDeclare(exchange, type, durable, autoDelete, false, arguments); } - public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, ExchangeType type, boolean durable, boolean autoDelete, Map arguments) throws IOException { + public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, BuiltinExchangeType type, boolean durable, boolean autoDelete, Map arguments) throws IOException { return exchangeDeclare(exchange, type.getType(), durable, autoDelete, arguments); } @@ -213,7 +213,7 @@ public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, String type, boo return ok; } - public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, ExchangeType type, boolean durable, boolean autoDelete, boolean internal, Map arguments) throws IOException { + public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, BuiltinExchangeType type, boolean durable, boolean autoDelete, boolean internal, Map arguments) throws IOException { return exchangeDeclare(exchange, type.getType(), durable, autoDelete, internal, arguments); } @@ -229,7 +229,7 @@ public void exchangeDeclareNoWait(String exchange, String type, boolean durable, } @Override - public void exchangeDeclareNoWait(String exchange, ExchangeType type, boolean durable, boolean autoDelete, boolean internal, Map arguments) throws IOException { + public void exchangeDeclareNoWait(String exchange, BuiltinExchangeType type, boolean durable, boolean autoDelete, boolean internal, Map arguments) throws IOException { exchangeDeclareNoWait(exchange, type.getType(), durable, autoDelete, internal, arguments); } diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java index 61939a7b09..f699f9bb3c 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java @@ -19,7 +19,7 @@ import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; -import com.rabbitmq.client.ExchangeType; +import com.rabbitmq.client.BuiltinExchangeType; import java.io.IOException; import java.util.HashMap; @@ -81,8 +81,8 @@ public void testExchangeDeclaredWithEnumerationEquivalentOnRecoverableConnection } private void doTestExchangeDeclaredWithEnumerationEquivalent(Channel channel) throws IOException, InterruptedException { - assertEquals("There are 4 standard exchange types", 4, ExchangeType.values().length); - for (ExchangeType exchangeType : ExchangeType.values()) { + assertEquals("There are 4 standard exchange types", 4, BuiltinExchangeType.values().length); + for (BuiltinExchangeType exchangeType : BuiltinExchangeType.values()) { channel.exchangeDeclare(NAME, exchangeType); verifyEquivalent(NAME, exchangeType.getType(), false, false, null); channel.exchangeDelete(NAME); From 438051472cb7e07dbde8adcc37ecc01c528bf86e Mon Sep 17 00:00:00 2001 From: ayoub Date: Tue, 9 Aug 2016 07:38:21 -0500 Subject: [PATCH 0221/2114] Add config manager for openstack perf utility --- .../examples/perf/openstack/Consumer.java | 5 ++ .../examples/perf/openstack/Producer.java | 14 ++++ .../perf/openstack/samples/Configuration.java | 66 +++++++++++++++++++ 3 files changed, 85 insertions(+) create mode 100644 src/test/java/com/rabbitmq/examples/perf/openstack/Consumer.java create mode 100644 src/test/java/com/rabbitmq/examples/perf/openstack/Producer.java create mode 100644 src/test/java/com/rabbitmq/examples/perf/openstack/samples/Configuration.java diff --git a/src/test/java/com/rabbitmq/examples/perf/openstack/Consumer.java b/src/test/java/com/rabbitmq/examples/perf/openstack/Consumer.java new file mode 100644 index 0000000000..b372182a79 --- /dev/null +++ b/src/test/java/com/rabbitmq/examples/perf/openstack/Consumer.java @@ -0,0 +1,5 @@ +package com.rabbitmq.examples.perf.openstack; + +public class Consumer { + +} diff --git a/src/test/java/com/rabbitmq/examples/perf/openstack/Producer.java b/src/test/java/com/rabbitmq/examples/perf/openstack/Producer.java new file mode 100644 index 0000000000..4ecaa536cc --- /dev/null +++ b/src/test/java/com/rabbitmq/examples/perf/openstack/Producer.java @@ -0,0 +1,14 @@ +package com.rabbitmq.examples.perf.openstack; + +import com.rabbitmq.examples.perf.ProducerConsumerBase; + +/* + * This producer will publish OpenStack-alike messages to the RabbitMQ server. + * These messages simulate the OpenStack heartbeats, in particular, those that + * are used by Nova and Neutron modules to update N-CPU, L2, L3 and DHCP agents' + * status. + */ + +public class Producer extends ProducerConsumerBase { + +} diff --git a/src/test/java/com/rabbitmq/examples/perf/openstack/samples/Configuration.java b/src/test/java/com/rabbitmq/examples/perf/openstack/samples/Configuration.java new file mode 100644 index 0000000000..249023dae1 --- /dev/null +++ b/src/test/java/com/rabbitmq/examples/perf/openstack/samples/Configuration.java @@ -0,0 +1,66 @@ +package com.rabbitmq.examples.perf.openstack.samples; + +public class Configuration { + + //------------------------------------- + //AMQP messages sizes in Bytes + //Note: VN: Virtual Network, VM: Virtual Machine + //compute node published heartbeats (0 VN 0 VM): exchange originated + public static final int RPC_NOVA_OA_MEAN_SIZE = 1890; + public static final int RPC_NOVA_OCAV_MEAN_SIZE = 1890; + public static final int RPC_NOVA_SII_MEAN_SIZE = 1000; + public static final int RPC_NEUTRON_RS_MEAN_SIZE = 1530; + + //compute node consumed heartbeats: queue originated + public static final int RPC_NOVA_REPLY_MEAN_SIZE = 640; + public static final int RPC_NEUTRON_REPLY_MEAN_SIZE = 200; + + private static final int NBR_OF_VARIABLES = 6; + + //additional size when resources are deployed (1 VN 1 VM): exchange + public static final int RPC_NOVA_OA_ADD_SIZE = 110; + public static final int RPC_NOVA_OCAV_ADD_SIZE = 110; + public static final int RPC_NOVA_SII_ADD_SIZE = 210; + public static final int RPC_NEUTRON_RS_ADD_SIZE = 0; + + //additional size of queue originated messages + public static final int RPC_NOVA_REPLY_ADD_SIZE = 480; + public static final int RPC_NEUTRON_REPLY_ADD_SIZE = 40; + + //------------------------------------- + //POP (Point of Presence; i.e. Datacenter) simulation variables + //For example: the number of compute nodes in a POP. + private int nbr_cpun; + private int nbr_vn; + private int nbr_vm_cpun; +// private int nbr_vm_vn; +// private int nbr_cross_vn; + + public Configuration(int nbr_cpu_nodes_per_pop, int nbr_vn_per_pop, + int nbr_vm_per_cpu_node, int nbr_vm_per_vn, int nbr_cross_pop_vn) { + + nbr_cpun = nbr_cpu_nodes_per_pop; + nbr_vn = nbr_vn_per_pop; + nbr_vm_cpun = nbr_vm_per_cpu_node; +// nbr_vm_vn = nbr_vm_per_vn; +// nbr_cross_vn = nbr_cross_pop_vn; + + } + + public int[] getPopConfigMatrix() { + int[] config = new int[NBR_OF_VARIABLES]; + config[0] = RPC_NOVA_OA_MEAN_SIZE + RPC_NOVA_OA_ADD_SIZE * nbr_vm_cpun; + config[1] = RPC_NOVA_OCAV_MEAN_SIZE + RPC_NOVA_OCAV_ADD_SIZE * nbr_vm_cpun; + config[2] = RPC_NOVA_SII_MEAN_SIZE + RPC_NOVA_SII_ADD_SIZE * nbr_vm_cpun; + config[3] = RPC_NEUTRON_RS_MEAN_SIZE + RPC_NEUTRON_RS_ADD_SIZE * nbr_vn; + config[4] = RPC_NOVA_REPLY_MEAN_SIZE + RPC_NOVA_REPLY_ADD_SIZE * nbr_vm_cpun; + config[5] = RPC_NEUTRON_REPLY_MEAN_SIZE + RPC_NEUTRON_REPLY_ADD_SIZE * nbr_vn; + + for (int i = 0; i < config.length; i++) { + config[i] = config[i] * nbr_cpun; + } + + return config; + } + +} From f4bda2b998a8d2983f5a6072246afb28325a9692 Mon Sep 17 00:00:00 2001 From: ayoub Date: Tue, 9 Aug 2016 10:49:53 -0500 Subject: [PATCH 0222/2114] Remove Configuration and empty P/C classes. --- .../examples/perf/openstack/Consumer.java | 5 -- .../examples/perf/openstack/Producer.java | 14 ---- .../perf/openstack/samples/Configuration.java | 66 ------------------- 3 files changed, 85 deletions(-) delete mode 100644 src/test/java/com/rabbitmq/examples/perf/openstack/Consumer.java delete mode 100644 src/test/java/com/rabbitmq/examples/perf/openstack/Producer.java delete mode 100644 src/test/java/com/rabbitmq/examples/perf/openstack/samples/Configuration.java diff --git a/src/test/java/com/rabbitmq/examples/perf/openstack/Consumer.java b/src/test/java/com/rabbitmq/examples/perf/openstack/Consumer.java deleted file mode 100644 index b372182a79..0000000000 --- a/src/test/java/com/rabbitmq/examples/perf/openstack/Consumer.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.rabbitmq.examples.perf.openstack; - -public class Consumer { - -} diff --git a/src/test/java/com/rabbitmq/examples/perf/openstack/Producer.java b/src/test/java/com/rabbitmq/examples/perf/openstack/Producer.java deleted file mode 100644 index 4ecaa536cc..0000000000 --- a/src/test/java/com/rabbitmq/examples/perf/openstack/Producer.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.rabbitmq.examples.perf.openstack; - -import com.rabbitmq.examples.perf.ProducerConsumerBase; - -/* - * This producer will publish OpenStack-alike messages to the RabbitMQ server. - * These messages simulate the OpenStack heartbeats, in particular, those that - * are used by Nova and Neutron modules to update N-CPU, L2, L3 and DHCP agents' - * status. - */ - -public class Producer extends ProducerConsumerBase { - -} diff --git a/src/test/java/com/rabbitmq/examples/perf/openstack/samples/Configuration.java b/src/test/java/com/rabbitmq/examples/perf/openstack/samples/Configuration.java deleted file mode 100644 index 249023dae1..0000000000 --- a/src/test/java/com/rabbitmq/examples/perf/openstack/samples/Configuration.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.rabbitmq.examples.perf.openstack.samples; - -public class Configuration { - - //------------------------------------- - //AMQP messages sizes in Bytes - //Note: VN: Virtual Network, VM: Virtual Machine - //compute node published heartbeats (0 VN 0 VM): exchange originated - public static final int RPC_NOVA_OA_MEAN_SIZE = 1890; - public static final int RPC_NOVA_OCAV_MEAN_SIZE = 1890; - public static final int RPC_NOVA_SII_MEAN_SIZE = 1000; - public static final int RPC_NEUTRON_RS_MEAN_SIZE = 1530; - - //compute node consumed heartbeats: queue originated - public static final int RPC_NOVA_REPLY_MEAN_SIZE = 640; - public static final int RPC_NEUTRON_REPLY_MEAN_SIZE = 200; - - private static final int NBR_OF_VARIABLES = 6; - - //additional size when resources are deployed (1 VN 1 VM): exchange - public static final int RPC_NOVA_OA_ADD_SIZE = 110; - public static final int RPC_NOVA_OCAV_ADD_SIZE = 110; - public static final int RPC_NOVA_SII_ADD_SIZE = 210; - public static final int RPC_NEUTRON_RS_ADD_SIZE = 0; - - //additional size of queue originated messages - public static final int RPC_NOVA_REPLY_ADD_SIZE = 480; - public static final int RPC_NEUTRON_REPLY_ADD_SIZE = 40; - - //------------------------------------- - //POP (Point of Presence; i.e. Datacenter) simulation variables - //For example: the number of compute nodes in a POP. - private int nbr_cpun; - private int nbr_vn; - private int nbr_vm_cpun; -// private int nbr_vm_vn; -// private int nbr_cross_vn; - - public Configuration(int nbr_cpu_nodes_per_pop, int nbr_vn_per_pop, - int nbr_vm_per_cpu_node, int nbr_vm_per_vn, int nbr_cross_pop_vn) { - - nbr_cpun = nbr_cpu_nodes_per_pop; - nbr_vn = nbr_vn_per_pop; - nbr_vm_cpun = nbr_vm_per_cpu_node; -// nbr_vm_vn = nbr_vm_per_vn; -// nbr_cross_vn = nbr_cross_pop_vn; - - } - - public int[] getPopConfigMatrix() { - int[] config = new int[NBR_OF_VARIABLES]; - config[0] = RPC_NOVA_OA_MEAN_SIZE + RPC_NOVA_OA_ADD_SIZE * nbr_vm_cpun; - config[1] = RPC_NOVA_OCAV_MEAN_SIZE + RPC_NOVA_OCAV_ADD_SIZE * nbr_vm_cpun; - config[2] = RPC_NOVA_SII_MEAN_SIZE + RPC_NOVA_SII_ADD_SIZE * nbr_vm_cpun; - config[3] = RPC_NEUTRON_RS_MEAN_SIZE + RPC_NEUTRON_RS_ADD_SIZE * nbr_vn; - config[4] = RPC_NOVA_REPLY_MEAN_SIZE + RPC_NOVA_REPLY_ADD_SIZE * nbr_vm_cpun; - config[5] = RPC_NEUTRON_REPLY_MEAN_SIZE + RPC_NEUTRON_REPLY_ADD_SIZE * nbr_vn; - - for (int i = 0; i < config.length; i++) { - config[i] = config[i] * nbr_cpun; - } - - return config; - } - -} From 5113b8baa32d7f1f62c04a06f3d634b9e1ee54d5 Mon Sep 17 00:00:00 2001 From: ayoub Date: Mon, 22 Aug 2016 07:23:42 -0500 Subject: [PATCH 0223/2114] Add an ID to PerfTest output. --- src/test/java/com/rabbitmq/examples/PerfTest.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/examples/PerfTest.java b/src/test/java/com/rabbitmq/examples/PerfTest.java index e65c057ed4..1244044500 100644 --- a/src/test/java/com/rabbitmq/examples/PerfTest.java +++ b/src/test/java/com/rabbitmq/examples/PerfTest.java @@ -15,7 +15,9 @@ package com.rabbitmq.examples; +import java.text.SimpleDateFormat; import java.util.Arrays; +import java.util.Calendar; import java.util.List; import com.rabbitmq.examples.perf.MulticastParams; @@ -33,6 +35,9 @@ public class PerfTest { + + private static String testID; + public static void main(String[] args) { Options options = getOptions(); CommandLineParser parser = new GnuParser(); @@ -43,7 +48,9 @@ public static void main(String[] args) { usage(options); System.exit(0); } - + testID = new SimpleDateFormat("HH:mm:ss.SSS").format(Calendar. + getInstance().getTime()); + testID = strArg(cmd, 'd', "test-" + testID); String exchangeType = strArg(cmd, 't', "direct"); String exchangeName = strArg(cmd, 'e', exchangeType); String queueName = strArg(cmd, 'u', ""); @@ -135,6 +142,7 @@ private static void usage(Options options) { private static Options getOptions() { Options options = new Options(); options.addOption(new Option("?", "help", false,"show usage")); + options.addOption(new Option("d", "id", true, "Test ID")); options.addOption(new Option("h", "uri", true, "connection URI")); options.addOption(new Option("t", "type", true, "exchange type")); options.addOption(new Option("e", "exchange", true, "exchange name")); @@ -204,6 +212,7 @@ public PrintlnStats(long interval, @Override protected void report(long now) { + System.out.print("id: " + testID + ", "); System.out.print("time: " + String.format("%.3f", (now - startTime)/1000.0) + "s"); showRate("sent", sendCountInterval, sendStatsEnabled, elapsedInterval); From 40eb0fe6aab0a8f8de1b2acba4f189ec0236e29a Mon Sep 17 00:00:00 2001 From: ayoub Date: Mon, 22 Aug 2016 11:22:23 -0500 Subject: [PATCH 0224/2114] Update test ID declaration. --- .../java/com/rabbitmq/examples/PerfTest.java | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/test/java/com/rabbitmq/examples/PerfTest.java b/src/test/java/com/rabbitmq/examples/PerfTest.java index 1244044500..5a177a2aac 100644 --- a/src/test/java/com/rabbitmq/examples/PerfTest.java +++ b/src/test/java/com/rabbitmq/examples/PerfTest.java @@ -36,8 +36,6 @@ public class PerfTest { - private static String testID; - public static void main(String[] args) { Options options = getOptions(); CommandLineParser parser = new GnuParser(); @@ -48,9 +46,9 @@ public static void main(String[] args) { usage(options); System.exit(0); } - testID = new SimpleDateFormat("HH:mm:ss.SSS").format(Calendar. + String testID = new SimpleDateFormat("HHmmss-SSS").format(Calendar. getInstance().getTime()); - testID = strArg(cmd, 'd', "test-" + testID); + testID = strArg(cmd, 'd', "test-"+testID); String exchangeType = strArg(cmd, 't', "direct"); String exchangeName = strArg(cmd, 'e', exchangeType); String queueName = strArg(cmd, 'u', ""); @@ -80,12 +78,13 @@ public static void main(String[] args) { String uri = strArg(cmd, 'h', "amqp://localhost"); //setup - PrintlnStats stats = new PrintlnStats(1000L * samplingInterval, - producerCount > 0, - consumerCount > 0, - (flags.contains("mandatory") || - flags.contains("immediate")), - confirm != -1); + PrintlnStats stats = new PrintlnStats(testID, + 1000L * samplingInterval, + producerCount > 0, + consumerCount > 0, + (flags.contains("mandatory") || + flags.contains("immediate")), + confirm != -1); ConnectionFactory factory = new ConnectionFactory(); factory.setShutdownTimeout(0); // So we still shut down even with slow consumers @@ -199,8 +198,10 @@ private static class PrintlnStats extends Stats { private final boolean recvStatsEnabled; private final boolean returnStatsEnabled; private final boolean confirmStatsEnabled; + + private final String testID; - public PrintlnStats(long interval, + public PrintlnStats(String testID, long interval, boolean sendStatsEnabled, boolean recvStatsEnabled, boolean returnStatsEnabled, boolean confirmStatsEnabled) { super(interval); @@ -208,11 +209,13 @@ public PrintlnStats(long interval, this.recvStatsEnabled = recvStatsEnabled; this.returnStatsEnabled = returnStatsEnabled; this.confirmStatsEnabled = confirmStatsEnabled; + this.testID = testID; } @Override protected void report(long now) { System.out.print("id: " + testID + ", "); + System.out.print("time: " + String.format("%.3f", (now - startTime)/1000.0) + "s"); showRate("sent", sendCountInterval, sendStatsEnabled, elapsedInterval); From 152595f85f5f296d555ab50ccfb8d071e35b8e45 Mon Sep 17 00:00:00 2001 From: ayoub Date: Mon, 22 Aug 2016 11:46:44 -0500 Subject: [PATCH 0225/2114] Update PerfTest System.out. --- .../java/com/rabbitmq/examples/PerfTest.java | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/test/java/com/rabbitmq/examples/PerfTest.java b/src/test/java/com/rabbitmq/examples/PerfTest.java index 5a177a2aac..4e44c2bf89 100644 --- a/src/test/java/com/rabbitmq/examples/PerfTest.java +++ b/src/test/java/com/rabbitmq/examples/PerfTest.java @@ -214,31 +214,32 @@ public PrintlnStats(String testID, long interval, @Override protected void report(long now) { - System.out.print("id: " + testID + ", "); + String output = "id: " + testID + ", "; - System.out.print("time: " + String.format("%.3f", (now - startTime)/1000.0) + "s"); + output += "time: " + String.format("%.3f", (now - startTime)/1000.0) + "s"; + output += + showRate("sent", sendCountInterval, sendStatsEnabled, elapsedInterval) + + showRate("returned", returnCountInterval, sendStatsEnabled && returnStatsEnabled, elapsedInterval) + + showRate("confirmed", confirmCountInterval, sendStatsEnabled && confirmStatsEnabled, elapsedInterval) + + showRate("nacked", nackCountInterval, sendStatsEnabled && confirmStatsEnabled, elapsedInterval) + + showRate("received", recvCountInterval, recvStatsEnabled, elapsedInterval); - showRate("sent", sendCountInterval, sendStatsEnabled, elapsedInterval); - showRate("returned", returnCountInterval, sendStatsEnabled && returnStatsEnabled, elapsedInterval); - showRate("confirmed", confirmCountInterval, sendStatsEnabled && confirmStatsEnabled, elapsedInterval); - showRate("nacked", nackCountInterval, sendStatsEnabled && confirmStatsEnabled, elapsedInterval); - showRate("received", recvCountInterval, recvStatsEnabled, elapsedInterval); - - System.out.print((latencyCountInterval > 0 ? + output += (latencyCountInterval > 0 ? ", min/avg/max latency: " + minLatency/1000L + "/" + cumulativeLatencyInterval / (1000L * latencyCountInterval) + "/" + maxLatency/1000L + " microseconds" : - "")); + ""); - System.out.println(); + System.out.println(output); } - private void showRate(String descr, long count, boolean display, + private String showRate(String descr, long count, boolean display, long elapsed) { - if (display) { - System.out.print(", " + descr + ": " + formatRate(1000.0 * count / elapsed) + " msg/s"); - } + if (display) + return ", " + descr + ": " + formatRate(1000.0 * count / elapsed) + " msg/s"; + else + return ""; } public void printFinal() { From e6ad1acc5fa470afdb2b9c51729e491536e6cc51 Mon Sep 17 00:00:00 2001 From: ayoub Date: Tue, 23 Aug 2016 04:55:30 -0500 Subject: [PATCH 0226/2114] Correction of an identation mistake. --- src/test/java/com/rabbitmq/examples/PerfTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/examples/PerfTest.java b/src/test/java/com/rabbitmq/examples/PerfTest.java index 4e44c2bf89..dec52632bb 100644 --- a/src/test/java/com/rabbitmq/examples/PerfTest.java +++ b/src/test/java/com/rabbitmq/examples/PerfTest.java @@ -48,7 +48,7 @@ public static void main(String[] args) { } String testID = new SimpleDateFormat("HHmmss-SSS").format(Calendar. getInstance().getTime()); - testID = strArg(cmd, 'd', "test-"+testID); + testID = strArg(cmd, 'd', "test-"+testID); String exchangeType = strArg(cmd, 't', "direct"); String exchangeName = strArg(cmd, 'e', exchangeType); String queueName = strArg(cmd, 'u', ""); From 0ef004069fa0ed8a0ac8eb84e249dd29f7c9a50c Mon Sep 17 00:00:00 2001 From: ayoub Date: Tue, 23 Aug 2016 11:25:25 -0500 Subject: [PATCH 0227/2114] Change showRate to getRate. --- src/test/java/com/rabbitmq/examples/PerfTest.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/test/java/com/rabbitmq/examples/PerfTest.java b/src/test/java/com/rabbitmq/examples/PerfTest.java index dec52632bb..25add55314 100644 --- a/src/test/java/com/rabbitmq/examples/PerfTest.java +++ b/src/test/java/com/rabbitmq/examples/PerfTest.java @@ -218,11 +218,11 @@ protected void report(long now) { output += "time: " + String.format("%.3f", (now - startTime)/1000.0) + "s"; output += - showRate("sent", sendCountInterval, sendStatsEnabled, elapsedInterval) + - showRate("returned", returnCountInterval, sendStatsEnabled && returnStatsEnabled, elapsedInterval) + - showRate("confirmed", confirmCountInterval, sendStatsEnabled && confirmStatsEnabled, elapsedInterval) + - showRate("nacked", nackCountInterval, sendStatsEnabled && confirmStatsEnabled, elapsedInterval) + - showRate("received", recvCountInterval, recvStatsEnabled, elapsedInterval); + getRate("sent", sendCountInterval, sendStatsEnabled, elapsedInterval) + + getRate("returned", returnCountInterval, sendStatsEnabled && returnStatsEnabled, elapsedInterval) + + getRate("confirmed", confirmCountInterval, sendStatsEnabled && confirmStatsEnabled, elapsedInterval) + + getRate("nacked", nackCountInterval, sendStatsEnabled && confirmStatsEnabled, elapsedInterval) + + getRate("received", recvCountInterval, recvStatsEnabled, elapsedInterval); output += (latencyCountInterval > 0 ? ", min/avg/max latency: " + @@ -234,7 +234,7 @@ protected void report(long now) { System.out.println(output); } - private String showRate(String descr, long count, boolean display, + private String getRate(String descr, long count, boolean display, long elapsed) { if (display) return ", " + descr + ": " + formatRate(1000.0 * count / elapsed) + " msg/s"; From 223317bec1df3bec457cc9adf972475533a90343 Mon Sep 17 00:00:00 2001 From: ayoub Date: Tue, 23 Aug 2016 11:28:35 -0500 Subject: [PATCH 0228/2114] Correct indentation mistake. --- src/test/java/com/rabbitmq/examples/PerfTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/examples/PerfTest.java b/src/test/java/com/rabbitmq/examples/PerfTest.java index 25add55314..99a93ce267 100644 --- a/src/test/java/com/rabbitmq/examples/PerfTest.java +++ b/src/test/java/com/rabbitmq/examples/PerfTest.java @@ -218,7 +218,7 @@ protected void report(long now) { output += "time: " + String.format("%.3f", (now - startTime)/1000.0) + "s"; output += - getRate("sent", sendCountInterval, sendStatsEnabled, elapsedInterval) + + getRate("sent", sendCountInterval, sendStatsEnabled, elapsedInterval) + getRate("returned", returnCountInterval, sendStatsEnabled && returnStatsEnabled, elapsedInterval) + getRate("confirmed", confirmCountInterval, sendStatsEnabled && confirmStatsEnabled, elapsedInterval) + getRate("nacked", nackCountInterval, sendStatsEnabled && confirmStatsEnabled, elapsedInterval) + From fc349adb85a5fab903e256347a0239e1af9c6a83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 24 Aug 2016 15:42:02 +0200 Subject: [PATCH 0229/2114] Add AddressResolver to try all DNS record IPs References #138 --- .../com/rabbitmq/client/AddressResolver.java | 3 +- .../client/DnsRecordIpAddressResolver.java | 64 +++++++++++++++++++ .../com/rabbitmq/client/test/ClientTests.java | 1 + .../test/DnsRecordIpAddressResolverTests.java | 48 ++++++++++++++ 4 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/rabbitmq/client/DnsRecordIpAddressResolver.java create mode 100644 src/test/java/com/rabbitmq/client/test/DnsRecordIpAddressResolverTests.java diff --git a/src/main/java/com/rabbitmq/client/AddressResolver.java b/src/main/java/com/rabbitmq/client/AddressResolver.java index f16672e4b9..41726b0ced 100644 --- a/src/main/java/com/rabbitmq/client/AddressResolver.java +++ b/src/main/java/com/rabbitmq/client/AddressResolver.java @@ -1,5 +1,6 @@ package com.rabbitmq.client; +import java.io.IOException; import java.util.List; /** @@ -7,6 +8,6 @@ */ public interface AddressResolver { - List
getAddresses(); + List
getAddresses() throws IOException; } diff --git a/src/main/java/com/rabbitmq/client/DnsRecordIpAddressResolver.java b/src/main/java/com/rabbitmq/client/DnsRecordIpAddressResolver.java new file mode 100644 index 0000000000..0416e25422 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/DnsRecordIpAddressResolver.java @@ -0,0 +1,64 @@ +package com.rabbitmq.client; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.List; + +/** + * + */ +public class DnsRecordIpAddressResolver implements AddressResolver { + + private final Address address; + + private final boolean ssl; + + public DnsRecordIpAddressResolver(String hostname, int port, boolean ssl) { + this(new Address(hostname, port), ssl); + } + + public DnsRecordIpAddressResolver(String hostname, int port) { + this(new Address(hostname, port), false); + } + + public DnsRecordIpAddressResolver() { + this("localhost"); + } + + public DnsRecordIpAddressResolver(String hostname) { + this(new Address(hostname), false); + } + + public DnsRecordIpAddressResolver(Address address) { + this(address, false); + } + + public DnsRecordIpAddressResolver(Address address, boolean ssl) { + this.address = address; + this.ssl = ssl; + } + + @Override + public List
getAddresses() throws IOException { + String hostName = address.getHost(); + int portNumber = ConnectionFactory.portOrDefault(address.getPort(), ssl); + InetAddress[] inetAddresses; + try { + inetAddresses = resolveIpAddresses(hostName); + } catch (UnknownHostException e) { + throw new IOException("Could not resolve IP addresses for host "+hostName, e); + } + List
addresses = new ArrayList
(); + for (InetAddress inetAddress : inetAddresses) { + addresses.add(new Address(inetAddress.getHostAddress(), portNumber)); + } + return addresses; + } + + protected InetAddress[] resolveIpAddresses(String hostName) throws UnknownHostException { + return InetAddress.getAllByName(hostName); + } + +} diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index 0da36c2f75..08e2d58d4f 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -39,6 +39,7 @@ public static TestSuite suite() { suite.addTestSuite(AmqpUriTest.class); suite.addTestSuite(JSONReadWriteTest.class); suite.addTestSuite(SharedThreadPoolTest.class); + suite.addTestSuite(DnsRecordIpAddressResolverTests.class); return suite; } } diff --git a/src/test/java/com/rabbitmq/client/test/DnsRecordIpAddressResolverTests.java b/src/test/java/com/rabbitmq/client/test/DnsRecordIpAddressResolverTests.java new file mode 100644 index 0000000000..098241c42c --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/DnsRecordIpAddressResolverTests.java @@ -0,0 +1,48 @@ +package com.rabbitmq.client.test; + +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.DnsRecordIpAddressResolver; + +import java.io.IOException; +import java.util.concurrent.TimeoutException; + +/** + * + */ +public class DnsRecordIpAddressResolverTests extends BrokerTestCase { + + public void testLocalhostResolution() throws IOException, TimeoutException { + DnsRecordIpAddressResolver addressResolver = new DnsRecordIpAddressResolver("localhost"); + ConnectionFactory connectionFactory = newConnectionFactory(); + Connection connection = connectionFactory.newConnection(addressResolver); + try { + connection.createChannel(); + } finally { + connection.abort(); + } + } + + public void testLoopbackInterfaceResolution() throws IOException, TimeoutException { + DnsRecordIpAddressResolver addressResolver = new DnsRecordIpAddressResolver("127.0.0.1"); + ConnectionFactory connectionFactory = newConnectionFactory(); + Connection connection = connectionFactory.newConnection(addressResolver); + try { + connection.createChannel(); + } finally { + connection.abort(); + } + } + + public void testResolutionFails() throws IOException, TimeoutException { + DnsRecordIpAddressResolver addressResolver = new DnsRecordIpAddressResolver( + "afancyandunlikelyhostname" + ); + try { + connectionFactory.newConnection(addressResolver); + fail("The host resolution should have failed"); + } catch (IOException e) { + // expected + } + } +} From d38a4be9e8a2363d430e08195df2ec9671a9a48d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 24 Aug 2016 16:27:12 +0200 Subject: [PATCH 0230/2114] Document AddressResolver and implementations References #138 --- .../java/com/rabbitmq/client/AddressResolver.java | 5 +++++ .../rabbitmq/client/DnsRecordIpAddressResolver.java | 12 +++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/AddressResolver.java b/src/main/java/com/rabbitmq/client/AddressResolver.java index 41726b0ced..dae00d425b 100644 --- a/src/main/java/com/rabbitmq/client/AddressResolver.java +++ b/src/main/java/com/rabbitmq/client/AddressResolver.java @@ -8,6 +8,11 @@ */ public interface AddressResolver { + /** + * Get the potential {@link Address}es to connect to. + * @return candidate {@link Address}es + * @throws IOException if it encounters a problem + */ List
getAddresses() throws IOException; } diff --git a/src/main/java/com/rabbitmq/client/DnsRecordIpAddressResolver.java b/src/main/java/com/rabbitmq/client/DnsRecordIpAddressResolver.java index 0416e25422..4a2cfee2f3 100644 --- a/src/main/java/com/rabbitmq/client/DnsRecordIpAddressResolver.java +++ b/src/main/java/com/rabbitmq/client/DnsRecordIpAddressResolver.java @@ -7,7 +7,12 @@ import java.util.List; /** - * + * {@link AddressResolver} that resolves DNS record IPs. + * Uses {@link InetAddress} internally. + * The first returned address is used when automatic recovery is NOT enabled + * at the {@link ConnectionFactory} level. + * When automatic recovery is enabled, a random address will be picked up + * from the returned list of {@link Address}es. */ public class DnsRecordIpAddressResolver implements AddressResolver { @@ -40,6 +45,11 @@ public DnsRecordIpAddressResolver(Address address, boolean ssl) { this.ssl = ssl; } + /** + * Get the IP addresses from a DNS query + * @return candidate {@link Address}es + * @throws IOException if DNS resolution fails + */ @Override public List
getAddresses() throws IOException { String hostName = address.getHost(); From e0b47e65f76f607cfb5c9c4af4d57d53c0f2c7a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 24 Aug 2016 17:05:59 +0200 Subject: [PATCH 0231/2114] Make DnsRecordIpAddressResolver the default For 1-hostname scenarios. Fixes #138 --- .../rabbitmq/client/ConnectionFactory.java | 42 +++++++++---------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 3743d200ba..611cc10e17 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -15,31 +15,21 @@ package com.rabbitmq.client; -import java.io.IOException; -import java.security.KeyManagementException; -import java.security.NoSuchAlgorithmException; -import java.util.Collections; -import java.util.Map; -import java.util.HashMap; -import java.util.concurrent.*; -import java.util.List; -import java.util.Arrays; - -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URLDecoder; +import com.rabbitmq.client.impl.*; +import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; import javax.net.SocketFactory; -import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; - -import com.rabbitmq.client.impl.AMQConnection; -import com.rabbitmq.client.impl.ConnectionParams; -import com.rabbitmq.client.impl.DefaultExceptionHandler; -import com.rabbitmq.client.impl.FrameHandler; -import com.rabbitmq.client.impl.FrameHandlerFactory; -import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URLDecoder; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.util.*; +import java.util.concurrent.*; /** * Convenience "factory" class to facilitate opening a {@link Connection} to an AMQP broker. @@ -836,7 +826,7 @@ public Connection newConnection(ExecutorService executor, AddressResolver addres */ public Connection newConnection(ExecutorService executor, List
addrs, String clientProvidedName) throws IOException, TimeoutException { - return newConnection(executor, new ListAddressResolver(addrs), clientProvidedName); + return newConnection(executor, createAddressResolver(addrs), clientProvidedName); } /** @@ -976,6 +966,14 @@ public Connection newConnection(ExecutorService executor, String connectionName) return newConnection(executor, Collections.singletonList(new Address(getHost(), getPort())), connectionName); } + protected AddressResolver createAddressResolver(List
addresses) { + if(addresses.size() == 1) { + return new DnsRecordIpAddressResolver(addresses.get(0), isSSL()); + } else { + return new ListAddressResolver(addresses); + } + } + @Override public ConnectionFactory clone(){ try { return (ConnectionFactory)super.clone(); From 0c0c4f4e608565be72e591a64ed23bb26f40078d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 25 Aug 2016 09:51:38 +0200 Subject: [PATCH 0232/2114] Refactor non-broker ClientTests to JUnit 4 References #174 --- .../client/test/AMQConnectionTest.java | 69 +++++++------------ .../client/test/AbstractRMQTestSuite.java | 2 +- .../client/test/BlockingCellTest.java | 32 ++++----- .../client/test/BrokenFramesTest.java | 53 +++++++------- .../test/ChannelNumberAllocationTests.java | 43 ++++++------ .../com/rabbitmq/client/test/ClientTests.java | 48 ++++++------- .../client/test/ClonePropertiesTest.java | 29 ++++---- .../client/test/JSONReadWriteTest.java | 14 ++-- .../rabbitmq/client/test/LongStringTest.java | 15 ++-- .../com/rabbitmq/client/test/TableTest.java | 28 ++------ .../client/test/TruncatedInputStreamTest.java | 32 ++++----- .../client/test/ValueOrExceptionTest.java | 22 ++---- .../rabbitmq/utility/IntAllocatorTests.java | 14 ++-- 13 files changed, 167 insertions(+), 234 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java b/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java index 4d21de328b..d86b322eb7 100644 --- a/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java +++ b/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java @@ -15,78 +15,55 @@ package com.rabbitmq.client.test; +import com.rabbitmq.client.*; +import com.rabbitmq.client.impl.AMQConnection; +import com.rabbitmq.client.impl.ConnectionParams; +import com.rabbitmq.client.impl.Frame; +import com.rabbitmq.client.impl.FrameHandler; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + import java.io.IOException; import java.net.InetAddress; import java.net.SocketException; import java.net.SocketTimeoutException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeoutException; -import java.util.concurrent.ExecutorService; -import com.rabbitmq.client.Address; -import java.util.Arrays; -import com.rabbitmq.client.impl.ConnectionParams; -import com.rabbitmq.client.TopologyRecoveryException; -import junit.framework.TestCase; -import junit.framework.TestSuite; - -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.ConnectionFactory; -import com.rabbitmq.client.Consumer; -import com.rabbitmq.client.impl.AMQConnection; -import com.rabbitmq.client.ExceptionHandler; -import com.rabbitmq.client.impl.Frame; -import com.rabbitmq.client.impl.FrameHandler; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; /** * Test suite for AMQConnection. */ -public class AMQConnectionTest extends TestCase { +public class AMQConnectionTest { // private static final String CLOSE_MESSAGE = "terminated by test"; - /** - * Build a suite of tests - * @return the test suite for this class - */ - public static TestSuite suite() { - TestSuite suite = new TestSuite("connection"); - suite.addTestSuite(AMQConnectionTest.class); - return suite; - } - /** The mock frame handler used to test connection behaviour. */ private MockFrameHandler _mockFrameHandler; private ConnectionFactory factory; private MyExceptionHandler exceptionHandler; - /** Setup the environment for this test - * @see junit.framework.TestCase#setUp() - * @throws Exception if anything goes wrong - */ - @Override protected void setUp() throws Exception { - super.setUp(); + @Before public void setUp() throws Exception { _mockFrameHandler = new MockFrameHandler(); factory = new ConnectionFactory(); exceptionHandler = new MyExceptionHandler(); factory.setExceptionHandler(exceptionHandler); } - /** Tear down the environment for this test - * @see junit.framework.TestCase#tearDown() - * @throws Exception if anything goes wrong - */ - @Override protected void tearDown() throws Exception { + @After public void tearDown() throws Exception { factory = null; _mockFrameHandler = null; - super.tearDown(); } - public void testNegativeTCPConnectionTimeout() { + @Test public void negativeTCPConnectionTimeout() { ConnectionFactory cf = new ConnectionFactory(); try { cf.setConnectionTimeout(-10); @@ -96,7 +73,7 @@ public void testNegativeTCPConnectionTimeout() { } } - public void testNegativeProtocolHandshakeTimeout() { + @Test public void negativeProtocolHandshakeTimeout() { ConnectionFactory cf = new ConnectionFactory(); try { cf.setHandshakeTimeout(-10); @@ -106,13 +83,13 @@ public void testNegativeProtocolHandshakeTimeout() { } } - public void testTCPConnectionTimeoutGreaterThanHandShakeTimeout() { + @Test public void tcpConnectionTimeoutGreaterThanHandShakeTimeout() { ConnectionFactory cf = new ConnectionFactory(); cf.setHandshakeTimeout(3000); cf.setConnectionTimeout(5000); } - public void testProtocolHandshakeTimeoutGreaterThanTCPConnectionTimeout() { + @Test public void protocolHandshakeTimeoutGreaterThanTCPConnectionTimeout() { ConnectionFactory cf = new ConnectionFactory(); cf.setConnectionTimeout(5000); @@ -125,7 +102,7 @@ public void testProtocolHandshakeTimeoutGreaterThanTCPConnectionTimeout() { /** Check the AMQConnection does send exactly 1 initial header, and deal correctly with * the frame handler throwing an exception when we try to read data */ - public void testConnectionSendsSingleHeaderAndTimesOut() throws TimeoutException { + @Test public void connectionSendsSingleHeaderAndTimesOut() throws TimeoutException { IOException exception = new SocketTimeoutException(); _mockFrameHandler.setExceptionOnReadingFrames(exception); assertEquals(0, _mockFrameHandler.countHeadersSent()); @@ -158,7 +135,7 @@ public void testConnectionSendsSingleHeaderAndTimesOut() throws TimeoutException /** * Test that we catch timeout between connect and negotiation of the connection being finished. */ - public void testConnectionHangInNegotiation() { + @Test public void connectionHangInNegotiation() { this._mockFrameHandler.setTimeoutCount(10); // to limit hang assertEquals(0, this._mockFrameHandler.countHeadersSent()); try { @@ -176,7 +153,7 @@ public void testConnectionHangInNegotiation() { assertEquals("Wrong type of exception returned.", SocketTimeoutException.class, exceptionList.get(0).getClass()); } - public void testClientProvidedConnectionName() throws IOException, TimeoutException { + @Test public void clientProvidedConnectionName() throws IOException, TimeoutException { String providedName = "event consumers connection"; Connection connection = factory.newConnection(providedName); assertEquals(providedName, connection.getClientProvidedName()); diff --git a/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java b/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java index 1937e074c5..95b6d1c7f3 100644 --- a/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java +++ b/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java @@ -26,7 +26,7 @@ import com.rabbitmq.tools.Host; -public abstract class AbstractRMQTestSuite extends TestSuite { +public abstract class AbstractRMQTestSuite { //extends TestSuite { private static final String DEFAULT_SSL_HOSTNAME = "localhost"; private static final int DEFAULT_SSL_PORT = 5671; diff --git a/src/test/java/com/rabbitmq/client/test/BlockingCellTest.java b/src/test/java/com/rabbitmq/client/test/BlockingCellTest.java index afc4acc5c7..26f588b771 100644 --- a/src/test/java/com/rabbitmq/client/test/BlockingCellTest.java +++ b/src/test/java/com/rabbitmq/client/test/BlockingCellTest.java @@ -16,25 +16,19 @@ package com.rabbitmq.client.test; +import com.rabbitmq.utility.BlockingCell; +import org.junit.Test; + import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; -import junit.framework.TestCase; -import junit.framework.TestSuite; - -import com.rabbitmq.utility.BlockingCell; +import static org.junit.Assert.*; public class BlockingCellTest - extends TestCase { - public static TestSuite suite() - { - TestSuite suite = new TestSuite("blockingCells"); - suite.addTestSuite(BlockingCellTest.class); - return suite; - } - public void testDoubleSet() throws InterruptedException + @Test + public void doubleSet() throws InterruptedException { BlockingCell cell = new BlockingCell(); cell.set("one"); @@ -47,7 +41,7 @@ public void testDoubleSet() throws InterruptedException fail("Expected AssertionError"); } - public void testMultiGet() + @Test public void multiGet() throws InterruptedException { final BlockingCell cell = new BlockingCell(); @@ -56,7 +50,7 @@ public void testMultiGet() assertEquals("one", cell.get()); } - public void testNullSet() + @Test public void nullSet() throws InterruptedException { BlockingCell c = new BlockingCell(); @@ -64,7 +58,7 @@ public void testNullSet() assertNull(c.get()); } - public void testEarlySet() + @Test public void earlySet() throws InterruptedException { final BlockingCell cell = new BlockingCell(); @@ -95,7 +89,7 @@ public void run() { assertEquals("hello", holder.get()); } - public void testLateSet() + @Test public void lateSet() throws InterruptedException { final BlockingCell cell = new BlockingCell(); @@ -129,8 +123,8 @@ public void run() { assertEquals("hello", holder.get()); } - - public void testGetWaitsUntilSet() throws InterruptedException { + + @Test public void getWaitsUntilSet() throws InterruptedException { final BlockingCell cell = new BlockingCell(); final String value = "foo"; final AtomicReference valueHolder = new AtomicReference(); @@ -155,7 +149,7 @@ public void testGetWaitsUntilSet() throws InterruptedException { assertTrue(value == valueHolder.get()); } - public void testSetIfUnset() throws InterruptedException { + @Test public void setIfUnset() throws InterruptedException { final BlockingCell cell = new BlockingCell(); assertTrue(cell.setIfUnset("foo")); assertEquals("foo", cell.get()); diff --git a/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java b/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java index 77faa8f1f3..566e2da66a 100644 --- a/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java +++ b/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java @@ -16,6 +16,17 @@ package com.rabbitmq.client.test; +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.UnexpectedFrameError; +import com.rabbitmq.client.impl.AMQConnection; +import com.rabbitmq.client.impl.AMQImpl.Basic.Publish; +import com.rabbitmq.client.impl.Frame; +import com.rabbitmq.client.impl.FrameHandler; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + import java.io.IOException; import java.net.InetAddress; import java.net.SocketException; @@ -24,42 +35,24 @@ import java.util.List; import java.util.concurrent.Executors; -import junit.framework.TestCase; -import junit.framework.TestSuite; - -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.ConnectionFactory; -import com.rabbitmq.client.UnexpectedFrameError; -import com.rabbitmq.client.impl.AMQConnection; -import com.rabbitmq.client.impl.Frame; -import com.rabbitmq.client.impl.FrameHandler; -import com.rabbitmq.client.impl.AMQImpl.Basic.Publish; +import static org.junit.Assert.*; -public class BrokenFramesTest extends TestCase { - public static TestSuite suite() { - TestSuite suite = new TestSuite("connection"); - suite.addTestSuite(BrokenFramesTest.class); - return suite; - } +public class BrokenFramesTest { private MyFrameHandler myFrameHandler; private ConnectionFactory factory; - @Override - protected void setUp() throws Exception { - super.setUp(); + @Before public void setUp() throws Exception { myFrameHandler = new MyFrameHandler(); factory = new ConnectionFactory(); } - @Override - protected void tearDown() throws Exception { + @After public void tearDown() throws Exception { factory = null; myFrameHandler = null; - super.tearDown(); } - public void testNoMethod() throws Exception { + @Test public void noMethod() throws Exception { List frames = new ArrayList(); frames.add(new Frame(AMQP.FRAME_HEADER, 0)); myFrameHandler.setFrames(frames.iterator()); @@ -77,7 +70,7 @@ public void testNoMethod() throws Exception { fail("No UnexpectedFrameError thrown"); } - public void testMethodThenBody() throws Exception { + @Test public void methodThenBody() throws Exception { List frames = new ArrayList(); byte[] contentBody = new byte[10]; @@ -116,14 +109,14 @@ private UnexpectedFrameError findUnexpectedFrameError(Exception e) { } private static class MyFrameHandler implements FrameHandler { - private Iterator frames; + private Iterator frames; - public void setFrames(Iterator frames) { - this.frames = frames; - } + public void setFrames(Iterator frames) { + this.frames = frames; + } - public Frame readFrame() throws IOException { - return frames.next(); + public Frame readFrame() throws IOException { + return frames.next(); } public void sendHeader() throws IOException { diff --git a/src/test/java/com/rabbitmq/client/test/ChannelNumberAllocationTests.java b/src/test/java/com/rabbitmq/client/test/ChannelNumberAllocationTests.java index 0d817325b1..a2d3da6dff 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelNumberAllocationTests.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelNumberAllocationTests.java @@ -15,18 +15,21 @@ package com.rabbitmq.client.test; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; -import junit.framework.TestCase; - -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.ConnectionFactory; +import static org.junit.Assert.*; -public class ChannelNumberAllocationTests extends TestCase{ +public class ChannelNumberAllocationTests { static final int CHANNEL_COUNT = 100; static final Comparator COMPARATOR = new Comparator(){ public int compare(Channel x, Channel y){ @@ -38,21 +41,21 @@ public int compare(Channel x, Channel y){ Connection connection; - public void setUp() throws Exception{ + @Before public void setUp() throws Exception{ connection = new ConnectionFactory().newConnection(); } - public void tearDown() throws Exception{ + @After public void tearDown() throws Exception{ connection.close(); connection = null; } - public void testAllocateInOrder() throws Exception{ + @Test public void allocateInOrder() throws Exception{ for(int i = 1; i <= CHANNEL_COUNT; i++) assertEquals(i, connection.createChannel().getChannelNumber()); } - public void testAllocateAfterFreeingLast() throws Exception{ + @Test public void allocateAfterFreeingLast() throws Exception{ Channel ch = connection.createChannel(); assertEquals(1, ch.getChannelNumber()); ch.close(); @@ -60,7 +63,7 @@ public void testAllocateAfterFreeingLast() throws Exception{ assertEquals(1, ch.getChannelNumber()); } - public void testAllocateAfterFreeingMany() throws Exception{ + @Test public void allocateAfterFreeingMany() throws Exception{ List channels = new ArrayList(); for(int i = 1; i <= CHANNEL_COUNT; i++) @@ -80,36 +83,36 @@ public void testAllocateAfterFreeingMany() throws Exception{ assertEquals("Didn't create the right number of channels!", CHANNEL_COUNT, channels.size()); for(int i = 1; i < CHANNEL_COUNT; ++i) { - assertTrue("Channel numbers should be distinct." - , channels.get(i-1).getChannelNumber() < channels.get(i).getChannelNumber() - ); + assertTrue("Channel numbers should be distinct." + , channels.get(i-1).getChannelNumber() < channels.get(i).getChannelNumber() + ); } } - public void testAllocateAfterManualAssign() throws Exception{ + @Test public void allocateAfterManualAssign() throws Exception{ connection.createChannel(10); for(int i = 0; i < 20; i++) - assertTrue(10 != connection.createChannel().getChannelNumber()); + assertTrue(10 != connection.createChannel().getChannelNumber()); } - public void testManualAllocationDoesntBreakThings() throws Exception{ + @Test public void manualAllocationDoesntBreakThings() throws Exception{ connection.createChannel((1 << 16) - 1); Channel ch = connection.createChannel(); assertNotNull(ch); } - public void testReuseManuallyAllocatedChannelNumber1() throws Exception{ + @Test public void reuseManuallyAllocatedChannelNumber1() throws Exception{ connection.createChannel(1).close(); assertNotNull(connection.createChannel(1)); } - public void testReuseManuallyAllocatedChannelNumber2() throws Exception{ + @Test public void reuseManuallyAllocatedChannelNumber2() throws Exception{ connection.createChannel(2).close(); assertNotNull(connection.createChannel(3)); } - public void testReserveOnBoundaries() throws Exception{ + @Test public void reserveOnBoundaries() throws Exception{ assertNotNull(connection.createChannel(3)); assertNotNull(connection.createChannel(4)); assertNotNull(connection.createChannel(2)); diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index 0da36c2f75..d81103f3c2 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -16,29 +16,31 @@ package com.rabbitmq.client.test; -import junit.framework.TestSuite; +import com.rabbitmq.utility.IntAllocatorTests; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +@RunWith(Suite.class) +@Suite.SuiteClasses({ + TableTest.class, + LongStringTest.class, + BlockingCellTest.class, + TruncatedInputStreamTest.class, + AMQConnectionTest.class, + ValueOrExceptionTest.class, + BrokenFramesTest.class, + ClonePropertiesTest.class, + Bug20004Test.class, + CloseInMainLoop.class, + ChannelNumberAllocationTests.class, + QueueingConsumerShutdownTests.class, + MultiThreadedChannel.class, + IntAllocatorTests.class, + AMQBuilderApiTest.class, + AmqpUriTest.class, + JSONReadWriteTest.class, + SharedThreadPoolTest.class +}) public class ClientTests extends AbstractRMQTestSuite { - public static TestSuite suite() { - TestSuite suite = new TestSuite("client"); - suite.addTest(TableTest.suite()); - suite.addTest(LongStringTest.suite()); - suite.addTest(BlockingCellTest.suite()); - suite.addTest(TruncatedInputStreamTest.suite()); - suite.addTest(AMQConnectionTest.suite()); - suite.addTest(ValueOrExceptionTest.suite()); - suite.addTest(BrokenFramesTest.suite()); - suite.addTest(ClonePropertiesTest.suite()); - suite.addTestSuite(Bug20004Test.class); - suite.addTestSuite(CloseInMainLoop.class); - suite.addTestSuite(ChannelNumberAllocationTests.class); - suite.addTestSuite(QueueingConsumerShutdownTests.class); - suite.addTestSuite(MultiThreadedChannel.class); - suite.addTestSuite(com.rabbitmq.utility.IntAllocatorTests.class); - suite.addTestSuite(AMQBuilderApiTest.class); - suite.addTestSuite(AmqpUriTest.class); - suite.addTestSuite(JSONReadWriteTest.class); - suite.addTestSuite(SharedThreadPoolTest.class); - return suite; - } + } diff --git a/src/test/java/com/rabbitmq/client/test/ClonePropertiesTest.java b/src/test/java/com/rabbitmq/client/test/ClonePropertiesTest.java index 1db2a86013..981b7bfd1b 100644 --- a/src/test/java/com/rabbitmq/client/test/ClonePropertiesTest.java +++ b/src/test/java/com/rabbitmq/client/test/ClonePropertiesTest.java @@ -15,36 +15,31 @@ package com.rabbitmq.client.test; -import junit.framework.TestCase; -import junit.framework.TestSuite; - import com.rabbitmq.client.AMQP.BasicProperties; import com.rabbitmq.client.MessageProperties; +import org.junit.Test; -public class ClonePropertiesTest extends TestCase { +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class ClonePropertiesTest { - public static TestSuite suite() - { - TestSuite suite = new TestSuite("cloneProperties"); - suite.addTestSuite(ClonePropertiesTest.class); - return suite; - } - public void testPropertyCloneIsDistinct() + @Test public void propertyCloneIsDistinct() throws CloneNotSupportedException { assertTrue(MessageProperties.MINIMAL_PERSISTENT_BASIC != - MessageProperties.MINIMAL_PERSISTENT_BASIC.clone()); + MessageProperties.MINIMAL_PERSISTENT_BASIC.clone()); } - public void testPropertyClonePreservesValues() + @Test public void propertyClonePreservesValues() throws CloneNotSupportedException { assertEquals(MessageProperties.MINIMAL_PERSISTENT_BASIC.getDeliveryMode(), - ((BasicProperties) MessageProperties.MINIMAL_PERSISTENT_BASIC.clone()) - .getDeliveryMode()); + ((BasicProperties) MessageProperties.MINIMAL_PERSISTENT_BASIC.clone()) + .getDeliveryMode()); assertEquals(new Integer(2), - ((BasicProperties) MessageProperties.MINIMAL_PERSISTENT_BASIC.clone()) - .getDeliveryMode()); + ((BasicProperties) MessageProperties.MINIMAL_PERSISTENT_BASIC.clone()) + .getDeliveryMode()); } } diff --git a/src/test/java/com/rabbitmq/client/test/JSONReadWriteTest.java b/src/test/java/com/rabbitmq/client/test/JSONReadWriteTest.java index ba51649388..44f322f2e0 100644 --- a/src/test/java/com/rabbitmq/client/test/JSONReadWriteTest.java +++ b/src/test/java/com/rabbitmq/client/test/JSONReadWriteTest.java @@ -16,14 +16,16 @@ package com.rabbitmq.client.test; -import junit.framework.TestCase; - import com.rabbitmq.tools.json.JSONReader; import com.rabbitmq.tools.json.JSONWriter; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; -public class JSONReadWriteTest extends TestCase { +public class JSONReadWriteTest { - public void testReadWriteSimple() throws Exception { + @Test public void readWriteSimple() throws Exception { Object myRet; String myJson; @@ -62,7 +64,7 @@ public void testReadWriteSimple() throws Exception { } - public void testMoreComplicated() throws Exception { + @Test public void moreComplicated() throws Exception { String v, s; Object t; @@ -90,7 +92,7 @@ public void testMoreComplicated() throws Exception { } - public void testBadJSON() throws Exception { + @Test public void badJSON() throws Exception { try { new JSONReader().read("[\"foo\",{\"bar\":[\"b\"az\",null,1.0,2]}]"); diff --git a/src/test/java/com/rabbitmq/client/test/LongStringTest.java b/src/test/java/com/rabbitmq/client/test/LongStringTest.java index 56db5fa1e0..df04cddd51 100644 --- a/src/test/java/com/rabbitmq/client/test/LongStringTest.java +++ b/src/test/java/com/rabbitmq/client/test/LongStringTest.java @@ -17,20 +17,15 @@ import com.rabbitmq.client.LongString; import com.rabbitmq.client.impl.LongStringHelper; -import junit.framework.TestCase; -import junit.framework.TestSuite; +import org.junit.Test; import java.io.UnsupportedEncodingException; -public class LongStringTest extends TestCase { -public static TestSuite suite() - { - TestSuite suite = new TestSuite("longString"); - suite.addTestSuite(LongStringTest.class); - return suite; - } +import static org.junit.Assert.assertTrue; + +public class LongStringTest { - public void testToString() throws UnsupportedEncodingException { + @Test public void testToString() throws UnsupportedEncodingException { String s = "abcdef"; LongString ls = LongStringHelper.asLongString(s); diff --git a/src/test/java/com/rabbitmq/client/test/TableTest.java b/src/test/java/com/rabbitmq/client/test/TableTest.java index c2e914d4ba..630c7fc34d 100644 --- a/src/test/java/com/rabbitmq/client/test/TableTest.java +++ b/src/test/java/com/rabbitmq/client/test/TableTest.java @@ -16,35 +16,19 @@ package com.rabbitmq.client.test; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; +import com.rabbitmq.client.impl.*; +import org.junit.Test; + +import java.io.*; import java.math.BigDecimal; import java.util.Date; import java.util.HashMap; import java.util.Map; -import junit.framework.TestCase; -import junit.framework.TestSuite; - -import com.rabbitmq.client.impl.Frame; -import com.rabbitmq.client.impl.LongStringHelper; -import com.rabbitmq.client.impl.MethodArgumentReader; -import com.rabbitmq.client.impl.MethodArgumentWriter; -import com.rabbitmq.client.impl.ValueReader; -import com.rabbitmq.client.impl.ValueWriter; +import static org.junit.Assert.assertEquals; public class TableTest - extends TestCase { - public static TestSuite suite() - { - TestSuite suite = new TestSuite("tables"); - suite.addTestSuite(TableTest.class); - return suite; - } public byte [] marshal(Map table) throws IOException @@ -75,7 +59,7 @@ public Date secondDate() return new Date((System.currentTimeMillis()/1000)*1000); } - public void testLoop() + @Test public void loop() throws IOException { Map table = new HashMap(); diff --git a/src/test/java/com/rabbitmq/client/test/TruncatedInputStreamTest.java b/src/test/java/com/rabbitmq/client/test/TruncatedInputStreamTest.java index 7a1f62f53e..4409798a17 100644 --- a/src/test/java/com/rabbitmq/client/test/TruncatedInputStreamTest.java +++ b/src/test/java/com/rabbitmq/client/test/TruncatedInputStreamTest.java @@ -15,19 +15,21 @@ package com.rabbitmq.client.test; +import com.rabbitmq.client.impl.TruncatedInputStream; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; -import junit.framework.TestCase; -import junit.framework.TestSuite; - -import com.rabbitmq.client.impl.TruncatedInputStream; +import static org.junit.Assert.assertEquals; /** * Some basic (retroactive) tests for TruncatedInputStream. */ -public class TruncatedInputStreamTest extends TestCase { +public class TruncatedInputStreamTest { /** a sample truncated stream to run tests on */ private TruncatedInputStream _truncStream; @@ -38,28 +40,20 @@ public class TruncatedInputStreamTest extends TestCase { /** what length to truncate it to */ private static final int TRUNCATED_LENGTH = 3; - @Override protected void setUp() throws Exception { - super.setUp(); + @Before public void setUp() throws Exception { InputStream baseStream = new ByteArrayInputStream(TEST_BYTES); _truncStream = new TruncatedInputStream(baseStream, TRUNCATED_LENGTH); } - @Override protected void tearDown() throws Exception { + @After public void tearDown() throws Exception { _truncStream = null; - super.tearDown(); - } - - public static TestSuite suite() { - TestSuite suite = new TestSuite("truncStreams"); - suite.addTestSuite(TruncatedInputStreamTest.class); - return suite; } /** * Check the amount of data initially available is as it should be * @throws IOException if there is an I/O problem */ - public void testAmountInitiallyAvailable() throws IOException { + @Test public void amountInitiallyAvailable() throws IOException { assertEquals(TRUNCATED_LENGTH, _truncStream.available()); } @@ -67,7 +61,7 @@ public void testAmountInitiallyAvailable() throws IOException { * Check the data read from the truncated stream is as it should be * @throws IOException if there is an I/O problem */ - public void testReadTruncatedBytes() throws IOException { + @Test public void readTruncatedBytes() throws IOException { byte[] readBytes = new byte[TEST_BYTES.length]; int numRead = _truncStream.read(readBytes); assertEquals(TRUNCATED_LENGTH, numRead); @@ -81,7 +75,7 @@ public void testReadTruncatedBytes() throws IOException { * @throws IOException * */ - public void testSingleByteReads() throws IOException { + @Test public void singleByteReads() throws IOException { for (int i = 0; i < TRUNCATED_LENGTH; i++) { assertEquals(TEST_BYTES[i], _truncStream.read()); } @@ -95,7 +89,7 @@ public void testSingleByteReads() throws IOException { /** * Check reading a specified number of bytes at an offset gives the right result */ - public void testOffsetMultipleByteReads() throws IOException { + @Test public void offsetMultipleByteReads() throws IOException { byte[] readBytes = new byte[TEST_OFFSET + TEST_LENGTH]; _truncStream.read(readBytes, TEST_OFFSET, TEST_LENGTH); for (int i = 0; i < TEST_OFFSET; i++) { // check the array's initially blank... diff --git a/src/test/java/com/rabbitmq/client/test/ValueOrExceptionTest.java b/src/test/java/com/rabbitmq/client/test/ValueOrExceptionTest.java index 9f7d6e1753..3c2640d057 100644 --- a/src/test/java/com/rabbitmq/client/test/ValueOrExceptionTest.java +++ b/src/test/java/com/rabbitmq/client/test/ValueOrExceptionTest.java @@ -15,14 +15,14 @@ package com.rabbitmq.client.test; -import junit.framework.TestCase; -import junit.framework.TestSuite; - -import com.rabbitmq.utility.ValueOrException; import com.rabbitmq.utility.SensibleClone; +import com.rabbitmq.utility.ValueOrException; +import org.junit.Test; + +import static org.junit.Assert.*; -public class ValueOrExceptionTest extends TestCase { +public class ValueOrExceptionTest { public static class InsufficientMagicException extends Exception implements SensibleClone { /** Default for no check. */ @@ -37,15 +37,7 @@ public InsufficientMagicException sensibleClone() { } } - - public static TestSuite suite() - { - TestSuite suite = new TestSuite("valueOrEx"); - suite.addTestSuite(ValueOrExceptionTest.class); - return suite; - } - - public void testStoresValue() throws InsufficientMagicException { + @Test public void storesValue() throws InsufficientMagicException { Integer value = new Integer(3); ValueOrException valueOrEx = @@ -55,7 +47,7 @@ public void testStoresValue() throws InsufficientMagicException { assertTrue(returnedValue == value); } - public void testClonesException() { + @Test public void clonesException() { InsufficientMagicException exception = new InsufficientMagicException("dummy message"); ValueOrException valueOrEx diff --git a/src/test/java/com/rabbitmq/utility/IntAllocatorTests.java b/src/test/java/com/rabbitmq/utility/IntAllocatorTests.java index ba0f5a8633..96586f5686 100644 --- a/src/test/java/com/rabbitmq/utility/IntAllocatorTests.java +++ b/src/test/java/com/rabbitmq/utility/IntAllocatorTests.java @@ -15,14 +15,16 @@ package com.rabbitmq.utility; +import org.junit.Test; + import java.util.HashSet; import java.util.Iterator; import java.util.Random; import java.util.Set; -import junit.framework.TestCase; +import static org.junit.Assert.*; -public class IntAllocatorTests extends TestCase { +public class IntAllocatorTests { private static final int TEST_ITERATIONS = 50000; private static final int HI_RANGE = 100000; @@ -31,7 +33,7 @@ public class IntAllocatorTests extends TestCase { private final Random rand = new Random(70608L); - public void testReserveAndFree() throws Exception { + @Test public void reserveAndFree() throws Exception { Set set = new HashSet(); for (int i = 0; i < TEST_ITERATIONS; ++i) { int trial = getTrial(rand); @@ -49,7 +51,7 @@ public void testReserveAndFree() throws Exception { } } - public void testAllocateAndFree() throws Exception { + @Test public void allocateAndFree() throws Exception { Set set = new HashSet(); for (int i=0; i < TEST_ITERATIONS; ++i) { if (getBool(rand)) { @@ -70,7 +72,7 @@ public void testAllocateAndFree() throws Exception { } } - public void testToString() throws Exception { + @Test public void testToString() throws Exception { IntAllocator ibs = new IntAllocator(LO_RANGE, HI_RANGE); assertEquals("IntAllocator{allocated = []}", ibs.toString()); ibs.allocate(); @@ -81,7 +83,7 @@ public void testToString() throws Exception { ibs.reserve(i+2); } assertEquals("IntAllocator{allocated = [100, 200..202, 204..206, 208..210]}" - , ibs.toString()); + , ibs.toString()); } private static int extractOne(Set set) { From 52289f48c79b5a4db87b82d9170f51a0c5b8c82c Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Thu, 25 Aug 2016 12:59:10 +0300 Subject: [PATCH 0233/2114] Remove a comment that's no longer needed --- .../java/com/rabbitmq/client/test/AbstractRMQTestSuite.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java b/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java index 95b6d1c7f3..6046671640 100644 --- a/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java +++ b/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java @@ -26,7 +26,7 @@ import com.rabbitmq.tools.Host; -public abstract class AbstractRMQTestSuite { //extends TestSuite { +public abstract class AbstractRMQTestSuite { private static final String DEFAULT_SSL_HOSTNAME = "localhost"; private static final int DEFAULT_SSL_PORT = 5671; From 8783a9322c0cb0059fa9fa9197a854446561fa7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 25 Aug 2016 15:51:31 +0200 Subject: [PATCH 0234/2114] Refactor functional/server/SSL tests to JUnit 4 Fixes #174 --- .../rabbitmq/client/impl/WorkPoolTests.java | 21 ++-- .../client/test/AMQBuilderApiTest.java | 15 ++- .../client/test/AbstractRMQTestSuite.java | 2 +- .../com/rabbitmq/client/test/AmqpUriTest.java | 11 +- .../rabbitmq/client/test/BrokerTestCase.java | 27 ++-- .../rabbitmq/client/test/Bug20004Test.java | 6 +- .../com/rabbitmq/client/test/ClientTests.java | 7 +- .../rabbitmq/client/test/CloseInMainLoop.java | 8 +- .../com/rabbitmq/client/test/ConfirmBase.java | 6 +- .../test/DnsRecordIpAddressResolverTests.java | 16 ++- .../client/test/MultiThreadedChannel.java | 6 +- .../test/QueueingConsumerShutdownTests.java | 6 +- .../client/test/RequiredPropertiesSuite.java | 44 +++++++ .../client/test/SharedThreadPoolTest.java | 11 +- .../test/functional/AbstractRejectTest.java | 16 ++- .../test/functional/AlternateExchange.java | 24 ++-- .../client/test/functional/BasicGet.java | 20 ++- .../test/functional/BindingLifecycle.java | 24 ++-- .../test/functional/BindingLifecycleBase.java | 9 +- .../client/test/functional/CcRoutes.java | 36 +++--- .../client/test/functional/Confirm.java | 36 +++--- .../test/functional/ConnectionOpen.java | 22 ++-- .../test/functional/ConnectionRecovery.java | 113 ++++++++++------- .../ConsumerCancelNotification.java | 25 ++-- .../client/test/functional/ConsumerCount.java | 10 +- .../test/functional/ConsumerPriorities.java | 21 ++-- .../test/functional/DeadLetterExchange.java | 78 ++++++------ .../test/functional/DefaultExchange.java | 18 +-- .../client/test/functional/DirectReplyTo.java | 20 ++- .../test/functional/DoubleDeletion.java | 6 +- .../test/functional/DurableOnTransient.java | 8 +- .../test/functional/ExceptionHandling.java | 24 ++-- .../test/functional/ExceptionMessages.java | 13 +- .../test/functional/ExchangeDeclare.java | 32 ++--- .../functional/ExchangeDeleteIfUnused.java | 6 +- .../functional/ExchangeEquivalenceBase.java | 6 +- .../functional/ExchangeExchangeBindings.java | 18 +-- .../ExchangeExchangeBindingsAutoDelete.java | 12 +- .../client/test/functional/FrameMax.java | 25 +++- .../test/functional/FunctionalTests.java | 118 +++++++++--------- .../functional/HeadersExchangeValidation.java | 12 +- .../client/test/functional/Heartbeat.java | 8 +- .../test/functional/InternalExchange.java | 6 +- .../test/functional/InvalidAcksBase.java | 6 +- .../client/test/functional/MessageCount.java | 8 +- .../rabbitmq/client/test/functional/Nack.java | 11 +- .../test/functional/NoRequeueOnCancel.java | 9 +- .../test/functional/PerConsumerPrefetch.java | 28 +++-- .../client/test/functional/PerMessageTTL.java | 15 ++- .../client/test/functional/PerQueueTTL.java | 14 ++- .../functional/PerQueueVsPerMessageTTL.java | 8 +- .../client/test/functional/Policies.java | 36 +++--- .../client/test/functional/QosTests.java | 43 ++++--- .../test/functional/QueueExclusivity.java | 20 +-- .../client/test/functional/QueueLease.java | 26 ++-- .../test/functional/QueueLifecycle.java | 34 ++--- .../test/functional/QueueSizeLimit.java | 23 ++-- .../client/test/functional/Recover.java | 22 ++-- .../client/test/functional/Reject.java | 10 +- .../test/functional/RequeueOnClose.java | 24 ++-- .../client/test/functional/Routing.java | 35 +++--- .../test/functional/SaslMechanisms.java | 24 ++-- .../client/test/functional/TTLHandling.java | 33 +++-- .../client/test/functional/Tables.java | 25 ++-- .../client/test/functional/Transactions.java | 54 ++++---- .../functional/UnbindAutoDeleteExchange.java | 10 +- .../test/functional/UnexpectedFrames.java | 18 +-- .../client/test/functional/UserIDHeader.java | 16 ++- .../client/test/server/AbsentQueue.java | 11 +- .../server/AlternateExchangeEquivalence.java | 10 +- .../client/test/server/BlockedConnection.java | 8 +- .../client/test/server/Bug19219Test.java | 12 +- .../test/server/ChannelLimitNegotiation.java | 24 ++-- .../server/DeadLetterExchangeDurable.java | 14 ++- .../test/server/DurableBindingLifecycle.java | 21 ++-- .../server/EffectVisibilityCrossNodeTest.java | 8 +- .../test/server/ExclusiveQueueDurability.java | 6 +- .../rabbitmq/client/test/server/Firehose.java | 13 +- .../rabbitmq/client/test/server/HATests.java | 48 +++---- .../client/test/server/LoopbackUsers.java | 24 ++-- .../client/test/server/MemoryAlarms.java | 13 +- .../client/test/server/MessageRecovery.java | 4 +- .../client/test/server/Permissions.java | 42 ++++--- .../test/server/PersistenceGuarantees.java | 12 +- .../client/test/server/PriorityQueues.java | 14 ++- .../client/test/server/ServerTests.java | 52 ++++---- .../rabbitmq/client/test/server/Shutdown.java | 4 +- .../test/server/XDeathHeaderGrowth.java | 19 +-- .../test/ssl/BadVerifiedConnection.java | 7 +- .../rabbitmq/client/test/ssl/SSLTests.java | 67 +++++++--- .../client/test/ssl/UnverifiedConnection.java | 6 +- .../client/test/ssl/VerifiedConnection.java | 3 +- 92 files changed, 1211 insertions(+), 735 deletions(-) create mode 100644 src/test/java/com/rabbitmq/client/test/RequiredPropertiesSuite.java diff --git a/src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java b/src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java index b0bd7653ca..90739f4206 100644 --- a/src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java +++ b/src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java @@ -15,15 +15,20 @@ package com.rabbitmq.client.impl; -import junit.framework.TestCase; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.List; +import org.junit.Test; + /** * Unit tests for {@link WorkPool} */ -public class WorkPoolTests extends TestCase { +public class WorkPoolTests { private final WorkPool pool = new WorkPool(); @@ -31,7 +36,7 @@ public class WorkPoolTests extends TestCase { * Test unknown key tolerated silently * @throws Exception untested */ - public void testUnknownKey() throws Exception{ + @Test public void unknownKey() throws Exception{ assertFalse(this.pool.addWorkItem("test", new Object())); } @@ -39,7 +44,7 @@ public void testUnknownKey() throws Exception{ * Test add work and remove work * @throws Exception untested */ - public void testBasicInOut() throws Exception { + @Test public void basicInOut() throws Exception { Object one = new Object(); Object two = new Object(); @@ -69,7 +74,7 @@ public void testBasicInOut() throws Exception { * Test add work when work in progress. * @throws Exception untested */ - public void testWorkInWhileInProgress() throws Exception { + @Test public void workInWhileInProgress() throws Exception { Object one = new Object(); Object two = new Object(); @@ -97,7 +102,7 @@ public void testWorkInWhileInProgress() throws Exception { * Test multiple work keys. * @throws Exception untested */ - public void testInterleavingKeys() throws Exception { + @Test public void interleavingKeys() throws Exception { Object one = new Object(); Object two = new Object(); Object three = new Object(); @@ -128,7 +133,7 @@ public void testInterleavingKeys() throws Exception { * Test removal of key (with work) * @throws Exception untested */ - public void testUnregisterKey() throws Exception { + @Test public void unregisterKey() throws Exception { Object one = new Object(); Object two = new Object(); Object three = new Object(); @@ -153,7 +158,7 @@ public void testUnregisterKey() throws Exception { * Test removal of all keys (with work). * @throws Exception untested */ - public void testUnregisterAllKeys() throws Exception { + @Test public void unregisterAllKeys() throws Exception { Object one = new Object(); Object two = new Object(); Object three = new Object(); diff --git a/src/test/java/com/rabbitmq/client/test/AMQBuilderApiTest.java b/src/test/java/com/rabbitmq/client/test/AMQBuilderApiTest.java index 4a9ec8f430..27a3f5b304 100644 --- a/src/test/java/com/rabbitmq/client/test/AMQBuilderApiTest.java +++ b/src/test/java/com/rabbitmq/client/test/AMQBuilderApiTest.java @@ -14,16 +14,21 @@ // info@rabbitmq.com. package com.rabbitmq.client.test; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.Method; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.io.IOException; +import org.junit.Test; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Method; + public class AMQBuilderApiTest extends BrokerTestCase { private static final String XCHG_NAME = "builder_test_xchg"; - public void testParticularBuilderForBasicSanityWithRpc() throws IOException + @Test public void particularBuilderForBasicSanityWithRpc() throws IOException { Method retVal = channel.rpc(new AMQP.Exchange.Declare.Builder() @@ -45,7 +50,7 @@ public void testParticularBuilderForBasicSanityWithRpc() throws IOException assertTrue(retVal instanceof AMQP.Exchange.DeleteOk); } - public void testParticularBuilderForBasicSanityWithAsyncRpc() throws IOException + @Test public void particularBuilderForBasicSanityWithAsyncRpc() throws IOException { channel.asyncRpc(new AMQP.Exchange.Declare.Builder() .exchange(XCHG_NAME) @@ -64,7 +69,7 @@ public void testParticularBuilderForBasicSanityWithAsyncRpc() throws IOException assertTrue("Channel should still be open.", channel.isOpen()); } - public void testIllFormedBuilder() + @Test public void illFormedBuilder() { try { diff --git a/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java b/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java index 95b6d1c7f3..ccc26e977b 100644 --- a/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java +++ b/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java @@ -26,7 +26,7 @@ import com.rabbitmq.tools.Host; -public abstract class AbstractRMQTestSuite { //extends TestSuite { +public abstract class AbstractRMQTestSuite { private static final String DEFAULT_SSL_HOSTNAME = "localhost"; private static final int DEFAULT_SSL_PORT = 5671; diff --git a/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java b/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java index db68cfa3f9..62c49b64a9 100644 --- a/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java +++ b/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java @@ -14,15 +14,20 @@ // info@rabbitmq.com. package com.rabbitmq.client.test; -import com.rabbitmq.client.ConnectionFactory; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import java.net.URISyntaxException; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; -import java.net.URISyntaxException; + +import org.junit.Test; + +import com.rabbitmq.client.ConnectionFactory; public class AmqpUriTest extends BrokerTestCase { - public void testUriParsing() + @Test public void uriParsing() throws URISyntaxException, NoSuchAlgorithmException, KeyManagementException { /* From the spec (subset of the tests) */ diff --git a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java index 81c412d700..d5963bb672 100644 --- a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java +++ b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java @@ -16,6 +16,12 @@ package com.rabbitmq.client.test; +import com.rabbitmq.client.*; +import com.rabbitmq.tools.Host; +import org.junit.After; +import org.junit.Before; + +import javax.net.ssl.SSLContext; import java.io.IOException; import java.security.NoSuchAlgorithmException; import java.util.Arrays; @@ -23,22 +29,9 @@ import java.util.UUID; import java.util.concurrent.TimeoutException; -import javax.net.ssl.SSLContext; - -import junit.framework.TestCase; - -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.AlreadyClosedException; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.ConnectionFactory; -import com.rabbitmq.client.GetResponse; -import com.rabbitmq.client.MessageProperties; -import com.rabbitmq.client.Method; -import com.rabbitmq.client.ShutdownSignalException; -import com.rabbitmq.tools.Host; +import static org.junit.Assert.*; -public class BrokerTestCase extends TestCase { +public class BrokerTestCase { protected ConnectionFactory connectionFactory = newConnectionFactory(); protected ConnectionFactory newConnectionFactory() { @@ -48,7 +41,7 @@ protected ConnectionFactory newConnectionFactory() { protected Connection connection; protected Channel channel; - protected void setUp() + @Before public void setUp() throws IOException, TimeoutException { openConnection(); openChannel(); @@ -56,7 +49,7 @@ protected void setUp() createResources(); } - protected void tearDown() + @After public void tearDown() throws IOException, TimeoutException { closeChannel(); closeConnection(); diff --git a/src/test/java/com/rabbitmq/client/test/Bug20004Test.java b/src/test/java/com/rabbitmq/client/test/Bug20004Test.java index 86288f3582..58581f076f 100644 --- a/src/test/java/com/rabbitmq/client/test/Bug20004Test.java +++ b/src/test/java/com/rabbitmq/client/test/Bug20004Test.java @@ -15,8 +15,12 @@ package com.rabbitmq.client.test; +import org.junit.Test; + import java.io.IOException; +import static org.junit.Assert.*; + /** * Test for bug 20004 - deadlock through internal synchronization on * the channel object. This is more properly a unit test, but since it @@ -40,7 +44,7 @@ protected void releaseResources() } @SuppressWarnings("deprecation") - public void testBug20004() throws IOException + @Test public void bug20004() throws IOException { final Bug20004Test testInstance = this; diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index 1a40951050..e0fd071e66 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -42,6 +42,11 @@ SharedThreadPoolTest.class, DnsRecordIpAddressResolverTests.class }) -public class ClientTests extends AbstractRMQTestSuite { +public class ClientTests { + + // initialize system properties + static{ + new AbstractRMQTestSuite(){}; + } } diff --git a/src/test/java/com/rabbitmq/client/test/CloseInMainLoop.java b/src/test/java/com/rabbitmq/client/test/CloseInMainLoop.java index d21b5e93af..3a832b0ff1 100644 --- a/src/test/java/com/rabbitmq/client/test/CloseInMainLoop.java +++ b/src/test/java/com/rabbitmq/client/test/CloseInMainLoop.java @@ -15,6 +15,8 @@ package com.rabbitmq.client.test; +import static org.junit.Assert.assertTrue; + import java.io.IOException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executors; @@ -23,6 +25,8 @@ import javax.net.SocketFactory; +import org.junit.Test; + import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Command; @@ -87,7 +91,7 @@ public boolean processControlCommand(Command c) throws IOException{ } } - public void testCloseOKNormallyReceived() throws Exception{ + @Test public void closeOKNormallyReceived() throws Exception{ SpecialConnection connection = new SpecialConnection(); connection.close(); assertTrue(connection.hadValidShutdown()); @@ -95,7 +99,7 @@ public void testCloseOKNormallyReceived() throws Exception{ // The thrown runtime exception should get intercepted by the // consumer exception handler, and result in a clean shut down. - public void testCloseWithFaultyConsumer() throws Exception{ + @Test public void closeWithFaultyConsumer() throws Exception{ SpecialConnection connection = new SpecialConnection(); Channel channel = connection.createChannel(); channel.exchangeDeclare("x", "direct"); diff --git a/src/test/java/com/rabbitmq/client/test/ConfirmBase.java b/src/test/java/com/rabbitmq/client/test/ConfirmBase.java index b712239d26..099f8e8d04 100644 --- a/src/test/java/com/rabbitmq/client/test/ConfirmBase.java +++ b/src/test/java/com/rabbitmq/client/test/ConfirmBase.java @@ -15,14 +15,16 @@ package com.rabbitmq.client.test; -import com.rabbitmq.client.ShutdownSignalException; +import static org.junit.Assert.fail; import java.io.IOException; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; import java.util.concurrent.FutureTask; -import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import com.rabbitmq.client.ShutdownSignalException; import junit.framework.AssertionFailedError; diff --git a/src/test/java/com/rabbitmq/client/test/DnsRecordIpAddressResolverTests.java b/src/test/java/com/rabbitmq/client/test/DnsRecordIpAddressResolverTests.java index 098241c42c..01459cfb29 100644 --- a/src/test/java/com/rabbitmq/client/test/DnsRecordIpAddressResolverTests.java +++ b/src/test/java/com/rabbitmq/client/test/DnsRecordIpAddressResolverTests.java @@ -1,18 +1,22 @@ package com.rabbitmq.client.test; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.ConnectionFactory; -import com.rabbitmq.client.DnsRecordIpAddressResolver; +import static org.junit.Assert.fail; import java.io.IOException; import java.util.concurrent.TimeoutException; +import org.junit.Test; + +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.DnsRecordIpAddressResolver; + /** * */ public class DnsRecordIpAddressResolverTests extends BrokerTestCase { - public void testLocalhostResolution() throws IOException, TimeoutException { + @Test public void localhostResolution() throws IOException, TimeoutException { DnsRecordIpAddressResolver addressResolver = new DnsRecordIpAddressResolver("localhost"); ConnectionFactory connectionFactory = newConnectionFactory(); Connection connection = connectionFactory.newConnection(addressResolver); @@ -23,7 +27,7 @@ public void testLocalhostResolution() throws IOException, TimeoutException { } } - public void testLoopbackInterfaceResolution() throws IOException, TimeoutException { + @Test public void loopbackInterfaceResolution() throws IOException, TimeoutException { DnsRecordIpAddressResolver addressResolver = new DnsRecordIpAddressResolver("127.0.0.1"); ConnectionFactory connectionFactory = newConnectionFactory(); Connection connection = connectionFactory.newConnection(addressResolver); @@ -34,7 +38,7 @@ public void testLoopbackInterfaceResolution() throws IOException, TimeoutExcepti } } - public void testResolutionFails() throws IOException, TimeoutException { + @Test public void resolutionFails() throws IOException, TimeoutException { DnsRecordIpAddressResolver addressResolver = new DnsRecordIpAddressResolver( "afancyandunlikelyhostname" ); diff --git a/src/test/java/com/rabbitmq/client/test/MultiThreadedChannel.java b/src/test/java/com/rabbitmq/client/test/MultiThreadedChannel.java index 96ee123215..d583a03b4a 100644 --- a/src/test/java/com/rabbitmq/client/test/MultiThreadedChannel.java +++ b/src/test/java/com/rabbitmq/client/test/MultiThreadedChannel.java @@ -15,10 +15,10 @@ package com.rabbitmq.client.test; -import com.rabbitmq.client.test.BrokerTestCase; - import java.util.concurrent.atomic.AtomicReference; +import org.junit.Test; + /** * Tests whether a Channel is safe for multi-threaded access */ @@ -28,7 +28,7 @@ public class MultiThreadedChannel extends BrokerTestCase { private static final String DUMMY_EXCHANGE_NAME = "dummy.exchange"; - public void testInterleavedRpcs() throws Throwable { + @Test public void interleavedRpcs() throws Throwable { final AtomicReference throwableRef = new AtomicReference(null); diff --git a/src/test/java/com/rabbitmq/client/test/QueueingConsumerShutdownTests.java b/src/test/java/com/rabbitmq/client/test/QueueingConsumerShutdownTests.java index a0e249579a..143b2947e2 100644 --- a/src/test/java/com/rabbitmq/client/test/QueueingConsumerShutdownTests.java +++ b/src/test/java/com/rabbitmq/client/test/QueueingConsumerShutdownTests.java @@ -15,6 +15,10 @@ package com.rabbitmq.client.test; +import static org.junit.Assert.*; +import org.junit.Test; + + import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @@ -27,7 +31,7 @@ public class QueueingConsumerShutdownTests extends BrokerTestCase{ static final String QUEUE = "some-queue"; static final int THREADS = 5; - public void testNThreadShutdown() throws Exception{ + @Test public void nThreadShutdown() throws Exception{ Channel channel = connection.createChannel(); final QueueingConsumer c = new QueueingConsumer(channel); channel.queueDeclare(QUEUE, false, true, true, null); diff --git a/src/test/java/com/rabbitmq/client/test/RequiredPropertiesSuite.java b/src/test/java/com/rabbitmq/client/test/RequiredPropertiesSuite.java new file mode 100644 index 0000000000..b97a0b0af6 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/RequiredPropertiesSuite.java @@ -0,0 +1,44 @@ +package com.rabbitmq.client.test; + +import org.junit.runner.Runner; +import org.junit.runners.Suite; +import org.junit.runners.model.InitializationError; +import org.junit.runners.model.RunnerBuilder; + +import java.util.ArrayList; +import java.util.List; + +/** + * + */ +public class RequiredPropertiesSuite extends Suite { + + public RequiredPropertiesSuite(Class klass, RunnerBuilder builder) throws InitializationError { + super(klass, builder); + } + + public RequiredPropertiesSuite(RunnerBuilder builder, Class[] classes) throws InitializationError { + super(builder, classes); + } + + protected RequiredPropertiesSuite(Class klass, Class[] suiteClasses) throws InitializationError { + super(klass, suiteClasses); + } + + protected RequiredPropertiesSuite(RunnerBuilder builder, Class klass, Class[] suiteClasses) throws InitializationError { + super(builder, klass, suiteClasses); + } + + protected RequiredPropertiesSuite(Class klass, List runners) throws InitializationError { + super(klass, runners); + } + + @Override + protected List getChildren() { + if(!AbstractRMQTestSuite.requiredProperties()) { + return new ArrayList(); + } else { + return super.getChildren(); + } + } +} diff --git a/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java b/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java index c709d0e9f7..499d2de0f6 100644 --- a/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java +++ b/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java @@ -15,16 +15,21 @@ package com.rabbitmq.client.test; -import com.rabbitmq.client.ConnectionFactory; -import com.rabbitmq.client.impl.AMQConnection; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import java.io.IOException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeoutException; +import org.junit.Test; + +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.impl.AMQConnection; + public class SharedThreadPoolTest extends BrokerTestCase { - public void testWillShutDownExecutor() throws IOException, TimeoutException { + @Test public void willShutDownExecutor() throws IOException, TimeoutException { ConnectionFactory cf = new ConnectionFactory(); ExecutorService executor = Executors.newFixedThreadPool(8); cf.setSharedExecutor(executor); diff --git a/src/test/java/com/rabbitmq/client/test/functional/AbstractRejectTest.java b/src/test/java/com/rabbitmq/client/test/functional/AbstractRejectTest.java index 50d3a18868..9d58d590de 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/AbstractRejectTest.java +++ b/src/test/java/com/rabbitmq/client/test/functional/AbstractRejectTest.java @@ -16,22 +16,26 @@ package com.rabbitmq.client.test.functional; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.util.Arrays; +import java.util.concurrent.TimeoutException; + import com.rabbitmq.client.Channel; import com.rabbitmq.client.Envelope; import com.rabbitmq.client.GetResponse; import com.rabbitmq.client.QueueingConsumer; import com.rabbitmq.client.test.BrokerTestCase; -import java.io.IOException; -import java.util.Arrays; -import java.util.concurrent.TimeoutException; - abstract class AbstractRejectTest extends BrokerTestCase { protected Channel secondaryChannel; @Override - protected void setUp() + public void setUp() throws IOException, TimeoutException { super.setUp(); secondaryChannel = connection.createChannel(); @@ -39,7 +43,7 @@ protected void setUp() } @Override - protected void tearDown() + public void tearDown() throws IOException, TimeoutException { if (secondaryChannel != null) { secondaryChannel.abort(); diff --git a/src/test/java/com/rabbitmq/client/test/functional/AlternateExchange.java b/src/test/java/com/rabbitmq/client/test/functional/AlternateExchange.java index 794b19f0cd..b408cffca0 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/AlternateExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/AlternateExchange.java @@ -16,16 +16,20 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.test.BrokerTestCase; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.ReturnListener; -import com.rabbitmq.client.GetResponse; +import static org.junit.Assert.assertEquals; import java.io.IOException; +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.Map; -import java.util.HashMap; + +import org.junit.Test; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.GetResponse; +import com.rabbitmq.client.ReturnListener; +import com.rabbitmq.client.test.BrokerTestCase; public class AlternateExchange extends BrokerTestCase { @@ -55,7 +59,7 @@ private static boolean[] expected(String key) { return expected; } - @Override protected void setUp() throws IOException, TimeoutException { + @Override public void setUp() throws IOException, TimeoutException { super.setUp(); channel.addReturnListener(new ReturnListener() { public void handleReturn(int replyCode, @@ -177,7 +181,7 @@ protected void check(String key, boolean ret) throws IOException { * check various cases of missing AEs - we expect to see some * warnings in the server logs */ - public void testMissing() throws IOException { + @Test public void missing() throws IOException { setupRouting("x", "u"); check("x", false); //no warning check("u", unrouted, false); //warning @@ -193,7 +197,7 @@ public void testMissing() throws IOException { cleanup(); } - public void testAe() throws IOException { + @Test public void ae() throws IOException { setupRouting(); for (String k : keys) { @@ -206,7 +210,7 @@ public void testAe() throws IOException { cleanup(); } - public void testCycleBreaking() throws IOException { + @Test public void cycleBreaking() throws IOException { setupRouting(); check("z", false); cleanup(); diff --git a/src/test/java/com/rabbitmq/client/test/functional/BasicGet.java b/src/test/java/com/rabbitmq/client/test/functional/BasicGet.java index c110c7f987..dddd17e8d6 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/BasicGet.java +++ b/src/test/java/com/rabbitmq/client/test/functional/BasicGet.java @@ -15,15 +15,23 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.AlreadyClosedException; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.io.IOException; import java.util.concurrent.TimeoutException; +import org.junit.Test; + +import com.rabbitmq.client.AlreadyClosedException; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.test.BrokerTestCase; + public class BasicGet extends BrokerTestCase { - public void testBasicGetWithEnqueuedMessages() throws IOException, InterruptedException { + @Test public void basicGetWithEnqueuedMessages() throws IOException, InterruptedException { assertTrue(channel.isOpen()); String q = channel.queueDeclare().getQueue(); @@ -36,7 +44,7 @@ public void testBasicGetWithEnqueuedMessages() throws IOException, InterruptedEx channel.queueDelete(q); } - public void testBasicGetWithEmptyQueue() throws IOException, InterruptedException { + @Test public void basicGetWithEmptyQueue() throws IOException, InterruptedException { assertTrue(channel.isOpen()); String q = channel.queueDeclare().getQueue(); @@ -44,7 +52,7 @@ public void testBasicGetWithEmptyQueue() throws IOException, InterruptedExceptio channel.queueDelete(q); } - public void testBasicGetWithClosedChannel() throws IOException, InterruptedException, TimeoutException { + @Test public void basicGetWithClosedChannel() throws IOException, InterruptedException, TimeoutException { assertTrue(channel.isOpen()); String q = channel.queueDeclare().getQueue(); diff --git a/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java b/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java index 2c155d579b..0090d40a45 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java +++ b/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java @@ -16,9 +16,17 @@ package com.rabbitmq.client.test.functional; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + import java.io.IOException; import java.util.concurrent.TimeoutException; +import org.junit.Test; + import com.rabbitmq.client.AMQP; import com.rabbitmq.client.GetResponse; @@ -36,7 +44,7 @@ public class BindingLifecycle extends BindingLifecycleBase { /** * This tests that when you purge a queue, all of its messages go. */ - public void testQueuePurge() throws IOException { + @Test public void queuePurge() throws IOException { Binding binding = setupExchangeBindings(false); channel.basicPublish(binding.x, binding.k, null, payload); @@ -57,7 +65,7 @@ public void testQueuePurge() throws IOException { * (Tx-)transacted." */ @SuppressWarnings("deprecation") - public void testUnackedPurge() throws IOException { + @Test public void unackedPurge() throws IOException { Binding binding = setupExchangeBindings(false); channel.basicPublish(binding.x, binding.k, null, payload); @@ -89,7 +97,7 @@ public void testUnackedPurge() throws IOException { * This tests whether when you delete an exchange, that any * bindings attached to it are deleted as well. */ - public void testExchangeDelete() throws IOException { + @Test public void exchangeDelete() throws IOException { boolean durable = true; Binding binding = setupExchangeAndRouteMessage(true); @@ -113,7 +121,7 @@ public void testExchangeDelete() throws IOException { * To test this, you try to delete an exchange with a queue still * bound to it and expect the delete operation to fail. */ - public void testExchangeIfUnused() throws IOException { + @Test public void exchangeIfUnused() throws IOException { boolean durable = true; Binding binding = setupExchangeBindings(true); @@ -150,7 +158,7 @@ public void testExchangeIfUnused() throws IOException { * Because the exchange has been auto-deleted, the bind operation * should fail. */ - public void testExchangeAutoDelete() throws IOException, TimeoutException { + @Test public void exchangeAutoDelete() throws IOException, TimeoutException { doAutoDelete(false, 1); } @@ -161,14 +169,14 @@ public void testExchangeAutoDelete() throws IOException, TimeoutException { * The difference should be that the original exchange should not * get auto-deleted */ - public void testExchangeAutoDeleteManyBindings() throws IOException, TimeoutException { + @Test public void exchangeAutoDeleteManyBindings() throws IOException, TimeoutException { doAutoDelete(false, 10); } /** * */ - public void testExchangePassiveDeclare() throws IOException { + @Test public void exchangePassiveDeclare() throws IOException { channel.exchangeDeclare("testPassive", "direct"); channel.exchangeDeclarePassive("testPassive"); @@ -184,7 +192,7 @@ public void testExchangePassiveDeclare() throws IOException { /** * Test the behaviour of queue.unbind */ - public void testUnbind() throws Exception { + @Test public void unbind() throws Exception { for (String exchange: new String[]{"amq.fanout", "amq.direct", "amq.topic", "amq.headers"}) { testUnbind(exchange); } diff --git a/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycleBase.java b/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycleBase.java index 0ff9be86ef..bb5f24c634 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycleBase.java +++ b/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycleBase.java @@ -16,11 +16,16 @@ package com.rabbitmq.client.test.functional; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.util.concurrent.TimeoutException; + import com.rabbitmq.client.AMQP; import com.rabbitmq.client.GetResponse; import com.rabbitmq.client.QueueingConsumer; -import java.io.IOException; -import java.util.concurrent.TimeoutException; /** * This tests whether bindings are created and nuked properly. diff --git a/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java b/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java index 6b2db8320f..8d0136419c 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java +++ b/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java @@ -15,19 +15,27 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.AMQP.BasicProperties; -import com.rabbitmq.client.GetResponse; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; import java.io.IOException; import java.util.ArrayList; -import java.util.HashMap; import java.util.Arrays; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.TimeoutException; +import org.junit.Test; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.AMQP.BasicProperties; +import com.rabbitmq.client.GetResponse; +import com.rabbitmq.client.test.BrokerTestCase; + public class CcRoutes extends BrokerTestCase { static private final String[] queues = new String[]{"queue1", "queue2", "queue3"}; @@ -38,7 +46,7 @@ public class CcRoutes extends BrokerTestCase { protected List ccList; protected List bccList; - @Override protected void setUp() throws IOException, TimeoutException { + @Override public void setUp() throws IOException, TimeoutException { super.setUp(); propsBuilder = new BasicProperties.Builder(); headers = new HashMap(); @@ -55,26 +63,26 @@ public class CcRoutes extends BrokerTestCase { channel.exchangeDeclare(exTopic, "topic", false, true, null); } - public void testCcList() throws IOException { + @Test public void ccList() throws IOException { ccList.add("queue2"); ccList.add("queue3"); headerPublish("", "queue1", ccList, null); expect(new String []{"queue1", "queue2", "queue3"}, true); } - public void testCcIgnoreEmptyAndInvalidRoutes() throws IOException { + @Test public void ccIgnoreEmptyAndInvalidRoutes() throws IOException { bccList.add("frob"); headerPublish("", "queue1", ccList, bccList); expect(new String []{"queue1"}, true); } - public void testBcc() throws IOException { + @Test public void bcc() throws IOException { bccList.add("queue2"); headerPublish("", "queue1", null, bccList); expect(new String []{"queue1", "queue2"}, false); } - public void testNoDuplicates() throws IOException { + @Test public void noDuplicates() throws IOException { ccList.add("queue1"); ccList.add("queue1"); bccList.add("queue1"); @@ -82,20 +90,20 @@ public void testNoDuplicates() throws IOException { expect(new String[] {"queue1"}, true); } - public void testDirectExchangeWithoutBindings() throws IOException { + @Test public void directExchangeWithoutBindings() throws IOException { ccList.add("queue1"); headerPublish(exDirect, "queue2", ccList, null); expect(new String[] {}, true); } - public void testTopicExchange() throws IOException { + @Test public void topicExchange() throws IOException { ccList.add("routing_key"); channel.queueBind("queue2", exTopic, "routing_key"); headerPublish(exTopic, "", ccList, null); expect(new String[] {"queue2"}, true); } - public void testBoundExchanges() throws IOException { + @Test public void boundExchanges() throws IOException { ccList.add("routing_key1"); bccList.add("routing_key2"); channel.exchangeBind(exTopic, exDirect, "routing_key1"); @@ -104,7 +112,7 @@ public void testBoundExchanges() throws IOException { expect(new String[] {"queue2"}, true); } - public void testNonArray() throws IOException { + @Test public void nonArray() throws IOException { headers.put("CC", 0); propsBuilder.headers(headers); channel.basicPublish("", "queue1", propsBuilder.build(), new byte[0]); diff --git a/src/test/java/com/rabbitmq/client/test/functional/Confirm.java b/src/test/java/com/rabbitmq/client/test/functional/Confirm.java index ef56719774..20adb70886 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Confirm.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Confirm.java @@ -16,6 +16,10 @@ package com.rabbitmq.client.test.functional; +import static org.junit.Assert.*; +import org.junit.Test; + + import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; import com.rabbitmq.client.ConfirmListener; @@ -39,7 +43,7 @@ public class Confirm extends BrokerTestCase private static final String TTL_ARG = "x-message-ttl"; @Override - protected void setUp() throws IOException, TimeoutException { + public void setUp() throws IOException, TimeoutException { super.setUp(); channel.confirmSelect(); channel.queueDeclare("confirm-test", true, true, false, null); @@ -62,7 +66,7 @@ protected void setUp() throws IOException, TimeoutException { "confirm-multiple-queues"); } - public void testPersistentMandatoryCombinations() + @Test public void persistentMandatoryCombinations() throws IOException, InterruptedException, TimeoutException { boolean b[] = { false, true }; for (boolean persistent : b) { @@ -72,18 +76,18 @@ public void testPersistentMandatoryCombinations() } } - public void testNonDurable() + @Test public void nonDurable() throws IOException, InterruptedException, TimeoutException { confirmTest("", "confirm-test-nondurable", true, false); } - public void testMandatoryNoRoute() + @Test public void mandatoryNoRoute() throws IOException, InterruptedException, TimeoutException { confirmTest("", "confirm-test-doesnotexist", false, true); confirmTest("", "confirm-test-doesnotexist", true, true); } - public void testMultipleQueues() + @Test public void multipleQueues() throws IOException, InterruptedException, TimeoutException { confirmTest("amq.direct", "confirm-multiple-queues", true, false); } @@ -93,7 +97,7 @@ public void testMultipleQueues() * (thus causing a confirm). I'd manually comment out the line in * internal_sync that notifies the clients. */ - public void testQueueDelete() + @Test public void queueDelete() throws IOException, InterruptedException, TimeoutException { publishN("","confirm-test-noconsumer", true, false); @@ -102,7 +106,7 @@ public void testQueueDelete() channel.waitForConfirmsOrDie(60000); } - public void testQueuePurge() + @Test public void queuePurge() throws IOException, InterruptedException, TimeoutException { publishN("", "confirm-test-noconsumer", true, false); @@ -112,7 +116,7 @@ public void testQueuePurge() } /* Tests rabbitmq-server #854 */ - public void testConfirmQueuePurge() + @Test public void confirmQueuePurge() throws IOException, InterruptedException, TimeoutException { channel.basicQos(1); for (int i = 0; i < 20000; i++) { @@ -124,14 +128,14 @@ public void testConfirmQueuePurge() channel.waitForConfirmsOrDie(90000); } - public void testBasicReject() + @Test public void basicReject() throws IOException, InterruptedException, TimeoutException { basicRejectCommon(false); channel.waitForConfirmsOrDie(60000); } - public void testQueueTTL() + @Test public void queueTTL() throws IOException, InterruptedException, TimeoutException { for (int ttl : new int[]{ 1, 0 }) { Map argMap = @@ -145,7 +149,7 @@ public void testQueueTTL() } } - public void testBasicRejectRequeue() + @Test public void basicRejectRequeue() throws IOException, InterruptedException, TimeoutException { basicRejectCommon(true); @@ -158,7 +162,7 @@ public void testBasicRejectRequeue() channel.waitForConfirmsOrDie(60000); } - public void testBasicRecover() + @Test public void basicRecover() throws IOException, InterruptedException, TimeoutException { publishN("", "confirm-test-noconsumer", true, false); @@ -179,7 +183,7 @@ public void testBasicRecover() channel.waitForConfirmsOrDie(60000); } - public void testSelect() + @Test public void select() throws IOException { channel.confirmSelect(); @@ -201,7 +205,7 @@ public void testSelect() } } - public void testWaitForConfirms() + @Test public void waitForConfirms() throws IOException, InterruptedException, TimeoutException { final SortedSet unconfirmedSet = Collections.synchronizedSortedSet(new TreeSet()); @@ -233,7 +237,7 @@ public void handleNack(long seqNo, boolean multiple) { } } - public void testWaitForConfirmsWithoutConfirmSelected() + @Test public void waitForConfirmsWithoutConfirmSelected() throws IOException, InterruptedException { channel = connection.createChannel(); @@ -247,7 +251,7 @@ public void testWaitForConfirmsWithoutConfirmSelected() } } - public void testWaitForConfirmsException() + @Test public void waitForConfirmsException() throws IOException, InterruptedException, TimeoutException { publishN("", "confirm-test", true, false); channel.close(); diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionOpen.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionOpen.java index b53e347f10..0cc3f2a2dd 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionOpen.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionOpen.java @@ -16,26 +16,30 @@ package com.rabbitmq.client.test.functional; -import java.io.IOException; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + import java.io.DataInputStream; +import java.io.IOException; import java.net.Socket; import java.util.concurrent.TimeoutException; +import org.junit.Test; + import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.MalformedFrameException; import com.rabbitmq.client.Method; -import com.rabbitmq.client.impl.SocketFrameHandler; import com.rabbitmq.client.impl.AMQCommand; -import com.rabbitmq.client.ConnectionFactory; - -import junit.framework.TestCase; +import com.rabbitmq.client.impl.SocketFrameHandler; /** * Check that protocol negotiation works */ -public class ConnectionOpen extends TestCase { - public void testCorrectProtocolHeader() throws IOException { +public class ConnectionOpen { + @Test public void correctProtocolHeader() throws IOException { ConnectionFactory factory = new ConnectionFactory(); SocketFrameHandler fh = new SocketFrameHandler(factory.getSocketFactory().createSocket("localhost", AMQP.PROTOCOL.PORT)); fh.sendHeader(); @@ -52,7 +56,7 @@ public void testCorrectProtocolHeader() throws IOException { start.getVersionMinor() <= AMQP.PROTOCOL.MINOR)); } - public void testCrazyProtocolHeader() throws IOException { + @Test public void crazyProtocolHeader() throws IOException { ConnectionFactory factory = new ConnectionFactory(); // keep the frame handler's socket Socket fhSocket = factory.getSocketFactory().createSocket("localhost", AMQP.PROTOCOL.PORT); @@ -84,7 +88,7 @@ public void testCrazyProtocolHeader() throws IOException { } } - public void testFrameMaxLessThanFrameMinSize() throws IOException, TimeoutException { + @Test public void frameMaxLessThanFrameMinSize() throws IOException, TimeoutException { ConnectionFactory factory = new ConnectionFactory(); factory.setRequestedFrameMax(100); try { diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java index f059898fcf..cccad4488d 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -15,18 +15,15 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.*; -import com.rabbitmq.client.impl.AMQConnection; -import com.rabbitmq.client.impl.recovery.*; -import com.rabbitmq.client.Recoverable; -import com.rabbitmq.client.RecoveryListener; -import com.rabbitmq.client.test.BrokerTestCase; -import com.rabbitmq.tools.Host; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.io.IOException; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.ArrayList; import java.util.UUID; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -34,17 +31,43 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; +import org.junit.Test; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Address; +import com.rabbitmq.client.BlockedListener; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.ConfirmListener; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.Consumer; +import com.rabbitmq.client.DefaultConsumer; +import com.rabbitmq.client.Envelope; +import com.rabbitmq.client.QueueingConsumer; +import com.rabbitmq.client.Recoverable; +import com.rabbitmq.client.RecoveryListener; +import com.rabbitmq.client.ReturnListener; +import com.rabbitmq.client.ShutdownListener; +import com.rabbitmq.client.ShutdownSignalException; +import com.rabbitmq.client.impl.recovery.AutorecoveringChannel; +import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; +import com.rabbitmq.client.impl.recovery.ConsumerRecoveryListener; +import com.rabbitmq.client.impl.recovery.QueueRecoveryListener; +import com.rabbitmq.client.impl.recovery.RecoveryCanBeginListener; +import com.rabbitmq.client.test.BrokerTestCase; +import com.rabbitmq.tools.Host; + @SuppressWarnings("ThrowFromFinallyBlock") public class ConnectionRecovery extends BrokerTestCase { private static final long RECOVERY_INTERVAL = 2000; - public void testConnectionRecovery() throws IOException, InterruptedException { + @Test public void connectionRecovery() throws IOException, InterruptedException { assertTrue(connection.isOpen()); closeAndWaitForRecovery(); assertTrue(connection.isOpen()); } - public void testNamedConnectionRecovery() + @Test public void namedConnectionRecovery() throws IOException, InterruptedException, TimeoutException { String connectionName = "custom name"; AutorecoveringConnection c = newRecoveringConnection(connectionName); @@ -59,13 +82,13 @@ public void testNamedConnectionRecovery() } } - public void testConnectionRecoveryWithServerRestart() throws IOException, InterruptedException { + @Test public void connectionRecoveryWithServerRestart() throws IOException, InterruptedException { assertTrue(connection.isOpen()); restartPrimaryAndWaitForRecovery(); assertTrue(connection.isOpen()); } - public void testConnectionRecoveryWithArrayOfAddresses() + @Test public void connectionRecoveryWithArrayOfAddresses() throws IOException, InterruptedException, TimeoutException { final Address[] addresses = {new Address("127.0.0.1"), new Address("127.0.0.1", 5672)}; AutorecoveringConnection c = newRecoveringConnection(addresses); @@ -79,7 +102,7 @@ public void testConnectionRecoveryWithArrayOfAddresses() } - public void testConnectionRecoveryWithListOfAddresses() + @Test public void connectionRecoveryWithListOfAddresses() throws IOException, InterruptedException, TimeoutException { final List
addresses = Arrays.asList(new Address("127.0.0.1"), new Address("127.0.0.1", 5672)); @@ -94,7 +117,7 @@ public void testConnectionRecoveryWithListOfAddresses() } } - public void testConnectionRecoveryWithDisabledTopologyRecovery() + @Test public void connectionRecoveryWithDisabledTopologyRecovery() throws IOException, InterruptedException, TimeoutException { AutorecoveringConnection c = newRecoveringConnection(true); Channel ch = c.createChannel(); @@ -119,7 +142,7 @@ public void testConnectionRecoveryWithDisabledTopologyRecovery() } // see https://github.com/rabbitmq/rabbitmq-java-client/issues/135 - public void testThatShutdownHooksOnConnectionFireBeforeRecoveryStarts() throws IOException, InterruptedException { + @Test public void thatShutdownHooksOnConnectionFireBeforeRecoveryStarts() throws IOException, InterruptedException { final List events = new ArrayList(); final CountDownLatch latch = new CountDownLatch(1); connection.addShutdownListener(new ShutdownListener() { @@ -156,7 +179,7 @@ public void handleRecovery(Recoverable recoverable) { wait(latch); } - public void testShutdownHooksRecoveryOnConnection() throws IOException, InterruptedException { + @Test public void shutdownHooksRecoveryOnConnection() throws IOException, InterruptedException { final CountDownLatch latch = new CountDownLatch(2); connection.addShutdownListener(new ShutdownListener() { public void shutdownCompleted(ShutdownSignalException cause) { @@ -170,7 +193,7 @@ public void shutdownCompleted(ShutdownSignalException cause) { wait(latch); } - public void testShutdownHooksRecoveryOnChannel() throws IOException, InterruptedException { + @Test public void shutdownHooksRecoveryOnChannel() throws IOException, InterruptedException { final CountDownLatch latch = new CountDownLatch(3); channel.addShutdownListener(new ShutdownListener() { public void shutdownCompleted(ShutdownSignalException cause) { @@ -186,7 +209,7 @@ public void shutdownCompleted(ShutdownSignalException cause) { wait(latch); } - public void testBlockedListenerRecovery() throws IOException, InterruptedException { + @Test public void blockedListenerRecovery() throws IOException, InterruptedException { final CountDownLatch latch = new CountDownLatch(2); connection.addBlockedListener(new BlockedListener() { public void handleBlocked(String reason) throws IOException { @@ -204,7 +227,7 @@ public void handleUnblocked() throws IOException { wait(latch); } - public void testChannelRecovery() throws IOException, InterruptedException { + @Test public void channelRecovery() throws IOException, InterruptedException { Channel ch1 = connection.createChannel(); Channel ch2 = connection.createChannel(); @@ -215,7 +238,7 @@ public void testChannelRecovery() throws IOException, InterruptedException { expectChannelRecovery(ch2); } - public void testReturnListenerRecovery() throws IOException, InterruptedException { + @Test public void returnListenerRecovery() throws IOException, InterruptedException { final CountDownLatch latch = new CountDownLatch(1); channel.addReturnListener(new ReturnListener() { public void handleReturn(int replyCode, String replyText, String exchange, @@ -230,7 +253,7 @@ public void handleReturn(int replyCode, String replyText, String exchange, wait(latch); } - public void testConfirmListenerRecovery() throws IOException, InterruptedException, TimeoutException { + @Test public void confirmListenerRecovery() throws IOException, InterruptedException, TimeoutException { final CountDownLatch latch = new CountDownLatch(1); channel.addConfirmListener(new ConfirmListener() { public void handleAck(long deliveryTag, boolean multiple) throws IOException { @@ -250,7 +273,7 @@ public void handleNack(long deliveryTag, boolean multiple) throws IOException { wait(latch); } - public void testExchangeRecovery() throws IOException, InterruptedException, TimeoutException { + @Test public void exchangeRecovery() throws IOException, InterruptedException, TimeoutException { Channel ch = connection.createChannel(); String x = "java-client.test.recovery.x1"; declareExchange(ch, x); @@ -260,7 +283,7 @@ public void testExchangeRecovery() throws IOException, InterruptedException, Tim ch.exchangeDelete(x); } - public void testExchangeRecoveryWithNoWait() throws IOException, InterruptedException, TimeoutException { + @Test public void exchangeRecoveryWithNoWait() throws IOException, InterruptedException, TimeoutException { Channel ch = connection.createChannel(); String x = "java-client.test.recovery.x1-nowait"; declareExchangeNoWait(ch, x); @@ -270,11 +293,11 @@ public void testExchangeRecoveryWithNoWait() throws IOException, InterruptedExce ch.exchangeDelete(x); } - public void testClientNamedQueueRecovery() throws IOException, InterruptedException, TimeoutException { + @Test public void clientNamedQueueRecovery() throws IOException, InterruptedException, TimeoutException { testClientNamedQueueRecoveryWith("java-client.test.recovery.q1", false); } - public void testClientNamedQueueRecoveryWithNoWait() throws IOException, InterruptedException, TimeoutException { + @Test public void clientNamedQueueRecoveryWithNoWait() throws IOException, InterruptedException, TimeoutException { testClientNamedQueueRecoveryWith("java-client.test.recovery.q1-nowait", true); } @@ -291,7 +314,7 @@ private void testClientNamedQueueRecoveryWith(String q, boolean noWait) throws I ch.queueDelete(q); } - public void testClientNamedQueueBindingRecovery() throws IOException, InterruptedException, TimeoutException { + @Test public void clientNamedQueueBindingRecovery() throws IOException, InterruptedException, TimeoutException { String q = "java-client.test.recovery.q2"; String x = "tmp-fanout"; Channel ch = connection.createChannel(); @@ -308,7 +331,7 @@ public void testClientNamedQueueBindingRecovery() throws IOException, Interrupte } // bug 26552 - public void testClientNamedTransientAutoDeleteQueueAndBindingRecovery() throws IOException, InterruptedException, TimeoutException { + @Test public void clientNamedTransientAutoDeleteQueueAndBindingRecovery() throws IOException, InterruptedException, TimeoutException { String q = UUID.randomUUID().toString(); String x = "tmp-fanout"; Channel ch = connection.createChannel(); @@ -331,7 +354,7 @@ public void testClientNamedTransientAutoDeleteQueueAndBindingRecovery() throws I } // bug 26552 - public void testServerNamedTransientAutoDeleteQueueAndBindingRecovery() throws IOException, InterruptedException, TimeoutException { + @Test public void serverNamedTransientAutoDeleteQueueAndBindingRecovery() throws IOException, InterruptedException, TimeoutException { String x = "tmp-fanout"; Channel ch = connection.createChannel(); ch.exchangeDelete(x); @@ -361,7 +384,7 @@ public void queueRecovered(String oldName, String newName) { ch.exchangeDelete(x); } - public void testDeclarationOfManyAutoDeleteQueuesWithTransientConsumer() throws IOException, TimeoutException { + @Test public void declarationOfManyAutoDeleteQueuesWithTransientConsumer() throws IOException, TimeoutException { Channel ch = connection.createChannel(); assertRecordedQueues(connection, 0); for(int i = 0; i < 5000; i++) { @@ -375,7 +398,7 @@ public void testDeclarationOfManyAutoDeleteQueuesWithTransientConsumer() throws ch.close(); } - public void testDeclarationOfManyAutoDeleteExchangesWithTransientQueuesThatAreUnbound() throws IOException, TimeoutException { + @Test public void declarationOfManyAutoDeleteExchangesWithTransientQueuesThatAreUnbound() throws IOException, TimeoutException { Channel ch = connection.createChannel(); assertRecordedExchanges(connection, 0); for(int i = 0; i < 5000; i++) { @@ -391,7 +414,7 @@ public void testDeclarationOfManyAutoDeleteExchangesWithTransientQueuesThatAreUn ch.close(); } - public void testDeclarationOfManyAutoDeleteExchangesWithTransientQueuesThatAreDeleted() throws IOException, TimeoutException { + @Test public void declarationOfManyAutoDeleteExchangesWithTransientQueuesThatAreDeleted() throws IOException, TimeoutException { Channel ch = connection.createChannel(); assertRecordedExchanges(connection, 0); for(int i = 0; i < 5000; i++) { @@ -405,7 +428,7 @@ public void testDeclarationOfManyAutoDeleteExchangesWithTransientQueuesThatAreDe ch.close(); } - public void testDeclarationOfManyAutoDeleteExchangesWithTransientExchangesThatAreUnbound() throws IOException, TimeoutException { + @Test public void declarationOfManyAutoDeleteExchangesWithTransientExchangesThatAreUnbound() throws IOException, TimeoutException { Channel ch = connection.createChannel(); assertRecordedExchanges(connection, 0); for(int i = 0; i < 5000; i++) { @@ -422,7 +445,7 @@ public void testDeclarationOfManyAutoDeleteExchangesWithTransientExchangesThatAr ch.close(); } - public void testDeclarationOfManyAutoDeleteExchangesWithTransientExchangesThatAreDeleted() throws IOException, TimeoutException { + @Test public void declarationOfManyAutoDeleteExchangesWithTransientExchangesThatAreDeleted() throws IOException, TimeoutException { Channel ch = connection.createChannel(); assertRecordedExchanges(connection, 0); for(int i = 0; i < 5000; i++) { @@ -437,7 +460,7 @@ public void testDeclarationOfManyAutoDeleteExchangesWithTransientExchangesThatAr ch.close(); } - public void testServerNamedQueueRecovery() throws IOException, InterruptedException { + @Test public void serverNamedQueueRecovery() throws IOException, InterruptedException { String q = channel.queueDeclare("", false, false, false, null).getQueue(); String x = "amq.fanout"; channel.queueBind(q, x, ""); @@ -463,7 +486,7 @@ public void queueRecovered(String oldName, String newName) { channel.queueDelete(q); } - public void testExchangeToExchangeBindingRecovery() throws IOException, InterruptedException { + @Test public void exchangeToExchangeBindingRecovery() throws IOException, InterruptedException { String q = channel.queueDeclare("", false, false, false, null).getQueue(); String x1 = "amq.fanout"; String x2 = generateExchangeName(); @@ -482,7 +505,7 @@ public void testExchangeToExchangeBindingRecovery() throws IOException, Interrup } } - public void testThatDeletedQueueBindingsDontReappearOnRecovery() throws IOException, InterruptedException { + @Test public void thatDeletedQueueBindingsDontReappearOnRecovery() throws IOException, InterruptedException { String q = channel.queueDeclare("", false, false, false, null).getQueue(); String x1 = "amq.fanout"; String x2 = generateExchangeName(); @@ -502,7 +525,7 @@ public void testThatDeletedQueueBindingsDontReappearOnRecovery() throws IOExcept } } - public void testThatDeletedExchangeBindingsDontReappearOnRecovery() throws IOException, InterruptedException { + @Test public void thatDeletedExchangeBindingsDontReappearOnRecovery() throws IOException, InterruptedException { String q = channel.queueDeclare("", false, false, false, null).getQueue(); String x1 = "amq.fanout"; String x2 = generateExchangeName(); @@ -522,7 +545,7 @@ public void testThatDeletedExchangeBindingsDontReappearOnRecovery() throws IOExc } } - public void testThatDeletedExchangeDoesNotReappearOnRecover() throws IOException, InterruptedException { + @Test public void thatDeletedExchangeDoesNotReappearOnRecover() throws IOException, InterruptedException { String x = generateExchangeName(); channel.exchangeDeclare(x, "fanout"); channel.exchangeDelete(x); @@ -536,7 +559,7 @@ public void testThatDeletedExchangeDoesNotReappearOnRecover() throws IOException } } - public void testThatDeletedQueueDoesNotReappearOnRecover() throws IOException, InterruptedException { + @Test public void thatDeletedQueueDoesNotReappearOnRecover() throws IOException, InterruptedException { String q = channel.queueDeclare().getQueue(); channel.queueDelete(q); try { @@ -549,7 +572,7 @@ public void testThatDeletedQueueDoesNotReappearOnRecover() throws IOException, I } } - public void testThatCancelledConsumerDoesNotReappearOnRecover() throws IOException, InterruptedException { + @Test public void thatCancelledConsumerDoesNotReappearOnRecover() throws IOException, InterruptedException { String q = UUID.randomUUID().toString(); channel.queueDeclare(q, false, false, false, null); String tag = channel.basicConsume(q, new DefaultConsumer(channel)); @@ -560,7 +583,7 @@ public void testThatCancelledConsumerDoesNotReappearOnRecover() throws IOExcepti assertConsumerCount(0, q); } - public void testConsumerRecoveryWithManyConsumers() throws IOException, InterruptedException { + @Test public void consumerRecoveryWithManyConsumers() throws IOException, InterruptedException { String q = channel.queueDeclare(UUID.randomUUID().toString(), false, false, false, null).getQueue(); final int n = 1024; for (int i = 0; i < n; i++) { @@ -587,7 +610,7 @@ public void consumerRecovered(String oldConsumerTag, String newConsumerTag) { } - public void testSubsequentRecoveriesWithClientNamedQueue() throws IOException, InterruptedException { + @Test public void subsequentRecoveriesWithClientNamedQueue() throws IOException, InterruptedException { String q = channel.queueDeclare(UUID.randomUUID().toString(), false, false, false, null).getQueue(); assertConsumerCount(0, q); @@ -601,7 +624,7 @@ public void testSubsequentRecoveriesWithClientNamedQueue() throws IOException, I channel.queueDelete(q); } - public void testQueueRecoveryWithManyQueues() throws IOException, InterruptedException, TimeoutException { + @Test public void queueRecoveryWithManyQueues() throws IOException, InterruptedException, TimeoutException { List qs = new ArrayList(); final int n = 1024; for (int i = 0; i < n; i++) { @@ -615,7 +638,7 @@ public void testQueueRecoveryWithManyQueues() throws IOException, InterruptedExc } } - public void testChannelRecoveryCallback() throws IOException, InterruptedException { + @Test public void channelRecoveryCallback() throws IOException, InterruptedException { final CountDownLatch latch = new CountDownLatch(2); final RecoveryListener listener = new RecoveryListener() { public void handleRecovery(Recoverable recoverable) { @@ -635,7 +658,7 @@ public void handleRecovery(Recoverable recoverable) { wait(latch); } - public void testBasicAckAfterChannelRecovery() throws IOException, InterruptedException, TimeoutException { + @Test public void basicAckAfterChannelRecovery() throws IOException, InterruptedException, TimeoutException { final AtomicInteger consumed = new AtomicInteger(0); int n = 5; final CountDownLatch latch = new CountDownLatch(n); diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java b/src/test/java/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java index f73625cd62..087986608d 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java @@ -15,13 +15,8 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.Consumer; -import com.rabbitmq.client.DefaultConsumer; -import com.rabbitmq.client.ConsumerCancelledException; -import com.rabbitmq.client.QueueingConsumer; -import com.rabbitmq.client.ShutdownSignalException; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.io.IOException; import java.util.concurrent.ArrayBlockingQueue; @@ -29,11 +24,21 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import org.junit.Test; + +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Consumer; +import com.rabbitmq.client.ConsumerCancelledException; +import com.rabbitmq.client.DefaultConsumer; +import com.rabbitmq.client.QueueingConsumer; +import com.rabbitmq.client.ShutdownSignalException; +import com.rabbitmq.client.test.BrokerTestCase; + public class ConsumerCancelNotification extends BrokerTestCase { private final String queue = "cancel_notification_queue"; - public void testConsumerCancellationNotification() throws IOException, + @Test public void consumerCancellationNotification() throws IOException, InterruptedException { final BlockingQueue result = new ArrayBlockingQueue(1); @@ -53,7 +58,7 @@ public void handleCancel(String consumerTag) throws IOException { assertTrue(result.take()); } - public void testConsumerCancellationInterruptsQueuingConsumerWait() + @Test public void consumerCancellationInterruptsQueuingConsumerWait() throws IOException, InterruptedException { final BlockingQueue result = new ArrayBlockingQueue(1); channel.queueDeclare(queue, false, true, false, null); @@ -112,7 +117,7 @@ public void handleCancel(String consumerTag) { } } - public void testConsumerCancellationHandlerUsesBlockingOperations() + @Test public void consumerCancellationHandlerUsesBlockingOperations() throws IOException, InterruptedException { final String altQueue = "basic.cancel.fallback"; channel.queueDeclare(queue, false, true, false, null); diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConsumerCount.java b/src/test/java/com/rabbitmq/client/test/functional/ConsumerCount.java index 1bc4c76944..e4230d9f92 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConsumerCount.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConsumerCount.java @@ -15,13 +15,17 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.DefaultConsumer; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.assertEquals; import java.io.IOException; +import org.junit.Test; + +import com.rabbitmq.client.DefaultConsumer; +import com.rabbitmq.client.test.BrokerTestCase; + public class ConsumerCount extends BrokerTestCase { - public void testConsumerCount() throws IOException { + @Test public void consumerCount() throws IOException { String q = generateQueueName(); channel.queueDeclare(q, false, true, false, null); assertEquals(0, channel.consumerCount(q)); diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConsumerPriorities.java b/src/test/java/com/rabbitmq/client/test/functional/ConsumerPriorities.java index 6b2da2a114..e9c24dbf0d 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConsumerPriorities.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConsumerPriorities.java @@ -15,21 +15,26 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.MessageProperties; -import com.rabbitmq.client.QueueingConsumer; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; import java.io.IOException; import java.util.Arrays; import java.util.HashMap; import java.util.Map; +import org.junit.Test; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.MessageProperties; +import com.rabbitmq.client.QueueingConsumer; +import com.rabbitmq.client.test.BrokerTestCase; + public class ConsumerPriorities extends BrokerTestCase { - public void testValidation() throws IOException { + @Test public void validation() throws IOException { assertFailValidation(args("banana")); - assertFailValidation(args(new HashMap())); + assertFailValidation(args(new HashMap())); assertFailValidation(args(null)); assertFailValidation(args(Arrays.asList(1, 2, 3))); } @@ -47,7 +52,7 @@ private void assertFailValidation(Map args) throws IOException { private static final int COUNT = 10; - public void testConsumerPriorities() throws Exception { + @Test public void consumerPriorities() throws Exception { String queue = channel.queueDeclare().getQueue(); QueueingConsumer highConsumer = new QueueingConsumer(channel); QueueingConsumer medConsumer = new QueueingConsumer(channel); diff --git a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java index 5e3fb55d4a..44bbb3a639 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java @@ -15,20 +15,15 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.AMQP.BasicProperties; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.DefaultConsumer; -import com.rabbitmq.client.Envelope; -import com.rabbitmq.client.GetResponse; -import com.rabbitmq.client.MessageProperties; -import com.rabbitmq.client.QueueingConsumer; -import com.rabbitmq.client.QueueingConsumer.Delivery; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.io.IOException; -import java.util.Arrays; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -37,6 +32,19 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import org.junit.Test; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.AMQP.BasicProperties; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.DefaultConsumer; +import com.rabbitmq.client.Envelope; +import com.rabbitmq.client.GetResponse; +import com.rabbitmq.client.MessageProperties; +import com.rabbitmq.client.QueueingConsumer; +import com.rabbitmq.client.QueueingConsumer.Delivery; +import com.rabbitmq.client.test.BrokerTestCase; + public class DeadLetterExchange extends BrokerTestCase { public static final String DLX = "dead.letter.exchange"; public static final String DLX_ARG = "x-dead-letter-exchange"; @@ -60,33 +68,33 @@ protected void releaseResources() throws IOException { channel.exchangeDelete(DLX); } - public void testDeclareQueueWithExistingDeadLetterExchange() + @Test public void declareQueueWithExistingDeadLetterExchange() throws IOException { declareQueue(DLX); } - public void testDeclareQueueWithNonExistingDeadLetterExchange() + @Test public void declareQueueWithNonExistingDeadLetterExchange() throws IOException { declareQueue("some.random.exchange.name"); } - public void testDeclareQueueWithEquivalentDeadLetterExchange() + @Test public void declareQueueWithEquivalentDeadLetterExchange() throws IOException { declareQueue(DLX); declareQueue(DLX); } - public void testDeclareQueueWithEquivalentDeadLetterRoutingKey() + @Test public void declareQueueWithEquivalentDeadLetterRoutingKey() throws IOException { declareQueue(TEST_QUEUE_NAME, DLX, "routing_key", null); declareQueue(TEST_QUEUE_NAME, DLX, "routing_key", null); } - public void testDeclareQueueWithInvalidDeadLetterExchangeArg() + @Test public void declareQueueWithInvalidDeadLetterExchangeArg() throws IOException { try { @@ -97,7 +105,7 @@ public void testDeclareQueueWithInvalidDeadLetterExchangeArg() } } - public void testRedeclareQueueWithInvalidDeadLetterExchangeArg() + @Test public void redeclareQueueWithInvalidDeadLetterExchangeArg() throws IOException { declareQueue("inequivalent_dlx_name", "dlx_foo", null, null); @@ -110,7 +118,7 @@ public void testRedeclareQueueWithInvalidDeadLetterExchangeArg() } } - public void testDeclareQueueWithInvalidDeadLetterRoutingKeyArg() + @Test public void declareQueueWithInvalidDeadLetterRoutingKeyArg() throws IOException { try { @@ -121,7 +129,7 @@ public void testDeclareQueueWithInvalidDeadLetterRoutingKeyArg() } } - public void testRedeclareQueueWithInvalidDeadLetterRoutingKeyArg() + @Test public void redeclareQueueWithInvalidDeadLetterRoutingKeyArg() throws IOException { declareQueue("inequivalent_dlx_rk", "amq.direct", "dlx_rk", null); @@ -134,7 +142,7 @@ public void testRedeclareQueueWithInvalidDeadLetterRoutingKeyArg() } } - public void testDeclareQueueWithRoutingKeyButNoDeadLetterExchange() + @Test public void declareQueueWithRoutingKeyButNoDeadLetterExchange() throws IOException { try { @@ -148,7 +156,7 @@ public void testDeclareQueueWithRoutingKeyButNoDeadLetterExchange() } } - public void testRedeclareQueueWithRoutingKeyButNoDeadLetterExchange() + @Test public void redeclareQueueWithRoutingKeyButNoDeadLetterExchange() throws IOException { try { @@ -165,15 +173,15 @@ public void testRedeclareQueueWithRoutingKeyButNoDeadLetterExchange() } } - public void testDeadLetterQueueTTLExpiredMessages() throws Exception { + @Test public void deadLetterQueueTTLExpiredMessages() throws Exception { ttlTest(TTL); } - public void testDeadLetterQueueZeroTTLExpiredMessages() throws Exception { + @Test public void deadLetterQueueZeroTTLExpiredMessages() throws Exception { ttlTest(0); } - public void testDeadLetterQueueTTLPromptExpiry() throws Exception { + @Test public void deadLetterQueueTTLPromptExpiry() throws Exception { Map args = new HashMap(); args.put("x-message-ttl", TTL); declareQueue(TEST_QUEUE_NAME, DLX, null, args); @@ -226,7 +234,7 @@ public void testDeadLetterQueueTTLPromptExpiry() throws Exception { checkPromptArrival(c, 2, latency); } - public void testDeadLetterDeletedDLX() throws Exception { + @Test public void deadLetterDeletedDLX() throws Exception { declareQueue(TEST_QUEUE_NAME, DLX, null, null, 1); channel.queueBind(TEST_QUEUE_NAME, "amq.direct", "test"); channel.queueBind(DLQ, DLX, "test"); @@ -246,7 +254,7 @@ public void testDeadLetterDeletedDLX() throws Exception { consumeN(DLQ, MSG_COUNT, WithResponse.NULL); } - public void testDeadLetterPerMessageTTLRemoved() throws Exception { + @Test public void deadLetterPerMessageTTLRemoved() throws Exception { declareQueue(TEST_QUEUE_NAME, DLX, null, null, 1); channel.queueBind(TEST_QUEUE_NAME, "amq.direct", "test"); channel.queueBind(DLQ, DLX, "test"); @@ -275,15 +283,15 @@ public void process(GetResponse getResponse) { }); } - public void testDeadLetterOnReject() throws Exception { + @Test public void deadLetterOnReject() throws Exception { rejectionTest(false); } - public void testDeadLetterOnNack() throws Exception { + @Test public void deadLetterOnNack() throws Exception { rejectionTest(true); } - public void testDeadLetterNoDeadLetterQueue() throws IOException { + @Test public void deadLetterNoDeadLetterQueue() throws IOException { channel.queueDelete(DLQ); declareQueue(TEST_QUEUE_NAME, DLX, null, null, 1); @@ -292,7 +300,7 @@ public void testDeadLetterNoDeadLetterQueue() throws IOException { publishN(MSG_COUNT); } - public void testDeadLetterMultipleDeadLetterQueues() + @Test public void deadLetterMultipleDeadLetterQueues() throws IOException { declareQueue(TEST_QUEUE_NAME, DLX, null, null, 1); @@ -306,7 +314,7 @@ public void testDeadLetterMultipleDeadLetterQueues() publishN(MSG_COUNT); } - public void testDeadLetterTwice() throws Exception { + @Test public void deadLetterTwice() throws Exception { declareQueue(TEST_QUEUE_NAME, DLX, null, null, 1); channel.queueDelete(DLQ); @@ -343,7 +351,7 @@ public void process(GetResponse getResponse) { }); } - public void testDeadLetterSelf() throws Exception { + @Test public void deadLetterSelf() throws Exception { declareQueue(TEST_QUEUE_NAME, "amq.direct", "test", null, 1); channel.queueBind(TEST_QUEUE_NAME, "amq.direct", "test"); @@ -357,7 +365,7 @@ public void testDeadLetterSelf() throws Exception { consumeN(TEST_QUEUE_NAME, 0, WithResponse.NULL); } - public void testDeadLetterCycle() throws Exception { + @Test public void deadLetterCycle() throws Exception { // testDeadLetterTwice and testDeadLetterSelf both test that we drop // messages in pure-expiry cycles. So we just need to test that // non-pure-expiry cycles do not drop messages. @@ -379,7 +387,7 @@ public void handleDelivery(String consumerTag, Envelope envelope, assertTrue(latch.await(10, TimeUnit.SECONDS)); } - public void testDeadLetterNewRK() throws Exception { + @Test public void deadLetterNewRK() throws Exception { declareQueue(TEST_QUEUE_NAME, DLX, "test-other", null, 1); channel.queueDeclare(DLQ2, false, true, false, null); @@ -418,7 +426,7 @@ public void process(GetResponse getResponse) { } @SuppressWarnings("unchecked") - public void testRepublish() throws Exception { + @Test public void republish() throws Exception { Map args = new HashMap(); args.put("x-message-ttl", 100); declareQueue(TEST_QUEUE_NAME, DLX, null, args); diff --git a/src/test/java/com/rabbitmq/client/test/functional/DefaultExchange.java b/src/test/java/com/rabbitmq/client/test/functional/DefaultExchange.java index 25c4c99390..fb27da6391 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DefaultExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DefaultExchange.java @@ -15,11 +15,15 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.fail; import java.io.IOException; +import org.junit.Test; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.test.BrokerTestCase; + public class DefaultExchange extends BrokerTestCase { String queueName; @@ -31,12 +35,12 @@ protected void createResources() throws IOException { // See bug 22101: publish and declare are the only operations // permitted on the default exchange - public void testDefaultExchangePublish() throws IOException { + @Test public void defaultExchangePublish() throws IOException { basicPublishVolatile("", queueName); // Implicit binding assertDelivered(queueName, 1); } - public void testBindToDefaultExchange() throws IOException { + @Test public void bindToDefaultExchange() throws IOException { try { channel.queueBind(queueName, "", "foobar"); fail(); @@ -45,7 +49,7 @@ public void testBindToDefaultExchange() throws IOException { } } - public void testUnbindFromDefaultExchange() throws IOException { + @Test public void unbindFromDefaultExchange() throws IOException { try { channel.queueUnbind(queueName, "", queueName); fail(); @@ -54,7 +58,7 @@ public void testUnbindFromDefaultExchange() throws IOException { } } - public void testDeclareDefaultExchange() throws IOException { + @Test public void declareDefaultExchange() throws IOException { try { channel.exchangeDeclare("", "direct", true); fail(); @@ -63,7 +67,7 @@ public void testDeclareDefaultExchange() throws IOException { } } - public void testDeleteDefaultExchange() throws IOException { + @Test public void deleteDefaultExchange() throws IOException { try { channel.exchangeDelete(""); fail(); diff --git a/src/test/java/com/rabbitmq/client/test/functional/DirectReplyTo.java b/src/test/java/com/rabbitmq/client/test/functional/DirectReplyTo.java index aa39e4804c..06b3d9e3b4 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DirectReplyTo.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DirectReplyTo.java @@ -15,6 +15,16 @@ package com.rabbitmq.client.test.functional; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; + +import org.junit.Test; + import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; @@ -23,12 +33,10 @@ import com.rabbitmq.client.QueueingConsumer; import com.rabbitmq.client.test.BrokerTestCase; -import java.io.IOException; - public class DirectReplyTo extends BrokerTestCase { private static final String QUEUE = "amq.rabbitmq.reply-to"; - public void testRoundTrip() throws IOException, InterruptedException { + @Test public void roundTrip() throws IOException, InterruptedException { QueueingConsumer c = new QueueingConsumer(channel); String replyTo = rpcFirstHalf(c); declare(connection, replyTo, true); @@ -40,7 +48,7 @@ public void testRoundTrip() throws IOException, InterruptedException { assertEquals("response", new String(del.getBody())); } - public void testHack() throws IOException, InterruptedException { + @Test public void hack() throws IOException, InterruptedException { QueueingConsumer c = new QueueingConsumer(channel); String replyTo = rpcFirstHalf(c); // 5 chars should overwrite part of the key but not the pid; aiming to prove @@ -66,7 +74,7 @@ private void declare(Connection connection, String q, boolean expectedExists) th } } - public void testConsumeFail() throws IOException, InterruptedException { + @Test public void consumeFail() throws IOException, InterruptedException { QueueingConsumer c = new QueueingConsumer(channel); Channel ch = connection.createChannel(); try { @@ -86,7 +94,7 @@ public void testConsumeFail() throws IOException, InterruptedException { } } - public void testConsumeSuccess() throws IOException, InterruptedException { + @Test public void consumeSuccess() throws IOException, InterruptedException { QueueingConsumer c = new QueueingConsumer(channel); String ctag = channel.basicConsume(QUEUE, true, c); channel.basicCancel(ctag); diff --git a/src/test/java/com/rabbitmq/client/test/functional/DoubleDeletion.java b/src/test/java/com/rabbitmq/client/test/functional/DoubleDeletion.java index bae5eb7c8d..305b152fab 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DoubleDeletion.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DoubleDeletion.java @@ -18,6 +18,8 @@ import java.io.IOException; +import org.junit.Test; + import com.rabbitmq.client.test.BrokerTestCase; public class DoubleDeletion extends BrokerTestCase @@ -25,7 +27,7 @@ public class DoubleDeletion extends BrokerTestCase protected static final String Q = "DoubleDeletionQueue"; protected static final String X = "DoubleDeletionExchange"; - public void testDoubleDeletionQueue() + @Test public void doubleDeletionQueue() throws IOException { channel.queueDelete(Q); @@ -34,7 +36,7 @@ public void testDoubleDeletionQueue() channel.queueDelete(Q); } - public void testDoubleDeletionExchange() + @Test public void doubleDeletionExchange() throws IOException { channel.exchangeDelete(X); diff --git a/src/test/java/com/rabbitmq/client/test/functional/DurableOnTransient.java b/src/test/java/com/rabbitmq/client/test/functional/DurableOnTransient.java index 84f488df7c..adb11c9bf3 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DurableOnTransient.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DurableOnTransient.java @@ -16,8 +16,12 @@ package com.rabbitmq.client.test.functional; +import static org.junit.Assert.assertNotNull; + import java.io.IOException; +import org.junit.Test; + import com.rabbitmq.client.GetResponse; import com.rabbitmq.client.MessageProperties; @@ -55,7 +59,7 @@ protected void releaseResources() throws IOException { channel.exchangeDelete(X); } - public void testBindDurableToTransient() + @Test public void bindDurableToTransient() throws IOException { channel.queueBind(Q, X, ""); @@ -63,7 +67,7 @@ public void testBindDurableToTransient() assertNotNull(basicGet()); } - public void testSemiDurableBindingRemoval() throws IOException { + @Test public void semiDurableBindingRemoval() throws IOException { if (clusteredConnection != null) { deleteExchange("x"); declareTransientTopicExchange("x"); diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExceptionHandling.java b/src/test/java/com/rabbitmq/client/test/functional/ExceptionHandling.java index 8a25798cd3..828d24a774 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExceptionHandling.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExceptionHandling.java @@ -15,6 +15,16 @@ package com.rabbitmq.client.test.functional; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import org.junit.Test; + import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; @@ -25,21 +35,15 @@ import com.rabbitmq.client.ExceptionHandler; import com.rabbitmq.client.impl.DefaultExceptionHandler; import com.rabbitmq.client.impl.ForgivingExceptionHandler; -import junit.framework.TestCase; - -import java.io.IOException; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -public class ExceptionHandling extends TestCase { +public class ExceptionHandling { private ConnectionFactory newConnectionFactory(ExceptionHandler eh) { ConnectionFactory cf = new ConnectionFactory(); cf.setExceptionHandler(eh); return cf; } - public void testDefaultConsumerHandleConsumerException() throws IOException, InterruptedException, TimeoutException { + @Test public void defaultConsumerHandleConsumerException() throws IOException, InterruptedException, TimeoutException { final CountDownLatch latch = new CountDownLatch(1); final ExceptionHandler eh = new DefaultExceptionHandler() { @Override @@ -52,7 +56,7 @@ public void handleConsumerException(Channel channel, Throwable exception, Consum testConsumerHandleConsumerException(eh, latch, true); } - public void testForgivingConsumerHandleConsumerException() throws IOException, InterruptedException, TimeoutException { + @Test public void forgivingConsumerHandleConsumerException() throws IOException, InterruptedException, TimeoutException { final CountDownLatch latch = new CountDownLatch(1); final ExceptionHandler eh = new ForgivingExceptionHandler() { @Override @@ -86,7 +90,7 @@ public void handleDelivery(String consumerTag, Envelope envelope, assertEquals(!expectChannelClose, ch.isOpen()); } - public void testNullExceptionHandler() { + @Test public void nullExceptionHandler() { ConnectionFactory cf = new ConnectionFactory(); try { cf.setExceptionHandler(null); diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExceptionMessages.java b/src/test/java/com/rabbitmq/client/test/functional/ExceptionMessages.java index 27c52f2d50..88b53a8b9a 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExceptionMessages.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExceptionMessages.java @@ -15,14 +15,19 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.AlreadyClosedException; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.io.IOException; import java.util.UUID; +import org.junit.Test; + +import com.rabbitmq.client.AlreadyClosedException; +import com.rabbitmq.client.test.BrokerTestCase; + public class ExceptionMessages extends BrokerTestCase { - public void testAlreadyClosedExceptionMessageWithChannelError() throws IOException { + @Test public void alreadyClosedExceptionMessageWithChannelError() throws IOException { String uuid = UUID.randomUUID().toString(); try { channel.queueDeclarePassive(uuid); @@ -39,7 +44,7 @@ public void testAlreadyClosedExceptionMessageWithChannelError() throws IOExcepti } } - public void testAlreadyClosedExceptionMessageWithCleanClose() throws IOException { + @Test public void alreadyClosedExceptionMessageWithCleanClose() throws IOException { String uuid = UUID.randomUUID().toString(); try { diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java index 3b20d75dfb..95de33b780 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java @@ -16,16 +16,20 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.ConnectionFactory; -import com.rabbitmq.client.BuiltinExchangeType; +import static org.junit.Assert.assertEquals; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeoutException; +import org.junit.Test; + +import com.rabbitmq.client.BuiltinExchangeType; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; + public class ExchangeDeclare extends ExchangeEquivalenceBase { static final String TYPE = "direct"; @@ -36,53 +40,53 @@ public void releaseResources() throws IOException { channel.exchangeDelete(NAME); } - public void testExchangeNoArgsEquivalence() throws IOException { + @Test public void exchangeNoArgsEquivalence() throws IOException { channel.exchangeDeclare(NAME, TYPE, false, false, null); verifyEquivalent(NAME, TYPE, false, false, null); } - public void testSingleLineFeedStrippedFromExchangeName() throws IOException { + @Test public void singleLineFeedStrippedFromExchangeName() throws IOException { channel.exchangeDeclare("exchange_test\n", TYPE, false, false, null); verifyEquivalent(NAME, TYPE, false, false, null); } - public void testMultipleLineFeedsStrippedFromExchangeName() throws IOException { + @Test public void multipleLineFeedsStrippedFromExchangeName() throws IOException { channel.exchangeDeclare("exchange\n_test\n", TYPE, false, false, null); verifyEquivalent(NAME, TYPE, false, false, null); } - public void testMultipleLineFeedAndCarriageReturnsStrippedFromExchangeName() throws IOException { + @Test public void multipleLineFeedAndCarriageReturnsStrippedFromExchangeName() throws IOException { channel.exchangeDeclare("e\nxc\rhange\n\r_test\n\r", TYPE, false, false, null); verifyEquivalent(NAME, TYPE, false, false, null); } - public void testExchangeNonsenseArgsEquivalent() throws IOException { + @Test public void exchangeNonsenseArgsEquivalent() throws IOException { channel.exchangeDeclare(NAME, TYPE, false, false, null); Map args = new HashMap(); args.put("nonsensical-argument-surely-not-in-use", "foo"); verifyEquivalent(NAME, TYPE, false, false, args); } - public void testExchangeDurableNotEquivalent() throws IOException { + @Test public void exchangeDurableNotEquivalent() throws IOException { channel.exchangeDeclare(NAME, TYPE, false, false, null); verifyNotEquivalent(NAME, TYPE, true, false, null); } - public void testExchangeTypeNotEquivalent() throws IOException { + @Test public void exchangeTypeNotEquivalent() throws IOException { channel.exchangeDeclare(NAME, "direct", false, false, null); verifyNotEquivalent(NAME, "fanout", false, false, null); } - public void testExchangeAutoDeleteNotEquivalent() throws IOException { + @Test public void exchangeAutoDeleteNotEquivalent() throws IOException { channel.exchangeDeclare(NAME, "direct", false, false, null); verifyNotEquivalent(NAME, "direct", false, true, null); } - public void testExchangeDeclaredWithEnumerationEquivalentOnNonRecoverableConnection() throws IOException, InterruptedException { + @Test public void exchangeDeclaredWithEnumerationEquivalentOnNonRecoverableConnection() throws IOException, InterruptedException { doTestExchangeDeclaredWithEnumerationEquivalent(channel); } - public void testExchangeDeclaredWithEnumerationEquivalentOnRecoverableConnection() throws IOException, TimeoutException, InterruptedException { + @Test public void exchangeDeclaredWithEnumerationEquivalentOnRecoverableConnection() throws IOException, TimeoutException, InterruptedException { ConnectionFactory connectionFactory = new ConnectionFactory(); connectionFactory.setAutomaticRecoveryEnabled(true); connectionFactory.setTopologyRecoveryEnabled(false); diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java index f5c3defcf5..dab4ebd080 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java @@ -16,9 +16,13 @@ package com.rabbitmq.client.test.functional; +import static org.junit.Assert.fail; + import java.io.IOException; import java.util.concurrent.TimeoutException; +import org.junit.Test; + import com.rabbitmq.client.AMQP; import com.rabbitmq.client.test.BrokerTestCase; @@ -45,7 +49,7 @@ protected void releaseResources() /* Attempt to Exchange.Delete(ifUnused = true) a used exchange. * Should throw an exception. */ - public void testExchangeDelete() { + @Test public void exchangeDelete() { try { channel.exchangeDelete(EXCHANGE_NAME, true); fail("Exception expected if exchange in use"); diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java index 82e4eccbdc..0e8bfcd92a 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java @@ -15,12 +15,14 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.fail; import java.io.IOException; import java.util.Map; +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.test.BrokerTestCase; + public abstract class ExchangeEquivalenceBase extends BrokerTestCase { public void verifyEquivalent(String name, String type, boolean durable, boolean autoDelete, diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java index 64c07c9ddd..739da0c71a 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java @@ -16,12 +16,16 @@ package com.rabbitmq.client.test.functional; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + import java.io.IOException; -import com.rabbitmq.client.AMQP; +import org.junit.Test; + import com.rabbitmq.client.QueueingConsumer; -import com.rabbitmq.client.ShutdownSignalException; import com.rabbitmq.client.QueueingConsumer.Delivery; +import com.rabbitmq.client.ShutdownSignalException; import com.rabbitmq.client.test.BrokerTestCase; public class ExchangeExchangeBindings extends BrokerTestCase { @@ -78,7 +82,7 @@ protected void consumeNoDuplicates(QueueingConsumer consumer) assertEquals(new String(MARKER), new String(markerDelivery.getBody())); } - public void testBindingCreationDeletion() throws IOException { + @Test public void bindingCreationDeletion() throws IOException { channel.exchangeUnbind("e2", "e1", ""); channel.exchangeBind("e2", "e1", ""); channel.exchangeBind("e2", "e1", ""); @@ -93,7 +97,7 @@ public void testBindingCreationDeletion() throws IOException { * add binding (e2 --> e1) * test (e2 --> {q2, q1, q0}) */ - public void testSimpleChains() throws IOException, ShutdownSignalException, + @Test public void simpleChains() throws IOException, ShutdownSignalException, InterruptedException { publishWithMarker("e0", ""); consumeNoDuplicates(consumers[0]); @@ -120,7 +124,7 @@ public void testSimpleChains() throws IOException, ShutdownSignalException, * resulting in: (e1 --> {q1, e0 --> {q0, q1}}) * test (e1 --> {q0, q1}) */ - public void testDuplicateQueueDestinations() throws IOException, + @Test public void duplicateQueueDestinations() throws IOException, ShutdownSignalException, InterruptedException { channel.queueBind("q1", "e0", ""); publishWithMarker("e0", ""); @@ -142,7 +146,7 @@ public void testDuplicateQueueDestinations() throws IOException, * add binding (e0 --> e2) * test (eN --> {q0, q1, q2}) for N in [0..2] */ - public void testExchangeRoutingLoop() throws IOException, + @Test public void exchangeRoutingLoop() throws IOException, ShutdownSignalException, InterruptedException { channel.exchangeBind("e0", "e1", ""); channel.exchangeBind("e1", "e2", ""); @@ -171,7 +175,7 @@ public void testExchangeRoutingLoop() throws IOException, * Then remove the first set of bindings from e --> eN for N in [0..2] * test publish with rk to e */ - public void testTopicExchange() throws IOException, ShutdownSignalException, + @Test public void topicExchange() throws IOException, ShutdownSignalException, InterruptedException { channel.exchangeDeclare("e", "topic"); diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java index 8773f6d29f..baf7a1ce6a 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java @@ -16,8 +16,12 @@ package com.rabbitmq.client.test.functional; +import static org.junit.Assert.fail; + import java.io.IOException; +import org.junit.Test; + import com.rabbitmq.client.AMQP; import com.rabbitmq.client.test.BrokerTestCase; @@ -48,7 +52,7 @@ protected void assertExchangeNotExists(String name) throws IOException { * build (A -> B) and (B -> A) and then delete one binding and both * exchanges should autodelete */ - public void testAutoDeleteExchangesSimpleLoop() throws IOException { + @Test public void autoDeleteExchangesSimpleLoop() throws IOException { String[] exchanges = new String[] {"A", "B"}; declareExchanges(exchanges); channel.exchangeBind("A", "B", ""); @@ -61,7 +65,7 @@ public void testAutoDeleteExchangesSimpleLoop() throws IOException { /* * build (A -> B) (B -> C) (C -> D) and then delete D. All should autodelete */ - public void testTransientAutoDelete() throws IOException { + @Test public void transientAutoDelete() throws IOException { String[] exchanges = new String[] {"A", "B", "C", "D"}; declareExchanges(exchanges); channel.exchangeBind("B", "A", ""); @@ -76,7 +80,7 @@ public void testTransientAutoDelete() throws IOException { * build (A -> B) (B -> C) (C -> D) (Source -> A) (Source -> B) (Source -> * C) (Source -> D) On removal of D, all should autodelete */ - public void testRepeatedTargetAutoDelete() throws IOException { + @Test public void repeatedTargetAutoDelete() throws IOException { String[] exchanges = new String[] {"A", "B", "C", "D"}; declareExchanges(exchanges); channel.exchangeDeclare("Source", "fanout", false, true, null); @@ -102,7 +106,7 @@ public void testRepeatedTargetAutoDelete() throws IOException { /* * build (A -> B) (B -> C) (A -> C). Delete C and they should all vanish */ - public void testAutoDeleteBindingToVanishedExchange() throws IOException { + @Test public void autoDeleteBindingToVanishedExchange() throws IOException { String[] exchanges = new String[] {"A", "B", "C"}; declareExchanges(exchanges); channel.exchangeBind("C", "B", ""); diff --git a/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java b/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java index 757674455d..923681888f 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java +++ b/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java @@ -16,9 +16,7 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.*; -import com.rabbitmq.client.impl.*; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.fail; import java.io.IOException; import java.net.Socket; @@ -26,6 +24,21 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeoutException; +import org.junit.Test; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Address; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.GetResponse; +import com.rabbitmq.client.impl.AMQCommand; +import com.rabbitmq.client.impl.AMQConnection; +import com.rabbitmq.client.impl.Frame; +import com.rabbitmq.client.impl.FrameHandler; +import com.rabbitmq.client.impl.LongStringHelper; +import com.rabbitmq.client.impl.SocketFrameHandler; +import com.rabbitmq.client.test.BrokerTestCase; + public class FrameMax extends BrokerTestCase { /* This value for FrameMax is larger than the minimum and less * than what Rabbit suggests. */ @@ -40,7 +53,7 @@ public FrameMax() { /* Publish a message of size FRAME_MAX. The broker should split * this into two frames before sending back. Frame content should * be less or equal to frame-max - 8. */ - public void testFrameSizes() + @Test public void frameSizes() throws IOException, InterruptedException { String queueName = channel.queueDeclare().getQueue(); @@ -61,7 +74,7 @@ public void testFrameSizes() /* server should reject frames larger than AMQP.FRAME_MIN_SIZE * during connection negotiation */ - public void testRejectLargeFramesDuringConnectionNegotiation() + @Test public void rejectLargeFramesDuringConnectionNegotiation() throws IOException, TimeoutException { ConnectionFactory cf = new ConnectionFactory(); cf.getClientProperties().put("too_long", LongStringHelper.asLongString(new byte[AMQP.FRAME_MIN_SIZE])); @@ -74,7 +87,7 @@ public void testRejectLargeFramesDuringConnectionNegotiation() /* server should reject frames larger than the negotiated frame * size */ - public void testRejectExceedingFrameMax() + @Test public void rejectExceedingFrameMax() throws IOException, TimeoutException { closeChannel(); closeConnection(); diff --git a/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java b/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java index 8c785982bd..e24cd2d039 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java +++ b/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java @@ -19,66 +19,66 @@ import com.rabbitmq.client.impl.WorkPoolTests; import com.rabbitmq.client.test.AbstractRMQTestSuite; import com.rabbitmq.client.test.Bug20004Test; +import com.rabbitmq.client.test.RequiredPropertiesSuite; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; -import junit.framework.TestCase; -import junit.framework.TestSuite; +@RunWith(RequiredPropertiesSuite.class) +@Suite.SuiteClasses({ + ConnectionOpen.class, + Heartbeat.class, + Tables.class, + DoubleDeletion.class, + Routing.class, + BindingLifecycle.class, + Recover.class, + Reject.class, + Transactions.class, + RequeueOnConnectionClose.class, + RequeueOnChannelClose.class, + DurableOnTransient.class, + NoRequeueOnCancel.class, + Bug20004Test.class, + ExchangeDeleteIfUnused.class, + QosTests.class, + AlternateExchange.class, + ExchangeExchangeBindings.class, + ExchangeExchangeBindingsAutoDelete.class, + ExchangeDeclare.class, + FrameMax.class, + QueueLifecycle.class, + QueueLease.class, + QueueExclusivity.class, + QueueSizeLimit.class, + InvalidAcks.class, + InvalidAcksTx.class, + DefaultExchange.class, + UnbindAutoDeleteExchange.class, + Confirm.class, + ConsumerCancelNotification.class, + UnexpectedFrames.class, + PerQueueTTL.class, + PerMessageTTL.class, + PerQueueVsPerMessageTTL.class, + DeadLetterExchange.class, + SaslMechanisms.class, + UserIDHeader.class, + InternalExchange.class, + CcRoutes.class, + WorkPoolTests.class, + HeadersExchangeValidation.class, + ConsumerPriorities.class, + Policies.class, + ConnectionRecovery.class, + ExceptionHandling.class, + PerConsumerPrefetch.class, + DirectReplyTo.class +}) +public class FunctionalTests { -public class FunctionalTests extends AbstractRMQTestSuite { - public static TestSuite suite() { - TestSuite suite = new TestSuite("functional"); - if (!requiredProperties()) return suite; - add(suite); - return suite; - } + // initialize system properties + static{ + new AbstractRMQTestSuite(){}; + } - public static void add(TestSuite suite) { - suite.addTestSuite(ConnectionOpen.class); - suite.addTestSuite(Heartbeat.class); - suite.addTestSuite(Tables.class); - suite.addTestSuite(DoubleDeletion.class); - suite.addTestSuite(Routing.class); - suite.addTestSuite(BindingLifecycle.class); - suite.addTestSuite(Recover.class); - suite.addTestSuite(Reject.class); - suite.addTestSuite(Transactions.class); - suite.addTestSuite(RequeueOnConnectionClose.class); - suite.addTestSuite(RequeueOnChannelClose.class); - suite.addTestSuite(DurableOnTransient.class); - suite.addTestSuite(NoRequeueOnCancel.class); - suite.addTestSuite(Bug20004Test.class); - suite.addTestSuite(ExchangeDeleteIfUnused.class); - suite.addTestSuite(QosTests.class); - suite.addTestSuite(AlternateExchange.class); - suite.addTestSuite(ExchangeExchangeBindings.class); - suite.addTestSuite(ExchangeExchangeBindingsAutoDelete.class); - suite.addTestSuite(ExchangeDeclare.class); - suite.addTestSuite(FrameMax.class); - suite.addTestSuite(QueueLifecycle.class); - suite.addTestSuite(QueueLease.class); - suite.addTestSuite(QueueExclusivity.class); - suite.addTestSuite(QueueSizeLimit.class); - suite.addTestSuite(InvalidAcks.class); - suite.addTestSuite(InvalidAcksTx.class); - suite.addTestSuite(DefaultExchange.class); - suite.addTestSuite(UnbindAutoDeleteExchange.class); - suite.addTestSuite(Confirm.class); - suite.addTestSuite(ConsumerCancelNotification.class); - suite.addTestSuite(UnexpectedFrames.class); - suite.addTestSuite(PerQueueTTL.class); - suite.addTestSuite(PerMessageTTL.class); - suite.addTestSuite(PerQueueVsPerMessageTTL.class); - suite.addTestSuite(DeadLetterExchange.class); - suite.addTestSuite(SaslMechanisms.class); - suite.addTestSuite(UserIDHeader.class); - suite.addTestSuite(InternalExchange.class); - suite.addTestSuite(CcRoutes.class); - suite.addTestSuite(WorkPoolTests.class); - suite.addTestSuite(HeadersExchangeValidation.class); - suite.addTestSuite(ConsumerPriorities.class); - suite.addTestSuite(Policies.class); - suite.addTestSuite(ConnectionRecovery.class); - suite.addTestSuite(ExceptionHandling.class); - suite.addTestSuite(PerConsumerPrefetch.class); - suite.addTestSuite(DirectReplyTo.class); - } } diff --git a/src/test/java/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java b/src/test/java/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java index 7959d88af6..ac28b3ed68 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java +++ b/src/test/java/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java @@ -15,16 +15,20 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.fail; import java.io.IOException; import java.util.HashMap; +import org.junit.Test; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.test.BrokerTestCase; + public class HeadersExchangeValidation extends BrokerTestCase { - public void testHeadersValidation() throws IOException + @Test public void headersValidation() throws IOException { AMQP.Queue.DeclareOk ok = channel.queueDeclare(); String queue = ok.getQueue(); diff --git a/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java b/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java index 67e63886c5..8ea14bce25 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java @@ -16,8 +16,14 @@ package com.rabbitmq.client.test.functional; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + import java.io.IOException; +import org.junit.Test; + import com.rabbitmq.client.impl.AMQConnection; import com.rabbitmq.client.test.BrokerTestCase; @@ -29,7 +35,7 @@ public Heartbeat() connectionFactory.setRequestedHeartbeat(1); } - public void testHeartbeat() + @Test public void heartbeat() throws IOException, InterruptedException { assertEquals(1, connection.getHeartbeat()); diff --git a/src/test/java/com/rabbitmq/client/test/functional/InternalExchange.java b/src/test/java/com/rabbitmq/client/test/functional/InternalExchange.java index a4091820c5..97b34bfdba 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/InternalExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/InternalExchange.java @@ -16,9 +16,13 @@ package com.rabbitmq.client.test.functional; +import static org.junit.Assert.assertTrue; + import java.io.IOException; import java.util.Arrays; +import org.junit.Test; + import com.rabbitmq.client.AMQP; import com.rabbitmq.client.GetResponse; import com.rabbitmq.client.test.BrokerTestCase; @@ -69,7 +73,7 @@ protected void createResources() throws IOException } - public void testTryPublishingToInternalExchange() + @Test public void tryPublishingToInternalExchange() throws IOException { byte[] testDataBody = "test-data".getBytes(); diff --git a/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksBase.java b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksBase.java index 18f4764272..e71404a268 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksBase.java +++ b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksBase.java @@ -20,6 +20,8 @@ import java.io.IOException; +import org.junit.Test; + /** * See bug 21846: * Basic.Ack is now required to signal a channel error immediately upon @@ -31,7 +33,7 @@ public abstract class InvalidAcksBase extends BrokerTestCase { protected abstract void select() throws IOException; protected abstract void commit() throws IOException; - public void testDoubleAck() + @Test public void doubleAck() throws IOException { select(); @@ -46,7 +48,7 @@ public void testDoubleAck() expectError(AMQP.PRECONDITION_FAILED); } - public void testCrazyAck() + @Test public void crazyAck() throws IOException { select(); diff --git a/src/test/java/com/rabbitmq/client/test/functional/MessageCount.java b/src/test/java/com/rabbitmq/client/test/functional/MessageCount.java index bced38a762..9820e6aa68 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/MessageCount.java +++ b/src/test/java/com/rabbitmq/client/test/functional/MessageCount.java @@ -15,12 +15,16 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.assertEquals; import java.io.IOException; +import org.junit.Test; + +import com.rabbitmq.client.test.BrokerTestCase; + public class MessageCount extends BrokerTestCase { - public void testMessageCount() throws IOException { + @Test public void messageCount() throws IOException { String q = generateQueueName(); channel.queueDeclare(q, false, true, false, null); assertEquals(0, channel.messageCount(q)); diff --git a/src/test/java/com/rabbitmq/client/test/functional/Nack.java b/src/test/java/com/rabbitmq/client/test/functional/Nack.java index 983355b2ea..65057cb363 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Nack.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Nack.java @@ -16,15 +16,20 @@ package com.rabbitmq.client.test.functional; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + import java.util.HashSet; import java.util.Set; +import org.junit.Test; + import com.rabbitmq.client.AMQP; import com.rabbitmq.client.QueueingConsumer; public class Nack extends AbstractRejectTest { - public void testSingleNack() throws Exception { + @Test public void singleNack() throws Exception { String q = channel.queueDeclare("", false, true, false, null).getQueue(); @@ -56,7 +61,7 @@ public void testSingleNack() throws Exception { expectError(AMQP.PRECONDITION_FAILED); } - public void testMultiNack() throws Exception { + @Test public void multiNack() throws Exception { String q = channel.queueDeclare("", false, true, false, null).getQueue(); @@ -98,7 +103,7 @@ public void testMultiNack() throws Exception { expectError(AMQP.PRECONDITION_FAILED); } - public void testNackAll() throws Exception { + @Test public void nackAll() throws Exception { String q = channel.queueDeclare("", false, true, false, null).getQueue(); diff --git a/src/test/java/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java b/src/test/java/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java index e6b91ccb8b..4e5fc0770a 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java +++ b/src/test/java/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java @@ -16,10 +16,15 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + import java.io.IOException; +import org.junit.Test; + import com.rabbitmq.client.QueueingConsumer; +import com.rabbitmq.client.test.BrokerTestCase; public class NoRequeueOnCancel extends BrokerTestCase { @@ -33,7 +38,7 @@ protected void releaseResources() throws IOException { channel.queueDelete(Q); } - public void testNoRequeueOnCancel() + @Test public void noRequeueOnCancel() throws IOException, InterruptedException { channel.basicPublish("", Q, null, "1".getBytes()); diff --git a/src/test/java/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java b/src/test/java/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java index 9c7c4de68e..31dd63f3a0 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java +++ b/src/test/java/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java @@ -15,16 +15,18 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.GetResponse; -import com.rabbitmq.client.QueueingConsumer; -import com.rabbitmq.client.QueueingConsumer.Delivery; -import com.rabbitmq.client.test.BrokerTestCase; +import static com.rabbitmq.client.test.functional.QosTests.drain; import java.io.IOException; import java.util.Arrays; import java.util.List; -import static com.rabbitmq.client.test.functional.QosTests.drain; +import org.junit.Test; + +import com.rabbitmq.client.GetResponse; +import com.rabbitmq.client.QueueingConsumer; +import com.rabbitmq.client.QueueingConsumer.Delivery; +import com.rabbitmq.client.test.BrokerTestCase; public class PerConsumerPrefetch extends BrokerTestCase { private String q; @@ -38,7 +40,7 @@ private interface Closure { public void makeMore(List deliveries) throws IOException; } - public void testSingleAck() throws IOException { + @Test public void singleAck() throws IOException { testPrefetch(new Closure() { public void makeMore(List deliveries) throws IOException { for (Delivery del : deliveries) { @@ -48,7 +50,7 @@ public void makeMore(List deliveries) throws IOException { }); } - public void testMultiAck() throws IOException { + @Test public void multiAck() throws IOException { testPrefetch(new Closure() { public void makeMore(List deliveries) throws IOException { ack(deliveries.get(deliveries.size() - 1), true); @@ -56,7 +58,7 @@ public void makeMore(List deliveries) throws IOException { }); } - public void testSingleNack() throws IOException { + @Test public void singleNack() throws IOException { for (final boolean requeue: Arrays.asList(false, true)) { testPrefetch(new Closure() { public void makeMore(List deliveries) throws IOException { @@ -68,7 +70,7 @@ public void makeMore(List deliveries) throws IOException { } } - public void testMultiNack() throws IOException { + @Test public void multiNack() throws IOException { for (final boolean requeue: Arrays.asList(false, true)) { testPrefetch(new Closure() { public void makeMore(List deliveries) throws IOException { @@ -78,7 +80,7 @@ public void makeMore(List deliveries) throws IOException { } } - public void testRecover() throws IOException { + @Test public void recover() throws IOException { testPrefetch(new Closure() { public void makeMore(List deliveries) throws IOException { channel.basicRecover(); @@ -99,7 +101,7 @@ private void testPrefetch(Closure closure) throws IOException { drain(c, 5); } - public void testPrefetchOnEmpty() throws IOException { + @Test public void prefetchOnEmpty() throws IOException { QueueingConsumer c = new QueueingConsumer(channel); publish(q, 5); consume(c, 10, false); @@ -108,14 +110,14 @@ public void testPrefetchOnEmpty() throws IOException { drain(c, 5); } - public void testAutoAckIgnoresPrefetch() throws IOException { + @Test public void autoAckIgnoresPrefetch() throws IOException { QueueingConsumer c = new QueueingConsumer(channel); publish(q, 10); consume(c, 1, true); drain(c, 10); } - public void testPrefetchZeroMeansInfinity() throws IOException { + @Test public void prefetchZeroMeansInfinity() throws IOException { QueueingConsumer c = new QueueingConsumer(channel); publish(q, 10); consume(c, 0, false); diff --git a/src/test/java/com/rabbitmq/client/test/functional/PerMessageTTL.java b/src/test/java/com/rabbitmq/client/test/functional/PerMessageTTL.java index a0fbb8898a..00a3adc98d 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/PerMessageTTL.java +++ b/src/test/java/com/rabbitmq/client/test/functional/PerMessageTTL.java @@ -16,12 +16,17 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.QueueingConsumer; -import com.rabbitmq.client.MessageProperties; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import java.io.IOException; +import org.junit.Test; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.MessageProperties; +import com.rabbitmq.client.QueueingConsumer; + public class PerMessageTTL extends TTLHandling { protected Object sessionTTL; @@ -41,7 +46,7 @@ protected AMQP.Queue.DeclareOk declareQueue(String name, Object ttlValue) throws return this.channel.queueDeclare(name, false, true, false, null); } - public void testExpiryWhenConsumerIsLateToTheParty() throws Exception { + @Test public void expiryWhenConsumerIsLateToTheParty() throws Exception { declareAndBindQueue(500); publish(MSG[0]); @@ -57,7 +62,7 @@ public void testExpiryWhenConsumerIsLateToTheParty() throws Exception { assertNull("Message should have been expired!!", c.nextDelivery(100)); } - public void testRestartingExpiry() throws Exception { + @Test public void restartingExpiry() throws Exception { final String expiryDelay = "2000"; declareDurableQueue(TTL_QUEUE_NAME); bindQueue(); diff --git a/src/test/java/com/rabbitmq/client/test/functional/PerQueueTTL.java b/src/test/java/com/rabbitmq/client/test/functional/PerQueueTTL.java index 138965f3eb..8a221e2bb6 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/PerQueueTTL.java +++ b/src/test/java/com/rabbitmq/client/test/functional/PerQueueTTL.java @@ -16,13 +16,17 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.MessageProperties; +import static org.junit.Assert.fail; import java.io.IOException; import java.util.Collections; import java.util.Map; +import org.junit.Test; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.MessageProperties; + public class PerQueueTTL extends TTLHandling { protected static final String TTL_ARG = "x-message-ttl"; @@ -33,7 +37,7 @@ protected AMQP.Queue.DeclareOk declareQueue(String name, Object ttlValue) throws return this.channel.queueDeclare(name, false, true, false, argMap); } - public void testQueueReDeclareEquivalence() throws Exception { + @Test public void queueReDeclareEquivalence() throws Exception { declareQueue(10); try { declareQueue(20); @@ -43,14 +47,14 @@ public void testQueueReDeclareEquivalence() throws Exception { } } - public void testQueueReDeclareSemanticEquivalence() throws Exception { + @Test public void queueReDeclareSemanticEquivalence() throws Exception { declareQueue((byte)10); declareQueue(10); declareQueue((short)10); declareQueue(10L); } - public void testQueueReDeclareSemanticNonEquivalence() throws Exception { + @Test public void queueReDeclareSemanticNonEquivalence() throws Exception { declareQueue(10); try { declareQueue(10.0); diff --git a/src/test/java/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java b/src/test/java/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java index 64b01b6dfa..b586c98c5d 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java +++ b/src/test/java/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java @@ -15,15 +15,19 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.AMQP; +import static org.junit.Assert.assertNull; import java.io.IOException; import java.util.Collections; import java.util.Map; +import org.junit.Test; + +import com.rabbitmq.client.AMQP; + public class PerQueueVsPerMessageTTL extends PerMessageTTL { - public void testSmallerPerQueueExpiryWins() throws IOException, InterruptedException { + @Test public void smallerPerQueueExpiryWins() throws IOException, InterruptedException { declareAndBindQueue(10); this.sessionTTL = 1000; diff --git a/src/test/java/com/rabbitmq/client/test/functional/Policies.java b/src/test/java/com/rabbitmq/client/test/functional/Policies.java index f1ae122d1c..f1dba4d33d 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Policies.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Policies.java @@ -15,11 +15,9 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.GetResponse; -import com.rabbitmq.client.test.BrokerTestCase; -import com.rabbitmq.client.test.server.HATests; -import com.rabbitmq.tools.Host; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import java.io.IOException; import java.util.HashMap; @@ -27,6 +25,14 @@ import java.util.Map; import java.util.Set; +import org.junit.Test; + +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.GetResponse; +import com.rabbitmq.client.test.BrokerTestCase; +import com.rabbitmq.client.test.server.HATests; +import com.rabbitmq.tools.Host; + public class Policies extends BrokerTestCase { private static final int DELAY = 100; // MILLIS @@ -42,7 +48,7 @@ public class Policies extends BrokerTestCase { channel.exchangeDeclare("has-ae-args", "fanout", false, false, args); } - public void testAlternateExchange() throws IOException, InterruptedException { + @Test public void alternateExchange() throws IOException, InterruptedException { String q = declareQueue(); channel.exchangeDeclare("ae", "fanout", false, true, null); channel.queueBind(q, "ae", ""); @@ -55,7 +61,7 @@ public void testAlternateExchange() throws IOException, InterruptedException { } // i.e. the argument takes priority over the policy - public void testAlternateExchangeArgs() throws IOException { + @Test public void alternateExchangeArgs() throws IOException { String q = declareQueue(); channel.exchangeDeclare("ae2", "fanout", false, true, null); channel.queueBind(q, "ae2", ""); @@ -63,7 +69,7 @@ public void testAlternateExchangeArgs() throws IOException { assertDelivered(q, 1); } - public void testDeadLetterExchange() throws IOException, InterruptedException { + @Test public void deadLetterExchange() throws IOException, InterruptedException { Map args = ttlArgs(0); String src = declareQueue("has-dlx", args); String dest = declareQueue(); @@ -81,7 +87,7 @@ public void testDeadLetterExchange() throws IOException, InterruptedException { } // again the argument takes priority over the policy - public void testDeadLetterExchangeArgs() throws IOException, InterruptedException { + @Test public void deadLetterExchangeArgs() throws IOException, InterruptedException { Map args = ttlArgs(0); args.put("x-dead-letter-exchange", "dlx2"); args.put("x-dead-letter-routing-key", "rk2"); @@ -95,7 +101,7 @@ public void testDeadLetterExchangeArgs() throws IOException, InterruptedExceptio assertEquals("rk2", resp.getEnvelope().getRoutingKey()); } - public void testTTL() throws IOException, InterruptedException { + @Test public void tTL() throws IOException, InterruptedException { String q = declareQueue("has-ttl", null); basicPublishVolatile(q); Thread.sleep(2 * DELAY); @@ -108,7 +114,7 @@ public void testTTL() throws IOException, InterruptedException { } // Test that we get lower of args and policy - public void testTTLArgs() throws IOException, InterruptedException { + @Test public void tTLArgs() throws IOException, InterruptedException { String q = declareQueue("has-ttl", ttlArgs(3 * DELAY)); basicPublishVolatile(q); Thread.sleep(2 * DELAY); @@ -123,7 +129,7 @@ public void testTTLArgs() throws IOException, InterruptedException { assertDelivered(q, 0); } - public void testExpires() throws IOException, InterruptedException { + @Test public void expires() throws IOException, InterruptedException { String q = declareQueue("has-expires", null); Thread.sleep(2 * DELAY); assertFalse(queueExists(q)); @@ -135,7 +141,7 @@ public void testExpires() throws IOException, InterruptedException { } // Test that we get lower of args and policy - public void testExpiresArgs() throws IOException, InterruptedException { + @Test public void expiresArgs() throws IOException, InterruptedException { String q = declareQueue("has-expires", args("x-expires", 3 * DELAY)); Thread.sleep(2 * DELAY); assertFalse(queueExists(q)); @@ -146,7 +152,7 @@ public void testExpiresArgs() throws IOException, InterruptedException { assertTrue(queueExists(q)); } - public void testMaxLength() throws IOException, InterruptedException { + @Test public void maxLength() throws IOException, InterruptedException { String q = declareQueue("has-max-length", null); basicPublishVolatileN(q, 3); assertDelivered(q, 1); @@ -156,7 +162,7 @@ public void testMaxLength() throws IOException, InterruptedException { assertDelivered(q, 3); } - public void testMaxLengthArgs() throws IOException, InterruptedException { + @Test public void maxLengthArgs() throws IOException, InterruptedException { String q = declareQueue("has-max-length", args("x-max-length", 2)); basicPublishVolatileN(q, 3); assertDelivered(q, 1); diff --git a/src/test/java/com/rabbitmq/client/test/functional/QosTests.java b/src/test/java/com/rabbitmq/client/test/functional/QosTests.java index dbf3b8cba0..637df3c894 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QosTests.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QosTests.java @@ -16,7 +16,11 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; @@ -27,23 +31,26 @@ import java.util.Map; import java.util.concurrent.TimeoutException; +import org.junit.Test; + import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Envelope; import com.rabbitmq.client.GetResponse; import com.rabbitmq.client.QueueingConsumer; import com.rabbitmq.client.QueueingConsumer.Delivery; +import com.rabbitmq.client.test.BrokerTestCase; public class QosTests extends BrokerTestCase { - protected void setUp() + public void setUp() throws IOException, TimeoutException { openConnection(); openChannel(); } - protected void tearDown() + public void tearDown() throws IOException { closeChannel(); @@ -83,7 +90,7 @@ public static List drain(QueueingConsumer c, int n) return res; } - public void testMessageLimitPrefetchSizeFails() + @Test public void messageLimitPrefetchSizeFails() throws IOException { try { @@ -94,7 +101,7 @@ public void testMessageLimitPrefetchSizeFails() } } - public void testMessageLimitUnlimited() + @Test public void messageLimitUnlimited() throws IOException { QueueingConsumer c = new QueueingConsumer(channel); @@ -102,7 +109,7 @@ public void testMessageLimitUnlimited() drain(c, 2); } - public void testNoAckNoAlterLimit() + @Test public void noAckNoAlterLimit() throws IOException { QueueingConsumer c = new QueueingConsumer(channel); @@ -112,7 +119,7 @@ public void testNoAckNoAlterLimit() drain(c, 2); } - public void testNoAckObeysLimit() + @Test public void noAckObeysLimit() throws IOException { channel.basicQos(1, true); @@ -135,7 +142,7 @@ public void testNoAckObeysLimit() drain(c2, 1); } - public void testPermutations() + @Test public void permutations() throws IOException { closeChannel(); @@ -152,7 +159,7 @@ public void testPermutations() } } - public void testFairness() + @Test public void fairness() throws IOException { QueueingConsumer c = new QueueingConsumer(channel); @@ -181,7 +188,7 @@ public void testFairness() } - public void testSingleChannelAndQueueFairness() + @Test public void singleChannelAndQueueFairness() throws IOException { //check that when we have multiple consumers on the same @@ -230,7 +237,7 @@ public void testSingleChannelAndQueueFairness() assertTrue(counts.get("c2").intValue() > 0); } - public void testConsumerLifecycle() + @Test public void consumerLifecycle() throws IOException { channel.basicQos(1, true); @@ -251,7 +258,7 @@ public void testConsumerLifecycle() channel.queueDelete(queue); } - public void testSetLimitAfterConsume() + @Test public void setLimitAfterConsume() throws IOException { QueueingConsumer c = new QueueingConsumer(channel); @@ -266,7 +273,7 @@ public void testSetLimitAfterConsume() drain(c, 1); } - public void testLimitIncrease() + @Test public void limitIncrease() throws IOException { QueueingConsumer c = new QueueingConsumer(channel); @@ -275,7 +282,7 @@ public void testLimitIncrease() drain(c, 1); } - public void testLimitDecrease() + @Test public void limitDecrease() throws IOException { QueueingConsumer c = new QueueingConsumer(channel); @@ -286,7 +293,7 @@ public void testLimitDecrease() drain(c, 1); } - public void testLimitedToUnlimited() + @Test public void limitedToUnlimited() throws IOException { QueueingConsumer c = new QueueingConsumer(channel); @@ -295,7 +302,7 @@ public void testLimitedToUnlimited() drain(c, 2); } - public void testLimitingMultipleChannels() + @Test public void limitingMultipleChannels() throws IOException { Channel ch1 = connection.createChannel(); @@ -319,7 +326,7 @@ public void testLimitingMultipleChannels() ch2.abort(); } - public void testLimitInheritsUnackedCount() + @Test public void limitInheritsUnackedCount() throws IOException { QueueingConsumer c = new QueueingConsumer(channel); @@ -331,7 +338,7 @@ public void testLimitInheritsUnackedCount() drain(c, 1); } - public void testRecoverReducesLimit() throws Exception { + @Test public void recoverReducesLimit() throws Exception { channel.basicQos(2, true); QueueingConsumer c = new QueueingConsumer(channel); declareBindConsume(c); diff --git a/src/test/java/com/rabbitmq/client/test/functional/QueueExclusivity.java b/src/test/java/com/rabbitmq/client/test/functional/QueueExclusivity.java index dcc994ce84..5d7f84663a 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QueueExclusivity.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QueueExclusivity.java @@ -16,10 +16,14 @@ package com.rabbitmq.client.test.functional; +import static org.junit.Assert.fail; + import java.io.IOException; import java.util.HashMap; import java.util.concurrent.TimeoutException; +import org.junit.Test; + import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; @@ -49,7 +53,7 @@ protected void releaseResources() throws IOException { } } - public void testQueueExclusiveForPassiveDeclare() throws Exception { + @Test public void queueExclusiveForPassiveDeclare() throws Exception { try { channel.queueDeclarePassive(q); } catch (IOException ioe) { @@ -61,7 +65,7 @@ public void testQueueExclusiveForPassiveDeclare() throws Exception { // This is a different scenario because active declare takes notice of // the all the arguments - public void testQueueExclusiveForDeclare() throws Exception { + @Test public void queueExclusiveForDeclare() throws Exception { try { channel.queueDeclare(q, false, true, false, noArgs); } catch (IOException ioe) { @@ -71,7 +75,7 @@ public void testQueueExclusiveForDeclare() throws Exception { fail("Active queue declaration of an exclusive queue from another connection should fail"); } - public void testQueueExclusiveForConsume() throws Exception { + @Test public void queueExclusiveForConsume() throws Exception { QueueingConsumer c = new QueueingConsumer(channel); try { channel.basicConsume(q, c); @@ -82,7 +86,7 @@ public void testQueueExclusiveForConsume() throws Exception { fail("Exclusive queue should be locked for basic consume from another connection"); } - public void testQueueExclusiveForPurge() throws Exception { + @Test public void queueExclusiveForPurge() throws Exception { try { channel.queuePurge(q); } catch (IOException ioe) { @@ -92,7 +96,7 @@ public void testQueueExclusiveForPurge() throws Exception { fail("Exclusive queue should be locked for queue purge from another connection"); } - public void testQueueExclusiveForDelete() throws Exception { + @Test public void queueExclusiveForDelete() throws Exception { try { channel.queueDelete(q); } catch (IOException ioe) { @@ -102,7 +106,7 @@ public void testQueueExclusiveForDelete() throws Exception { fail("Exclusive queue should be locked for queue delete from another connection"); } - public void testQueueExclusiveForBind() throws Exception { + @Test public void queueExclusiveForBind() throws Exception { try { channel.queueBind(q, "amq.direct", ""); } catch (IOException ioe) { @@ -119,7 +123,7 @@ public void testQueueExclusiveForBind() throws Exception { // basic.cancel is inherently local to a channel, so it // *doesn't* make sense to include it. - public void testQueueExclusiveForUnbind() throws Exception { + @Test public void queueExclusiveForUnbind() throws Exception { altChannel.queueBind(q, "amq.direct", ""); try { channel.queueUnbind(q, "amq.direct", ""); @@ -130,7 +134,7 @@ public void testQueueExclusiveForUnbind() throws Exception { fail("Exclusive queue should be locked for queue unbind from another connection"); } - public void testQueueExclusiveForGet() throws Exception { + @Test public void queueExclusiveForGet() throws Exception { try { channel.basicGet(q, true); } catch (IOException ioe) { diff --git a/src/test/java/com/rabbitmq/client/test/functional/QueueLease.java b/src/test/java/com/rabbitmq/client/test/functional/QueueLease.java index 284869acda..b5ab03a48d 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QueueLease.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QueueLease.java @@ -16,10 +16,14 @@ package com.rabbitmq.client.test.functional; +import static org.junit.Assert.fail; + import java.io.IOException; import java.util.HashMap; import java.util.Map; +import org.junit.Test; + import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Consumer; import com.rabbitmq.client.DefaultConsumer; @@ -40,19 +44,19 @@ public class QueueLease extends BrokerTestCase { * Verify that a queue with the 'x-expires` flag is actually deleted within * a sensible period of time after expiry. */ - public void testQueueExpires() throws IOException, InterruptedException { + @Test public void queueExpires() throws IOException, InterruptedException { verifyQueueExpires(TEST_EXPIRE_QUEUE, true); } /** * Verify that the server does not delete normal queues... ;) */ - public void testDoesNotExpireOthers() throws IOException, + @Test public void doesNotExpireOthers() throws IOException, InterruptedException { verifyQueueExpires(TEST_NORMAL_QUEUE, false); } - public void testExpireMayBeByte() throws IOException { + @Test public void expireMayBeByte() throws IOException { Map args = new HashMap(); args.put("x-expires", (byte)100); @@ -63,7 +67,7 @@ public void testExpireMayBeByte() throws IOException { } } - public void testExpireMayBeShort() throws IOException { + @Test public void expireMayBeShort() throws IOException { Map args = new HashMap(); args.put("x-expires", (short)100); @@ -74,7 +78,7 @@ public void testExpireMayBeShort() throws IOException { } } - public void testExpireMayBeLong() throws IOException { + @Test public void expireMayBeLong() throws IOException { Map args = new HashMap(); args.put("x-expires", 100L); @@ -85,7 +89,7 @@ public void testExpireMayBeLong() throws IOException { } } - public void testExpireMustBeGtZero() throws IOException { + @Test public void expireMustBeGtZero() throws IOException { Map args = new HashMap(); args.put("x-expires", 0); @@ -98,7 +102,7 @@ public void testExpireMustBeGtZero() throws IOException { } } - public void testExpireMustBePositive() throws IOException { + @Test public void expireMustBePositive() throws IOException { Map args = new HashMap(); args.put("x-expires", -10); @@ -115,7 +119,7 @@ public void testExpireMustBePositive() throws IOException { * Verify that the server throws an error if the client redeclares a queue * with mismatching 'x-expires' values. */ - public void testQueueRedeclareEquivalence() throws IOException { + @Test public void queueRedeclareEquivalence() throws IOException { Map args1 = new HashMap(); args1.put("x-expires", 10000); Map args2 = new HashMap(); @@ -133,7 +137,7 @@ public void testQueueRedeclareEquivalence() throws IOException { } } - public void testActiveQueueDeclareExtendsLease() + @Test public void activeQueueDeclareExtendsLease() throws InterruptedException, IOException { Map args = new HashMap(); args.put("x-expires", QUEUE_EXPIRES); @@ -156,7 +160,7 @@ public void testActiveQueueDeclareExtendsLease() } } - public void testPassiveQueueDeclareExtendsLease() + @Test public void passiveQueueDeclareExtendsLease() throws InterruptedException, IOException { Map args = new HashMap(); args.put("x-expires", QUEUE_EXPIRES); @@ -179,7 +183,7 @@ public void testPassiveQueueDeclareExtendsLease() } } - public void testExpiresWithConsumers() + @Test public void expiresWithConsumers() throws InterruptedException, IOException { Map args = new HashMap(); args.put("x-expires", QUEUE_EXPIRES); diff --git a/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java b/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java index 625b4d0374..7de96205b3 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java @@ -16,15 +16,19 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.QueueingConsumer; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.fail; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeoutException; +import org.junit.Test; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.QueueingConsumer; +import com.rabbitmq.client.test.BrokerTestCase; + /** * Test queue auto-delete and exclusive semantics. */ @@ -86,7 +90,7 @@ void verifyNotEquivalent(boolean durable, boolean exclusive, * Declare-Ok if the requested queue matches these fields, and MUST * raise a channel exception if not." */ - public void testQueueEquivalence() throws IOException { + @Test public void queueEquivalence() throws IOException { String q = "queue"; channel.queueDeclare(q, false, false, false, null); // equivalent @@ -101,22 +105,22 @@ public void testQueueEquivalence() throws IOException { } // not equivalent in various ways - public void testQueueNonEquivalenceDurable() throws IOException { + @Test public void queueNonEquivalenceDurable() throws IOException { verifyNotEquivalent(true, false, false); } - public void testQueueNonEquivalenceExclusive() throws IOException { + @Test public void queueNonEquivalenceExclusive() throws IOException { verifyNotEquivalent(false, true, false); } - public void testQueueNonEquivalenceAutoDelete() throws IOException { + @Test public void queueNonEquivalenceAutoDelete() throws IOException { verifyNotEquivalent(false, false, true); } // Note that this assumes that auto-deletion is synchronous with // basic.cancel, // which is not actually in the spec. (If it isn't, there's a race here). - public void testQueueAutoDelete() throws IOException { + @Test public void queueAutoDelete() throws IOException { String name = "tempqueue"; channel.queueDeclare(name, false, false, true, null); // now it's there @@ -134,7 +138,7 @@ public void testQueueAutoDelete() throws IOException { fail("Queue should have been auto-deleted after we removed its only consumer"); } - public void testExclusiveNotAutoDelete() throws IOException { + @Test public void exclusiveNotAutoDelete() throws IOException { String name = "exclusivequeue"; channel.queueDeclare(name, false, true, false, null); // now it's there @@ -146,7 +150,7 @@ public void testExclusiveNotAutoDelete() throws IOException { verifyQueueExists(name); } - public void testExclusiveGoesWithConnection() throws IOException, TimeoutException { + @Test public void exclusiveGoesWithConnection() throws IOException, TimeoutException { String name = "exclusivequeue2"; channel.queueDeclare(name, false, true, false, null); // now it's there @@ -157,7 +161,7 @@ public void testExclusiveGoesWithConnection() throws IOException, TimeoutExcepti verifyQueueMissing(name); } - public void testArgumentArrays() throws IOException { + @Test public void argumentArrays() throws IOException { Map args = new HashMap(); String[] arr = new String[]{"foo", "bar", "baz"}; args.put("my-key", arr); @@ -166,7 +170,7 @@ public void testArgumentArrays() throws IOException { verifyQueue(queueName, true, true, false, args); } - public void testQueueNamesLongerThan255Characters() throws IOException { + @Test public void queueNamesLongerThan255Characters() throws IOException { String q = new String(new byte[300]).replace('\u0000', 'x'); try { channel.queueDeclare(q, false, false, false, null); @@ -176,17 +180,17 @@ public void testQueueNamesLongerThan255Characters() throws IOException { } } - public void testSingleLineFeedStrippedFromQueueName() throws IOException { + @Test public void singleLineFeedStrippedFromQueueName() throws IOException { channel.queueDeclare("que\nue_test", false, false, true, null); verifyQueue(NAME_STRIPPED, false, false, true, null); } - public void testMultipleLineFeedsStrippedFromQueueName() throws IOException { + @Test public void multipleLineFeedsStrippedFromQueueName() throws IOException { channel.queueDeclare("que\nue_\ntest\n", false, false, true, null); verifyQueue(NAME_STRIPPED, false, false, true, null); } - public void testMultipleLineFeedAndCarriageReturnsStrippedFromQueueName() throws IOException { + @Test public void multipleLineFeedAndCarriageReturnsStrippedFromQueueName() throws IOException { channel.queueDeclare("q\ru\ne\r\nue_\ntest\n\r", false, false, true, null); verifyQueue(NAME_STRIPPED, false, false, true, null); } diff --git a/src/test/java/com/rabbitmq/client/test/functional/QueueSizeLimit.java b/src/test/java/com/rabbitmq/client/test/functional/QueueSizeLimit.java index 411c040a78..7bec3e47c2 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QueueSizeLimit.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QueueSizeLimit.java @@ -16,14 +16,21 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.GetResponse; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import org.junit.Test; + +import com.rabbitmq.client.GetResponse; +import com.rabbitmq.client.test.BrokerTestCase; + /** * Test queue max length limit. */ @@ -32,7 +39,7 @@ public class QueueSizeLimit extends BrokerTestCase { private final int MAXMAXLENGTH = 3; private final String q = "queue-maxlength"; - public void testQueueSize() throws IOException, InterruptedException { + @Test public void queueSize() throws IOException, InterruptedException { for (int maxLen = 0; maxLen <= MAXMAXLENGTH; maxLen ++){ setupNonDlxTest(maxLen, false); assertHead(maxLen, "msg2", q); @@ -40,7 +47,7 @@ public void testQueueSize() throws IOException, InterruptedException { } } - public void testQueueSizeUnacked() throws IOException, InterruptedException { + @Test public void queueSizeUnacked() throws IOException, InterruptedException { for (int maxLen = 0; maxLen <= MAXMAXLENGTH; maxLen ++){ setupNonDlxTest(maxLen, true); assertHead(maxLen > 0 ? 1 : 0, "msg" + (maxLen + 1), q); @@ -48,7 +55,7 @@ public void testQueueSizeUnacked() throws IOException, InterruptedException { } } - public void testQueueSizeDlx() throws IOException, InterruptedException { + @Test public void queueSizeDlx() throws IOException, InterruptedException { for (int maxLen = 0; maxLen <= MAXMAXLENGTH; maxLen ++){ setupDlxTest(maxLen, false); assertHead(1, "msg1", "DLQ"); @@ -57,7 +64,7 @@ public void testQueueSizeDlx() throws IOException, InterruptedException { } } - public void testQueueSizeUnackedDlx() throws IOException, InterruptedException { + @Test public void queueSizeUnackedDlx() throws IOException, InterruptedException { for (int maxLen = 0; maxLen <= MAXMAXLENGTH; maxLen ++){ setupDlxTest(maxLen, true); assertHead(maxLen > 0 ? 0 : 1, "msg1", "DLQ"); @@ -66,7 +73,7 @@ public void testQueueSizeUnackedDlx() throws IOException, InterruptedException } } - public void testRequeue() throws IOException, InterruptedException { + @Test public void requeue() throws IOException, InterruptedException { for (int maxLen = 1; maxLen <= MAXMAXLENGTH; maxLen ++) { declareQueue(maxLen, false); setupRequeueTest(maxLen); @@ -75,7 +82,7 @@ public void testRequeue() throws IOException, InterruptedException { } } - public void testRequeueWithDlx() throws IOException, InterruptedException { + @Test public void requeueWithDlx() throws IOException, InterruptedException { for (int maxLen = 1; maxLen <= MAXMAXLENGTH; maxLen ++) { declareQueue(maxLen, true); setupRequeueTest(maxLen); diff --git a/src/test/java/com/rabbitmq/client/test/functional/Recover.java b/src/test/java/com/rabbitmq/client/test/functional/Recover.java index e54f4591f4..bb1e858c83 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Recover.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Recover.java @@ -16,15 +16,19 @@ package com.rabbitmq.client.test.functional; -import java.util.Arrays; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + import java.io.IOException; +import java.util.Arrays; + +import org.junit.Test; import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.QueueingConsumer; import com.rabbitmq.client.Channel; -import com.rabbitmq.client.Command; -import com.rabbitmq.client.ShutdownSignalException; - +import com.rabbitmq.client.QueueingConsumer; import com.rabbitmq.client.test.BrokerTestCase; public class Recover extends BrokerTestCase { @@ -85,21 +89,21 @@ public void recover(Channel channel) throws IOException { } }; - public void testRedeliveryOnRecover() throws IOException, InterruptedException { + @Test public void redeliveryOnRecover() throws IOException, InterruptedException { verifyRedeliverOnRecover(recoverSync); } - public void testRedeliverOnRecoverConvenience() + @Test public void redeliverOnRecoverConvenience() throws IOException, InterruptedException { verifyRedeliverOnRecover(recoverSyncConvenience); } - public void testNoRedeliveryWithAutoAck() + @Test public void noRedeliveryWithAutoAck() throws IOException, InterruptedException { verifyNoRedeliveryWithAutoAck(recoverSync); } - public void testRequeueFalseNotSupported() throws Exception { + @Test public void requeueFalseNotSupported() throws Exception { try { channel.basicRecover(false); fail("basicRecover(false) should not be supported"); diff --git a/src/test/java/com/rabbitmq/client/test/functional/Reject.java b/src/test/java/com/rabbitmq/client/test/functional/Reject.java index 7f3ebb80f9..0a99111137 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Reject.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Reject.java @@ -16,14 +16,18 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.QueueingConsumer; +import static org.junit.Assert.assertNull; import java.io.IOException; +import org.junit.Test; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.QueueingConsumer; + public class Reject extends AbstractRejectTest { - public void testReject() + @Test public void reject() throws IOException, InterruptedException { String q = channel.queueDeclare("", false, true, false, null).getQueue(); diff --git a/src/test/java/com/rabbitmq/client/test/functional/RequeueOnClose.java b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnClose.java index 60bdb6d163..35150997a8 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/RequeueOnClose.java +++ b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnClose.java @@ -15,6 +15,10 @@ package com.rabbitmq.client.test.functional; +import static org.junit.Assert.*; +import org.junit.Test; + + import com.rabbitmq.client.test.BrokerTestCase; import java.io.IOException; import java.util.concurrent.CountDownLatch; @@ -42,13 +46,13 @@ public abstract class RequeueOnClose protected abstract void close() throws IOException; - protected void setUp() + public void setUp() throws IOException { // Override to disable the default behaviour from BrokerTestCase. } - protected void tearDown() + public void tearDown() throws IOException { // Override to disable the default behaviour from BrokerTestCase. @@ -93,7 +97,7 @@ private void publishAndGet(int count, boolean doAck) * Test we don't requeue acknowledged messages (using get) * @throws Exception untested */ - public void testNormal() throws Exception + @Test public void normal() throws Exception { publishAndGet(3, true); } @@ -102,7 +106,7 @@ public void testNormal() throws Exception * Test we requeue unacknowledged messages (using get) * @throws Exception untested */ - public void testRequeueing() throws Exception + @Test public void requeueing() throws Exception { publishAndGet(3, false); } @@ -111,7 +115,7 @@ public void testRequeueing() throws Exception * Test we requeue unacknowledged message (using consumer) * @throws Exception untested */ - public void testRequeueingConsumer() throws Exception + @Test public void requeueingConsumer() throws Exception { openConnection(); open(); @@ -155,7 +159,7 @@ private void publishLotsAndGet() * Test close while consuming many messages successfully requeues unacknowledged messages * @throws Exception untested */ - public void testRequeueInFlight() throws Exception + @Test public void requeueInFlight() throws Exception { for (int i = 0; i < 5; i++) { publishLotsAndGet(); @@ -166,7 +170,7 @@ public void testRequeueInFlight() throws Exception * Test close while consuming partially not acked with cancel successfully requeues unacknowledged messages * @throws Exception untested */ - public void testRequeueInFlightConsumerNoAck() throws Exception + @Test public void requeueInFlightConsumerNoAck() throws Exception { for (int i = 0; i < 5; i++) { publishLotsAndConsumeSome(false, true); @@ -177,7 +181,7 @@ public void testRequeueInFlightConsumerNoAck() throws Exception * Test close while consuming partially acked with cancel successfully requeues unacknowledged messages * @throws Exception untested */ - public void testRequeueInFlightConsumerAck() throws Exception + @Test public void requeueInFlightConsumerAck() throws Exception { for (int i = 0; i < 5; i++) { publishLotsAndConsumeSome(true, true); @@ -188,7 +192,7 @@ public void testRequeueInFlightConsumerAck() throws Exception * Test close while consuming partially not acked without cancel successfully requeues unacknowledged messages * @throws Exception untested */ - public void testRequeueInFlightConsumerNoAckNoCancel() throws Exception + @Test public void requeueInFlightConsumerNoAckNoCancel() throws Exception { for (int i = 0; i < 5; i++) { publishLotsAndConsumeSome(false, false); @@ -199,7 +203,7 @@ public void testRequeueInFlightConsumerNoAckNoCancel() throws Exception * Test close while consuming partially acked without cancel successfully requeues unacknowledged messages * @throws Exception untested */ - public void testRequeueInFlightConsumerAckNoCancel() throws Exception + @Test public void requeueInFlightConsumerAckNoCancel() throws Exception { for (int i = 0; i < 5; i++) { publishLotsAndConsumeSome(true, false); diff --git a/src/test/java/com/rabbitmq/client/test/functional/Routing.java b/src/test/java/com/rabbitmq/client/test/functional/Routing.java index a10fc6e3ee..f4efdab194 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Routing.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Routing.java @@ -16,20 +16,27 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.AlreadyClosedException; -import com.rabbitmq.client.test.BrokerTestCase; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.GetResponse; -import com.rabbitmq.client.ReturnListener; -import com.rabbitmq.utility.BlockingCell; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; import java.io.IOException; -import java.util.List; import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.TimeoutException; +import org.junit.Test; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.AlreadyClosedException; +import com.rabbitmq.client.GetResponse; +import com.rabbitmq.client.ReturnListener; +import com.rabbitmq.client.test.BrokerTestCase; +import com.rabbitmq.utility.BlockingCell; + public class Routing extends BrokerTestCase { @@ -81,7 +88,7 @@ private void checkGet(String queue, boolean messageExpected) * of the spec. See the doc for the "queue" and "routing key" * fields of queue.bind. */ - public void testMRDQRouting() + @Test public void mRDQRouting() throws IOException { bind(Q1, "baz"); //Q1, "baz" @@ -99,7 +106,7 @@ public void testMRDQRouting() * NOT receive duplicate copies of a message that matches both * bindings. */ - public void testDoubleBinding() + @Test public void doubleBinding() throws IOException { channel.queueBind(Q1, "amq.topic", "x.#"); @@ -115,7 +122,7 @@ public void testDoubleBinding() checkGet(Q1, false); } - public void testFanoutRouting() throws Exception { + @Test public void fanoutRouting() throws Exception { List queues = new ArrayList(); @@ -138,7 +145,7 @@ public void testFanoutRouting() throws Exception { } } - public void testTopicRouting() throws Exception { + @Test public void topicRouting() throws Exception { List queues = new ArrayList(); @@ -158,7 +165,7 @@ public void testTopicRouting() throws Exception { } } - public void testHeadersRouting() throws Exception { + @Test public void headersRouting() throws Exception { Map spec = new HashMap(); spec.put("h1", "12345"); spec.put("h2", "bar"); @@ -233,7 +240,7 @@ public void testHeadersRouting() throws Exception { checkGet(Q2, false); } - public void testBasicReturn() throws IOException { + @Test public void basicReturn() throws IOException { channel.addReturnListener(makeReturnListener()); returnCell = new BlockingCell(); @@ -257,7 +264,7 @@ public void testBasicReturn() throws IOException { } } - public void testBasicReturnTransactional() throws IOException { + @Test public void basicReturnTransactional() throws IOException { channel.txSelect(); channel.addReturnListener(makeReturnListener()); returnCell = new BlockingCell(); diff --git a/src/test/java/com/rabbitmq/client/test/functional/SaslMechanisms.java b/src/test/java/com/rabbitmq/client/test/functional/SaslMechanisms.java index 2946e73537..ae12330eba 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/SaslMechanisms.java +++ b/src/test/java/com/rabbitmq/client/test/functional/SaslMechanisms.java @@ -15,6 +15,15 @@ package com.rabbitmq.client.test.functional; +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Map; +import java.util.concurrent.TimeoutException; + +import org.junit.Test; + import com.rabbitmq.client.AuthenticationFailureException; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; @@ -26,11 +35,6 @@ import com.rabbitmq.client.impl.LongStringHelper; import com.rabbitmq.client.test.BrokerTestCase; -import java.io.IOException; -import java.util.Arrays; -import java.util.Map; -import java.util.concurrent.TimeoutException; - public class SaslMechanisms extends BrokerTestCase { private String[] mechanisms; @@ -69,19 +73,19 @@ public SaslMechanism getSaslMechanism(String[] mechanisms) { } } - public void testPlainLogin() throws IOException, TimeoutException { + @Test public void plainLogin() throws IOException, TimeoutException { loginOk("PLAIN", new byte[][] {"\0guest\0guest".getBytes()} ); loginBad("PLAIN", new byte[][] {"\0guest\0wrong".getBytes()} ); } - public void testAMQPlainLogin() throws IOException, TimeoutException { + @Test public void aMQPlainLogin() throws IOException, TimeoutException { // guest / guest loginOk("AMQPLAIN", new byte[][] {{5,76,79,71,73,78,83,0,0,0,5,103,117,101,115,116,8,80,65,83,83,87,79,82,68,83,0,0,0,5,103,117,101,115,116}} ); // guest / wrong loginBad("AMQPLAIN", new byte[][] {{5,76,79,71,73,78,83,0,0,0,5,103,117,101,115,116,8,80,65,83,83,87,79,82,68,83,0,0,0,5,119,114,111,110,103}} ); } - public void testCRLogin() throws IOException, TimeoutException { + @Test public void cRLogin() throws IOException, TimeoutException { // Make sure mechanisms is populated loginOk("PLAIN", new byte[][] {"\0guest\0guest".getBytes()} ); @@ -92,11 +96,11 @@ public void testCRLogin() throws IOException, TimeoutException { } } - public void testConnectionCloseAuthFailureUsername() throws IOException, TimeoutException { + @Test public void connectionCloseAuthFailureUsername() throws IOException, TimeoutException { connectionCloseAuthFailure("incorrect-username", "incorrect-password"); } - public void testConnectionCloseAuthFailurePassword() throws IOException, TimeoutException { + @Test public void connectionCloseAuthFailurePassword() throws IOException, TimeoutException { connectionCloseAuthFailure(connectionFactory.getUsername(), "incorrect-password"); } diff --git a/src/test/java/com/rabbitmq/client/test/functional/TTLHandling.java b/src/test/java/com/rabbitmq/client/test/functional/TTLHandling.java index 83e139de3f..e60c89c255 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/TTLHandling.java +++ b/src/test/java/com/rabbitmq/client/test/functional/TTLHandling.java @@ -15,13 +15,20 @@ package com.rabbitmq.client.test.functional; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; + +import java.io.IOException; + +import org.junit.Test; + import com.rabbitmq.client.AMQP; import com.rabbitmq.client.GetResponse; import com.rabbitmq.client.QueueingConsumer; import com.rabbitmq.client.test.BrokerTestCase; -import java.io.IOException; - public abstract class TTLHandling extends BrokerTestCase { protected static final String TTL_EXCHANGE = "ttl.exchange"; @@ -40,7 +47,7 @@ protected void releaseResources() throws IOException { this.channel.exchangeDelete(TTL_EXCHANGE); } - public void testMultipleTTLTypes() throws IOException { + @Test public void multipleTTLTypes() throws IOException { final Object[] args = { (((byte)200) & (0xff)), (short)200, 200, 200L }; for (Object ttl : args) { try { @@ -53,7 +60,7 @@ public void testMultipleTTLTypes() throws IOException { } } - public void testInvalidTypeUsedInTTL() throws Exception { + @Test public void invalidTypeUsedInTTL() throws Exception { try { declareAndBindQueue("foobar"); publishAndSync(MSG[0]); @@ -63,7 +70,7 @@ public void testInvalidTypeUsedInTTL() throws Exception { } } - public void testTrailingCharsUsedInTTL() throws Exception { + @Test public void trailingCharsUsedInTTL() throws Exception { try { declareAndBindQueue("10000foobar"); publishAndSync(MSG[0]); @@ -73,7 +80,7 @@ public void testTrailingCharsUsedInTTL() throws Exception { } } - public void testTTLMustBePositive() throws Exception { + @Test public void tTLMustBePositive() throws Exception { try { declareAndBindQueue(-10); publishAndSync(MSG[0]); @@ -83,7 +90,7 @@ public void testTTLMustBePositive() throws Exception { } } - public void testTTLAllowZero() throws Exception { + @Test public void tTLAllowZero() throws Exception { try { declareQueue(0); publishAndSync(MSG[0]); @@ -92,7 +99,7 @@ public void testTTLAllowZero() throws Exception { } } - public void testMessagesExpireWhenUsingBasicGet() throws Exception { + @Test public void messagesExpireWhenUsingBasicGet() throws Exception { declareAndBindQueue(200); publish(MSG[0]); Thread.sleep(1000); @@ -101,7 +108,7 @@ public void testMessagesExpireWhenUsingBasicGet() throws Exception { assertNull("expected message " + what + " to have been removed", what); } - public void testPublishAndGetWithExpiry() throws Exception { + @Test public void publishAndGetWithExpiry() throws Exception { declareAndBindQueue(200); publish(MSG[0]); @@ -117,7 +124,7 @@ public void testPublishAndGetWithExpiry() throws Exception { assertNull(get()); } - public void testTransactionalPublishWithGet() throws Exception { + @Test public void transactionalPublishWithGet() throws Exception { declareAndBindQueue(100); this.channel.txSelect(); @@ -135,7 +142,7 @@ public void testTransactionalPublishWithGet() throws Exception { assertNull(get()); } - public void testExpiryWithRequeue() throws Exception { + @Test public void expiryWithRequeue() throws Exception { declareAndBindQueue(200); publish(MSG[0]); @@ -157,7 +164,7 @@ public void testExpiryWithRequeue() throws Exception { /* * Test expiry of re-queued messages after being consumed instantly */ - public void testExpiryWithReQueueAfterConsume() throws Exception { + @Test public void expiryWithReQueueAfterConsume() throws Exception { declareAndBindQueue(100); QueueingConsumer c = new QueueingConsumer(channel); channel.basicConsume(TTL_QUEUE_NAME, c); @@ -172,7 +179,7 @@ public void testExpiryWithReQueueAfterConsume() throws Exception { assertNull("Re-queued message not expired", get()); } - public void testZeroTTLDelivery() throws Exception { + @Test public void zeroTTLDelivery() throws Exception { declareAndBindQueue(0); // when there is no consumer, message should expire diff --git a/src/test/java/com/rabbitmq/client/test/functional/Tables.java b/src/test/java/com/rabbitmq/client/test/functional/Tables.java index 0e72ea11e6..73d98cd014 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Tables.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Tables.java @@ -16,25 +16,30 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.test.BrokerTestCase; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.impl.LongStringHelper; -import com.rabbitmq.client.AMQP.BasicProperties; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import java.io.IOException; +import java.math.BigDecimal; +import java.util.ArrayList; import java.util.Arrays; -import java.util.Map; -import java.util.List; +import java.util.HashMap; import java.util.Iterator; -import java.util.ArrayList; +import java.util.List; +import java.util.Map; import java.util.Set; -import java.util.HashMap; -import java.math.BigDecimal; + +import org.junit.Test; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.AMQP.BasicProperties; +import com.rabbitmq.client.impl.LongStringHelper; +import com.rabbitmq.client.test.BrokerTestCase; public class Tables extends BrokerTestCase { - public void testTypes() throws IOException { + @Test public void types() throws IOException { Map table = new HashMap(); Map subTable = new HashMap(); diff --git a/src/test/java/com/rabbitmq/client/test/functional/Transactions.java b/src/test/java/com/rabbitmq/client/test/functional/Transactions.java index 5276be217e..ff677dde35 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Transactions.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Transactions.java @@ -16,12 +16,18 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; + import java.io.IOException; import java.util.concurrent.TimeoutException; +import org.junit.Test; + +import com.rabbitmq.client.AMQP; import com.rabbitmq.client.GetResponse; +import com.rabbitmq.client.test.BrokerTestCase; public class Transactions extends BrokerTestCase { @@ -108,7 +114,7 @@ private long[] publishSelectAndGet(int n) /* publishes are embargoed until commit */ - public void testCommitPublish() + @Test public void commitPublish() throws IOException { txSelect(); @@ -122,7 +128,7 @@ public void testCommitPublish() /* rollback rolls back publishes */ - public void testRollbackPublish() + @Test public void rollbackPublish() throws IOException { txSelect(); @@ -134,7 +140,7 @@ public void testRollbackPublish() /* closing a channel rolls back publishes */ - public void testRollbackPublishOnClose() + @Test public void rollbackPublishOnClose() throws IOException { txSelect(); @@ -147,7 +153,7 @@ public void testRollbackPublishOnClose() /* closing a channel requeues both ack'ed and un-ack'ed messages */ - public void testRequeueOnClose() + @Test public void requeueOnClose() throws IOException { basicPublish(); @@ -168,7 +174,7 @@ public void testRequeueOnClose() messages with committed acks are not requeued on channel close, messages that weren't ack'ed are requeued on close, but not before then. */ - public void testCommitAcks() + @Test public void commitAcks() throws IOException { basicPublish(); @@ -188,7 +194,7 @@ public void testCommitAcks() /* */ - public void testCommitAcksOutOfOrder() + @Test public void commitAcksOutOfOrder() throws IOException { long tags[] = publishSelectAndGet(4); @@ -203,7 +209,7 @@ public void testCommitAcksOutOfOrder() rollback rolls back acks and a rolled back ack can be re-issued */ - public void testRollbackAcksAndReAck() + @Test public void rollbackAcksAndReAck() throws IOException { basicPublish(); @@ -222,7 +228,7 @@ public void testRollbackAcksAndReAck() /* it is illegal to ack with an unknown delivery tag */ - public void testUnknownTagAck() + @Test public void unknownTagAck() throws IOException { basicPublish(); @@ -238,7 +244,7 @@ public void testUnknownTagAck() /* rollback does not requeue delivered ack'ed or un-ack'ed messages */ - public void testNoRequeueOnRollback() + @Test public void noRequeueOnRollback() throws IOException { basicPublish(); @@ -254,7 +260,7 @@ public void testNoRequeueOnRollback() /* auto-acks are not part of tx */ - public void testAutoAck() + @Test public void autoAck() throws IOException { basicPublish(); @@ -268,7 +274,7 @@ public void testAutoAck() /* "ack all", once committed, acks all delivered messages */ - public void testAckAll() + @Test public void ackAll() throws IOException { basicPublish(); @@ -283,7 +289,7 @@ public void testAckAll() assertNull(basicGet()); } - public void testNonTransactedCommit() + @Test public void nonTransactedCommit() throws IOException { try { @@ -294,7 +300,7 @@ public void testNonTransactedCommit() } } - public void testNonTransactedRollback() + @Test public void nonTransactedRollback() throws IOException { try { @@ -305,7 +311,7 @@ public void testNonTransactedRollback() } } - public void testRedeliverAckedUncommitted() + @Test public void redeliverAckedUncommitted() throws IOException { txSelect(); @@ -322,7 +328,7 @@ public void testRedeliverAckedUncommitted() basicGet(true)); } - public void testCommitWithDeletedQueue() + @Test public void commitWithDeletedQueue() throws IOException, TimeoutException { txSelect(); basicPublish(); @@ -339,7 +345,7 @@ public void testCommitWithDeletedQueue() } } - public void testShuffleAcksBeforeRollback() + @Test public void shuffleAcksBeforeRollback() throws IOException { long tags[] = publishSelectAndGet(3); @@ -432,37 +438,37 @@ public void commitAcksAndNacks(NackMethod method) assertNull(basicGet()); } - public void testCommitNacks() + @Test public void commitNacks() throws IOException { commitNacks(basicNack); } - public void testRollbackNacks() + @Test public void rollbackNacks() throws IOException { rollbackNacks(basicNack); } - public void testCommitAcksAndNacks() + @Test public void commitAcksAndNacks() throws IOException { commitAcksAndNacks(basicNack); } - public void testCommitRejects() + @Test public void commitRejects() throws IOException { commitNacks(basicReject); } - public void testRollbackRejects() + @Test public void rollbackRejects() throws IOException { rollbackNacks(basicReject); } - public void testCommitAcksAndRejects() + @Test public void commitAcksAndRejects() throws IOException { commitAcksAndNacks(basicReject); diff --git a/src/test/java/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java b/src/test/java/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java index 6678c6c0c2..cb9491a6e7 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java @@ -15,17 +15,21 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.fail; import java.io.IOException; +import org.junit.Test; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.test.BrokerTestCase; + /** * Test that unbinding from an auto-delete exchange causes the exchange to go * away */ public class UnbindAutoDeleteExchange extends BrokerTestCase { - public void testUnbind() throws IOException, InterruptedException { + @Test public void unbind() throws IOException, InterruptedException { String exchange = "myexchange"; channel.exchangeDeclare(exchange, "fanout", false, true, null); String queue = channel.queueDeclare().getQueue(); diff --git a/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java b/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java index b79caf2e00..3c236c1ef5 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java +++ b/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java @@ -18,6 +18,10 @@ import java.io.IOException; import java.net.Socket; +import javax.net.SocketFactory; + +import org.junit.Test; + import com.rabbitmq.client.AMQP; import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.DefaultSocketConfigurator; @@ -28,8 +32,6 @@ import com.rabbitmq.client.impl.SocketFrameHandler; import com.rabbitmq.client.test.BrokerTestCase; -import javax.net.SocketFactory; - /** * Test that the server correctly handles us when we send it bad frames */ @@ -90,7 +92,7 @@ public UnexpectedFrames() { connectionFactory = new ConfusedConnectionFactory(); } - public void testMissingHeader() throws IOException { + @Test public void missingHeader() throws IOException { expectUnexpectedFrameError(new Confuser() { public Frame confuse(Frame frame) { if (frame.type == AMQP.FRAME_HEADER) { @@ -101,7 +103,7 @@ public Frame confuse(Frame frame) { }); } - public void testMissingMethod() throws IOException { + @Test public void missingMethod() throws IOException { expectUnexpectedFrameError(new Confuser() { public Frame confuse(Frame frame) { if (frame.type == AMQP.FRAME_METHOD) { @@ -115,7 +117,7 @@ public Frame confuse(Frame frame) { }); } - public void testMissingBody() throws IOException { + @Test public void missingBody() throws IOException { expectUnexpectedFrameError(new Confuser() { public Frame confuse(Frame frame) { if (frame.type == AMQP.FRAME_BODY) { @@ -126,7 +128,7 @@ public Frame confuse(Frame frame) { }); } - public void testWrongClassInHeader() throws IOException { + @Test public void wrongClassInHeader() throws IOException { expectUnexpectedFrameError(new Confuser() { public Frame confuse(Frame frame) { if (frame.type == AMQP.FRAME_HEADER) { @@ -144,7 +146,7 @@ public Frame confuse(Frame frame) { }); } - public void testHeartbeatOnChannel() throws IOException { + @Test public void heartbeatOnChannel() throws IOException { expectUnexpectedFrameError(new Confuser() { public Frame confuse(Frame frame) { if (frame.type == AMQP.FRAME_METHOD) { @@ -155,7 +157,7 @@ public Frame confuse(Frame frame) { }); } - public void testUnknownFrameType() throws IOException { + @Test public void unknownFrameType() throws IOException { expectError(AMQP.FRAME_ERROR, new Confuser() { public Frame confuse(Frame frame) { if (frame.type == AMQP.FRAME_METHOD) { diff --git a/src/test/java/com/rabbitmq/client/test/functional/UserIDHeader.java b/src/test/java/com/rabbitmq/client/test/functional/UserIDHeader.java index ad5ba89ff4..e31bb64bb1 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/UserIDHeader.java +++ b/src/test/java/com/rabbitmq/client/test/functional/UserIDHeader.java @@ -15,23 +15,27 @@ package com.rabbitmq.client.test.functional; +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.util.concurrent.TimeoutException; + +import org.junit.Test; + import com.rabbitmq.client.AMQP; import com.rabbitmq.client.AlreadyClosedException; import com.rabbitmq.client.test.BrokerTestCase; import com.rabbitmq.tools.Host; -import java.io.IOException; -import java.util.concurrent.TimeoutException; - public class UserIDHeader extends BrokerTestCase { private static final AMQP.BasicProperties GOOD = new AMQP.BasicProperties.Builder().userId("guest").build(); private static final AMQP.BasicProperties BAD = new AMQP.BasicProperties.Builder().userId("not the guest, honest").build(); - public void testValidUserId() throws IOException { + @Test public void validUserId() throws IOException { publish(GOOD); } - public void testInvalidUserId() { + @Test public void invalidUserId() { try { publish(BAD); fail("Accepted publish with incorrect user ID"); @@ -42,7 +46,7 @@ public void testInvalidUserId() { } } - public void testImpersonatedUserId() throws IOException, TimeoutException { + @Test public void impersonatedUserId() throws IOException, TimeoutException { Host.rabbitmqctl("set_user_tags guest administrator impersonator"); connection = null; channel = null; diff --git a/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java b/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java index 628aa77be2..9f22b14210 100644 --- a/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java +++ b/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java @@ -16,9 +16,14 @@ package com.rabbitmq.client.test.server; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.fail; + import java.io.IOException; import java.util.concurrent.TimeoutException; +import org.junit.Test; + import com.rabbitmq.client.AMQP; import com.rabbitmq.client.test.functional.ClusteredTestBase; @@ -30,13 +35,13 @@ public class AbsentQueue extends ClusteredTestBase { private static final String Q = "absent-queue"; - @Override protected void setUp() throws IOException, TimeoutException { + @Override public void setUp() throws IOException, TimeoutException { super.setUp(); if (clusteredConnection != null) stopSecondary(); } - @Override protected void tearDown() throws IOException, TimeoutException { + @Override public void tearDown() throws IOException, TimeoutException { if (clusteredConnection != null) startSecondary(); super.tearDown(); @@ -50,7 +55,7 @@ public class AbsentQueue extends ClusteredTestBase { alternateChannel.queueDelete(Q); } - public void testNotFound() throws IOException { + @Test public void notFound() throws IOException { assertNotFound(new Task() { public void run() throws IOException { channel.queueDeclare(Q, true, false, false, null); diff --git a/src/test/java/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java b/src/test/java/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java index d2eae1bc79..213240039d 100644 --- a/src/test/java/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java +++ b/src/test/java/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java @@ -16,9 +16,11 @@ package com.rabbitmq.client.test.server; -import java.util.Map; -import java.util.HashMap; import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.junit.Test; import com.rabbitmq.client.test.functional.ExchangeEquivalenceBase; @@ -28,12 +30,12 @@ public class AlternateExchangeEquivalence extends ExchangeEquivalenceBase { args.put("alternate-exchange", "UME"); } - public void testAlternateExchangeEquivalence() throws IOException { + @Test public void alternateExchangeEquivalence() throws IOException { channel.exchangeDeclare("alternate", "direct", false, false, args); verifyEquivalent("alternate", "direct", false, false, args); } - public void testAlternateExchangeNonEquivalence() throws IOException { + @Test public void alternateExchangeNonEquivalence() throws IOException { channel.exchangeDeclare("alternate", "direct", false, false, args); Map altargs = new HashMap(); altargs.put("alternate-exchange", "somewhere"); diff --git a/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java b/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java index 2850c2f46a..1fa60169fc 100644 --- a/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java @@ -16,11 +16,15 @@ package com.rabbitmq.client.test.server; +import static org.junit.Assert.assertTrue; + import java.io.IOException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import org.junit.Test; + import com.rabbitmq.client.BlockedListener; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; @@ -38,7 +42,7 @@ protected void releaseResources() throws IOException { } // this test first opens a connection, then triggers // and alarm and blocks - public void testBlock() throws Exception { + @Test public void testBlock() throws Exception { final CountDownLatch latch = new CountDownLatch(1); Connection connection = connection(latch); @@ -50,7 +54,7 @@ public void testBlock() throws Exception { // this test first triggers an alarm, then opens a // connection - public void testInitialBlock() throws Exception { + @Test public void initialBlock() throws Exception { final CountDownLatch latch = new CountDownLatch(1); block(); diff --git a/src/test/java/com/rabbitmq/client/test/server/Bug19219Test.java b/src/test/java/com/rabbitmq/client/test/server/Bug19219Test.java index fb7b6801c2..f048252728 100644 --- a/src/test/java/com/rabbitmq/client/test/server/Bug19219Test.java +++ b/src/test/java/com/rabbitmq/client/test/server/Bug19219Test.java @@ -15,12 +15,14 @@ package com.rabbitmq.client.test.server; +import static org.junit.Assert.assertTrue; + import java.io.IOException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeoutException; -import junit.framework.TestSuite; +import org.junit.Test; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; @@ -55,12 +57,6 @@ public class Bug19219Test extends BrokerTestCase { private static final Semaphore init = new Semaphore(0); private static final CountDownLatch resume = new CountDownLatch(1); - public static TestSuite suite() { - TestSuite suite = new TestSuite("Bug19219"); - suite.addTestSuite(Bug19219Test.class); - return suite; - } - private static void publish(final Channel ch) throws IOException { ch.basicPublish("amq.fanout", "", @@ -68,7 +64,7 @@ private static void publish(final Channel ch) new byte[0]); } - public void testIt() throws IOException, InterruptedException { + @Test public void it() throws IOException, InterruptedException { final Consumer c = new DefaultConsumer(channel); diff --git a/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java b/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java index d6f887b2a3..3aa4c5ba78 100644 --- a/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java +++ b/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java @@ -15,6 +15,18 @@ package com.rabbitmq.client.test.server; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.util.concurrent.Executors; + +import javax.net.SocketFactory; + +import org.junit.Test; + import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; @@ -22,15 +34,11 @@ import com.rabbitmq.client.ShutdownSignalException; import com.rabbitmq.client.impl.AMQConnection; import com.rabbitmq.client.impl.ChannelN; -import com.rabbitmq.client.impl.SocketFrameHandler; import com.rabbitmq.client.impl.ConsumerWorkService; +import com.rabbitmq.client.impl.SocketFrameHandler; import com.rabbitmq.client.test.BrokerTestCase; import com.rabbitmq.tools.Host; -import javax.net.SocketFactory; -import java.io.IOException; -import java.util.concurrent.Executors; - public class ChannelLimitNegotiation extends BrokerTestCase { class SpecialConnection extends AMQConnection { private final int channelMax; @@ -53,7 +61,7 @@ protected int negotiateChannelMax(int requestedChannelMax, int serverMax) { } } - public void testChannelMaxLowerThanServerMinimum() throws Exception { + @Test public void channelMaxLowerThanServerMinimum() throws Exception { int n = 64; ConnectionFactory cf = new ConnectionFactory(); cf.setRequestedChannelMax(n); @@ -62,7 +70,7 @@ public void testChannelMaxLowerThanServerMinimum() throws Exception { assertEquals(n, conn.getChannelMax()); } - public void testChannelMaxGreaterThanServerValue() throws Exception { + @Test public void channelMaxGreaterThanServerValue() throws Exception { try { Host.rabbitmqctl("eval 'application:set_env(rabbit, channel_max, 2048).'"); @@ -78,7 +86,7 @@ public void testChannelMaxGreaterThanServerValue() throws Exception { } } - public void testOpeningTooManyChannels() throws Exception { + @Test public void openingTooManyChannels() throws Exception { int n = 48; try { diff --git a/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java b/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java index 5c1c65d939..3973521128 100644 --- a/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java +++ b/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java @@ -15,15 +15,19 @@ package com.rabbitmq.client.test.server; -import com.rabbitmq.client.MessageProperties; -import com.rabbitmq.client.test.BrokerTestCase; -import com.rabbitmq.client.test.functional.DeadLetterExchange; -import com.rabbitmq.tools.Host; +import static org.junit.Assert.assertNull; import java.io.IOException; import java.util.HashMap; import java.util.Map; +import org.junit.Test; + +import com.rabbitmq.client.MessageProperties; +import com.rabbitmq.client.test.BrokerTestCase; +import com.rabbitmq.client.test.functional.DeadLetterExchange; +import com.rabbitmq.tools.Host; + public class DeadLetterExchangeDurable extends BrokerTestCase { @Override protected void createResources() throws IOException { @@ -45,7 +49,7 @@ protected void releaseResources() throws IOException { channel.queueDelete(DeadLetterExchange.TEST_QUEUE_NAME); } - public void testDeadLetterQueueTTLExpiredWhileDown() throws Exception { + @Test public void deadLetterQueueTTLExpiredWhileDown() throws Exception { // This test is nonsensical (and often breaks) in HA mode. if (HATests.HA_TESTS_RUNNING) return; diff --git a/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java b/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java index f484d1f49e..4c4b6fd910 100644 --- a/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java +++ b/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java @@ -16,15 +16,18 @@ package com.rabbitmq.client.test.server; -import com.rabbitmq.client.GetResponse; - -import com.rabbitmq.client.test.functional.BindingLifecycleBase; - -import com.rabbitmq.tools.Host; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import java.io.IOException; import java.util.concurrent.TimeoutException; +import org.junit.Test; + +import com.rabbitmq.client.GetResponse; +import com.rabbitmq.client.test.functional.BindingLifecycleBase; +import com.rabbitmq.tools.Host; + /** * This tests whether bindings are created and nuked properly. * @@ -64,7 +67,7 @@ private void restartPrimary() throws IOException, TimeoutException { /** * Tests whether durable bindings are correctly recovered. */ - public void testDurableBindingRecovery() throws IOException, TimeoutException { + @Test public void durableBindingRecovery() throws IOException, TimeoutException { declareDurableTopicExchange(X); declareAndBindDurableQueue(Q, X, K); @@ -97,7 +100,7 @@ public void testDurableBindingRecovery() throws IOException, TimeoutException { * main difference is that the broker has to be restarted to * verify that the durable routes have been turfed. */ - public void testDurableBindingsDeletion() throws IOException, TimeoutException { + @Test public void durableBindingsDeletion() throws IOException, TimeoutException { declareDurableTopicExchange(X); declareAndBindDurableQueue(Q, X, K); @@ -126,7 +129,7 @@ public void testDurableBindingsDeletion() throws IOException, TimeoutException { * The idea is to create a durable queue, nuke the server and then * publish a message to it using the queue name as a routing key */ - public void testDefaultBindingRecovery() throws IOException, TimeoutException { + @Test public void defaultBindingRecovery() throws IOException, TimeoutException { declareDurableQueue(Q); restart(); @@ -144,7 +147,7 @@ public void testDefaultBindingRecovery() throws IOException, TimeoutException { * queue and the durable queue is on a cluster node that restarts, * we do not lose the binding. See bug 24009. */ - public void testTransientExchangeDurableQueue() throws IOException, TimeoutException { + @Test public void transientExchangeDurableQueue() throws IOException, TimeoutException { // This test depends on the second node in the cluster to keep // the transient X alive if (clusteredConnection != null) { diff --git a/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java b/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java index 10ccf71495..78b2291781 100644 --- a/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java +++ b/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java @@ -15,10 +15,14 @@ package com.rabbitmq.client.test.server; -import com.rabbitmq.client.test.functional.ClusteredTestBase; +import static org.junit.Assert.assertEquals; import java.io.IOException; +import org.junit.Test; + +import com.rabbitmq.client.test.functional.ClusteredTestBase; + /** * From bug 19844 - we want to be sure that publish vs everything else can't * happen out of order @@ -47,7 +51,7 @@ protected void releaseResources() throws IOException { private static final byte[] msg = "".getBytes(); - public void testEffectVisibility() throws Exception { + @Test public void effectVisibility() throws Exception { for (int i = 0; i < BATCHES; i++) { for (int j = 0; j < MESSAGES_PER_BATCH; j++) { diff --git a/src/test/java/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java b/src/test/java/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java index 7c6fbafa98..b5a8c6d4dc 100644 --- a/src/test/java/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java +++ b/src/test/java/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java @@ -16,9 +16,13 @@ package com.rabbitmq.client.test.server; +import static org.junit.Assert.fail; + import java.io.IOException; import java.util.concurrent.TimeoutException; +import org.junit.Test; + import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; import com.rabbitmq.client.test.BrokerTestCase; @@ -41,7 +45,7 @@ void verifyQueueMissing(Channel channel, String queueName) // 1) connection and queue are on same node, node restarts -> queue // should no longer exist - public void testConnectionQueueSameNode() throws Exception { + @Test public void connectionQueueSameNode() throws Exception { channel.queueDeclare("scenario1", true, true, false, null); restartPrimaryAbruptly(); verifyQueueMissing(channel, "scenario1"); diff --git a/src/test/java/com/rabbitmq/client/test/server/Firehose.java b/src/test/java/com/rabbitmq/client/test/server/Firehose.java index 7a2c3329fe..c1c95ab8a4 100644 --- a/src/test/java/com/rabbitmq/client/test/server/Firehose.java +++ b/src/test/java/com/rabbitmq/client/test/server/Firehose.java @@ -15,15 +15,20 @@ package com.rabbitmq.client.test.server; -import com.rabbitmq.client.GetResponse; -import com.rabbitmq.client.test.BrokerTestCase; -import com.rabbitmq.tools.Host; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import java.io.IOException; import java.util.List; import java.util.Map; import java.util.concurrent.TimeoutException; +import org.junit.Test; + +import com.rabbitmq.client.GetResponse; +import com.rabbitmq.client.test.BrokerTestCase; +import com.rabbitmq.tools.Host; + public class Firehose extends BrokerTestCase { private String q; private String firehose; @@ -38,7 +43,7 @@ protected void createResources() throws IOException, TimeoutException { channel.queueBind(firehose, "amq.rabbitmq.trace", "#"); } - public void testFirehose() throws IOException { + @Test public void firehose() throws IOException { publishGet("not traced"); enable(); GetResponse msg = publishGet("traced"); diff --git a/src/test/java/com/rabbitmq/client/test/server/HATests.java b/src/test/java/com/rabbitmq/client/test/server/HATests.java index 9d97ad7b8f..17b8ad1351 100644 --- a/src/test/java/com/rabbitmq/client/test/server/HATests.java +++ b/src/test/java/com/rabbitmq/client/test/server/HATests.java @@ -15,47 +15,51 @@ package com.rabbitmq.client.test.server; -import junit.framework.TestCase; -import junit.framework.TestSuite; - import com.rabbitmq.client.test.AbstractRMQTestSuite; +import com.rabbitmq.client.test.RequiredPropertiesSuite; import com.rabbitmq.client.test.functional.FunctionalTests; import com.rabbitmq.tools.Host; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; -public class HATests extends AbstractRMQTestSuite { - // this is horrific - public static boolean HA_TESTS_RUNNING = false; +@RunWith(RequiredPropertiesSuite.class) +@Suite.SuiteClasses({ + HATests.SetUp.class, + FunctionalTests.class, + ServerTests.class, + HATests.TearDown.class +}) +public class HATests { - public static TestSuite suite() { - TestSuite suite = new TestSuite("server-tests"); - if (!requiredProperties()) return suite; - suite.addTestSuite(SetUp.class); - FunctionalTests.add(suite); - ServerTests.add(suite); - suite.addTestSuite(TearDown.class); - return suite; + // initialize system properties + static{ + new AbstractRMQTestSuite(){}; } + // this is horrific + public static boolean HA_TESTS_RUNNING = false; + // This is of course an abuse of the TestCase concept - but I don't want to // run this command on every test case. And there's no hook for "before / // after this test suite". - public static class SetUp extends TestCase { - @Override - protected void setUp() throws Exception { + public static class SetUp { + + @Test public void setUp() throws Exception { Host.rabbitmqctl("set_policy HA '.*' '{\"ha-mode\":\"all\"}'"); HA_TESTS_RUNNING = true; } - public void testNothing() {} + @Test public void testNothing() {} } - public static class TearDown extends TestCase { - @Override - protected void tearDown() throws Exception { + public static class TearDown { + + @Test public void tearDown() throws Exception { Host.rabbitmqctl("clear_policy HA"); HA_TESTS_RUNNING = false; } - public void testNothing() {} + @Test public void testNothing() {} } } diff --git a/src/test/java/com/rabbitmq/client/test/server/LoopbackUsers.java b/src/test/java/com/rabbitmq/client/test/server/LoopbackUsers.java index ea4c1a6af3..7e6fff9e06 100644 --- a/src/test/java/com/rabbitmq/client/test/server/LoopbackUsers.java +++ b/src/test/java/com/rabbitmq/client/test/server/LoopbackUsers.java @@ -15,10 +15,7 @@ package com.rabbitmq.client.test.server; -import com.rabbitmq.client.AuthenticationFailureException; -import com.rabbitmq.client.ConnectionFactory; -import com.rabbitmq.tools.Host; -import junit.framework.TestCase; +import static org.junit.Assert.fail; import java.io.IOException; import java.net.Inet4Address; @@ -28,19 +25,26 @@ import java.util.Enumeration; import java.util.concurrent.TimeoutException; -public class LoopbackUsers extends TestCase { - @Override - protected void setUp() throws IOException { +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.rabbitmq.client.AuthenticationFailureException; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.tools.Host; + +public class LoopbackUsers { + + @Before public void setUp() throws IOException { Host.rabbitmqctl("add_user test test"); Host.rabbitmqctl("set_permissions test '.*' '.*' '.*'"); } - @Override - protected void tearDown() throws IOException { + @After public void tearDown() throws IOException { Host.rabbitmqctl("delete_user test"); } - public void testLoopback() throws IOException, TimeoutException { + @Test public void loopback() throws IOException, TimeoutException { String addr = findRealIPAddress().getHostAddress(); assertGuestFail(addr); Host.rabbitmqctl("eval 'application:set_env(rabbit, loopback_users, []).'"); diff --git a/src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java b/src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java index 6e5b35609d..998fecd987 100644 --- a/src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java +++ b/src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java @@ -15,9 +15,14 @@ package com.rabbitmq.client.test.server; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + import java.io.IOException; import java.util.concurrent.TimeoutException; +import org.junit.Test; + import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.QueueingConsumer; @@ -31,7 +36,7 @@ public class MemoryAlarms extends BrokerTestCase { private Channel channel2; @Override - protected void setUp() throws IOException, TimeoutException { + public void setUp() throws IOException, TimeoutException { connectionFactory.setRequestedHeartbeat(1); super.setUp(); if (connection2 == null) { @@ -41,7 +46,7 @@ protected void setUp() throws IOException, TimeoutException { } @Override - protected void tearDown() throws IOException, TimeoutException { + public void tearDown() throws IOException, TimeoutException { if (channel2 != null) { channel2.abort(); channel2 = null; @@ -70,7 +75,7 @@ protected void releaseResources() throws IOException { } } - public void testFlowControl() throws IOException, InterruptedException { + @Test public void flowControl() throws IOException, InterruptedException { basicPublishVolatile(Q); setResourceAlarm("memory"); // non-publish actions only after an alarm should be fine @@ -92,7 +97,7 @@ public void testFlowControl() throws IOException, InterruptedException { } - public void testOverlappingAlarmsFlowControl() throws IOException, InterruptedException { + @Test public void overlappingAlarmsFlowControl() throws IOException, InterruptedException { QueueingConsumer c = new QueueingConsumer(channel); String consumerTag = channel.basicConsume(Q, true, c); diff --git a/src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java b/src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java index ee78e950c6..f877b0e001 100644 --- a/src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java @@ -17,6 +17,8 @@ import java.io.IOException; +import org.junit.Test; + import com.rabbitmq.client.AMQP; import com.rabbitmq.client.MessageProperties; import com.rabbitmq.client.test.ConfirmBase; @@ -27,7 +29,7 @@ public class MessageRecovery extends ConfirmBase private final static String Q = "recovery-test"; private final static String Q2 = "recovery-test-ha-check"; - public void testMessageRecovery() + @Test public void messageRecovery() throws Exception { channel.queueDelete(Q); diff --git a/src/test/java/com/rabbitmq/client/test/server/Permissions.java b/src/test/java/com/rabbitmq/client/test/server/Permissions.java index 782754833d..9b702a0701 100644 --- a/src/test/java/com/rabbitmq/client/test/server/Permissions.java +++ b/src/test/java/com/rabbitmq/client/test/server/Permissions.java @@ -16,20 +16,26 @@ package com.rabbitmq.client.test.server; -import com.rabbitmq.client.AlreadyClosedException; -import com.rabbitmq.client.AuthenticationFailureException; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + import java.io.IOException; -import java.util.Map; import java.util.HashMap; +import java.util.Map; import java.util.concurrent.TimeoutException; +import org.junit.Test; + import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.AlreadyClosedException; +import com.rabbitmq.client.AuthenticationFailureException; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.QueueingConsumer; import com.rabbitmq.client.impl.AMQChannel; +import com.rabbitmq.client.test.BrokerTestCase; import com.rabbitmq.tools.Host; public class Permissions extends BrokerTestCase @@ -46,14 +52,14 @@ public Permissions() connectionFactory = factory; } - protected void setUp() + public void setUp() throws IOException, TimeoutException { deleteRestrictedAccount(); addRestrictedAccount(); super.setUp(); } - protected void tearDown() + public void tearDown() throws IOException, TimeoutException { super.tearDown(); deleteRestrictedAccount(); @@ -114,7 +120,7 @@ protected void withNames(WithName action) action.with("none"); } - public void testAuth() throws TimeoutException { + @Test public void auth() throws TimeoutException { ConnectionFactory unAuthFactory = new ConnectionFactory(); unAuthFactory.setUsername("test"); unAuthFactory.setPassword("tset"); @@ -130,7 +136,7 @@ public void testAuth() throws TimeoutException { } } - public void testExchangeConfiguration() + @Test public void exchangeConfiguration() throws IOException { runConfigureTest(new WithName() { @@ -143,7 +149,7 @@ public void with(String name) throws IOException { }}); } - public void testQueueConfiguration() + @Test public void queueConfiguration() throws IOException { runConfigureTest(new WithName() { @@ -156,7 +162,7 @@ public void with(String name) throws IOException { }}); } - public void testPassiveDeclaration() throws IOException { + @Test public void passiveDeclaration() throws IOException { runTest(true, true, true, true, new WithName() { public void with(String name) throws IOException { channel.exchangeDeclarePassive(name); @@ -167,7 +173,7 @@ public void with(String name) throws IOException { }}); } - public void testBinding() + @Test public void binding() throws IOException { runTest(false, true, false, false, new WithName() { @@ -180,7 +186,7 @@ public void with(String name) throws IOException { }}); } - public void testPublish() + @Test public void publish() throws IOException { runTest(false, true, false, false, new WithName() { @@ -192,7 +198,7 @@ public void with(String name) throws IOException { }}); } - public void testGet() + @Test public void get() throws IOException { runTest(false, false, true, false, new WithName() { @@ -201,7 +207,7 @@ public void with(String name) throws IOException { }}); } - public void testConsume() + @Test public void consume() throws IOException { runTest(false, false, true, false, new WithName() { @@ -210,7 +216,7 @@ public void with(String name) throws IOException { }}); } - public void testPurge() + @Test public void purge() throws IOException { runTest(false, false, true, false, new WithName() { @@ -222,7 +228,7 @@ public void with(String name) throws IOException { }}); } - public void testAltExchConfiguration() + @Test public void altExchConfiguration() throws IOException { runTest(false, false, false, false, @@ -233,7 +239,7 @@ public void testAltExchConfiguration() createAltExchConfigTest("configure-and-read-me")); } - public void testDLXConfiguration() + @Test public void dLXConfiguration() throws IOException { runTest(false, false, false, false, @@ -244,7 +250,7 @@ public void testDLXConfiguration() createDLXConfigTest("configure-and-read-me")); } - public void testNoAccess() + @Test public void noAccess() throws IOException, InterruptedException { Host.rabbitmqctl("set_permissions -p /test test \"\" \"\" \"\""); diff --git a/src/test/java/com/rabbitmq/client/test/server/PersistenceGuarantees.java b/src/test/java/com/rabbitmq/client/test/server/PersistenceGuarantees.java index b4df0710db..a627abf6dd 100644 --- a/src/test/java/com/rabbitmq/client/test/server/PersistenceGuarantees.java +++ b/src/test/java/com/rabbitmq/client/test/server/PersistenceGuarantees.java @@ -15,11 +15,15 @@ package com.rabbitmq.client.test.server; -import com.rabbitmq.client.MessageProperties; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.assertEquals; import java.io.IOException; +import org.junit.Test; + +import com.rabbitmq.client.MessageProperties; +import com.rabbitmq.client.test.BrokerTestCase; + public class PersistenceGuarantees extends BrokerTestCase { private static final int COUNT = 10000; private String queue; @@ -28,7 +32,7 @@ protected void declareQueue() throws IOException { queue = channel.queueDeclare("", true, false, false, null).getQueue(); } - public void testTxPersistence() throws Exception { + @Test public void txPersistence() throws Exception { declareQueue(); channel.txSelect(); publish(); @@ -37,7 +41,7 @@ public void testTxPersistence() throws Exception { assertPersisted(); } - public void testConfirmPersistence() throws Exception { + @Test public void confirmPersistence() throws Exception { declareQueue(); channel.confirmSelect(); publish(); diff --git a/src/test/java/com/rabbitmq/client/test/server/PriorityQueues.java b/src/test/java/com/rabbitmq/client/test/server/PriorityQueues.java index 1810f39ad9..af16b2135c 100644 --- a/src/test/java/com/rabbitmq/client/test/server/PriorityQueues.java +++ b/src/test/java/com/rabbitmq/client/test/server/PriorityQueues.java @@ -15,10 +15,7 @@ package com.rabbitmq.client.test.server; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.DefaultConsumer; -import com.rabbitmq.client.Envelope; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.assertEquals; import java.io.IOException; import java.util.ArrayList; @@ -29,8 +26,15 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import org.junit.Test; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.DefaultConsumer; +import com.rabbitmq.client.Envelope; +import com.rabbitmq.client.test.BrokerTestCase; + public class PriorityQueues extends BrokerTestCase { - public void testPrioritisingBasics() throws IOException, TimeoutException, InterruptedException { + @Test public void prioritisingBasics() throws IOException, TimeoutException, InterruptedException { String q = "with-3-priorities"; int n = 3; channel.queueDeclare(q, true, false, false, argsWithPriorities(n)); diff --git a/src/test/java/com/rabbitmq/client/test/server/ServerTests.java b/src/test/java/com/rabbitmq/client/test/server/ServerTests.java index 4250e9bea1..59687862f8 100644 --- a/src/test/java/com/rabbitmq/client/test/server/ServerTests.java +++ b/src/test/java/com/rabbitmq/client/test/server/ServerTests.java @@ -16,34 +16,34 @@ package com.rabbitmq.client.test.server; -import junit.framework.TestSuite; - import com.rabbitmq.client.test.AbstractRMQTestSuite; +import com.rabbitmq.client.test.RequiredPropertiesSuite; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; -public class ServerTests extends AbstractRMQTestSuite { +@RunWith(RequiredPropertiesSuite.class) +@Suite.SuiteClasses({ + Permissions.class, + DurableBindingLifecycle.class, + DeadLetterExchangeDurable.class, + EffectVisibilityCrossNodeTest.class, + ExclusiveQueueDurability.class, + AbsentQueue.class, + AlternateExchangeEquivalence.class, + MemoryAlarms.class, + MessageRecovery.class, + Firehose.class, + PersistenceGuarantees.class, + Shutdown.class, + BlockedConnection.class, + ChannelLimitNegotiation.class, + LoopbackUsers.class +}) +public class ServerTests { - public static TestSuite suite() { - TestSuite suite = new TestSuite("server-tests"); - if (!requiredProperties()) return suite; - add(suite); - return suite; - } + // initialize system properties + static{ + new AbstractRMQTestSuite(){}; + } - public static void add(TestSuite suite) { - suite.addTestSuite(Permissions.class); - suite.addTestSuite(DurableBindingLifecycle.class); - suite.addTestSuite(DeadLetterExchangeDurable.class); - suite.addTestSuite(EffectVisibilityCrossNodeTest.class); - suite.addTestSuite(ExclusiveQueueDurability.class); - suite.addTestSuite(AbsentQueue.class); - suite.addTestSuite(AlternateExchangeEquivalence.class); - suite.addTestSuite(MemoryAlarms.class); - suite.addTestSuite(MessageRecovery.class); - suite.addTestSuite(Firehose.class); - suite.addTestSuite(PersistenceGuarantees.class); - suite.addTestSuite(Shutdown.class); - suite.addTestSuite(BlockedConnection.class); - suite.addTestSuite(ChannelLimitNegotiation.class); - suite.addTestSuite(LoopbackUsers.class); - } } diff --git a/src/test/java/com/rabbitmq/client/test/server/Shutdown.java b/src/test/java/com/rabbitmq/client/test/server/Shutdown.java index 521325b9d2..bab3724818 100644 --- a/src/test/java/com/rabbitmq/client/test/server/Shutdown.java +++ b/src/test/java/com/rabbitmq/client/test/server/Shutdown.java @@ -15,12 +15,14 @@ package com.rabbitmq.client.test.server; +import org.junit.Test; + import com.rabbitmq.client.AMQP; import com.rabbitmq.client.test.BrokerTestCase; public class Shutdown extends BrokerTestCase { - public void testErrorOnShutdown() throws Exception { + @Test public void errorOnShutdown() throws Exception { bareRestart(); expectError(AMQP.CONNECTION_FORCED); } diff --git a/src/test/java/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java b/src/test/java/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java index 5a6b9bac33..75ee9b882d 100644 --- a/src/test/java/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java +++ b/src/test/java/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java @@ -15,11 +15,8 @@ package com.rabbitmq.client.test.server; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.DefaultConsumer; -import com.rabbitmq.client.Envelope; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import java.io.IOException; import java.util.ArrayList; @@ -32,6 +29,14 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import org.junit.Test; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.DefaultConsumer; +import com.rabbitmq.client.Envelope; +import com.rabbitmq.client.test.BrokerTestCase; + class RejectingConsumer extends DefaultConsumer { private CountDownLatch latch; private Map headers; @@ -63,7 +68,7 @@ public Map getHeaders() { public class XDeathHeaderGrowth extends BrokerTestCase { @SuppressWarnings("unchecked") - public void testBoundedXDeathHeaderGrowth() throws IOException, InterruptedException { + @Test public void boundedXDeathHeaderGrowth() throws IOException, InterruptedException { final String x1 = "issues.rabbitmq-server-78.fanout1"; declareTransientFanoutExchange(x1); final String x2 = "issues.rabbitmq-server-78.fanout2"; @@ -124,7 +129,7 @@ private void cleanUpQueues(String... qs) throws IOException { } @SuppressWarnings("unchecked") - public void testHandlingOfXDeathHeadersFromEarlierVersions() throws IOException, InterruptedException { + @Test public void handlingOfXDeathHeadersFromEarlierVersions() throws IOException, InterruptedException { final String x1 = "issues.rabbitmq-server-152.fanout1"; declareTransientFanoutExchange(x1); final String x2 = "issues.rabbitmq-server-152.fanout2"; diff --git a/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java index 3026fe547a..d4e3c33360 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java @@ -15,6 +15,9 @@ package com.rabbitmq.client.test.ssl; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + import java.io.FileInputStream; import java.io.IOException; import java.security.KeyManagementException; @@ -30,6 +33,8 @@ import javax.net.ssl.SSLHandshakeException; import javax.net.ssl.TrustManagerFactory; +import org.junit.Test; + import com.rabbitmq.client.ConnectionFactory; /** @@ -92,5 +97,5 @@ public void openConnection() } public void openChannel() {} - public void testSSL() {} + @Test public void sSL() {} } diff --git a/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java index 71d59f95a3..1854e1753c 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java @@ -16,20 +16,59 @@ package com.rabbitmq.client.test.ssl; -import junit.framework.TestSuite; - import com.rabbitmq.client.test.AbstractRMQTestSuite; +import org.junit.runner.RunWith; +import org.junit.runner.Runner; +import org.junit.runners.Suite; +import org.junit.runners.model.InitializationError; +import org.junit.runners.model.RunnerBuilder; + +import java.util.ArrayList; +import java.util.List; + +@RunWith(Suite.class) +@Suite.SuiteClasses({ + UnverifiedConnection.class, + VerifiedConnection.class, + BadVerifiedConnection.class +}) +public class SSLTests { + + // initialize system properties + static{ + new AbstractRMQTestSuite(){}; + } + + public static class SslSuite extends Suite { + + public SslSuite(Class klass, RunnerBuilder builder) throws InitializationError { + super(klass, builder); + } + + public SslSuite(RunnerBuilder builder, Class[] classes) throws InitializationError { + super(builder, classes); + } + + protected SslSuite(Class klass, Class[] suiteClasses) throws InitializationError { + super(klass, suiteClasses); + } + + protected SslSuite(RunnerBuilder builder, Class klass, Class[] suiteClasses) throws InitializationError { + super(builder, klass, suiteClasses); + } + + protected SslSuite(Class klass, List runners) throws InitializationError { + super(klass, runners); + } + + @Override + protected List getChildren() { + if(!AbstractRMQTestSuite.requiredProperties() && !AbstractRMQTestSuite.isSSLAvailable()) { + return new ArrayList(); + } else { + return super.getChildren(); + } + } + } -public class SSLTests extends AbstractRMQTestSuite { - public static TestSuite suite() { - TestSuite suite = new TestSuite("ssl"); - suite.addTestSuite(ConnectionFactoryDefaultTlsVersion.class); - // Skip the tests if not under umbrella and no TLS setup available - if (!requiredProperties()) return suite; - if (!isSSLAvailable()) return suite; - suite.addTestSuite(UnverifiedConnection.class); - suite.addTestSuite(VerifiedConnection.class); - suite.addTestSuite(BadVerifiedConnection.class); - return suite; - } } diff --git a/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java index d7462ef989..603aa1f372 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java @@ -15,6 +15,10 @@ package com.rabbitmq.client.test.ssl; +import static org.junit.Assert.*; +import org.junit.Test; + + import java.io.IOException; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; @@ -43,7 +47,7 @@ public void openConnection() } } - public void testSSL() throws IOException + @Test public void sSL() throws IOException { channel.queueDeclare("Bug19356Test", false, true, true, null); channel.basicPublish("", "Bug19356Test", null, "SSL".getBytes()); diff --git a/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java index 645dec1104..467c6d8b71 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java @@ -15,6 +15,8 @@ package com.rabbitmq.client.test.ssl; +import static org.junit.Assert.assertNotNull; + import java.io.FileInputStream; import java.io.IOException; import java.security.KeyManagementException; @@ -23,7 +25,6 @@ import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; -import java.util.Arrays; import java.util.concurrent.TimeoutException; import javax.net.ssl.KeyManagerFactory; From fde2dc90ba53fb15b8f8e0347ca09a111d6bfe14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 25 Aug 2016 16:06:06 +0200 Subject: [PATCH 0235/2114] Add tests to the suites Fixes #174 --- .../rabbitmq/client/test/AbstractRMQTestSuite.java | 11 +---------- .../client/test/functional/FunctionalTests.java | 6 +++++- .../com/rabbitmq/client/test/server/ServerTests.java | 5 ++++- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java b/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java index 77d97e6b73..cb27d22e7c 100644 --- a/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java +++ b/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java @@ -22,12 +22,7 @@ import java.net.Socket; import java.util.Properties; -public abstract class AbstractRMQTestSuite { - - private static final String DEFAULT_SSL_HOSTNAME = "localhost"; - private static final int DEFAULT_SSL_PORT = 5671; - - private static boolean buildSSLPropertiesFound = false; +public abstract class AbstractRMQTestSuite { static { Properties TESTS_PROPS = new Properties(System.getProperties()); @@ -86,10 +81,6 @@ public static boolean requiredProperties() { return true; } - public static boolean isUnderUmbrella() { - return new File("../../UMBRELLA.md").isFile(); - } - public static boolean isSSLAvailable() { String sslClientCertsDir = System.getProperty("test-client-cert.path"); String hostname = System.getProperty("broker.hostname"); diff --git a/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java b/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java index e24cd2d039..8633cf6c40 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java +++ b/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java @@ -72,7 +72,11 @@ ConnectionRecovery.class, ExceptionHandling.class, PerConsumerPrefetch.class, - DirectReplyTo.class + DirectReplyTo.class, + ConsumerCount.class, + BasicGet.class, + Nack.class, + ExceptionMessages.class }) public class FunctionalTests { diff --git a/src/test/java/com/rabbitmq/client/test/server/ServerTests.java b/src/test/java/com/rabbitmq/client/test/server/ServerTests.java index 59687862f8..2478b72994 100644 --- a/src/test/java/com/rabbitmq/client/test/server/ServerTests.java +++ b/src/test/java/com/rabbitmq/client/test/server/ServerTests.java @@ -37,7 +37,10 @@ Shutdown.class, BlockedConnection.class, ChannelLimitNegotiation.class, - LoopbackUsers.class + LoopbackUsers.class, + XDeathHeaderGrowth.class, + PriorityQueues.class, + }) public class ServerTests { From b34d5495264c9c01f3aa658024f77563a9e8d803 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 24 Aug 2016 15:42:02 +0200 Subject: [PATCH 0236/2114] Add AddressResolver to try all DNS record IPs References #138 --- .../com/rabbitmq/client/AddressResolver.java | 3 +- .../client/DnsRecordIpAddressResolver.java | 64 +++++++++++++++++++ .../com/rabbitmq/client/test/ClientTests.java | 1 + .../test/DnsRecordIpAddressResolverTests.java | 48 ++++++++++++++ 4 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/rabbitmq/client/DnsRecordIpAddressResolver.java create mode 100644 src/test/java/com/rabbitmq/client/test/DnsRecordIpAddressResolverTests.java diff --git a/src/main/java/com/rabbitmq/client/AddressResolver.java b/src/main/java/com/rabbitmq/client/AddressResolver.java index f16672e4b9..41726b0ced 100644 --- a/src/main/java/com/rabbitmq/client/AddressResolver.java +++ b/src/main/java/com/rabbitmq/client/AddressResolver.java @@ -1,5 +1,6 @@ package com.rabbitmq.client; +import java.io.IOException; import java.util.List; /** @@ -7,6 +8,6 @@ */ public interface AddressResolver { - List
getAddresses(); + List
getAddresses() throws IOException; } diff --git a/src/main/java/com/rabbitmq/client/DnsRecordIpAddressResolver.java b/src/main/java/com/rabbitmq/client/DnsRecordIpAddressResolver.java new file mode 100644 index 0000000000..0416e25422 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/DnsRecordIpAddressResolver.java @@ -0,0 +1,64 @@ +package com.rabbitmq.client; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.List; + +/** + * + */ +public class DnsRecordIpAddressResolver implements AddressResolver { + + private final Address address; + + private final boolean ssl; + + public DnsRecordIpAddressResolver(String hostname, int port, boolean ssl) { + this(new Address(hostname, port), ssl); + } + + public DnsRecordIpAddressResolver(String hostname, int port) { + this(new Address(hostname, port), false); + } + + public DnsRecordIpAddressResolver() { + this("localhost"); + } + + public DnsRecordIpAddressResolver(String hostname) { + this(new Address(hostname), false); + } + + public DnsRecordIpAddressResolver(Address address) { + this(address, false); + } + + public DnsRecordIpAddressResolver(Address address, boolean ssl) { + this.address = address; + this.ssl = ssl; + } + + @Override + public List
getAddresses() throws IOException { + String hostName = address.getHost(); + int portNumber = ConnectionFactory.portOrDefault(address.getPort(), ssl); + InetAddress[] inetAddresses; + try { + inetAddresses = resolveIpAddresses(hostName); + } catch (UnknownHostException e) { + throw new IOException("Could not resolve IP addresses for host "+hostName, e); + } + List
addresses = new ArrayList
(); + for (InetAddress inetAddress : inetAddresses) { + addresses.add(new Address(inetAddress.getHostAddress(), portNumber)); + } + return addresses; + } + + protected InetAddress[] resolveIpAddresses(String hostName) throws UnknownHostException { + return InetAddress.getAllByName(hostName); + } + +} diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index b7d75d0d9b..3955f7be72 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -40,6 +40,7 @@ public static TestSuite suite() { suite.addTestSuite(AmqpUriTest.class); suite.addTestSuite(JSONReadWriteTest.class); suite.addTestSuite(SharedThreadPoolTest.class); + suite.addTestSuite(DnsRecordIpAddressResolverTests.class); return suite; } } diff --git a/src/test/java/com/rabbitmq/client/test/DnsRecordIpAddressResolverTests.java b/src/test/java/com/rabbitmq/client/test/DnsRecordIpAddressResolverTests.java new file mode 100644 index 0000000000..098241c42c --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/DnsRecordIpAddressResolverTests.java @@ -0,0 +1,48 @@ +package com.rabbitmq.client.test; + +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.DnsRecordIpAddressResolver; + +import java.io.IOException; +import java.util.concurrent.TimeoutException; + +/** + * + */ +public class DnsRecordIpAddressResolverTests extends BrokerTestCase { + + public void testLocalhostResolution() throws IOException, TimeoutException { + DnsRecordIpAddressResolver addressResolver = new DnsRecordIpAddressResolver("localhost"); + ConnectionFactory connectionFactory = newConnectionFactory(); + Connection connection = connectionFactory.newConnection(addressResolver); + try { + connection.createChannel(); + } finally { + connection.abort(); + } + } + + public void testLoopbackInterfaceResolution() throws IOException, TimeoutException { + DnsRecordIpAddressResolver addressResolver = new DnsRecordIpAddressResolver("127.0.0.1"); + ConnectionFactory connectionFactory = newConnectionFactory(); + Connection connection = connectionFactory.newConnection(addressResolver); + try { + connection.createChannel(); + } finally { + connection.abort(); + } + } + + public void testResolutionFails() throws IOException, TimeoutException { + DnsRecordIpAddressResolver addressResolver = new DnsRecordIpAddressResolver( + "afancyandunlikelyhostname" + ); + try { + connectionFactory.newConnection(addressResolver); + fail("The host resolution should have failed"); + } catch (IOException e) { + // expected + } + } +} From a5362a3cff12a8acdde1f0243fe68fa877a58b36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 24 Aug 2016 16:27:12 +0200 Subject: [PATCH 0237/2114] Document AddressResolver and implementations References #138 --- .../java/com/rabbitmq/client/AddressResolver.java | 5 +++++ .../rabbitmq/client/DnsRecordIpAddressResolver.java | 12 +++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/AddressResolver.java b/src/main/java/com/rabbitmq/client/AddressResolver.java index 41726b0ced..dae00d425b 100644 --- a/src/main/java/com/rabbitmq/client/AddressResolver.java +++ b/src/main/java/com/rabbitmq/client/AddressResolver.java @@ -8,6 +8,11 @@ */ public interface AddressResolver { + /** + * Get the potential {@link Address}es to connect to. + * @return candidate {@link Address}es + * @throws IOException if it encounters a problem + */ List
getAddresses() throws IOException; } diff --git a/src/main/java/com/rabbitmq/client/DnsRecordIpAddressResolver.java b/src/main/java/com/rabbitmq/client/DnsRecordIpAddressResolver.java index 0416e25422..4a2cfee2f3 100644 --- a/src/main/java/com/rabbitmq/client/DnsRecordIpAddressResolver.java +++ b/src/main/java/com/rabbitmq/client/DnsRecordIpAddressResolver.java @@ -7,7 +7,12 @@ import java.util.List; /** - * + * {@link AddressResolver} that resolves DNS record IPs. + * Uses {@link InetAddress} internally. + * The first returned address is used when automatic recovery is NOT enabled + * at the {@link ConnectionFactory} level. + * When automatic recovery is enabled, a random address will be picked up + * from the returned list of {@link Address}es. */ public class DnsRecordIpAddressResolver implements AddressResolver { @@ -40,6 +45,11 @@ public DnsRecordIpAddressResolver(Address address, boolean ssl) { this.ssl = ssl; } + /** + * Get the IP addresses from a DNS query + * @return candidate {@link Address}es + * @throws IOException if DNS resolution fails + */ @Override public List
getAddresses() throws IOException { String hostName = address.getHost(); From ab9690a1bd5a52cb8431e78c238b3ed7f0c41650 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 25 Aug 2016 09:51:38 +0200 Subject: [PATCH 0238/2114] Refactor non-broker ClientTests to JUnit 4 References #174 --- .../client/test/AMQConnectionTest.java | 69 +++++++------------ .../client/test/AbstractRMQTestSuite.java | 2 +- .../client/test/BlockingCellTest.java | 32 ++++----- .../client/test/BrokenFramesTest.java | 53 +++++++------- .../test/ChannelNumberAllocationTests.java | 43 ++++++------ .../com/rabbitmq/client/test/ClientTests.java | 48 ++++++------- .../client/test/ClonePropertiesTest.java | 29 ++++---- .../client/test/JSONReadWriteTest.java | 19 +++-- .../rabbitmq/client/test/LongStringTest.java | 15 ++-- .../com/rabbitmq/client/test/TableTest.java | 28 ++------ .../client/test/TruncatedInputStreamTest.java | 32 ++++----- .../client/test/ValueOrExceptionTest.java | 22 ++---- .../rabbitmq/utility/IntAllocatorTests.java | 14 ++-- 13 files changed, 166 insertions(+), 240 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java b/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java index 4d21de328b..d86b322eb7 100644 --- a/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java +++ b/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java @@ -15,78 +15,55 @@ package com.rabbitmq.client.test; +import com.rabbitmq.client.*; +import com.rabbitmq.client.impl.AMQConnection; +import com.rabbitmq.client.impl.ConnectionParams; +import com.rabbitmq.client.impl.Frame; +import com.rabbitmq.client.impl.FrameHandler; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + import java.io.IOException; import java.net.InetAddress; import java.net.SocketException; import java.net.SocketTimeoutException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeoutException; -import java.util.concurrent.ExecutorService; -import com.rabbitmq.client.Address; -import java.util.Arrays; -import com.rabbitmq.client.impl.ConnectionParams; -import com.rabbitmq.client.TopologyRecoveryException; -import junit.framework.TestCase; -import junit.framework.TestSuite; - -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.ConnectionFactory; -import com.rabbitmq.client.Consumer; -import com.rabbitmq.client.impl.AMQConnection; -import com.rabbitmq.client.ExceptionHandler; -import com.rabbitmq.client.impl.Frame; -import com.rabbitmq.client.impl.FrameHandler; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; /** * Test suite for AMQConnection. */ -public class AMQConnectionTest extends TestCase { +public class AMQConnectionTest { // private static final String CLOSE_MESSAGE = "terminated by test"; - /** - * Build a suite of tests - * @return the test suite for this class - */ - public static TestSuite suite() { - TestSuite suite = new TestSuite("connection"); - suite.addTestSuite(AMQConnectionTest.class); - return suite; - } - /** The mock frame handler used to test connection behaviour. */ private MockFrameHandler _mockFrameHandler; private ConnectionFactory factory; private MyExceptionHandler exceptionHandler; - /** Setup the environment for this test - * @see junit.framework.TestCase#setUp() - * @throws Exception if anything goes wrong - */ - @Override protected void setUp() throws Exception { - super.setUp(); + @Before public void setUp() throws Exception { _mockFrameHandler = new MockFrameHandler(); factory = new ConnectionFactory(); exceptionHandler = new MyExceptionHandler(); factory.setExceptionHandler(exceptionHandler); } - /** Tear down the environment for this test - * @see junit.framework.TestCase#tearDown() - * @throws Exception if anything goes wrong - */ - @Override protected void tearDown() throws Exception { + @After public void tearDown() throws Exception { factory = null; _mockFrameHandler = null; - super.tearDown(); } - public void testNegativeTCPConnectionTimeout() { + @Test public void negativeTCPConnectionTimeout() { ConnectionFactory cf = new ConnectionFactory(); try { cf.setConnectionTimeout(-10); @@ -96,7 +73,7 @@ public void testNegativeTCPConnectionTimeout() { } } - public void testNegativeProtocolHandshakeTimeout() { + @Test public void negativeProtocolHandshakeTimeout() { ConnectionFactory cf = new ConnectionFactory(); try { cf.setHandshakeTimeout(-10); @@ -106,13 +83,13 @@ public void testNegativeProtocolHandshakeTimeout() { } } - public void testTCPConnectionTimeoutGreaterThanHandShakeTimeout() { + @Test public void tcpConnectionTimeoutGreaterThanHandShakeTimeout() { ConnectionFactory cf = new ConnectionFactory(); cf.setHandshakeTimeout(3000); cf.setConnectionTimeout(5000); } - public void testProtocolHandshakeTimeoutGreaterThanTCPConnectionTimeout() { + @Test public void protocolHandshakeTimeoutGreaterThanTCPConnectionTimeout() { ConnectionFactory cf = new ConnectionFactory(); cf.setConnectionTimeout(5000); @@ -125,7 +102,7 @@ public void testProtocolHandshakeTimeoutGreaterThanTCPConnectionTimeout() { /** Check the AMQConnection does send exactly 1 initial header, and deal correctly with * the frame handler throwing an exception when we try to read data */ - public void testConnectionSendsSingleHeaderAndTimesOut() throws TimeoutException { + @Test public void connectionSendsSingleHeaderAndTimesOut() throws TimeoutException { IOException exception = new SocketTimeoutException(); _mockFrameHandler.setExceptionOnReadingFrames(exception); assertEquals(0, _mockFrameHandler.countHeadersSent()); @@ -158,7 +135,7 @@ public void testConnectionSendsSingleHeaderAndTimesOut() throws TimeoutException /** * Test that we catch timeout between connect and negotiation of the connection being finished. */ - public void testConnectionHangInNegotiation() { + @Test public void connectionHangInNegotiation() { this._mockFrameHandler.setTimeoutCount(10); // to limit hang assertEquals(0, this._mockFrameHandler.countHeadersSent()); try { @@ -176,7 +153,7 @@ public void testConnectionHangInNegotiation() { assertEquals("Wrong type of exception returned.", SocketTimeoutException.class, exceptionList.get(0).getClass()); } - public void testClientProvidedConnectionName() throws IOException, TimeoutException { + @Test public void clientProvidedConnectionName() throws IOException, TimeoutException { String providedName = "event consumers connection"; Connection connection = factory.newConnection(providedName); assertEquals(providedName, connection.getClientProvidedName()); diff --git a/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java b/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java index 1937e074c5..95b6d1c7f3 100644 --- a/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java +++ b/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java @@ -26,7 +26,7 @@ import com.rabbitmq.tools.Host; -public abstract class AbstractRMQTestSuite extends TestSuite { +public abstract class AbstractRMQTestSuite { //extends TestSuite { private static final String DEFAULT_SSL_HOSTNAME = "localhost"; private static final int DEFAULT_SSL_PORT = 5671; diff --git a/src/test/java/com/rabbitmq/client/test/BlockingCellTest.java b/src/test/java/com/rabbitmq/client/test/BlockingCellTest.java index afc4acc5c7..26f588b771 100644 --- a/src/test/java/com/rabbitmq/client/test/BlockingCellTest.java +++ b/src/test/java/com/rabbitmq/client/test/BlockingCellTest.java @@ -16,25 +16,19 @@ package com.rabbitmq.client.test; +import com.rabbitmq.utility.BlockingCell; +import org.junit.Test; + import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; -import junit.framework.TestCase; -import junit.framework.TestSuite; - -import com.rabbitmq.utility.BlockingCell; +import static org.junit.Assert.*; public class BlockingCellTest - extends TestCase { - public static TestSuite suite() - { - TestSuite suite = new TestSuite("blockingCells"); - suite.addTestSuite(BlockingCellTest.class); - return suite; - } - public void testDoubleSet() throws InterruptedException + @Test + public void doubleSet() throws InterruptedException { BlockingCell cell = new BlockingCell(); cell.set("one"); @@ -47,7 +41,7 @@ public void testDoubleSet() throws InterruptedException fail("Expected AssertionError"); } - public void testMultiGet() + @Test public void multiGet() throws InterruptedException { final BlockingCell cell = new BlockingCell(); @@ -56,7 +50,7 @@ public void testMultiGet() assertEquals("one", cell.get()); } - public void testNullSet() + @Test public void nullSet() throws InterruptedException { BlockingCell c = new BlockingCell(); @@ -64,7 +58,7 @@ public void testNullSet() assertNull(c.get()); } - public void testEarlySet() + @Test public void earlySet() throws InterruptedException { final BlockingCell cell = new BlockingCell(); @@ -95,7 +89,7 @@ public void run() { assertEquals("hello", holder.get()); } - public void testLateSet() + @Test public void lateSet() throws InterruptedException { final BlockingCell cell = new BlockingCell(); @@ -129,8 +123,8 @@ public void run() { assertEquals("hello", holder.get()); } - - public void testGetWaitsUntilSet() throws InterruptedException { + + @Test public void getWaitsUntilSet() throws InterruptedException { final BlockingCell cell = new BlockingCell(); final String value = "foo"; final AtomicReference valueHolder = new AtomicReference(); @@ -155,7 +149,7 @@ public void testGetWaitsUntilSet() throws InterruptedException { assertTrue(value == valueHolder.get()); } - public void testSetIfUnset() throws InterruptedException { + @Test public void setIfUnset() throws InterruptedException { final BlockingCell cell = new BlockingCell(); assertTrue(cell.setIfUnset("foo")); assertEquals("foo", cell.get()); diff --git a/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java b/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java index 77faa8f1f3..566e2da66a 100644 --- a/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java +++ b/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java @@ -16,6 +16,17 @@ package com.rabbitmq.client.test; +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.UnexpectedFrameError; +import com.rabbitmq.client.impl.AMQConnection; +import com.rabbitmq.client.impl.AMQImpl.Basic.Publish; +import com.rabbitmq.client.impl.Frame; +import com.rabbitmq.client.impl.FrameHandler; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + import java.io.IOException; import java.net.InetAddress; import java.net.SocketException; @@ -24,42 +35,24 @@ import java.util.List; import java.util.concurrent.Executors; -import junit.framework.TestCase; -import junit.framework.TestSuite; - -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.ConnectionFactory; -import com.rabbitmq.client.UnexpectedFrameError; -import com.rabbitmq.client.impl.AMQConnection; -import com.rabbitmq.client.impl.Frame; -import com.rabbitmq.client.impl.FrameHandler; -import com.rabbitmq.client.impl.AMQImpl.Basic.Publish; +import static org.junit.Assert.*; -public class BrokenFramesTest extends TestCase { - public static TestSuite suite() { - TestSuite suite = new TestSuite("connection"); - suite.addTestSuite(BrokenFramesTest.class); - return suite; - } +public class BrokenFramesTest { private MyFrameHandler myFrameHandler; private ConnectionFactory factory; - @Override - protected void setUp() throws Exception { - super.setUp(); + @Before public void setUp() throws Exception { myFrameHandler = new MyFrameHandler(); factory = new ConnectionFactory(); } - @Override - protected void tearDown() throws Exception { + @After public void tearDown() throws Exception { factory = null; myFrameHandler = null; - super.tearDown(); } - public void testNoMethod() throws Exception { + @Test public void noMethod() throws Exception { List frames = new ArrayList(); frames.add(new Frame(AMQP.FRAME_HEADER, 0)); myFrameHandler.setFrames(frames.iterator()); @@ -77,7 +70,7 @@ public void testNoMethod() throws Exception { fail("No UnexpectedFrameError thrown"); } - public void testMethodThenBody() throws Exception { + @Test public void methodThenBody() throws Exception { List frames = new ArrayList(); byte[] contentBody = new byte[10]; @@ -116,14 +109,14 @@ private UnexpectedFrameError findUnexpectedFrameError(Exception e) { } private static class MyFrameHandler implements FrameHandler { - private Iterator frames; + private Iterator frames; - public void setFrames(Iterator frames) { - this.frames = frames; - } + public void setFrames(Iterator frames) { + this.frames = frames; + } - public Frame readFrame() throws IOException { - return frames.next(); + public Frame readFrame() throws IOException { + return frames.next(); } public void sendHeader() throws IOException { diff --git a/src/test/java/com/rabbitmq/client/test/ChannelNumberAllocationTests.java b/src/test/java/com/rabbitmq/client/test/ChannelNumberAllocationTests.java index 0d817325b1..a2d3da6dff 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelNumberAllocationTests.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelNumberAllocationTests.java @@ -15,18 +15,21 @@ package com.rabbitmq.client.test; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; -import junit.framework.TestCase; - -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.ConnectionFactory; +import static org.junit.Assert.*; -public class ChannelNumberAllocationTests extends TestCase{ +public class ChannelNumberAllocationTests { static final int CHANNEL_COUNT = 100; static final Comparator COMPARATOR = new Comparator(){ public int compare(Channel x, Channel y){ @@ -38,21 +41,21 @@ public int compare(Channel x, Channel y){ Connection connection; - public void setUp() throws Exception{ + @Before public void setUp() throws Exception{ connection = new ConnectionFactory().newConnection(); } - public void tearDown() throws Exception{ + @After public void tearDown() throws Exception{ connection.close(); connection = null; } - public void testAllocateInOrder() throws Exception{ + @Test public void allocateInOrder() throws Exception{ for(int i = 1; i <= CHANNEL_COUNT; i++) assertEquals(i, connection.createChannel().getChannelNumber()); } - public void testAllocateAfterFreeingLast() throws Exception{ + @Test public void allocateAfterFreeingLast() throws Exception{ Channel ch = connection.createChannel(); assertEquals(1, ch.getChannelNumber()); ch.close(); @@ -60,7 +63,7 @@ public void testAllocateAfterFreeingLast() throws Exception{ assertEquals(1, ch.getChannelNumber()); } - public void testAllocateAfterFreeingMany() throws Exception{ + @Test public void allocateAfterFreeingMany() throws Exception{ List channels = new ArrayList(); for(int i = 1; i <= CHANNEL_COUNT; i++) @@ -80,36 +83,36 @@ public void testAllocateAfterFreeingMany() throws Exception{ assertEquals("Didn't create the right number of channels!", CHANNEL_COUNT, channels.size()); for(int i = 1; i < CHANNEL_COUNT; ++i) { - assertTrue("Channel numbers should be distinct." - , channels.get(i-1).getChannelNumber() < channels.get(i).getChannelNumber() - ); + assertTrue("Channel numbers should be distinct." + , channels.get(i-1).getChannelNumber() < channels.get(i).getChannelNumber() + ); } } - public void testAllocateAfterManualAssign() throws Exception{ + @Test public void allocateAfterManualAssign() throws Exception{ connection.createChannel(10); for(int i = 0; i < 20; i++) - assertTrue(10 != connection.createChannel().getChannelNumber()); + assertTrue(10 != connection.createChannel().getChannelNumber()); } - public void testManualAllocationDoesntBreakThings() throws Exception{ + @Test public void manualAllocationDoesntBreakThings() throws Exception{ connection.createChannel((1 << 16) - 1); Channel ch = connection.createChannel(); assertNotNull(ch); } - public void testReuseManuallyAllocatedChannelNumber1() throws Exception{ + @Test public void reuseManuallyAllocatedChannelNumber1() throws Exception{ connection.createChannel(1).close(); assertNotNull(connection.createChannel(1)); } - public void testReuseManuallyAllocatedChannelNumber2() throws Exception{ + @Test public void reuseManuallyAllocatedChannelNumber2() throws Exception{ connection.createChannel(2).close(); assertNotNull(connection.createChannel(3)); } - public void testReserveOnBoundaries() throws Exception{ + @Test public void reserveOnBoundaries() throws Exception{ assertNotNull(connection.createChannel(3)); assertNotNull(connection.createChannel(4)); assertNotNull(connection.createChannel(2)); diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index 3955f7be72..d81103f3c2 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -16,31 +16,31 @@ package com.rabbitmq.client.test; -import junit.framework.TestSuite; +import com.rabbitmq.utility.IntAllocatorTests; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +@RunWith(Suite.class) +@Suite.SuiteClasses({ + TableTest.class, + LongStringTest.class, + BlockingCellTest.class, + TruncatedInputStreamTest.class, + AMQConnectionTest.class, + ValueOrExceptionTest.class, + BrokenFramesTest.class, + ClonePropertiesTest.class, + Bug20004Test.class, + CloseInMainLoop.class, + ChannelNumberAllocationTests.class, + QueueingConsumerShutdownTests.class, + MultiThreadedChannel.class, + IntAllocatorTests.class, + AMQBuilderApiTest.class, + AmqpUriTest.class, + JSONReadWriteTest.class, + SharedThreadPoolTest.class +}) public class ClientTests extends AbstractRMQTestSuite { - public static TestSuite suite() { - TestSuite suite = new TestSuite("client"); - suite.addTest(TableTest.suite()); - suite.addTest(LongStringTest.suite()); - suite.addTest(BlockingCellTest.suite()); - suite.addTest(TruncatedInputStreamTest.suite()); - suite.addTest(AMQConnectionTest.suite()); - suite.addTest(ValueOrExceptionTest.suite()); - suite.addTest(BrokenFramesTest.suite()); - suite.addTest(ClonePropertiesTest.suite()); - suite.addTestSuite(Bug20004Test.class); - suite.addTestSuite(CloseInMainLoop.class); - suite.addTestSuite(ChannelNumberAllocationTests.class); - suite.addTestSuite(QueueingConsumerShutdownTests.class); - suite.addTestSuite(MultiThreadedChannel.class); - suite.addTestSuite(com.rabbitmq.utility.IntAllocatorTests.class); - suite.addTestSuite(AMQBuilderApiTest.class); - suite.addTestSuite(AmqpUriTest.class); - suite.addTestSuite(JSONReadWriteTest.class); - suite.addTestSuite(SharedThreadPoolTest.class); - suite.addTestSuite(DnsRecordIpAddressResolverTests.class); - return suite; - } } diff --git a/src/test/java/com/rabbitmq/client/test/ClonePropertiesTest.java b/src/test/java/com/rabbitmq/client/test/ClonePropertiesTest.java index 1db2a86013..981b7bfd1b 100644 --- a/src/test/java/com/rabbitmq/client/test/ClonePropertiesTest.java +++ b/src/test/java/com/rabbitmq/client/test/ClonePropertiesTest.java @@ -15,36 +15,31 @@ package com.rabbitmq.client.test; -import junit.framework.TestCase; -import junit.framework.TestSuite; - import com.rabbitmq.client.AMQP.BasicProperties; import com.rabbitmq.client.MessageProperties; +import org.junit.Test; -public class ClonePropertiesTest extends TestCase { +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class ClonePropertiesTest { - public static TestSuite suite() - { - TestSuite suite = new TestSuite("cloneProperties"); - suite.addTestSuite(ClonePropertiesTest.class); - return suite; - } - public void testPropertyCloneIsDistinct() + @Test public void propertyCloneIsDistinct() throws CloneNotSupportedException { assertTrue(MessageProperties.MINIMAL_PERSISTENT_BASIC != - MessageProperties.MINIMAL_PERSISTENT_BASIC.clone()); + MessageProperties.MINIMAL_PERSISTENT_BASIC.clone()); } - public void testPropertyClonePreservesValues() + @Test public void propertyClonePreservesValues() throws CloneNotSupportedException { assertEquals(MessageProperties.MINIMAL_PERSISTENT_BASIC.getDeliveryMode(), - ((BasicProperties) MessageProperties.MINIMAL_PERSISTENT_BASIC.clone()) - .getDeliveryMode()); + ((BasicProperties) MessageProperties.MINIMAL_PERSISTENT_BASIC.clone()) + .getDeliveryMode()); assertEquals(new Integer(2), - ((BasicProperties) MessageProperties.MINIMAL_PERSISTENT_BASIC.clone()) - .getDeliveryMode()); + ((BasicProperties) MessageProperties.MINIMAL_PERSISTENT_BASIC.clone()) + .getDeliveryMode()); } } diff --git a/src/test/java/com/rabbitmq/client/test/JSONReadWriteTest.java b/src/test/java/com/rabbitmq/client/test/JSONReadWriteTest.java index 5fc00d434e..44f322f2e0 100644 --- a/src/test/java/com/rabbitmq/client/test/JSONReadWriteTest.java +++ b/src/test/java/com/rabbitmq/client/test/JSONReadWriteTest.java @@ -16,19 +16,16 @@ package com.rabbitmq.client.test; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; - -import com.rabbitmq.tools.json.JSONWriter; import com.rabbitmq.tools.json.JSONReader; +import com.rabbitmq.tools.json.JSONWriter; +import org.junit.Test; -import junit.framework.TestCase; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; -public class JSONReadWriteTest extends TestCase { +public class JSONReadWriteTest { - public void testReadWriteSimple() throws Exception { + @Test public void readWriteSimple() throws Exception { Object myRet; String myJson; @@ -67,7 +64,7 @@ public void testReadWriteSimple() throws Exception { } - public void testMoreComplicated() throws Exception { + @Test public void moreComplicated() throws Exception { String v, s; Object t; @@ -95,7 +92,7 @@ public void testMoreComplicated() throws Exception { } - public void testBadJSON() throws Exception { + @Test public void badJSON() throws Exception { try { new JSONReader().read("[\"foo\",{\"bar\":[\"b\"az\",null,1.0,2]}]"); diff --git a/src/test/java/com/rabbitmq/client/test/LongStringTest.java b/src/test/java/com/rabbitmq/client/test/LongStringTest.java index 56db5fa1e0..df04cddd51 100644 --- a/src/test/java/com/rabbitmq/client/test/LongStringTest.java +++ b/src/test/java/com/rabbitmq/client/test/LongStringTest.java @@ -17,20 +17,15 @@ import com.rabbitmq.client.LongString; import com.rabbitmq.client.impl.LongStringHelper; -import junit.framework.TestCase; -import junit.framework.TestSuite; +import org.junit.Test; import java.io.UnsupportedEncodingException; -public class LongStringTest extends TestCase { -public static TestSuite suite() - { - TestSuite suite = new TestSuite("longString"); - suite.addTestSuite(LongStringTest.class); - return suite; - } +import static org.junit.Assert.assertTrue; + +public class LongStringTest { - public void testToString() throws UnsupportedEncodingException { + @Test public void testToString() throws UnsupportedEncodingException { String s = "abcdef"; LongString ls = LongStringHelper.asLongString(s); diff --git a/src/test/java/com/rabbitmq/client/test/TableTest.java b/src/test/java/com/rabbitmq/client/test/TableTest.java index c2e914d4ba..630c7fc34d 100644 --- a/src/test/java/com/rabbitmq/client/test/TableTest.java +++ b/src/test/java/com/rabbitmq/client/test/TableTest.java @@ -16,35 +16,19 @@ package com.rabbitmq.client.test; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; +import com.rabbitmq.client.impl.*; +import org.junit.Test; + +import java.io.*; import java.math.BigDecimal; import java.util.Date; import java.util.HashMap; import java.util.Map; -import junit.framework.TestCase; -import junit.framework.TestSuite; - -import com.rabbitmq.client.impl.Frame; -import com.rabbitmq.client.impl.LongStringHelper; -import com.rabbitmq.client.impl.MethodArgumentReader; -import com.rabbitmq.client.impl.MethodArgumentWriter; -import com.rabbitmq.client.impl.ValueReader; -import com.rabbitmq.client.impl.ValueWriter; +import static org.junit.Assert.assertEquals; public class TableTest - extends TestCase { - public static TestSuite suite() - { - TestSuite suite = new TestSuite("tables"); - suite.addTestSuite(TableTest.class); - return suite; - } public byte [] marshal(Map table) throws IOException @@ -75,7 +59,7 @@ public Date secondDate() return new Date((System.currentTimeMillis()/1000)*1000); } - public void testLoop() + @Test public void loop() throws IOException { Map table = new HashMap(); diff --git a/src/test/java/com/rabbitmq/client/test/TruncatedInputStreamTest.java b/src/test/java/com/rabbitmq/client/test/TruncatedInputStreamTest.java index 7a1f62f53e..4409798a17 100644 --- a/src/test/java/com/rabbitmq/client/test/TruncatedInputStreamTest.java +++ b/src/test/java/com/rabbitmq/client/test/TruncatedInputStreamTest.java @@ -15,19 +15,21 @@ package com.rabbitmq.client.test; +import com.rabbitmq.client.impl.TruncatedInputStream; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; -import junit.framework.TestCase; -import junit.framework.TestSuite; - -import com.rabbitmq.client.impl.TruncatedInputStream; +import static org.junit.Assert.assertEquals; /** * Some basic (retroactive) tests for TruncatedInputStream. */ -public class TruncatedInputStreamTest extends TestCase { +public class TruncatedInputStreamTest { /** a sample truncated stream to run tests on */ private TruncatedInputStream _truncStream; @@ -38,28 +40,20 @@ public class TruncatedInputStreamTest extends TestCase { /** what length to truncate it to */ private static final int TRUNCATED_LENGTH = 3; - @Override protected void setUp() throws Exception { - super.setUp(); + @Before public void setUp() throws Exception { InputStream baseStream = new ByteArrayInputStream(TEST_BYTES); _truncStream = new TruncatedInputStream(baseStream, TRUNCATED_LENGTH); } - @Override protected void tearDown() throws Exception { + @After public void tearDown() throws Exception { _truncStream = null; - super.tearDown(); - } - - public static TestSuite suite() { - TestSuite suite = new TestSuite("truncStreams"); - suite.addTestSuite(TruncatedInputStreamTest.class); - return suite; } /** * Check the amount of data initially available is as it should be * @throws IOException if there is an I/O problem */ - public void testAmountInitiallyAvailable() throws IOException { + @Test public void amountInitiallyAvailable() throws IOException { assertEquals(TRUNCATED_LENGTH, _truncStream.available()); } @@ -67,7 +61,7 @@ public void testAmountInitiallyAvailable() throws IOException { * Check the data read from the truncated stream is as it should be * @throws IOException if there is an I/O problem */ - public void testReadTruncatedBytes() throws IOException { + @Test public void readTruncatedBytes() throws IOException { byte[] readBytes = new byte[TEST_BYTES.length]; int numRead = _truncStream.read(readBytes); assertEquals(TRUNCATED_LENGTH, numRead); @@ -81,7 +75,7 @@ public void testReadTruncatedBytes() throws IOException { * @throws IOException * */ - public void testSingleByteReads() throws IOException { + @Test public void singleByteReads() throws IOException { for (int i = 0; i < TRUNCATED_LENGTH; i++) { assertEquals(TEST_BYTES[i], _truncStream.read()); } @@ -95,7 +89,7 @@ public void testSingleByteReads() throws IOException { /** * Check reading a specified number of bytes at an offset gives the right result */ - public void testOffsetMultipleByteReads() throws IOException { + @Test public void offsetMultipleByteReads() throws IOException { byte[] readBytes = new byte[TEST_OFFSET + TEST_LENGTH]; _truncStream.read(readBytes, TEST_OFFSET, TEST_LENGTH); for (int i = 0; i < TEST_OFFSET; i++) { // check the array's initially blank... diff --git a/src/test/java/com/rabbitmq/client/test/ValueOrExceptionTest.java b/src/test/java/com/rabbitmq/client/test/ValueOrExceptionTest.java index 9f7d6e1753..3c2640d057 100644 --- a/src/test/java/com/rabbitmq/client/test/ValueOrExceptionTest.java +++ b/src/test/java/com/rabbitmq/client/test/ValueOrExceptionTest.java @@ -15,14 +15,14 @@ package com.rabbitmq.client.test; -import junit.framework.TestCase; -import junit.framework.TestSuite; - -import com.rabbitmq.utility.ValueOrException; import com.rabbitmq.utility.SensibleClone; +import com.rabbitmq.utility.ValueOrException; +import org.junit.Test; + +import static org.junit.Assert.*; -public class ValueOrExceptionTest extends TestCase { +public class ValueOrExceptionTest { public static class InsufficientMagicException extends Exception implements SensibleClone { /** Default for no check. */ @@ -37,15 +37,7 @@ public InsufficientMagicException sensibleClone() { } } - - public static TestSuite suite() - { - TestSuite suite = new TestSuite("valueOrEx"); - suite.addTestSuite(ValueOrExceptionTest.class); - return suite; - } - - public void testStoresValue() throws InsufficientMagicException { + @Test public void storesValue() throws InsufficientMagicException { Integer value = new Integer(3); ValueOrException valueOrEx = @@ -55,7 +47,7 @@ public void testStoresValue() throws InsufficientMagicException { assertTrue(returnedValue == value); } - public void testClonesException() { + @Test public void clonesException() { InsufficientMagicException exception = new InsufficientMagicException("dummy message"); ValueOrException valueOrEx diff --git a/src/test/java/com/rabbitmq/utility/IntAllocatorTests.java b/src/test/java/com/rabbitmq/utility/IntAllocatorTests.java index ba0f5a8633..96586f5686 100644 --- a/src/test/java/com/rabbitmq/utility/IntAllocatorTests.java +++ b/src/test/java/com/rabbitmq/utility/IntAllocatorTests.java @@ -15,14 +15,16 @@ package com.rabbitmq.utility; +import org.junit.Test; + import java.util.HashSet; import java.util.Iterator; import java.util.Random; import java.util.Set; -import junit.framework.TestCase; +import static org.junit.Assert.*; -public class IntAllocatorTests extends TestCase { +public class IntAllocatorTests { private static final int TEST_ITERATIONS = 50000; private static final int HI_RANGE = 100000; @@ -31,7 +33,7 @@ public class IntAllocatorTests extends TestCase { private final Random rand = new Random(70608L); - public void testReserveAndFree() throws Exception { + @Test public void reserveAndFree() throws Exception { Set set = new HashSet(); for (int i = 0; i < TEST_ITERATIONS; ++i) { int trial = getTrial(rand); @@ -49,7 +51,7 @@ public void testReserveAndFree() throws Exception { } } - public void testAllocateAndFree() throws Exception { + @Test public void allocateAndFree() throws Exception { Set set = new HashSet(); for (int i=0; i < TEST_ITERATIONS; ++i) { if (getBool(rand)) { @@ -70,7 +72,7 @@ public void testAllocateAndFree() throws Exception { } } - public void testToString() throws Exception { + @Test public void testToString() throws Exception { IntAllocator ibs = new IntAllocator(LO_RANGE, HI_RANGE); assertEquals("IntAllocator{allocated = []}", ibs.toString()); ibs.allocate(); @@ -81,7 +83,7 @@ public void testToString() throws Exception { ibs.reserve(i+2); } assertEquals("IntAllocator{allocated = [100, 200..202, 204..206, 208..210]}" - , ibs.toString()); + , ibs.toString()); } private static int extractOne(Set set) { From 7d3c254414c3dcb2df2a2b1b658b2251c7b4423b Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Thu, 25 Aug 2016 12:59:10 +0300 Subject: [PATCH 0239/2114] Remove a comment that's no longer needed --- .../java/com/rabbitmq/client/test/AbstractRMQTestSuite.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java b/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java index 95b6d1c7f3..6046671640 100644 --- a/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java +++ b/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java @@ -26,7 +26,7 @@ import com.rabbitmq.tools.Host; -public abstract class AbstractRMQTestSuite { //extends TestSuite { +public abstract class AbstractRMQTestSuite { private static final String DEFAULT_SSL_HOSTNAME = "localhost"; private static final int DEFAULT_SSL_PORT = 5671; From 6c1f49487b7d18a108a9e99b471441721bf81527 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 25 Aug 2016 15:51:31 +0200 Subject: [PATCH 0240/2114] Refactor functional/server/SSL tests to JUnit 4 Fixes #174 --- .../rabbitmq/client/impl/WorkPoolTests.java | 21 ++-- .../client/test/AMQBuilderApiTest.java | 15 ++- .../client/test/AbstractRMQTestSuite.java | 9 +- .../com/rabbitmq/client/test/AmqpUriTest.java | 11 +- .../rabbitmq/client/test/BrokerTestCase.java | 28 ++--- .../rabbitmq/client/test/Bug20004Test.java | 6 +- .../com/rabbitmq/client/test/ClientTests.java | 7 +- .../rabbitmq/client/test/CloseInMainLoop.java | 8 +- .../com/rabbitmq/client/test/ConfirmBase.java | 6 +- .../test/DnsRecordIpAddressResolverTests.java | 16 ++- .../client/test/MultiThreadedChannel.java | 6 +- .../test/QueueingConsumerShutdownTests.java | 6 +- .../client/test/RequiredPropertiesSuite.java | 44 +++++++ .../client/test/SharedThreadPoolTest.java | 11 +- .../test/functional/AbstractRejectTest.java | 16 ++- .../test/functional/AlternateExchange.java | 24 ++-- .../client/test/functional/BasicGet.java | 20 ++- .../test/functional/BindingLifecycle.java | 24 ++-- .../test/functional/BindingLifecycleBase.java | 9 +- .../client/test/functional/CcRoutes.java | 36 +++--- .../client/test/functional/Confirm.java | 36 +++--- .../test/functional/ConnectionOpen.java | 22 ++-- .../test/functional/ConnectionRecovery.java | 80 ++++++------ .../ConsumerCancelNotification.java | 25 ++-- .../client/test/functional/ConsumerCount.java | 10 +- .../test/functional/ConsumerPriorities.java | 21 ++-- .../test/functional/DeadLetterExchange.java | 78 ++++++------ .../test/functional/DefaultExchange.java | 18 +-- .../client/test/functional/DirectReplyTo.java | 20 ++- .../test/functional/DoubleDeletion.java | 6 +- .../test/functional/DurableOnTransient.java | 8 +- .../test/functional/ExceptionHandling.java | 24 ++-- .../test/functional/ExceptionMessages.java | 13 +- .../test/functional/ExchangeDeclare.java | 19 +-- .../functional/ExchangeDeleteIfUnused.java | 6 +- .../functional/ExchangeEquivalenceBase.java | 6 +- .../functional/ExchangeExchangeBindings.java | 18 +-- .../ExchangeExchangeBindingsAutoDelete.java | 12 +- .../client/test/functional/FrameMax.java | 25 +++- .../test/functional/FunctionalTests.java | 118 +++++++++--------- .../functional/HeadersExchangeValidation.java | 12 +- .../client/test/functional/Heartbeat.java | 8 +- .../test/functional/InternalExchange.java | 6 +- .../test/functional/InvalidAcksBase.java | 6 +- .../client/test/functional/MessageCount.java | 8 +- .../rabbitmq/client/test/functional/Nack.java | 11 +- .../test/functional/NoRequeueOnCancel.java | 9 +- .../test/functional/PerConsumerPrefetch.java | 28 +++-- .../client/test/functional/PerMessageTTL.java | 15 ++- .../client/test/functional/PerQueueTTL.java | 14 ++- .../functional/PerQueueVsPerMessageTTL.java | 8 +- .../client/test/functional/Policies.java | 36 +++--- .../client/test/functional/QosTests.java | 43 ++++--- .../test/functional/QueueExclusivity.java | 20 +-- .../client/test/functional/QueueLease.java | 26 ++-- .../test/functional/QueueLifecycle.java | 29 +++-- .../test/functional/QueueSizeLimit.java | 23 ++-- .../client/test/functional/Recover.java | 22 ++-- .../client/test/functional/Reject.java | 10 +- .../test/functional/RequeueOnClose.java | 24 ++-- .../client/test/functional/Routing.java | 35 +++--- .../test/functional/SaslMechanisms.java | 24 ++-- .../client/test/functional/TTLHandling.java | 33 +++-- .../client/test/functional/Tables.java | 25 ++-- .../client/test/functional/Transactions.java | 54 ++++---- .../functional/UnbindAutoDeleteExchange.java | 10 +- .../test/functional/UnexpectedFrames.java | 18 +-- .../client/test/functional/UserIDHeader.java | 16 ++- .../client/test/server/AbsentQueue.java | 11 +- .../server/AlternateExchangeEquivalence.java | 10 +- .../client/test/server/BlockedConnection.java | 14 +-- .../client/test/server/Bug19219Test.java | 12 +- .../test/server/ChannelLimitNegotiation.java | 24 ++-- .../server/DeadLetterExchangeDurable.java | 14 ++- .../test/server/DurableBindingLifecycle.java | 21 ++-- .../server/EffectVisibilityCrossNodeTest.java | 8 +- .../test/server/ExclusiveQueueDurability.java | 6 +- .../rabbitmq/client/test/server/Firehose.java | 13 +- .../rabbitmq/client/test/server/HATests.java | 48 +++---- .../client/test/server/LoopbackUsers.java | 24 ++-- .../client/test/server/MemoryAlarms.java | 13 +- .../client/test/server/MessageRecovery.java | 4 +- .../client/test/server/Permissions.java | 42 ++++--- .../test/server/PersistenceGuarantees.java | 12 +- .../client/test/server/PriorityQueues.java | 14 ++- .../client/test/server/ServerTests.java | 52 ++++---- .../rabbitmq/client/test/server/Shutdown.java | 9 +- .../test/server/XDeathHeaderGrowth.java | 19 +-- .../test/ssl/BadVerifiedConnection.java | 7 +- .../rabbitmq/client/test/ssl/SSLTests.java | 67 +++++++--- .../client/test/ssl/UnverifiedConnection.java | 6 +- .../client/test/ssl/VerifiedConnection.java | 3 +- 92 files changed, 1174 insertions(+), 740 deletions(-) create mode 100644 src/test/java/com/rabbitmq/client/test/RequiredPropertiesSuite.java diff --git a/src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java b/src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java index b0bd7653ca..90739f4206 100644 --- a/src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java +++ b/src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java @@ -15,15 +15,20 @@ package com.rabbitmq.client.impl; -import junit.framework.TestCase; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.List; +import org.junit.Test; + /** * Unit tests for {@link WorkPool} */ -public class WorkPoolTests extends TestCase { +public class WorkPoolTests { private final WorkPool pool = new WorkPool(); @@ -31,7 +36,7 @@ public class WorkPoolTests extends TestCase { * Test unknown key tolerated silently * @throws Exception untested */ - public void testUnknownKey() throws Exception{ + @Test public void unknownKey() throws Exception{ assertFalse(this.pool.addWorkItem("test", new Object())); } @@ -39,7 +44,7 @@ public void testUnknownKey() throws Exception{ * Test add work and remove work * @throws Exception untested */ - public void testBasicInOut() throws Exception { + @Test public void basicInOut() throws Exception { Object one = new Object(); Object two = new Object(); @@ -69,7 +74,7 @@ public void testBasicInOut() throws Exception { * Test add work when work in progress. * @throws Exception untested */ - public void testWorkInWhileInProgress() throws Exception { + @Test public void workInWhileInProgress() throws Exception { Object one = new Object(); Object two = new Object(); @@ -97,7 +102,7 @@ public void testWorkInWhileInProgress() throws Exception { * Test multiple work keys. * @throws Exception untested */ - public void testInterleavingKeys() throws Exception { + @Test public void interleavingKeys() throws Exception { Object one = new Object(); Object two = new Object(); Object three = new Object(); @@ -128,7 +133,7 @@ public void testInterleavingKeys() throws Exception { * Test removal of key (with work) * @throws Exception untested */ - public void testUnregisterKey() throws Exception { + @Test public void unregisterKey() throws Exception { Object one = new Object(); Object two = new Object(); Object three = new Object(); @@ -153,7 +158,7 @@ public void testUnregisterKey() throws Exception { * Test removal of all keys (with work). * @throws Exception untested */ - public void testUnregisterAllKeys() throws Exception { + @Test public void unregisterAllKeys() throws Exception { Object one = new Object(); Object two = new Object(); Object three = new Object(); diff --git a/src/test/java/com/rabbitmq/client/test/AMQBuilderApiTest.java b/src/test/java/com/rabbitmq/client/test/AMQBuilderApiTest.java index 4a9ec8f430..27a3f5b304 100644 --- a/src/test/java/com/rabbitmq/client/test/AMQBuilderApiTest.java +++ b/src/test/java/com/rabbitmq/client/test/AMQBuilderApiTest.java @@ -14,16 +14,21 @@ // info@rabbitmq.com. package com.rabbitmq.client.test; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.Method; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.io.IOException; +import org.junit.Test; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Method; + public class AMQBuilderApiTest extends BrokerTestCase { private static final String XCHG_NAME = "builder_test_xchg"; - public void testParticularBuilderForBasicSanityWithRpc() throws IOException + @Test public void particularBuilderForBasicSanityWithRpc() throws IOException { Method retVal = channel.rpc(new AMQP.Exchange.Declare.Builder() @@ -45,7 +50,7 @@ public void testParticularBuilderForBasicSanityWithRpc() throws IOException assertTrue(retVal instanceof AMQP.Exchange.DeleteOk); } - public void testParticularBuilderForBasicSanityWithAsyncRpc() throws IOException + @Test public void particularBuilderForBasicSanityWithAsyncRpc() throws IOException { channel.asyncRpc(new AMQP.Exchange.Declare.Builder() .exchange(XCHG_NAME) @@ -64,7 +69,7 @@ public void testParticularBuilderForBasicSanityWithAsyncRpc() throws IOException assertTrue("Channel should still be open.", channel.isOpen()); } - public void testIllFormedBuilder() + @Test public void illFormedBuilder() { try { diff --git a/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java b/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java index 6046671640..bafbc6f739 100644 --- a/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java +++ b/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java @@ -15,18 +15,15 @@ package com.rabbitmq.client.test; +import com.rabbitmq.tools.Host; + import java.io.File; import java.io.IOException; import java.net.Socket; import java.util.Properties; -import junit.framework.Test; -import junit.framework.TestResult; -import junit.framework.TestSuite; - -import com.rabbitmq.tools.Host; - public abstract class AbstractRMQTestSuite { + private static final String DEFAULT_SSL_HOSTNAME = "localhost"; private static final int DEFAULT_SSL_PORT = 5671; diff --git a/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java b/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java index db68cfa3f9..62c49b64a9 100644 --- a/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java +++ b/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java @@ -14,15 +14,20 @@ // info@rabbitmq.com. package com.rabbitmq.client.test; -import com.rabbitmq.client.ConnectionFactory; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import java.net.URISyntaxException; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; -import java.net.URISyntaxException; + +import org.junit.Test; + +import com.rabbitmq.client.ConnectionFactory; public class AmqpUriTest extends BrokerTestCase { - public void testUriParsing() + @Test public void uriParsing() throws URISyntaxException, NoSuchAlgorithmException, KeyManagementException { /* From the spec (subset of the tests) */ diff --git a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java index 60edba206b..4fd4198d68 100644 --- a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java +++ b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java @@ -16,6 +16,12 @@ package com.rabbitmq.client.test; +import com.rabbitmq.client.*; +import com.rabbitmq.tools.Host; +import org.junit.After; +import org.junit.Before; + +import javax.net.ssl.SSLContext; import java.io.IOException; import java.security.NoSuchAlgorithmException; import java.util.Arrays; @@ -23,24 +29,10 @@ import java.util.UUID; import java.util.concurrent.TimeoutException; -import junit.framework.TestCase; - -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.Command; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.ConnectionFactory; -import com.rabbitmq.client.GetResponse; -import com.rabbitmq.client.MessageProperties; -import com.rabbitmq.client.Method; -import com.rabbitmq.client.ShutdownSignalException; -import com.rabbitmq.client.AlreadyClosedException; -import com.rabbitmq.client.impl.ShutdownNotifierComponent; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.tools.Host; +import static org.junit.Assert.*; -import javax.net.ssl.SSLContext; +public class BrokerTestCase { -public class BrokerTestCase extends TestCase { protected ConnectionFactory connectionFactory = newConnectionFactory(); protected ConnectionFactory newConnectionFactory() { @@ -50,7 +42,7 @@ protected ConnectionFactory newConnectionFactory() { protected Connection connection; protected Channel channel; - protected void setUp() + @Before public void setUp() throws IOException, TimeoutException { openConnection(); openChannel(); @@ -58,7 +50,7 @@ protected void setUp() createResources(); } - protected void tearDown() + @After public void tearDown() throws IOException, TimeoutException { closeChannel(); closeConnection(); diff --git a/src/test/java/com/rabbitmq/client/test/Bug20004Test.java b/src/test/java/com/rabbitmq/client/test/Bug20004Test.java index 86288f3582..58581f076f 100644 --- a/src/test/java/com/rabbitmq/client/test/Bug20004Test.java +++ b/src/test/java/com/rabbitmq/client/test/Bug20004Test.java @@ -15,8 +15,12 @@ package com.rabbitmq.client.test; +import org.junit.Test; + import java.io.IOException; +import static org.junit.Assert.*; + /** * Test for bug 20004 - deadlock through internal synchronization on * the channel object. This is more properly a unit test, but since it @@ -40,7 +44,7 @@ protected void releaseResources() } @SuppressWarnings("deprecation") - public void testBug20004() throws IOException + @Test public void bug20004() throws IOException { final Bug20004Test testInstance = this; diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index d81103f3c2..db845a73ee 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -41,6 +41,11 @@ JSONReadWriteTest.class, SharedThreadPoolTest.class }) -public class ClientTests extends AbstractRMQTestSuite { +public class ClientTests { + + // initialize system properties + static{ + new AbstractRMQTestSuite(){}; + } } diff --git a/src/test/java/com/rabbitmq/client/test/CloseInMainLoop.java b/src/test/java/com/rabbitmq/client/test/CloseInMainLoop.java index d21b5e93af..3a832b0ff1 100644 --- a/src/test/java/com/rabbitmq/client/test/CloseInMainLoop.java +++ b/src/test/java/com/rabbitmq/client/test/CloseInMainLoop.java @@ -15,6 +15,8 @@ package com.rabbitmq.client.test; +import static org.junit.Assert.assertTrue; + import java.io.IOException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executors; @@ -23,6 +25,8 @@ import javax.net.SocketFactory; +import org.junit.Test; + import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Command; @@ -87,7 +91,7 @@ public boolean processControlCommand(Command c) throws IOException{ } } - public void testCloseOKNormallyReceived() throws Exception{ + @Test public void closeOKNormallyReceived() throws Exception{ SpecialConnection connection = new SpecialConnection(); connection.close(); assertTrue(connection.hadValidShutdown()); @@ -95,7 +99,7 @@ public void testCloseOKNormallyReceived() throws Exception{ // The thrown runtime exception should get intercepted by the // consumer exception handler, and result in a clean shut down. - public void testCloseWithFaultyConsumer() throws Exception{ + @Test public void closeWithFaultyConsumer() throws Exception{ SpecialConnection connection = new SpecialConnection(); Channel channel = connection.createChannel(); channel.exchangeDeclare("x", "direct"); diff --git a/src/test/java/com/rabbitmq/client/test/ConfirmBase.java b/src/test/java/com/rabbitmq/client/test/ConfirmBase.java index b712239d26..099f8e8d04 100644 --- a/src/test/java/com/rabbitmq/client/test/ConfirmBase.java +++ b/src/test/java/com/rabbitmq/client/test/ConfirmBase.java @@ -15,14 +15,16 @@ package com.rabbitmq.client.test; -import com.rabbitmq.client.ShutdownSignalException; +import static org.junit.Assert.fail; import java.io.IOException; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; import java.util.concurrent.FutureTask; -import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import com.rabbitmq.client.ShutdownSignalException; import junit.framework.AssertionFailedError; diff --git a/src/test/java/com/rabbitmq/client/test/DnsRecordIpAddressResolverTests.java b/src/test/java/com/rabbitmq/client/test/DnsRecordIpAddressResolverTests.java index 098241c42c..01459cfb29 100644 --- a/src/test/java/com/rabbitmq/client/test/DnsRecordIpAddressResolverTests.java +++ b/src/test/java/com/rabbitmq/client/test/DnsRecordIpAddressResolverTests.java @@ -1,18 +1,22 @@ package com.rabbitmq.client.test; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.ConnectionFactory; -import com.rabbitmq.client.DnsRecordIpAddressResolver; +import static org.junit.Assert.fail; import java.io.IOException; import java.util.concurrent.TimeoutException; +import org.junit.Test; + +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.DnsRecordIpAddressResolver; + /** * */ public class DnsRecordIpAddressResolverTests extends BrokerTestCase { - public void testLocalhostResolution() throws IOException, TimeoutException { + @Test public void localhostResolution() throws IOException, TimeoutException { DnsRecordIpAddressResolver addressResolver = new DnsRecordIpAddressResolver("localhost"); ConnectionFactory connectionFactory = newConnectionFactory(); Connection connection = connectionFactory.newConnection(addressResolver); @@ -23,7 +27,7 @@ public void testLocalhostResolution() throws IOException, TimeoutException { } } - public void testLoopbackInterfaceResolution() throws IOException, TimeoutException { + @Test public void loopbackInterfaceResolution() throws IOException, TimeoutException { DnsRecordIpAddressResolver addressResolver = new DnsRecordIpAddressResolver("127.0.0.1"); ConnectionFactory connectionFactory = newConnectionFactory(); Connection connection = connectionFactory.newConnection(addressResolver); @@ -34,7 +38,7 @@ public void testLoopbackInterfaceResolution() throws IOException, TimeoutExcepti } } - public void testResolutionFails() throws IOException, TimeoutException { + @Test public void resolutionFails() throws IOException, TimeoutException { DnsRecordIpAddressResolver addressResolver = new DnsRecordIpAddressResolver( "afancyandunlikelyhostname" ); diff --git a/src/test/java/com/rabbitmq/client/test/MultiThreadedChannel.java b/src/test/java/com/rabbitmq/client/test/MultiThreadedChannel.java index 96ee123215..d583a03b4a 100644 --- a/src/test/java/com/rabbitmq/client/test/MultiThreadedChannel.java +++ b/src/test/java/com/rabbitmq/client/test/MultiThreadedChannel.java @@ -15,10 +15,10 @@ package com.rabbitmq.client.test; -import com.rabbitmq.client.test.BrokerTestCase; - import java.util.concurrent.atomic.AtomicReference; +import org.junit.Test; + /** * Tests whether a Channel is safe for multi-threaded access */ @@ -28,7 +28,7 @@ public class MultiThreadedChannel extends BrokerTestCase { private static final String DUMMY_EXCHANGE_NAME = "dummy.exchange"; - public void testInterleavedRpcs() throws Throwable { + @Test public void interleavedRpcs() throws Throwable { final AtomicReference throwableRef = new AtomicReference(null); diff --git a/src/test/java/com/rabbitmq/client/test/QueueingConsumerShutdownTests.java b/src/test/java/com/rabbitmq/client/test/QueueingConsumerShutdownTests.java index a0e249579a..143b2947e2 100644 --- a/src/test/java/com/rabbitmq/client/test/QueueingConsumerShutdownTests.java +++ b/src/test/java/com/rabbitmq/client/test/QueueingConsumerShutdownTests.java @@ -15,6 +15,10 @@ package com.rabbitmq.client.test; +import static org.junit.Assert.*; +import org.junit.Test; + + import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @@ -27,7 +31,7 @@ public class QueueingConsumerShutdownTests extends BrokerTestCase{ static final String QUEUE = "some-queue"; static final int THREADS = 5; - public void testNThreadShutdown() throws Exception{ + @Test public void nThreadShutdown() throws Exception{ Channel channel = connection.createChannel(); final QueueingConsumer c = new QueueingConsumer(channel); channel.queueDeclare(QUEUE, false, true, true, null); diff --git a/src/test/java/com/rabbitmq/client/test/RequiredPropertiesSuite.java b/src/test/java/com/rabbitmq/client/test/RequiredPropertiesSuite.java new file mode 100644 index 0000000000..b97a0b0af6 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/RequiredPropertiesSuite.java @@ -0,0 +1,44 @@ +package com.rabbitmq.client.test; + +import org.junit.runner.Runner; +import org.junit.runners.Suite; +import org.junit.runners.model.InitializationError; +import org.junit.runners.model.RunnerBuilder; + +import java.util.ArrayList; +import java.util.List; + +/** + * + */ +public class RequiredPropertiesSuite extends Suite { + + public RequiredPropertiesSuite(Class klass, RunnerBuilder builder) throws InitializationError { + super(klass, builder); + } + + public RequiredPropertiesSuite(RunnerBuilder builder, Class[] classes) throws InitializationError { + super(builder, classes); + } + + protected RequiredPropertiesSuite(Class klass, Class[] suiteClasses) throws InitializationError { + super(klass, suiteClasses); + } + + protected RequiredPropertiesSuite(RunnerBuilder builder, Class klass, Class[] suiteClasses) throws InitializationError { + super(builder, klass, suiteClasses); + } + + protected RequiredPropertiesSuite(Class klass, List runners) throws InitializationError { + super(klass, runners); + } + + @Override + protected List getChildren() { + if(!AbstractRMQTestSuite.requiredProperties()) { + return new ArrayList(); + } else { + return super.getChildren(); + } + } +} diff --git a/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java b/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java index c709d0e9f7..499d2de0f6 100644 --- a/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java +++ b/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java @@ -15,16 +15,21 @@ package com.rabbitmq.client.test; -import com.rabbitmq.client.ConnectionFactory; -import com.rabbitmq.client.impl.AMQConnection; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import java.io.IOException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeoutException; +import org.junit.Test; + +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.impl.AMQConnection; + public class SharedThreadPoolTest extends BrokerTestCase { - public void testWillShutDownExecutor() throws IOException, TimeoutException { + @Test public void willShutDownExecutor() throws IOException, TimeoutException { ConnectionFactory cf = new ConnectionFactory(); ExecutorService executor = Executors.newFixedThreadPool(8); cf.setSharedExecutor(executor); diff --git a/src/test/java/com/rabbitmq/client/test/functional/AbstractRejectTest.java b/src/test/java/com/rabbitmq/client/test/functional/AbstractRejectTest.java index 50d3a18868..9d58d590de 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/AbstractRejectTest.java +++ b/src/test/java/com/rabbitmq/client/test/functional/AbstractRejectTest.java @@ -16,22 +16,26 @@ package com.rabbitmq.client.test.functional; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.util.Arrays; +import java.util.concurrent.TimeoutException; + import com.rabbitmq.client.Channel; import com.rabbitmq.client.Envelope; import com.rabbitmq.client.GetResponse; import com.rabbitmq.client.QueueingConsumer; import com.rabbitmq.client.test.BrokerTestCase; -import java.io.IOException; -import java.util.Arrays; -import java.util.concurrent.TimeoutException; - abstract class AbstractRejectTest extends BrokerTestCase { protected Channel secondaryChannel; @Override - protected void setUp() + public void setUp() throws IOException, TimeoutException { super.setUp(); secondaryChannel = connection.createChannel(); @@ -39,7 +43,7 @@ protected void setUp() } @Override - protected void tearDown() + public void tearDown() throws IOException, TimeoutException { if (secondaryChannel != null) { secondaryChannel.abort(); diff --git a/src/test/java/com/rabbitmq/client/test/functional/AlternateExchange.java b/src/test/java/com/rabbitmq/client/test/functional/AlternateExchange.java index 794b19f0cd..b408cffca0 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/AlternateExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/AlternateExchange.java @@ -16,16 +16,20 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.test.BrokerTestCase; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.ReturnListener; -import com.rabbitmq.client.GetResponse; +import static org.junit.Assert.assertEquals; import java.io.IOException; +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.Map; -import java.util.HashMap; + +import org.junit.Test; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.GetResponse; +import com.rabbitmq.client.ReturnListener; +import com.rabbitmq.client.test.BrokerTestCase; public class AlternateExchange extends BrokerTestCase { @@ -55,7 +59,7 @@ private static boolean[] expected(String key) { return expected; } - @Override protected void setUp() throws IOException, TimeoutException { + @Override public void setUp() throws IOException, TimeoutException { super.setUp(); channel.addReturnListener(new ReturnListener() { public void handleReturn(int replyCode, @@ -177,7 +181,7 @@ protected void check(String key, boolean ret) throws IOException { * check various cases of missing AEs - we expect to see some * warnings in the server logs */ - public void testMissing() throws IOException { + @Test public void missing() throws IOException { setupRouting("x", "u"); check("x", false); //no warning check("u", unrouted, false); //warning @@ -193,7 +197,7 @@ public void testMissing() throws IOException { cleanup(); } - public void testAe() throws IOException { + @Test public void ae() throws IOException { setupRouting(); for (String k : keys) { @@ -206,7 +210,7 @@ public void testAe() throws IOException { cleanup(); } - public void testCycleBreaking() throws IOException { + @Test public void cycleBreaking() throws IOException { setupRouting(); check("z", false); cleanup(); diff --git a/src/test/java/com/rabbitmq/client/test/functional/BasicGet.java b/src/test/java/com/rabbitmq/client/test/functional/BasicGet.java index c110c7f987..dddd17e8d6 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/BasicGet.java +++ b/src/test/java/com/rabbitmq/client/test/functional/BasicGet.java @@ -15,15 +15,23 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.AlreadyClosedException; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.io.IOException; import java.util.concurrent.TimeoutException; +import org.junit.Test; + +import com.rabbitmq.client.AlreadyClosedException; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.test.BrokerTestCase; + public class BasicGet extends BrokerTestCase { - public void testBasicGetWithEnqueuedMessages() throws IOException, InterruptedException { + @Test public void basicGetWithEnqueuedMessages() throws IOException, InterruptedException { assertTrue(channel.isOpen()); String q = channel.queueDeclare().getQueue(); @@ -36,7 +44,7 @@ public void testBasicGetWithEnqueuedMessages() throws IOException, InterruptedEx channel.queueDelete(q); } - public void testBasicGetWithEmptyQueue() throws IOException, InterruptedException { + @Test public void basicGetWithEmptyQueue() throws IOException, InterruptedException { assertTrue(channel.isOpen()); String q = channel.queueDeclare().getQueue(); @@ -44,7 +52,7 @@ public void testBasicGetWithEmptyQueue() throws IOException, InterruptedExceptio channel.queueDelete(q); } - public void testBasicGetWithClosedChannel() throws IOException, InterruptedException, TimeoutException { + @Test public void basicGetWithClosedChannel() throws IOException, InterruptedException, TimeoutException { assertTrue(channel.isOpen()); String q = channel.queueDeclare().getQueue(); diff --git a/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java b/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java index 2c155d579b..0090d40a45 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java +++ b/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java @@ -16,9 +16,17 @@ package com.rabbitmq.client.test.functional; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + import java.io.IOException; import java.util.concurrent.TimeoutException; +import org.junit.Test; + import com.rabbitmq.client.AMQP; import com.rabbitmq.client.GetResponse; @@ -36,7 +44,7 @@ public class BindingLifecycle extends BindingLifecycleBase { /** * This tests that when you purge a queue, all of its messages go. */ - public void testQueuePurge() throws IOException { + @Test public void queuePurge() throws IOException { Binding binding = setupExchangeBindings(false); channel.basicPublish(binding.x, binding.k, null, payload); @@ -57,7 +65,7 @@ public void testQueuePurge() throws IOException { * (Tx-)transacted." */ @SuppressWarnings("deprecation") - public void testUnackedPurge() throws IOException { + @Test public void unackedPurge() throws IOException { Binding binding = setupExchangeBindings(false); channel.basicPublish(binding.x, binding.k, null, payload); @@ -89,7 +97,7 @@ public void testUnackedPurge() throws IOException { * This tests whether when you delete an exchange, that any * bindings attached to it are deleted as well. */ - public void testExchangeDelete() throws IOException { + @Test public void exchangeDelete() throws IOException { boolean durable = true; Binding binding = setupExchangeAndRouteMessage(true); @@ -113,7 +121,7 @@ public void testExchangeDelete() throws IOException { * To test this, you try to delete an exchange with a queue still * bound to it and expect the delete operation to fail. */ - public void testExchangeIfUnused() throws IOException { + @Test public void exchangeIfUnused() throws IOException { boolean durable = true; Binding binding = setupExchangeBindings(true); @@ -150,7 +158,7 @@ public void testExchangeIfUnused() throws IOException { * Because the exchange has been auto-deleted, the bind operation * should fail. */ - public void testExchangeAutoDelete() throws IOException, TimeoutException { + @Test public void exchangeAutoDelete() throws IOException, TimeoutException { doAutoDelete(false, 1); } @@ -161,14 +169,14 @@ public void testExchangeAutoDelete() throws IOException, TimeoutException { * The difference should be that the original exchange should not * get auto-deleted */ - public void testExchangeAutoDeleteManyBindings() throws IOException, TimeoutException { + @Test public void exchangeAutoDeleteManyBindings() throws IOException, TimeoutException { doAutoDelete(false, 10); } /** * */ - public void testExchangePassiveDeclare() throws IOException { + @Test public void exchangePassiveDeclare() throws IOException { channel.exchangeDeclare("testPassive", "direct"); channel.exchangeDeclarePassive("testPassive"); @@ -184,7 +192,7 @@ public void testExchangePassiveDeclare() throws IOException { /** * Test the behaviour of queue.unbind */ - public void testUnbind() throws Exception { + @Test public void unbind() throws Exception { for (String exchange: new String[]{"amq.fanout", "amq.direct", "amq.topic", "amq.headers"}) { testUnbind(exchange); } diff --git a/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycleBase.java b/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycleBase.java index 0ff9be86ef..bb5f24c634 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycleBase.java +++ b/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycleBase.java @@ -16,11 +16,16 @@ package com.rabbitmq.client.test.functional; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.util.concurrent.TimeoutException; + import com.rabbitmq.client.AMQP; import com.rabbitmq.client.GetResponse; import com.rabbitmq.client.QueueingConsumer; -import java.io.IOException; -import java.util.concurrent.TimeoutException; /** * This tests whether bindings are created and nuked properly. diff --git a/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java b/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java index 6b2db8320f..8d0136419c 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java +++ b/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java @@ -15,19 +15,27 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.AMQP.BasicProperties; -import com.rabbitmq.client.GetResponse; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; import java.io.IOException; import java.util.ArrayList; -import java.util.HashMap; import java.util.Arrays; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.TimeoutException; +import org.junit.Test; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.AMQP.BasicProperties; +import com.rabbitmq.client.GetResponse; +import com.rabbitmq.client.test.BrokerTestCase; + public class CcRoutes extends BrokerTestCase { static private final String[] queues = new String[]{"queue1", "queue2", "queue3"}; @@ -38,7 +46,7 @@ public class CcRoutes extends BrokerTestCase { protected List ccList; protected List bccList; - @Override protected void setUp() throws IOException, TimeoutException { + @Override public void setUp() throws IOException, TimeoutException { super.setUp(); propsBuilder = new BasicProperties.Builder(); headers = new HashMap(); @@ -55,26 +63,26 @@ public class CcRoutes extends BrokerTestCase { channel.exchangeDeclare(exTopic, "topic", false, true, null); } - public void testCcList() throws IOException { + @Test public void ccList() throws IOException { ccList.add("queue2"); ccList.add("queue3"); headerPublish("", "queue1", ccList, null); expect(new String []{"queue1", "queue2", "queue3"}, true); } - public void testCcIgnoreEmptyAndInvalidRoutes() throws IOException { + @Test public void ccIgnoreEmptyAndInvalidRoutes() throws IOException { bccList.add("frob"); headerPublish("", "queue1", ccList, bccList); expect(new String []{"queue1"}, true); } - public void testBcc() throws IOException { + @Test public void bcc() throws IOException { bccList.add("queue2"); headerPublish("", "queue1", null, bccList); expect(new String []{"queue1", "queue2"}, false); } - public void testNoDuplicates() throws IOException { + @Test public void noDuplicates() throws IOException { ccList.add("queue1"); ccList.add("queue1"); bccList.add("queue1"); @@ -82,20 +90,20 @@ public void testNoDuplicates() throws IOException { expect(new String[] {"queue1"}, true); } - public void testDirectExchangeWithoutBindings() throws IOException { + @Test public void directExchangeWithoutBindings() throws IOException { ccList.add("queue1"); headerPublish(exDirect, "queue2", ccList, null); expect(new String[] {}, true); } - public void testTopicExchange() throws IOException { + @Test public void topicExchange() throws IOException { ccList.add("routing_key"); channel.queueBind("queue2", exTopic, "routing_key"); headerPublish(exTopic, "", ccList, null); expect(new String[] {"queue2"}, true); } - public void testBoundExchanges() throws IOException { + @Test public void boundExchanges() throws IOException { ccList.add("routing_key1"); bccList.add("routing_key2"); channel.exchangeBind(exTopic, exDirect, "routing_key1"); @@ -104,7 +112,7 @@ public void testBoundExchanges() throws IOException { expect(new String[] {"queue2"}, true); } - public void testNonArray() throws IOException { + @Test public void nonArray() throws IOException { headers.put("CC", 0); propsBuilder.headers(headers); channel.basicPublish("", "queue1", propsBuilder.build(), new byte[0]); diff --git a/src/test/java/com/rabbitmq/client/test/functional/Confirm.java b/src/test/java/com/rabbitmq/client/test/functional/Confirm.java index ef56719774..20adb70886 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Confirm.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Confirm.java @@ -16,6 +16,10 @@ package com.rabbitmq.client.test.functional; +import static org.junit.Assert.*; +import org.junit.Test; + + import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; import com.rabbitmq.client.ConfirmListener; @@ -39,7 +43,7 @@ public class Confirm extends BrokerTestCase private static final String TTL_ARG = "x-message-ttl"; @Override - protected void setUp() throws IOException, TimeoutException { + public void setUp() throws IOException, TimeoutException { super.setUp(); channel.confirmSelect(); channel.queueDeclare("confirm-test", true, true, false, null); @@ -62,7 +66,7 @@ protected void setUp() throws IOException, TimeoutException { "confirm-multiple-queues"); } - public void testPersistentMandatoryCombinations() + @Test public void persistentMandatoryCombinations() throws IOException, InterruptedException, TimeoutException { boolean b[] = { false, true }; for (boolean persistent : b) { @@ -72,18 +76,18 @@ public void testPersistentMandatoryCombinations() } } - public void testNonDurable() + @Test public void nonDurable() throws IOException, InterruptedException, TimeoutException { confirmTest("", "confirm-test-nondurable", true, false); } - public void testMandatoryNoRoute() + @Test public void mandatoryNoRoute() throws IOException, InterruptedException, TimeoutException { confirmTest("", "confirm-test-doesnotexist", false, true); confirmTest("", "confirm-test-doesnotexist", true, true); } - public void testMultipleQueues() + @Test public void multipleQueues() throws IOException, InterruptedException, TimeoutException { confirmTest("amq.direct", "confirm-multiple-queues", true, false); } @@ -93,7 +97,7 @@ public void testMultipleQueues() * (thus causing a confirm). I'd manually comment out the line in * internal_sync that notifies the clients. */ - public void testQueueDelete() + @Test public void queueDelete() throws IOException, InterruptedException, TimeoutException { publishN("","confirm-test-noconsumer", true, false); @@ -102,7 +106,7 @@ public void testQueueDelete() channel.waitForConfirmsOrDie(60000); } - public void testQueuePurge() + @Test public void queuePurge() throws IOException, InterruptedException, TimeoutException { publishN("", "confirm-test-noconsumer", true, false); @@ -112,7 +116,7 @@ public void testQueuePurge() } /* Tests rabbitmq-server #854 */ - public void testConfirmQueuePurge() + @Test public void confirmQueuePurge() throws IOException, InterruptedException, TimeoutException { channel.basicQos(1); for (int i = 0; i < 20000; i++) { @@ -124,14 +128,14 @@ public void testConfirmQueuePurge() channel.waitForConfirmsOrDie(90000); } - public void testBasicReject() + @Test public void basicReject() throws IOException, InterruptedException, TimeoutException { basicRejectCommon(false); channel.waitForConfirmsOrDie(60000); } - public void testQueueTTL() + @Test public void queueTTL() throws IOException, InterruptedException, TimeoutException { for (int ttl : new int[]{ 1, 0 }) { Map argMap = @@ -145,7 +149,7 @@ public void testQueueTTL() } } - public void testBasicRejectRequeue() + @Test public void basicRejectRequeue() throws IOException, InterruptedException, TimeoutException { basicRejectCommon(true); @@ -158,7 +162,7 @@ public void testBasicRejectRequeue() channel.waitForConfirmsOrDie(60000); } - public void testBasicRecover() + @Test public void basicRecover() throws IOException, InterruptedException, TimeoutException { publishN("", "confirm-test-noconsumer", true, false); @@ -179,7 +183,7 @@ public void testBasicRecover() channel.waitForConfirmsOrDie(60000); } - public void testSelect() + @Test public void select() throws IOException { channel.confirmSelect(); @@ -201,7 +205,7 @@ public void testSelect() } } - public void testWaitForConfirms() + @Test public void waitForConfirms() throws IOException, InterruptedException, TimeoutException { final SortedSet unconfirmedSet = Collections.synchronizedSortedSet(new TreeSet()); @@ -233,7 +237,7 @@ public void handleNack(long seqNo, boolean multiple) { } } - public void testWaitForConfirmsWithoutConfirmSelected() + @Test public void waitForConfirmsWithoutConfirmSelected() throws IOException, InterruptedException { channel = connection.createChannel(); @@ -247,7 +251,7 @@ public void testWaitForConfirmsWithoutConfirmSelected() } } - public void testWaitForConfirmsException() + @Test public void waitForConfirmsException() throws IOException, InterruptedException, TimeoutException { publishN("", "confirm-test", true, false); channel.close(); diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionOpen.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionOpen.java index b53e347f10..0cc3f2a2dd 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionOpen.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionOpen.java @@ -16,26 +16,30 @@ package com.rabbitmq.client.test.functional; -import java.io.IOException; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + import java.io.DataInputStream; +import java.io.IOException; import java.net.Socket; import java.util.concurrent.TimeoutException; +import org.junit.Test; + import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.MalformedFrameException; import com.rabbitmq.client.Method; -import com.rabbitmq.client.impl.SocketFrameHandler; import com.rabbitmq.client.impl.AMQCommand; -import com.rabbitmq.client.ConnectionFactory; - -import junit.framework.TestCase; +import com.rabbitmq.client.impl.SocketFrameHandler; /** * Check that protocol negotiation works */ -public class ConnectionOpen extends TestCase { - public void testCorrectProtocolHeader() throws IOException { +public class ConnectionOpen { + @Test public void correctProtocolHeader() throws IOException { ConnectionFactory factory = new ConnectionFactory(); SocketFrameHandler fh = new SocketFrameHandler(factory.getSocketFactory().createSocket("localhost", AMQP.PROTOCOL.PORT)); fh.sendHeader(); @@ -52,7 +56,7 @@ public void testCorrectProtocolHeader() throws IOException { start.getVersionMinor() <= AMQP.PROTOCOL.MINOR)); } - public void testCrazyProtocolHeader() throws IOException { + @Test public void crazyProtocolHeader() throws IOException { ConnectionFactory factory = new ConnectionFactory(); // keep the frame handler's socket Socket fhSocket = factory.getSocketFactory().createSocket("localhost", AMQP.PROTOCOL.PORT); @@ -84,7 +88,7 @@ public void testCrazyProtocolHeader() throws IOException { } } - public void testFrameMaxLessThanFrameMinSize() throws IOException, TimeoutException { + @Test public void frameMaxLessThanFrameMinSize() throws IOException, TimeoutException { ConnectionFactory factory = new ConnectionFactory(); factory.setRequestedFrameMax(100); try { diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java index a7dbd7b6cb..be11fba332 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -18,17 +18,16 @@ import com.rabbitmq.client.*; import com.rabbitmq.client.impl.recovery.AutorecoveringChannel; import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; -import com.rabbitmq.client.Recoverable; -import com.rabbitmq.client.RecoveryListener; import com.rabbitmq.client.impl.recovery.ConsumerRecoveryListener; import com.rabbitmq.client.impl.recovery.QueueRecoveryListener; import com.rabbitmq.client.test.BrokerTestCase; import com.rabbitmq.tools.Host; +import org.junit.Test; import java.io.IOException; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.ArrayList; import java.util.UUID; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -36,16 +35,19 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; +import static org.junit.Assert.*; + +@SuppressWarnings("ThrowFromFinallyBlock") public class ConnectionRecovery extends BrokerTestCase { public static final long RECOVERY_INTERVAL = 2000; - public void testConnectionRecovery() throws IOException, InterruptedException { + @Test public void connectionRecovery() throws IOException, InterruptedException { assertTrue(connection.isOpen()); closeAndWaitForRecovery(); assertTrue(connection.isOpen()); } - public void testNamedConnectionRecovery() + @Test public void namedConnectionRecovery() throws IOException, InterruptedException, TimeoutException { String connectionName = "custom name"; AutorecoveringConnection c = newRecoveringConnection(connectionName); @@ -60,13 +62,13 @@ public void testNamedConnectionRecovery() } } - public void testConnectionRecoveryWithServerRestart() throws IOException, InterruptedException { + @Test public void connectionRecoveryWithServerRestart() throws IOException, InterruptedException { assertTrue(connection.isOpen()); restartPrimaryAndWaitForRecovery(); assertTrue(connection.isOpen()); } - public void testConnectionRecoveryWithArrayOfAddresses() + @Test public void connectionRecoveryWithArrayOfAddresses() throws IOException, InterruptedException, TimeoutException { final Address[] addresses = {new Address("127.0.0.1"), new Address("127.0.0.1", 5672)}; AutorecoveringConnection c = newRecoveringConnection(addresses); @@ -80,7 +82,7 @@ public void testConnectionRecoveryWithArrayOfAddresses() } - public void testConnectionRecoveryWithListOfAddresses() + @Test public void connectionRecoveryWithListOfAddresses() throws IOException, InterruptedException, TimeoutException { final List
addresses = Arrays.asList(new Address("127.0.0.1"), new Address("127.0.0.1", 5672)); @@ -95,7 +97,7 @@ public void testConnectionRecoveryWithListOfAddresses() } } - public void testConnectionRecoveryWithDisabledTopologyRecovery() + @Test public void connectionRecoveryWithDisabledTopologyRecovery() throws IOException, InterruptedException, TimeoutException { AutorecoveringConnection c = newRecoveringConnection(true); Channel ch = c.createChannel(); @@ -119,7 +121,7 @@ public void testConnectionRecoveryWithDisabledTopologyRecovery() } } - public void testShutdownHooksRecoveryOnConnection() throws IOException, InterruptedException { + @Test public void shutdownHooksRecoveryOnConnection() throws IOException, InterruptedException { final CountDownLatch latch = new CountDownLatch(2); connection.addShutdownListener(new ShutdownListener() { public void shutdownCompleted(ShutdownSignalException cause) { @@ -133,7 +135,7 @@ public void shutdownCompleted(ShutdownSignalException cause) { wait(latch); } - public void testShutdownHooksRecoveryOnChannel() throws IOException, InterruptedException { + @Test public void shutdownHooksRecoveryOnChannel() throws IOException, InterruptedException { final CountDownLatch latch = new CountDownLatch(3); channel.addShutdownListener(new ShutdownListener() { public void shutdownCompleted(ShutdownSignalException cause) { @@ -149,7 +151,7 @@ public void shutdownCompleted(ShutdownSignalException cause) { wait(latch); } - public void testBlockedListenerRecovery() throws IOException, InterruptedException { + @Test public void blockedListenerRecovery() throws IOException, InterruptedException { final CountDownLatch latch = new CountDownLatch(2); connection.addBlockedListener(new BlockedListener() { public void handleBlocked(String reason) throws IOException { @@ -167,7 +169,7 @@ public void handleUnblocked() throws IOException { wait(latch); } - public void testChannelRecovery() throws IOException, InterruptedException { + @Test public void channelRecovery() throws IOException, InterruptedException { Channel ch1 = connection.createChannel(); Channel ch2 = connection.createChannel(); @@ -178,7 +180,7 @@ public void testChannelRecovery() throws IOException, InterruptedException { expectChannelRecovery(ch2); } - public void testReturnListenerRecovery() throws IOException, InterruptedException { + @Test public void returnListenerRecovery() throws IOException, InterruptedException { final CountDownLatch latch = new CountDownLatch(1); channel.addReturnListener(new ReturnListener() { public void handleReturn(int replyCode, String replyText, String exchange, @@ -193,7 +195,7 @@ public void handleReturn(int replyCode, String replyText, String exchange, wait(latch); } - public void testConfirmListenerRecovery() throws IOException, InterruptedException, TimeoutException { + @Test public void confirmListenerRecovery() throws IOException, InterruptedException, TimeoutException { final CountDownLatch latch = new CountDownLatch(1); channel.addConfirmListener(new ConfirmListener() { public void handleAck(long deliveryTag, boolean multiple) throws IOException { @@ -213,7 +215,7 @@ public void handleNack(long deliveryTag, boolean multiple) throws IOException { wait(latch); } - public void testExchangeRecovery() throws IOException, InterruptedException, TimeoutException { + @Test public void exchangeRecovery() throws IOException, InterruptedException, TimeoutException { Channel ch = connection.createChannel(); String x = "java-client.test.recovery.x1"; declareExchange(ch, x); @@ -223,7 +225,7 @@ public void testExchangeRecovery() throws IOException, InterruptedException, Tim ch.exchangeDelete(x); } - public void testExchangeRecoveryWithNoWait() throws IOException, InterruptedException, TimeoutException { + @Test public void exchangeRecoveryWithNoWait() throws IOException, InterruptedException, TimeoutException { Channel ch = connection.createChannel(); String x = "java-client.test.recovery.x1-nowait"; declareExchangeNoWait(ch, x); @@ -233,11 +235,11 @@ public void testExchangeRecoveryWithNoWait() throws IOException, InterruptedExce ch.exchangeDelete(x); } - public void testClientNamedQueueRecovery() throws IOException, InterruptedException, TimeoutException { + @Test public void clientNamedQueueRecovery() throws IOException, InterruptedException, TimeoutException { testClientNamedQueueRecoveryWith("java-client.test.recovery.q1", false); } - public void testClientNamedQueueRecoveryWithNoWait() throws IOException, InterruptedException, TimeoutException { + @Test public void clientNamedQueueRecoveryWithNoWait() throws IOException, InterruptedException, TimeoutException { testClientNamedQueueRecoveryWith("java-client.test.recovery.q1-nowait", true); } @@ -254,7 +256,7 @@ protected void testClientNamedQueueRecoveryWith(String q, boolean noWait) throws ch.queueDelete(q); } - public void testClientNamedQueueBindingRecovery() throws IOException, InterruptedException, TimeoutException { + @Test public void clientNamedQueueBindingRecovery() throws IOException, InterruptedException, TimeoutException { String q = "java-client.test.recovery.q2"; String x = "tmp-fanout"; Channel ch = connection.createChannel(); @@ -271,7 +273,7 @@ public void testClientNamedQueueBindingRecovery() throws IOException, Interrupte } // bug 26552 - public void testClientNamedTransientAutoDeleteQueueAndBindingRecovery() throws IOException, InterruptedException, TimeoutException { + @Test public void clientNamedTransientAutoDeleteQueueAndBindingRecovery() throws IOException, InterruptedException, TimeoutException { String q = UUID.randomUUID().toString(); String x = "tmp-fanout"; Channel ch = connection.createChannel(); @@ -294,7 +296,7 @@ public void testClientNamedTransientAutoDeleteQueueAndBindingRecovery() throws I } // bug 26552 - public void testServerNamedTransientAutoDeleteQueueAndBindingRecovery() throws IOException, InterruptedException, TimeoutException { + @Test public void serverNamedTransientAutoDeleteQueueAndBindingRecovery() throws IOException, InterruptedException, TimeoutException { String x = "tmp-fanout"; Channel ch = connection.createChannel(); ch.exchangeDelete(x); @@ -324,7 +326,7 @@ public void queueRecovered(String oldName, String newName) { ch.exchangeDelete(x); } - public void testDeclarationOfManyAutoDeleteQueuesWithTransientConsumer() throws IOException, TimeoutException { + @Test public void declarationOfManyAutoDeleteQueuesWithTransientConsumer() throws IOException, TimeoutException { Channel ch = connection.createChannel(); assertRecordedQueues(connection, 0); for(int i = 0; i < 5000; i++) { @@ -338,7 +340,7 @@ public void testDeclarationOfManyAutoDeleteQueuesWithTransientConsumer() throws ch.close(); } - public void testDeclarationOfManyAutoDeleteExchangesWithTransientQueuesThatAreUnbound() throws IOException, TimeoutException { + @Test public void declarationOfManyAutoDeleteExchangesWithTransientQueuesThatAreUnbound() throws IOException, TimeoutException { Channel ch = connection.createChannel(); assertRecordedExchanges(connection, 0); for(int i = 0; i < 5000; i++) { @@ -354,7 +356,7 @@ public void testDeclarationOfManyAutoDeleteExchangesWithTransientQueuesThatAreUn ch.close(); } - public void testDeclarationOfManyAutoDeleteExchangesWithTransientQueuesThatAreDeleted() throws IOException, TimeoutException { + @Test public void declarationOfManyAutoDeleteExchangesWithTransientQueuesThatAreDeleted() throws IOException, TimeoutException { Channel ch = connection.createChannel(); assertRecordedExchanges(connection, 0); for(int i = 0; i < 5000; i++) { @@ -368,7 +370,7 @@ public void testDeclarationOfManyAutoDeleteExchangesWithTransientQueuesThatAreDe ch.close(); } - public void testDeclarationOfManyAutoDeleteExchangesWithTransientExchangesThatAreUnbound() throws IOException, TimeoutException { + @Test public void declarationOfManyAutoDeleteExchangesWithTransientExchangesThatAreUnbound() throws IOException, TimeoutException { Channel ch = connection.createChannel(); assertRecordedExchanges(connection, 0); for(int i = 0; i < 5000; i++) { @@ -385,7 +387,7 @@ public void testDeclarationOfManyAutoDeleteExchangesWithTransientExchangesThatAr ch.close(); } - public void testDeclarationOfManyAutoDeleteExchangesWithTransientExchangesThatAreDeleted() throws IOException, TimeoutException { + @Test public void declarationOfManyAutoDeleteExchangesWithTransientExchangesThatAreDeleted() throws IOException, TimeoutException { Channel ch = connection.createChannel(); assertRecordedExchanges(connection, 0); for(int i = 0; i < 5000; i++) { @@ -400,7 +402,7 @@ public void testDeclarationOfManyAutoDeleteExchangesWithTransientExchangesThatAr ch.close(); } - public void testServerNamedQueueRecovery() throws IOException, InterruptedException { + @Test public void serverNamedQueueRecovery() throws IOException, InterruptedException { String q = channel.queueDeclare("", false, false, false, null).getQueue(); String x = "amq.fanout"; channel.queueBind(q, x, ""); @@ -426,7 +428,7 @@ public void queueRecovered(String oldName, String newName) { channel.queueDelete(q); } - public void testExchangeToExchangeBindingRecovery() throws IOException, InterruptedException { + @Test public void exchangeToExchangeBindingRecovery() throws IOException, InterruptedException { String q = channel.queueDeclare("", false, false, false, null).getQueue(); String x1 = "amq.fanout"; String x2 = generateExchangeName(); @@ -445,7 +447,7 @@ public void testExchangeToExchangeBindingRecovery() throws IOException, Interrup } } - public void testThatDeletedQueueBindingsDontReappearOnRecovery() throws IOException, InterruptedException { + @Test public void thatDeletedQueueBindingsDontReappearOnRecovery() throws IOException, InterruptedException { String q = channel.queueDeclare("", false, false, false, null).getQueue(); String x1 = "amq.fanout"; String x2 = generateExchangeName(); @@ -465,7 +467,7 @@ public void testThatDeletedQueueBindingsDontReappearOnRecovery() throws IOExcept } } - public void testThatDeletedExchangeBindingsDontReappearOnRecovery() throws IOException, InterruptedException { + @Test public void thatDeletedExchangeBindingsDontReappearOnRecovery() throws IOException, InterruptedException { String q = channel.queueDeclare("", false, false, false, null).getQueue(); String x1 = "amq.fanout"; String x2 = generateExchangeName(); @@ -485,7 +487,7 @@ public void testThatDeletedExchangeBindingsDontReappearOnRecovery() throws IOExc } } - public void testThatDeletedExchangeDoesNotReappearOnRecover() throws IOException, InterruptedException { + @Test public void thatDeletedExchangeDoesNotReappearOnRecover() throws IOException, InterruptedException { String x = generateExchangeName(); channel.exchangeDeclare(x, "fanout"); channel.exchangeDelete(x); @@ -499,7 +501,7 @@ public void testThatDeletedExchangeDoesNotReappearOnRecover() throws IOException } } - public void testThatDeletedQueueDoesNotReappearOnRecover() throws IOException, InterruptedException { + @Test public void thatDeletedQueueDoesNotReappearOnRecover() throws IOException, InterruptedException { String q = channel.queueDeclare().getQueue(); channel.queueDelete(q); try { @@ -512,7 +514,7 @@ public void testThatDeletedQueueDoesNotReappearOnRecover() throws IOException, I } } - public void testThatCancelledConsumerDoesNotReappearOnRecover() throws IOException, InterruptedException { + @Test public void thatCancelledConsumerDoesNotReappearOnRecover() throws IOException, InterruptedException { String q = UUID.randomUUID().toString(); channel.queueDeclare(q, false, false, false, null); String tag = channel.basicConsume(q, new DefaultConsumer(channel)); @@ -523,7 +525,7 @@ public void testThatCancelledConsumerDoesNotReappearOnRecover() throws IOExcepti assertConsumerCount(0, q); } - public void testConsumerRecoveryWithManyConsumers() throws IOException, InterruptedException { + @Test public void consumerRecoveryWithManyConsumers() throws IOException, InterruptedException { String q = channel.queueDeclare(UUID.randomUUID().toString(), false, false, false, null).getQueue(); final int n = 1024; for (int i = 0; i < n; i++) { @@ -550,7 +552,7 @@ public void consumerRecovered(String oldConsumerTag, String newConsumerTag) { } - public void testSubsequentRecoveriesWithClientNamedQueue() throws IOException, InterruptedException { + @Test public void subsequentRecoveriesWithClientNamedQueue() throws IOException, InterruptedException { String q = channel.queueDeclare(UUID.randomUUID().toString(), false, false, false, null).getQueue(); assertConsumerCount(0, q); @@ -564,7 +566,7 @@ public void testSubsequentRecoveriesWithClientNamedQueue() throws IOException, I channel.queueDelete(q); } - public void testQueueRecoveryWithManyQueues() throws IOException, InterruptedException, TimeoutException { + @Test public void queueRecoveryWithManyQueues() throws IOException, InterruptedException, TimeoutException { List qs = new ArrayList(); final int n = 1024; for (int i = 0; i < n; i++) { @@ -578,7 +580,7 @@ public void testQueueRecoveryWithManyQueues() throws IOException, InterruptedExc } } - public void testChannelRecoveryCallback() throws IOException, InterruptedException { + @Test public void channelRecoveryCallback() throws IOException, InterruptedException { final CountDownLatch latch = new CountDownLatch(2); final RecoveryListener listener = new RecoveryListener() { public void handleRecovery(Recoverable recoverable) { @@ -598,7 +600,7 @@ public void handleRecovery(Recoverable recoverable) { wait(latch); } - public void testBasicAckAfterChannelRecovery() throws IOException, InterruptedException, TimeoutException { + @Test public void basicAckAfterChannelRecovery() throws IOException, InterruptedException, TimeoutException { final AtomicInteger consumed = new AtomicInteger(0); int n = 5; final CountDownLatch latch = new CountDownLatch(n); diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java b/src/test/java/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java index f73625cd62..087986608d 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java @@ -15,13 +15,8 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.Consumer; -import com.rabbitmq.client.DefaultConsumer; -import com.rabbitmq.client.ConsumerCancelledException; -import com.rabbitmq.client.QueueingConsumer; -import com.rabbitmq.client.ShutdownSignalException; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.io.IOException; import java.util.concurrent.ArrayBlockingQueue; @@ -29,11 +24,21 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import org.junit.Test; + +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Consumer; +import com.rabbitmq.client.ConsumerCancelledException; +import com.rabbitmq.client.DefaultConsumer; +import com.rabbitmq.client.QueueingConsumer; +import com.rabbitmq.client.ShutdownSignalException; +import com.rabbitmq.client.test.BrokerTestCase; + public class ConsumerCancelNotification extends BrokerTestCase { private final String queue = "cancel_notification_queue"; - public void testConsumerCancellationNotification() throws IOException, + @Test public void consumerCancellationNotification() throws IOException, InterruptedException { final BlockingQueue result = new ArrayBlockingQueue(1); @@ -53,7 +58,7 @@ public void handleCancel(String consumerTag) throws IOException { assertTrue(result.take()); } - public void testConsumerCancellationInterruptsQueuingConsumerWait() + @Test public void consumerCancellationInterruptsQueuingConsumerWait() throws IOException, InterruptedException { final BlockingQueue result = new ArrayBlockingQueue(1); channel.queueDeclare(queue, false, true, false, null); @@ -112,7 +117,7 @@ public void handleCancel(String consumerTag) { } } - public void testConsumerCancellationHandlerUsesBlockingOperations() + @Test public void consumerCancellationHandlerUsesBlockingOperations() throws IOException, InterruptedException { final String altQueue = "basic.cancel.fallback"; channel.queueDeclare(queue, false, true, false, null); diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConsumerCount.java b/src/test/java/com/rabbitmq/client/test/functional/ConsumerCount.java index 1bc4c76944..e4230d9f92 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConsumerCount.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConsumerCount.java @@ -15,13 +15,17 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.DefaultConsumer; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.assertEquals; import java.io.IOException; +import org.junit.Test; + +import com.rabbitmq.client.DefaultConsumer; +import com.rabbitmq.client.test.BrokerTestCase; + public class ConsumerCount extends BrokerTestCase { - public void testConsumerCount() throws IOException { + @Test public void consumerCount() throws IOException { String q = generateQueueName(); channel.queueDeclare(q, false, true, false, null); assertEquals(0, channel.consumerCount(q)); diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConsumerPriorities.java b/src/test/java/com/rabbitmq/client/test/functional/ConsumerPriorities.java index 6b2da2a114..e9c24dbf0d 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConsumerPriorities.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConsumerPriorities.java @@ -15,21 +15,26 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.MessageProperties; -import com.rabbitmq.client.QueueingConsumer; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; import java.io.IOException; import java.util.Arrays; import java.util.HashMap; import java.util.Map; +import org.junit.Test; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.MessageProperties; +import com.rabbitmq.client.QueueingConsumer; +import com.rabbitmq.client.test.BrokerTestCase; + public class ConsumerPriorities extends BrokerTestCase { - public void testValidation() throws IOException { + @Test public void validation() throws IOException { assertFailValidation(args("banana")); - assertFailValidation(args(new HashMap())); + assertFailValidation(args(new HashMap())); assertFailValidation(args(null)); assertFailValidation(args(Arrays.asList(1, 2, 3))); } @@ -47,7 +52,7 @@ private void assertFailValidation(Map args) throws IOException { private static final int COUNT = 10; - public void testConsumerPriorities() throws Exception { + @Test public void consumerPriorities() throws Exception { String queue = channel.queueDeclare().getQueue(); QueueingConsumer highConsumer = new QueueingConsumer(channel); QueueingConsumer medConsumer = new QueueingConsumer(channel); diff --git a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java index 5e3fb55d4a..44bbb3a639 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java @@ -15,20 +15,15 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.AMQP.BasicProperties; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.DefaultConsumer; -import com.rabbitmq.client.Envelope; -import com.rabbitmq.client.GetResponse; -import com.rabbitmq.client.MessageProperties; -import com.rabbitmq.client.QueueingConsumer; -import com.rabbitmq.client.QueueingConsumer.Delivery; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.io.IOException; -import java.util.Arrays; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -37,6 +32,19 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import org.junit.Test; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.AMQP.BasicProperties; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.DefaultConsumer; +import com.rabbitmq.client.Envelope; +import com.rabbitmq.client.GetResponse; +import com.rabbitmq.client.MessageProperties; +import com.rabbitmq.client.QueueingConsumer; +import com.rabbitmq.client.QueueingConsumer.Delivery; +import com.rabbitmq.client.test.BrokerTestCase; + public class DeadLetterExchange extends BrokerTestCase { public static final String DLX = "dead.letter.exchange"; public static final String DLX_ARG = "x-dead-letter-exchange"; @@ -60,33 +68,33 @@ protected void releaseResources() throws IOException { channel.exchangeDelete(DLX); } - public void testDeclareQueueWithExistingDeadLetterExchange() + @Test public void declareQueueWithExistingDeadLetterExchange() throws IOException { declareQueue(DLX); } - public void testDeclareQueueWithNonExistingDeadLetterExchange() + @Test public void declareQueueWithNonExistingDeadLetterExchange() throws IOException { declareQueue("some.random.exchange.name"); } - public void testDeclareQueueWithEquivalentDeadLetterExchange() + @Test public void declareQueueWithEquivalentDeadLetterExchange() throws IOException { declareQueue(DLX); declareQueue(DLX); } - public void testDeclareQueueWithEquivalentDeadLetterRoutingKey() + @Test public void declareQueueWithEquivalentDeadLetterRoutingKey() throws IOException { declareQueue(TEST_QUEUE_NAME, DLX, "routing_key", null); declareQueue(TEST_QUEUE_NAME, DLX, "routing_key", null); } - public void testDeclareQueueWithInvalidDeadLetterExchangeArg() + @Test public void declareQueueWithInvalidDeadLetterExchangeArg() throws IOException { try { @@ -97,7 +105,7 @@ public void testDeclareQueueWithInvalidDeadLetterExchangeArg() } } - public void testRedeclareQueueWithInvalidDeadLetterExchangeArg() + @Test public void redeclareQueueWithInvalidDeadLetterExchangeArg() throws IOException { declareQueue("inequivalent_dlx_name", "dlx_foo", null, null); @@ -110,7 +118,7 @@ public void testRedeclareQueueWithInvalidDeadLetterExchangeArg() } } - public void testDeclareQueueWithInvalidDeadLetterRoutingKeyArg() + @Test public void declareQueueWithInvalidDeadLetterRoutingKeyArg() throws IOException { try { @@ -121,7 +129,7 @@ public void testDeclareQueueWithInvalidDeadLetterRoutingKeyArg() } } - public void testRedeclareQueueWithInvalidDeadLetterRoutingKeyArg() + @Test public void redeclareQueueWithInvalidDeadLetterRoutingKeyArg() throws IOException { declareQueue("inequivalent_dlx_rk", "amq.direct", "dlx_rk", null); @@ -134,7 +142,7 @@ public void testRedeclareQueueWithInvalidDeadLetterRoutingKeyArg() } } - public void testDeclareQueueWithRoutingKeyButNoDeadLetterExchange() + @Test public void declareQueueWithRoutingKeyButNoDeadLetterExchange() throws IOException { try { @@ -148,7 +156,7 @@ public void testDeclareQueueWithRoutingKeyButNoDeadLetterExchange() } } - public void testRedeclareQueueWithRoutingKeyButNoDeadLetterExchange() + @Test public void redeclareQueueWithRoutingKeyButNoDeadLetterExchange() throws IOException { try { @@ -165,15 +173,15 @@ public void testRedeclareQueueWithRoutingKeyButNoDeadLetterExchange() } } - public void testDeadLetterQueueTTLExpiredMessages() throws Exception { + @Test public void deadLetterQueueTTLExpiredMessages() throws Exception { ttlTest(TTL); } - public void testDeadLetterQueueZeroTTLExpiredMessages() throws Exception { + @Test public void deadLetterQueueZeroTTLExpiredMessages() throws Exception { ttlTest(0); } - public void testDeadLetterQueueTTLPromptExpiry() throws Exception { + @Test public void deadLetterQueueTTLPromptExpiry() throws Exception { Map args = new HashMap(); args.put("x-message-ttl", TTL); declareQueue(TEST_QUEUE_NAME, DLX, null, args); @@ -226,7 +234,7 @@ public void testDeadLetterQueueTTLPromptExpiry() throws Exception { checkPromptArrival(c, 2, latency); } - public void testDeadLetterDeletedDLX() throws Exception { + @Test public void deadLetterDeletedDLX() throws Exception { declareQueue(TEST_QUEUE_NAME, DLX, null, null, 1); channel.queueBind(TEST_QUEUE_NAME, "amq.direct", "test"); channel.queueBind(DLQ, DLX, "test"); @@ -246,7 +254,7 @@ public void testDeadLetterDeletedDLX() throws Exception { consumeN(DLQ, MSG_COUNT, WithResponse.NULL); } - public void testDeadLetterPerMessageTTLRemoved() throws Exception { + @Test public void deadLetterPerMessageTTLRemoved() throws Exception { declareQueue(TEST_QUEUE_NAME, DLX, null, null, 1); channel.queueBind(TEST_QUEUE_NAME, "amq.direct", "test"); channel.queueBind(DLQ, DLX, "test"); @@ -275,15 +283,15 @@ public void process(GetResponse getResponse) { }); } - public void testDeadLetterOnReject() throws Exception { + @Test public void deadLetterOnReject() throws Exception { rejectionTest(false); } - public void testDeadLetterOnNack() throws Exception { + @Test public void deadLetterOnNack() throws Exception { rejectionTest(true); } - public void testDeadLetterNoDeadLetterQueue() throws IOException { + @Test public void deadLetterNoDeadLetterQueue() throws IOException { channel.queueDelete(DLQ); declareQueue(TEST_QUEUE_NAME, DLX, null, null, 1); @@ -292,7 +300,7 @@ public void testDeadLetterNoDeadLetterQueue() throws IOException { publishN(MSG_COUNT); } - public void testDeadLetterMultipleDeadLetterQueues() + @Test public void deadLetterMultipleDeadLetterQueues() throws IOException { declareQueue(TEST_QUEUE_NAME, DLX, null, null, 1); @@ -306,7 +314,7 @@ public void testDeadLetterMultipleDeadLetterQueues() publishN(MSG_COUNT); } - public void testDeadLetterTwice() throws Exception { + @Test public void deadLetterTwice() throws Exception { declareQueue(TEST_QUEUE_NAME, DLX, null, null, 1); channel.queueDelete(DLQ); @@ -343,7 +351,7 @@ public void process(GetResponse getResponse) { }); } - public void testDeadLetterSelf() throws Exception { + @Test public void deadLetterSelf() throws Exception { declareQueue(TEST_QUEUE_NAME, "amq.direct", "test", null, 1); channel.queueBind(TEST_QUEUE_NAME, "amq.direct", "test"); @@ -357,7 +365,7 @@ public void testDeadLetterSelf() throws Exception { consumeN(TEST_QUEUE_NAME, 0, WithResponse.NULL); } - public void testDeadLetterCycle() throws Exception { + @Test public void deadLetterCycle() throws Exception { // testDeadLetterTwice and testDeadLetterSelf both test that we drop // messages in pure-expiry cycles. So we just need to test that // non-pure-expiry cycles do not drop messages. @@ -379,7 +387,7 @@ public void handleDelivery(String consumerTag, Envelope envelope, assertTrue(latch.await(10, TimeUnit.SECONDS)); } - public void testDeadLetterNewRK() throws Exception { + @Test public void deadLetterNewRK() throws Exception { declareQueue(TEST_QUEUE_NAME, DLX, "test-other", null, 1); channel.queueDeclare(DLQ2, false, true, false, null); @@ -418,7 +426,7 @@ public void process(GetResponse getResponse) { } @SuppressWarnings("unchecked") - public void testRepublish() throws Exception { + @Test public void republish() throws Exception { Map args = new HashMap(); args.put("x-message-ttl", 100); declareQueue(TEST_QUEUE_NAME, DLX, null, args); diff --git a/src/test/java/com/rabbitmq/client/test/functional/DefaultExchange.java b/src/test/java/com/rabbitmq/client/test/functional/DefaultExchange.java index 25c4c99390..fb27da6391 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DefaultExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DefaultExchange.java @@ -15,11 +15,15 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.fail; import java.io.IOException; +import org.junit.Test; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.test.BrokerTestCase; + public class DefaultExchange extends BrokerTestCase { String queueName; @@ -31,12 +35,12 @@ protected void createResources() throws IOException { // See bug 22101: publish and declare are the only operations // permitted on the default exchange - public void testDefaultExchangePublish() throws IOException { + @Test public void defaultExchangePublish() throws IOException { basicPublishVolatile("", queueName); // Implicit binding assertDelivered(queueName, 1); } - public void testBindToDefaultExchange() throws IOException { + @Test public void bindToDefaultExchange() throws IOException { try { channel.queueBind(queueName, "", "foobar"); fail(); @@ -45,7 +49,7 @@ public void testBindToDefaultExchange() throws IOException { } } - public void testUnbindFromDefaultExchange() throws IOException { + @Test public void unbindFromDefaultExchange() throws IOException { try { channel.queueUnbind(queueName, "", queueName); fail(); @@ -54,7 +58,7 @@ public void testUnbindFromDefaultExchange() throws IOException { } } - public void testDeclareDefaultExchange() throws IOException { + @Test public void declareDefaultExchange() throws IOException { try { channel.exchangeDeclare("", "direct", true); fail(); @@ -63,7 +67,7 @@ public void testDeclareDefaultExchange() throws IOException { } } - public void testDeleteDefaultExchange() throws IOException { + @Test public void deleteDefaultExchange() throws IOException { try { channel.exchangeDelete(""); fail(); diff --git a/src/test/java/com/rabbitmq/client/test/functional/DirectReplyTo.java b/src/test/java/com/rabbitmq/client/test/functional/DirectReplyTo.java index aa39e4804c..06b3d9e3b4 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DirectReplyTo.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DirectReplyTo.java @@ -15,6 +15,16 @@ package com.rabbitmq.client.test.functional; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; + +import org.junit.Test; + import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; @@ -23,12 +33,10 @@ import com.rabbitmq.client.QueueingConsumer; import com.rabbitmq.client.test.BrokerTestCase; -import java.io.IOException; - public class DirectReplyTo extends BrokerTestCase { private static final String QUEUE = "amq.rabbitmq.reply-to"; - public void testRoundTrip() throws IOException, InterruptedException { + @Test public void roundTrip() throws IOException, InterruptedException { QueueingConsumer c = new QueueingConsumer(channel); String replyTo = rpcFirstHalf(c); declare(connection, replyTo, true); @@ -40,7 +48,7 @@ public void testRoundTrip() throws IOException, InterruptedException { assertEquals("response", new String(del.getBody())); } - public void testHack() throws IOException, InterruptedException { + @Test public void hack() throws IOException, InterruptedException { QueueingConsumer c = new QueueingConsumer(channel); String replyTo = rpcFirstHalf(c); // 5 chars should overwrite part of the key but not the pid; aiming to prove @@ -66,7 +74,7 @@ private void declare(Connection connection, String q, boolean expectedExists) th } } - public void testConsumeFail() throws IOException, InterruptedException { + @Test public void consumeFail() throws IOException, InterruptedException { QueueingConsumer c = new QueueingConsumer(channel); Channel ch = connection.createChannel(); try { @@ -86,7 +94,7 @@ public void testConsumeFail() throws IOException, InterruptedException { } } - public void testConsumeSuccess() throws IOException, InterruptedException { + @Test public void consumeSuccess() throws IOException, InterruptedException { QueueingConsumer c = new QueueingConsumer(channel); String ctag = channel.basicConsume(QUEUE, true, c); channel.basicCancel(ctag); diff --git a/src/test/java/com/rabbitmq/client/test/functional/DoubleDeletion.java b/src/test/java/com/rabbitmq/client/test/functional/DoubleDeletion.java index bae5eb7c8d..305b152fab 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DoubleDeletion.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DoubleDeletion.java @@ -18,6 +18,8 @@ import java.io.IOException; +import org.junit.Test; + import com.rabbitmq.client.test.BrokerTestCase; public class DoubleDeletion extends BrokerTestCase @@ -25,7 +27,7 @@ public class DoubleDeletion extends BrokerTestCase protected static final String Q = "DoubleDeletionQueue"; protected static final String X = "DoubleDeletionExchange"; - public void testDoubleDeletionQueue() + @Test public void doubleDeletionQueue() throws IOException { channel.queueDelete(Q); @@ -34,7 +36,7 @@ public void testDoubleDeletionQueue() channel.queueDelete(Q); } - public void testDoubleDeletionExchange() + @Test public void doubleDeletionExchange() throws IOException { channel.exchangeDelete(X); diff --git a/src/test/java/com/rabbitmq/client/test/functional/DurableOnTransient.java b/src/test/java/com/rabbitmq/client/test/functional/DurableOnTransient.java index 84f488df7c..adb11c9bf3 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DurableOnTransient.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DurableOnTransient.java @@ -16,8 +16,12 @@ package com.rabbitmq.client.test.functional; +import static org.junit.Assert.assertNotNull; + import java.io.IOException; +import org.junit.Test; + import com.rabbitmq.client.GetResponse; import com.rabbitmq.client.MessageProperties; @@ -55,7 +59,7 @@ protected void releaseResources() throws IOException { channel.exchangeDelete(X); } - public void testBindDurableToTransient() + @Test public void bindDurableToTransient() throws IOException { channel.queueBind(Q, X, ""); @@ -63,7 +67,7 @@ public void testBindDurableToTransient() assertNotNull(basicGet()); } - public void testSemiDurableBindingRemoval() throws IOException { + @Test public void semiDurableBindingRemoval() throws IOException { if (clusteredConnection != null) { deleteExchange("x"); declareTransientTopicExchange("x"); diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExceptionHandling.java b/src/test/java/com/rabbitmq/client/test/functional/ExceptionHandling.java index 8a25798cd3..828d24a774 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExceptionHandling.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExceptionHandling.java @@ -15,6 +15,16 @@ package com.rabbitmq.client.test.functional; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import org.junit.Test; + import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; @@ -25,21 +35,15 @@ import com.rabbitmq.client.ExceptionHandler; import com.rabbitmq.client.impl.DefaultExceptionHandler; import com.rabbitmq.client.impl.ForgivingExceptionHandler; -import junit.framework.TestCase; - -import java.io.IOException; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -public class ExceptionHandling extends TestCase { +public class ExceptionHandling { private ConnectionFactory newConnectionFactory(ExceptionHandler eh) { ConnectionFactory cf = new ConnectionFactory(); cf.setExceptionHandler(eh); return cf; } - public void testDefaultConsumerHandleConsumerException() throws IOException, InterruptedException, TimeoutException { + @Test public void defaultConsumerHandleConsumerException() throws IOException, InterruptedException, TimeoutException { final CountDownLatch latch = new CountDownLatch(1); final ExceptionHandler eh = new DefaultExceptionHandler() { @Override @@ -52,7 +56,7 @@ public void handleConsumerException(Channel channel, Throwable exception, Consum testConsumerHandleConsumerException(eh, latch, true); } - public void testForgivingConsumerHandleConsumerException() throws IOException, InterruptedException, TimeoutException { + @Test public void forgivingConsumerHandleConsumerException() throws IOException, InterruptedException, TimeoutException { final CountDownLatch latch = new CountDownLatch(1); final ExceptionHandler eh = new ForgivingExceptionHandler() { @Override @@ -86,7 +90,7 @@ public void handleDelivery(String consumerTag, Envelope envelope, assertEquals(!expectChannelClose, ch.isOpen()); } - public void testNullExceptionHandler() { + @Test public void nullExceptionHandler() { ConnectionFactory cf = new ConnectionFactory(); try { cf.setExceptionHandler(null); diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExceptionMessages.java b/src/test/java/com/rabbitmq/client/test/functional/ExceptionMessages.java index 27c52f2d50..88b53a8b9a 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExceptionMessages.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExceptionMessages.java @@ -15,14 +15,19 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.AlreadyClosedException; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.io.IOException; import java.util.UUID; +import org.junit.Test; + +import com.rabbitmq.client.AlreadyClosedException; +import com.rabbitmq.client.test.BrokerTestCase; + public class ExceptionMessages extends BrokerTestCase { - public void testAlreadyClosedExceptionMessageWithChannelError() throws IOException { + @Test public void alreadyClosedExceptionMessageWithChannelError() throws IOException { String uuid = UUID.randomUUID().toString(); try { channel.queueDeclarePassive(uuid); @@ -39,7 +44,7 @@ public void testAlreadyClosedExceptionMessageWithChannelError() throws IOExcepti } } - public void testAlreadyClosedExceptionMessageWithCleanClose() throws IOException { + @Test public void alreadyClosedExceptionMessageWithCleanClose() throws IOException { String uuid = UUID.randomUUID().toString(); try { diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java index f699f9bb3c..e9de936194 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java @@ -16,16 +16,19 @@ package com.rabbitmq.client.test.functional; +import com.rabbitmq.client.BuiltinExchangeType; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; -import com.rabbitmq.client.BuiltinExchangeType; +import org.junit.Test; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeoutException; +import static org.junit.Assert.assertEquals; + public class ExchangeDeclare extends ExchangeEquivalenceBase { static final String TYPE = "direct"; @@ -36,38 +39,38 @@ public void releaseResources() throws IOException { channel.exchangeDelete(NAME); } - public void testExchangeNoArgsEquivalence() throws IOException { + @Test public void exchangeNoArgsEquivalence() throws IOException { channel.exchangeDeclare(NAME, TYPE, false, false, null); verifyEquivalent(NAME, TYPE, false, false, null); } - public void testExchangeNonsenseArgsEquivalent() throws IOException { + @Test public void exchangeNonsenseArgsEquivalent() throws IOException { channel.exchangeDeclare(NAME, TYPE, false, false, null); Map args = new HashMap(); args.put("nonsensical-argument-surely-not-in-use", "foo"); verifyEquivalent(NAME, TYPE, false, false, args); } - public void testExchangeDurableNotEquivalent() throws IOException { + @Test public void exchangeDurableNotEquivalent() throws IOException { channel.exchangeDeclare(NAME, TYPE, false, false, null); verifyNotEquivalent(NAME, TYPE, true, false, null); } - public void testExchangeTypeNotEquivalent() throws IOException { + @Test public void exchangeTypeNotEquivalent() throws IOException { channel.exchangeDeclare(NAME, "direct", false, false, null); verifyNotEquivalent(NAME, "fanout", false, false, null); } - public void testExchangeAutoDeleteNotEquivalent() throws IOException { + @Test public void exchangeAutoDeleteNotEquivalent() throws IOException { channel.exchangeDeclare(NAME, "direct", false, false, null); verifyNotEquivalent(NAME, "direct", false, true, null); } - public void testExchangeDeclaredWithEnumerationEquivalentOnNonRecoverableConnection() throws IOException, InterruptedException { + @Test public void exchangeDeclaredWithEnumerationEquivalentOnNonRecoverableConnection() throws IOException, InterruptedException { doTestExchangeDeclaredWithEnumerationEquivalent(channel); } - public void testExchangeDeclaredWithEnumerationEquivalentOnRecoverableConnection() throws IOException, TimeoutException, InterruptedException { + @Test public void exchangeDeclaredWithEnumerationEquivalentOnRecoverableConnection() throws IOException, TimeoutException, InterruptedException { ConnectionFactory connectionFactory = new ConnectionFactory(); connectionFactory.setAutomaticRecoveryEnabled(true); connectionFactory.setTopologyRecoveryEnabled(false); diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java index f5c3defcf5..dab4ebd080 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java @@ -16,9 +16,13 @@ package com.rabbitmq.client.test.functional; +import static org.junit.Assert.fail; + import java.io.IOException; import java.util.concurrent.TimeoutException; +import org.junit.Test; + import com.rabbitmq.client.AMQP; import com.rabbitmq.client.test.BrokerTestCase; @@ -45,7 +49,7 @@ protected void releaseResources() /* Attempt to Exchange.Delete(ifUnused = true) a used exchange. * Should throw an exception. */ - public void testExchangeDelete() { + @Test public void exchangeDelete() { try { channel.exchangeDelete(EXCHANGE_NAME, true); fail("Exception expected if exchange in use"); diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java index 82e4eccbdc..0e8bfcd92a 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java @@ -15,12 +15,14 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.fail; import java.io.IOException; import java.util.Map; +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.test.BrokerTestCase; + public abstract class ExchangeEquivalenceBase extends BrokerTestCase { public void verifyEquivalent(String name, String type, boolean durable, boolean autoDelete, diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java index 64c07c9ddd..739da0c71a 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java @@ -16,12 +16,16 @@ package com.rabbitmq.client.test.functional; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + import java.io.IOException; -import com.rabbitmq.client.AMQP; +import org.junit.Test; + import com.rabbitmq.client.QueueingConsumer; -import com.rabbitmq.client.ShutdownSignalException; import com.rabbitmq.client.QueueingConsumer.Delivery; +import com.rabbitmq.client.ShutdownSignalException; import com.rabbitmq.client.test.BrokerTestCase; public class ExchangeExchangeBindings extends BrokerTestCase { @@ -78,7 +82,7 @@ protected void consumeNoDuplicates(QueueingConsumer consumer) assertEquals(new String(MARKER), new String(markerDelivery.getBody())); } - public void testBindingCreationDeletion() throws IOException { + @Test public void bindingCreationDeletion() throws IOException { channel.exchangeUnbind("e2", "e1", ""); channel.exchangeBind("e2", "e1", ""); channel.exchangeBind("e2", "e1", ""); @@ -93,7 +97,7 @@ public void testBindingCreationDeletion() throws IOException { * add binding (e2 --> e1) * test (e2 --> {q2, q1, q0}) */ - public void testSimpleChains() throws IOException, ShutdownSignalException, + @Test public void simpleChains() throws IOException, ShutdownSignalException, InterruptedException { publishWithMarker("e0", ""); consumeNoDuplicates(consumers[0]); @@ -120,7 +124,7 @@ public void testSimpleChains() throws IOException, ShutdownSignalException, * resulting in: (e1 --> {q1, e0 --> {q0, q1}}) * test (e1 --> {q0, q1}) */ - public void testDuplicateQueueDestinations() throws IOException, + @Test public void duplicateQueueDestinations() throws IOException, ShutdownSignalException, InterruptedException { channel.queueBind("q1", "e0", ""); publishWithMarker("e0", ""); @@ -142,7 +146,7 @@ public void testDuplicateQueueDestinations() throws IOException, * add binding (e0 --> e2) * test (eN --> {q0, q1, q2}) for N in [0..2] */ - public void testExchangeRoutingLoop() throws IOException, + @Test public void exchangeRoutingLoop() throws IOException, ShutdownSignalException, InterruptedException { channel.exchangeBind("e0", "e1", ""); channel.exchangeBind("e1", "e2", ""); @@ -171,7 +175,7 @@ public void testExchangeRoutingLoop() throws IOException, * Then remove the first set of bindings from e --> eN for N in [0..2] * test publish with rk to e */ - public void testTopicExchange() throws IOException, ShutdownSignalException, + @Test public void topicExchange() throws IOException, ShutdownSignalException, InterruptedException { channel.exchangeDeclare("e", "topic"); diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java index 8773f6d29f..baf7a1ce6a 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java @@ -16,8 +16,12 @@ package com.rabbitmq.client.test.functional; +import static org.junit.Assert.fail; + import java.io.IOException; +import org.junit.Test; + import com.rabbitmq.client.AMQP; import com.rabbitmq.client.test.BrokerTestCase; @@ -48,7 +52,7 @@ protected void assertExchangeNotExists(String name) throws IOException { * build (A -> B) and (B -> A) and then delete one binding and both * exchanges should autodelete */ - public void testAutoDeleteExchangesSimpleLoop() throws IOException { + @Test public void autoDeleteExchangesSimpleLoop() throws IOException { String[] exchanges = new String[] {"A", "B"}; declareExchanges(exchanges); channel.exchangeBind("A", "B", ""); @@ -61,7 +65,7 @@ public void testAutoDeleteExchangesSimpleLoop() throws IOException { /* * build (A -> B) (B -> C) (C -> D) and then delete D. All should autodelete */ - public void testTransientAutoDelete() throws IOException { + @Test public void transientAutoDelete() throws IOException { String[] exchanges = new String[] {"A", "B", "C", "D"}; declareExchanges(exchanges); channel.exchangeBind("B", "A", ""); @@ -76,7 +80,7 @@ public void testTransientAutoDelete() throws IOException { * build (A -> B) (B -> C) (C -> D) (Source -> A) (Source -> B) (Source -> * C) (Source -> D) On removal of D, all should autodelete */ - public void testRepeatedTargetAutoDelete() throws IOException { + @Test public void repeatedTargetAutoDelete() throws IOException { String[] exchanges = new String[] {"A", "B", "C", "D"}; declareExchanges(exchanges); channel.exchangeDeclare("Source", "fanout", false, true, null); @@ -102,7 +106,7 @@ public void testRepeatedTargetAutoDelete() throws IOException { /* * build (A -> B) (B -> C) (A -> C). Delete C and they should all vanish */ - public void testAutoDeleteBindingToVanishedExchange() throws IOException { + @Test public void autoDeleteBindingToVanishedExchange() throws IOException { String[] exchanges = new String[] {"A", "B", "C"}; declareExchanges(exchanges); channel.exchangeBind("C", "B", ""); diff --git a/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java b/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java index 757674455d..923681888f 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java +++ b/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java @@ -16,9 +16,7 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.*; -import com.rabbitmq.client.impl.*; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.fail; import java.io.IOException; import java.net.Socket; @@ -26,6 +24,21 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeoutException; +import org.junit.Test; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Address; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.GetResponse; +import com.rabbitmq.client.impl.AMQCommand; +import com.rabbitmq.client.impl.AMQConnection; +import com.rabbitmq.client.impl.Frame; +import com.rabbitmq.client.impl.FrameHandler; +import com.rabbitmq.client.impl.LongStringHelper; +import com.rabbitmq.client.impl.SocketFrameHandler; +import com.rabbitmq.client.test.BrokerTestCase; + public class FrameMax extends BrokerTestCase { /* This value for FrameMax is larger than the minimum and less * than what Rabbit suggests. */ @@ -40,7 +53,7 @@ public FrameMax() { /* Publish a message of size FRAME_MAX. The broker should split * this into two frames before sending back. Frame content should * be less or equal to frame-max - 8. */ - public void testFrameSizes() + @Test public void frameSizes() throws IOException, InterruptedException { String queueName = channel.queueDeclare().getQueue(); @@ -61,7 +74,7 @@ public void testFrameSizes() /* server should reject frames larger than AMQP.FRAME_MIN_SIZE * during connection negotiation */ - public void testRejectLargeFramesDuringConnectionNegotiation() + @Test public void rejectLargeFramesDuringConnectionNegotiation() throws IOException, TimeoutException { ConnectionFactory cf = new ConnectionFactory(); cf.getClientProperties().put("too_long", LongStringHelper.asLongString(new byte[AMQP.FRAME_MIN_SIZE])); @@ -74,7 +87,7 @@ public void testRejectLargeFramesDuringConnectionNegotiation() /* server should reject frames larger than the negotiated frame * size */ - public void testRejectExceedingFrameMax() + @Test public void rejectExceedingFrameMax() throws IOException, TimeoutException { closeChannel(); closeConnection(); diff --git a/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java b/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java index 8c785982bd..e24cd2d039 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java +++ b/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java @@ -19,66 +19,66 @@ import com.rabbitmq.client.impl.WorkPoolTests; import com.rabbitmq.client.test.AbstractRMQTestSuite; import com.rabbitmq.client.test.Bug20004Test; +import com.rabbitmq.client.test.RequiredPropertiesSuite; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; -import junit.framework.TestCase; -import junit.framework.TestSuite; +@RunWith(RequiredPropertiesSuite.class) +@Suite.SuiteClasses({ + ConnectionOpen.class, + Heartbeat.class, + Tables.class, + DoubleDeletion.class, + Routing.class, + BindingLifecycle.class, + Recover.class, + Reject.class, + Transactions.class, + RequeueOnConnectionClose.class, + RequeueOnChannelClose.class, + DurableOnTransient.class, + NoRequeueOnCancel.class, + Bug20004Test.class, + ExchangeDeleteIfUnused.class, + QosTests.class, + AlternateExchange.class, + ExchangeExchangeBindings.class, + ExchangeExchangeBindingsAutoDelete.class, + ExchangeDeclare.class, + FrameMax.class, + QueueLifecycle.class, + QueueLease.class, + QueueExclusivity.class, + QueueSizeLimit.class, + InvalidAcks.class, + InvalidAcksTx.class, + DefaultExchange.class, + UnbindAutoDeleteExchange.class, + Confirm.class, + ConsumerCancelNotification.class, + UnexpectedFrames.class, + PerQueueTTL.class, + PerMessageTTL.class, + PerQueueVsPerMessageTTL.class, + DeadLetterExchange.class, + SaslMechanisms.class, + UserIDHeader.class, + InternalExchange.class, + CcRoutes.class, + WorkPoolTests.class, + HeadersExchangeValidation.class, + ConsumerPriorities.class, + Policies.class, + ConnectionRecovery.class, + ExceptionHandling.class, + PerConsumerPrefetch.class, + DirectReplyTo.class +}) +public class FunctionalTests { -public class FunctionalTests extends AbstractRMQTestSuite { - public static TestSuite suite() { - TestSuite suite = new TestSuite("functional"); - if (!requiredProperties()) return suite; - add(suite); - return suite; - } + // initialize system properties + static{ + new AbstractRMQTestSuite(){}; + } - public static void add(TestSuite suite) { - suite.addTestSuite(ConnectionOpen.class); - suite.addTestSuite(Heartbeat.class); - suite.addTestSuite(Tables.class); - suite.addTestSuite(DoubleDeletion.class); - suite.addTestSuite(Routing.class); - suite.addTestSuite(BindingLifecycle.class); - suite.addTestSuite(Recover.class); - suite.addTestSuite(Reject.class); - suite.addTestSuite(Transactions.class); - suite.addTestSuite(RequeueOnConnectionClose.class); - suite.addTestSuite(RequeueOnChannelClose.class); - suite.addTestSuite(DurableOnTransient.class); - suite.addTestSuite(NoRequeueOnCancel.class); - suite.addTestSuite(Bug20004Test.class); - suite.addTestSuite(ExchangeDeleteIfUnused.class); - suite.addTestSuite(QosTests.class); - suite.addTestSuite(AlternateExchange.class); - suite.addTestSuite(ExchangeExchangeBindings.class); - suite.addTestSuite(ExchangeExchangeBindingsAutoDelete.class); - suite.addTestSuite(ExchangeDeclare.class); - suite.addTestSuite(FrameMax.class); - suite.addTestSuite(QueueLifecycle.class); - suite.addTestSuite(QueueLease.class); - suite.addTestSuite(QueueExclusivity.class); - suite.addTestSuite(QueueSizeLimit.class); - suite.addTestSuite(InvalidAcks.class); - suite.addTestSuite(InvalidAcksTx.class); - suite.addTestSuite(DefaultExchange.class); - suite.addTestSuite(UnbindAutoDeleteExchange.class); - suite.addTestSuite(Confirm.class); - suite.addTestSuite(ConsumerCancelNotification.class); - suite.addTestSuite(UnexpectedFrames.class); - suite.addTestSuite(PerQueueTTL.class); - suite.addTestSuite(PerMessageTTL.class); - suite.addTestSuite(PerQueueVsPerMessageTTL.class); - suite.addTestSuite(DeadLetterExchange.class); - suite.addTestSuite(SaslMechanisms.class); - suite.addTestSuite(UserIDHeader.class); - suite.addTestSuite(InternalExchange.class); - suite.addTestSuite(CcRoutes.class); - suite.addTestSuite(WorkPoolTests.class); - suite.addTestSuite(HeadersExchangeValidation.class); - suite.addTestSuite(ConsumerPriorities.class); - suite.addTestSuite(Policies.class); - suite.addTestSuite(ConnectionRecovery.class); - suite.addTestSuite(ExceptionHandling.class); - suite.addTestSuite(PerConsumerPrefetch.class); - suite.addTestSuite(DirectReplyTo.class); - } } diff --git a/src/test/java/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java b/src/test/java/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java index 7959d88af6..ac28b3ed68 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java +++ b/src/test/java/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java @@ -15,16 +15,20 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.fail; import java.io.IOException; import java.util.HashMap; +import org.junit.Test; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.test.BrokerTestCase; + public class HeadersExchangeValidation extends BrokerTestCase { - public void testHeadersValidation() throws IOException + @Test public void headersValidation() throws IOException { AMQP.Queue.DeclareOk ok = channel.queueDeclare(); String queue = ok.getQueue(); diff --git a/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java b/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java index 67e63886c5..8ea14bce25 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java @@ -16,8 +16,14 @@ package com.rabbitmq.client.test.functional; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + import java.io.IOException; +import org.junit.Test; + import com.rabbitmq.client.impl.AMQConnection; import com.rabbitmq.client.test.BrokerTestCase; @@ -29,7 +35,7 @@ public Heartbeat() connectionFactory.setRequestedHeartbeat(1); } - public void testHeartbeat() + @Test public void heartbeat() throws IOException, InterruptedException { assertEquals(1, connection.getHeartbeat()); diff --git a/src/test/java/com/rabbitmq/client/test/functional/InternalExchange.java b/src/test/java/com/rabbitmq/client/test/functional/InternalExchange.java index a4091820c5..97b34bfdba 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/InternalExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/InternalExchange.java @@ -16,9 +16,13 @@ package com.rabbitmq.client.test.functional; +import static org.junit.Assert.assertTrue; + import java.io.IOException; import java.util.Arrays; +import org.junit.Test; + import com.rabbitmq.client.AMQP; import com.rabbitmq.client.GetResponse; import com.rabbitmq.client.test.BrokerTestCase; @@ -69,7 +73,7 @@ protected void createResources() throws IOException } - public void testTryPublishingToInternalExchange() + @Test public void tryPublishingToInternalExchange() throws IOException { byte[] testDataBody = "test-data".getBytes(); diff --git a/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksBase.java b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksBase.java index 18f4764272..e71404a268 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksBase.java +++ b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksBase.java @@ -20,6 +20,8 @@ import java.io.IOException; +import org.junit.Test; + /** * See bug 21846: * Basic.Ack is now required to signal a channel error immediately upon @@ -31,7 +33,7 @@ public abstract class InvalidAcksBase extends BrokerTestCase { protected abstract void select() throws IOException; protected abstract void commit() throws IOException; - public void testDoubleAck() + @Test public void doubleAck() throws IOException { select(); @@ -46,7 +48,7 @@ public void testDoubleAck() expectError(AMQP.PRECONDITION_FAILED); } - public void testCrazyAck() + @Test public void crazyAck() throws IOException { select(); diff --git a/src/test/java/com/rabbitmq/client/test/functional/MessageCount.java b/src/test/java/com/rabbitmq/client/test/functional/MessageCount.java index bced38a762..9820e6aa68 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/MessageCount.java +++ b/src/test/java/com/rabbitmq/client/test/functional/MessageCount.java @@ -15,12 +15,16 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.assertEquals; import java.io.IOException; +import org.junit.Test; + +import com.rabbitmq.client.test.BrokerTestCase; + public class MessageCount extends BrokerTestCase { - public void testMessageCount() throws IOException { + @Test public void messageCount() throws IOException { String q = generateQueueName(); channel.queueDeclare(q, false, true, false, null); assertEquals(0, channel.messageCount(q)); diff --git a/src/test/java/com/rabbitmq/client/test/functional/Nack.java b/src/test/java/com/rabbitmq/client/test/functional/Nack.java index 983355b2ea..65057cb363 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Nack.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Nack.java @@ -16,15 +16,20 @@ package com.rabbitmq.client.test.functional; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + import java.util.HashSet; import java.util.Set; +import org.junit.Test; + import com.rabbitmq.client.AMQP; import com.rabbitmq.client.QueueingConsumer; public class Nack extends AbstractRejectTest { - public void testSingleNack() throws Exception { + @Test public void singleNack() throws Exception { String q = channel.queueDeclare("", false, true, false, null).getQueue(); @@ -56,7 +61,7 @@ public void testSingleNack() throws Exception { expectError(AMQP.PRECONDITION_FAILED); } - public void testMultiNack() throws Exception { + @Test public void multiNack() throws Exception { String q = channel.queueDeclare("", false, true, false, null).getQueue(); @@ -98,7 +103,7 @@ public void testMultiNack() throws Exception { expectError(AMQP.PRECONDITION_FAILED); } - public void testNackAll() throws Exception { + @Test public void nackAll() throws Exception { String q = channel.queueDeclare("", false, true, false, null).getQueue(); diff --git a/src/test/java/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java b/src/test/java/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java index e6b91ccb8b..4e5fc0770a 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java +++ b/src/test/java/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java @@ -16,10 +16,15 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + import java.io.IOException; +import org.junit.Test; + import com.rabbitmq.client.QueueingConsumer; +import com.rabbitmq.client.test.BrokerTestCase; public class NoRequeueOnCancel extends BrokerTestCase { @@ -33,7 +38,7 @@ protected void releaseResources() throws IOException { channel.queueDelete(Q); } - public void testNoRequeueOnCancel() + @Test public void noRequeueOnCancel() throws IOException, InterruptedException { channel.basicPublish("", Q, null, "1".getBytes()); diff --git a/src/test/java/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java b/src/test/java/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java index 9c7c4de68e..31dd63f3a0 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java +++ b/src/test/java/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java @@ -15,16 +15,18 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.GetResponse; -import com.rabbitmq.client.QueueingConsumer; -import com.rabbitmq.client.QueueingConsumer.Delivery; -import com.rabbitmq.client.test.BrokerTestCase; +import static com.rabbitmq.client.test.functional.QosTests.drain; import java.io.IOException; import java.util.Arrays; import java.util.List; -import static com.rabbitmq.client.test.functional.QosTests.drain; +import org.junit.Test; + +import com.rabbitmq.client.GetResponse; +import com.rabbitmq.client.QueueingConsumer; +import com.rabbitmq.client.QueueingConsumer.Delivery; +import com.rabbitmq.client.test.BrokerTestCase; public class PerConsumerPrefetch extends BrokerTestCase { private String q; @@ -38,7 +40,7 @@ private interface Closure { public void makeMore(List deliveries) throws IOException; } - public void testSingleAck() throws IOException { + @Test public void singleAck() throws IOException { testPrefetch(new Closure() { public void makeMore(List deliveries) throws IOException { for (Delivery del : deliveries) { @@ -48,7 +50,7 @@ public void makeMore(List deliveries) throws IOException { }); } - public void testMultiAck() throws IOException { + @Test public void multiAck() throws IOException { testPrefetch(new Closure() { public void makeMore(List deliveries) throws IOException { ack(deliveries.get(deliveries.size() - 1), true); @@ -56,7 +58,7 @@ public void makeMore(List deliveries) throws IOException { }); } - public void testSingleNack() throws IOException { + @Test public void singleNack() throws IOException { for (final boolean requeue: Arrays.asList(false, true)) { testPrefetch(new Closure() { public void makeMore(List deliveries) throws IOException { @@ -68,7 +70,7 @@ public void makeMore(List deliveries) throws IOException { } } - public void testMultiNack() throws IOException { + @Test public void multiNack() throws IOException { for (final boolean requeue: Arrays.asList(false, true)) { testPrefetch(new Closure() { public void makeMore(List deliveries) throws IOException { @@ -78,7 +80,7 @@ public void makeMore(List deliveries) throws IOException { } } - public void testRecover() throws IOException { + @Test public void recover() throws IOException { testPrefetch(new Closure() { public void makeMore(List deliveries) throws IOException { channel.basicRecover(); @@ -99,7 +101,7 @@ private void testPrefetch(Closure closure) throws IOException { drain(c, 5); } - public void testPrefetchOnEmpty() throws IOException { + @Test public void prefetchOnEmpty() throws IOException { QueueingConsumer c = new QueueingConsumer(channel); publish(q, 5); consume(c, 10, false); @@ -108,14 +110,14 @@ public void testPrefetchOnEmpty() throws IOException { drain(c, 5); } - public void testAutoAckIgnoresPrefetch() throws IOException { + @Test public void autoAckIgnoresPrefetch() throws IOException { QueueingConsumer c = new QueueingConsumer(channel); publish(q, 10); consume(c, 1, true); drain(c, 10); } - public void testPrefetchZeroMeansInfinity() throws IOException { + @Test public void prefetchZeroMeansInfinity() throws IOException { QueueingConsumer c = new QueueingConsumer(channel); publish(q, 10); consume(c, 0, false); diff --git a/src/test/java/com/rabbitmq/client/test/functional/PerMessageTTL.java b/src/test/java/com/rabbitmq/client/test/functional/PerMessageTTL.java index a0fbb8898a..00a3adc98d 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/PerMessageTTL.java +++ b/src/test/java/com/rabbitmq/client/test/functional/PerMessageTTL.java @@ -16,12 +16,17 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.QueueingConsumer; -import com.rabbitmq.client.MessageProperties; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import java.io.IOException; +import org.junit.Test; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.MessageProperties; +import com.rabbitmq.client.QueueingConsumer; + public class PerMessageTTL extends TTLHandling { protected Object sessionTTL; @@ -41,7 +46,7 @@ protected AMQP.Queue.DeclareOk declareQueue(String name, Object ttlValue) throws return this.channel.queueDeclare(name, false, true, false, null); } - public void testExpiryWhenConsumerIsLateToTheParty() throws Exception { + @Test public void expiryWhenConsumerIsLateToTheParty() throws Exception { declareAndBindQueue(500); publish(MSG[0]); @@ -57,7 +62,7 @@ public void testExpiryWhenConsumerIsLateToTheParty() throws Exception { assertNull("Message should have been expired!!", c.nextDelivery(100)); } - public void testRestartingExpiry() throws Exception { + @Test public void restartingExpiry() throws Exception { final String expiryDelay = "2000"; declareDurableQueue(TTL_QUEUE_NAME); bindQueue(); diff --git a/src/test/java/com/rabbitmq/client/test/functional/PerQueueTTL.java b/src/test/java/com/rabbitmq/client/test/functional/PerQueueTTL.java index 138965f3eb..8a221e2bb6 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/PerQueueTTL.java +++ b/src/test/java/com/rabbitmq/client/test/functional/PerQueueTTL.java @@ -16,13 +16,17 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.MessageProperties; +import static org.junit.Assert.fail; import java.io.IOException; import java.util.Collections; import java.util.Map; +import org.junit.Test; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.MessageProperties; + public class PerQueueTTL extends TTLHandling { protected static final String TTL_ARG = "x-message-ttl"; @@ -33,7 +37,7 @@ protected AMQP.Queue.DeclareOk declareQueue(String name, Object ttlValue) throws return this.channel.queueDeclare(name, false, true, false, argMap); } - public void testQueueReDeclareEquivalence() throws Exception { + @Test public void queueReDeclareEquivalence() throws Exception { declareQueue(10); try { declareQueue(20); @@ -43,14 +47,14 @@ public void testQueueReDeclareEquivalence() throws Exception { } } - public void testQueueReDeclareSemanticEquivalence() throws Exception { + @Test public void queueReDeclareSemanticEquivalence() throws Exception { declareQueue((byte)10); declareQueue(10); declareQueue((short)10); declareQueue(10L); } - public void testQueueReDeclareSemanticNonEquivalence() throws Exception { + @Test public void queueReDeclareSemanticNonEquivalence() throws Exception { declareQueue(10); try { declareQueue(10.0); diff --git a/src/test/java/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java b/src/test/java/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java index 64b01b6dfa..b586c98c5d 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java +++ b/src/test/java/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java @@ -15,15 +15,19 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.AMQP; +import static org.junit.Assert.assertNull; import java.io.IOException; import java.util.Collections; import java.util.Map; +import org.junit.Test; + +import com.rabbitmq.client.AMQP; + public class PerQueueVsPerMessageTTL extends PerMessageTTL { - public void testSmallerPerQueueExpiryWins() throws IOException, InterruptedException { + @Test public void smallerPerQueueExpiryWins() throws IOException, InterruptedException { declareAndBindQueue(10); this.sessionTTL = 1000; diff --git a/src/test/java/com/rabbitmq/client/test/functional/Policies.java b/src/test/java/com/rabbitmq/client/test/functional/Policies.java index f1ae122d1c..f1dba4d33d 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Policies.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Policies.java @@ -15,11 +15,9 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.GetResponse; -import com.rabbitmq.client.test.BrokerTestCase; -import com.rabbitmq.client.test.server.HATests; -import com.rabbitmq.tools.Host; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import java.io.IOException; import java.util.HashMap; @@ -27,6 +25,14 @@ import java.util.Map; import java.util.Set; +import org.junit.Test; + +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.GetResponse; +import com.rabbitmq.client.test.BrokerTestCase; +import com.rabbitmq.client.test.server.HATests; +import com.rabbitmq.tools.Host; + public class Policies extends BrokerTestCase { private static final int DELAY = 100; // MILLIS @@ -42,7 +48,7 @@ public class Policies extends BrokerTestCase { channel.exchangeDeclare("has-ae-args", "fanout", false, false, args); } - public void testAlternateExchange() throws IOException, InterruptedException { + @Test public void alternateExchange() throws IOException, InterruptedException { String q = declareQueue(); channel.exchangeDeclare("ae", "fanout", false, true, null); channel.queueBind(q, "ae", ""); @@ -55,7 +61,7 @@ public void testAlternateExchange() throws IOException, InterruptedException { } // i.e. the argument takes priority over the policy - public void testAlternateExchangeArgs() throws IOException { + @Test public void alternateExchangeArgs() throws IOException { String q = declareQueue(); channel.exchangeDeclare("ae2", "fanout", false, true, null); channel.queueBind(q, "ae2", ""); @@ -63,7 +69,7 @@ public void testAlternateExchangeArgs() throws IOException { assertDelivered(q, 1); } - public void testDeadLetterExchange() throws IOException, InterruptedException { + @Test public void deadLetterExchange() throws IOException, InterruptedException { Map args = ttlArgs(0); String src = declareQueue("has-dlx", args); String dest = declareQueue(); @@ -81,7 +87,7 @@ public void testDeadLetterExchange() throws IOException, InterruptedException { } // again the argument takes priority over the policy - public void testDeadLetterExchangeArgs() throws IOException, InterruptedException { + @Test public void deadLetterExchangeArgs() throws IOException, InterruptedException { Map args = ttlArgs(0); args.put("x-dead-letter-exchange", "dlx2"); args.put("x-dead-letter-routing-key", "rk2"); @@ -95,7 +101,7 @@ public void testDeadLetterExchangeArgs() throws IOException, InterruptedExceptio assertEquals("rk2", resp.getEnvelope().getRoutingKey()); } - public void testTTL() throws IOException, InterruptedException { + @Test public void tTL() throws IOException, InterruptedException { String q = declareQueue("has-ttl", null); basicPublishVolatile(q); Thread.sleep(2 * DELAY); @@ -108,7 +114,7 @@ public void testTTL() throws IOException, InterruptedException { } // Test that we get lower of args and policy - public void testTTLArgs() throws IOException, InterruptedException { + @Test public void tTLArgs() throws IOException, InterruptedException { String q = declareQueue("has-ttl", ttlArgs(3 * DELAY)); basicPublishVolatile(q); Thread.sleep(2 * DELAY); @@ -123,7 +129,7 @@ public void testTTLArgs() throws IOException, InterruptedException { assertDelivered(q, 0); } - public void testExpires() throws IOException, InterruptedException { + @Test public void expires() throws IOException, InterruptedException { String q = declareQueue("has-expires", null); Thread.sleep(2 * DELAY); assertFalse(queueExists(q)); @@ -135,7 +141,7 @@ public void testExpires() throws IOException, InterruptedException { } // Test that we get lower of args and policy - public void testExpiresArgs() throws IOException, InterruptedException { + @Test public void expiresArgs() throws IOException, InterruptedException { String q = declareQueue("has-expires", args("x-expires", 3 * DELAY)); Thread.sleep(2 * DELAY); assertFalse(queueExists(q)); @@ -146,7 +152,7 @@ public void testExpiresArgs() throws IOException, InterruptedException { assertTrue(queueExists(q)); } - public void testMaxLength() throws IOException, InterruptedException { + @Test public void maxLength() throws IOException, InterruptedException { String q = declareQueue("has-max-length", null); basicPublishVolatileN(q, 3); assertDelivered(q, 1); @@ -156,7 +162,7 @@ public void testMaxLength() throws IOException, InterruptedException { assertDelivered(q, 3); } - public void testMaxLengthArgs() throws IOException, InterruptedException { + @Test public void maxLengthArgs() throws IOException, InterruptedException { String q = declareQueue("has-max-length", args("x-max-length", 2)); basicPublishVolatileN(q, 3); assertDelivered(q, 1); diff --git a/src/test/java/com/rabbitmq/client/test/functional/QosTests.java b/src/test/java/com/rabbitmq/client/test/functional/QosTests.java index dbf3b8cba0..637df3c894 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QosTests.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QosTests.java @@ -16,7 +16,11 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; @@ -27,23 +31,26 @@ import java.util.Map; import java.util.concurrent.TimeoutException; +import org.junit.Test; + import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Envelope; import com.rabbitmq.client.GetResponse; import com.rabbitmq.client.QueueingConsumer; import com.rabbitmq.client.QueueingConsumer.Delivery; +import com.rabbitmq.client.test.BrokerTestCase; public class QosTests extends BrokerTestCase { - protected void setUp() + public void setUp() throws IOException, TimeoutException { openConnection(); openChannel(); } - protected void tearDown() + public void tearDown() throws IOException { closeChannel(); @@ -83,7 +90,7 @@ public static List drain(QueueingConsumer c, int n) return res; } - public void testMessageLimitPrefetchSizeFails() + @Test public void messageLimitPrefetchSizeFails() throws IOException { try { @@ -94,7 +101,7 @@ public void testMessageLimitPrefetchSizeFails() } } - public void testMessageLimitUnlimited() + @Test public void messageLimitUnlimited() throws IOException { QueueingConsumer c = new QueueingConsumer(channel); @@ -102,7 +109,7 @@ public void testMessageLimitUnlimited() drain(c, 2); } - public void testNoAckNoAlterLimit() + @Test public void noAckNoAlterLimit() throws IOException { QueueingConsumer c = new QueueingConsumer(channel); @@ -112,7 +119,7 @@ public void testNoAckNoAlterLimit() drain(c, 2); } - public void testNoAckObeysLimit() + @Test public void noAckObeysLimit() throws IOException { channel.basicQos(1, true); @@ -135,7 +142,7 @@ public void testNoAckObeysLimit() drain(c2, 1); } - public void testPermutations() + @Test public void permutations() throws IOException { closeChannel(); @@ -152,7 +159,7 @@ public void testPermutations() } } - public void testFairness() + @Test public void fairness() throws IOException { QueueingConsumer c = new QueueingConsumer(channel); @@ -181,7 +188,7 @@ public void testFairness() } - public void testSingleChannelAndQueueFairness() + @Test public void singleChannelAndQueueFairness() throws IOException { //check that when we have multiple consumers on the same @@ -230,7 +237,7 @@ public void testSingleChannelAndQueueFairness() assertTrue(counts.get("c2").intValue() > 0); } - public void testConsumerLifecycle() + @Test public void consumerLifecycle() throws IOException { channel.basicQos(1, true); @@ -251,7 +258,7 @@ public void testConsumerLifecycle() channel.queueDelete(queue); } - public void testSetLimitAfterConsume() + @Test public void setLimitAfterConsume() throws IOException { QueueingConsumer c = new QueueingConsumer(channel); @@ -266,7 +273,7 @@ public void testSetLimitAfterConsume() drain(c, 1); } - public void testLimitIncrease() + @Test public void limitIncrease() throws IOException { QueueingConsumer c = new QueueingConsumer(channel); @@ -275,7 +282,7 @@ public void testLimitIncrease() drain(c, 1); } - public void testLimitDecrease() + @Test public void limitDecrease() throws IOException { QueueingConsumer c = new QueueingConsumer(channel); @@ -286,7 +293,7 @@ public void testLimitDecrease() drain(c, 1); } - public void testLimitedToUnlimited() + @Test public void limitedToUnlimited() throws IOException { QueueingConsumer c = new QueueingConsumer(channel); @@ -295,7 +302,7 @@ public void testLimitedToUnlimited() drain(c, 2); } - public void testLimitingMultipleChannels() + @Test public void limitingMultipleChannels() throws IOException { Channel ch1 = connection.createChannel(); @@ -319,7 +326,7 @@ public void testLimitingMultipleChannels() ch2.abort(); } - public void testLimitInheritsUnackedCount() + @Test public void limitInheritsUnackedCount() throws IOException { QueueingConsumer c = new QueueingConsumer(channel); @@ -331,7 +338,7 @@ public void testLimitInheritsUnackedCount() drain(c, 1); } - public void testRecoverReducesLimit() throws Exception { + @Test public void recoverReducesLimit() throws Exception { channel.basicQos(2, true); QueueingConsumer c = new QueueingConsumer(channel); declareBindConsume(c); diff --git a/src/test/java/com/rabbitmq/client/test/functional/QueueExclusivity.java b/src/test/java/com/rabbitmq/client/test/functional/QueueExclusivity.java index dcc994ce84..5d7f84663a 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QueueExclusivity.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QueueExclusivity.java @@ -16,10 +16,14 @@ package com.rabbitmq.client.test.functional; +import static org.junit.Assert.fail; + import java.io.IOException; import java.util.HashMap; import java.util.concurrent.TimeoutException; +import org.junit.Test; + import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; @@ -49,7 +53,7 @@ protected void releaseResources() throws IOException { } } - public void testQueueExclusiveForPassiveDeclare() throws Exception { + @Test public void queueExclusiveForPassiveDeclare() throws Exception { try { channel.queueDeclarePassive(q); } catch (IOException ioe) { @@ -61,7 +65,7 @@ public void testQueueExclusiveForPassiveDeclare() throws Exception { // This is a different scenario because active declare takes notice of // the all the arguments - public void testQueueExclusiveForDeclare() throws Exception { + @Test public void queueExclusiveForDeclare() throws Exception { try { channel.queueDeclare(q, false, true, false, noArgs); } catch (IOException ioe) { @@ -71,7 +75,7 @@ public void testQueueExclusiveForDeclare() throws Exception { fail("Active queue declaration of an exclusive queue from another connection should fail"); } - public void testQueueExclusiveForConsume() throws Exception { + @Test public void queueExclusiveForConsume() throws Exception { QueueingConsumer c = new QueueingConsumer(channel); try { channel.basicConsume(q, c); @@ -82,7 +86,7 @@ public void testQueueExclusiveForConsume() throws Exception { fail("Exclusive queue should be locked for basic consume from another connection"); } - public void testQueueExclusiveForPurge() throws Exception { + @Test public void queueExclusiveForPurge() throws Exception { try { channel.queuePurge(q); } catch (IOException ioe) { @@ -92,7 +96,7 @@ public void testQueueExclusiveForPurge() throws Exception { fail("Exclusive queue should be locked for queue purge from another connection"); } - public void testQueueExclusiveForDelete() throws Exception { + @Test public void queueExclusiveForDelete() throws Exception { try { channel.queueDelete(q); } catch (IOException ioe) { @@ -102,7 +106,7 @@ public void testQueueExclusiveForDelete() throws Exception { fail("Exclusive queue should be locked for queue delete from another connection"); } - public void testQueueExclusiveForBind() throws Exception { + @Test public void queueExclusiveForBind() throws Exception { try { channel.queueBind(q, "amq.direct", ""); } catch (IOException ioe) { @@ -119,7 +123,7 @@ public void testQueueExclusiveForBind() throws Exception { // basic.cancel is inherently local to a channel, so it // *doesn't* make sense to include it. - public void testQueueExclusiveForUnbind() throws Exception { + @Test public void queueExclusiveForUnbind() throws Exception { altChannel.queueBind(q, "amq.direct", ""); try { channel.queueUnbind(q, "amq.direct", ""); @@ -130,7 +134,7 @@ public void testQueueExclusiveForUnbind() throws Exception { fail("Exclusive queue should be locked for queue unbind from another connection"); } - public void testQueueExclusiveForGet() throws Exception { + @Test public void queueExclusiveForGet() throws Exception { try { channel.basicGet(q, true); } catch (IOException ioe) { diff --git a/src/test/java/com/rabbitmq/client/test/functional/QueueLease.java b/src/test/java/com/rabbitmq/client/test/functional/QueueLease.java index 284869acda..b5ab03a48d 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QueueLease.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QueueLease.java @@ -16,10 +16,14 @@ package com.rabbitmq.client.test.functional; +import static org.junit.Assert.fail; + import java.io.IOException; import java.util.HashMap; import java.util.Map; +import org.junit.Test; + import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Consumer; import com.rabbitmq.client.DefaultConsumer; @@ -40,19 +44,19 @@ public class QueueLease extends BrokerTestCase { * Verify that a queue with the 'x-expires` flag is actually deleted within * a sensible period of time after expiry. */ - public void testQueueExpires() throws IOException, InterruptedException { + @Test public void queueExpires() throws IOException, InterruptedException { verifyQueueExpires(TEST_EXPIRE_QUEUE, true); } /** * Verify that the server does not delete normal queues... ;) */ - public void testDoesNotExpireOthers() throws IOException, + @Test public void doesNotExpireOthers() throws IOException, InterruptedException { verifyQueueExpires(TEST_NORMAL_QUEUE, false); } - public void testExpireMayBeByte() throws IOException { + @Test public void expireMayBeByte() throws IOException { Map args = new HashMap(); args.put("x-expires", (byte)100); @@ -63,7 +67,7 @@ public void testExpireMayBeByte() throws IOException { } } - public void testExpireMayBeShort() throws IOException { + @Test public void expireMayBeShort() throws IOException { Map args = new HashMap(); args.put("x-expires", (short)100); @@ -74,7 +78,7 @@ public void testExpireMayBeShort() throws IOException { } } - public void testExpireMayBeLong() throws IOException { + @Test public void expireMayBeLong() throws IOException { Map args = new HashMap(); args.put("x-expires", 100L); @@ -85,7 +89,7 @@ public void testExpireMayBeLong() throws IOException { } } - public void testExpireMustBeGtZero() throws IOException { + @Test public void expireMustBeGtZero() throws IOException { Map args = new HashMap(); args.put("x-expires", 0); @@ -98,7 +102,7 @@ public void testExpireMustBeGtZero() throws IOException { } } - public void testExpireMustBePositive() throws IOException { + @Test public void expireMustBePositive() throws IOException { Map args = new HashMap(); args.put("x-expires", -10); @@ -115,7 +119,7 @@ public void testExpireMustBePositive() throws IOException { * Verify that the server throws an error if the client redeclares a queue * with mismatching 'x-expires' values. */ - public void testQueueRedeclareEquivalence() throws IOException { + @Test public void queueRedeclareEquivalence() throws IOException { Map args1 = new HashMap(); args1.put("x-expires", 10000); Map args2 = new HashMap(); @@ -133,7 +137,7 @@ public void testQueueRedeclareEquivalence() throws IOException { } } - public void testActiveQueueDeclareExtendsLease() + @Test public void activeQueueDeclareExtendsLease() throws InterruptedException, IOException { Map args = new HashMap(); args.put("x-expires", QUEUE_EXPIRES); @@ -156,7 +160,7 @@ public void testActiveQueueDeclareExtendsLease() } } - public void testPassiveQueueDeclareExtendsLease() + @Test public void passiveQueueDeclareExtendsLease() throws InterruptedException, IOException { Map args = new HashMap(); args.put("x-expires", QUEUE_EXPIRES); @@ -179,7 +183,7 @@ public void testPassiveQueueDeclareExtendsLease() } } - public void testExpiresWithConsumers() + @Test public void expiresWithConsumers() throws InterruptedException, IOException { Map args = new HashMap(); args.put("x-expires", QUEUE_EXPIRES); diff --git a/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java b/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java index e7c6885f88..bb142d9b2f 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java @@ -16,15 +16,17 @@ package com.rabbitmq.client.test.functional; +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.QueueingConsumer; +import com.rabbitmq.client.test.BrokerTestCase; +import org.junit.Test; + import java.io.IOException; -import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeoutException; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.QueueingConsumer; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.fail; /** * Test queue auto-delete and exclusive semantics. @@ -87,7 +89,7 @@ void verifyNotEquivalent(boolean durable, boolean exclusive, * Declare-Ok if the requested queue matches these fields, and MUST * raise a channel exception if not." */ - public void testQueueEquivalence() throws IOException { + @Test public void queueEquivalence() throws IOException { String q = "queue"; channel.queueDeclare(q, false, false, false, null); // equivalent @@ -102,22 +104,22 @@ public void testQueueEquivalence() throws IOException { } // not equivalent in various ways - public void testQueueNonEquivalenceDurable() throws IOException { + @Test public void queueNonEquivalenceDurable() throws IOException { verifyNotEquivalent(true, false, false); } - public void testQueueNonEquivalenceExclusive() throws IOException { + @Test public void queueNonEquivalenceExclusive() throws IOException { verifyNotEquivalent(false, true, false); } - public void testQueueNonEquivalenceAutoDelete() throws IOException { + @Test public void queueNonEquivalenceAutoDelete() throws IOException { verifyNotEquivalent(false, false, true); } // Note that this assumes that auto-deletion is synchronous with // basic.cancel, // which is not actually in the spec. (If it isn't, there's a race here). - public void testQueueAutoDelete() throws IOException { + @Test public void queueAutoDelete() throws IOException { String name = "tempqueue"; channel.queueDeclare(name, false, false, true, null); // now it's there @@ -135,7 +137,7 @@ public void testQueueAutoDelete() throws IOException { fail("Queue should have been auto-deleted after we removed its only consumer"); } - public void testExclusiveNotAutoDelete() throws IOException { + @Test public void exclusiveNotAutoDelete() throws IOException { String name = "exclusivequeue"; channel.queueDeclare(name, false, true, false, null); // now it's there @@ -147,7 +149,7 @@ public void testExclusiveNotAutoDelete() throws IOException { verifyQueueExists(name); } - public void testExclusiveGoesWithConnection() throws IOException, TimeoutException { + @Test public void exclusiveGoesWithConnection() throws IOException, TimeoutException { String name = "exclusivequeue2"; channel.queueDeclare(name, false, true, false, null); // now it's there @@ -158,7 +160,7 @@ public void testExclusiveGoesWithConnection() throws IOException, TimeoutExcepti verifyQueueMissing(name); } - public void testArgumentArrays() throws IOException { + @Test public void argumentArrays() throws IOException { Map args = new HashMap(); String[] arr = new String[]{"foo", "bar", "baz"}; args.put("my-key", arr); @@ -167,7 +169,7 @@ public void testArgumentArrays() throws IOException { verifyQueue(queueName, true, true, false, args); } - public void testQueueNamesLongerThan255Characters() throws IOException { + @Test public void queueNamesLongerThan255Characters() throws IOException { String q = new String(new byte[300]).replace('\u0000', 'x'); try { channel.queueDeclare(q, false, false, false, null); @@ -176,4 +178,5 @@ public void testQueueNamesLongerThan255Characters() throws IOException { // expected } } + } diff --git a/src/test/java/com/rabbitmq/client/test/functional/QueueSizeLimit.java b/src/test/java/com/rabbitmq/client/test/functional/QueueSizeLimit.java index 411c040a78..7bec3e47c2 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QueueSizeLimit.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QueueSizeLimit.java @@ -16,14 +16,21 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.GetResponse; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import org.junit.Test; + +import com.rabbitmq.client.GetResponse; +import com.rabbitmq.client.test.BrokerTestCase; + /** * Test queue max length limit. */ @@ -32,7 +39,7 @@ public class QueueSizeLimit extends BrokerTestCase { private final int MAXMAXLENGTH = 3; private final String q = "queue-maxlength"; - public void testQueueSize() throws IOException, InterruptedException { + @Test public void queueSize() throws IOException, InterruptedException { for (int maxLen = 0; maxLen <= MAXMAXLENGTH; maxLen ++){ setupNonDlxTest(maxLen, false); assertHead(maxLen, "msg2", q); @@ -40,7 +47,7 @@ public void testQueueSize() throws IOException, InterruptedException { } } - public void testQueueSizeUnacked() throws IOException, InterruptedException { + @Test public void queueSizeUnacked() throws IOException, InterruptedException { for (int maxLen = 0; maxLen <= MAXMAXLENGTH; maxLen ++){ setupNonDlxTest(maxLen, true); assertHead(maxLen > 0 ? 1 : 0, "msg" + (maxLen + 1), q); @@ -48,7 +55,7 @@ public void testQueueSizeUnacked() throws IOException, InterruptedException { } } - public void testQueueSizeDlx() throws IOException, InterruptedException { + @Test public void queueSizeDlx() throws IOException, InterruptedException { for (int maxLen = 0; maxLen <= MAXMAXLENGTH; maxLen ++){ setupDlxTest(maxLen, false); assertHead(1, "msg1", "DLQ"); @@ -57,7 +64,7 @@ public void testQueueSizeDlx() throws IOException, InterruptedException { } } - public void testQueueSizeUnackedDlx() throws IOException, InterruptedException { + @Test public void queueSizeUnackedDlx() throws IOException, InterruptedException { for (int maxLen = 0; maxLen <= MAXMAXLENGTH; maxLen ++){ setupDlxTest(maxLen, true); assertHead(maxLen > 0 ? 0 : 1, "msg1", "DLQ"); @@ -66,7 +73,7 @@ public void testQueueSizeUnackedDlx() throws IOException, InterruptedException } } - public void testRequeue() throws IOException, InterruptedException { + @Test public void requeue() throws IOException, InterruptedException { for (int maxLen = 1; maxLen <= MAXMAXLENGTH; maxLen ++) { declareQueue(maxLen, false); setupRequeueTest(maxLen); @@ -75,7 +82,7 @@ public void testRequeue() throws IOException, InterruptedException { } } - public void testRequeueWithDlx() throws IOException, InterruptedException { + @Test public void requeueWithDlx() throws IOException, InterruptedException { for (int maxLen = 1; maxLen <= MAXMAXLENGTH; maxLen ++) { declareQueue(maxLen, true); setupRequeueTest(maxLen); diff --git a/src/test/java/com/rabbitmq/client/test/functional/Recover.java b/src/test/java/com/rabbitmq/client/test/functional/Recover.java index e54f4591f4..bb1e858c83 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Recover.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Recover.java @@ -16,15 +16,19 @@ package com.rabbitmq.client.test.functional; -import java.util.Arrays; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + import java.io.IOException; +import java.util.Arrays; + +import org.junit.Test; import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.QueueingConsumer; import com.rabbitmq.client.Channel; -import com.rabbitmq.client.Command; -import com.rabbitmq.client.ShutdownSignalException; - +import com.rabbitmq.client.QueueingConsumer; import com.rabbitmq.client.test.BrokerTestCase; public class Recover extends BrokerTestCase { @@ -85,21 +89,21 @@ public void recover(Channel channel) throws IOException { } }; - public void testRedeliveryOnRecover() throws IOException, InterruptedException { + @Test public void redeliveryOnRecover() throws IOException, InterruptedException { verifyRedeliverOnRecover(recoverSync); } - public void testRedeliverOnRecoverConvenience() + @Test public void redeliverOnRecoverConvenience() throws IOException, InterruptedException { verifyRedeliverOnRecover(recoverSyncConvenience); } - public void testNoRedeliveryWithAutoAck() + @Test public void noRedeliveryWithAutoAck() throws IOException, InterruptedException { verifyNoRedeliveryWithAutoAck(recoverSync); } - public void testRequeueFalseNotSupported() throws Exception { + @Test public void requeueFalseNotSupported() throws Exception { try { channel.basicRecover(false); fail("basicRecover(false) should not be supported"); diff --git a/src/test/java/com/rabbitmq/client/test/functional/Reject.java b/src/test/java/com/rabbitmq/client/test/functional/Reject.java index 7f3ebb80f9..0a99111137 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Reject.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Reject.java @@ -16,14 +16,18 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.QueueingConsumer; +import static org.junit.Assert.assertNull; import java.io.IOException; +import org.junit.Test; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.QueueingConsumer; + public class Reject extends AbstractRejectTest { - public void testReject() + @Test public void reject() throws IOException, InterruptedException { String q = channel.queueDeclare("", false, true, false, null).getQueue(); diff --git a/src/test/java/com/rabbitmq/client/test/functional/RequeueOnClose.java b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnClose.java index 60bdb6d163..35150997a8 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/RequeueOnClose.java +++ b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnClose.java @@ -15,6 +15,10 @@ package com.rabbitmq.client.test.functional; +import static org.junit.Assert.*; +import org.junit.Test; + + import com.rabbitmq.client.test.BrokerTestCase; import java.io.IOException; import java.util.concurrent.CountDownLatch; @@ -42,13 +46,13 @@ public abstract class RequeueOnClose protected abstract void close() throws IOException; - protected void setUp() + public void setUp() throws IOException { // Override to disable the default behaviour from BrokerTestCase. } - protected void tearDown() + public void tearDown() throws IOException { // Override to disable the default behaviour from BrokerTestCase. @@ -93,7 +97,7 @@ private void publishAndGet(int count, boolean doAck) * Test we don't requeue acknowledged messages (using get) * @throws Exception untested */ - public void testNormal() throws Exception + @Test public void normal() throws Exception { publishAndGet(3, true); } @@ -102,7 +106,7 @@ public void testNormal() throws Exception * Test we requeue unacknowledged messages (using get) * @throws Exception untested */ - public void testRequeueing() throws Exception + @Test public void requeueing() throws Exception { publishAndGet(3, false); } @@ -111,7 +115,7 @@ public void testRequeueing() throws Exception * Test we requeue unacknowledged message (using consumer) * @throws Exception untested */ - public void testRequeueingConsumer() throws Exception + @Test public void requeueingConsumer() throws Exception { openConnection(); open(); @@ -155,7 +159,7 @@ private void publishLotsAndGet() * Test close while consuming many messages successfully requeues unacknowledged messages * @throws Exception untested */ - public void testRequeueInFlight() throws Exception + @Test public void requeueInFlight() throws Exception { for (int i = 0; i < 5; i++) { publishLotsAndGet(); @@ -166,7 +170,7 @@ public void testRequeueInFlight() throws Exception * Test close while consuming partially not acked with cancel successfully requeues unacknowledged messages * @throws Exception untested */ - public void testRequeueInFlightConsumerNoAck() throws Exception + @Test public void requeueInFlightConsumerNoAck() throws Exception { for (int i = 0; i < 5; i++) { publishLotsAndConsumeSome(false, true); @@ -177,7 +181,7 @@ public void testRequeueInFlightConsumerNoAck() throws Exception * Test close while consuming partially acked with cancel successfully requeues unacknowledged messages * @throws Exception untested */ - public void testRequeueInFlightConsumerAck() throws Exception + @Test public void requeueInFlightConsumerAck() throws Exception { for (int i = 0; i < 5; i++) { publishLotsAndConsumeSome(true, true); @@ -188,7 +192,7 @@ public void testRequeueInFlightConsumerAck() throws Exception * Test close while consuming partially not acked without cancel successfully requeues unacknowledged messages * @throws Exception untested */ - public void testRequeueInFlightConsumerNoAckNoCancel() throws Exception + @Test public void requeueInFlightConsumerNoAckNoCancel() throws Exception { for (int i = 0; i < 5; i++) { publishLotsAndConsumeSome(false, false); @@ -199,7 +203,7 @@ public void testRequeueInFlightConsumerNoAckNoCancel() throws Exception * Test close while consuming partially acked without cancel successfully requeues unacknowledged messages * @throws Exception untested */ - public void testRequeueInFlightConsumerAckNoCancel() throws Exception + @Test public void requeueInFlightConsumerAckNoCancel() throws Exception { for (int i = 0; i < 5; i++) { publishLotsAndConsumeSome(true, false); diff --git a/src/test/java/com/rabbitmq/client/test/functional/Routing.java b/src/test/java/com/rabbitmq/client/test/functional/Routing.java index a10fc6e3ee..f4efdab194 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Routing.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Routing.java @@ -16,20 +16,27 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.AlreadyClosedException; -import com.rabbitmq.client.test.BrokerTestCase; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.GetResponse; -import com.rabbitmq.client.ReturnListener; -import com.rabbitmq.utility.BlockingCell; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; import java.io.IOException; -import java.util.List; import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.TimeoutException; +import org.junit.Test; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.AlreadyClosedException; +import com.rabbitmq.client.GetResponse; +import com.rabbitmq.client.ReturnListener; +import com.rabbitmq.client.test.BrokerTestCase; +import com.rabbitmq.utility.BlockingCell; + public class Routing extends BrokerTestCase { @@ -81,7 +88,7 @@ private void checkGet(String queue, boolean messageExpected) * of the spec. See the doc for the "queue" and "routing key" * fields of queue.bind. */ - public void testMRDQRouting() + @Test public void mRDQRouting() throws IOException { bind(Q1, "baz"); //Q1, "baz" @@ -99,7 +106,7 @@ public void testMRDQRouting() * NOT receive duplicate copies of a message that matches both * bindings. */ - public void testDoubleBinding() + @Test public void doubleBinding() throws IOException { channel.queueBind(Q1, "amq.topic", "x.#"); @@ -115,7 +122,7 @@ public void testDoubleBinding() checkGet(Q1, false); } - public void testFanoutRouting() throws Exception { + @Test public void fanoutRouting() throws Exception { List queues = new ArrayList(); @@ -138,7 +145,7 @@ public void testFanoutRouting() throws Exception { } } - public void testTopicRouting() throws Exception { + @Test public void topicRouting() throws Exception { List queues = new ArrayList(); @@ -158,7 +165,7 @@ public void testTopicRouting() throws Exception { } } - public void testHeadersRouting() throws Exception { + @Test public void headersRouting() throws Exception { Map spec = new HashMap(); spec.put("h1", "12345"); spec.put("h2", "bar"); @@ -233,7 +240,7 @@ public void testHeadersRouting() throws Exception { checkGet(Q2, false); } - public void testBasicReturn() throws IOException { + @Test public void basicReturn() throws IOException { channel.addReturnListener(makeReturnListener()); returnCell = new BlockingCell(); @@ -257,7 +264,7 @@ public void testBasicReturn() throws IOException { } } - public void testBasicReturnTransactional() throws IOException { + @Test public void basicReturnTransactional() throws IOException { channel.txSelect(); channel.addReturnListener(makeReturnListener()); returnCell = new BlockingCell(); diff --git a/src/test/java/com/rabbitmq/client/test/functional/SaslMechanisms.java b/src/test/java/com/rabbitmq/client/test/functional/SaslMechanisms.java index 2946e73537..ae12330eba 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/SaslMechanisms.java +++ b/src/test/java/com/rabbitmq/client/test/functional/SaslMechanisms.java @@ -15,6 +15,15 @@ package com.rabbitmq.client.test.functional; +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Map; +import java.util.concurrent.TimeoutException; + +import org.junit.Test; + import com.rabbitmq.client.AuthenticationFailureException; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; @@ -26,11 +35,6 @@ import com.rabbitmq.client.impl.LongStringHelper; import com.rabbitmq.client.test.BrokerTestCase; -import java.io.IOException; -import java.util.Arrays; -import java.util.Map; -import java.util.concurrent.TimeoutException; - public class SaslMechanisms extends BrokerTestCase { private String[] mechanisms; @@ -69,19 +73,19 @@ public SaslMechanism getSaslMechanism(String[] mechanisms) { } } - public void testPlainLogin() throws IOException, TimeoutException { + @Test public void plainLogin() throws IOException, TimeoutException { loginOk("PLAIN", new byte[][] {"\0guest\0guest".getBytes()} ); loginBad("PLAIN", new byte[][] {"\0guest\0wrong".getBytes()} ); } - public void testAMQPlainLogin() throws IOException, TimeoutException { + @Test public void aMQPlainLogin() throws IOException, TimeoutException { // guest / guest loginOk("AMQPLAIN", new byte[][] {{5,76,79,71,73,78,83,0,0,0,5,103,117,101,115,116,8,80,65,83,83,87,79,82,68,83,0,0,0,5,103,117,101,115,116}} ); // guest / wrong loginBad("AMQPLAIN", new byte[][] {{5,76,79,71,73,78,83,0,0,0,5,103,117,101,115,116,8,80,65,83,83,87,79,82,68,83,0,0,0,5,119,114,111,110,103}} ); } - public void testCRLogin() throws IOException, TimeoutException { + @Test public void cRLogin() throws IOException, TimeoutException { // Make sure mechanisms is populated loginOk("PLAIN", new byte[][] {"\0guest\0guest".getBytes()} ); @@ -92,11 +96,11 @@ public void testCRLogin() throws IOException, TimeoutException { } } - public void testConnectionCloseAuthFailureUsername() throws IOException, TimeoutException { + @Test public void connectionCloseAuthFailureUsername() throws IOException, TimeoutException { connectionCloseAuthFailure("incorrect-username", "incorrect-password"); } - public void testConnectionCloseAuthFailurePassword() throws IOException, TimeoutException { + @Test public void connectionCloseAuthFailurePassword() throws IOException, TimeoutException { connectionCloseAuthFailure(connectionFactory.getUsername(), "incorrect-password"); } diff --git a/src/test/java/com/rabbitmq/client/test/functional/TTLHandling.java b/src/test/java/com/rabbitmq/client/test/functional/TTLHandling.java index 83e139de3f..e60c89c255 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/TTLHandling.java +++ b/src/test/java/com/rabbitmq/client/test/functional/TTLHandling.java @@ -15,13 +15,20 @@ package com.rabbitmq.client.test.functional; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; + +import java.io.IOException; + +import org.junit.Test; + import com.rabbitmq.client.AMQP; import com.rabbitmq.client.GetResponse; import com.rabbitmq.client.QueueingConsumer; import com.rabbitmq.client.test.BrokerTestCase; -import java.io.IOException; - public abstract class TTLHandling extends BrokerTestCase { protected static final String TTL_EXCHANGE = "ttl.exchange"; @@ -40,7 +47,7 @@ protected void releaseResources() throws IOException { this.channel.exchangeDelete(TTL_EXCHANGE); } - public void testMultipleTTLTypes() throws IOException { + @Test public void multipleTTLTypes() throws IOException { final Object[] args = { (((byte)200) & (0xff)), (short)200, 200, 200L }; for (Object ttl : args) { try { @@ -53,7 +60,7 @@ public void testMultipleTTLTypes() throws IOException { } } - public void testInvalidTypeUsedInTTL() throws Exception { + @Test public void invalidTypeUsedInTTL() throws Exception { try { declareAndBindQueue("foobar"); publishAndSync(MSG[0]); @@ -63,7 +70,7 @@ public void testInvalidTypeUsedInTTL() throws Exception { } } - public void testTrailingCharsUsedInTTL() throws Exception { + @Test public void trailingCharsUsedInTTL() throws Exception { try { declareAndBindQueue("10000foobar"); publishAndSync(MSG[0]); @@ -73,7 +80,7 @@ public void testTrailingCharsUsedInTTL() throws Exception { } } - public void testTTLMustBePositive() throws Exception { + @Test public void tTLMustBePositive() throws Exception { try { declareAndBindQueue(-10); publishAndSync(MSG[0]); @@ -83,7 +90,7 @@ public void testTTLMustBePositive() throws Exception { } } - public void testTTLAllowZero() throws Exception { + @Test public void tTLAllowZero() throws Exception { try { declareQueue(0); publishAndSync(MSG[0]); @@ -92,7 +99,7 @@ public void testTTLAllowZero() throws Exception { } } - public void testMessagesExpireWhenUsingBasicGet() throws Exception { + @Test public void messagesExpireWhenUsingBasicGet() throws Exception { declareAndBindQueue(200); publish(MSG[0]); Thread.sleep(1000); @@ -101,7 +108,7 @@ public void testMessagesExpireWhenUsingBasicGet() throws Exception { assertNull("expected message " + what + " to have been removed", what); } - public void testPublishAndGetWithExpiry() throws Exception { + @Test public void publishAndGetWithExpiry() throws Exception { declareAndBindQueue(200); publish(MSG[0]); @@ -117,7 +124,7 @@ public void testPublishAndGetWithExpiry() throws Exception { assertNull(get()); } - public void testTransactionalPublishWithGet() throws Exception { + @Test public void transactionalPublishWithGet() throws Exception { declareAndBindQueue(100); this.channel.txSelect(); @@ -135,7 +142,7 @@ public void testTransactionalPublishWithGet() throws Exception { assertNull(get()); } - public void testExpiryWithRequeue() throws Exception { + @Test public void expiryWithRequeue() throws Exception { declareAndBindQueue(200); publish(MSG[0]); @@ -157,7 +164,7 @@ public void testExpiryWithRequeue() throws Exception { /* * Test expiry of re-queued messages after being consumed instantly */ - public void testExpiryWithReQueueAfterConsume() throws Exception { + @Test public void expiryWithReQueueAfterConsume() throws Exception { declareAndBindQueue(100); QueueingConsumer c = new QueueingConsumer(channel); channel.basicConsume(TTL_QUEUE_NAME, c); @@ -172,7 +179,7 @@ public void testExpiryWithReQueueAfterConsume() throws Exception { assertNull("Re-queued message not expired", get()); } - public void testZeroTTLDelivery() throws Exception { + @Test public void zeroTTLDelivery() throws Exception { declareAndBindQueue(0); // when there is no consumer, message should expire diff --git a/src/test/java/com/rabbitmq/client/test/functional/Tables.java b/src/test/java/com/rabbitmq/client/test/functional/Tables.java index 0e72ea11e6..73d98cd014 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Tables.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Tables.java @@ -16,25 +16,30 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.test.BrokerTestCase; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.impl.LongStringHelper; -import com.rabbitmq.client.AMQP.BasicProperties; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import java.io.IOException; +import java.math.BigDecimal; +import java.util.ArrayList; import java.util.Arrays; -import java.util.Map; -import java.util.List; +import java.util.HashMap; import java.util.Iterator; -import java.util.ArrayList; +import java.util.List; +import java.util.Map; import java.util.Set; -import java.util.HashMap; -import java.math.BigDecimal; + +import org.junit.Test; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.AMQP.BasicProperties; +import com.rabbitmq.client.impl.LongStringHelper; +import com.rabbitmq.client.test.BrokerTestCase; public class Tables extends BrokerTestCase { - public void testTypes() throws IOException { + @Test public void types() throws IOException { Map table = new HashMap(); Map subTable = new HashMap(); diff --git a/src/test/java/com/rabbitmq/client/test/functional/Transactions.java b/src/test/java/com/rabbitmq/client/test/functional/Transactions.java index 5276be217e..ff677dde35 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Transactions.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Transactions.java @@ -16,12 +16,18 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; + import java.io.IOException; import java.util.concurrent.TimeoutException; +import org.junit.Test; + +import com.rabbitmq.client.AMQP; import com.rabbitmq.client.GetResponse; +import com.rabbitmq.client.test.BrokerTestCase; public class Transactions extends BrokerTestCase { @@ -108,7 +114,7 @@ private long[] publishSelectAndGet(int n) /* publishes are embargoed until commit */ - public void testCommitPublish() + @Test public void commitPublish() throws IOException { txSelect(); @@ -122,7 +128,7 @@ public void testCommitPublish() /* rollback rolls back publishes */ - public void testRollbackPublish() + @Test public void rollbackPublish() throws IOException { txSelect(); @@ -134,7 +140,7 @@ public void testRollbackPublish() /* closing a channel rolls back publishes */ - public void testRollbackPublishOnClose() + @Test public void rollbackPublishOnClose() throws IOException { txSelect(); @@ -147,7 +153,7 @@ public void testRollbackPublishOnClose() /* closing a channel requeues both ack'ed and un-ack'ed messages */ - public void testRequeueOnClose() + @Test public void requeueOnClose() throws IOException { basicPublish(); @@ -168,7 +174,7 @@ public void testRequeueOnClose() messages with committed acks are not requeued on channel close, messages that weren't ack'ed are requeued on close, but not before then. */ - public void testCommitAcks() + @Test public void commitAcks() throws IOException { basicPublish(); @@ -188,7 +194,7 @@ public void testCommitAcks() /* */ - public void testCommitAcksOutOfOrder() + @Test public void commitAcksOutOfOrder() throws IOException { long tags[] = publishSelectAndGet(4); @@ -203,7 +209,7 @@ public void testCommitAcksOutOfOrder() rollback rolls back acks and a rolled back ack can be re-issued */ - public void testRollbackAcksAndReAck() + @Test public void rollbackAcksAndReAck() throws IOException { basicPublish(); @@ -222,7 +228,7 @@ public void testRollbackAcksAndReAck() /* it is illegal to ack with an unknown delivery tag */ - public void testUnknownTagAck() + @Test public void unknownTagAck() throws IOException { basicPublish(); @@ -238,7 +244,7 @@ public void testUnknownTagAck() /* rollback does not requeue delivered ack'ed or un-ack'ed messages */ - public void testNoRequeueOnRollback() + @Test public void noRequeueOnRollback() throws IOException { basicPublish(); @@ -254,7 +260,7 @@ public void testNoRequeueOnRollback() /* auto-acks are not part of tx */ - public void testAutoAck() + @Test public void autoAck() throws IOException { basicPublish(); @@ -268,7 +274,7 @@ public void testAutoAck() /* "ack all", once committed, acks all delivered messages */ - public void testAckAll() + @Test public void ackAll() throws IOException { basicPublish(); @@ -283,7 +289,7 @@ public void testAckAll() assertNull(basicGet()); } - public void testNonTransactedCommit() + @Test public void nonTransactedCommit() throws IOException { try { @@ -294,7 +300,7 @@ public void testNonTransactedCommit() } } - public void testNonTransactedRollback() + @Test public void nonTransactedRollback() throws IOException { try { @@ -305,7 +311,7 @@ public void testNonTransactedRollback() } } - public void testRedeliverAckedUncommitted() + @Test public void redeliverAckedUncommitted() throws IOException { txSelect(); @@ -322,7 +328,7 @@ public void testRedeliverAckedUncommitted() basicGet(true)); } - public void testCommitWithDeletedQueue() + @Test public void commitWithDeletedQueue() throws IOException, TimeoutException { txSelect(); basicPublish(); @@ -339,7 +345,7 @@ public void testCommitWithDeletedQueue() } } - public void testShuffleAcksBeforeRollback() + @Test public void shuffleAcksBeforeRollback() throws IOException { long tags[] = publishSelectAndGet(3); @@ -432,37 +438,37 @@ public void commitAcksAndNacks(NackMethod method) assertNull(basicGet()); } - public void testCommitNacks() + @Test public void commitNacks() throws IOException { commitNacks(basicNack); } - public void testRollbackNacks() + @Test public void rollbackNacks() throws IOException { rollbackNacks(basicNack); } - public void testCommitAcksAndNacks() + @Test public void commitAcksAndNacks() throws IOException { commitAcksAndNacks(basicNack); } - public void testCommitRejects() + @Test public void commitRejects() throws IOException { commitNacks(basicReject); } - public void testRollbackRejects() + @Test public void rollbackRejects() throws IOException { rollbackNacks(basicReject); } - public void testCommitAcksAndRejects() + @Test public void commitAcksAndRejects() throws IOException { commitAcksAndNacks(basicReject); diff --git a/src/test/java/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java b/src/test/java/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java index 6678c6c0c2..cb9491a6e7 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java @@ -15,17 +15,21 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.fail; import java.io.IOException; +import org.junit.Test; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.test.BrokerTestCase; + /** * Test that unbinding from an auto-delete exchange causes the exchange to go * away */ public class UnbindAutoDeleteExchange extends BrokerTestCase { - public void testUnbind() throws IOException, InterruptedException { + @Test public void unbind() throws IOException, InterruptedException { String exchange = "myexchange"; channel.exchangeDeclare(exchange, "fanout", false, true, null); String queue = channel.queueDeclare().getQueue(); diff --git a/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java b/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java index b79caf2e00..3c236c1ef5 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java +++ b/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java @@ -18,6 +18,10 @@ import java.io.IOException; import java.net.Socket; +import javax.net.SocketFactory; + +import org.junit.Test; + import com.rabbitmq.client.AMQP; import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.DefaultSocketConfigurator; @@ -28,8 +32,6 @@ import com.rabbitmq.client.impl.SocketFrameHandler; import com.rabbitmq.client.test.BrokerTestCase; -import javax.net.SocketFactory; - /** * Test that the server correctly handles us when we send it bad frames */ @@ -90,7 +92,7 @@ public UnexpectedFrames() { connectionFactory = new ConfusedConnectionFactory(); } - public void testMissingHeader() throws IOException { + @Test public void missingHeader() throws IOException { expectUnexpectedFrameError(new Confuser() { public Frame confuse(Frame frame) { if (frame.type == AMQP.FRAME_HEADER) { @@ -101,7 +103,7 @@ public Frame confuse(Frame frame) { }); } - public void testMissingMethod() throws IOException { + @Test public void missingMethod() throws IOException { expectUnexpectedFrameError(new Confuser() { public Frame confuse(Frame frame) { if (frame.type == AMQP.FRAME_METHOD) { @@ -115,7 +117,7 @@ public Frame confuse(Frame frame) { }); } - public void testMissingBody() throws IOException { + @Test public void missingBody() throws IOException { expectUnexpectedFrameError(new Confuser() { public Frame confuse(Frame frame) { if (frame.type == AMQP.FRAME_BODY) { @@ -126,7 +128,7 @@ public Frame confuse(Frame frame) { }); } - public void testWrongClassInHeader() throws IOException { + @Test public void wrongClassInHeader() throws IOException { expectUnexpectedFrameError(new Confuser() { public Frame confuse(Frame frame) { if (frame.type == AMQP.FRAME_HEADER) { @@ -144,7 +146,7 @@ public Frame confuse(Frame frame) { }); } - public void testHeartbeatOnChannel() throws IOException { + @Test public void heartbeatOnChannel() throws IOException { expectUnexpectedFrameError(new Confuser() { public Frame confuse(Frame frame) { if (frame.type == AMQP.FRAME_METHOD) { @@ -155,7 +157,7 @@ public Frame confuse(Frame frame) { }); } - public void testUnknownFrameType() throws IOException { + @Test public void unknownFrameType() throws IOException { expectError(AMQP.FRAME_ERROR, new Confuser() { public Frame confuse(Frame frame) { if (frame.type == AMQP.FRAME_METHOD) { diff --git a/src/test/java/com/rabbitmq/client/test/functional/UserIDHeader.java b/src/test/java/com/rabbitmq/client/test/functional/UserIDHeader.java index ad5ba89ff4..e31bb64bb1 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/UserIDHeader.java +++ b/src/test/java/com/rabbitmq/client/test/functional/UserIDHeader.java @@ -15,23 +15,27 @@ package com.rabbitmq.client.test.functional; +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.util.concurrent.TimeoutException; + +import org.junit.Test; + import com.rabbitmq.client.AMQP; import com.rabbitmq.client.AlreadyClosedException; import com.rabbitmq.client.test.BrokerTestCase; import com.rabbitmq.tools.Host; -import java.io.IOException; -import java.util.concurrent.TimeoutException; - public class UserIDHeader extends BrokerTestCase { private static final AMQP.BasicProperties GOOD = new AMQP.BasicProperties.Builder().userId("guest").build(); private static final AMQP.BasicProperties BAD = new AMQP.BasicProperties.Builder().userId("not the guest, honest").build(); - public void testValidUserId() throws IOException { + @Test public void validUserId() throws IOException { publish(GOOD); } - public void testInvalidUserId() { + @Test public void invalidUserId() { try { publish(BAD); fail("Accepted publish with incorrect user ID"); @@ -42,7 +46,7 @@ public void testInvalidUserId() { } } - public void testImpersonatedUserId() throws IOException, TimeoutException { + @Test public void impersonatedUserId() throws IOException, TimeoutException { Host.rabbitmqctl("set_user_tags guest administrator impersonator"); connection = null; channel = null; diff --git a/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java b/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java index 716ac7c195..b4b55d1c64 100644 --- a/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java +++ b/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java @@ -18,11 +18,14 @@ import com.rabbitmq.client.AMQP; import com.rabbitmq.client.test.functional.ClusteredTestBase; -import com.rabbitmq.tools.Host; +import org.junit.Test; import java.io.IOException; import java.util.concurrent.TimeoutException; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.fail; + /** * This tests whether 'absent' queues - durable queues whose home node * is down - are handled properly. @@ -31,13 +34,13 @@ public class AbsentQueue extends ClusteredTestBase { private static final String Q = "absent-queue"; - @Override protected void setUp() throws IOException, TimeoutException { + @Override public void setUp() throws IOException, TimeoutException { super.setUp(); if (clusteredConnection != null) stopSecondary(); } - @Override protected void tearDown() throws IOException, TimeoutException { + @Override public void tearDown() throws IOException, TimeoutException { if (clusteredConnection != null) startSecondary(); super.tearDown(); @@ -51,7 +54,7 @@ public class AbsentQueue extends ClusteredTestBase { alternateChannel.queueDelete(Q); } - public void testNotFound() throws IOException { + @Test public void notFound() throws IOException { assertNotFound(new Task() { public void run() throws IOException { channel.queueDeclare(Q, true, false, false, null); diff --git a/src/test/java/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java b/src/test/java/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java index d2eae1bc79..213240039d 100644 --- a/src/test/java/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java +++ b/src/test/java/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java @@ -16,9 +16,11 @@ package com.rabbitmq.client.test.server; -import java.util.Map; -import java.util.HashMap; import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.junit.Test; import com.rabbitmq.client.test.functional.ExchangeEquivalenceBase; @@ -28,12 +30,12 @@ public class AlternateExchangeEquivalence extends ExchangeEquivalenceBase { args.put("alternate-exchange", "UME"); } - public void testAlternateExchangeEquivalence() throws IOException { + @Test public void alternateExchangeEquivalence() throws IOException { channel.exchangeDeclare("alternate", "direct", false, false, args); verifyEquivalent("alternate", "direct", false, false, args); } - public void testAlternateExchangeNonEquivalence() throws IOException { + @Test public void alternateExchangeNonEquivalence() throws IOException { channel.exchangeDeclare("alternate", "direct", false, false, args); Map altargs = new HashMap(); altargs.put("alternate-exchange", "somewhere"); diff --git a/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java b/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java index 2b21a187fe..79115f6328 100644 --- a/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java @@ -16,19 +16,17 @@ package com.rabbitmq.client.test.server; -import com.rabbitmq.client.BlockedListener; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.ConnectionFactory; -import com.rabbitmq.client.MessageProperties; +import com.rabbitmq.client.*; import com.rabbitmq.client.test.BrokerTestCase; -import com.rabbitmq.tools.Host; +import org.junit.Test; import java.io.IOException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import static org.junit.Assert.assertTrue; + public class BlockedConnection extends BrokerTestCase { protected void releaseResources() throws IOException { try { @@ -39,7 +37,7 @@ protected void releaseResources() throws IOException { } // this test first opens a connection, then triggers // and alarm and blocks - public void testBlock() throws Exception { + @Test public void testBlock() throws Exception { final CountDownLatch latch = new CountDownLatch(1); Connection connection = connection(latch); @@ -51,7 +49,7 @@ public void testBlock() throws Exception { // this test first triggers an alarm, then opens a // connection - public void testInitialBlock() throws Exception { + @Test public void initialBlock() throws Exception { final CountDownLatch latch = new CountDownLatch(1); block(); diff --git a/src/test/java/com/rabbitmq/client/test/server/Bug19219Test.java b/src/test/java/com/rabbitmq/client/test/server/Bug19219Test.java index fb7b6801c2..f048252728 100644 --- a/src/test/java/com/rabbitmq/client/test/server/Bug19219Test.java +++ b/src/test/java/com/rabbitmq/client/test/server/Bug19219Test.java @@ -15,12 +15,14 @@ package com.rabbitmq.client.test.server; +import static org.junit.Assert.assertTrue; + import java.io.IOException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeoutException; -import junit.framework.TestSuite; +import org.junit.Test; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; @@ -55,12 +57,6 @@ public class Bug19219Test extends BrokerTestCase { private static final Semaphore init = new Semaphore(0); private static final CountDownLatch resume = new CountDownLatch(1); - public static TestSuite suite() { - TestSuite suite = new TestSuite("Bug19219"); - suite.addTestSuite(Bug19219Test.class); - return suite; - } - private static void publish(final Channel ch) throws IOException { ch.basicPublish("amq.fanout", "", @@ -68,7 +64,7 @@ private static void publish(final Channel ch) new byte[0]); } - public void testIt() throws IOException, InterruptedException { + @Test public void it() throws IOException, InterruptedException { final Consumer c = new DefaultConsumer(channel); diff --git a/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java b/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java index d6f887b2a3..3aa4c5ba78 100644 --- a/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java +++ b/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java @@ -15,6 +15,18 @@ package com.rabbitmq.client.test.server; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.util.concurrent.Executors; + +import javax.net.SocketFactory; + +import org.junit.Test; + import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; @@ -22,15 +34,11 @@ import com.rabbitmq.client.ShutdownSignalException; import com.rabbitmq.client.impl.AMQConnection; import com.rabbitmq.client.impl.ChannelN; -import com.rabbitmq.client.impl.SocketFrameHandler; import com.rabbitmq.client.impl.ConsumerWorkService; +import com.rabbitmq.client.impl.SocketFrameHandler; import com.rabbitmq.client.test.BrokerTestCase; import com.rabbitmq.tools.Host; -import javax.net.SocketFactory; -import java.io.IOException; -import java.util.concurrent.Executors; - public class ChannelLimitNegotiation extends BrokerTestCase { class SpecialConnection extends AMQConnection { private final int channelMax; @@ -53,7 +61,7 @@ protected int negotiateChannelMax(int requestedChannelMax, int serverMax) { } } - public void testChannelMaxLowerThanServerMinimum() throws Exception { + @Test public void channelMaxLowerThanServerMinimum() throws Exception { int n = 64; ConnectionFactory cf = new ConnectionFactory(); cf.setRequestedChannelMax(n); @@ -62,7 +70,7 @@ public void testChannelMaxLowerThanServerMinimum() throws Exception { assertEquals(n, conn.getChannelMax()); } - public void testChannelMaxGreaterThanServerValue() throws Exception { + @Test public void channelMaxGreaterThanServerValue() throws Exception { try { Host.rabbitmqctl("eval 'application:set_env(rabbit, channel_max, 2048).'"); @@ -78,7 +86,7 @@ public void testChannelMaxGreaterThanServerValue() throws Exception { } } - public void testOpeningTooManyChannels() throws Exception { + @Test public void openingTooManyChannels() throws Exception { int n = 48; try { diff --git a/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java b/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java index 5c1c65d939..3973521128 100644 --- a/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java +++ b/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java @@ -15,15 +15,19 @@ package com.rabbitmq.client.test.server; -import com.rabbitmq.client.MessageProperties; -import com.rabbitmq.client.test.BrokerTestCase; -import com.rabbitmq.client.test.functional.DeadLetterExchange; -import com.rabbitmq.tools.Host; +import static org.junit.Assert.assertNull; import java.io.IOException; import java.util.HashMap; import java.util.Map; +import org.junit.Test; + +import com.rabbitmq.client.MessageProperties; +import com.rabbitmq.client.test.BrokerTestCase; +import com.rabbitmq.client.test.functional.DeadLetterExchange; +import com.rabbitmq.tools.Host; + public class DeadLetterExchangeDurable extends BrokerTestCase { @Override protected void createResources() throws IOException { @@ -45,7 +49,7 @@ protected void releaseResources() throws IOException { channel.queueDelete(DeadLetterExchange.TEST_QUEUE_NAME); } - public void testDeadLetterQueueTTLExpiredWhileDown() throws Exception { + @Test public void deadLetterQueueTTLExpiredWhileDown() throws Exception { // This test is nonsensical (and often breaks) in HA mode. if (HATests.HA_TESTS_RUNNING) return; diff --git a/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java b/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java index f484d1f49e..4c4b6fd910 100644 --- a/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java +++ b/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java @@ -16,15 +16,18 @@ package com.rabbitmq.client.test.server; -import com.rabbitmq.client.GetResponse; - -import com.rabbitmq.client.test.functional.BindingLifecycleBase; - -import com.rabbitmq.tools.Host; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import java.io.IOException; import java.util.concurrent.TimeoutException; +import org.junit.Test; + +import com.rabbitmq.client.GetResponse; +import com.rabbitmq.client.test.functional.BindingLifecycleBase; +import com.rabbitmq.tools.Host; + /** * This tests whether bindings are created and nuked properly. * @@ -64,7 +67,7 @@ private void restartPrimary() throws IOException, TimeoutException { /** * Tests whether durable bindings are correctly recovered. */ - public void testDurableBindingRecovery() throws IOException, TimeoutException { + @Test public void durableBindingRecovery() throws IOException, TimeoutException { declareDurableTopicExchange(X); declareAndBindDurableQueue(Q, X, K); @@ -97,7 +100,7 @@ public void testDurableBindingRecovery() throws IOException, TimeoutException { * main difference is that the broker has to be restarted to * verify that the durable routes have been turfed. */ - public void testDurableBindingsDeletion() throws IOException, TimeoutException { + @Test public void durableBindingsDeletion() throws IOException, TimeoutException { declareDurableTopicExchange(X); declareAndBindDurableQueue(Q, X, K); @@ -126,7 +129,7 @@ public void testDurableBindingsDeletion() throws IOException, TimeoutException { * The idea is to create a durable queue, nuke the server and then * publish a message to it using the queue name as a routing key */ - public void testDefaultBindingRecovery() throws IOException, TimeoutException { + @Test public void defaultBindingRecovery() throws IOException, TimeoutException { declareDurableQueue(Q); restart(); @@ -144,7 +147,7 @@ public void testDefaultBindingRecovery() throws IOException, TimeoutException { * queue and the durable queue is on a cluster node that restarts, * we do not lose the binding. See bug 24009. */ - public void testTransientExchangeDurableQueue() throws IOException, TimeoutException { + @Test public void transientExchangeDurableQueue() throws IOException, TimeoutException { // This test depends on the second node in the cluster to keep // the transient X alive if (clusteredConnection != null) { diff --git a/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java b/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java index 10ccf71495..78b2291781 100644 --- a/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java +++ b/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java @@ -15,10 +15,14 @@ package com.rabbitmq.client.test.server; -import com.rabbitmq.client.test.functional.ClusteredTestBase; +import static org.junit.Assert.assertEquals; import java.io.IOException; +import org.junit.Test; + +import com.rabbitmq.client.test.functional.ClusteredTestBase; + /** * From bug 19844 - we want to be sure that publish vs everything else can't * happen out of order @@ -47,7 +51,7 @@ protected void releaseResources() throws IOException { private static final byte[] msg = "".getBytes(); - public void testEffectVisibility() throws Exception { + @Test public void effectVisibility() throws Exception { for (int i = 0; i < BATCHES; i++) { for (int j = 0; j < MESSAGES_PER_BATCH; j++) { diff --git a/src/test/java/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java b/src/test/java/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java index c1ada2e619..2af310a59a 100644 --- a/src/test/java/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java +++ b/src/test/java/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java @@ -16,9 +16,13 @@ package com.rabbitmq.client.test.server; +import static org.junit.Assert.fail; + import java.io.IOException; import java.util.concurrent.TimeoutException; +import org.junit.Test; + import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; import com.rabbitmq.client.test.BrokerTestCase; @@ -42,7 +46,7 @@ void verifyQueueMissing(Channel channel, String queueName) // 1) connection and queue are on same node, node restarts -> queue // should no longer exist - public void testConnectionQueueSameNode() throws Exception { + @Test public void connectionQueueSameNode() throws Exception { channel.queueDeclare("scenario1", true, true, false, null); restartPrimaryAbruptly(); verifyQueueMissing(channel, "scenario1"); diff --git a/src/test/java/com/rabbitmq/client/test/server/Firehose.java b/src/test/java/com/rabbitmq/client/test/server/Firehose.java index 7a2c3329fe..c1c95ab8a4 100644 --- a/src/test/java/com/rabbitmq/client/test/server/Firehose.java +++ b/src/test/java/com/rabbitmq/client/test/server/Firehose.java @@ -15,15 +15,20 @@ package com.rabbitmq.client.test.server; -import com.rabbitmq.client.GetResponse; -import com.rabbitmq.client.test.BrokerTestCase; -import com.rabbitmq.tools.Host; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import java.io.IOException; import java.util.List; import java.util.Map; import java.util.concurrent.TimeoutException; +import org.junit.Test; + +import com.rabbitmq.client.GetResponse; +import com.rabbitmq.client.test.BrokerTestCase; +import com.rabbitmq.tools.Host; + public class Firehose extends BrokerTestCase { private String q; private String firehose; @@ -38,7 +43,7 @@ protected void createResources() throws IOException, TimeoutException { channel.queueBind(firehose, "amq.rabbitmq.trace", "#"); } - public void testFirehose() throws IOException { + @Test public void firehose() throws IOException { publishGet("not traced"); enable(); GetResponse msg = publishGet("traced"); diff --git a/src/test/java/com/rabbitmq/client/test/server/HATests.java b/src/test/java/com/rabbitmq/client/test/server/HATests.java index bcb6ec6a0d..17b8ad1351 100644 --- a/src/test/java/com/rabbitmq/client/test/server/HATests.java +++ b/src/test/java/com/rabbitmq/client/test/server/HATests.java @@ -15,47 +15,51 @@ package com.rabbitmq.client.test.server; -import junit.framework.TestCase; -import junit.framework.TestSuite; - import com.rabbitmq.client.test.AbstractRMQTestSuite; +import com.rabbitmq.client.test.RequiredPropertiesSuite; import com.rabbitmq.client.test.functional.FunctionalTests; import com.rabbitmq.tools.Host; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; -public class HATests extends AbstractRMQTestSuite { - // this is horrific - public static boolean HA_TESTS_RUNNING = false; +@RunWith(RequiredPropertiesSuite.class) +@Suite.SuiteClasses({ + HATests.SetUp.class, + FunctionalTests.class, + ServerTests.class, + HATests.TearDown.class +}) +public class HATests { - public static TestSuite suite() { - TestSuite suite = new TestSuite("server-tests"); - if (!requiredProperties()) return suite; - suite.addTestSuite(SetUp.class); - FunctionalTests.add(suite); - ServerTests.add(suite); - suite.addTestSuite(TearDown.class); - return suite; + // initialize system properties + static{ + new AbstractRMQTestSuite(){}; } + // this is horrific + public static boolean HA_TESTS_RUNNING = false; + // This is of course an abuse of the TestCase concept - but I don't want to // run this command on every test case. And there's no hook for "before / // after this test suite". - public static class SetUp extends TestCase { - @Override - protected void setUp() throws Exception { + public static class SetUp { + + @Test public void setUp() throws Exception { Host.rabbitmqctl("set_policy HA '.*' '{\"ha-mode\":\"all\"}'"); HA_TESTS_RUNNING = true; } - public void testNothing() {} + @Test public void testNothing() {} } - public static class TearDown extends TestCase { - @Override - protected void tearDown() throws Exception { + public static class TearDown { + + @Test public void tearDown() throws Exception { Host.rabbitmqctl("clear_policy HA"); HA_TESTS_RUNNING = false; } - public void testNothing() {} + @Test public void testNothing() {} } } diff --git a/src/test/java/com/rabbitmq/client/test/server/LoopbackUsers.java b/src/test/java/com/rabbitmq/client/test/server/LoopbackUsers.java index ea4c1a6af3..7e6fff9e06 100644 --- a/src/test/java/com/rabbitmq/client/test/server/LoopbackUsers.java +++ b/src/test/java/com/rabbitmq/client/test/server/LoopbackUsers.java @@ -15,10 +15,7 @@ package com.rabbitmq.client.test.server; -import com.rabbitmq.client.AuthenticationFailureException; -import com.rabbitmq.client.ConnectionFactory; -import com.rabbitmq.tools.Host; -import junit.framework.TestCase; +import static org.junit.Assert.fail; import java.io.IOException; import java.net.Inet4Address; @@ -28,19 +25,26 @@ import java.util.Enumeration; import java.util.concurrent.TimeoutException; -public class LoopbackUsers extends TestCase { - @Override - protected void setUp() throws IOException { +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.rabbitmq.client.AuthenticationFailureException; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.tools.Host; + +public class LoopbackUsers { + + @Before public void setUp() throws IOException { Host.rabbitmqctl("add_user test test"); Host.rabbitmqctl("set_permissions test '.*' '.*' '.*'"); } - @Override - protected void tearDown() throws IOException { + @After public void tearDown() throws IOException { Host.rabbitmqctl("delete_user test"); } - public void testLoopback() throws IOException, TimeoutException { + @Test public void loopback() throws IOException, TimeoutException { String addr = findRealIPAddress().getHostAddress(); assertGuestFail(addr); Host.rabbitmqctl("eval 'application:set_env(rabbit, loopback_users, []).'"); diff --git a/src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java b/src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java index f4d7068dbd..da89a2cafe 100644 --- a/src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java +++ b/src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java @@ -15,9 +15,14 @@ package com.rabbitmq.client.test.server; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + import java.io.IOException; import java.util.concurrent.TimeoutException; +import org.junit.Test; + import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.QueueingConsumer; @@ -32,7 +37,7 @@ public class MemoryAlarms extends BrokerTestCase { private Channel channel2; @Override - protected void setUp() throws IOException, TimeoutException { + public void setUp() throws IOException, TimeoutException { connectionFactory.setRequestedHeartbeat(1); super.setUp(); if (connection2 == null) { @@ -42,7 +47,7 @@ protected void setUp() throws IOException, TimeoutException { } @Override - protected void tearDown() throws IOException, TimeoutException { + public void tearDown() throws IOException, TimeoutException { if (channel2 != null) { channel2.abort(); channel2 = null; @@ -71,7 +76,7 @@ protected void releaseResources() throws IOException { } } - public void testFlowControl() throws IOException, InterruptedException { + @Test public void flowControl() throws IOException, InterruptedException { basicPublishVolatile(Q); setResourceAlarm("memory"); // non-publish actions only after an alarm should be fine @@ -93,7 +98,7 @@ public void testFlowControl() throws IOException, InterruptedException { } - public void testOverlappingAlarmsFlowControl() throws IOException, InterruptedException { + @Test public void overlappingAlarmsFlowControl() throws IOException, InterruptedException { QueueingConsumer c = new QueueingConsumer(channel); String consumerTag = channel.basicConsume(Q, true, c); diff --git a/src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java b/src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java index b30b86ccda..a884632b6f 100644 --- a/src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java @@ -16,9 +16,9 @@ package com.rabbitmq.client.test.server; import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.Channel; import com.rabbitmq.client.MessageProperties; import com.rabbitmq.client.test.ConfirmBase; +import org.junit.Test; import java.io.IOException; @@ -28,7 +28,7 @@ public class MessageRecovery extends ConfirmBase private final static String Q = "recovery-test"; private final static String Q2 = "recovery-test-ha-check"; - public void testMessageRecovery() + @Test public void messageRecovery() throws Exception { channel.queueDelete(Q); diff --git a/src/test/java/com/rabbitmq/client/test/server/Permissions.java b/src/test/java/com/rabbitmq/client/test/server/Permissions.java index 782754833d..9b702a0701 100644 --- a/src/test/java/com/rabbitmq/client/test/server/Permissions.java +++ b/src/test/java/com/rabbitmq/client/test/server/Permissions.java @@ -16,20 +16,26 @@ package com.rabbitmq.client.test.server; -import com.rabbitmq.client.AlreadyClosedException; -import com.rabbitmq.client.AuthenticationFailureException; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + import java.io.IOException; -import java.util.Map; import java.util.HashMap; +import java.util.Map; import java.util.concurrent.TimeoutException; +import org.junit.Test; + import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.AlreadyClosedException; +import com.rabbitmq.client.AuthenticationFailureException; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.QueueingConsumer; import com.rabbitmq.client.impl.AMQChannel; +import com.rabbitmq.client.test.BrokerTestCase; import com.rabbitmq.tools.Host; public class Permissions extends BrokerTestCase @@ -46,14 +52,14 @@ public Permissions() connectionFactory = factory; } - protected void setUp() + public void setUp() throws IOException, TimeoutException { deleteRestrictedAccount(); addRestrictedAccount(); super.setUp(); } - protected void tearDown() + public void tearDown() throws IOException, TimeoutException { super.tearDown(); deleteRestrictedAccount(); @@ -114,7 +120,7 @@ protected void withNames(WithName action) action.with("none"); } - public void testAuth() throws TimeoutException { + @Test public void auth() throws TimeoutException { ConnectionFactory unAuthFactory = new ConnectionFactory(); unAuthFactory.setUsername("test"); unAuthFactory.setPassword("tset"); @@ -130,7 +136,7 @@ public void testAuth() throws TimeoutException { } } - public void testExchangeConfiguration() + @Test public void exchangeConfiguration() throws IOException { runConfigureTest(new WithName() { @@ -143,7 +149,7 @@ public void with(String name) throws IOException { }}); } - public void testQueueConfiguration() + @Test public void queueConfiguration() throws IOException { runConfigureTest(new WithName() { @@ -156,7 +162,7 @@ public void with(String name) throws IOException { }}); } - public void testPassiveDeclaration() throws IOException { + @Test public void passiveDeclaration() throws IOException { runTest(true, true, true, true, new WithName() { public void with(String name) throws IOException { channel.exchangeDeclarePassive(name); @@ -167,7 +173,7 @@ public void with(String name) throws IOException { }}); } - public void testBinding() + @Test public void binding() throws IOException { runTest(false, true, false, false, new WithName() { @@ -180,7 +186,7 @@ public void with(String name) throws IOException { }}); } - public void testPublish() + @Test public void publish() throws IOException { runTest(false, true, false, false, new WithName() { @@ -192,7 +198,7 @@ public void with(String name) throws IOException { }}); } - public void testGet() + @Test public void get() throws IOException { runTest(false, false, true, false, new WithName() { @@ -201,7 +207,7 @@ public void with(String name) throws IOException { }}); } - public void testConsume() + @Test public void consume() throws IOException { runTest(false, false, true, false, new WithName() { @@ -210,7 +216,7 @@ public void with(String name) throws IOException { }}); } - public void testPurge() + @Test public void purge() throws IOException { runTest(false, false, true, false, new WithName() { @@ -222,7 +228,7 @@ public void with(String name) throws IOException { }}); } - public void testAltExchConfiguration() + @Test public void altExchConfiguration() throws IOException { runTest(false, false, false, false, @@ -233,7 +239,7 @@ public void testAltExchConfiguration() createAltExchConfigTest("configure-and-read-me")); } - public void testDLXConfiguration() + @Test public void dLXConfiguration() throws IOException { runTest(false, false, false, false, @@ -244,7 +250,7 @@ public void testDLXConfiguration() createDLXConfigTest("configure-and-read-me")); } - public void testNoAccess() + @Test public void noAccess() throws IOException, InterruptedException { Host.rabbitmqctl("set_permissions -p /test test \"\" \"\" \"\""); diff --git a/src/test/java/com/rabbitmq/client/test/server/PersistenceGuarantees.java b/src/test/java/com/rabbitmq/client/test/server/PersistenceGuarantees.java index b4df0710db..a627abf6dd 100644 --- a/src/test/java/com/rabbitmq/client/test/server/PersistenceGuarantees.java +++ b/src/test/java/com/rabbitmq/client/test/server/PersistenceGuarantees.java @@ -15,11 +15,15 @@ package com.rabbitmq.client.test.server; -import com.rabbitmq.client.MessageProperties; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.assertEquals; import java.io.IOException; +import org.junit.Test; + +import com.rabbitmq.client.MessageProperties; +import com.rabbitmq.client.test.BrokerTestCase; + public class PersistenceGuarantees extends BrokerTestCase { private static final int COUNT = 10000; private String queue; @@ -28,7 +32,7 @@ protected void declareQueue() throws IOException { queue = channel.queueDeclare("", true, false, false, null).getQueue(); } - public void testTxPersistence() throws Exception { + @Test public void txPersistence() throws Exception { declareQueue(); channel.txSelect(); publish(); @@ -37,7 +41,7 @@ public void testTxPersistence() throws Exception { assertPersisted(); } - public void testConfirmPersistence() throws Exception { + @Test public void confirmPersistence() throws Exception { declareQueue(); channel.confirmSelect(); publish(); diff --git a/src/test/java/com/rabbitmq/client/test/server/PriorityQueues.java b/src/test/java/com/rabbitmq/client/test/server/PriorityQueues.java index 1810f39ad9..af16b2135c 100644 --- a/src/test/java/com/rabbitmq/client/test/server/PriorityQueues.java +++ b/src/test/java/com/rabbitmq/client/test/server/PriorityQueues.java @@ -15,10 +15,7 @@ package com.rabbitmq.client.test.server; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.DefaultConsumer; -import com.rabbitmq.client.Envelope; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.assertEquals; import java.io.IOException; import java.util.ArrayList; @@ -29,8 +26,15 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import org.junit.Test; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.DefaultConsumer; +import com.rabbitmq.client.Envelope; +import com.rabbitmq.client.test.BrokerTestCase; + public class PriorityQueues extends BrokerTestCase { - public void testPrioritisingBasics() throws IOException, TimeoutException, InterruptedException { + @Test public void prioritisingBasics() throws IOException, TimeoutException, InterruptedException { String q = "with-3-priorities"; int n = 3; channel.queueDeclare(q, true, false, false, argsWithPriorities(n)); diff --git a/src/test/java/com/rabbitmq/client/test/server/ServerTests.java b/src/test/java/com/rabbitmq/client/test/server/ServerTests.java index 4250e9bea1..59687862f8 100644 --- a/src/test/java/com/rabbitmq/client/test/server/ServerTests.java +++ b/src/test/java/com/rabbitmq/client/test/server/ServerTests.java @@ -16,34 +16,34 @@ package com.rabbitmq.client.test.server; -import junit.framework.TestSuite; - import com.rabbitmq.client.test.AbstractRMQTestSuite; +import com.rabbitmq.client.test.RequiredPropertiesSuite; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; -public class ServerTests extends AbstractRMQTestSuite { +@RunWith(RequiredPropertiesSuite.class) +@Suite.SuiteClasses({ + Permissions.class, + DurableBindingLifecycle.class, + DeadLetterExchangeDurable.class, + EffectVisibilityCrossNodeTest.class, + ExclusiveQueueDurability.class, + AbsentQueue.class, + AlternateExchangeEquivalence.class, + MemoryAlarms.class, + MessageRecovery.class, + Firehose.class, + PersistenceGuarantees.class, + Shutdown.class, + BlockedConnection.class, + ChannelLimitNegotiation.class, + LoopbackUsers.class +}) +public class ServerTests { - public static TestSuite suite() { - TestSuite suite = new TestSuite("server-tests"); - if (!requiredProperties()) return suite; - add(suite); - return suite; - } + // initialize system properties + static{ + new AbstractRMQTestSuite(){}; + } - public static void add(TestSuite suite) { - suite.addTestSuite(Permissions.class); - suite.addTestSuite(DurableBindingLifecycle.class); - suite.addTestSuite(DeadLetterExchangeDurable.class); - suite.addTestSuite(EffectVisibilityCrossNodeTest.class); - suite.addTestSuite(ExclusiveQueueDurability.class); - suite.addTestSuite(AbsentQueue.class); - suite.addTestSuite(AlternateExchangeEquivalence.class); - suite.addTestSuite(MemoryAlarms.class); - suite.addTestSuite(MessageRecovery.class); - suite.addTestSuite(Firehose.class); - suite.addTestSuite(PersistenceGuarantees.class); - suite.addTestSuite(Shutdown.class); - suite.addTestSuite(BlockedConnection.class); - suite.addTestSuite(ChannelLimitNegotiation.class); - suite.addTestSuite(LoopbackUsers.class); - } } diff --git a/src/test/java/com/rabbitmq/client/test/server/Shutdown.java b/src/test/java/com/rabbitmq/client/test/server/Shutdown.java index e5226273f6..4581c57e09 100644 --- a/src/test/java/com/rabbitmq/client/test/server/Shutdown.java +++ b/src/test/java/com/rabbitmq/client/test/server/Shutdown.java @@ -15,16 +15,13 @@ package com.rabbitmq.client.test.server; -import com.rabbitmq.client.test.BrokerTestCase; import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.Connection; - -import java.io.IOException; +import com.rabbitmq.client.test.BrokerTestCase; +import org.junit.Test; public class Shutdown extends BrokerTestCase { - public void testErrorOnShutdown() throws Exception { + @Test public void errorOnShutdown() throws Exception { bareRestart(); expectError(AMQP.CONNECTION_FORCED); } diff --git a/src/test/java/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java b/src/test/java/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java index 5a6b9bac33..75ee9b882d 100644 --- a/src/test/java/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java +++ b/src/test/java/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java @@ -15,11 +15,8 @@ package com.rabbitmq.client.test.server; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.DefaultConsumer; -import com.rabbitmq.client.Envelope; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import java.io.IOException; import java.util.ArrayList; @@ -32,6 +29,14 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import org.junit.Test; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.DefaultConsumer; +import com.rabbitmq.client.Envelope; +import com.rabbitmq.client.test.BrokerTestCase; + class RejectingConsumer extends DefaultConsumer { private CountDownLatch latch; private Map headers; @@ -63,7 +68,7 @@ public Map getHeaders() { public class XDeathHeaderGrowth extends BrokerTestCase { @SuppressWarnings("unchecked") - public void testBoundedXDeathHeaderGrowth() throws IOException, InterruptedException { + @Test public void boundedXDeathHeaderGrowth() throws IOException, InterruptedException { final String x1 = "issues.rabbitmq-server-78.fanout1"; declareTransientFanoutExchange(x1); final String x2 = "issues.rabbitmq-server-78.fanout2"; @@ -124,7 +129,7 @@ private void cleanUpQueues(String... qs) throws IOException { } @SuppressWarnings("unchecked") - public void testHandlingOfXDeathHeadersFromEarlierVersions() throws IOException, InterruptedException { + @Test public void handlingOfXDeathHeadersFromEarlierVersions() throws IOException, InterruptedException { final String x1 = "issues.rabbitmq-server-152.fanout1"; declareTransientFanoutExchange(x1); final String x2 = "issues.rabbitmq-server-152.fanout2"; diff --git a/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java index 3026fe547a..d4e3c33360 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java @@ -15,6 +15,9 @@ package com.rabbitmq.client.test.ssl; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + import java.io.FileInputStream; import java.io.IOException; import java.security.KeyManagementException; @@ -30,6 +33,8 @@ import javax.net.ssl.SSLHandshakeException; import javax.net.ssl.TrustManagerFactory; +import org.junit.Test; + import com.rabbitmq.client.ConnectionFactory; /** @@ -92,5 +97,5 @@ public void openConnection() } public void openChannel() {} - public void testSSL() {} + @Test public void sSL() {} } diff --git a/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java index 71d59f95a3..1854e1753c 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java @@ -16,20 +16,59 @@ package com.rabbitmq.client.test.ssl; -import junit.framework.TestSuite; - import com.rabbitmq.client.test.AbstractRMQTestSuite; +import org.junit.runner.RunWith; +import org.junit.runner.Runner; +import org.junit.runners.Suite; +import org.junit.runners.model.InitializationError; +import org.junit.runners.model.RunnerBuilder; + +import java.util.ArrayList; +import java.util.List; + +@RunWith(Suite.class) +@Suite.SuiteClasses({ + UnverifiedConnection.class, + VerifiedConnection.class, + BadVerifiedConnection.class +}) +public class SSLTests { + + // initialize system properties + static{ + new AbstractRMQTestSuite(){}; + } + + public static class SslSuite extends Suite { + + public SslSuite(Class klass, RunnerBuilder builder) throws InitializationError { + super(klass, builder); + } + + public SslSuite(RunnerBuilder builder, Class[] classes) throws InitializationError { + super(builder, classes); + } + + protected SslSuite(Class klass, Class[] suiteClasses) throws InitializationError { + super(klass, suiteClasses); + } + + protected SslSuite(RunnerBuilder builder, Class klass, Class[] suiteClasses) throws InitializationError { + super(builder, klass, suiteClasses); + } + + protected SslSuite(Class klass, List runners) throws InitializationError { + super(klass, runners); + } + + @Override + protected List getChildren() { + if(!AbstractRMQTestSuite.requiredProperties() && !AbstractRMQTestSuite.isSSLAvailable()) { + return new ArrayList(); + } else { + return super.getChildren(); + } + } + } -public class SSLTests extends AbstractRMQTestSuite { - public static TestSuite suite() { - TestSuite suite = new TestSuite("ssl"); - suite.addTestSuite(ConnectionFactoryDefaultTlsVersion.class); - // Skip the tests if not under umbrella and no TLS setup available - if (!requiredProperties()) return suite; - if (!isSSLAvailable()) return suite; - suite.addTestSuite(UnverifiedConnection.class); - suite.addTestSuite(VerifiedConnection.class); - suite.addTestSuite(BadVerifiedConnection.class); - return suite; - } } diff --git a/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java index d7462ef989..603aa1f372 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java @@ -15,6 +15,10 @@ package com.rabbitmq.client.test.ssl; +import static org.junit.Assert.*; +import org.junit.Test; + + import java.io.IOException; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; @@ -43,7 +47,7 @@ public void openConnection() } } - public void testSSL() throws IOException + @Test public void sSL() throws IOException { channel.queueDeclare("Bug19356Test", false, true, true, null); channel.basicPublish("", "Bug19356Test", null, "SSL".getBytes()); diff --git a/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java index 645dec1104..467c6d8b71 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java @@ -15,6 +15,8 @@ package com.rabbitmq.client.test.ssl; +import static org.junit.Assert.assertNotNull; + import java.io.FileInputStream; import java.io.IOException; import java.security.KeyManagementException; @@ -23,7 +25,6 @@ import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; -import java.util.Arrays; import java.util.concurrent.TimeoutException; import javax.net.ssl.KeyManagerFactory; From 4adab2afa17b48e8e9e80da05190fbcd83b904d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 25 Aug 2016 16:06:06 +0200 Subject: [PATCH 0241/2114] Add tests to the suites Fixes #174 --- .../com/rabbitmq/client/test/AbstractRMQTestSuite.java | 9 --------- .../rabbitmq/client/test/functional/FunctionalTests.java | 6 +++++- .../com/rabbitmq/client/test/server/ServerTests.java | 5 ++++- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java b/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java index bafbc6f739..cb27d22e7c 100644 --- a/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java +++ b/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java @@ -24,11 +24,6 @@ public abstract class AbstractRMQTestSuite { - private static final String DEFAULT_SSL_HOSTNAME = "localhost"; - private static final int DEFAULT_SSL_PORT = 5671; - - private static boolean buildSSLPropertiesFound = false; - static { Properties TESTS_PROPS = new Properties(System.getProperties()); String make = System.getenv("MAKE"); @@ -86,10 +81,6 @@ public static boolean requiredProperties() { return true; } - public static boolean isUnderUmbrella() { - return new File("../../UMBRELLA.md").isFile(); - } - public static boolean isSSLAvailable() { String sslClientCertsDir = System.getProperty("test-client-cert.path"); String hostname = System.getProperty("broker.hostname"); diff --git a/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java b/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java index e24cd2d039..8633cf6c40 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java +++ b/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java @@ -72,7 +72,11 @@ ConnectionRecovery.class, ExceptionHandling.class, PerConsumerPrefetch.class, - DirectReplyTo.class + DirectReplyTo.class, + ConsumerCount.class, + BasicGet.class, + Nack.class, + ExceptionMessages.class }) public class FunctionalTests { diff --git a/src/test/java/com/rabbitmq/client/test/server/ServerTests.java b/src/test/java/com/rabbitmq/client/test/server/ServerTests.java index 59687862f8..2478b72994 100644 --- a/src/test/java/com/rabbitmq/client/test/server/ServerTests.java +++ b/src/test/java/com/rabbitmq/client/test/server/ServerTests.java @@ -37,7 +37,10 @@ Shutdown.class, BlockedConnection.class, ChannelLimitNegotiation.class, - LoopbackUsers.class + LoopbackUsers.class, + XDeathHeaderGrowth.class, + PriorityQueues.class, + }) public class ServerTests { From 621682622eb8c67b4d5c734f6e8e776e7d661193 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 26 Aug 2016 11:40:13 +0200 Subject: [PATCH 0242/2114] Add SLF4J Fixes #114 --- pom.xml | 19 +++++++- .../impl/ForgivingExceptionHandler.java | 48 +++++++------------ .../client/impl/StrictExceptionHandler.java | 27 +++++------ .../com/rabbitmq/tools/json/JSONUtil.java | 11 +++-- .../java/com/rabbitmq/utility/Utility.java | 7 ++- 5 files changed, 58 insertions(+), 54 deletions(-) diff --git a/pom.xml b/pom.xml index b179b742e6..9699236f79 100644 --- a/pom.xml +++ b/pom.xml @@ -53,6 +53,10 @@ UTF-8 UTF-8 + 1.7.21 + 1.1 + 4.12 + | (dormant) | - * | ------------- - * ------------- next() | add(item) - * | in progress | <--------- | - * ------------- | V - * | ------------- - * -----------> | ready | - * finish(k) ------------- - * - * dormant is not represented in the implementation state, and adding items - * when the client is in progress or ready does not change its state. * @param Key -- type of client * @param Work -- type of work item */ @@ -95,7 +65,6 @@ public class WorkPool { /** * Add client key to pool of item queues, with an empty queue. * A client is initially dormant. - *

* No-op if key already present. * @param key client to add to pool */ @@ -158,7 +127,6 @@ public void unregisterAllKeys() { * Return the next ready client, * and transfer a collection of that client's items to process. * Mark client in progress. - *

* If there is no ready client, return null. * @param to collection object in which to transfer items * @param size max number of items to transfer diff --git a/src/main/java/com/rabbitmq/tools/Tracer.java b/src/main/java/com/rabbitmq/tools/Tracer.java index cbb25dc6bf..c297382dcc 100644 --- a/src/main/java/com/rabbitmq/tools/Tracer.java +++ b/src/main/java/com/rabbitmq/tools/Tracer.java @@ -40,40 +40,27 @@ import com.rabbitmq.utility.Utility; /** - * AMQP Protocol Analyzer program. Listens on a port (in-port) and when a + *

AMQP 0-9-1 protocol traffic capture program. Listens on a port (in-port) and when a * connection arrives, makes an outbound connection to a host and * port (out-port). Relays frames from the in-port to the out-port. * Commands are decoded and printed to a supplied {@link Logger}. - *

+ *

+ *

* The stand-alone program ({@link #main(String[])}) prints to System.out, * using a private {@link AsyncLogger} instance. When the connection closes * the program listens for a subsequent connection and traces that to the same {@link Logger}. * This continues until the program is interrupted. - *

+ *

+ *

* Options for controlling, for example, whether command bodies are decoded, * are obtained from System.properties, and are reported to the console * before starting the trace. - *

- * A {@link Tracer} object may be instantiated, using one of the constructors - *

    - *
  • Tracer(int listenPort, String id, String host, int port, Logger logger, Properties props)
  • - *
  • Tracer(String id)
  • - *
  • Tracer(String id, Properties props) - *

    where the missing parameters default as follows: - *

      - *
    • listenPort defaults to 5673
    • - *
    • host defaults to localhost
    • - *
    • port defaults to 5672
    • - *
    • logger defaults to new AsyncLogger(System.out)
    • and - *
    • props defaults to System.getProperties()
    • - *
    - *
  • - *
- *

+ *

+ *

* These constructors block waiting for a connection to arrive on the listenPort. * Tracing does not begin until the tracer is {@link #start()}ed which {@link Logger#start()}s * the supplied logger and creates and starts a {@link Thread} for relaying and deconstructing the frames. - *

+ *

* The properties specified in props are used at {@link Tracer#start()} time and may be modified * before this call. * @see Tracer.Logger @@ -386,19 +373,19 @@ public interface Logger { /** * A {@link Tracer.Logger} designed to print {@link String}s to a designated {@link OutputStream} * on a private thread. - *

{@link String}s are read from a private queue and printed to a buffered {@link PrintStream} + * {@link String}s are read from a private queue and printed to a buffered {@link PrintStream} * which is periodically flushed. - *

+ * * When instantiated the private queue is created (an in-memory {@link ArrayBlockingQueue} in this * implementation) and when {@link #start()}ed the private thread is created and started unless it is * already present. An {@link AsyncLogger} may be started many times, but only one thread is created. - *

+ * * When {@link #stop()}ed either the number of starts is decremented, or, if this count reaches zero, * a special element is queued which causes the private thread to end when encountered. - *

+ * * If the private thread is interrupted, the thread will also end, and the count set to zero, * This will cause subsequent {@link #stop()}s to be ignored, and the next {@link #start()} will create a new thread. - *

+ * * {@link #log(String)} never blocks unless the private queue is full; this may never un-block if the {@link Logger} is stopped. */ public static class AsyncLogger implements Logger { @@ -433,10 +420,6 @@ private enum LogCmd { private final BlockingQueue > queue = new ArrayBlockingQueue >( LOG_QUEUE_SIZE, true); - /** - * Same as {@link #Tracer.AsyncLogger(OutputStream, int)} with a one-second flush interval. - * @param os OutputStream to print to. - */ public AsyncLogger(OutputStream os) { this(os, ONE_SECOND_INTERVAL); } diff --git a/src/main/java/com/rabbitmq/utility/IntAllocator.java b/src/main/java/com/rabbitmq/utility/IntAllocator.java index 917a036d3a..b0f25075b7 100644 --- a/src/main/java/com/rabbitmq/utility/IntAllocator.java +++ b/src/main/java/com/rabbitmq/utility/IntAllocator.java @@ -18,17 +18,22 @@ import java.util.BitSet; /** - * A class for allocating integers from a given range that uses a + *

+ * A class for allocating integers from a given range that uses a * {@link BitSet} representation of the free integers. + *

* - *

Concurrent Semantics:
+ *

Concurrecy Semantics:

* This class is not thread safe. * - *

Implementation notes: - *
This was originally an ordered chain of non-overlapping Intervals, + *

Implementation notes:

+ *

This was originally an ordered chain of non-overlapping Intervals, * together with a fixed size array cache for freed integers. - *
{@link #reserve(int)} was expensive in this scheme, whereas in the + *

+ *

+ * {@link #reserve(int)} was expensive in this scheme, whereas in the * present implementation it is O(1), as is {@link #free(int)}. + *

*

Although {@link #allocate()} is slightly slower than O(1) and in the * worst case could be O(N), the use of a "lastIndex" field * for starting the next scan for free integers means this is negligible. @@ -83,7 +88,7 @@ public int allocate() { /** * Make the provided integer available for allocation again. This operation * runs in O(1) time. - *
No error checking is performed, so if you double free or free an + * No error checking is performed, so if you double free or free an * integer that was not originally allocated the results are undefined. * @param reservation the previously allocated integer to free */ @@ -94,7 +99,6 @@ public void free(int reservation) { /** * Attempt to reserve the provided ID as if it had been allocated. Returns * true if it is available, false otherwise. - *
* This operation runs in O(1) time. * @param reservation the integer to be allocated, if possible * @return true if allocated, false From 92b6c0f23f0835ee2f76203b1c596098999c614e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 29 Aug 2016 18:01:19 +0200 Subject: [PATCH 0254/2114] Makefile: Generate javadoc in `make dist` --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 849d5e0fc7..ee1ec4c726 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,7 @@ deps: $(DEPS_DIR)/rabbit @: dist: - $(MVN) $(MVN_FLAGS) -DskipTests=true package + $(MVN) $(MVN_FLAGS) -DskipTests=true package javadoc:javadoc $(DEPS_DIR)/rabbit: git clone https://github.com/rabbitmq/rabbitmq-server.git $@ From 26a88039dc7ba75ecd6983498fc60c13f4ac81b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 29 Aug 2016 18:22:55 +0200 Subject: [PATCH 0255/2114] Support ack count in statistics Fixes #79 --- pom.xml | 7 + .../java/com/rabbitmq/client/Channel.java | 4 + .../com/rabbitmq/client/NoOpStatistics.java | 17 +- .../rabbitmq/client/StatisticsCollector.java | 7 +- .../com/rabbitmq/client/impl/ChannelN.java | 23 +- .../client/impl/ConcurrentStatistics.java | 94 ++++++- .../impl/recovery/AutorecoveringChannel.java | 10 + .../com/rabbitmq/client/test/ClientTests.java | 3 +- .../client/test/ConcurrentStatisticsTest.java | 81 ++++++ .../test/functional/FunctionalTests.java | 3 +- .../client/test/functional/Statistics.java | 242 +++++++++++++++++- 11 files changed, 478 insertions(+), 13 deletions(-) create mode 100644 src/test/java/com/rabbitmq/client/test/ConcurrentStatisticsTest.java diff --git a/pom.xml b/pom.xml index 703741eb13..7f350817d9 100644 --- a/pom.xml +++ b/pom.xml @@ -58,6 +58,7 @@ 1.1 4.12 2.0.0 + 1.10.19 %g microseconds/roundtrip \r", - (100 * i / repeatCount), - now, - delta)); - startTime = System.currentTimeMillis(); - } - chan.basicPublish("", q, props, body); - QueueingConsumer.Delivery d = consumer.nextDelivery(); - chan.basicAck(d.getEnvelope().getDeliveryTag(), false); - } - System.out.println(); - - trace("Switching QOS to unlimited"); - chan.basicQos(0); - - trace("Draining backlog"); - for (int i = 0; i < backlogSize; i++) { - QueueingConsumer.Delivery d = consumer.nextDelivery(); - chan.basicAck(d.getEnvelope().getDeliveryTag(), false); - } - - redeclare(q, chan); - - trace("Closing connection"); - chan.abort(); - conn.close(); - - trace("Sample results (timestamp in milliseconds since epoch; microseconds/roundtrip)"); - System.out.println("(See log file for results; final sample was " + - plateauSampleDeltas.get(plateauSampleDeltas.size() - 1) + ")"); - for (int i = 0; i < plateauSampleTimes.size(); i++) { - String s = String.format("%d %d", - plateauSampleTimes.get(i), - plateauSampleDeltas.get(i).longValue()); - logOut.println(s); - } - logOut.flush(); - } -} diff --git a/src/test/java/com/rabbitmq/examples/TracerConcurrencyTest.java b/src/test/java/com/rabbitmq/examples/TracerConcurrencyTest.java deleted file mode 100644 index 0c651e15cf..0000000000 --- a/src/test/java/com/rabbitmq/examples/TracerConcurrencyTest.java +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - -package com.rabbitmq.examples; - -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.ConnectionFactory; - -/** - * Java Application. Repeatedly generate (and get) messages on multiple concurrently processing channels. - *

- * This application connects to localhost port 5673, and is useful for testing {@link com.rabbitmq.tools.Tracer Tracer}. - * @see com.rabbitmq.tools.Tracer Tracer - */ -public class TracerConcurrencyTest { - - private static final String uri = "amqp://localhost:5673"; - private static final int THREADCOUNT = 3; - private static final String EXCHANGE = "tracer-exchange"; - private static final String QUEUE = "tracer-queue"; - private static final String ROUTING_KEY = ""; - - /** - * @param args command-line parameters -- all ignored. - * @throws Exception test - */ - public static void main(String[] args) throws Exception { - - final Object outputSync = new Object(); - - final Connection conn = createConnectionAndResources(); - - for (int i = 0; i < THREADCOUNT; i++) { - new TestThread(conn, outputSync).start(); - } - } - - private static class TestThread extends Thread { - private final Connection conn; - private final Object outputSync; - - private TestThread(Connection conn, Object outputSync) { - this.conn = conn; - this.outputSync = outputSync; - } - - @Override - public void run() { - try { - while (true) { - Channel ch = conn.createChannel(); - ch.basicPublish(EXCHANGE, ROUTING_KEY, null, new byte[1024 * 1024]); - ch.basicGet(QUEUE, true); - ch.close(); - } - } catch (Exception e) { - synchronized (outputSync) { - e.printStackTrace(); - System.err.println(); - } - System.exit(1); - } - } - - } - - /** - * Create connection and declare exchange and queue for local use. - * - * @return connection - */ - private static Connection createConnectionAndResources() throws Exception { - ConnectionFactory cf = new ConnectionFactory(); - cf.setUri(uri); - Connection conn = cf.newConnection(); - Channel setup = conn.createChannel(); - - setup.exchangeDeclare(EXCHANGE, "direct"); - setup.queueDeclare(QUEUE, false, false, false, null); - setup.queueBind(QUEUE, EXCHANGE, ROUTING_KEY); - - setup.close(); - return conn; - } -} diff --git a/src/test/java/com/rabbitmq/examples/perf/Broker.java b/src/test/java/com/rabbitmq/examples/perf/Broker.java deleted file mode 100644 index d0561e983f..0000000000 --- a/src/test/java/com/rabbitmq/examples/perf/Broker.java +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - -package com.rabbitmq.examples.perf; - -import com.rabbitmq.tools.Host; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.PrintWriter; - -public class Broker { - private static final String BASE = "/tmp/rabbitmq-performance/"; - private static final String SCRIPTS = "../rabbitmq-server/scripts/"; - - private static final String HIPE_C = "{rabbit, [{hipe_compile, true}]}"; - private static final String COARSE_C = "{rabbitmq_management_agent, [{force_fine_statistics, false}]}"; - - private final String name; - private final String config; - - public Broker(String name) { - this(name, "[]."); - } - - public Broker(String name, String config) { - this.name = name; - this.config = config; - } - - public void start() throws IOException { - Process pr = null; - try { - writeConfig(); - - System.out.println("Starting broker '" + name + "'..."); - ProcessBuilder pb = new ProcessBuilder(SCRIPTS + "rabbitmq-server"); - pb.environment().put("RABBITMQ_PID_FILE", pidfile()); - pb.environment().put("RABBITMQ_LOG_BASE", BASE + "logs"); - pb.environment().put("RABBITMQ_MNESIA_DIR", BASE + "db"); - pb.environment().put("RABBITMQ_PLUGINS_EXPAND_DIR", BASE + "plugins-expand"); - pb.environment().put("RABBITMQ_CONFIG_FILE", BASE + "rabbitmq"); - - pr = pb.start(); - - Host.executeCommand(SCRIPTS + "rabbitmqctl wait " + pidfile()); - - } catch (IOException e) { - System.out.println("Broker start failed!"); - assert pr != null; - String stdout = capture(pr.getInputStream()); - String stderr = capture(pr.getErrorStream()); - System.out.println(stdout); - System.out.println(stderr); - throw new RuntimeException(e); - } - } - - private String pidfile() { - return BASE + "pid"; - } - - private void writeConfig() throws IOException { - new File(BASE).mkdirs(); - FileWriter outFile = new FileWriter(BASE + "rabbitmq.config"); - PrintWriter out = new PrintWriter(outFile); - out.println(config); - outFile.close(); - } - - public void stop() { - System.out.println("Stopping broker '" + name + "' ..."); - try { - Host.executeCommand(SCRIPTS + "rabbitmqctl stop " + pidfile()); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - public String getName() { - return name; - } - - - private static String capture(InputStream is) - throws IOException - { - BufferedReader br = new BufferedReader(new InputStreamReader(is)); - String line; - StringBuilder buff = new StringBuilder(); - while ((line = br.readLine()) != null) { - buff.append(line); - } - return buff.toString(); - } -} diff --git a/src/test/java/com/rabbitmq/examples/perf/BrokerValue.java b/src/test/java/com/rabbitmq/examples/perf/BrokerValue.java deleted file mode 100644 index 2ceba3e7ec..0000000000 --- a/src/test/java/com/rabbitmq/examples/perf/BrokerValue.java +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - -package com.rabbitmq.examples.perf; - -import java.io.IOException; - -public class BrokerValue implements VariableValue { - private final Broker broker; - - public BrokerValue(Broker broker) { - this.broker = broker; - } - - public void setup(MulticastParams params) throws IOException { - broker.start(); - } - - public void teardown(MulticastParams params) { - broker.stop(); - } - - public String getName() { - return "broker_type"; - } - - public String getValue() { - return broker.getName(); - } -} diff --git a/src/test/java/com/rabbitmq/examples/perf/BrokerVariable.java b/src/test/java/com/rabbitmq/examples/perf/BrokerVariable.java deleted file mode 100644 index e91aabb5c0..0000000000 --- a/src/test/java/com/rabbitmq/examples/perf/BrokerVariable.java +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - -package com.rabbitmq.examples.perf; - -import java.util.ArrayList; -import java.util.List; - -public class BrokerVariable implements Variable { - private final Broker[] brokers; - - public BrokerVariable(Broker... brokers) { - this.brokers = brokers; - } - - public List getValues() { - List values = new ArrayList(); - for (Broker b : brokers) { - values.add(new BrokerValue(b)); - } - return values; - } -} diff --git a/src/test/java/com/rabbitmq/examples/perf/Consumer.java b/src/test/java/com/rabbitmq/examples/perf/Consumer.java deleted file mode 100644 index 8825a91a24..0000000000 --- a/src/test/java/com/rabbitmq/examples/perf/Consumer.java +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - -package com.rabbitmq.examples.perf; - -import com.rabbitmq.client.AMQP.BasicProperties; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.DefaultConsumer; -import com.rabbitmq.client.Envelope; -import com.rabbitmq.client.ShutdownSignalException; - -import java.io.ByteArrayInputStream; -import java.io.DataInputStream; -import java.io.IOException; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -public class Consumer extends ProducerConsumerBase implements Runnable { - - private ConsumerImpl q; - private final Channel channel; - private final String id; - private final String queueName; - private final int txSize; - private final boolean autoAck; - private final int multiAckEvery; - private final Stats stats; - private final int msgLimit; - private final long timeLimit; - private final CountDownLatch latch = new CountDownLatch(1); - - public Consumer(Channel channel, String id, - String queueName, int txSize, boolean autoAck, - int multiAckEvery, Stats stats, float rateLimit, int msgLimit, int timeLimit) { - - this.channel = channel; - this.id = id; - this.queueName = queueName; - this.rateLimit = rateLimit; - this.txSize = txSize; - this.autoAck = autoAck; - this.multiAckEvery = multiAckEvery; - this.stats = stats; - this.msgLimit = msgLimit; - this.timeLimit = 1000L * timeLimit; - } - - public void run() { - try { - q = new ConsumerImpl(channel); - channel.basicConsume(queueName, autoAck, q); - if (timeLimit == 0) { - latch.await(); - } - else { - latch.await(timeLimit, TimeUnit.MILLISECONDS); - } - - } catch (IOException e) { - throw new RuntimeException(e); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } catch (ShutdownSignalException e) { - throw new RuntimeException(e); - } - } - - private class ConsumerImpl extends DefaultConsumer { - long now; - int totalMsgCount = 0; - - private ConsumerImpl(Channel channel) { - super(channel); - lastStatsTime = now = System.currentTimeMillis(); - msgCount = 0; - } - - @Override - public void handleDelivery(String consumerTag, Envelope envelope, BasicProperties properties, byte[] body) throws IOException { - totalMsgCount++; - msgCount++; - - if (msgLimit == 0 || msgCount <= msgLimit) { - DataInputStream d = new DataInputStream(new ByteArrayInputStream(body)); - d.readInt(); - long msgNano = d.readLong(); - long nano = System.nanoTime(); - - if (!autoAck) { - if (multiAckEvery == 0) { - channel.basicAck(envelope.getDeliveryTag(), false); - } else if (totalMsgCount % multiAckEvery == 0) { - channel.basicAck(envelope.getDeliveryTag(), true); - } - } - - if (txSize != 0 && totalMsgCount % txSize == 0) { - channel.txCommit(); - } - - now = System.currentTimeMillis(); - - stats.handleRecv(id.equals(envelope.getRoutingKey()) ? (nano - msgNano) : 0L); - delay(now); - } - if (msgLimit != 0 && msgCount >= msgLimit) { // NB: not quite the inverse of above - latch.countDown(); - } - } - - @Override - public void handleShutdownSignal(String consumerTag, ShutdownSignalException sig) { - latch.countDown(); - } - - @Override - public void handleCancel(String consumerTag) throws IOException { - System.out.println("Consumer cancelled by broker. Re-consuming."); - channel.basicConsume(queueName, autoAck, q); - } - } -} diff --git a/src/test/java/com/rabbitmq/examples/perf/MulticastParams.java b/src/test/java/com/rabbitmq/examples/perf/MulticastParams.java deleted file mode 100644 index 5263ed4029..0000000000 --- a/src/test/java/com/rabbitmq/examples/perf/MulticastParams.java +++ /dev/null @@ -1,261 +0,0 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - -package com.rabbitmq.examples.perf; - -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.ShutdownSignalException; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -public class MulticastParams { - private long confirm = -1; - private int consumerCount = 1; - private int producerCount = 1; - private int consumerTxSize = 0; - private int producerTxSize = 0; - private int channelPrefetch = 0; - private int consumerPrefetch = 0; - private int minMsgSize = 0; - - private int timeLimit = 0; - private float producerRateLimit = 0; - private float consumerRateLimit = 0; - private int producerMsgCount = 0; - private int consumerMsgCount = 0; - - private String exchangeName = "direct"; - private String exchangeType = "direct"; - private String queueName = ""; - private String routingKey = null; - private boolean randomRoutingKey = false; - - private List flags = new ArrayList(); - - private int multiAckEvery = 0; - private boolean autoAck = true; - private boolean autoDelete = false; - - private boolean predeclared; - - public void setExchangeType(String exchangeType) { - this.exchangeType = exchangeType; - } - - public void setExchangeName(String exchangeName) { - this.exchangeName = exchangeName; - } - - public void setQueueName(String queueName) { - this.queueName = queueName; - } - - public void setRoutingKey(String routingKey) { - this.routingKey = routingKey; - } - - public void setRandomRoutingKey(boolean randomRoutingKey) { - this.randomRoutingKey = randomRoutingKey; - } - - public void setProducerRateLimit(float producerRateLimit) { - this.producerRateLimit = producerRateLimit; - } - - public void setProducerCount(int producerCount) { - this.producerCount = producerCount; - } - - public void setConsumerRateLimit(float consumerRateLimit) { - this.consumerRateLimit = consumerRateLimit; - } - - public void setConsumerCount(int consumerCount) { - this.consumerCount = consumerCount; - } - - public void setProducerTxSize(int producerTxSize) { - this.producerTxSize = producerTxSize; - } - - public void setConsumerTxSize(int consumerTxSize) { - this.consumerTxSize = consumerTxSize; - } - - public void setConfirm(long confirm) { - this.confirm = confirm; - } - - public void setAutoAck(boolean autoAck) { - this.autoAck = autoAck; - } - - public void setMultiAckEvery(int multiAckEvery) { - this.multiAckEvery = multiAckEvery; - } - - public void setChannelPrefetch(int channelPrefetch) { - this.channelPrefetch = channelPrefetch; - } - - public void setConsumerPrefetch(int consumerPrefetch) { - this.consumerPrefetch = consumerPrefetch; - } - - public void setMinMsgSize(int minMsgSize) { - this.minMsgSize = minMsgSize; - } - - public void setTimeLimit(int timeLimit) { - this.timeLimit = timeLimit; - } - - public void setProducerMsgCount(int producerMsgCount) { - this.producerMsgCount = producerMsgCount; - } - - public void setConsumerMsgCount(int consumerMsgCount) { - this.consumerMsgCount = consumerMsgCount; - } - - public void setMsgCount(int msgCount) { - setProducerMsgCount(msgCount); - setConsumerMsgCount(msgCount); - } - - public void setFlags(List flags) { - this.flags = flags; - } - - public void setAutoDelete(boolean autoDelete) { - this.autoDelete = autoDelete; - } - - public void setPredeclared(boolean predeclared) { - this.predeclared = predeclared; - } - - public int getConsumerCount() { - return consumerCount; - } - - public int getProducerCount() { - return producerCount; - } - - public int getMinMsgSize() { - return minMsgSize; - } - - public String getRoutingKey() { - return routingKey; - } - - public boolean getRandomRoutingKey() { - return randomRoutingKey; - } - - public Producer createProducer(Connection connection, Stats stats, String id) throws IOException { - Channel channel = connection.createChannel(); - if (producerTxSize > 0) channel.txSelect(); - if (confirm >= 0) channel.confirmSelect(); - if (!predeclared || !exchangeExists(connection, exchangeName)) { - channel.exchangeDeclare(exchangeName, exchangeType); - } - final Producer producer = new Producer(channel, exchangeName, id, - randomRoutingKey, flags, producerTxSize, - producerRateLimit, producerMsgCount, - minMsgSize, timeLimit, - confirm, stats); - channel.addReturnListener(producer); - channel.addConfirmListener(producer); - return producer; - } - - public Consumer createConsumer(Connection connection, Stats stats, String id) throws IOException { - Channel channel = connection.createChannel(); - if (consumerTxSize > 0) channel.txSelect(); - String qName = configureQueue(connection, id); - if (consumerPrefetch > 0) channel.basicQos(consumerPrefetch); - if (channelPrefetch > 0) channel.basicQos(channelPrefetch, true); - return new Consumer(channel, id, qName, - consumerTxSize, autoAck, multiAckEvery, - stats, consumerRateLimit, consumerMsgCount, timeLimit); - } - - public boolean shouldConfigureQueue() { - return consumerCount == 0 && !queueName.equals(""); - } - - public String configureQueue(Connection connection, String id) throws IOException { - Channel channel = connection.createChannel(); - if (!predeclared || !exchangeExists(connection, exchangeName)) { - channel.exchangeDeclare(exchangeName, exchangeType); - } - String qName = queueName; - if (!predeclared || !queueExists(connection, queueName)) { - qName = channel.queueDeclare(queueName, - flags.contains("persistent"), - false, autoDelete, - null).getQueue(); - } - channel.queueBind(qName, exchangeName, id); - channel.abort(); - return qName; - } - - private static boolean exchangeExists(Connection connection, final String exchangeName) throws IOException { - return exists(connection, new Checker() { - public void check(Channel ch) throws IOException { - ch.exchangeDeclarePassive(exchangeName); - } - }); - } - - private static boolean queueExists(Connection connection, final String queueName) throws IOException { - return queueName != null && exists(connection, new Checker() { - public void check(Channel ch) throws IOException { - ch.queueDeclarePassive(queueName); - } - }); - } - - private static interface Checker { - public void check(Channel ch) throws IOException; - } - - private static boolean exists(Connection connection, Checker checker) throws IOException { - try { - Channel ch = connection.createChannel(); - checker.check(ch); - ch.abort(); - return true; - } - catch (IOException e) { - ShutdownSignalException sse = (ShutdownSignalException) e.getCause(); - if (!sse.isHardError()) { - AMQP.Channel.Close closeMethod = (AMQP.Channel.Close) sse.getReason(); - if (closeMethod.getReplyCode() == AMQP.NOT_FOUND) { - return false; - } - } - throw e; - } - } -} diff --git a/src/test/java/com/rabbitmq/examples/perf/MulticastSet.java b/src/test/java/com/rabbitmq/examples/perf/MulticastSet.java deleted file mode 100644 index f64fc05e0a..0000000000 --- a/src/test/java/com/rabbitmq/examples/perf/MulticastSet.java +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - -package com.rabbitmq.examples.perf; - -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.ConnectionFactory; - -import java.io.IOException; -import java.util.UUID; -import java.util.concurrent.TimeoutException; - -public class MulticastSet { - private final String id; - private final Stats stats; - private final ConnectionFactory factory; - private final MulticastParams params; - private final String testID; - - public MulticastSet(Stats stats, ConnectionFactory factory, - MulticastParams params) { - if (params.getRoutingKey() == null) { - this.id = UUID.randomUUID().toString(); - } else { - this.id = params.getRoutingKey(); - } - this.stats = stats; - this.factory = factory; - this.params = params; - this.testID = "perftest"; - } - - public MulticastSet(Stats stats, ConnectionFactory factory, - MulticastParams params, String testID) { - if (params.getRoutingKey() == null) { - this.id = UUID.randomUUID().toString(); - } else { - this.id = params.getRoutingKey(); - } - this.stats = stats; - this.factory = factory; - this.params = params; - this.testID = testID; - } - - public void run() throws IOException, InterruptedException, TimeoutException { - run(false); - } - - public void run(boolean announceStartup) throws IOException, InterruptedException, TimeoutException { - Thread[] consumerThreads = new Thread[params.getConsumerCount()]; - Connection[] consumerConnections = new Connection[consumerThreads.length]; - for (int i = 0; i < consumerConnections.length; i++) { - if (announceStartup) { - System.out.println("id: " + testID + ", starting consumer #" + i); - } - Connection conn = factory.newConnection(); - consumerConnections[i] = conn; - Thread t = new Thread(params.createConsumer(conn, stats, id)); - consumerThreads[i] = t; - } - - if (params.shouldConfigureQueue()) { - Connection conn = factory.newConnection(); - params.configureQueue(conn, id); - conn.close(); - } - - Thread[] producerThreads = new Thread[params.getProducerCount()]; - Connection[] producerConnections = new Connection[producerThreads.length]; - for (int i = 0; i < producerThreads.length; i++) { - if (announceStartup) { - System.out.println("id: " + testID + ", starting producer #" + i); - } - Connection conn = factory.newConnection(); - producerConnections[i] = conn; - Thread t = new Thread(params.createProducer(conn, stats, id)); - producerThreads[i] = t; - } - - for (Thread consumerThread : consumerThreads) { - consumerThread.start(); - } - - for (Thread producerThread : producerThreads) { - producerThread.start(); - } - - for (int i = 0; i < producerThreads.length; i++) { - producerThreads[i].join(); - producerConnections[i].close(); - } - - for (int i = 0; i < consumerThreads.length; i++) { - consumerThreads[i].join(); - consumerConnections[i].close(); - } - } -} diff --git a/src/test/java/com/rabbitmq/examples/perf/MulticastValue.java b/src/test/java/com/rabbitmq/examples/perf/MulticastValue.java deleted file mode 100644 index d728667713..0000000000 --- a/src/test/java/com/rabbitmq/examples/perf/MulticastValue.java +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - -package com.rabbitmq.examples.perf; - -class MulticastValue implements VariableValue { - private final String name; - private final Object value; - - MulticastValue(String name, Object value) { - this.name = name; - this.value = value; - } - - public void setup(MulticastParams params) { - PerfUtil.setValue(params, name, value); - } - - public void teardown(MulticastParams params) { - } - - public String getName() { - return name; - } - - public Object getValue() { - return value; - } -} diff --git a/src/test/java/com/rabbitmq/examples/perf/MulticastVariable.java b/src/test/java/com/rabbitmq/examples/perf/MulticastVariable.java deleted file mode 100644 index c051281529..0000000000 --- a/src/test/java/com/rabbitmq/examples/perf/MulticastVariable.java +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - -package com.rabbitmq.examples.perf; - -import java.util.ArrayList; -import java.util.List; - -public class MulticastVariable implements Variable { - private final List values = new ArrayList(); - - public MulticastVariable(String name, Object... values) { - for (Object v : values) { - this.values.add(new MulticastValue(name, v)); - } - } - - public List getValues() { - return values; - } -} diff --git a/src/test/java/com/rabbitmq/examples/perf/PerfUtil.java b/src/test/java/com/rabbitmq/examples/perf/PerfUtil.java deleted file mode 100644 index 2adead26f0..0000000000 --- a/src/test/java/com/rabbitmq/examples/perf/PerfUtil.java +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - -package com.rabbitmq.examples.perf; - -import java.beans.IntrospectionException; -import java.beans.Introspector; -import java.beans.PropertyDescriptor; -import java.lang.reflect.InvocationTargetException; - -public class PerfUtil { - public static void setValue(Object obj, Object name, Object value) { - try { - PropertyDescriptor[] props = Introspector.getBeanInfo(obj.getClass()).getPropertyDescriptors(); - for (PropertyDescriptor prop : props) { - if (prop.getName().equals(name)) { - prop.getWriteMethod().invoke(obj, value); - return; - } - } - throw new RuntimeException("Could not find property " + name + " in " + obj.getClass()); - } catch (IntrospectionException e) { - throw new RuntimeException(e); - } catch (InvocationTargetException e) { - throw new RuntimeException(e); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - } -} diff --git a/src/test/java/com/rabbitmq/examples/perf/Producer.java b/src/test/java/com/rabbitmq/examples/perf/Producer.java deleted file mode 100644 index 477f2319b7..0000000000 --- a/src/test/java/com/rabbitmq/examples/perf/Producer.java +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - -package com.rabbitmq.examples.perf; - -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.ConfirmListener; -import com.rabbitmq.client.MessageProperties; -import com.rabbitmq.client.ReturnListener; - -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.Collections; -import java.util.List; -import java.util.SortedSet; -import java.util.TreeSet; -import java.util.UUID; -import java.util.concurrent.Semaphore; - -public class Producer extends ProducerConsumerBase implements Runnable, ReturnListener, - ConfirmListener -{ - private final Channel channel; - private final String exchangeName; - private final String id; - private final boolean randomRoutingKey; - private final boolean mandatory; - private final boolean immediate; - private final boolean persistent; - private final int txSize; - private final int msgLimit; - private final long timeLimit; - - private final Stats stats; - - private final byte[] message; - - private Semaphore confirmPool; - private final SortedSet unconfirmedSet = - Collections.synchronizedSortedSet(new TreeSet()); - - public Producer(Channel channel, String exchangeName, String id, boolean randomRoutingKey, - List flags, int txSize, - float rateLimit, int msgLimit, int minMsgSize, int timeLimit, - long confirm, Stats stats) - throws IOException { - - this.channel = channel; - this.exchangeName = exchangeName; - this.id = id; - this.randomRoutingKey = randomRoutingKey; - this.mandatory = flags.contains("mandatory"); - this.immediate = flags.contains("immediate"); - this.persistent = flags.contains("persistent"); - this.txSize = txSize; - this.rateLimit = rateLimit; - this.msgLimit = msgLimit; - this.timeLimit = 1000L * timeLimit; - this.message = new byte[minMsgSize]; - if (confirm > 0) { - this.confirmPool = new Semaphore((int)confirm); - } - this.stats = stats; - } - - public void handleReturn(int replyCode, - String replyText, - String exchange, - String routingKey, - AMQP.BasicProperties properties, - byte[] body) - throws IOException { - stats.handleReturn(); - } - - public void handleAck(long seqNo, boolean multiple) { - handleAckNack(seqNo, multiple, false); - } - - public void handleNack(long seqNo, boolean multiple) { - handleAckNack(seqNo, multiple, true); - } - - private void handleAckNack(long seqNo, boolean multiple, - boolean nack) { - int numConfirms = 0; - if (multiple) { - SortedSet confirmed = unconfirmedSet.headSet(seqNo + 1); - numConfirms += confirmed.size(); - confirmed.clear(); - } else { - unconfirmedSet.remove(seqNo); - numConfirms = 1; - } - if (nack) { - stats.handleNack(numConfirms); - } else { - stats.handleConfirm(numConfirms); - } - - if (confirmPool != null) { - for (int i = 0; i < numConfirms; ++i) { - confirmPool.release(); - } - } - - } - - public void run() { - long now; - long startTime; - startTime = now = System.currentTimeMillis(); - lastStatsTime = startTime; - msgCount = 0; - int totalMsgCount = 0; - - try { - - while ((timeLimit == 0 || now < startTime + timeLimit) && - (msgLimit == 0 || msgCount < msgLimit)) { - delay(now); - if (confirmPool != null) { - confirmPool.acquire(); - } - publish(createMessage(totalMsgCount)); - totalMsgCount++; - msgCount++; - - if (txSize != 0 && totalMsgCount % txSize == 0) { - channel.txCommit(); - } - stats.handleSend(); - now = System.currentTimeMillis(); - } - - } catch (IOException e) { - throw new RuntimeException(e); - } catch (InterruptedException e) { - throw new RuntimeException (e); - } - } - - private void publish(byte[] msg) - throws IOException { - - unconfirmedSet.add(channel.getNextPublishSeqNo()); - channel.basicPublish(exchangeName, randomRoutingKey ? UUID.randomUUID().toString() : id, - mandatory, immediate, - persistent ? MessageProperties.MINIMAL_PERSISTENT_BASIC : MessageProperties.MINIMAL_BASIC, - msg); - } - - private byte[] createMessage(int sequenceNumber) - throws IOException { - - ByteArrayOutputStream acc = new ByteArrayOutputStream(); - DataOutputStream d = new DataOutputStream(acc); - long nano = System.nanoTime(); - d.writeInt(sequenceNumber); - d.writeLong(nano); - d.flush(); - acc.flush(); - byte[] m = acc.toByteArray(); - if (m.length <= message.length) { - System.arraycopy(m, 0, message, 0, m.length); - return message; - } else { - return m; - } - } - -} diff --git a/src/test/java/com/rabbitmq/examples/perf/ProducerConsumerBase.java b/src/test/java/com/rabbitmq/examples/perf/ProducerConsumerBase.java deleted file mode 100644 index a5edf755a8..0000000000 --- a/src/test/java/com/rabbitmq/examples/perf/ProducerConsumerBase.java +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - -package com.rabbitmq.examples.perf; - -/** - * - */ -public class ProducerConsumerBase { - protected float rateLimit; - protected long lastStatsTime; - protected int msgCount; - - protected void delay(long now) { - - long elapsed = now - lastStatsTime; - //example: rateLimit is 5000 msg/s, - //10 ms have elapsed, we have sent 200 messages - //the 200 msgs we have actually sent should have taken us - //200 * 1000 / 5000 = 40 ms. So we pause for 40ms - 10ms - long pause = (long) (rateLimit == 0.0f ? - 0.0f : (msgCount * 1000.0 / rateLimit - elapsed)); - if (pause > 0) { - try { - Thread.sleep(pause); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - } - } -} diff --git a/src/test/java/com/rabbitmq/examples/perf/RateVsLatencyScenario.java b/src/test/java/com/rabbitmq/examples/perf/RateVsLatencyScenario.java deleted file mode 100644 index 588ae18e18..0000000000 --- a/src/test/java/com/rabbitmq/examples/perf/RateVsLatencyScenario.java +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - -package com.rabbitmq.examples.perf; - -import com.rabbitmq.client.ConnectionFactory; - -public class RateVsLatencyScenario implements Scenario { - private final String name; - private final ConnectionFactory factory; - private final MulticastParams params; - private VaryingScenario impl; - - public RateVsLatencyScenario(String name, ConnectionFactory factory, MulticastParams params) { - this.name = name; - this.factory = factory; - this.params = params; - } - - public void run() throws Exception { - SimpleScenario s = new SimpleScenario("untitled", factory, params); - s.run(); - SimpleScenarioStats m = s.getStats(); - int maxRate = (int) (m.getRecvRate() + m.getSendRate()) / 2; - Double[] factors = new Double[]{0.01, 0.2, 0.4, 0.6, 0.8, 0.9, 0.95, 0.96, 0.97, 0.98, 0.99, 1.0, 1.01, 1.02, 1.03, 1.04, 1.05}; - Integer [] rates = new Integer[factors.length]; - for (int i = 0; i < rates.length; i++) { - rates[i] = (int) (factors[i] * maxRate); - } - impl = new VaryingScenario("untitled", factory, params, - new MulticastVariable("producerRateLimit", (Object[]) rates)); - impl.run(); - } - - public ScenarioStats getStats() { - return impl.getStats(); - } - - public String getName() { - return name; - } -} diff --git a/src/test/java/com/rabbitmq/examples/perf/Scenario.java b/src/test/java/com/rabbitmq/examples/perf/Scenario.java deleted file mode 100644 index 733920dd8e..0000000000 --- a/src/test/java/com/rabbitmq/examples/perf/Scenario.java +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - -package com.rabbitmq.examples.perf; - -public interface Scenario { - public String getName(); - public void run() throws Exception; - public ScenarioStats getStats(); -} diff --git a/src/test/java/com/rabbitmq/examples/perf/ScenarioFactory.java b/src/test/java/com/rabbitmq/examples/perf/ScenarioFactory.java deleted file mode 100644 index 287249875e..0000000000 --- a/src/test/java/com/rabbitmq/examples/perf/ScenarioFactory.java +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - -package com.rabbitmq.examples.perf; - -import com.rabbitmq.client.ConnectionFactory; - -import java.util.List; -import java.util.Map; - -public class ScenarioFactory { - public static Scenario fromJSON(Map json, ConnectionFactory factory) { - String uri = "amqp://localhost"; - String type = read("type", json, String.class); - String name = read("name", json, String.class); - Integer interval = read("interval", json, Integer.class, 1000); - List paramsJSON = read("params", json, List.class); - - try { - uri = read("uri", json, String.class); - factory.setUri(uri); - } catch(Exception e) { - throw new RuntimeException("scenario: " + name + " with malformed uri: " - + uri + " - " + e.getMessage()); - } - - MulticastParams[] params = new MulticastParams[paramsJSON.size()]; - for (int i = 0; i < paramsJSON.size(); i++) { - params[i] = paramsFromJSON((Map) paramsJSON.get(i)); - } - - if (type.equals("simple")) { - return new SimpleScenario(name, factory, interval, params); - } - else if (type.equals("rate-vs-latency")) { - return new RateVsLatencyScenario(name, factory, params[0]); // TODO - } - else if (type.equals("varying")) { - List variablesJSON = read("variables", json, List.class); - Variable[] variables = new Variable[variablesJSON.size()]; - for (int i = 0; i < variablesJSON.size(); i++) { - variables[i] = variableFromJSON((Map) variablesJSON.get(i)); - } - - return new VaryingScenario(name, factory, params, variables); - } - - throw new RuntimeException("Type " + type + " was not simple or varying."); - } - - private static T read(String key, Map map, Class clazz) { - if (map.containsKey(key)) { - return read0(key, map, clazz); - } - else { - throw new RuntimeException("Key " + key + " not found."); - } - } - - private static T read(String key, Map map, Class clazz, T def) { - if (map.containsKey(key)) { - return read0(key, map, clazz); - } - else { - return def; - } - } - - @SuppressWarnings("unchecked") - private static T read0(String key, Map map, Class clazz) { - Object o = map.get(key); - if (clazz.isAssignableFrom(o.getClass())) { - return (T) o; - } - else { - throw new RuntimeException("Object under key " + key + " was a " + o.getClass() + ", not a " + clazz + "."); - } - } - - private static MulticastParams paramsFromJSON(Map json) { - MulticastParams params = new MulticastParams(); - params.setAutoDelete(true); - for (Object key : json.keySet()) { - PerfUtil.setValue(params, hyphensToCamel((String)key), json.get(key)); - } - return params; - } - - private static Variable variableFromJSON(Map json) { - String type = read("type", json, String.class, "multicast"); - String name = read("name", json, String.class); - Object[] values = read("values", json, List.class).toArray(); - - if (type.equals("multicast")) { - return new MulticastVariable(hyphensToCamel(name), values); - } - - throw new RuntimeException("Type " + type + " was not multicast"); - } - - private static String hyphensToCamel(String name) { - String out = ""; - for (String part : name.split("-")) { - out += part.substring(0, 1).toUpperCase() + part.substring(1); - } - return out.substring(0, 1).toLowerCase() + out.substring(1); - } -} diff --git a/src/test/java/com/rabbitmq/examples/perf/ScenarioStats.java b/src/test/java/com/rabbitmq/examples/perf/ScenarioStats.java deleted file mode 100644 index 89ca97e3d2..0000000000 --- a/src/test/java/com/rabbitmq/examples/perf/ScenarioStats.java +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - -package com.rabbitmq.examples.perf; - -import java.util.Map; - -public interface ScenarioStats { - public Map results(); -} diff --git a/src/test/java/com/rabbitmq/examples/perf/SimpleScenario.java b/src/test/java/com/rabbitmq/examples/perf/SimpleScenario.java deleted file mode 100644 index 219e6792ac..0000000000 --- a/src/test/java/com/rabbitmq/examples/perf/SimpleScenario.java +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - -package com.rabbitmq.examples.perf; - -import com.rabbitmq.client.ConnectionFactory; - -import java.io.IOException; -import java.util.concurrent.TimeoutException; - -public class SimpleScenario implements Scenario { - private final String name; - private final ConnectionFactory factory; - private final MulticastParams[] params; - private final long interval; - private SimpleScenarioStats stats; - - public SimpleScenario(String name, ConnectionFactory factory, MulticastParams... params) { - this(name, factory, 1000L, params); - } - - public SimpleScenario(String name, ConnectionFactory factory, long interval, MulticastParams... params) { - this.name = name; - this.factory = factory; - this.params = params; - this.interval = interval; - } - - public void run() throws IOException, InterruptedException, TimeoutException { - this.stats = new SimpleScenarioStats(interval); - for (MulticastParams p : params) { - MulticastSet set = new MulticastSet(stats, factory, p); - stats.setup(p); - set.run(); - } - } - - public SimpleScenarioStats getStats() { - return stats; - } - - public String getName() { - return name; - } -} diff --git a/src/test/java/com/rabbitmq/examples/perf/SimpleScenarioStats.java b/src/test/java/com/rabbitmq/examples/perf/SimpleScenarioStats.java deleted file mode 100644 index 91f5fb80ab..0000000000 --- a/src/test/java/com/rabbitmq/examples/perf/SimpleScenarioStats.java +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - -package com.rabbitmq.examples.perf; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -class SimpleScenarioStats extends Stats implements ScenarioStats { - private static final int IGNORE_FIRST = 3; - - private final List> samples = new ArrayList>(); - private long elapsedTotalToIgnore; - private long minMsgSize; - - public SimpleScenarioStats(long interval) { - super(interval); - } - - protected void report(long now) { - if (samples.size() == IGNORE_FIRST) { - cumulativeLatencyTotal = 0; - latencyCountTotal = 0; - sendCountTotal = 0; - recvCountTotal = 0; - elapsedTotalToIgnore = elapsedTotal; - } - - Map sample = new HashMap(); - sample.put("send-msg-rate", rate(sendCountInterval, elapsedInterval)); - sample.put("send-bytes-rate", rate(sendCountInterval, elapsedInterval) * minMsgSize); - sample.put("recv-msg-rate", rate(recvCountInterval, elapsedInterval)); - sample.put("recv-bytes-rate", rate(recvCountInterval, elapsedInterval) * minMsgSize); - sample.put("elapsed", elapsedTotal); - if (latencyCountInterval > 0) { - sample.put("avg-latency", intervalAverageLatency()); - sample.put("min-latency", minLatency / 1000L); - sample.put("max-latency", maxLatency / 1000L); - } - samples.add(sample); - } - - public Map results() { - Map map = new HashMap(); - map.put("send-msg-rate", getSendRate()); - map.put("send-bytes-rate", getSendRate() * minMsgSize); - map.put("recv-msg-rate", getRecvRate()); - map.put("recv-bytes-rate", getRecvRate() * minMsgSize); - if (latencyCountTotal > 0) { - map.put("avg-latency", overallAverageLatency()); - } - map.put("samples", samples); - return map; - } - - public void setup(MulticastParams params) { - this.minMsgSize = params.getMinMsgSize(); - } - - public double getSendRate() { - return rate(sendCountTotal, elapsedTotal - elapsedTotalToIgnore); - } - - public double getRecvRate() { - return rate(recvCountTotal, elapsedTotal - elapsedTotalToIgnore); - } - - private double rate(long count, long elapsed) { - return elapsed == 0 ? 0.0 : (1000.0 * count / elapsed); - } - - private long overallAverageLatency() { - return cumulativeLatencyTotal / (1000L * latencyCountTotal); - } - - private long intervalAverageLatency() { - return cumulativeLatencyInterval / (1000L * latencyCountInterval); - } -} diff --git a/src/test/java/com/rabbitmq/examples/perf/Stats.java b/src/test/java/com/rabbitmq/examples/perf/Stats.java deleted file mode 100644 index ba0c9d44e7..0000000000 --- a/src/test/java/com/rabbitmq/examples/perf/Stats.java +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - -package com.rabbitmq.examples.perf; - -public abstract class Stats { - protected final long interval; - - protected final long startTime; - protected long lastStatsTime; - - protected int sendCountInterval; - protected int returnCountInterval; - protected int confirmCountInterval; - protected int nackCountInterval; - protected int recvCountInterval; - - protected int sendCountTotal; - protected int recvCountTotal; - - protected int latencyCountInterval; - protected int latencyCountTotal; - protected long minLatency; - protected long maxLatency; - protected long cumulativeLatencyInterval; - protected long cumulativeLatencyTotal; - - protected long elapsedInterval; - protected long elapsedTotal; - - public Stats(long interval) { - this.interval = interval; - startTime = System.currentTimeMillis(); - reset(startTime); - } - - private void reset(long t) { - lastStatsTime = t; - - sendCountInterval = 0; - returnCountInterval = 0; - confirmCountInterval = 0; - nackCountInterval = 0; - recvCountInterval = 0; - - minLatency = Long.MAX_VALUE; - maxLatency = Long.MIN_VALUE; - latencyCountInterval = 0; - cumulativeLatencyInterval = 0L; - } - - private void report() { - long now = System.currentTimeMillis(); - elapsedInterval = now - lastStatsTime; - - if (elapsedInterval >= interval) { - elapsedTotal += elapsedInterval; - report(now); - reset(now); - } - } - - protected abstract void report(long now); - - public synchronized void handleSend() { - sendCountInterval++; - sendCountTotal++; - report(); - } - - public synchronized void handleReturn() { - returnCountInterval++; - report(); - } - - public synchronized void handleConfirm(int numConfirms) { - confirmCountInterval +=numConfirms; - report(); - } - - public synchronized void handleNack(int numAcks) { - nackCountInterval +=numAcks; - report(); - } - - public synchronized void handleRecv(long latency) { - recvCountInterval++; - recvCountTotal++; - if (latency > 0) { - minLatency = Math.min(minLatency, latency); - maxLatency = Math.max(maxLatency, latency); - cumulativeLatencyInterval += latency; - cumulativeLatencyTotal += latency; - latencyCountInterval++; - latencyCountTotal++; - } - report(); - } - -} diff --git a/src/test/java/com/rabbitmq/examples/perf/Variable.java b/src/test/java/com/rabbitmq/examples/perf/Variable.java deleted file mode 100644 index 17042f5f56..0000000000 --- a/src/test/java/com/rabbitmq/examples/perf/Variable.java +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - -package com.rabbitmq.examples.perf; - -import java.util.List; - -public interface Variable { - public List getValues(); -} diff --git a/src/test/java/com/rabbitmq/examples/perf/VariableValue.java b/src/test/java/com/rabbitmq/examples/perf/VariableValue.java deleted file mode 100644 index 44812fa055..0000000000 --- a/src/test/java/com/rabbitmq/examples/perf/VariableValue.java +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - -package com.rabbitmq.examples.perf; - -public interface VariableValue { - public void setup(MulticastParams params) throws Exception; - public void teardown(MulticastParams params); - - public String getName(); - public Object getValue(); -} diff --git a/src/test/java/com/rabbitmq/examples/perf/VaryingScenario.java b/src/test/java/com/rabbitmq/examples/perf/VaryingScenario.java deleted file mode 100644 index d34938e247..0000000000 --- a/src/test/java/com/rabbitmq/examples/perf/VaryingScenario.java +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - -package com.rabbitmq.examples.perf; - -import com.rabbitmq.client.ConnectionFactory; - -import java.util.ArrayList; -import java.util.List; - -public class VaryingScenario implements Scenario { - private final String name; - private final ConnectionFactory factory; - private final MulticastParams[] params; - private final VaryingScenarioStats stats = new VaryingScenarioStats(); - private final Variable[] variables; - - public VaryingScenario(String name, ConnectionFactory factory, - MulticastParams params, Variable... variables) { - this(name, factory, new MulticastParams[]{params}, variables); - } - - public VaryingScenario(String name, ConnectionFactory factory, - MulticastParams[] params, Variable... variables) { - this.name = name; - this.factory = factory; - this.params = params; - this.variables = variables; - } - - public void run() throws Exception { - run(variables, new ArrayList()); - } - - private void run(Variable[] variables, List values) throws Exception { - if (variables.length > 0) { - Variable variable = variables[0]; - Variable[] rest = rest(variables); - for (VariableValue value : variable.getValues()) { - List values2 = new ArrayList(values); - values2.add(value); - run(rest, values2); - } - } - else { - SimpleScenarioStats stats0 = stats.next(values); - for (MulticastParams p : params) { - for (VariableValue value : values) { - value.setup(p); - } - MulticastSet set = new MulticastSet(stats0, factory, p); - stats0.setup(p); - set.run(); - for (VariableValue value : values) { - value.teardown(p); - } - } - System.out.print("#"); - System.out.flush(); - } - } - - private Variable[] rest(Variable[] variables) { - Variable[] tail = new Variable[variables.length - 1]; - System.arraycopy(variables, 1, tail, 0, tail.length); - return tail; - } - - public ScenarioStats getStats() { - return stats; - } - - public String getName() { - return name; - } -} diff --git a/src/test/java/com/rabbitmq/examples/perf/VaryingScenarioStats.java b/src/test/java/com/rabbitmq/examples/perf/VaryingScenarioStats.java deleted file mode 100644 index 317b24c863..0000000000 --- a/src/test/java/com/rabbitmq/examples/perf/VaryingScenarioStats.java +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - -package com.rabbitmq.examples.perf; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class VaryingScenarioStats implements ScenarioStats { - private final Map, SimpleScenarioStats> stats = new HashMap, SimpleScenarioStats>(); - private final List> keys = new ArrayList>(); - - public VaryingScenarioStats() {} - - public SimpleScenarioStats next(List value) { - SimpleScenarioStats stats = new SimpleScenarioStats(1000L); - keys.add(value); - this.stats.put(value, stats); - return stats; - } - - @SuppressWarnings("unchecked") - public Map results() { - Map map = new HashMap(); - - List dimensions = new ArrayList(); - for (VariableValue keyElem : keys.get(0)) { - dimensions.add(keyElem.getName()); - } - map.put("dimensions", dimensions); - - Map> dimensionValues = new HashMap>(); - for (List key : keys) { - for (VariableValue elem : key) { - List values = get(elem.getName(), dimensionValues, new ArrayList()); - String value = elem.getValue().toString(); - if (!values.contains(value)) { - values.add(value); - } - } - } - map.put("dimension-values", dimensionValues); - - Map data = new HashMap(); - for (List key : keys) { - Map results = stats.get(key).results(); - Map node = data; - for (int i = 0; i < key.size(); i++) { - VariableValue elem = key.get(i); - if (i == key.size() - 1) { - node.put(elem.getValue().toString(), results); - } - else { - node = (Map) get(elem.getValue().toString(), node, new HashMap()); - } - } - } - map.put("data", data); - - return map; - } - - private V get(K key, Map map, V def) { - V val = map.get(key); - if (val == null) { - val = def; - map.put(key, val); - } - return val; - } -} From 9e4a12114ab5df999afdb95edc0cef86e0592d2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 28 Sep 2016 08:55:57 +0200 Subject: [PATCH 0325/2114] Do not fail build if javadoc has warnings And use clean before creating distribution. --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index a3a990a64c..8bb2365baf 100644 --- a/Makefile +++ b/Makefile @@ -19,8 +19,8 @@ all: deps deps: $(DEPS_DIR)/rabbit @: -dist: - $(MVN) $(MVN_FLAGS) -DskipTests=true package javadoc:javadoc +dist: clean + $(MVN) $(MVN_FLAGS) -DskipTests=true -Dmaven.javadoc.failOnError=false package javadoc:javadoc $(DEPS_DIR)/rabbit: git clone https://github.com/rabbitmq/rabbitmq-server.git $@ From 3a3eafbb43fb8e884440bec8aac3803671eb7e3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 28 Sep 2016 15:05:18 +0200 Subject: [PATCH 0326/2114] Add TLS handshake test --- .../client/test/ssl/HandshakeTest.java | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 src/test/java/com/rabbitmq/client/test/ssl/HandshakeTest.java diff --git a/src/test/java/com/rabbitmq/client/test/ssl/HandshakeTest.java b/src/test/java/com/rabbitmq/client/test/ssl/HandshakeTest.java new file mode 100644 index 0000000000..6206fc4cef --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/ssl/HandshakeTest.java @@ -0,0 +1,82 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.test.ssl; + +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import org.junit.Test; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManagerFactory; +import java.io.FileInputStream; +import java.security.KeyStore; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + +/** + * + */ +public class HandshakeTest { + + @Test + public void handshake() throws Exception { + for (int i = 0; i < 100; i++) { + String keystorePath = System.getProperty("test-keystore.ca"); + assertNotNull(keystorePath); + String keystorePasswd = System.getProperty("test-keystore.password"); + assertNotNull(keystorePasswd); + char[] keystorePassword = keystorePasswd.toCharArray(); + + KeyStore tks = KeyStore.getInstance("JKS"); + tks.load(new FileInputStream(keystorePath), keystorePassword); + + TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); + tmf.init(tks); + + String p12Path = System.getProperty("test-client-cert.path"); + assertNotNull(p12Path); + String p12Passwd = System.getProperty("test-client-cert.password"); + assertNotNull(p12Passwd); + KeyStore ks = KeyStore.getInstance("PKCS12"); + char[] p12Password = p12Passwd.toCharArray(); + ks.load(new FileInputStream(p12Path), p12Password); + + KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); + kmf.init(ks, p12Password); + + SSLContext c = SSLContext.getInstance("TLSv1.2"); + c.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); + + c.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); + ConnectionFactory connectionFactory = new ConnectionFactory(); + connectionFactory.useBlockingIo(); + connectionFactory.useSslProtocol(c); + + Connection connection = null; + try { + connection = connectionFactory.newConnection(); + } catch (Exception e) { + fail("Connection #" + i + " failed with error " + e.getMessage()); + } finally { + if (connection != null) { + connection.abort(); + } + } + } + } +} From ee94a9ec7256f32b75ba58a543c02ef7e29db229 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 28 Sep 2016 15:52:11 +0200 Subject: [PATCH 0327/2114] Add TLS handshake test to test suite Fixes #11 --- src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java index 92f5ecdf57..7d2b9ee68f 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java @@ -34,7 +34,8 @@ ConnectionFactoryDefaultTlsVersion.class, NioTlsUnverifiedConnection.class, NioTlsVerifiedConnection.class, - NioTlsBadVerifiedConnection.class + NioTlsBadVerifiedConnection.class, + HandshakeTest.class }) public class SSLTests { From 6168e97760dd1c926c16aec59804605ec6d866b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 29 Sep 2016 09:24:03 +0200 Subject: [PATCH 0328/2114] Shutdown NIO loop ASAP Fixes #11 --- .../com/rabbitmq/client/impl/nio/NioLoop.java | 9 +++------ .../client/impl/nio/NioLoopContext.java | 14 +++++--------- .../impl/nio/SocketChannelFrameHandler.java | 1 - .../nio/SocketChannelFrameHandlerFactory.java | 18 +++++++++--------- .../com/rabbitmq/client/test/JavaNioTest.java | 10 ++++++++++ 5 files changed, 27 insertions(+), 25 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java b/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java index 01deb6aed1..0a96577bf5 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java @@ -66,12 +66,11 @@ public void run() { boolean writeRegistered = false; try { - int idlenessCount = 0; while (true && !Thread.currentThread().isInterrupted()) { for (SelectionKey selectionKey : selector.keys()) { SocketChannelFrameHandlerState state = (SocketChannelFrameHandlerState) selectionKey.attachment(); - if (state.getConnection().getHeartbeat() > 0) { + if (state.getConnection() != null && state.getConnection().getHeartbeat() > 0) { long now = System.currentTimeMillis(); if ((now - state.getLastActivity()) > state.getConnection().getHeartbeat() * 1000 * 2) { try { @@ -89,8 +88,7 @@ public void run() { if (!writeRegistered && registrations.isEmpty() && writeRegistrations.isEmpty()) { // we can block, registrations will call Selector.wakeup() select = selector.select(1000); - idlenessCount++; - if (idlenessCount == 10 && selector.keys().size() == 0) { + if (selector.keys().size() == 0) { // we haven't been doing anything for a while, shutdown state boolean clean = context.cleanUp(); if (clean) { @@ -118,7 +116,6 @@ public void run() { } if (select > 0) { - idlenessCount = 0; Set readyKeys = selector.selectedKeys(); Iterator iterator = readyKeys.iterator(); while (iterator.hasNext()) { @@ -246,7 +243,7 @@ public void run() { } } } catch (Exception e) { - LOGGER.error("Error in read loop", e); + LOGGER.error("Error in NIO loop", e); } } diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioLoopContext.java b/src/main/java/com/rabbitmq/client/impl/nio/NioLoopContext.java index e666985c6e..70211ccfcb 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioLoopContext.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioLoopContext.java @@ -9,7 +9,6 @@ import java.nio.channels.Selector; import java.util.concurrent.ExecutorService; import java.util.concurrent.ThreadFactory; -import java.util.concurrent.atomic.AtomicLong; /** * @@ -29,8 +28,6 @@ public class NioLoopContext { SelectorHolder readSelectorState; SelectorHolder writeSelectorState; - private final AtomicLong nioLoopsConnectionCount = new AtomicLong(); - public NioLoopContext(SocketChannelFrameHandlerFactory socketChannelFrameHandlerFactory, NioParams nioParams) { this.socketChannelFrameHandlerFactory = socketChannelFrameHandlerFactory; @@ -40,10 +37,6 @@ public NioLoopContext(SocketChannelFrameHandlerFactory socketChannelFrameHandler this.writeBuffer = ByteBuffer.allocate(nioParams.getWriteByteBufferSize()); } - void notifyNewConnection() { - nioLoopsConnectionCount.incrementAndGet(); - } - void initStateIfNecessary() throws IOException { if (this.readSelectorState == null) { this.readSelectorState = new SelectorHolder(Selector.open()); @@ -67,10 +60,13 @@ private void startIoLoops() { } protected boolean cleanUp() { - long connectionCountNow = nioLoopsConnectionCount.get(); + int readRegistrationsCount = readSelectorState.registrations.size(); + if(readRegistrationsCount != 0) { + return false; + } socketChannelFrameHandlerFactory.lock(); try { - if (connectionCountNow != nioLoopsConnectionCount.get()) { + if (readRegistrationsCount != readSelectorState.registrations.size()) { // a connection request has come in meanwhile, don't do anything return false; } diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandler.java b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandler.java index 296e521c2a..8e9bab5dc5 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandler.java @@ -76,7 +76,6 @@ public void sendHeader() throws IOException { @Override public void initialize(AMQConnection connection) { state.setConnection(connection); - state.startReading(); } @Override diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java index 66b2c1e84e..71c55206ab 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java @@ -98,20 +98,20 @@ public FrameHandler create(Address addr) throws IOException { long modulo = globalConnectionCount.getAndIncrement() % nioParams.getNbIoThreads(); nioLoopContext = nioLoopContexts.get((int) modulo); nioLoopContext.initStateIfNecessary(); - nioLoopContext.notifyNewConnection(); + SocketChannelFrameHandlerState state = new SocketChannelFrameHandlerState( + channel, + nioLoopContext, + nioParams, + sslEngine + ); + state.startReading(); + SocketChannelFrameHandler frameHandler = new SocketChannelFrameHandler(state); + return frameHandler; } finally { stateLock.unlock(); } - SocketChannelFrameHandlerState state = new SocketChannelFrameHandlerState( - channel, - nioLoopContext, - nioParams, - sslEngine - ); - SocketChannelFrameHandler frameHandler = new SocketChannelFrameHandler(state); - return frameHandler; } catch(IOException e) { try { if(sslEngine != null && channel != null) { diff --git a/src/test/java/com/rabbitmq/client/test/JavaNioTest.java b/src/test/java/com/rabbitmq/client/test/JavaNioTest.java index 7e61285d84..4ed0facc45 100644 --- a/src/test/java/com/rabbitmq/client/test/JavaNioTest.java +++ b/src/test/java/com/rabbitmq/client/test/JavaNioTest.java @@ -92,6 +92,16 @@ public void shutdownCompleted(ShutdownSignalException cause) { } } + @Test + public void nioLoopCleaning() throws Exception { + ConnectionFactory connectionFactory = new ConnectionFactory(); + connectionFactory.useNio(); + for(int i = 0; i < 10; i++) { + Connection connection = connectionFactory.newConnection(); + connection.abort(); + } + } + private Connection basicGetBasicConsume(ConnectionFactory connectionFactory, String queue, final CountDownLatch latch) throws IOException, TimeoutException { Connection connection = connectionFactory.newConnection(); From 9f3fe903ee094ea72f47805588cd04c95beda5ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 29 Sep 2016 18:11:19 +0200 Subject: [PATCH 0329/2114] Add connection re-attemps to stabilize SSL tests Fixes #11 --- .../client/test/ssl/BadVerifiedConnection.java | 14 +++++++------- .../test/ssl/NioTlsUnverifiedConnection.java | 18 ++++++++++++++++-- .../client/test/ssl/UnverifiedConnection.java | 15 ++++++++++++++- .../client/test/ssl/VerifiedConnection.java | 18 +++++++++++++++--- 4 files changed, 52 insertions(+), 13 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java index dddf43eeb9..bd55952d3f 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java @@ -90,13 +90,13 @@ public void openConnection() throw new IOException(ex.toString()); } - try { - connection = connectionFactory.newConnection(); - fail(); - } catch (SSLHandshakeException ignored) { - } catch (IOException e) { - fail(); - } + try { + connection = connectionFactory.newConnection(); + fail(); + } catch (SSLHandshakeException ignored) { + } catch (IOException e) { + fail(); + } } public void openChannel() {} diff --git a/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java index b7373e61df..06781e02a9 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java @@ -17,7 +17,9 @@ import com.rabbitmq.client.*; import com.rabbitmq.client.test.BrokerTestCase; +import org.junit.Assert; import org.junit.Test; +import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.concurrent.CountDownLatch; @@ -25,6 +27,7 @@ import java.util.concurrent.TimeoutException; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; /** * @@ -44,9 +47,20 @@ public void openConnection() throw new IOException(ex.toString()); } - if (connection == null) { - connection = connectionFactory.newConnection(); + int attempt = 0; + while(attempt < 3) { + try { + connection = connectionFactory.newConnection(); + break; + } catch(Exception e) { + LoggerFactory.getLogger(getClass()).warn("Error when opening TLS connection"); + attempt++; + } + } + if(connection == null) { + fail("Couldn't open TLS connection after 3 attemps"); } + } @Test diff --git a/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java index ae8cf4ffb6..bbf82e0287 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java @@ -26,6 +26,7 @@ import com.rabbitmq.client.GetResponse; import com.rabbitmq.client.test.BrokerTestCase; +import org.slf4j.LoggerFactory; /** * Test for bug 19356 - SSL Support in rabbitmq @@ -48,7 +49,19 @@ public void openConnection() throw new IOException(ex.toString()); } - connection = connectionFactory.newConnection(); + int attempt = 0; + while(attempt < 3) { + try { + connection = connectionFactory.newConnection(); + break; + } catch(Exception e) { + LoggerFactory.getLogger(getClass()).warn("Error when opening TLS connection"); + attempt++; + } + } + if(connection == null) { + fail("Couldn't open TLS connection after 3 attemps"); + } } @Test public void sSL() throws IOException diff --git a/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java index b8bbb855d4..1045b1ac17 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java @@ -16,6 +16,7 @@ package com.rabbitmq.client.test.ssl; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; import java.io.FileInputStream; import java.io.IOException; @@ -32,6 +33,7 @@ import javax.net.ssl.TrustManagerFactory; import com.rabbitmq.client.ConnectionFactory; +import org.slf4j.LoggerFactory; /** * Test for bug 19356 - SSL Support in rabbitmq @@ -87,8 +89,18 @@ public void openConnection() throw new IOException(ex.toString()); } - //if (connection == null) { - connection = connectionFactory.newConnection(); - //} + int attempt = 0; + while(attempt < 3) { + try { + connection = connectionFactory.newConnection(); + break; + } catch(Exception e) { + LoggerFactory.getLogger(getClass()).warn("Error when opening TLS connection"); + attempt++; + } + } + if(connection == null) { + fail("Couldn't open TLS connection after 3 attemps"); + } } } From 33cd661117bfb845ae029d39a2b6b44bde643507 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 30 Sep 2016 09:43:05 +0200 Subject: [PATCH 0330/2114] Repeat reading from socket when reading frame Fixes #11 --- .../impl/nio/ByteBufferInputStream.java | 17 +++++++++++- .../rabbitmq/client/test/BrokerTestCase.java | 27 +++++++++++-------- 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/nio/ByteBufferInputStream.java b/src/main/java/com/rabbitmq/client/impl/nio/ByteBufferInputStream.java index ffb248883d..2469f6e965 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/ByteBufferInputStream.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/ByteBufferInputStream.java @@ -47,7 +47,22 @@ private int readFromBuffer(ByteBuffer buffer) { private static void readFromNetworkIfNecessary(ReadableByteChannel channel, ByteBuffer buffer) throws IOException { if(!buffer.hasRemaining()) { buffer.clear(); - channel.read(buffer); + int read = channel.read(buffer); + if(read <= 0) { + int attempt = 0; + while(attempt < 3) { + try { + Thread.sleep(100L); + } catch (InterruptedException e) { + // ignore + } + read = channel.read(buffer); + if(read > 0) { + break; + } + attempt++; + } + } buffer.flip(); } } diff --git a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java index 7c0dd211d0..7601423022 100644 --- a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java +++ b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java @@ -91,19 +91,24 @@ protected boolean nio() { @After public void tearDown() throws IOException, TimeoutException { - closeChannel(); - closeConnection(); - - openConnection(); - openChannel(); - releaseResources(); - closeChannel(); - closeConnection(); - if(nio()) { - if(this.nioExecutor != null) { - this.nioExecutor.shutdownNow(); + try { + closeChannel(); + closeConnection(); + + openConnection(); + openChannel(); + releaseResources(); + closeChannel(); + closeConnection(); + } finally { + if(nio()) { + if(this.nioExecutor != null) { + this.nioExecutor.shutdownNow(); + } } } + + } /** From ac5f01197a94674d415aef876e8aacf77a326cea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 30 Sep 2016 11:03:11 +0200 Subject: [PATCH 0331/2114] Remove Tracer Now located here: https://github.com/rabbitmq/rabbitmq-tracer Fixes #204 --- src/main/java/com/rabbitmq/tools/Tracer.java | 572 ------------------- 1 file changed, 572 deletions(-) delete mode 100644 src/main/java/com/rabbitmq/tools/Tracer.java diff --git a/src/main/java/com/rabbitmq/tools/Tracer.java b/src/main/java/com/rabbitmq/tools/Tracer.java deleted file mode 100644 index 3df2492287..0000000000 --- a/src/main/java/com/rabbitmq/tools/Tracer.java +++ /dev/null @@ -1,572 +0,0 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - -package com.rabbitmq.tools; - -import java.io.BufferedOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.io.PrintStream; -import java.net.ServerSocket; -import java.net.Socket; -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; - -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.impl.AMQCommand; -import com.rabbitmq.client.impl.AMQContentHeader; -import com.rabbitmq.client.impl.AMQImpl; -import com.rabbitmq.client.impl.Frame; -import com.rabbitmq.utility.BlockingCell; -import com.rabbitmq.utility.Utility; - -/** - *

AMQP 0-9-1 protocol traffic capture program. Listens on a port (in-port) and when a - * connection arrives, makes an outbound connection to a host and - * port (out-port). Relays frames from the in-port to the out-port. - * Commands are decoded and printed to a supplied {@link Logger}. - *

- *

- * The stand-alone program ({@link #main(String[])}) prints to System.out, - * using a private {@link AsyncLogger} instance. When the connection closes - * the program listens for a subsequent connection and traces that to the same {@link Logger}. - * This continues until the program is interrupted. - *

- *

- * Options for controlling, for example, whether command bodies are decoded, - * are obtained from System.properties, and are reported to the console - * before starting the trace. - *

- *

- * These constructors block waiting for a connection to arrive on the listenPort. - * Tracing does not begin until the tracer is {@link #start()}ed which {@link Logger#start()}s - * the supplied logger and creates and starts a {@link Thread} for relaying and deconstructing the frames. - *

- * The properties specified in props are used at {@link Tracer#start()} time and may be modified - * before this call. - * @see Tracer.Logger - * @see Tracer.AsyncLogger - */ -public class Tracer implements Runnable { - private static final int DEFAULT_LISTEN_PORT = 5673; - private static final String DEFAULT_CONNECT_HOST = "localhost"; - private static final int DEFAULT_CONNECT_PORT = 5672; - - private static final String PROP_PREFIX = "com.rabbitmq.tools.Tracer."; - - private static boolean getBoolProperty(String propertyName, Properties props) { - return Boolean.parseBoolean(props.getProperty(PROP_PREFIX + propertyName)); - } - - private static void printBoolProperty(String propName, Properties props) { - StringBuilder sb = new StringBuilder(100); - System.out.println(sb.append(PROP_PREFIX).append(propName) - .append(" = ").append(getBoolProperty(propName, props)).toString()); - } - - public static void main(String[] args) { - int listenPort = args.length > 0 ? Integer.parseInt(args[0]) : DEFAULT_LISTEN_PORT; - String connectHost = args.length > 1 ? args[1] : DEFAULT_CONNECT_HOST; - int connectPort = args.length > 2 ? Integer.parseInt(args[2]) : DEFAULT_CONNECT_PORT; - - System.out.println("Usage: Tracer [ [ []]]"); - System.out.println(" Serially traces connections on the , logging\n" - + " frames received and passing them to the connect host and port."); - System.out.println("Invoked as: Tracer " + listenPort + " " + connectHost + " " + connectPort); - - Properties props = System.getProperties(); - printBoolProperty("WITHHOLD_INBOUND_HEARTBEATS", props); - printBoolProperty("WITHHOLD_OUTBOUND_HEARTBEATS", props); - printBoolProperty("NO_ASSEMBLE_FRAMES", props); - printBoolProperty("NO_DECODE_FRAMES", props); - printBoolProperty("SUPPRESS_COMMAND_BODIES", props); - - Logger logger = new AsyncLogger(System.out); // initially stopped - try { - ServerSocket server = new ServerSocket(listenPort); - int counter = 0; - while (true) { - Socket conn = server.accept(); - new Tracer( conn - , "Tracer-" + (counter++) - , connectHost, connectPort - , logger - ).start(); - } - } catch (Exception e) { - logger.stop(); // will stop shared logger thread - e.printStackTrace(); - System.exit(1); - } - } - - private final Properties props; - private final Socket inSock; - private final Socket outSock; - private final String idLabel; - private final DataInputStream iis; - private final DataOutputStream ios; - private final DataInputStream ois; - private final DataOutputStream oos; - private final Logger logger; - private final BlockingCell reportEnd; - private final AtomicBoolean started; - - private Tracer(Socket sock, String id, String host, int port, Logger logger, BlockingCell reportEnd, Properties props) - throws IOException { - - this.props = props; - this.inSock = sock; - this.outSock = new Socket(host, port); - this.idLabel = ": <" + id + "> "; - - this.iis = new DataInputStream(this.inSock.getInputStream()); - this.ios = new DataOutputStream(this.inSock.getOutputStream()); - this.ois = new DataInputStream(this.outSock.getInputStream()); - this.oos = new DataOutputStream(this.outSock.getOutputStream()); - this.logger = logger; - this.reportEnd = reportEnd; - this.started = new AtomicBoolean(false); - } - - private Tracer(Socket sock, String id, String host, int port, Logger logger) - throws IOException { - this(sock, id, host, port, logger, new BlockingCell(), System.getProperties()); - } - - private Tracer(int listenPort, String id, String host, int port, - Logger logger, BlockingCell reportEnd, Properties props) - throws IOException { - this(new ServerSocket(listenPort).accept(), id, host, port, logger, reportEnd, props); - } - - public Tracer(int listenPort, String id, String host, int port, Logger logger, Properties props) throws IOException { - this(listenPort, id, host, port, logger, new BlockingCell(), props); - } - - public Tracer(String id) throws IOException { - this(DEFAULT_LISTEN_PORT, id, DEFAULT_CONNECT_HOST, DEFAULT_CONNECT_PORT, new AsyncLogger(System.out), new BlockingCell(), System.getProperties()); - } - - public Tracer(String id, Properties props) throws IOException { - this(DEFAULT_LISTEN_PORT, id, DEFAULT_CONNECT_HOST, DEFAULT_CONNECT_PORT, new AsyncLogger(System.out), new BlockingCell(), props); - } - - public void start() { - if (this.started.compareAndSet(false, true)) { - this.logger.start(); - new Thread(this).start(); - } - } - - @Override - public void run() { - try { - byte[] handshake = new byte[8]; - this.iis.readFully(handshake); - this.oos.write(handshake); - - BlockingCell wio = new BlockingCell(); - - new Thread(new DirectionHandler(wio, true, this.iis, this.oos, this.props)) - .start(); - new Thread(new DirectionHandler(wio, false, this.ois, this.ios, this.props)) - .start(); - - waitAndLogException(wio); // either stops => we stop - } catch (Exception e) { - reportAndLogNonNullException(e); - } finally { - try { this.inSock.close(); } catch (Exception e) { logException(e); } - try { this.outSock.close(); } catch (Exception e) { logException(e); } - this.reportEnd.setIfUnset(null); - this.logger.stop(); - } - } - - private void waitAndLogException(BlockingCell bc) throws InterruptedException { - reportAndLogNonNullException(bc.get()); - } - - private void reportAndLogNonNullException(Exception e) { - if (e!=null) { - this.reportEnd.setIfUnset(e); - logException(e); - } - } - - public void log(String message) { - StringBuilder sb = new StringBuilder(); - this.logger.log(sb.append(System.currentTimeMillis()) - .append(this.idLabel) - .append(message) - .toString()); - } - - public void logException(Exception e) { - log("uncaught " + Utility.makeStackTrace(e)); - } - - private class DirectionHandler implements Runnable { - private final BlockingCell waitCell; - private final boolean silentMode; - private final boolean noDecodeFrames; - private final boolean noAssembleFrames; - private final boolean suppressCommandBodies; - private final boolean writeHeartBeats; - private final String directionIndicator; - private final DataInputStream inStream; - private final DataOutputStream outStream; - private final Map commands; - - public DirectionHandler(BlockingCell waitCell, boolean inBound, - DataInputStream inStream, DataOutputStream outStream, Properties props) { - this.waitCell = waitCell; - this.silentMode = getBoolProperty("SILENT_MODE", props); - this.noDecodeFrames = getBoolProperty("NO_DECODE_FRAMES", props); - this.noAssembleFrames = getBoolProperty("NO_ASSEMBLE_FRAMES", props); - this.suppressCommandBodies = getBoolProperty("SUPPRESS_COMMAND_BODIES", props); - this.writeHeartBeats - = ( inBound && !getBoolProperty("WITHHOLD_INBOUND_HEARTBEATS", props)) - || (!inBound && !getBoolProperty("WITHHOLD_OUTBOUND_HEARTBEATS", props)); - this.directionIndicator = (inBound ? " -> " : " <- "); - this.inStream = inStream; - this.outStream = outStream; - this.commands = new HashMap(); - } - - private Frame readFrame() throws IOException { - return Frame.readFrom(this.inStream); - } - - private void report(int channel, Object object) { - StringBuilder sb = new StringBuilder("ch#").append(channel) - .append(this.directionIndicator).append(object); - Tracer.this.log(sb.toString()); - } - - private void reportFrame(Frame frame) throws IOException { - switch (frame.type) { - - case AMQP.FRAME_METHOD: { - report(frame.channel, AMQImpl.readMethodFrom(frame.getInputStream())); - break; - } - - case AMQP.FRAME_HEADER: { - AMQContentHeader contentHeader = AMQImpl - .readContentHeaderFrom(frame.getInputStream()); - long remainingBodyBytes = contentHeader.getBodySize(); - StringBuilder sb = new StringBuilder("Expected body size: ") - .append(remainingBodyBytes).append("; ") - .append(contentHeader); - report(frame.channel, sb); - break; - } - - default: - report(frame.channel, frame); - } - } - - private void doFrame() throws IOException { - Frame frame = readFrame(); - - if (frame != null) { - if (this.silentMode) { - frame.writeTo(this.outStream); - return; - } - if (frame.type == AMQP.FRAME_HEARTBEAT) { - if (this.writeHeartBeats) { - frame.writeTo(this.outStream); - report(frame.channel, frame); - } else { - report(frame.channel, "(withheld) " + frame.toString()); - } - } else { - frame.writeTo(this.outStream); - if (this.noDecodeFrames) { - report(frame.channel, frame); - } else if (this.noAssembleFrames) { - reportFrame(frame); - } else { - AMQCommand cmd = this.commands.get(frame.channel); - if (cmd == null) { - cmd = new AMQCommand(); - this.commands.put(frame.channel, cmd); - } - if (cmd.handleFrame(frame)) { - report(frame.channel, cmd.toString(this.suppressCommandBodies)); - commands.remove(frame.channel); - } - } - } - } - } - - @Override - public void run() { - try { - while (true) { - doFrame(); - } - } catch (Exception e) { - this.waitCell.setIfUnset(e); - } finally { - this.waitCell.setIfUnset(null); - } - } - } - - /** - * Logging strings to an outputStream. Logging may be started and stopped. - */ - public interface Logger { - /** - * Start logging, that is, printing log entries written using - * {@link #log(String)}. Multiple successive starts are equivalent to a - * single start. - * - * @return true if start actually started the logger; - * false otherwise. - */ - boolean start(); - - /** - * Stop logging, that is, stop printing log entries written using - * {@link #log(String)}. Flush preceding writes. The logger can only be - * stopped if started. Multiple successive stops are equivalent to a - * single stop. - * - * @return true if stop actually stopped the logger; - * false otherwise. - */ - boolean stop(); - - /** - * Write msg to the log. This may block, and may block indefinitely if - * the logger is stopped. - * - * @param msg - */ - void log(String msg); - } - - /** - * A {@link Tracer.Logger} designed to print {@link String}s to a designated {@link OutputStream} - * on a private thread. - * {@link String}s are read from a private queue and printed to a buffered {@link PrintStream} - * which is periodically flushed. - * - * When instantiated the private queue is created (an in-memory {@link ArrayBlockingQueue} in this - * implementation) and when {@link #start()}ed the private thread is created and started unless it is - * already present. An {@link AsyncLogger} may be started many times, but only one thread is created. - * - * When {@link #stop()}ed either the number of starts is decremented, or, if this count reaches zero, - * a special element is queued which causes the private thread to end when encountered. - * - * If the private thread is interrupted, the thread will also end, and the count set to zero, - * This will cause subsequent {@link #stop()}s to be ignored, and the next {@link #start()} will create a new thread. - * - * {@link #log(String)} never blocks unless the private queue is full; this may never un-block if the {@link Logger} is stopped. - */ - public static class AsyncLogger implements Logger { - private static final int MIN_FLUSH_INTERVAL = 100; - private static final int ONE_SECOND_INTERVAL = 1000; - private static final int LOG_QUEUE_SIZE = 1024 * 1024; - private static final int BUFFER_SIZE = 10 * 1024 * 1024; - - private final Runnable loggerRunnable; - - private final SafeCounter countStarted; - private volatile Thread loggerThread = null; - - /** - * Simple pair class for queue elements. - * @param type of left item - * @param type of right item - */ - private static class Pr { - private final L left; - private final R right; - public L left() { return this.left; } - public R right() { return this.right; } - public Pr(L left, R right) { this.left=left; this.right=right; } - } - - private enum LogCmd { - STOP, - PRINT - } - - private final BlockingQueue > queue = new ArrayBlockingQueue >( - LOG_QUEUE_SIZE, true); - - public AsyncLogger(OutputStream os) { - this(os, ONE_SECOND_INTERVAL); - } - - /** - * Start/stoppable logger that prints to an {@link OutputStream} with flushes every flushInterval milliseconds. - * @param os OutputStream to print to. - * @param flushInterval in milliseconds, time between flushes. - */ - public AsyncLogger(OutputStream os, int flushInterval) { - if (flushInterval < MIN_FLUSH_INTERVAL) - throw new IllegalArgumentException("Flush interval (" - + flushInterval + "ms) must be positive and at least " - + MIN_FLUSH_INTERVAL + "ms."); - this.countStarted = new SafeCounter(); - - PrintStream printStream = new PrintStream(new BufferedOutputStream( - os, BUFFER_SIZE), false); - this.loggerRunnable = new AsyncLoggerRunnable(printStream, - flushInterval, this.queue); - } - - @Override - public void log(String message) { - if (message != null) { - try { - this.queue.put(new Pr(message, LogCmd.PRINT)); - } catch (InterruptedException ie) { - throw new RuntimeException("Interrupted while logging.", ie); - } - } - } - - @Override - public boolean start() { - if (this.countStarted.testZeroAndIncrement()) { - this.loggerThread = new Thread(this.loggerRunnable); - this.loggerThread.start(); - return true; - } - return false; // meaning already started - } - - @Override - public boolean stop() { - if (this.countStarted.decrementAndTestZero()) { - if (this.loggerThread != null) { - try { - this.queue.put(new Pr(null, LogCmd.STOP)); - } catch (InterruptedException ie) { - this.loggerThread.interrupt(); //try harder - throw new RuntimeException("Interrupted while stopping.", ie); - } - this.loggerThread = null; - } - return true; - } - return false; // meaning already stopped - } - - private class AsyncLoggerRunnable implements Runnable { - private final int flushInterval; - private final PrintStream ps; - private final BlockingQueue > queue; - - public AsyncLoggerRunnable(PrintStream ps, int flushInterval, - BlockingQueue > queue) { - this.flushInterval = flushInterval; - this.ps = ps; - this.queue = queue; - } - - @Override - public void run() { - try { - long timeOfNextFlush = System.currentTimeMillis() - + this.flushInterval; - boolean printedSinceLastFlush = false; - while (true) { - long timeToNextFlush; - while (0 >= (timeToNextFlush = timeOfNextFlush - - System.currentTimeMillis())) { - if (printedSinceLastFlush) { - this.ps.flush(); - printedSinceLastFlush = false; - } - timeOfNextFlush += this.flushInterval; - } - Pr item = this.queue.poll(timeToNextFlush, - TimeUnit.MILLISECONDS); - if (item != null) { - if (item.left() != null) { - this.ps.println(item.left()); - printedSinceLastFlush = true; - } - if (item.right() == LogCmd.STOP) break; - } - } - drainCurrentQueue(); - this.ps.println("Stopped."); - this.ps.flush(); - - } catch (InterruptedException ie) { - AsyncLogger.this.countStarted.reset(); - drainCurrentQueue(); - this.ps.println("Interrupted."); - this.ps.flush(); - } - } - - private void drainCurrentQueue() { - int currentSize = this.queue.size(); - while (currentSize-- > 0) { - Pr item = this.queue.poll(); - if (item != null && item.left() != null) - this.ps.println(item.left()); - } - } - } - } - - private static class SafeCounter { - private final Object countMonitor = new Object(); - private int count; - public SafeCounter() { - this.count = 0; - } - public boolean testZeroAndIncrement() { - synchronized (this.countMonitor) { - int val = this.count; - this.count++; - return (val == 0); - } - } - public boolean decrementAndTestZero() { - synchronized (this.countMonitor) { - if (this.count == 0) return false; - --this.count; - return (0 == this.count); - } - } - public void reset() { - synchronized (this.countMonitor) { - this.count = 0; - } - } - } -} From 278c835a499e0ebe2a67186badb8862121cb1f11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 30 Sep 2016 14:12:02 +0200 Subject: [PATCH 0332/2114] Check Connection availability in NIO loop Fixes #11 --- src/main/java/com/rabbitmq/client/impl/AMQChannel.java | 8 ++++++-- src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java | 5 +++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java index eeebaadf3f..c568214d66 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java @@ -143,8 +143,12 @@ public void handleCompleteInboundCommand(AMQCommand command) throws IOException if (!processAsync(command)) { // The filter decided not to handle/consume the command, // so it must be some reply to an earlier RPC. - nextOutstandingRpc().handleCommand(command); - markRpcFinished(); + RpcContinuation nextOutstandingRpc = nextOutstandingRpc(); + // the outstanding RPC can be null when calling Channel#asyncRpc + if(nextOutstandingRpc != null) { + nextOutstandingRpc.handleCommand(command); + markRpcFinished(); + } } } diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java b/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java index 0a96577bf5..aecafe93ee 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java @@ -134,6 +134,11 @@ public void run() { key.cancel(); continue; } + if(state.getConnection() == null) { + // we're in AMQConnection#start, between the header sending and the FrameHandler#initialize + // let's wait a bit more + continue; + } DataInputStream inputStream = state.inputStream; From b2677a65cdaf935117ac6a688d87ca28603f0110 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 3 Oct 2016 10:40:38 +0200 Subject: [PATCH 0333/2114] Remove runjava scripts There were used for PerfTest and the Tracer. References #196, #204 --- scripts/runjava.bat | 10 ---------- scripts/runjava.sh | 7 ------- 2 files changed, 17 deletions(-) delete mode 100644 scripts/runjava.bat delete mode 100755 scripts/runjava.sh diff --git a/scripts/runjava.bat b/scripts/runjava.bat deleted file mode 100644 index a4a3a919db..0000000000 --- a/scripts/runjava.bat +++ /dev/null @@ -1,10 +0,0 @@ -@echo off - -setlocal EnableDelayedExpansion - -set CP= -for %%F in ("%~dp0"/*.jar) do set CP=!CP!;"%%F" - -java -cp %CP% %1 %2 %3 %4 %5 %6 %7 %8 %9 - -endlocal diff --git a/scripts/runjava.sh b/scripts/runjava.sh deleted file mode 100755 index 74c6aa6ac6..0000000000 --- a/scripts/runjava.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh -RABBIT_JARS= -for d in `dirname $0`/*.jar -do - RABBIT_JARS="$d:$RABBIT_JARS" -done -exec java -cp "$RABBIT_JARS" "$@" From 22bf675a6017cde6dc676d733f71baed13c00453 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 3 Oct 2016 11:35:57 +0200 Subject: [PATCH 0334/2114] Remove TLS handshake looping test This test was initially created to reproduce a transient error during the TLS handshake. It looks like this issue was related to Erlang, introduced in 19.x and fixed in 19.1.1 (http://erlang.org/download/OTP-19.1.1.README). Fixes #11 --- .../client/test/ssl/HandshakeTest.java | 82 ------------------- .../rabbitmq/client/test/ssl/SSLTests.java | 3 +- 2 files changed, 1 insertion(+), 84 deletions(-) delete mode 100644 src/test/java/com/rabbitmq/client/test/ssl/HandshakeTest.java diff --git a/src/test/java/com/rabbitmq/client/test/ssl/HandshakeTest.java b/src/test/java/com/rabbitmq/client/test/ssl/HandshakeTest.java deleted file mode 100644 index 6206fc4cef..0000000000 --- a/src/test/java/com/rabbitmq/client/test/ssl/HandshakeTest.java +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - -package com.rabbitmq.client.test.ssl; - -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.ConnectionFactory; -import org.junit.Test; - -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManagerFactory; -import java.io.FileInputStream; -import java.security.KeyStore; - -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.fail; - -/** - * - */ -public class HandshakeTest { - - @Test - public void handshake() throws Exception { - for (int i = 0; i < 100; i++) { - String keystorePath = System.getProperty("test-keystore.ca"); - assertNotNull(keystorePath); - String keystorePasswd = System.getProperty("test-keystore.password"); - assertNotNull(keystorePasswd); - char[] keystorePassword = keystorePasswd.toCharArray(); - - KeyStore tks = KeyStore.getInstance("JKS"); - tks.load(new FileInputStream(keystorePath), keystorePassword); - - TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); - tmf.init(tks); - - String p12Path = System.getProperty("test-client-cert.path"); - assertNotNull(p12Path); - String p12Passwd = System.getProperty("test-client-cert.password"); - assertNotNull(p12Passwd); - KeyStore ks = KeyStore.getInstance("PKCS12"); - char[] p12Password = p12Passwd.toCharArray(); - ks.load(new FileInputStream(p12Path), p12Password); - - KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); - kmf.init(ks, p12Password); - - SSLContext c = SSLContext.getInstance("TLSv1.2"); - c.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); - - c.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); - ConnectionFactory connectionFactory = new ConnectionFactory(); - connectionFactory.useBlockingIo(); - connectionFactory.useSslProtocol(c); - - Connection connection = null; - try { - connection = connectionFactory.newConnection(); - } catch (Exception e) { - fail("Connection #" + i + " failed with error " + e.getMessage()); - } finally { - if (connection != null) { - connection.abort(); - } - } - } - } -} diff --git a/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java index 7d2b9ee68f..92f5ecdf57 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java @@ -34,8 +34,7 @@ ConnectionFactoryDefaultTlsVersion.class, NioTlsUnverifiedConnection.class, NioTlsVerifiedConnection.class, - NioTlsBadVerifiedConnection.class, - HandshakeTest.class + NioTlsBadVerifiedConnection.class }) public class SSLTests { From d74b125265635246465702c3f7a6f8cda33f310c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 4 Oct 2016 14:02:31 +0200 Subject: [PATCH 0335/2114] Use default ThreadFactory for NIO in test suite The ExecutorService wasn't closed properly in the base test class, there were thus many threads in park state when running the test suite. This could lead to resource exhaustion, especially on MacOS. Fixes #11 --- .../rabbitmq/client/test/BrokerTestCase.java | 32 ++++--------------- .../com/rabbitmq/client/test/JavaNioTest.java | 1 - .../test/functional/ConnectionRecovery.java | 2 -- .../client/test/functional/Metrics.java | 10 ++++-- 4 files changed, 14 insertions(+), 31 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java index 7601423022..bc154bd4c8 100644 --- a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java +++ b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java @@ -17,7 +17,6 @@ package com.rabbitmq.client.test; import com.rabbitmq.client.*; -import com.rabbitmq.client.impl.nio.NioParams; import com.rabbitmq.tools.Host; import org.junit.After; import org.junit.Before; @@ -34,8 +33,6 @@ import java.util.Arrays; import java.util.Map; import java.util.UUID; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import java.util.concurrent.TimeoutException; import static org.junit.Assert.*; @@ -58,17 +55,12 @@ protected void finished(Description description) { protected ConnectionFactory connectionFactory = newConnectionFactory(); - protected ExecutorService nioExecutor = null; - protected ConnectionFactory newConnectionFactory() { ConnectionFactory connectionFactory = new ConnectionFactory(); if(nio()) { connectionFactory.useNio(); - this.nioExecutor = Executors.newFixedThreadPool(5); - connectionFactory.setNioParams(new NioParams().setNioExecutor(this.nioExecutor)); } else { connectionFactory.useBlockingIo(); - this.nioExecutor = null; } return connectionFactory; @@ -91,24 +83,14 @@ protected boolean nio() { @After public void tearDown() throws IOException, TimeoutException { - try { - closeChannel(); - closeConnection(); - - openConnection(); - openChannel(); - releaseResources(); - closeChannel(); - closeConnection(); - } finally { - if(nio()) { - if(this.nioExecutor != null) { - this.nioExecutor.shutdownNow(); - } - } - } - + closeChannel(); + closeConnection(); + openConnection(); + openChannel(); + releaseResources(); + closeChannel(); + closeConnection(); } /** diff --git a/src/test/java/com/rabbitmq/client/test/JavaNioTest.java b/src/test/java/com/rabbitmq/client/test/JavaNioTest.java index 4ed0facc45..33630aef80 100644 --- a/src/test/java/com/rabbitmq/client/test/JavaNioTest.java +++ b/src/test/java/com/rabbitmq/client/test/JavaNioTest.java @@ -55,7 +55,6 @@ public void twoConnectionsWithNioExecutor() throws IOException, TimeoutException ExecutorService nioExecutor = Executors.newFixedThreadPool(5); ConnectionFactory connectionFactory = new ConnectionFactory(); connectionFactory.useNio(); - connectionFactory.setNioParams(new NioParams().setNioExecutor(nioExecutor)); Connection connection1 = null; Connection connection2 = null; try { diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java index 5e382d081c..ac876870c8 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -16,7 +16,6 @@ package com.rabbitmq.client.test.functional; import com.rabbitmq.client.*; -import com.rabbitmq.client.impl.nio.NioParams; import com.rabbitmq.client.impl.recovery.*; import com.rabbitmq.client.test.BrokerTestCase; import com.rabbitmq.tools.Host; @@ -831,7 +830,6 @@ private ConnectionFactory buildConnectionFactoryWithRecoveryEnabled(boolean disa } if(nio()) { cf.useNio(); - cf.setNioParams(new NioParams().setNioExecutor(this.nioExecutor)); } else { cf.useBlockingIo(); } diff --git a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java index 5727443977..e4df60ca1e 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java @@ -16,7 +16,6 @@ package com.rabbitmq.client.test.functional; import com.rabbitmq.client.*; -import com.rabbitmq.client.impl.nio.NioParams; import com.rabbitmq.client.impl.StandardMetricsCollector; import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; import com.rabbitmq.client.test.BrokerTestCase; @@ -268,6 +267,7 @@ private void doMultiThreadedMetrics(ConnectionFactory connectionFactory) throws // create connections Connection [] connections = new Connection[nbConnections]; + ExecutorService executorService = Executors.newFixedThreadPool(nbTasks); try { Channel [] channels = new Channel[nbChannels]; for(int i = 0; i < nbConnections; i++) { @@ -284,7 +284,7 @@ private void doMultiThreadedMetrics(ConnectionFactory connectionFactory) throws sendMessage(channels[random.nextInt(nbChannels)]); } - ExecutorService executorService = Executors.newFixedThreadPool(nbTasks); + List> tasks = new ArrayList>(); for(int i = 0; i < nbTasks; i++) { Channel channelForConsuming = channels[random.nextInt(nbChannels)]; @@ -311,6 +311,8 @@ private void doMultiThreadedMetrics(ConnectionFactory connectionFactory) throws sendMessage(channels[random.nextInt(nbChannels)]); } + executorService.shutdownNow(); + executorService = Executors.newFixedThreadPool(nbTasks); tasks = new ArrayList>(); for(int i = 0; i < nbTasks; i++) { @@ -338,6 +340,8 @@ private void doMultiThreadedMetrics(ConnectionFactory connectionFactory) throws sendMessage(channels[random.nextInt(nbChannels)]); } + executorService.shutdownNow(); + executorService = Executors.newFixedThreadPool(nbTasks); tasks = new ArrayList>(); for(int i = 0; i < nbTasks; i++) { @@ -356,6 +360,7 @@ private void doMultiThreadedMetrics(ConnectionFactory connectionFactory) throws for (Connection connection : connections) { safeClose(connection); } + executorService.shutdownNow(); } } @@ -427,7 +432,6 @@ private ConnectionFactory createConnectionFactory() { ConnectionFactory connectionFactory = new ConnectionFactory(); if(nio()) { connectionFactory.useNio(); - connectionFactory.setNioParams(new NioParams().setNioExecutor(this.nioExecutor)); } else { connectionFactory.useBlockingIo(); } From 6d912ddcd9e879db7a7d005b67d02221a2e2d3bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 5 Oct 2016 08:58:06 +0200 Subject: [PATCH 0336/2114] Handle EOF properly in NIO On MacOS, SocketChannel.read() can return EOF when the SocketChannel is closed. On Linux, it would throw an exception. This could lead to spinning threads on MacOS, because the NIO loop was never closed. Fixes #11 --- .../impl/nio/ByteBufferInputStream.java | 4 ++-- .../rabbitmq/client/impl/nio/NioHelper.java | 21 +++++++++++++++++++ .../com/rabbitmq/client/impl/nio/NioLoop.java | 7 +++++++ .../nio/SocketChannelFrameHandlerState.java | 6 +++--- .../nio/SslEngineByteBufferInputStream.java | 2 +- .../client/impl/nio/SslEngineHelper.java | 2 +- 6 files changed, 35 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/rabbitmq/client/impl/nio/NioHelper.java diff --git a/src/main/java/com/rabbitmq/client/impl/nio/ByteBufferInputStream.java b/src/main/java/com/rabbitmq/client/impl/nio/ByteBufferInputStream.java index 2469f6e965..97c739ca90 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/ByteBufferInputStream.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/ByteBufferInputStream.java @@ -47,7 +47,7 @@ private int readFromBuffer(ByteBuffer buffer) { private static void readFromNetworkIfNecessary(ReadableByteChannel channel, ByteBuffer buffer) throws IOException { if(!buffer.hasRemaining()) { buffer.clear(); - int read = channel.read(buffer); + int read = NioHelper.read(channel, buffer); if(read <= 0) { int attempt = 0; while(attempt < 3) { @@ -56,7 +56,7 @@ private static void readFromNetworkIfNecessary(ReadableByteChannel channel, Byte } catch (InterruptedException e) { // ignore } - read = channel.read(buffer); + read = NioHelper.read(channel, buffer); if(read > 0) { break; } diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioHelper.java b/src/main/java/com/rabbitmq/client/impl/nio/NioHelper.java new file mode 100644 index 0000000000..3372af8a1f --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioHelper.java @@ -0,0 +1,21 @@ +package com.rabbitmq.client.impl.nio; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.SocketChannel; + +/** + * Created by acogoluegnes on 04/10/2016. + */ +public class NioHelper { + + static int read(ReadableByteChannel channel, ByteBuffer buffer) throws IOException { + int read = channel.read(buffer); + if(read < 0) { + throw new IOException("Channel has reached EOF"); + } + return read; + } + +} diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java b/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java index aecafe93ee..cbc387fd33 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java @@ -22,6 +22,7 @@ import java.io.DataInputStream; import java.io.DataOutputStream; +import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; @@ -255,6 +256,12 @@ public void run() { protected void handleIoError(SocketChannelFrameHandlerState state, Throwable ex) { if (needToDispatchIoError(state)) { dispatchIoErrorToConnection(state, ex); + } else { + try { + state.close(); + } catch (IOException e) { + + } } } diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java index 291ae4c62b..73c444e848 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java @@ -186,7 +186,7 @@ void prepareForReadSequence() throws IOException { cipherIn.flip(); plainIn.flip(); } else { - channel.read(plainIn); + NioHelper.read(channel, plainIn); plainIn.flip(); } } @@ -196,7 +196,7 @@ boolean continueReading() throws IOException { if (!plainIn.hasRemaining() && !cipherIn.hasRemaining()) { // need to try to read something cipherIn.clear(); - int bytesRead = channel.read(cipherIn); + int bytesRead = NioHelper.read(channel, cipherIn); if (bytesRead <= 0) { return false; } else { @@ -209,7 +209,7 @@ boolean continueReading() throws IOException { } else { if (!plainIn.hasRemaining()) { plainIn.clear(); - channel.read(plainIn); + NioHelper.read(channel, plainIn); plainIn.flip(); } return plainIn.hasRemaining(); diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferInputStream.java b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferInputStream.java index 7048463ca8..60a60490b4 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferInputStream.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferInputStream.java @@ -65,7 +65,7 @@ public int read() throws IOException { cipherIn.clear(); } - int bytesRead = channel.read(cipherIn); + int bytesRead = NioHelper.read(channel, cipherIn); if (bytesRead > 0) { cipherIn.flip(); } else { diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java index 8b293eee6b..8e0b726ac3 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java @@ -87,7 +87,7 @@ private static SSLEngineResult.HandshakeStatus unwrap(ByteBuffer cipherIn, ByteB throw new SSLException("Buffer overflow during handshake"); case BUFFER_UNDERFLOW: cipherIn.compact(); - channel.read(cipherIn); + NioHelper.read(channel, cipherIn); cipherIn.flip(); break; case CLOSED: From b652b006bf3f27562b27ec7ed533ba569b322fd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 5 Oct 2016 10:44:55 +0200 Subject: [PATCH 0337/2114] Add use-nio profile for Maven test suite The default is to use blocking IO. Fixes #11 --- pom.xml | 22 +++++++++++++ .../rabbitmq/client/ConnectionFactory.java | 2 +- .../rabbitmq/client/impl/nio/NioHelper.java | 18 +++++++++-- .../client/test/AMQConnectionTest.java | 10 +++--- .../com/rabbitmq/client/test/AmqpUriTest.java | 4 +-- .../client/test/BrokenFramesTest.java | 2 +- .../rabbitmq/client/test/BrokerTestCase.java | 17 +++------- .../test/ChannelNumberAllocationTests.java | 2 +- .../rabbitmq/client/test/CloseInMainLoop.java | 2 +- .../client/test/SharedThreadPoolTest.java | 2 +- ...VerifiedConnection.java => TestUtils.java} | 23 +++++++++----- .../test/functional/ConnectionOpen.java | 7 +++-- .../test/functional/ConnectionRecovery.java | 8 ++--- .../test/functional/ExceptionHandling.java | 5 +-- .../test/functional/ExchangeDeclare.java | 3 +- .../client/test/functional/FrameMax.java | 22 ++++++++++++- .../client/test/functional/Metrics.java | 8 ++--- .../test/functional/SaslMechanisms.java | 3 +- .../test/functional/UnexpectedFrames.java | 11 +++++++ .../client/test/performance/QosScaling.java | 4 +-- .../client/test/server/BlockedConnection.java | 3 +- .../test/server/ChannelLimitNegotiation.java | 7 +++-- .../client/test/server/LoopbackUsers.java | 3 +- .../client/test/server/Permissions.java | 7 +++-- .../test/ssl/BadVerifiedConnection.java | 31 ++++++------------- .../ConnectionFactoryDefaultTlsVersion.java | 11 +++---- .../test/ssl/NioTlsUnverifiedConnection.java | 5 --- .../test/ssl/NioTlsVerifiedConnection.java | 27 ---------------- .../rabbitmq/client/test/ssl/SSLTests.java | 4 +-- .../client/test/ssl/UnverifiedConnection.java | 14 +++------ .../client/test/ssl/VerifiedConnection.java | 8 ++--- 31 files changed, 152 insertions(+), 143 deletions(-) rename src/test/java/com/rabbitmq/client/test/{ssl/NioTlsBadVerifiedConnection.java => TestUtils.java} (59%) delete mode 100644 src/test/java/com/rabbitmq/client/test/ssl/NioTlsVerifiedConnection.java diff --git a/pom.xml b/pom.xml index c4958b1789..e7f96e5c22 100644 --- a/pom.xml +++ b/pom.xml @@ -410,6 +410,28 @@ + + + use-nio + + + + org.apache.maven.plugins + maven-failsafe-plugin + 2.19.1 + + + true + + + + + + + diff --git a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java index eeebaadf3f..c568214d66 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java @@ -143,8 +143,12 @@ public void handleCompleteInboundCommand(AMQCommand command) throws IOException if (!processAsync(command)) { // The filter decided not to handle/consume the command, // so it must be some reply to an earlier RPC. - nextOutstandingRpc().handleCommand(command); - markRpcFinished(); + RpcContinuation nextOutstandingRpc = nextOutstandingRpc(); + // the outstanding RPC can be null when calling Channel#asyncRpc + if(nextOutstandingRpc != null) { + nextOutstandingRpc.handleCommand(command); + markRpcFinished(); + } } } From ccff73abf8cb52f20c83e4ce2c94eb26da932348 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 11 Oct 2016 12:12:55 +0200 Subject: [PATCH 0340/2114] Set log level to error in test suite --- src/test/resources/logback-test.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml index 4bd2e37606..97e9b47c42 100644 --- a/src/test/resources/logback-test.xml +++ b/src/test/resources/logback-test.xml @@ -5,7 +5,7 @@ - + \ No newline at end of file From eb95e5114f2576b7a8d1e20be8d8ad93e77997f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 12 Oct 2016 10:31:44 +0200 Subject: [PATCH 0341/2114] Add Bintray Milestones Maven repo --- pom.xml | 101 +++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 89 insertions(+), 12 deletions(-) diff --git a/pom.xml b/pom.xml index a84e34c273..d6e58f0b15 100644 --- a/pom.xml +++ b/pom.xml @@ -98,6 +98,9 @@ hare@localhost 5673 ${project.build.directory}/test-classes/${test-broker.B.nodename} + + + 6026DFCA @@ -482,9 +485,95 @@ + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.7 + true + + ossrh + https://oss.sonatype.org/ + false + + + + + + + milestone + + + + org.apache.maven.plugins + maven-source-plugin + 3.0.1 + + + + jar + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.10.4 + + ${javadoc.opts} + + + + + jar + + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.6 + + + sign-artifacts + package + + sign + + + ${gpg.keyname} + + + + + + + + + bintray-rabbitmq-maven-milestones + rabbitmq-maven-milestones + https://api.bintray.com/maven/rabbitmq/maven-milestones/java-client/;publish=1 + + + + @@ -739,18 +828,6 @@ - - org.sonatype.plugins - nexus-staging-maven-plugin - 1.6.7 - true - - ossrh - https://oss.sonatype.org/ - false - - - org.codehaus.mojo versions-maven-plugin From bbde580e0feee655f8847037609556b5d28eef80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 12 Oct 2016 10:34:51 +0200 Subject: [PATCH 0342/2114] Set POM version to 4.0.0.M1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d6e58f0b15..24cf7612fc 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.rabbitmq amqp-client - 4.0.0-SNAPSHOT + 4.0.0.M1 jar RabbitMQ Java Client From 67d794b1009f2430d44c31b895a5082d8b6183b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 12 Oct 2016 10:38:29 +0200 Subject: [PATCH 0343/2114] Set POM version to 4.0.0-SNAPSHOT --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 24cf7612fc..d6e58f0b15 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.rabbitmq amqp-client - 4.0.0.M1 + 4.0.0-SNAPSHOT jar RabbitMQ Java Client From cc8a3a4a34520f404d14cb28f519bedfd74eb1e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 13 Oct 2016 10:04:39 +0200 Subject: [PATCH 0344/2114] Set shutdown executor properly with auto-recovery References #194 --- src/main/java/com/rabbitmq/client/impl/AMQConnection.java | 8 ++++++-- .../client/impl/recovery/RecoveryAwareAMQConnection.java | 5 ++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index af0453b62e..aeb5e35884 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -397,11 +397,15 @@ public void start() protected ChannelManager instantiateChannelManager(int channelMax, ThreadFactory threadFactory) { ChannelManager result = new ChannelManager(this._workService, channelMax, threadFactory, this.metricsCollector); - result.setShutdownExecutor(this.shutdownExecutor); - result.setChannelShutdownTimeout((int) ((requestedHeartbeat * CHANNEL_SHUTDOWN_TIMEOUT_MULTIPLIER) * 1000)); + configureChannelManager(result); return result; } + protected void configureChannelManager(ChannelManager channelManager) { + channelManager.setShutdownExecutor(this.shutdownExecutor); + channelManager.setChannelShutdownTimeout((int) ((requestedHeartbeat * CHANNEL_SHUTDOWN_TIMEOUT_MULTIPLIER) * 1000)); + } + /** * Package private API, allows for easier testing. */ diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnection.java index 92037bc089..b50e7027e5 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnection.java @@ -38,6 +38,9 @@ public RecoveryAwareAMQConnection(ConnectionParams params, FrameHandler handler) @Override protected RecoveryAwareChannelManager instantiateChannelManager(int channelMax, ThreadFactory threadFactory) { - return new RecoveryAwareChannelManager(super._workService, channelMax, threadFactory, this.metricsCollector); + RecoveryAwareChannelManager recoveryAwareChannelManager = new RecoveryAwareChannelManager(super._workService, channelMax, threadFactory, + this.metricsCollector); + configureChannelManager(recoveryAwareChannelManager); + return recoveryAwareChannelManager; } } From f21be092827acd831de0a72aa21485e538bafff3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 14 Oct 2016 09:33:46 +0200 Subject: [PATCH 0345/2114] Add instructions to deploy milestone --- pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pom.xml b/pom.xml index d6e58f0b15..8f598b2a48 100644 --- a/pom.xml +++ b/pom.xml @@ -513,6 +513,11 @@ [username] [api-key] + + Checkout the correct tag and launch: + + mvn clean deploy -P milestone + --> milestone From 1693ddc9aeb9ff87df8a8280b686f5d229cb20c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 14 Oct 2016 09:34:48 +0200 Subject: [PATCH 0346/2114] Set POM version to 4.0.0.M2 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8f598b2a48..d3967295f5 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.rabbitmq amqp-client - 4.0.0-SNAPSHOT + 4.0.0.M2 jar RabbitMQ Java Client From 485e33551a50c8f990d5e052671319c741307c4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 14 Oct 2016 09:36:56 +0200 Subject: [PATCH 0347/2114] Set POM version to 4.0.0-SNAPSHOT --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d3967295f5..8f598b2a48 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.rabbitmq amqp-client - 4.0.0.M2 + 4.0.0-SNAPSHOT jar RabbitMQ Java Client From c960060c243e967654af12556c7182e930890f24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 14 Oct 2016 10:06:09 +0200 Subject: [PATCH 0348/2114] Fix instructions to deploy milestone version No need to launch the test suite. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8f598b2a48..a93738c78b 100644 --- a/pom.xml +++ b/pom.xml @@ -516,7 +516,7 @@ Checkout the correct tag and launch: - mvn clean deploy -P milestone + mvn clean deploy -P milestone -DskipTests --> From 7685930e045a24f0af932de40318f9aa0aa91366 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 18 Oct 2016 09:37:17 +0200 Subject: [PATCH 0349/2114] Add configuration for deployment on Sonatype OSSRH --- pom.xml | 56 ++++++++++++++++++++++++++++++-------------------------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/pom.xml b/pom.xml index a93738c78b..4e16caba16 100644 --- a/pom.xml +++ b/pom.xml @@ -101,6 +101,7 @@ 6026DFCA + 1.6.4 @@ -437,10 +438,23 @@ - release + ossrh-release @@ -478,28 +492,28 @@ sign-artifacts - verify + package sign + + ${gpg.keyname} + - - - org.sonatype.plugins - nexus-staging-maven-plugin - 1.6.7 - true - - ossrh - https://oss.sonatype.org/ - false - - - + + + ossrh + https://oss.sonatype.org/content/repositories/snapshots + + + ossrh + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + + + assemblies + + + + maven-assembly-plugin + 2.6 + + rabbitmq-${project.build.finalName} + + src/assembly/dist-bin.xml + src/assembly/dist-src.xml + + + + + + create-archive + package + + single + + + + + + + + diff --git a/src/assembly/dist-bin.xml b/src/assembly/dist-bin.xml new file mode 100644 index 0000000000..77042d1d23 --- /dev/null +++ b/src/assembly/dist-bin.xml @@ -0,0 +1,25 @@ + + bin + + tar.gz + zip + + + + true + false + test + + + + + ${project.basedir} + + + LICENSE* + + + + \ No newline at end of file diff --git a/src/assembly/dist-src.xml b/src/assembly/dist-src.xml new file mode 100644 index 0000000000..3b4ebda5ed --- /dev/null +++ b/src/assembly/dist-src.xml @@ -0,0 +1,31 @@ + + src + + tar.gz + zip + + + + ${project.basedir} + + README* + LICENSE* + *.md + codegen.py + Makefile + pom.xml + + true + + + ${project.basedir}/src + true + + + ${project.basedir}/doc + true + + + \ No newline at end of file From e82827a0b734389f713895d0142f2230c084ea84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 24 Oct 2016 15:30:41 +0200 Subject: [PATCH 0356/2114] Add Bintray release repository --- pom.xml | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 55ea64ebd3..686cca5afa 100644 --- a/pom.xml +++ b/pom.xml @@ -516,6 +516,83 @@ + + + bintray-release + + + + org.apache.maven.plugins + maven-source-plugin + 3.0.1 + + + + jar + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.10.4 + + ${javadoc.opts} + + + + + jar + + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.6 + + + sign-artifacts + package + + sign + + + ${gpg.keyname} + + + + + + + + + bintray-rabbitmq-maven + rabbitmq-maven + https://api.bintray.com/maven/rabbitmq/maven/java-client/;publish=1 + + + + ossrh-release @@ -519,20 +506,7 @@ + --> bintray-release @@ -596,20 +570,7 @@ + --> milestone @@ -670,39 +631,6 @@ - - - assemblies - - - - maven-assembly-plugin - 2.6 - - rabbitmq-${project.build.finalName} - - src/assembly/dist-bin.xml - src/assembly/dist-src.xml - - - - - - create-archive - package - - single - - - - - - - - diff --git a/src/assembly/dist-bin.xml b/src/assembly/dist-bin.xml deleted file mode 100644 index 77042d1d23..0000000000 --- a/src/assembly/dist-bin.xml +++ /dev/null @@ -1,25 +0,0 @@ - - bin - - tar.gz - zip - - - - true - false - test - - - - - ${project.basedir} - - - LICENSE* - - - - \ No newline at end of file diff --git a/src/assembly/dist-src.xml b/src/assembly/dist-src.xml deleted file mode 100644 index 3b4ebda5ed..0000000000 --- a/src/assembly/dist-src.xml +++ /dev/null @@ -1,31 +0,0 @@ - - src - - tar.gz - zip - - - - ${project.basedir} - - README* - LICENSE* - *.md - codegen.py - Makefile - pom.xml - - true - - - ${project.basedir}/src - true - - - ${project.basedir}/doc - true - - - \ No newline at end of file From d58e52e2ae976ac543ad0395f79d43fbf1452d12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 26 Oct 2016 09:53:33 +0200 Subject: [PATCH 0358/2114] Add script to deploy Javadoc --- deploy-javadoc.sh | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100755 deploy-javadoc.sh diff --git a/deploy-javadoc.sh b/deploy-javadoc.sh new file mode 100755 index 0000000000..f7c16a4488 --- /dev/null +++ b/deploy-javadoc.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash + +DEPLOY_PATH=/home/rabbitmq/extras/releases/rabbitmq-java-client/current-javadoc + +# RSync user/host to deploy to. Mandatory. +DEPLOY_USERHOST= + + +# Imitate make-style variable settings as arguments +while [[ $# -gt 0 ]] ; do + declare "$1" + shift +done + +mandatory_vars="DEPLOY_USERHOST" +optional_vars="DEPLOY_PATH" + +function die () { + echo "$@" 2>&1 + exit 1 +} + +# Check mandatory settings +for v in $mandatory_vars ; do + [[ -n "${!v}" ]] || die "$v not set" +done + +echo "Settings:" +for v in $mandatory_vars $optional_vars ; do + echo "${v}=${!v}" +done + +set -e -x + +mvn -q clean javadoc:javadoc -Dmaven.javadoc.failOnError=false + +ssh $DEPLOY_USERHOST \ + "rm -rf $DEPLOY_PATH; \ + mkdir -p $DEPLOY_PATH" + +rsync -rpl target/site/apidocs/ $DEPLOY_USERHOST:$DEPLOY_PATH + + From 540f1cd1e6d07feeb3def3f4b01ba8f95e4d5f32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 26 Oct 2016 11:09:41 +0200 Subject: [PATCH 0359/2114] Tweak Javadoc deployment rsync --- deploy-javadoc.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy-javadoc.sh b/deploy-javadoc.sh index f7c16a4488..9c3444592f 100755 --- a/deploy-javadoc.sh +++ b/deploy-javadoc.sh @@ -38,6 +38,6 @@ ssh $DEPLOY_USERHOST \ "rm -rf $DEPLOY_PATH; \ mkdir -p $DEPLOY_PATH" -rsync -rpl target/site/apidocs/ $DEPLOY_USERHOST:$DEPLOY_PATH +rsync -rpl --exclude '*.sh' target/site/apidocs/ $DEPLOY_USERHOST:$DEPLOY_PATH From c29b7cab27cbac336ffc186f484f8b9ec7c61587 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 26 Oct 2016 17:01:33 +0200 Subject: [PATCH 0360/2114] Add Maven release plugin --- pom.xml | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 7d84792be6..dcb1f73982 100644 --- a/pom.xml +++ b/pom.xml @@ -40,8 +40,9 @@ - https://github.com/rabbitmq/rabbitmq-java-client.git - scm:git:https://github.com/rabbitmq/rabbitmq-java-client.git + https://github.com/rabbitmq/rabbitmq-java-client + scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git + scm:git:git@github.com/rabbitmq/rabbitmq-java-client.git @@ -890,6 +891,16 @@ versions-maven-plugin 2.3 + + + org.apache.maven.plugins + maven-release-plugin + 2.5.3 + + v@{project.version} + + + From 2c2fab0ede5d28b21098a941e3fcfa241b3a0338 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 27 Oct 2016 10:07:59 +0200 Subject: [PATCH 0361/2114] [maven-release-plugin] prepare release v4.0.0.RC1 --- pom.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index dcb1f73982..aae53b9205 100644 --- a/pom.xml +++ b/pom.xml @@ -1,11 +1,10 @@ - + 4.0.0 com.rabbitmq amqp-client - 4.0.0-SNAPSHOT + 4.0.0.RC1 jar RabbitMQ Java Client @@ -43,6 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com/rabbitmq/rabbitmq-java-client.git + v4.0.0.RC1 @@ -300,7 +300,7 @@ org.codehaus.mojo From dc74cdc3fa2e4ab204ebcb974ebbd7ea52a0dc61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 27 Oct 2016 10:14:12 +0200 Subject: [PATCH 0362/2114] Correct repo url --- pom.xml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index aae53b9205..927f81df92 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.0.0.RC1 + 4.0.0-SNAPSHOT jar RabbitMQ Java Client @@ -41,8 +41,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git - scm:git:git@github.com/rabbitmq/rabbitmq-java-client.git - v4.0.0.RC1 + scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git From a9f7c6b7b3ea9c818cfe8f21ffd5e433838dcaa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 27 Oct 2016 10:16:49 +0200 Subject: [PATCH 0363/2114] [maven-release-plugin] prepare release v4.0.0.RC1 --- pom.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 927f81df92..36727bf14e 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.0.0-SNAPSHOT + 4.0.0.RC1 jar RabbitMQ Java Client @@ -42,6 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git + v4.0.0.RC1 From 0bf741ecdd4e619f1bd141c8f9ac5c95455e32d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 27 Oct 2016 10:32:07 +0200 Subject: [PATCH 0364/2114] Set POM version to 4.0.0-SNAPSHOT --- pom.xml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 36727bf14e..9c5ea8d293 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.0.0.RC1 + 4.0.0-SNAPSHOT jar RabbitMQ Java Client @@ -40,9 +40,8 @@ https://github.com/rabbitmq/rabbitmq-java-client - scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git - scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git - v4.0.0.RC1 + scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git + scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git From 25a83885e22ab35ee5baccd49ef99e577a5ddb05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 31 Oct 2016 18:28:49 +0100 Subject: [PATCH 0365/2114] Add Maven Central badge --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 82a4e899fc..36d77bb39f 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.rabbitmq/amqp-client/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.rabbitmq/amqp-client) + ## RabbitMQ Java Client This repository contains source code of the [RabbitMQ Java client](http://www.rabbitmq.com/api-guide.html). From a29a31c8fd82360d984e3d1f4781c8f24a80a36c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 31 Oct 2016 18:27:22 +0000 Subject: [PATCH 0366/2114] Use correct URL in SCM connection tag --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9c5ea8d293..6566e97483 100644 --- a/pom.xml +++ b/pom.xml @@ -40,7 +40,7 @@ https://github.com/rabbitmq/rabbitmq-java-client - scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git + scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git From 46be6856e145c52dfdcb46c057132e45f9d936a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 31 Oct 2016 18:36:29 +0000 Subject: [PATCH 0367/2114] Add release repositories --- pom.xml | 157 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 152 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index a80a532ec9..c53fd51e37 100644 --- a/pom.xml +++ b/pom.xml @@ -40,8 +40,9 @@ - https://github.com/rabbitmq/rabbitmq-java-client.git - scm:git:https://github.com/rabbitmq/rabbitmq-java-client.git + https://github.com/rabbitmq/rabbitmq-java-client + scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git + scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git @@ -90,6 +91,10 @@ hare@localhost 5673 ${project.build.directory}/test-classes/${test-broker.B.nodename} + + + 6026DFCA + 1.6.4 @@ -404,10 +409,141 @@ - release + ossrh-release + + + + org.apache.maven.plugins + maven-source-plugin + 3.0.1 + + + + jar + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.10.4 + + ${javadoc.opts} + + + + + jar + + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.6 + + + sign-artifacts + package + + sign + + + ${gpg.keyname} + + + + + + + + + ossrh + https://oss.sonatype.org/content/repositories/snapshots + + + ossrh + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + + + + + + + bintray-release + + + + org.apache.maven.plugins + maven-source-plugin + 3.0.1 + + + + jar + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.10.4 + + ${javadoc.opts} + + + + + jar + + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.6 + + + sign-artifacts + package + + sign + + + ${gpg.keyname} + + + + + + + + + bintray-rabbitmq-maven + rabbitmq-maven + https://api.bintray.com/maven/rabbitmq/maven/java-client/;publish=1 + + + + + + + milestone @@ -445,16 +581,27 @@ sign-artifacts - verify + package sign + + ${gpg.keyname} + + + + bintray-rabbitmq-maven-milestones + rabbitmq-maven-milestones + https://api.bintray.com/maven/rabbitmq/maven-milestones/java-client/;publish=1 + + + From 288c1c1a9bd1da02b2dcca669a789882ffc0655e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 3 Nov 2016 12:07:58 +0000 Subject: [PATCH 0368/2114] Add Nexus staging plugin in appropriate profile --- pom.xml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/pom.xml b/pom.xml index c53fd51e37..b450907728 100644 --- a/pom.xml +++ b/pom.xml @@ -415,6 +415,25 @@ ossrh-release + + org.sonatype.plugins + nexus-staging-maven-plugin + ${nexus-staging-maven-plugin.version} + + + default-deploy + deploy + + deploy + + + + + ossrh + https://oss.sonatype.org/ + false + + org.apache.maven.plugins maven-source-plugin From 302e10d02451238165259a6018913f213f6f5131 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 7 Nov 2016 09:27:46 +0100 Subject: [PATCH 0369/2114] Add warning on removal of deprecated methods --- src/main/java/com/rabbitmq/client/Channel.java | 4 ++++ src/main/java/com/rabbitmq/client/FlowListener.java | 3 +++ 2 files changed, 7 insertions(+) diff --git a/src/main/java/com/rabbitmq/client/Channel.java b/src/main/java/com/rabbitmq/client/Channel.java index 90149873c7..88106d0a31 100644 --- a/src/main/java/com/rabbitmq/client/Channel.java +++ b/src/main/java/com/rabbitmq/client/Channel.java @@ -86,6 +86,7 @@ public interface Channel extends ShutdownNotifier { /** * Deprecated, superseded by TCP back pressure. + * Will be removed in next major release. * @deprecated * @see Resource-driven alarms */ @@ -130,6 +131,7 @@ public interface Channel extends ShutdownNotifier { /** * Add a {@link FlowListener}. * Deprecated, superseded by TCP back pressure. + * Will be removed in next major release. * @deprecated * @see Resource-driven alarms * @param listener the listener to add @@ -139,6 +141,7 @@ public interface Channel extends ShutdownNotifier { /** * Remove a {@link FlowListener}. * Deprecated, superseded by TCP back pressure. + * Will be removed in next major release. * @deprecated * @see Resource-driven alarms * @param listener the listener to remove @@ -150,6 +153,7 @@ public interface Channel extends ShutdownNotifier { /** * Remove all {@link FlowListener}s. * Deprecated, superseded by TCP back pressure. + * Will be removed in next major release. * @deprecated * @see Resource-driven alarms */ diff --git a/src/main/java/com/rabbitmq/client/FlowListener.java b/src/main/java/com/rabbitmq/client/FlowListener.java index de6461ebc2..4f6ac1b3e8 100644 --- a/src/main/java/com/rabbitmq/client/FlowListener.java +++ b/src/main/java/com/rabbitmq/client/FlowListener.java @@ -21,6 +21,9 @@ /** * Implement this interface in order to be notified of Channel.Flow * events. + * Deprecated, superseded by TCP back pressure. + * Will be removed in next major release. + * @deprecated */ public interface FlowListener { void handleFlow(boolean active) From 7b16a33abf6e4c3c5c799bcdc869b653b14b3542 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 7 Nov 2016 10:42:24 +0100 Subject: [PATCH 0370/2114] Deprecate QueueingConsumer --- src/main/java/com/rabbitmq/client/QueueingConsumer.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/com/rabbitmq/client/QueueingConsumer.java b/src/main/java/com/rabbitmq/client/QueueingConsumer.java index be0b9442d0..44d061ecc5 100644 --- a/src/main/java/com/rabbitmq/client/QueueingConsumer.java +++ b/src/main/java/com/rabbitmq/client/QueueingConsumer.java @@ -28,6 +28,9 @@ * Convenience class: an implementation of {@link Consumer} with * straightforward blocking semantics. * + * Deprecated in favor of {@link Consumer} (see below for background). + * Will be removed in next major release. + * * The general pattern for using QueueingConsumer is as follows: * *
@@ -83,6 +86,8 @@
  * As such, it is now safe to implement Consumer directly or
  * to extend DefaultConsumer and QueueingConsumer
  * is a lot less relevant.

+ * + * @deprecated */ public class QueueingConsumer extends DefaultConsumer { private final BlockingQueue _queue; From 35bdc03d89fa3137cf7aced355b8fa37730705ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 7 Nov 2016 10:54:52 +0100 Subject: [PATCH 0371/2114] Favor DefaultConsumer over QueueingConsumer --- src/main/java/com/rabbitmq/client/QueueingConsumer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/QueueingConsumer.java b/src/main/java/com/rabbitmq/client/QueueingConsumer.java index 44d061ecc5..0a67a8b322 100644 --- a/src/main/java/com/rabbitmq/client/QueueingConsumer.java +++ b/src/main/java/com/rabbitmq/client/QueueingConsumer.java @@ -28,7 +28,7 @@ * Convenience class: an implementation of {@link Consumer} with * straightforward blocking semantics. * - * Deprecated in favor of {@link Consumer} (see below for background). + * Deprecated in favor of {@link DefaultConsumer} (see below for background). * Will be removed in next major release. * * The general pattern for using QueueingConsumer is as follows: @@ -87,7 +87,7 @@ * to extend DefaultConsumer and QueueingConsumer * is a lot less relevant.

* - * @deprecated + * @deprecated */ public class QueueingConsumer extends DefaultConsumer { private final BlockingQueue _queue; From ed694209205027231474cb7e40ef37eead59b606 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 10 Nov 2016 18:06:31 +0100 Subject: [PATCH 0372/2114] Enable automatic recovery by default (WIP) Fixes #210 --- .../rabbitmq/client/ConnectionFactory.java | 2 +- .../impl/recovery/RecoveryAwareChannelN.java | 8 +++-- .../client/test/SharedThreadPoolTest.java | 1 + .../client/test/functional/Heartbeat.java | 13 ++++---- .../test/functional/UnexpectedFrames.java | 19 ++++++------ .../test/server/ChannelLimitNegotiation.java | 3 +- .../client/test/server/Permissions.java | 30 +++++++------------ 7 files changed, 35 insertions(+), 41 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index d52a824e81..0788d75714 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -100,7 +100,7 @@ public class ConnectionFactory implements Cloneable { private SocketConfigurator socketConf = new DefaultSocketConfigurator(); private ExceptionHandler exceptionHandler = new DefaultExceptionHandler(); - private boolean automaticRecovery = false; + private boolean automaticRecovery = true; private boolean topologyRecovery = true; // long is used to make sure the users can use both ints diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java index d23c1231da..353578da6a 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java @@ -82,16 +82,20 @@ private AMQImpl.Basic.Deliver offsetDeliveryTag(AMQImpl.Basic.Deliver method) { @Override public void basicAck(long deliveryTag, boolean multiple) throws IOException { + // FIXME no check if deliveryTag = 0 (ack all) long realTag = deliveryTag - activeDeliveryTagOffset; - if (realTag > 0) { + // 0 tag means ack all + if (realTag >= 0) { super.basicAck(realTag, multiple); } } @Override public void basicNack(long deliveryTag, boolean multiple, boolean requeue) throws IOException { + // FIXME no check if deliveryTag = 0 (nack all) long realTag = deliveryTag - activeDeliveryTagOffset; - if (realTag > 0) { + // 0 tag means nack all + if (realTag >= 0) { super.basicNack(realTag, multiple, requeue); } } diff --git a/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java b/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java index 082035dabe..ceb26b264a 100644 --- a/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java +++ b/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java @@ -31,6 +31,7 @@ public class SharedThreadPoolTest extends BrokerTestCase { @Test public void willShutDownExecutor() throws IOException, TimeoutException { ConnectionFactory cf = TestUtils.connectionFactory(); + cf.setAutomaticRecoveryEnabled(false); ExecutorService executor = Executors.newFixedThreadPool(8); cf.setSharedExecutor(executor); diff --git a/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java b/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java index 8ea14bce25..fe0f904103 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java @@ -16,16 +16,13 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; +import com.rabbitmq.client.test.BrokerTestCase; +import org.junit.Test; import java.io.IOException; -import org.junit.Test; - -import com.rabbitmq.client.impl.AMQConnection; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.*; public class Heartbeat extends BrokerTestCase { @@ -41,7 +38,7 @@ public Heartbeat() assertEquals(1, connection.getHeartbeat()); Thread.sleep(3100); assertTrue(connection.isOpen()); - ((AMQConnection)connection).setHeartbeat(0); + ((AutorecoveringConnection)connection).getDelegate().setHeartbeat(0); assertEquals(0, connection.getHeartbeat()); Thread.sleep(3100); assertFalse(connection.isOpen()); diff --git a/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java b/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java index b95cd1350a..0ab8013969 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java +++ b/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java @@ -15,19 +15,18 @@ package com.rabbitmq.client.test.functional; -import java.io.IOException; -import java.net.Socket; - -import javax.net.SocketFactory; - -import com.rabbitmq.client.impl.*; -import com.rabbitmq.client.test.TestUtils; -import org.junit.Test; - import com.rabbitmq.client.AMQP; import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.DefaultSocketConfigurator; +import com.rabbitmq.client.impl.*; +import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; import com.rabbitmq.client.test.BrokerTestCase; +import com.rabbitmq.client.test.TestUtils; +import org.junit.Test; + +import javax.net.SocketFactory; +import java.io.IOException; +import java.net.Socket; /** * Test that the server correctly handles us when we send it bad frames @@ -177,7 +176,7 @@ public Frame confuse(Frame frame) { } private void expectError(int error, Confuser confuser) throws IOException { - ((ConfusedFrameHandler)((AMQConnection)connection).getFrameHandler()). + ((ConfusedFrameHandler)((AutorecoveringConnection)connection).getDelegate().getFrameHandler()). confuser = confuser; //NB: the frame confuser relies on the encoding of the diff --git a/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java b/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java index 3bf0a813d9..6111e2660e 100644 --- a/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java +++ b/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java @@ -25,6 +25,7 @@ import javax.net.SocketFactory; +import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; import com.rabbitmq.client.test.TestUtils; import org.junit.Test; @@ -103,7 +104,7 @@ protected int negotiateChannelMax(int requestedChannelMax, int serverMax) { assertNull(conn.createChannel(n + 1)); // Construct a channel directly - final ChannelN ch = new ChannelN((AMQConnection) conn, n + 1, + final ChannelN ch = new ChannelN(((AutorecoveringConnection) conn).getDelegate(), n + 1, new ConsumerWorkService(Executors.newSingleThreadExecutor(), Executors.defaultThreadFactory(), ConnectionFactory.DEFAULT_SHUTDOWN_TIMEOUT)); conn.addShutdownListener(new ShutdownListener() { diff --git a/src/test/java/com/rabbitmq/client/test/server/Permissions.java b/src/test/java/com/rabbitmq/client/test/server/Permissions.java index 39856dad86..233b85e9cc 100644 --- a/src/test/java/com/rabbitmq/client/test/server/Permissions.java +++ b/src/test/java/com/rabbitmq/client/test/server/Permissions.java @@ -16,28 +16,20 @@ package com.rabbitmq.client.test.server; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import com.rabbitmq.client.*; +import com.rabbitmq.client.impl.AMQChannel; +import com.rabbitmq.client.impl.recovery.AutorecoveringChannel; +import com.rabbitmq.client.test.BrokerTestCase; +import com.rabbitmq.client.test.TestUtils; +import com.rabbitmq.tools.Host; +import org.junit.Test; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeoutException; -import com.rabbitmq.client.test.TestUtils; -import org.junit.Test; - -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.AlreadyClosedException; -import com.rabbitmq.client.AuthenticationFailureException; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.ConnectionFactory; -import com.rabbitmq.client.QueueingConsumer; -import com.rabbitmq.client.impl.AMQChannel; -import com.rabbitmq.client.test.BrokerTestCase; -import com.rabbitmq.tools.Host; +import static org.junit.Assert.*; public class Permissions extends BrokerTestCase { @@ -222,9 +214,9 @@ public void with(String name) throws IOException { { runTest(false, false, true, false, new WithName() { public void with(String name) throws IOException { - ((AMQChannel)channel) - .exnWrappingRpc(new AMQP.Queue.Purge.Builder() - .queue(name) + AMQChannel channelDelegate = (AMQChannel) ((AutorecoveringChannel)channel).getDelegate(); + channelDelegate.exnWrappingRpc(new AMQP.Queue.Purge.Builder() + .queue(name) .build()); }}); } From 21f0adfb79d57b8ea2a12ea506874533a2c2aff7 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 11 Nov 2016 16:09:24 +0300 Subject: [PATCH 0373/2114] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 36d77bb39f..c33633f7d5 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,9 @@ The client is maintained by the [RabbitMQ team at Pivotal](http://github.com/rab ## Dependency (Maven Artifact) -Maven artifacts are [released to Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3Acom.rabbitmq%20a%3Aamqp-client). +Maven artifacts are [released to Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3Acom.rabbitmq%20a%3Aamqp-client) +via [RabbitMQ Maven repository on Bintray](https://bintray.com/rabbitmq/maven). There's also +a [Maven repository with milestone releases](https://bintray.com/rabbitmq/maven-milestones). ### Maven From 8d630e9fe30035dac9561768a39b4ae345c48522 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 11 Nov 2016 16:16:05 +0100 Subject: [PATCH 0374/2114] Fix typo --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5933c0ebfb..c0a4cfd0cd 100644 --- a/pom.xml +++ b/pom.xml @@ -167,7 +167,7 @@ is missing, nothing is setup and the testsuite relies on an externally provided broker/cluster. - If you want to explicitely disable the automatic cluster setup, + If you want to explicitly disable the automatic cluster setup, you must disable this profile: mvn verify -P '!setup-test-cluster' From 6841160915ac06928fb21d35bc53166daf812007 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 10 Nov 2016 18:06:31 +0100 Subject: [PATCH 0375/2114] Enable automatic recovery by default (WIP) Fixes #210 --- .../rabbitmq/client/ConnectionFactory.java | 2 +- .../impl/recovery/RecoveryAwareChannelN.java | 8 +++-- .../client/test/SharedThreadPoolTest.java | 1 + .../client/test/functional/Heartbeat.java | 13 ++++---- .../test/functional/UnexpectedFrames.java | 19 ++++++------ .../test/server/ChannelLimitNegotiation.java | 3 +- .../client/test/server/Permissions.java | 30 +++++++------------ 7 files changed, 35 insertions(+), 41 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index d52a824e81..0788d75714 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -100,7 +100,7 @@ public class ConnectionFactory implements Cloneable { private SocketConfigurator socketConf = new DefaultSocketConfigurator(); private ExceptionHandler exceptionHandler = new DefaultExceptionHandler(); - private boolean automaticRecovery = false; + private boolean automaticRecovery = true; private boolean topologyRecovery = true; // long is used to make sure the users can use both ints diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java index d23c1231da..353578da6a 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java @@ -82,16 +82,20 @@ private AMQImpl.Basic.Deliver offsetDeliveryTag(AMQImpl.Basic.Deliver method) { @Override public void basicAck(long deliveryTag, boolean multiple) throws IOException { + // FIXME no check if deliveryTag = 0 (ack all) long realTag = deliveryTag - activeDeliveryTagOffset; - if (realTag > 0) { + // 0 tag means ack all + if (realTag >= 0) { super.basicAck(realTag, multiple); } } @Override public void basicNack(long deliveryTag, boolean multiple, boolean requeue) throws IOException { + // FIXME no check if deliveryTag = 0 (nack all) long realTag = deliveryTag - activeDeliveryTagOffset; - if (realTag > 0) { + // 0 tag means nack all + if (realTag >= 0) { super.basicNack(realTag, multiple, requeue); } } diff --git a/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java b/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java index 082035dabe..ceb26b264a 100644 --- a/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java +++ b/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java @@ -31,6 +31,7 @@ public class SharedThreadPoolTest extends BrokerTestCase { @Test public void willShutDownExecutor() throws IOException, TimeoutException { ConnectionFactory cf = TestUtils.connectionFactory(); + cf.setAutomaticRecoveryEnabled(false); ExecutorService executor = Executors.newFixedThreadPool(8); cf.setSharedExecutor(executor); diff --git a/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java b/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java index 8ea14bce25..fe0f904103 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java @@ -16,16 +16,13 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; +import com.rabbitmq.client.test.BrokerTestCase; +import org.junit.Test; import java.io.IOException; -import org.junit.Test; - -import com.rabbitmq.client.impl.AMQConnection; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.*; public class Heartbeat extends BrokerTestCase { @@ -41,7 +38,7 @@ public Heartbeat() assertEquals(1, connection.getHeartbeat()); Thread.sleep(3100); assertTrue(connection.isOpen()); - ((AMQConnection)connection).setHeartbeat(0); + ((AutorecoveringConnection)connection).getDelegate().setHeartbeat(0); assertEquals(0, connection.getHeartbeat()); Thread.sleep(3100); assertFalse(connection.isOpen()); diff --git a/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java b/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java index b95cd1350a..0ab8013969 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java +++ b/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java @@ -15,19 +15,18 @@ package com.rabbitmq.client.test.functional; -import java.io.IOException; -import java.net.Socket; - -import javax.net.SocketFactory; - -import com.rabbitmq.client.impl.*; -import com.rabbitmq.client.test.TestUtils; -import org.junit.Test; - import com.rabbitmq.client.AMQP; import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.DefaultSocketConfigurator; +import com.rabbitmq.client.impl.*; +import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; import com.rabbitmq.client.test.BrokerTestCase; +import com.rabbitmq.client.test.TestUtils; +import org.junit.Test; + +import javax.net.SocketFactory; +import java.io.IOException; +import java.net.Socket; /** * Test that the server correctly handles us when we send it bad frames @@ -177,7 +176,7 @@ public Frame confuse(Frame frame) { } private void expectError(int error, Confuser confuser) throws IOException { - ((ConfusedFrameHandler)((AMQConnection)connection).getFrameHandler()). + ((ConfusedFrameHandler)((AutorecoveringConnection)connection).getDelegate().getFrameHandler()). confuser = confuser; //NB: the frame confuser relies on the encoding of the diff --git a/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java b/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java index 3bf0a813d9..6111e2660e 100644 --- a/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java +++ b/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java @@ -25,6 +25,7 @@ import javax.net.SocketFactory; +import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; import com.rabbitmq.client.test.TestUtils; import org.junit.Test; @@ -103,7 +104,7 @@ protected int negotiateChannelMax(int requestedChannelMax, int serverMax) { assertNull(conn.createChannel(n + 1)); // Construct a channel directly - final ChannelN ch = new ChannelN((AMQConnection) conn, n + 1, + final ChannelN ch = new ChannelN(((AutorecoveringConnection) conn).getDelegate(), n + 1, new ConsumerWorkService(Executors.newSingleThreadExecutor(), Executors.defaultThreadFactory(), ConnectionFactory.DEFAULT_SHUTDOWN_TIMEOUT)); conn.addShutdownListener(new ShutdownListener() { diff --git a/src/test/java/com/rabbitmq/client/test/server/Permissions.java b/src/test/java/com/rabbitmq/client/test/server/Permissions.java index 39856dad86..233b85e9cc 100644 --- a/src/test/java/com/rabbitmq/client/test/server/Permissions.java +++ b/src/test/java/com/rabbitmq/client/test/server/Permissions.java @@ -16,28 +16,20 @@ package com.rabbitmq.client.test.server; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import com.rabbitmq.client.*; +import com.rabbitmq.client.impl.AMQChannel; +import com.rabbitmq.client.impl.recovery.AutorecoveringChannel; +import com.rabbitmq.client.test.BrokerTestCase; +import com.rabbitmq.client.test.TestUtils; +import com.rabbitmq.tools.Host; +import org.junit.Test; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeoutException; -import com.rabbitmq.client.test.TestUtils; -import org.junit.Test; - -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.AlreadyClosedException; -import com.rabbitmq.client.AuthenticationFailureException; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.ConnectionFactory; -import com.rabbitmq.client.QueueingConsumer; -import com.rabbitmq.client.impl.AMQChannel; -import com.rabbitmq.client.test.BrokerTestCase; -import com.rabbitmq.tools.Host; +import static org.junit.Assert.*; public class Permissions extends BrokerTestCase { @@ -222,9 +214,9 @@ public void with(String name) throws IOException { { runTest(false, false, true, false, new WithName() { public void with(String name) throws IOException { - ((AMQChannel)channel) - .exnWrappingRpc(new AMQP.Queue.Purge.Builder() - .queue(name) + AMQChannel channelDelegate = (AMQChannel) ((AutorecoveringChannel)channel).getDelegate(); + channelDelegate.exnWrappingRpc(new AMQP.Queue.Purge.Builder() + .queue(name) .build()); }}); } From a51512c1bae89c444dd303c8c0d3368395f44465 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 14 Nov 2016 09:51:32 +0100 Subject: [PATCH 0376/2114] Fix DeadLetterExchange test Fixes #210 --- .../client/test/functional/DeadLetterExchange.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java index c0a31e4f8e..3d37a0b13a 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java @@ -157,14 +157,17 @@ protected void releaseResources() throws IOException { } @Test public void redeclareQueueWithRoutingKeyButNoDeadLetterExchange() - throws IOException - { + throws IOException, InterruptedException { try { Map args = new HashMap(); channel.queueDeclare("bar", false, true, false, args); args.put(DLX_RK_ARG, "foo"); + // sleep a little, otherwise the resource is still locked + // before the next call and we get a 405 - resource locked + Thread.sleep(100L); + channel.queueDeclare("bar", false, true, false, args); fail("x-dead-letter-exchange must be specified if " + "x-dead-letter-routing-key is set"); From de49971740b57612132ad73a0b8a97b3c5fd8d4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 14 Nov 2016 11:10:43 +0100 Subject: [PATCH 0377/2114] Disable auto recovery in DeadLetterExchange test Fixes #210 --- .../java/com/rabbitmq/client/test/BrokerTestCase.java | 5 +++++ .../client/test/functional/DeadLetterExchange.java | 9 +++++---- .../client/test/server/ExclusiveQueueDurability.java | 8 ++++++++ 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java index 11b1e44bc8..991c248a7c 100644 --- a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java +++ b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java @@ -60,9 +60,14 @@ protected void finished(Description description) { protected ConnectionFactory newConnectionFactory() { ConnectionFactory connectionFactory = TestUtils.connectionFactory(); + connectionFactory.setAutomaticRecoveryEnabled(isAutomaticRecoveryEnabled()); return connectionFactory; } + protected boolean isAutomaticRecoveryEnabled() { + return true; + } + protected Connection connection; protected Channel channel; diff --git a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java index 3d37a0b13a..e2c9ebb248 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java @@ -55,6 +55,11 @@ public class DeadLetterExchange extends BrokerTestCase { public static final int MSG_COUNT = 10; public static final int TTL = 1000; + @Override + protected boolean isAutomaticRecoveryEnabled() { + return false; + } + @Override protected void createResources() throws IOException { channel.exchangeDelete(DLX); @@ -164,10 +169,6 @@ protected void releaseResources() throws IOException { args.put(DLX_RK_ARG, "foo"); - // sleep a little, otherwise the resource is still locked - // before the next call and we get a 405 - resource locked - Thread.sleep(100L); - channel.queueDeclare("bar", false, true, false, args); fail("x-dead-letter-exchange must be specified if " + "x-dead-letter-routing-key is set"); diff --git a/src/test/java/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java b/src/test/java/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java index b5a8c6d4dc..57cb457087 100644 --- a/src/test/java/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java +++ b/src/test/java/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java @@ -33,6 +33,14 @@ */ public class ExclusiveQueueDurability extends BrokerTestCase { + @Override + protected boolean isAutomaticRecoveryEnabled() { + // With automatic recovery enabled, queue can be re-created when launching the test suite + // (because FunctionalTests are launched independently and as part of the HATests) + // This then makes this test fail. + return false; + } + void verifyQueueMissing(Channel channel, String queueName) throws IOException { try { From 7104a23408b701e94b54b52aa4c1df1caabb5ec5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 14 Nov 2016 14:07:50 +0100 Subject: [PATCH 0378/2114] Don't reuse queue name in DeadLetterExchange tests Fixes #210 --- .../test/functional/DeadLetterExchange.java | 46 ++++++------------- 1 file changed, 15 insertions(+), 31 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java index e2c9ebb248..73e357b021 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java @@ -15,35 +15,19 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import com.rabbitmq.client.*; +import com.rabbitmq.client.AMQP.BasicProperties; +import com.rabbitmq.client.QueueingConsumer.Delivery; +import com.rabbitmq.client.test.BrokerTestCase; +import org.junit.Test; import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.concurrent.Callable; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; -import org.junit.Test; - -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.AMQP.BasicProperties; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.DefaultConsumer; -import com.rabbitmq.client.Envelope; -import com.rabbitmq.client.GetResponse; -import com.rabbitmq.client.MessageProperties; -import com.rabbitmq.client.QueueingConsumer; -import com.rabbitmq.client.QueueingConsumer.Delivery; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.*; public class DeadLetterExchange extends BrokerTestCase { public static final String DLX = "dead.letter.exchange"; @@ -55,11 +39,6 @@ public class DeadLetterExchange extends BrokerTestCase { public static final int MSG_COUNT = 10; public static final int TTL = 1000; - @Override - protected boolean isAutomaticRecoveryEnabled() { - return false; - } - @Override protected void createResources() throws IOException { channel.exchangeDelete(DLX); @@ -154,7 +133,7 @@ protected void releaseResources() throws IOException { Map args = new HashMap(); args.put(DLX_RK_ARG, "foo"); - channel.queueDeclare("bar", false, true, false, args); + channel.queueDeclare(randomQueueName(), false, true, false, args); fail("dlx must be defined if dl-rk is set"); } catch (IOException ex) { checkShutdownSignal(AMQP.PRECONDITION_FAILED, ex); @@ -164,12 +143,13 @@ protected void releaseResources() throws IOException { @Test public void redeclareQueueWithRoutingKeyButNoDeadLetterExchange() throws IOException, InterruptedException { try { + String queueName = randomQueueName(); Map args = new HashMap(); - channel.queueDeclare("bar", false, true, false, args); + channel.queueDeclare(queueName, false, true, false, args); args.put(DLX_RK_ARG, "foo"); - channel.queueDeclare("bar", false, true, false, args); + channel.queueDeclare(queueName, false, true, false, args); fail("x-dead-letter-exchange must be specified if " + "x-dead-letter-routing-key is set"); } catch (IOException ex) { @@ -715,4 +695,8 @@ public void process(GetResponse getResponse) { public void process(GetResponse response); } + + private static String randomQueueName() { + return DeadLetterExchange.class.getSimpleName() + "-" + UUID.randomUUID().toString(); + } } From fc952a763df17126bb93b701782796f1f9257b1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 16 Nov 2016 10:25:06 +0100 Subject: [PATCH 0379/2114] [maven-release-plugin] prepare release v4.0.0.RC2 --- pom.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c0a4cfd0cd..08e64eafb4 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.0.0-SNAPSHOT + 4.0.0.RC2 jar RabbitMQ Java Client @@ -42,6 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git + v4.0.0.RC2 From 966ce1c3f668dcef170c974605ce2f3605513490 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 16 Nov 2016 10:25:15 +0100 Subject: [PATCH 0380/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 08e64eafb4..77adbfbf51 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.0.0.RC2 + 4.0.0-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v4.0.0.RC2 + HEAD From 415b5eb3a8f92867998b3c760fe035bb20a94382 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Thu, 17 Nov 2016 09:23:12 +0300 Subject: [PATCH 0381/2114] Move Maven Central badge lower --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c33633f7d5..6ddaae9636 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,4 @@ -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.rabbitmq/amqp-client/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.rabbitmq/amqp-client) - -## RabbitMQ Java Client +# RabbitMQ Java Client This repository contains source code of the [RabbitMQ Java client](http://www.rabbitmq.com/api-guide.html). The client is maintained by the [RabbitMQ team at Pivotal](http://github.com/rabbitmq/). @@ -14,6 +12,8 @@ a [Maven repository with milestone releases](https://bintray.com/rabbitmq/maven- ### Maven +[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.rabbitmq/amqp-client/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.rabbitmq/amqp-client) + ``` xml com.rabbitmq From 077f66fd169e2dedbe5c3aebb598b825ee8da8ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 21 Nov 2016 17:51:12 +0100 Subject: [PATCH 0382/2114] Remove some QueueingConsumer usages in tests References #213 --- .../com/rabbitmq/client/test/ClientTests.java | 2 +- ...nTests.java => QueueingConsumerTests.java} | 40 ++++++++++++- .../ConsumerCancelNotification.java | 53 +++-------------- .../test/functional/ConsumerPriorities.java | 57 +++++++++++++------ .../test/functional/DeadLetterExchange.java | 41 +++++++++---- 5 files changed, 119 insertions(+), 74 deletions(-) rename src/test/java/com/rabbitmq/client/test/{QueueingConsumerShutdownTests.java => QueueingConsumerTests.java} (63%) diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index 3a72a4da4e..3c1371669a 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -33,7 +33,7 @@ Bug20004Test.class, CloseInMainLoop.class, ChannelNumberAllocationTests.class, - QueueingConsumerShutdownTests.class, + QueueingConsumerTests.class, MultiThreadedChannel.class, IntAllocatorTests.class, AMQBuilderApiTest.class, diff --git a/src/test/java/com/rabbitmq/client/test/QueueingConsumerShutdownTests.java b/src/test/java/com/rabbitmq/client/test/QueueingConsumerTests.java similarity index 63% rename from src/test/java/com/rabbitmq/client/test/QueueingConsumerShutdownTests.java rename to src/test/java/com/rabbitmq/client/test/QueueingConsumerTests.java index 143b2947e2..cf5114faef 100644 --- a/src/test/java/com/rabbitmq/client/test/QueueingConsumerShutdownTests.java +++ b/src/test/java/com/rabbitmq/client/test/QueueingConsumerTests.java @@ -16,9 +16,13 @@ package com.rabbitmq.client.test; import static org.junit.Assert.*; -import org.junit.Test; +import com.rabbitmq.client.ConsumerCancelledException; +import org.junit.Test; +import java.io.IOException; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @@ -27,7 +31,7 @@ import com.rabbitmq.client.QueueingConsumer; import com.rabbitmq.client.ShutdownSignalException; -public class QueueingConsumerShutdownTests extends BrokerTestCase{ +public class QueueingConsumerTests extends BrokerTestCase{ static final String QUEUE = "some-queue"; static final int THREADS = 5; @@ -64,4 +68,36 @@ public class QueueingConsumerShutdownTests extends BrokerTestCase{ assertEquals(0, count.get()); } + @Test public void consumerCancellationInterruptsQueuingConsumerWait() + throws IOException, InterruptedException { + String queue = "cancel_notification_queue_for_queueing_consumer"; + final BlockingQueue result = new ArrayBlockingQueue(1); + channel.queueDeclare(queue, false, true, false, null); + final QueueingConsumer consumer = new QueueingConsumer(channel); + Runnable receiver = new Runnable() { + + public void run() { + try { + try { + consumer.nextDelivery(); + } catch (ConsumerCancelledException e) { + result.put(true); + return; + } catch (ShutdownSignalException e) { + } catch (InterruptedException e) { + } + result.put(false); + } catch (InterruptedException e) { + fail(); + } + } + }; + Thread t = new Thread(receiver); + t.start(); + channel.basicConsume(queue, consumer); + channel.queueDelete(queue); + assertTrue(result.take()); + t.join(); + } + } diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java b/src/test/java/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java index 087986608d..fdda32ea18 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java @@ -15,8 +15,12 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Consumer; +import com.rabbitmq.client.DefaultConsumer; +import com.rabbitmq.client.ShutdownSignalException; +import com.rabbitmq.client.test.BrokerTestCase; +import org.junit.Test; import java.io.IOException; import java.util.concurrent.ArrayBlockingQueue; @@ -24,15 +28,8 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; -import org.junit.Test; - -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.Consumer; -import com.rabbitmq.client.ConsumerCancelledException; -import com.rabbitmq.client.DefaultConsumer; -import com.rabbitmq.client.QueueingConsumer; -import com.rabbitmq.client.ShutdownSignalException; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; public class ConsumerCancelNotification extends BrokerTestCase { @@ -43,7 +40,7 @@ public class ConsumerCancelNotification extends BrokerTestCase { final BlockingQueue result = new ArrayBlockingQueue(1); channel.queueDeclare(queue, false, true, false, null); - Consumer consumer = new QueueingConsumer(channel) { + Consumer consumer = new DefaultConsumer(channel) { @Override public void handleCancel(String consumerTag) throws IOException { try { @@ -58,38 +55,6 @@ public void handleCancel(String consumerTag) throws IOException { assertTrue(result.take()); } - @Test public void consumerCancellationInterruptsQueuingConsumerWait() - throws IOException, InterruptedException { - final BlockingQueue result = new ArrayBlockingQueue(1); - channel.queueDeclare(queue, false, true, false, null); - final QueueingConsumer consumer = new QueueingConsumer(channel); - Runnable receiver = new Runnable() { - - public void run() { - try { - try { - consumer.nextDelivery(); - } catch (ConsumerCancelledException e) { - result.put(true); - return; - } catch (ShutdownSignalException e) { - } catch (InterruptedException e) { - } - result.put(false); - } catch (InterruptedException e) { - fail(); - } - } - }; - Thread t = new Thread(receiver); - t.start(); - channel.basicConsume(queue, consumer); - channel.queueDelete(queue); - assertTrue(result.take()); - t.join(); - } - - class AlteringConsumer extends DefaultConsumer { private final String altQueue; private final CountDownLatch latch; diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConsumerPriorities.java b/src/test/java/com/rabbitmq/client/test/functional/ConsumerPriorities.java index e9c24dbf0d..755000e7bc 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConsumerPriorities.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConsumerPriorities.java @@ -15,21 +15,20 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; +import com.rabbitmq.client.*; +import com.rabbitmq.client.test.BrokerTestCase; +import org.junit.Test; import java.io.IOException; import java.util.Arrays; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; -import org.junit.Test; - -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.MessageProperties; -import com.rabbitmq.client.QueueingConsumer; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; public class ConsumerPriorities extends BrokerTestCase { @Test public void validation() throws IOException { @@ -43,7 +42,7 @@ private void assertFailValidation(Map args) throws IOException { Channel ch = connection.createChannel(); String queue = ch.queueDeclare().getQueue(); try { - ch.basicConsume(queue, true, args, new QueueingConsumer(ch)); + ch.basicConsume(queue, true, args, new DefaultConsumer(ch)); fail("Validation should fail for " + args); } catch (IOException ioe) { checkShutdownSignal(AMQP.PRECONDITION_FAILED, ioe); @@ -54,9 +53,9 @@ private void assertFailValidation(Map args) throws IOException { @Test public void consumerPriorities() throws Exception { String queue = channel.queueDeclare().getQueue(); - QueueingConsumer highConsumer = new QueueingConsumer(channel); - QueueingConsumer medConsumer = new QueueingConsumer(channel); - QueueingConsumer lowConsumer = new QueueingConsumer(channel); + QueueMessageConsumer highConsumer = new QueueMessageConsumer(channel); + QueueMessageConsumer medConsumer = new QueueMessageConsumer(channel); + QueueMessageConsumer lowConsumer = new QueueMessageConsumer(channel); String high = channel.basicConsume(queue, true, args(1), highConsumer); String med = channel.basicConsume(queue, true, medConsumer); channel.basicConsume(queue, true, args(-1), lowConsumer); @@ -78,12 +77,12 @@ private Map args(Object o) { return map; } - private void assertContents(QueueingConsumer qc, int count, String msg) throws InterruptedException { + private void assertContents(QueueMessageConsumer c, int count, String msg) throws InterruptedException { for (int i = 0; i < count; i++) { - QueueingConsumer.Delivery d = qc.nextDelivery(); - assertEquals(msg, new String(d.getBody())); + byte[] body = c.nextDelivery(100); + assertEquals(msg, new String(body)); } - assertEquals(null, qc.nextDelivery(0)); + assertEquals(null, c.nextDelivery()); } private void publish(String queue, int count, String msg) throws IOException { @@ -91,4 +90,28 @@ private void publish(String queue, int count, String msg) throws IOException { channel.basicPublish("", queue, MessageProperties.MINIMAL_BASIC, msg.getBytes()); } } + + class QueueMessageConsumer extends DefaultConsumer { + + BlockingQueue messages = new LinkedBlockingQueue(); + + public QueueMessageConsumer(Channel channel) { + super(channel); + } + + @Override + public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { + messages.add(body); + } + + byte[] nextDelivery() { + return messages.poll(); + } + + byte[] nextDelivery(long timeoutInMs) throws InterruptedException { + return messages.poll(timeoutInMs, TimeUnit.MILLISECONDS); + } + + } + } diff --git a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java index 73e357b021..f0a35bee7a 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java @@ -23,9 +23,7 @@ import java.io.IOException; import java.util.*; -import java.util.concurrent.Callable; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; +import java.util.concurrent.*; import static org.junit.Assert.*; @@ -173,13 +171,13 @@ protected void releaseResources() throws IOException { channel.queueBind(DLQ, DLX, "test"); //measure round-trip latency - QueueingConsumer c = new QueueingConsumer(channel); + QueueMessageConsumer c = new QueueMessageConsumer(channel); String cTag = channel.basicConsume(TEST_QUEUE_NAME, true, c); long start = System.currentTimeMillis(); publish(null, "test"); - Delivery d = c.nextDelivery(TTL); + byte[] body = c.nextDelivery(TTL); long stop = System.currentTimeMillis(); - assertNotNull(d); + assertNotNull(body); channel.basicCancel(cTag); long latency = stop-start; @@ -565,14 +563,14 @@ private void sleep(long millis) { /* check that each message arrives within epsilon of the publication time + TTL + latency */ - private void checkPromptArrival(QueueingConsumer c, + private void checkPromptArrival(QueueMessageConsumer c, int count, long latency) throws Exception { long epsilon = TTL / 10; for (int i = 0; i < count; i++) { - Delivery d = c.nextDelivery(TTL + TTL + latency + epsilon); - assertNotNull("message #" + i + " did not expire", d); + byte[] body = c.nextDelivery(TTL + TTL + latency + epsilon); + assertNotNull("message #" + i + " did not expire", body); long now = System.currentTimeMillis(); - long publishTime = Long.valueOf(new String(d.getBody())); + long publishTime = Long.valueOf(new String(body)); long targetTime = publishTime + TTL + latency; assertTrue("expiry outside bounds (+/- " + epsilon + "): " + (now - targetTime), @@ -699,4 +697,27 @@ public void process(GetResponse getResponse) { private static String randomQueueName() { return DeadLetterExchange.class.getSimpleName() + "-" + UUID.randomUUID().toString(); } + + class QueueMessageConsumer extends DefaultConsumer { + + BlockingQueue messages = new LinkedBlockingQueue(); + + public QueueMessageConsumer(Channel channel) { + super(channel); + } + + @Override + public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { + messages.add(body); + } + + byte[] nextDelivery() { + return messages.poll(); + } + + byte[] nextDelivery(long timeoutInMs) throws InterruptedException { + return messages.poll(timeoutInMs, TimeUnit.MILLISECONDS); + } + + } } From 470cd48b3cb8b278f570ecddb2ecbf7890d6b23e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 22 Nov 2016 09:55:45 +0100 Subject: [PATCH 0383/2114] Use new CLI syntax to define policy priority --priority=1 instead of --priority 1 --- src/test/java/com/rabbitmq/client/test/functional/Policies.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/Policies.java b/src/test/java/com/rabbitmq/client/test/functional/Policies.java index f1dba4d33d..d3a512d956 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Policies.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Policies.java @@ -187,7 +187,7 @@ private void setPolicy(String name, String pattern, String definition) throws IO if (HATests.HA_TESTS_RUNNING) { definition += ",\"ha-mode\":\"all\""; } - Host.rabbitmqctl("set_policy --priority 1 " + name + " " + pattern + + Host.rabbitmqctl("set_policy --priority=1 " + name + " " + pattern + " {" + escapeDefinition(definition) + "}"); policies.add(name); } From 2ae1030c578fa5555d78c688ae279f41231f8e2f Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Tue, 22 Nov 2016 13:55:14 +0300 Subject: [PATCH 0384/2114] Revert "Use new CLI syntax to define policy priority" This reverts commit 470cd48b3cb8b278f570ecddb2ecbf7890d6b23e. The real problem is https://github.com/rabbitmq/rabbitmq-cli/issues/126. --- src/test/java/com/rabbitmq/client/test/functional/Policies.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/Policies.java b/src/test/java/com/rabbitmq/client/test/functional/Policies.java index d3a512d956..f1dba4d33d 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Policies.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Policies.java @@ -187,7 +187,7 @@ private void setPolicy(String name, String pattern, String definition) throws IO if (HATests.HA_TESTS_RUNNING) { definition += ",\"ha-mode\":\"all\""; } - Host.rabbitmqctl("set_policy --priority=1 " + name + " " + pattern + + Host.rabbitmqctl("set_policy --priority 1 " + name + " " + pattern + " {" + escapeDefinition(definition) + "}"); policies.add(name); } From 23bf6fd25effd857083505b0a524a9347d05eb2a Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Tue, 22 Nov 2016 21:39:00 +0300 Subject: [PATCH 0385/2114] Development version is now 3.6.7-SNAPSHOT --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b450907728..269a56250f 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.rabbitmq amqp-client - 3.6.6-SNAPSHOT + 3.6.7-SNAPSHOT jar RabbitMQ Java Client From c60388b06603d8aed9d18a13456ec1b116de6919 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 23 Nov 2016 15:02:35 +0100 Subject: [PATCH 0386/2114] [maven-release-plugin] prepare release v4.0.0 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 77adbfbf51..52c6014093 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.0.0-SNAPSHOT + 4.0.0 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v4.0.0 From ffda3ad7a36a18d1cc7078559291ef8221381aa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 23 Nov 2016 15:02:43 +0100 Subject: [PATCH 0387/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 52c6014093..54fd6beb05 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.0.0 + 4.0.1-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v4.0.0 + HEAD From 4f938698d761ddcf1fb13e14bed627acdc645e6e Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 23 Nov 2016 17:06:11 +0300 Subject: [PATCH 0388/2114] There are 2 release series now --- README.md | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6ddaae9636..de668e008a 100644 --- a/README.md +++ b/README.md @@ -14,18 +14,41 @@ a [Maven repository with milestone releases](https://bintray.com/rabbitmq/maven- [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.rabbitmq/amqp-client/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.rabbitmq/amqp-client) +#### 4.x Series + +Starting with `4.0`, this client releases are independent from RabbitMQ server releases. +These versions can still be used with RabbitMQ server `3.x`. + +``` xml + + com.rabbitmq + amqp-client + 4.0.0 + +``` + +### Gradle + +``` groovy +compile 'com.rabbitmq:amqp-client:4.0.0' +``` + +#### 3.6.x Series + +`3.6.x` series are released in concert with RabbitMQ server for historical reasons. + ``` xml com.rabbitmq amqp-client - 3.6.5 + 3.6.6 ``` ### Gradle ``` groovy -compile 'com.rabbitmq:amqp-client:3.6.5' +compile 'com.rabbitmq:amqp-client:3.6.6' ``` From 4fe8074618b4d5495b731e6ee28cb5a7778b9113 Mon Sep 17 00:00:00 2001 From: Gary Russell Date: Wed, 23 Nov 2016 14:46:14 -0500 Subject: [PATCH 0389/2114] GH-217: Add toString() to AutorecoveringChannel Resolves https://github.com/rabbitmq/rabbitmq-java-client/issues/217 --- .../client/impl/recovery/AutorecoveringChannel.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java index 4c3fde55f9..2ce488f00d 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java @@ -596,7 +596,7 @@ public void removeRecoveryListener(RecoveryListener listener) { public void automaticallyRecover(AutorecoveringConnection connection, Connection connDelegate) throws IOException { RecoveryAwareChannelN defunctChannel = this.delegate; this.connection = connection; - + final RecoveryAwareChannelN newChannel = (RecoveryAwareChannelN) connDelegate.createChannel(this.getChannelNumber()); if (newChannel == null) throw new IOException("Failed to create new channel for channel number=" + this.getChannelNumber() + " during recovery"); @@ -736,4 +736,9 @@ void updateConsumerTag(String tag, String newTag) { } } + @Override + public String toString() { + return this.delegate.toString(); + } + } From ee3aeacb1dd15b15215cd4c2e1fd59f8ab5af4f9 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 23 Nov 2016 23:01:51 +0300 Subject: [PATCH 0390/2114] Master is now 4.1.0-SNAPSHOT --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 54fd6beb05..c278b5d35b 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.0.1-SNAPSHOT + 4.1.0-SNAPSHOT jar RabbitMQ Java Client From d975201a14beeaad3c48d084d4d38d5c38ddfb76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 1 Dec 2016 16:33:51 +0100 Subject: [PATCH 0391/2114] Add configurable timeout on RPC calls Fixes #219 --- .../client/ChannelRpcTimeoutException.java | 28 ++++ .../rabbitmq/client/ConnectionFactory.java | 23 +++ .../com/rabbitmq/client/impl/AMQChannel.java | 35 ++++- .../rabbitmq/client/impl/AMQConnection.java | 18 ++- .../client/impl/ConnectionParams.java | 9 ++ .../rabbitmq/client/test/AMQChannelTest.java | 120 +++++++++++++++ .../ChannelRpcTimeoutIntegrationTest.java | 138 ++++++++++++++++++ .../com/rabbitmq/client/test/ClientTests.java | 2 + .../rabbitmq/client/test/RpcTimeoutTest.java | 20 +++ 9 files changed, 382 insertions(+), 11 deletions(-) create mode 100644 src/main/java/com/rabbitmq/client/ChannelRpcTimeoutException.java create mode 100644 src/test/java/com/rabbitmq/client/test/AMQChannelTest.java create mode 100644 src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java create mode 100644 src/test/java/com/rabbitmq/client/test/RpcTimeoutTest.java diff --git a/src/main/java/com/rabbitmq/client/ChannelRpcTimeoutException.java b/src/main/java/com/rabbitmq/client/ChannelRpcTimeoutException.java new file mode 100644 index 0000000000..5802a68a58 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/ChannelRpcTimeoutException.java @@ -0,0 +1,28 @@ +package com.rabbitmq.client; + +import java.io.IOException; +import java.util.concurrent.TimeoutException; + +/** + * + */ +public class ChannelRpcTimeoutException extends IOException { + + private final Object channel; + + private final Method method; + + public ChannelRpcTimeoutException(TimeoutException cause, Object channel, Method method) { + super(cause); + this.channel = channel; + this.method = method; + } + + public Method getMethod() { + return method; + } + + public Object getChannel() { + return channel; + } +} diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 0788d75714..a4736bd98c 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -73,6 +73,9 @@ public class ConnectionFactory implements Cloneable { * zero means wait indefinitely */ public static final int DEFAULT_SHUTDOWN_TIMEOUT = 10000; + /** The default timeout for RPC calls in channels: no timeout */ + public static final int DEFAULT_CHANNEL_RPC_TIMEOUT = -1; + private static final String PREFERRED_TLS_PROTOCOL = "TLSv1.2"; private static final String FALLBACK_TLS_PROTOCOL = "TLSv1"; @@ -116,6 +119,8 @@ public class ConnectionFactory implements Cloneable { private SSLContext sslContext; + private int channelRpcTimeout = DEFAULT_CHANNEL_RPC_TIMEOUT; + /** @return the default host to use for connections */ public String getHost() { return host; @@ -937,6 +942,7 @@ public ConnectionParams params(ExecutorService consumerWorkServiceExecutor) { result.setRequestedHeartbeat(requestedHeartbeat); result.setShutdownExecutor(shutdownExecutor); result.setHeartbeatExecutor(heartbeatExecutor); + result.setChannelRpcTimeout(channelRpcTimeout); return result; } @@ -1079,4 +1085,21 @@ public void useNio() { public void useBlockingIo() { this.nio = false; } + + /** + * Set the timeout for RPC calls in channels. + * Default is no timeout. + * @param channelRpcTimeout + */ + public void setChannelRpcTimeout(int channelRpcTimeout) { + this.channelRpcTimeout = channelRpcTimeout; + } + + /** + * Get the timeout for RPC calls in channels. + * @return + */ + public int getChannelRpcTimeout() { + return channelRpcTimeout; + } } diff --git a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java index c568214d66..806d3431b0 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java @@ -19,12 +19,11 @@ import java.io.IOException; import java.util.concurrent.TimeoutException; -import com.rabbitmq.client.AlreadyClosedException; -import com.rabbitmq.client.Command; +import com.rabbitmq.client.*; import com.rabbitmq.client.Method; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.ShutdownSignalException; import com.rabbitmq.utility.BlockingValueOrException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Base class modelling an AMQ channel. Subclasses implement @@ -37,6 +36,11 @@ * @see Connection */ public abstract class AMQChannel extends ShutdownNotifierComponent { + + private static final Logger LOGGER = LoggerFactory.getLogger(AMQChannel.class); + + private static final int NO_RPC_TIMEOUT = ConnectionFactory.DEFAULT_CHANNEL_RPC_TIMEOUT; + /** * Protected; used instead of synchronizing on the channel itself, * so that clients can themselves use the channel to synchronize @@ -59,6 +63,9 @@ public abstract class AMQChannel extends ShutdownNotifierComponent { /** Whether transmission of content-bearing methods should be blocked */ public volatile boolean _blockContent = false; + /** Timeout for RPC calls */ + private final int _rpcTimeout; + /** * Construct a channel on the given connection, with the given channel number. * @param connection the underlying connection for this channel @@ -67,6 +74,7 @@ public abstract class AMQChannel extends ShutdownNotifierComponent { public AMQChannel(AMQConnection connection, int channelNumber) { this._connection = connection; this._channelNumber = channelNumber; + this._rpcTimeout = connection.getChannelRpcTimeout(); } /** @@ -225,8 +233,23 @@ private AMQCommand privateRpc(Method m) // // Calling getReply() on the continuation puts us to sleep // until the connection's reader-thread throws the reply over - // the fence. - return k.getReply(); + // the fence or the RPC times out (if enabled) + if(_rpcTimeout == NO_RPC_TIMEOUT) { + return k.getReply(); + } else { + try { + return k.getReply(_rpcTimeout); + } catch (TimeoutException e) { + try { + // clean RPC channel state + nextOutstandingRpc(); + markRpcFinished(); + } catch(Exception ex) { + LOGGER.warn("Error while cleaning timed out channel RPC: {}", ex.getMessage()); + } + throw new ChannelRpcTimeoutException(e, this, m); + } + } } private AMQCommand privateRpc(Method m, int timeout) diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index aeb5e35884..2a40069380 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -94,11 +94,7 @@ public static Map defaultClientProperties() { new Version(AMQP.PROTOCOL.MAJOR, AMQP.PROTOCOL.MINOR); /** The special channel 0 (not managed by the _channelManager) */ - private final AMQChannel _channel0 = new AMQChannel(this, 0) { - @Override public boolean processAsync(Command c) throws IOException { - return getConnection().processControlCommand(c); - } - }; + private final AMQChannel _channel0; protected ConsumerWorkService _workService = null; @@ -137,6 +133,7 @@ public static Map defaultClientProperties() { private final String password; private final Collection blockedListeners = new CopyOnWriteArrayList(); protected final MetricsCollector metricsCollector; + private final int channelRpcTimeout; /* State modified after start - all volatile */ @@ -228,6 +225,13 @@ public AMQConnection(ConnectionParams params, FrameHandler frameHandler, Metrics this.heartbeatExecutor = params.getHeartbeatExecutor(); this.shutdownExecutor = params.getShutdownExecutor(); this.threadFactory = params.getThreadFactory(); + this.channelRpcTimeout = params.getChannelRpcTimeout(); + + this._channel0 = new AMQChannel(this, 0) { + @Override public boolean processAsync(Command c) throws IOException { + return getConnection().processControlCommand(c); + } + }; this._channelManager = null; @@ -1045,4 +1049,8 @@ public String getId() { public void setId(String id) { this.id = id; } + + public int getChannelRpcTimeout() { + return channelRpcTimeout; + } } diff --git a/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java b/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java index d13e6facc9..72c9004544 100644 --- a/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java +++ b/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java @@ -39,6 +39,7 @@ public class ConnectionParams { private SaslConfig saslConfig; private long networkRecoveryInterval; private boolean topologyRecovery; + private int channelRpcTimeout; private ExceptionHandler exceptionHandler; private ThreadFactory threadFactory; @@ -109,6 +110,10 @@ public ThreadFactory getThreadFactory() { return threadFactory; } + public int getChannelRpcTimeout() { + return channelRpcTimeout; + } + public void setUsername(String username) { this.username = username; } @@ -180,4 +185,8 @@ public ScheduledExecutorService getHeartbeatExecutor() { public void setHeartbeatExecutor(ScheduledExecutorService heartbeatExecutor) { this.heartbeatExecutor = heartbeatExecutor; } + + public void setChannelRpcTimeout(int channelRpcTimeout) { + this.channelRpcTimeout = channelRpcTimeout; + } } diff --git a/src/test/java/com/rabbitmq/client/test/AMQChannelTest.java b/src/test/java/com/rabbitmq/client/test/AMQChannelTest.java new file mode 100644 index 0000000000..a6f0891c09 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/AMQChannelTest.java @@ -0,0 +1,120 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.test; + +import com.rabbitmq.client.ChannelRpcTimeoutException; +import com.rabbitmq.client.Command; +import com.rabbitmq.client.Method; +import com.rabbitmq.client.impl.AMQChannel; +import com.rabbitmq.client.impl.AMQCommand; +import com.rabbitmq.client.impl.AMQConnection; +import com.rabbitmq.client.impl.AMQImpl; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.io.IOException; +import java.util.concurrent.Callable; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class AMQChannelTest { + + ScheduledExecutorService scheduler; + + @Before public void init() { + scheduler = Executors.newSingleThreadScheduledExecutor(); + } + + @After public void tearDown() { + scheduler.shutdownNow(); + } + + @Test public void rpcTimesOutWhenResponseDoesNotCome() throws IOException { + int rpcTimeout = 100; + AMQConnection connection = mock(AMQConnection.class); + when(connection.getChannelRpcTimeout()).thenReturn(rpcTimeout); + + DummyAmqChannel channel = new DummyAmqChannel(connection, 1); + Method method = new AMQImpl.Queue.Declare.Builder() + .queue("") + .durable(false) + .exclusive(true) + .autoDelete(true) + .arguments(null) + .build(); + + try { + channel.rpc(method); + fail("Should time out and throw an exception"); + } catch(ChannelRpcTimeoutException e) { + // OK + assertThat((DummyAmqChannel) e.getChannel(), is(channel)); + assertThat(e.getMethod(), is(method)); + assertNull("outstanding RPC should have been cleaned", channel.nextOutstandingRpc()); + } + } + + @Test public void rpcReturnsResultWhenResponseHasCome() throws IOException { + int rpcTimeout = 1000; + AMQConnection connection = mock(AMQConnection.class); + when(connection.getChannelRpcTimeout()).thenReturn(rpcTimeout); + + final DummyAmqChannel channel = new DummyAmqChannel(connection, 1); + Method method = new AMQImpl.Queue.Declare.Builder() + .queue("") + .durable(false) + .exclusive(true) + .autoDelete(true) + .arguments(null) + .build(); + + final Method response = new AMQImpl.Queue.DeclareOk.Builder() + .queue("whatever") + .consumerCount(0) + .messageCount(0).build(); + + scheduler.schedule(new Callable() { + @Override + public Void call() throws Exception { + channel.handleCompleteInboundCommand(new AMQCommand(response)); + return null; + } + }, (long) (rpcTimeout / 2.0), TimeUnit.MILLISECONDS); + + AMQCommand rpcResponse = channel.rpc(method); + assertThat(rpcResponse.getMethod(), is(response)); + } + + static class DummyAmqChannel extends AMQChannel { + + public DummyAmqChannel(AMQConnection connection, int channelNumber) { + super(connection, channelNumber); + } + + @Override + public boolean processAsync(Command command) throws IOException { + return false; + } + } + +} diff --git a/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java b/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java new file mode 100644 index 0000000000..4ee6838562 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java @@ -0,0 +1,138 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.test; + +import com.rabbitmq.client.*; +import com.rabbitmq.client.impl.*; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import javax.net.SocketFactory; +import java.io.IOException; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeoutException; + +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; + +public class ChannelRpcTimeoutIntegrationTest { + + static long waitTimeOnSomeResponses = 1000L; + + ConnectionFactory factory; + + @Before + public void setUp() throws Exception { + factory = TestUtils.connectionFactory(); + } + + @After + public void tearDown() throws Exception { + factory = null; + } + + @Test public void channelWaitsWhenNoTimeoutSet() throws IOException, TimeoutException { + FrameHandler frameHandler = createFrameHandler(); + ConnectionParams params = factory.params(Executors.newFixedThreadPool(1)); + WaitingAmqConnection connection = new WaitingAmqConnection(params, frameHandler); + try { + connection.start(); + Channel channel = connection.createChannel(); + channel.queueDeclare(); + } finally { + connection.close(); + } + + } + + @Test public void channelThrowsExceptionWhenTimeoutIsSet() throws IOException, TimeoutException { + FrameHandler frameHandler = createFrameHandler(); + ConnectionParams params = factory.params(Executors.newFixedThreadPool(1)); + params.setChannelRpcTimeout((int) (waitTimeOnSomeResponses / 5.0)); + WaitingAmqConnection connection = new WaitingAmqConnection(params, frameHandler); + try { + connection.start(); + Channel channel = connection.createChannel(); + try { + + channel.queueDeclare(); + fail("Should time out and throw an exception"); + } catch(ChannelRpcTimeoutException e) { + // OK + assertThat((Channel) e.getChannel(), is(channel)); + assertThat(e.getMethod(), instanceOf(AMQP.Queue.Declare.class)); + } + } finally { + connection.close(); + } + } + + private FrameHandler createFrameHandler() throws IOException { + SocketFrameHandlerFactory socketFrameHandlerFactory = new SocketFrameHandlerFactory(ConnectionFactory.DEFAULT_CONNECTION_TIMEOUT, + SocketFactory.getDefault(), new DefaultSocketConfigurator(), false, null); + return socketFrameHandlerFactory.create(new Address("localhost")); + } + + static class WaitingChannel extends ChannelN { + + public WaitingChannel(AMQConnection connection, int channelNumber, ConsumerWorkService workService) { + super(connection, channelNumber, workService); + } + + @Override + public void handleCompleteInboundCommand(AMQCommand command) throws IOException { + if(command.getMethod() instanceof AMQImpl.Queue.DeclareOk) { + try { + Thread.sleep(waitTimeOnSomeResponses); + } catch (InterruptedException e) { + throw new IOException(e); + } + } + super.handleCompleteInboundCommand(command); + } + } + + static class WaitingChannelManager extends ChannelManager { + + public WaitingChannelManager(ConsumerWorkService workService, int channelMax, ThreadFactory threadFactory) { + super(workService, channelMax, threadFactory); + } + + @Override + protected ChannelN instantiateChannel(AMQConnection connection, int channelNumber, ConsumerWorkService workService) { + return new WaitingChannel(connection, channelNumber, workService); + } + } + + static class WaitingAmqConnection extends AMQConnection { + + public WaitingAmqConnection(ConnectionParams params, FrameHandler frameHandler) { + super(params, frameHandler); + } + + @Override + protected ChannelManager instantiateChannelManager(int channelMax, ThreadFactory threadFactory) { + WaitingChannelManager channelManager = new WaitingChannelManager(_workService, channelMax, threadFactory); + configureChannelManager(channelManager); + return channelManager; + } + } + +} diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index 3c1371669a..34ec68de85 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -27,6 +27,8 @@ BlockingCellTest.class, TruncatedInputStreamTest.class, AMQConnectionTest.class, + AMQChannelTest.class, + ChannelRpcTimeoutIntegrationTest.class, ValueOrExceptionTest.class, BrokenFramesTest.class, ClonePropertiesTest.class, diff --git a/src/test/java/com/rabbitmq/client/test/RpcTimeoutTest.java b/src/test/java/com/rabbitmq/client/test/RpcTimeoutTest.java new file mode 100644 index 0000000000..ee0f3bb290 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/RpcTimeoutTest.java @@ -0,0 +1,20 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.test; + +public class RpcTimeoutTest { + +} From 03db0469613e01c38cb6dd01369138dfab0b1c99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 1 Dec 2016 16:44:05 +0100 Subject: [PATCH 0392/2114] Add Javadoc to RPC timeout related classes Fixes #219 --- .../com/rabbitmq/client/ChannelRpcTimeoutException.java | 9 ++++++++- src/main/java/com/rabbitmq/client/ConnectionFactory.java | 4 ++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/ChannelRpcTimeoutException.java b/src/main/java/com/rabbitmq/client/ChannelRpcTimeoutException.java index 5802a68a58..361dfd3c82 100644 --- a/src/main/java/com/rabbitmq/client/ChannelRpcTimeoutException.java +++ b/src/main/java/com/rabbitmq/client/ChannelRpcTimeoutException.java @@ -4,12 +4,19 @@ import java.util.concurrent.TimeoutException; /** - * + * Exception thrown when a channel times out on a RPC call. + * @since 4.1.0 */ public class ChannelRpcTimeoutException extends IOException { + /** + * The channel that performed the RPC. + */ private final Object channel; + /** + * The request method that timed out. + */ private final Method method; public ChannelRpcTimeoutException(TimeoutException cause, Object channel, Method method) { diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index a4736bd98c..420dfb942d 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -119,6 +119,10 @@ public class ConnectionFactory implements Cloneable { private SSLContext sslContext; + /** + * RPC timeout. + * @since 4.1.0 + */ private int channelRpcTimeout = DEFAULT_CHANNEL_RPC_TIMEOUT; /** @return the default host to use for connections */ From 4d8b09714c9fad25d6eb862f1008ae008c5afaec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 2 Dec 2016 10:04:09 +0100 Subject: [PATCH 0393/2114] Set default continuation timeout to 10 minutes Fixes #219 --- ...a => ChannelContinuationTimeoutException.java} | 8 ++++---- .../com/rabbitmq/client/ConnectionFactory.java | 15 ++++++++++----- .../java/com/rabbitmq/client/impl/AMQChannel.java | 8 ++++++-- .../com/rabbitmq/client/impl/AMQConnection.java | 3 +++ .../com/rabbitmq/client/test/AMQChannelTest.java | 4 ++-- .../rabbitmq/client/test/AMQConnectionTest.java | 10 ++++++++++ .../test/ChannelRpcTimeoutIntegrationTest.java | 3 +-- 7 files changed, 36 insertions(+), 15 deletions(-) rename src/main/java/com/rabbitmq/client/{ChannelRpcTimeoutException.java => ChannelContinuationTimeoutException.java} (61%) diff --git a/src/main/java/com/rabbitmq/client/ChannelRpcTimeoutException.java b/src/main/java/com/rabbitmq/client/ChannelContinuationTimeoutException.java similarity index 61% rename from src/main/java/com/rabbitmq/client/ChannelRpcTimeoutException.java rename to src/main/java/com/rabbitmq/client/ChannelContinuationTimeoutException.java index 361dfd3c82..18e1fc6027 100644 --- a/src/main/java/com/rabbitmq/client/ChannelRpcTimeoutException.java +++ b/src/main/java/com/rabbitmq/client/ChannelContinuationTimeoutException.java @@ -4,13 +4,13 @@ import java.util.concurrent.TimeoutException; /** - * Exception thrown when a channel times out on a RPC call. + * Exception thrown when a channel times out on a continuation during a RPC call. * @since 4.1.0 */ -public class ChannelRpcTimeoutException extends IOException { +public class ChannelContinuationTimeoutException extends IOException { /** - * The channel that performed the RPC. + * The channel that performed the call. */ private final Object channel; @@ -19,7 +19,7 @@ public class ChannelRpcTimeoutException extends IOException { */ private final Method method; - public ChannelRpcTimeoutException(TimeoutException cause, Object channel, Method method) { + public ChannelContinuationTimeoutException(TimeoutException cause, Object channel, Method method) { super(cause); this.channel = channel; this.method = method; diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 420dfb942d..25fa5a8fdc 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -33,6 +33,8 @@ import java.util.*; import java.util.concurrent.*; +import static java.util.concurrent.TimeUnit.*; + /** * Convenience "factory" class to facilitate opening a {@link Connection} to an AMQP broker. */ @@ -73,8 +75,8 @@ public class ConnectionFactory implements Cloneable { * zero means wait indefinitely */ public static final int DEFAULT_SHUTDOWN_TIMEOUT = 10000; - /** The default timeout for RPC calls in channels: no timeout */ - public static final int DEFAULT_CHANNEL_RPC_TIMEOUT = -1; + /** The default continuation timeout for RPC calls in channels: 10 minutes */ + public static final int DEFAULT_CHANNEL_RPC_TIMEOUT = (int) MINUTES.toMillis(10); private static final String PREFERRED_TLS_PROTOCOL = "TLSv1.2"; @@ -120,7 +122,7 @@ public class ConnectionFactory implements Cloneable { private SSLContext sslContext; /** - * RPC timeout. + * Continuation timeout on RPC calls. * @since 4.1.0 */ private int channelRpcTimeout = DEFAULT_CHANNEL_RPC_TIMEOUT; @@ -1091,11 +1093,14 @@ public void useBlockingIo() { } /** - * Set the timeout for RPC calls in channels. - * Default is no timeout. + * Set the continuation timeout for RPC calls in channels. + * Default is 10 minutes. 0 means no timeout. * @param channelRpcTimeout */ public void setChannelRpcTimeout(int channelRpcTimeout) { + if(channelRpcTimeout < 0) { + throw new IllegalArgumentException("Timeout cannot be less than 0"); + } this.channelRpcTimeout = channelRpcTimeout; } diff --git a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java index 806d3431b0..662e06a79f 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java @@ -39,7 +39,7 @@ public abstract class AMQChannel extends ShutdownNotifierComponent { private static final Logger LOGGER = LoggerFactory.getLogger(AMQChannel.class); - private static final int NO_RPC_TIMEOUT = ConnectionFactory.DEFAULT_CHANNEL_RPC_TIMEOUT; + private static final int NO_RPC_TIMEOUT = 0; /** * Protected; used instead of synchronizing on the channel itself, @@ -74,6 +74,9 @@ public abstract class AMQChannel extends ShutdownNotifierComponent { public AMQChannel(AMQConnection connection, int channelNumber) { this._connection = connection; this._channelNumber = channelNumber; + if(connection.getChannelRpcTimeout() < 0) { + throw new IllegalArgumentException("Continuation timeout on RPC calls cannot be less than 0"); + } this._rpcTimeout = connection.getChannelRpcTimeout(); } @@ -235,6 +238,7 @@ private AMQCommand privateRpc(Method m) // until the connection's reader-thread throws the reply over // the fence or the RPC times out (if enabled) if(_rpcTimeout == NO_RPC_TIMEOUT) { + System.out.println("passe"); return k.getReply(); } else { try { @@ -247,7 +251,7 @@ private AMQCommand privateRpc(Method m) } catch(Exception ex) { LOGGER.warn("Error while cleaning timed out channel RPC: {}", ex.getMessage()); } - throw new ChannelRpcTimeoutException(e, this, m); + throw new ChannelContinuationTimeoutException(e, this, m); } } } diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index 2a40069380..7593fe22ec 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -225,6 +225,9 @@ public AMQConnection(ConnectionParams params, FrameHandler frameHandler, Metrics this.heartbeatExecutor = params.getHeartbeatExecutor(); this.shutdownExecutor = params.getShutdownExecutor(); this.threadFactory = params.getThreadFactory(); + if(params.getChannelRpcTimeout() < 0) { + throw new IllegalArgumentException("Continuation timeout on RPC calls cannot be less than 0"); + } this.channelRpcTimeout = params.getChannelRpcTimeout(); this._channel0 = new AMQChannel(this, 0) { diff --git a/src/test/java/com/rabbitmq/client/test/AMQChannelTest.java b/src/test/java/com/rabbitmq/client/test/AMQChannelTest.java index a6f0891c09..1adf3e4d17 100644 --- a/src/test/java/com/rabbitmq/client/test/AMQChannelTest.java +++ b/src/test/java/com/rabbitmq/client/test/AMQChannelTest.java @@ -15,7 +15,7 @@ package com.rabbitmq.client.test; -import com.rabbitmq.client.ChannelRpcTimeoutException; +import com.rabbitmq.client.ChannelContinuationTimeoutException; import com.rabbitmq.client.Command; import com.rabbitmq.client.Method; import com.rabbitmq.client.impl.AMQChannel; @@ -66,7 +66,7 @@ public class AMQChannelTest { try { channel.rpc(method); fail("Should time out and throw an exception"); - } catch(ChannelRpcTimeoutException e) { + } catch(ChannelContinuationTimeoutException e) { // OK assertThat((DummyAmqChannel) e.getChannel(), is(channel)); assertThat(e.getMethod(), is(method)); diff --git a/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java b/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java index 8d5a0d479d..ae8bc1e258 100644 --- a/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java +++ b/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java @@ -99,6 +99,16 @@ public class AMQConnectionTest { cf.setHandshakeTimeout(7000); } + @Test public void negativeRpcTimeoutIsForbidden() { + ConnectionFactory cf = TestUtils.connectionFactory(); + try { + cf.setChannelRpcTimeout(-10); + fail("expected an exception"); + } catch (IllegalArgumentException _ignored) { + // expected + } + } + /** Check the AMQConnection does send exactly 1 initial header, and deal correctly with * the frame handler throwing an exception when we try to read data */ diff --git a/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java b/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java index 4ee6838562..36be0939bf 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java @@ -71,10 +71,9 @@ public void tearDown() throws Exception { connection.start(); Channel channel = connection.createChannel(); try { - channel.queueDeclare(); fail("Should time out and throw an exception"); - } catch(ChannelRpcTimeoutException e) { + } catch(ChannelContinuationTimeoutException e) { // OK assertThat((Channel) e.getChannel(), is(channel)); assertThat(e.getMethod(), instanceOf(AMQP.Queue.Declare.class)); From 4688f2aee47a72be3b24e7005f5771456bb0db1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 2 Dec 2016 10:10:52 +0100 Subject: [PATCH 0394/2114] Remove a sysout --- src/main/java/com/rabbitmq/client/impl/AMQChannel.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java index 662e06a79f..29f8cd598e 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java @@ -238,7 +238,6 @@ private AMQCommand privateRpc(Method m) // until the connection's reader-thread throws the reply over // the fence or the RPC times out (if enabled) if(_rpcTimeout == NO_RPC_TIMEOUT) { - System.out.println("passe"); return k.getReply(); } else { try { From 8b576a9b2852bd058362a01cd26a1e0045bbd8cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 2 Dec 2016 10:13:27 +0100 Subject: [PATCH 0395/2114] Delete unused test class --- .../rabbitmq/client/test/RpcTimeoutTest.java | 20 ------------------- 1 file changed, 20 deletions(-) delete mode 100644 src/test/java/com/rabbitmq/client/test/RpcTimeoutTest.java diff --git a/src/test/java/com/rabbitmq/client/test/RpcTimeoutTest.java b/src/test/java/com/rabbitmq/client/test/RpcTimeoutTest.java deleted file mode 100644 index ee0f3bb290..0000000000 --- a/src/test/java/com/rabbitmq/client/test/RpcTimeoutTest.java +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - -package com.rabbitmq.client.test; - -public class RpcTimeoutTest { - -} From 176a9a5f7b510257b7751f5cc3b8481c4049cd18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 5 Dec 2016 11:56:00 +0100 Subject: [PATCH 0396/2114] Create abstract class for metrics collection Fixes #222 --- .../client/impl/AbstractMetricsCollector.java | 370 ++++++++++++++++++ .../client/impl/StandardMetricsCollector.java | 265 +------------ 2 files changed, 390 insertions(+), 245 deletions(-) create mode 100644 src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java diff --git a/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java new file mode 100644 index 0000000000..2b2bb1e35c --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java @@ -0,0 +1,370 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl; + +import com.rabbitmq.client.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +/** + * Base class for {@link MetricsCollector}. + * Implements tricky logic such as keeping track of acknowledged and + * rejected messages. Sub-classes just need to implement + * the logic to increment their metrics. + * Note transactions are not supported (see {@link MetricsCollector}. + * + * @see MetricsCollector + */ +public abstract class AbstractMetricsCollector implements MetricsCollector { + + private static final Logger LOGGER = LoggerFactory.getLogger(AbstractMetricsCollector.class); + + private final ConcurrentMap connectionState = new ConcurrentHashMap(); + + private final Runnable markAcknowledgedMessageAction = new Runnable() { + @Override + public void run() { + markAcknowledgedMessage(); + } + }; + + private final Runnable markRejectedMessageAction = new Runnable() { + @Override + public void run() { + markRejectedMessage(); + } + }; + + @Override + public void newConnection(final Connection connection) { + try { + if(connection.getId() == null) { + connection.setId(UUID.randomUUID().toString()); + } + incrementConnectionCount(connection); + connectionState.put(connection.getId(), new ConnectionState(connection)); + connection.addShutdownListener(new ShutdownListener() { + @Override + public void shutdownCompleted(ShutdownSignalException cause) { + closeConnection(connection); + } + }); + } catch(Exception e) { + LOGGER.info("Error while computing metrics in newConnection: " + e.getMessage()); + } + } + + @Override + public void closeConnection(Connection connection) { + try { + ConnectionState removed = connectionState.remove(connection.getId()); + if(removed != null) { + decrementConnectionCount(connection); + } + } catch(Exception e) { + LOGGER.info("Error while computing metrics in closeConnection: " + e.getMessage()); + } + } + + @Override + public void newChannel(final Channel channel) { + try { + incrementChannelCount(channel); + channel.addShutdownListener(new ShutdownListener() { + @Override + public void shutdownCompleted(ShutdownSignalException cause) { + closeChannel(channel); + } + }); + connectionState(channel.getConnection()).channelState.put(channel.getChannelNumber(), new ChannelState(channel)); + } catch(Exception e) { + LOGGER.info("Error while computing metrics in newChannel: " + e.getMessage()); + } + } + + @Override + public void closeChannel(Channel channel) { + try { + ChannelState removed = connectionState(channel.getConnection()).channelState.remove(channel.getChannelNumber()); + if(removed != null) { + decrementChannelCount(channel); + } + } catch(Exception e) { + LOGGER.info("Error while computing metrics in closeChannel: " + e.getMessage()); + } + } + + @Override + public void basicPublish(Channel channel) { + try { + markPublishedMessage(); + } catch(Exception e) { + LOGGER.info("Error while computing metrics in basicPublish: " + e.getMessage()); + } + } + + @Override + public void basicConsume(Channel channel, String consumerTag, boolean autoAck) { + try { + if(!autoAck) { + ChannelState channelState = channelState(channel); + channelState.lock.lock(); + try { + channelState(channel).consumersWithManualAck.add(consumerTag); + } finally { + channelState.lock.unlock(); + } + } + } catch(Exception e) { + LOGGER.info("Error while computing metrics in basicConsume: " + e.getMessage()); + } + } + + @Override + public void basicCancel(Channel channel, String consumerTag) { + try { + ChannelState channelState = channelState(channel); + channelState.lock.lock(); + try { + channelState(channel).consumersWithManualAck.remove(consumerTag); + } finally { + channelState.lock.unlock(); + } + } catch(Exception e) { + LOGGER.info("Error while computing metrics in basicCancel: " + e.getMessage()); + } + } + + @Override + public void consumedMessage(Channel channel, long deliveryTag, boolean autoAck) { + try { + markConsumedMessage(); + if(!autoAck) { + ChannelState channelState = channelState(channel); + channelState.lock.lock(); + try { + channelState(channel).unackedMessageDeliveryTags.add(deliveryTag); + } finally { + channelState.lock.unlock(); + } + } + } catch(Exception e) { + LOGGER.info("Error while computing metrics in consumedMessage: " + e.getMessage()); + } + } + + @Override + public void consumedMessage(Channel channel, long deliveryTag, String consumerTag) { + try { + markConsumedMessage(); + ChannelState channelState = channelState(channel); + channelState.lock.lock(); + try { + if(channelState.consumersWithManualAck.contains(consumerTag)) { + channelState.unackedMessageDeliveryTags.add(deliveryTag); + } + } finally { + channelState.lock.unlock(); + } + } catch(Exception e) { + LOGGER.info("Error while computing metrics in consumedMessage: " + e.getMessage()); + } + } + + @Override + public void basicAck(Channel channel, long deliveryTag, boolean multiple) { + try { + updateChannelStateAfterAckReject(channel, deliveryTag, multiple, markAcknowledgedMessageAction); + } catch(Exception e) { + LOGGER.info("Error while computing metrics in basicAck: " + e.getMessage()); + } + } + + @Override + public void basicNack(Channel channel, long deliveryTag) { + try { + updateChannelStateAfterAckReject(channel, deliveryTag, true, markRejectedMessageAction); + } catch(Exception e) { + LOGGER.info("Error while computing metrics in basicNack: " + e.getMessage()); + } + } + + @Override + public void basicReject(Channel channel, long deliveryTag) { + try { + updateChannelStateAfterAckReject(channel, deliveryTag, false, markRejectedMessageAction); + } catch(Exception e) { + LOGGER.info("Error while computing metrics in basicReject: " + e.getMessage()); + } + } + + private void updateChannelStateAfterAckReject(Channel channel, long deliveryTag, boolean multiple, Runnable action) { + ChannelState channelState = channelState(channel); + channelState.lock.lock(); + try { + if(multiple) { + Iterator iterator = channelState.unackedMessageDeliveryTags.iterator(); + while(iterator.hasNext()) { + long messageDeliveryTag = iterator.next(); + if(messageDeliveryTag <= deliveryTag) { + iterator.remove(); + action.run(); + } + } + } else { + channelState.unackedMessageDeliveryTags.remove(deliveryTag); + action.run(); + } + } finally { + channelState.lock.unlock(); + } + } + + private ConnectionState connectionState(Connection connection) { + return connectionState.get(connection.getId()); + } + + private ChannelState channelState(Channel channel) { + return connectionState(channel.getConnection()).channelState.get(channel.getChannelNumber()); + } + + /** + * Clean inner state for close connections and channels. + * Inner state is automatically cleaned on connection + * and channel closing. + * Thus, this method is provided as a safety net, to be externally + * called periodically if closing of resources wouldn't work + * properly for some corner cases. + */ + public void cleanStaleState() { + try { + Iterator> connectionStateIterator = connectionState.entrySet().iterator(); + while(connectionStateIterator.hasNext()) { + Map.Entry connectionEntry = connectionStateIterator.next(); + Connection connection = connectionEntry.getValue().connection; + if(connection.isOpen()) { + Iterator> channelStateIterator = connectionEntry.getValue().channelState.entrySet().iterator(); + while(channelStateIterator.hasNext()) { + Map.Entry channelStateEntry = channelStateIterator.next(); + Channel channel = channelStateEntry.getValue().channel; + if(!channel.isOpen()) { + channelStateIterator.remove(); + decrementChannelCount(channel); + LOGGER.info("Ripped off state of channel {} of connection {}. This is abnormal, please report.", + channel.getChannelNumber(), connection.getId()); + } + } + } else { + connectionStateIterator.remove(); + decrementConnectionCount(connection); + for(int i = 0; i < connectionEntry.getValue().channelState.size(); i++) { + decrementChannelCount(null); + } + LOGGER.info("Ripped off state of connection {}. This is abnormal, please report.", + connection.getId()); + } + } + } catch(Exception e) { + LOGGER.info("Error during periodic clean of metricsCollector: "+e.getMessage()); + } + } + + private static class ConnectionState { + + final ConcurrentMap channelState = new ConcurrentHashMap(); + final Connection connection; + + private ConnectionState(Connection connection) { + this.connection = connection; + } + } + + private static class ChannelState { + + final Lock lock = new ReentrantLock(); + + final Set unackedMessageDeliveryTags = new HashSet(); + final Set consumersWithManualAck = new HashSet(); + + final Channel channel; + + private ChannelState(Channel channel) { + this.channel = channel; + } + + } + + /** + * Increments connection count. + * The connection object is passed in as complementary information + * and without any guarantee of not being null. + * @param connection the connection that has been created (can be null) + */ + protected abstract void incrementConnectionCount(Connection connection); + + /** + * Decrements connection count. + * The connection object is passed in as complementary information + * and without any guarantee of not being null. + * @param connection the connection that has been closed (can be null) + */ + protected abstract void decrementConnectionCount(Connection connection); + + /** + * Increments channel count. + * The channel object is passed in as complementary information + * and without any guarantee of not being null. + * @param channel the channel that has been created (can be null) + */ + protected abstract void incrementChannelCount(Channel channel); + + /** + * Decrements channel count. + * The channel object is passed in as complementary information + * and without any guarantee of not being null. + * @param channel + */ + protected abstract void decrementChannelCount(Channel channel); + + /** + * Marks the event of a published message. + */ + protected abstract void markPublishedMessage(); + + /** + * Marks the event of a consumed message. + */ + protected abstract void markConsumedMessage(); + + /** + * Marks the event of an acknowledged message. + */ + protected abstract void markAcknowledgedMessage(); + + /** + * Marks the event of a rejected message. + */ + protected abstract void markRejectedMessage(); + + + +} diff --git a/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java index d3ee261878..08a3939f24 100644 --- a/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java @@ -18,15 +18,9 @@ import com.codahale.metrics.Counter; import com.codahale.metrics.Meter; import com.codahale.metrics.MetricRegistry; -import com.rabbitmq.client.*; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.MetricsCollector; /** * Dropwizard Metrics implementation of {@link MetricsCollector}. @@ -37,11 +31,7 @@ * * @see MetricsCollector */ -public class StandardMetricsCollector implements MetricsCollector { - - private static final Logger LOGGER = LoggerFactory.getLogger(StandardMetricsCollector.class); - - private final ConcurrentMap connectionState = new ConcurrentHashMap(); +public class StandardMetricsCollector extends AbstractMetricsCollector { private final MetricRegistry registry; @@ -72,261 +62,46 @@ public StandardMetricsCollector(MetricRegistry metricRegistry) { } @Override - public void newConnection(final Connection connection) { - try { - if(connection.getId() == null) { - connection.setId(UUID.randomUUID().toString()); - } - connections.inc(); - connectionState.put(connection.getId(), new ConnectionState(connection)); - connection.addShutdownListener(new ShutdownListener() { - @Override - public void shutdownCompleted(ShutdownSignalException cause) { - closeConnection(connection); - } - }); - } catch(Exception e) { - LOGGER.info("Error while computing metrics in newConnection: " + e.getMessage()); - } - } - - @Override - public void closeConnection(Connection connection) { - try { - ConnectionState removed = connectionState.remove(connection.getId()); - if(removed != null) { - connections.dec(); - } - } catch(Exception e) { - LOGGER.info("Error while computing metrics in closeConnection: " + e.getMessage()); - } - } - - @Override - public void newChannel(final Channel channel) { - try { - channels.inc(); - channel.addShutdownListener(new ShutdownListener() { - @Override - public void shutdownCompleted(ShutdownSignalException cause) { - closeChannel(channel); - } - }); - connectionState(channel.getConnection()).channelState.put(channel.getChannelNumber(), new ChannelState(channel)); - } catch(Exception e) { - LOGGER.info("Error while computing metrics in newChannel: " + e.getMessage()); - } - } - - @Override - public void closeChannel(Channel channel) { - try { - ChannelState removed = connectionState(channel.getConnection()).channelState.remove(channel.getChannelNumber()); - if(removed != null) { - channels.dec(); - } - } catch(Exception e) { - LOGGER.info("Error while computing metrics in closeChannel: " + e.getMessage()); - } + protected void incrementConnectionCount(Connection connection) { + connections.inc(); } @Override - public void basicPublish(Channel channel) { - try { - publishedMessages.mark(); - } catch(Exception e) { - LOGGER.info("Error while computing metrics in basicPublish: " + e.getMessage()); - } + protected void decrementConnectionCount(Connection connection) { + connections.dec(); } @Override - public void basicConsume(Channel channel, String consumerTag, boolean autoAck) { - try { - if(!autoAck) { - ChannelState channelState = channelState(channel); - channelState.lock.lock(); - try { - channelState(channel).consumersWithManualAck.add(consumerTag); - } finally { - channelState.lock.unlock(); - } - } - } catch(Exception e) { - LOGGER.info("Error while computing metrics in basicConsume: " + e.getMessage()); - } + protected void incrementChannelCount(Channel channel) { + channels.inc(); } @Override - public void basicCancel(Channel channel, String consumerTag) { - try { - ChannelState channelState = channelState(channel); - channelState.lock.lock(); - try { - channelState(channel).consumersWithManualAck.remove(consumerTag); - } finally { - channelState.lock.unlock(); - } - } catch(Exception e) { - LOGGER.info("Error while computing metrics in basicCancel: " + e.getMessage()); - } + protected void decrementChannelCount(Channel channel) { + channels.dec(); } @Override - public void consumedMessage(Channel channel, long deliveryTag, boolean autoAck) { - try { - consumedMessages.mark(); - if(!autoAck) { - ChannelState channelState = channelState(channel); - channelState.lock.lock(); - try { - channelState(channel).unackedMessageDeliveryTags.add(deliveryTag); - } finally { - channelState.lock.unlock(); - } - } - } catch(Exception e) { - LOGGER.info("Error while computing metrics in consumedMessage: " + e.getMessage()); - } + protected void markPublishedMessage() { + publishedMessages.mark(); } @Override - public void consumedMessage(Channel channel, long deliveryTag, String consumerTag) { - try { - consumedMessages.mark(); - ChannelState channelState = channelState(channel); - channelState.lock.lock(); - try { - if(channelState.consumersWithManualAck.contains(consumerTag)) { - channelState.unackedMessageDeliveryTags.add(deliveryTag); - } - } finally { - channelState.lock.unlock(); - } - } catch(Exception e) { - LOGGER.info("Error while computing metrics in consumedMessage: " + e.getMessage()); - } + protected void markConsumedMessage() { + consumedMessages.mark(); } @Override - public void basicAck(Channel channel, long deliveryTag, boolean multiple) { - try { - updateChannelStateAfterAckReject(channel, deliveryTag, multiple, acknowledgedMessages); - } catch(Exception e) { - LOGGER.info("Error while computing metrics in basicAck: " + e.getMessage()); - } + protected void markAcknowledgedMessage() { + acknowledgedMessages.mark(); } @Override - public void basicNack(Channel channel, long deliveryTag) { - try { - updateChannelStateAfterAckReject(channel, deliveryTag, true, rejectedMessages); - } catch(Exception e) { - LOGGER.info("Error while computing metrics in basicNack: " + e.getMessage()); - } - } - - @Override - public void basicReject(Channel channel, long deliveryTag) { - try { - updateChannelStateAfterAckReject(channel, deliveryTag, false, rejectedMessages); - } catch(Exception e) { - LOGGER.info("Error while computing metrics in basicReject: " + e.getMessage()); - } - } - - private void updateChannelStateAfterAckReject(Channel channel, long deliveryTag, boolean multiple, Meter meter) { - ChannelState channelState = channelState(channel); - channelState.lock.lock(); - try { - if(multiple) { - Iterator iterator = channelState.unackedMessageDeliveryTags.iterator(); - while(iterator.hasNext()) { - long messageDeliveryTag = iterator.next(); - if(messageDeliveryTag <= deliveryTag) { - iterator.remove(); - meter.mark(); - } - } - } else { - channelState.unackedMessageDeliveryTags.remove(deliveryTag); - meter.mark(); - } - } finally { - channelState.lock.unlock(); - } - } - - private ConnectionState connectionState(Connection connection) { - return connectionState.get(connection.getId()); - } - - private ChannelState channelState(Channel channel) { - return connectionState(channel.getConnection()).channelState.get(channel.getChannelNumber()); - } - - /** - * Clean inner state for close connections and channels. - * Inner state is automatically cleaned on connection - * and channel closing. - * Thus, this method is provided as a safety net, to be externally - * called periodically if closing of resources wouldn't work - * properly for some corner cases. - */ - public void cleanStaleState() { - try { - Iterator> connectionStateIterator = connectionState.entrySet().iterator(); - while(connectionStateIterator.hasNext()) { - Map.Entry connectionEntry = connectionStateIterator.next(); - Connection connection = connectionEntry.getValue().connection; - if(connection.isOpen()) { - Iterator> channelStateIterator = connectionEntry.getValue().channelState.entrySet().iterator(); - while(channelStateIterator.hasNext()) { - Map.Entry channelStateEntry = channelStateIterator.next(); - Channel channel = channelStateEntry.getValue().channel; - if(!channel.isOpen()) { - channelStateIterator.remove(); - channels.dec(); - LOGGER.info("Ripped off state of channel {} of connection {}. This is abnormal, please report.", - channel.getChannelNumber(), connection.getId()); - } - } - } else { - connectionStateIterator.remove(); - connections.dec(); - channels.dec(connectionEntry.getValue().channelState.size()); - LOGGER.info("Ripped off state of connection {}. This is abnormal, please report.", - connection.getId()); - } - } - } catch(Exception e) { - LOGGER.info("Error during periodic clean of metricsCollector: "+e.getMessage()); - } - } - - private static class ConnectionState { - - final ConcurrentMap channelState = new ConcurrentHashMap(); - final Connection connection; - - private ConnectionState(Connection connection) { - this.connection = connection; - } + protected void markRejectedMessage() { + rejectedMessages.mark(); } - private static class ChannelState { - - final Lock lock = new ReentrantLock(); - final Set unackedMessageDeliveryTags = new HashSet(); - final Set consumersWithManualAck = new HashSet(); - - final Channel channel; - - private ChannelState(Channel channel) { - this.channel = channel; - } - - } public MetricRegistry getMetricRegistry() { return registry; From 6b5d676d15ae2d2761609f09735257ce352a12b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 5 Dec 2016 12:09:43 +0100 Subject: [PATCH 0397/2114] Add channel number to ChannelContinuationTimeoutException Fixes #219 --- .../ChannelContinuationTimeoutException.java | 32 +++++++++++++++++-- .../com/rabbitmq/client/impl/AMQChannel.java | 2 +- .../rabbitmq/client/test/AMQChannelTest.java | 1 + .../ChannelRpcTimeoutIntegrationTest.java | 1 + 4 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ChannelContinuationTimeoutException.java b/src/main/java/com/rabbitmq/client/ChannelContinuationTimeoutException.java index 18e1fc6027..d5bca1eeba 100644 --- a/src/main/java/com/rabbitmq/client/ChannelContinuationTimeoutException.java +++ b/src/main/java/com/rabbitmq/client/ChannelContinuationTimeoutException.java @@ -11,25 +11,53 @@ public class ChannelContinuationTimeoutException extends IOException { /** * The channel that performed the call. + * Typed as Object as the underlying + * object that performs the call might + * not be an implementation of {@link Channel}. */ private final Object channel; + /** + * The number of the channel that performed the call. + */ + private final int channelNumber; + /** * The request method that timed out. */ private final Method method; - public ChannelContinuationTimeoutException(TimeoutException cause, Object channel, Method method) { - super(cause); + public ChannelContinuationTimeoutException(TimeoutException cause, Object channel, int channelNumber, Method method) { + super( + "Continuation call for method " + method + " on channel " + channel + " (#" + channelNumber + ") timed out", + cause + ); this.channel = channel; + this.channelNumber = channelNumber; this.method = method; } + /** + * + * @return request method that timed out + */ public Method getMethod() { return method; } + /** + * channel that performed the call + * @return + */ public Object getChannel() { return channel; } + + /** + * + * @return number of the channel that performed the call + */ + public int getChannelNumber() { + return channelNumber; + } } diff --git a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java index 29f8cd598e..6726f728f8 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java @@ -250,7 +250,7 @@ private AMQCommand privateRpc(Method m) } catch(Exception ex) { LOGGER.warn("Error while cleaning timed out channel RPC: {}", ex.getMessage()); } - throw new ChannelContinuationTimeoutException(e, this, m); + throw new ChannelContinuationTimeoutException(e, this, this._channelNumber, m); } } } diff --git a/src/test/java/com/rabbitmq/client/test/AMQChannelTest.java b/src/test/java/com/rabbitmq/client/test/AMQChannelTest.java index 1adf3e4d17..460ae3e93c 100644 --- a/src/test/java/com/rabbitmq/client/test/AMQChannelTest.java +++ b/src/test/java/com/rabbitmq/client/test/AMQChannelTest.java @@ -69,6 +69,7 @@ public class AMQChannelTest { } catch(ChannelContinuationTimeoutException e) { // OK assertThat((DummyAmqChannel) e.getChannel(), is(channel)); + assertThat(e.getChannelNumber(), is(channel.getChannelNumber())); assertThat(e.getMethod(), is(method)); assertNull("outstanding RPC should have been cleaned", channel.nextOutstandingRpc()); } diff --git a/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java b/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java index 36be0939bf..dd5b8c0c6f 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java @@ -76,6 +76,7 @@ public void tearDown() throws Exception { } catch(ChannelContinuationTimeoutException e) { // OK assertThat((Channel) e.getChannel(), is(channel)); + assertThat(e.getChannelNumber(), is(channel.getChannelNumber())); assertThat(e.getMethod(), instanceOf(AMQP.Queue.Declare.class)); } } finally { From 99c751fbebaa9f1f5ff8956ba012d6263cba29f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 6 Dec 2016 09:52:48 +0100 Subject: [PATCH 0398/2114] Revert "Create abstract class for metrics collection" This reverts commit 176a9a5f7b510257b7751f5cc3b8481c4049cd18. This refactoring should be applied only on 4.1. --- .../client/impl/AbstractMetricsCollector.java | 370 ------------------ .../client/impl/StandardMetricsCollector.java | 265 ++++++++++++- 2 files changed, 245 insertions(+), 390 deletions(-) delete mode 100644 src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java diff --git a/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java deleted file mode 100644 index 2b2bb1e35c..0000000000 --- a/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java +++ /dev/null @@ -1,370 +0,0 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - -package com.rabbitmq.client.impl; - -import com.rabbitmq.client.*; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - -/** - * Base class for {@link MetricsCollector}. - * Implements tricky logic such as keeping track of acknowledged and - * rejected messages. Sub-classes just need to implement - * the logic to increment their metrics. - * Note transactions are not supported (see {@link MetricsCollector}. - * - * @see MetricsCollector - */ -public abstract class AbstractMetricsCollector implements MetricsCollector { - - private static final Logger LOGGER = LoggerFactory.getLogger(AbstractMetricsCollector.class); - - private final ConcurrentMap connectionState = new ConcurrentHashMap(); - - private final Runnable markAcknowledgedMessageAction = new Runnable() { - @Override - public void run() { - markAcknowledgedMessage(); - } - }; - - private final Runnable markRejectedMessageAction = new Runnable() { - @Override - public void run() { - markRejectedMessage(); - } - }; - - @Override - public void newConnection(final Connection connection) { - try { - if(connection.getId() == null) { - connection.setId(UUID.randomUUID().toString()); - } - incrementConnectionCount(connection); - connectionState.put(connection.getId(), new ConnectionState(connection)); - connection.addShutdownListener(new ShutdownListener() { - @Override - public void shutdownCompleted(ShutdownSignalException cause) { - closeConnection(connection); - } - }); - } catch(Exception e) { - LOGGER.info("Error while computing metrics in newConnection: " + e.getMessage()); - } - } - - @Override - public void closeConnection(Connection connection) { - try { - ConnectionState removed = connectionState.remove(connection.getId()); - if(removed != null) { - decrementConnectionCount(connection); - } - } catch(Exception e) { - LOGGER.info("Error while computing metrics in closeConnection: " + e.getMessage()); - } - } - - @Override - public void newChannel(final Channel channel) { - try { - incrementChannelCount(channel); - channel.addShutdownListener(new ShutdownListener() { - @Override - public void shutdownCompleted(ShutdownSignalException cause) { - closeChannel(channel); - } - }); - connectionState(channel.getConnection()).channelState.put(channel.getChannelNumber(), new ChannelState(channel)); - } catch(Exception e) { - LOGGER.info("Error while computing metrics in newChannel: " + e.getMessage()); - } - } - - @Override - public void closeChannel(Channel channel) { - try { - ChannelState removed = connectionState(channel.getConnection()).channelState.remove(channel.getChannelNumber()); - if(removed != null) { - decrementChannelCount(channel); - } - } catch(Exception e) { - LOGGER.info("Error while computing metrics in closeChannel: " + e.getMessage()); - } - } - - @Override - public void basicPublish(Channel channel) { - try { - markPublishedMessage(); - } catch(Exception e) { - LOGGER.info("Error while computing metrics in basicPublish: " + e.getMessage()); - } - } - - @Override - public void basicConsume(Channel channel, String consumerTag, boolean autoAck) { - try { - if(!autoAck) { - ChannelState channelState = channelState(channel); - channelState.lock.lock(); - try { - channelState(channel).consumersWithManualAck.add(consumerTag); - } finally { - channelState.lock.unlock(); - } - } - } catch(Exception e) { - LOGGER.info("Error while computing metrics in basicConsume: " + e.getMessage()); - } - } - - @Override - public void basicCancel(Channel channel, String consumerTag) { - try { - ChannelState channelState = channelState(channel); - channelState.lock.lock(); - try { - channelState(channel).consumersWithManualAck.remove(consumerTag); - } finally { - channelState.lock.unlock(); - } - } catch(Exception e) { - LOGGER.info("Error while computing metrics in basicCancel: " + e.getMessage()); - } - } - - @Override - public void consumedMessage(Channel channel, long deliveryTag, boolean autoAck) { - try { - markConsumedMessage(); - if(!autoAck) { - ChannelState channelState = channelState(channel); - channelState.lock.lock(); - try { - channelState(channel).unackedMessageDeliveryTags.add(deliveryTag); - } finally { - channelState.lock.unlock(); - } - } - } catch(Exception e) { - LOGGER.info("Error while computing metrics in consumedMessage: " + e.getMessage()); - } - } - - @Override - public void consumedMessage(Channel channel, long deliveryTag, String consumerTag) { - try { - markConsumedMessage(); - ChannelState channelState = channelState(channel); - channelState.lock.lock(); - try { - if(channelState.consumersWithManualAck.contains(consumerTag)) { - channelState.unackedMessageDeliveryTags.add(deliveryTag); - } - } finally { - channelState.lock.unlock(); - } - } catch(Exception e) { - LOGGER.info("Error while computing metrics in consumedMessage: " + e.getMessage()); - } - } - - @Override - public void basicAck(Channel channel, long deliveryTag, boolean multiple) { - try { - updateChannelStateAfterAckReject(channel, deliveryTag, multiple, markAcknowledgedMessageAction); - } catch(Exception e) { - LOGGER.info("Error while computing metrics in basicAck: " + e.getMessage()); - } - } - - @Override - public void basicNack(Channel channel, long deliveryTag) { - try { - updateChannelStateAfterAckReject(channel, deliveryTag, true, markRejectedMessageAction); - } catch(Exception e) { - LOGGER.info("Error while computing metrics in basicNack: " + e.getMessage()); - } - } - - @Override - public void basicReject(Channel channel, long deliveryTag) { - try { - updateChannelStateAfterAckReject(channel, deliveryTag, false, markRejectedMessageAction); - } catch(Exception e) { - LOGGER.info("Error while computing metrics in basicReject: " + e.getMessage()); - } - } - - private void updateChannelStateAfterAckReject(Channel channel, long deliveryTag, boolean multiple, Runnable action) { - ChannelState channelState = channelState(channel); - channelState.lock.lock(); - try { - if(multiple) { - Iterator iterator = channelState.unackedMessageDeliveryTags.iterator(); - while(iterator.hasNext()) { - long messageDeliveryTag = iterator.next(); - if(messageDeliveryTag <= deliveryTag) { - iterator.remove(); - action.run(); - } - } - } else { - channelState.unackedMessageDeliveryTags.remove(deliveryTag); - action.run(); - } - } finally { - channelState.lock.unlock(); - } - } - - private ConnectionState connectionState(Connection connection) { - return connectionState.get(connection.getId()); - } - - private ChannelState channelState(Channel channel) { - return connectionState(channel.getConnection()).channelState.get(channel.getChannelNumber()); - } - - /** - * Clean inner state for close connections and channels. - * Inner state is automatically cleaned on connection - * and channel closing. - * Thus, this method is provided as a safety net, to be externally - * called periodically if closing of resources wouldn't work - * properly for some corner cases. - */ - public void cleanStaleState() { - try { - Iterator> connectionStateIterator = connectionState.entrySet().iterator(); - while(connectionStateIterator.hasNext()) { - Map.Entry connectionEntry = connectionStateIterator.next(); - Connection connection = connectionEntry.getValue().connection; - if(connection.isOpen()) { - Iterator> channelStateIterator = connectionEntry.getValue().channelState.entrySet().iterator(); - while(channelStateIterator.hasNext()) { - Map.Entry channelStateEntry = channelStateIterator.next(); - Channel channel = channelStateEntry.getValue().channel; - if(!channel.isOpen()) { - channelStateIterator.remove(); - decrementChannelCount(channel); - LOGGER.info("Ripped off state of channel {} of connection {}. This is abnormal, please report.", - channel.getChannelNumber(), connection.getId()); - } - } - } else { - connectionStateIterator.remove(); - decrementConnectionCount(connection); - for(int i = 0; i < connectionEntry.getValue().channelState.size(); i++) { - decrementChannelCount(null); - } - LOGGER.info("Ripped off state of connection {}. This is abnormal, please report.", - connection.getId()); - } - } - } catch(Exception e) { - LOGGER.info("Error during periodic clean of metricsCollector: "+e.getMessage()); - } - } - - private static class ConnectionState { - - final ConcurrentMap channelState = new ConcurrentHashMap(); - final Connection connection; - - private ConnectionState(Connection connection) { - this.connection = connection; - } - } - - private static class ChannelState { - - final Lock lock = new ReentrantLock(); - - final Set unackedMessageDeliveryTags = new HashSet(); - final Set consumersWithManualAck = new HashSet(); - - final Channel channel; - - private ChannelState(Channel channel) { - this.channel = channel; - } - - } - - /** - * Increments connection count. - * The connection object is passed in as complementary information - * and without any guarantee of not being null. - * @param connection the connection that has been created (can be null) - */ - protected abstract void incrementConnectionCount(Connection connection); - - /** - * Decrements connection count. - * The connection object is passed in as complementary information - * and without any guarantee of not being null. - * @param connection the connection that has been closed (can be null) - */ - protected abstract void decrementConnectionCount(Connection connection); - - /** - * Increments channel count. - * The channel object is passed in as complementary information - * and without any guarantee of not being null. - * @param channel the channel that has been created (can be null) - */ - protected abstract void incrementChannelCount(Channel channel); - - /** - * Decrements channel count. - * The channel object is passed in as complementary information - * and without any guarantee of not being null. - * @param channel - */ - protected abstract void decrementChannelCount(Channel channel); - - /** - * Marks the event of a published message. - */ - protected abstract void markPublishedMessage(); - - /** - * Marks the event of a consumed message. - */ - protected abstract void markConsumedMessage(); - - /** - * Marks the event of an acknowledged message. - */ - protected abstract void markAcknowledgedMessage(); - - /** - * Marks the event of a rejected message. - */ - protected abstract void markRejectedMessage(); - - - -} diff --git a/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java index 08a3939f24..d3ee261878 100644 --- a/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java @@ -18,9 +18,15 @@ import com.codahale.metrics.Counter; import com.codahale.metrics.Meter; import com.codahale.metrics.MetricRegistry; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.MetricsCollector; +import com.rabbitmq.client.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; /** * Dropwizard Metrics implementation of {@link MetricsCollector}. @@ -31,7 +37,11 @@ * * @see MetricsCollector */ -public class StandardMetricsCollector extends AbstractMetricsCollector { +public class StandardMetricsCollector implements MetricsCollector { + + private static final Logger LOGGER = LoggerFactory.getLogger(StandardMetricsCollector.class); + + private final ConcurrentMap connectionState = new ConcurrentHashMap(); private final MetricRegistry registry; @@ -62,46 +72,261 @@ public StandardMetricsCollector(MetricRegistry metricRegistry) { } @Override - protected void incrementConnectionCount(Connection connection) { - connections.inc(); + public void newConnection(final Connection connection) { + try { + if(connection.getId() == null) { + connection.setId(UUID.randomUUID().toString()); + } + connections.inc(); + connectionState.put(connection.getId(), new ConnectionState(connection)); + connection.addShutdownListener(new ShutdownListener() { + @Override + public void shutdownCompleted(ShutdownSignalException cause) { + closeConnection(connection); + } + }); + } catch(Exception e) { + LOGGER.info("Error while computing metrics in newConnection: " + e.getMessage()); + } + } + + @Override + public void closeConnection(Connection connection) { + try { + ConnectionState removed = connectionState.remove(connection.getId()); + if(removed != null) { + connections.dec(); + } + } catch(Exception e) { + LOGGER.info("Error while computing metrics in closeConnection: " + e.getMessage()); + } + } + + @Override + public void newChannel(final Channel channel) { + try { + channels.inc(); + channel.addShutdownListener(new ShutdownListener() { + @Override + public void shutdownCompleted(ShutdownSignalException cause) { + closeChannel(channel); + } + }); + connectionState(channel.getConnection()).channelState.put(channel.getChannelNumber(), new ChannelState(channel)); + } catch(Exception e) { + LOGGER.info("Error while computing metrics in newChannel: " + e.getMessage()); + } + } + + @Override + public void closeChannel(Channel channel) { + try { + ChannelState removed = connectionState(channel.getConnection()).channelState.remove(channel.getChannelNumber()); + if(removed != null) { + channels.dec(); + } + } catch(Exception e) { + LOGGER.info("Error while computing metrics in closeChannel: " + e.getMessage()); + } } @Override - protected void decrementConnectionCount(Connection connection) { - connections.dec(); + public void basicPublish(Channel channel) { + try { + publishedMessages.mark(); + } catch(Exception e) { + LOGGER.info("Error while computing metrics in basicPublish: " + e.getMessage()); + } } @Override - protected void incrementChannelCount(Channel channel) { - channels.inc(); + public void basicConsume(Channel channel, String consumerTag, boolean autoAck) { + try { + if(!autoAck) { + ChannelState channelState = channelState(channel); + channelState.lock.lock(); + try { + channelState(channel).consumersWithManualAck.add(consumerTag); + } finally { + channelState.lock.unlock(); + } + } + } catch(Exception e) { + LOGGER.info("Error while computing metrics in basicConsume: " + e.getMessage()); + } } @Override - protected void decrementChannelCount(Channel channel) { - channels.dec(); + public void basicCancel(Channel channel, String consumerTag) { + try { + ChannelState channelState = channelState(channel); + channelState.lock.lock(); + try { + channelState(channel).consumersWithManualAck.remove(consumerTag); + } finally { + channelState.lock.unlock(); + } + } catch(Exception e) { + LOGGER.info("Error while computing metrics in basicCancel: " + e.getMessage()); + } } @Override - protected void markPublishedMessage() { - publishedMessages.mark(); + public void consumedMessage(Channel channel, long deliveryTag, boolean autoAck) { + try { + consumedMessages.mark(); + if(!autoAck) { + ChannelState channelState = channelState(channel); + channelState.lock.lock(); + try { + channelState(channel).unackedMessageDeliveryTags.add(deliveryTag); + } finally { + channelState.lock.unlock(); + } + } + } catch(Exception e) { + LOGGER.info("Error while computing metrics in consumedMessage: " + e.getMessage()); + } } @Override - protected void markConsumedMessage() { - consumedMessages.mark(); + public void consumedMessage(Channel channel, long deliveryTag, String consumerTag) { + try { + consumedMessages.mark(); + ChannelState channelState = channelState(channel); + channelState.lock.lock(); + try { + if(channelState.consumersWithManualAck.contains(consumerTag)) { + channelState.unackedMessageDeliveryTags.add(deliveryTag); + } + } finally { + channelState.lock.unlock(); + } + } catch(Exception e) { + LOGGER.info("Error while computing metrics in consumedMessage: " + e.getMessage()); + } } @Override - protected void markAcknowledgedMessage() { - acknowledgedMessages.mark(); + public void basicAck(Channel channel, long deliveryTag, boolean multiple) { + try { + updateChannelStateAfterAckReject(channel, deliveryTag, multiple, acknowledgedMessages); + } catch(Exception e) { + LOGGER.info("Error while computing metrics in basicAck: " + e.getMessage()); + } } @Override - protected void markRejectedMessage() { - rejectedMessages.mark(); + public void basicNack(Channel channel, long deliveryTag) { + try { + updateChannelStateAfterAckReject(channel, deliveryTag, true, rejectedMessages); + } catch(Exception e) { + LOGGER.info("Error while computing metrics in basicNack: " + e.getMessage()); + } + } + + @Override + public void basicReject(Channel channel, long deliveryTag) { + try { + updateChannelStateAfterAckReject(channel, deliveryTag, false, rejectedMessages); + } catch(Exception e) { + LOGGER.info("Error while computing metrics in basicReject: " + e.getMessage()); + } + } + + private void updateChannelStateAfterAckReject(Channel channel, long deliveryTag, boolean multiple, Meter meter) { + ChannelState channelState = channelState(channel); + channelState.lock.lock(); + try { + if(multiple) { + Iterator iterator = channelState.unackedMessageDeliveryTags.iterator(); + while(iterator.hasNext()) { + long messageDeliveryTag = iterator.next(); + if(messageDeliveryTag <= deliveryTag) { + iterator.remove(); + meter.mark(); + } + } + } else { + channelState.unackedMessageDeliveryTags.remove(deliveryTag); + meter.mark(); + } + } finally { + channelState.lock.unlock(); + } + } + + private ConnectionState connectionState(Connection connection) { + return connectionState.get(connection.getId()); + } + + private ChannelState channelState(Channel channel) { + return connectionState(channel.getConnection()).channelState.get(channel.getChannelNumber()); + } + + /** + * Clean inner state for close connections and channels. + * Inner state is automatically cleaned on connection + * and channel closing. + * Thus, this method is provided as a safety net, to be externally + * called periodically if closing of resources wouldn't work + * properly for some corner cases. + */ + public void cleanStaleState() { + try { + Iterator> connectionStateIterator = connectionState.entrySet().iterator(); + while(connectionStateIterator.hasNext()) { + Map.Entry connectionEntry = connectionStateIterator.next(); + Connection connection = connectionEntry.getValue().connection; + if(connection.isOpen()) { + Iterator> channelStateIterator = connectionEntry.getValue().channelState.entrySet().iterator(); + while(channelStateIterator.hasNext()) { + Map.Entry channelStateEntry = channelStateIterator.next(); + Channel channel = channelStateEntry.getValue().channel; + if(!channel.isOpen()) { + channelStateIterator.remove(); + channels.dec(); + LOGGER.info("Ripped off state of channel {} of connection {}. This is abnormal, please report.", + channel.getChannelNumber(), connection.getId()); + } + } + } else { + connectionStateIterator.remove(); + connections.dec(); + channels.dec(connectionEntry.getValue().channelState.size()); + LOGGER.info("Ripped off state of connection {}. This is abnormal, please report.", + connection.getId()); + } + } + } catch(Exception e) { + LOGGER.info("Error during periodic clean of metricsCollector: "+e.getMessage()); + } + } + + private static class ConnectionState { + + final ConcurrentMap channelState = new ConcurrentHashMap(); + final Connection connection; + + private ConnectionState(Connection connection) { + this.connection = connection; + } } + private static class ChannelState { + + final Lock lock = new ReentrantLock(); + final Set unackedMessageDeliveryTags = new HashSet(); + final Set consumersWithManualAck = new HashSet(); + + final Channel channel; + + private ChannelState(Channel channel) { + this.channel = channel; + } + + } public MetricRegistry getMetricRegistry() { return registry; From d5bdfa789aff5e69744e343e3d40690567c02a83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 6 Dec 2016 09:53:41 +0100 Subject: [PATCH 0399/2114] Revert "Revert "Create abstract class for metrics collection"" This reverts commit 99c751fbebaa9f1f5ff8956ba012d6263cba29f9. Re-apply the introduction of an abstract class for metrics collection on 4.1. --- .../client/impl/AbstractMetricsCollector.java | 370 ++++++++++++++++++ .../client/impl/StandardMetricsCollector.java | 265 +------------ 2 files changed, 390 insertions(+), 245 deletions(-) create mode 100644 src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java diff --git a/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java new file mode 100644 index 0000000000..2b2bb1e35c --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java @@ -0,0 +1,370 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl; + +import com.rabbitmq.client.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +/** + * Base class for {@link MetricsCollector}. + * Implements tricky logic such as keeping track of acknowledged and + * rejected messages. Sub-classes just need to implement + * the logic to increment their metrics. + * Note transactions are not supported (see {@link MetricsCollector}. + * + * @see MetricsCollector + */ +public abstract class AbstractMetricsCollector implements MetricsCollector { + + private static final Logger LOGGER = LoggerFactory.getLogger(AbstractMetricsCollector.class); + + private final ConcurrentMap connectionState = new ConcurrentHashMap(); + + private final Runnable markAcknowledgedMessageAction = new Runnable() { + @Override + public void run() { + markAcknowledgedMessage(); + } + }; + + private final Runnable markRejectedMessageAction = new Runnable() { + @Override + public void run() { + markRejectedMessage(); + } + }; + + @Override + public void newConnection(final Connection connection) { + try { + if(connection.getId() == null) { + connection.setId(UUID.randomUUID().toString()); + } + incrementConnectionCount(connection); + connectionState.put(connection.getId(), new ConnectionState(connection)); + connection.addShutdownListener(new ShutdownListener() { + @Override + public void shutdownCompleted(ShutdownSignalException cause) { + closeConnection(connection); + } + }); + } catch(Exception e) { + LOGGER.info("Error while computing metrics in newConnection: " + e.getMessage()); + } + } + + @Override + public void closeConnection(Connection connection) { + try { + ConnectionState removed = connectionState.remove(connection.getId()); + if(removed != null) { + decrementConnectionCount(connection); + } + } catch(Exception e) { + LOGGER.info("Error while computing metrics in closeConnection: " + e.getMessage()); + } + } + + @Override + public void newChannel(final Channel channel) { + try { + incrementChannelCount(channel); + channel.addShutdownListener(new ShutdownListener() { + @Override + public void shutdownCompleted(ShutdownSignalException cause) { + closeChannel(channel); + } + }); + connectionState(channel.getConnection()).channelState.put(channel.getChannelNumber(), new ChannelState(channel)); + } catch(Exception e) { + LOGGER.info("Error while computing metrics in newChannel: " + e.getMessage()); + } + } + + @Override + public void closeChannel(Channel channel) { + try { + ChannelState removed = connectionState(channel.getConnection()).channelState.remove(channel.getChannelNumber()); + if(removed != null) { + decrementChannelCount(channel); + } + } catch(Exception e) { + LOGGER.info("Error while computing metrics in closeChannel: " + e.getMessage()); + } + } + + @Override + public void basicPublish(Channel channel) { + try { + markPublishedMessage(); + } catch(Exception e) { + LOGGER.info("Error while computing metrics in basicPublish: " + e.getMessage()); + } + } + + @Override + public void basicConsume(Channel channel, String consumerTag, boolean autoAck) { + try { + if(!autoAck) { + ChannelState channelState = channelState(channel); + channelState.lock.lock(); + try { + channelState(channel).consumersWithManualAck.add(consumerTag); + } finally { + channelState.lock.unlock(); + } + } + } catch(Exception e) { + LOGGER.info("Error while computing metrics in basicConsume: " + e.getMessage()); + } + } + + @Override + public void basicCancel(Channel channel, String consumerTag) { + try { + ChannelState channelState = channelState(channel); + channelState.lock.lock(); + try { + channelState(channel).consumersWithManualAck.remove(consumerTag); + } finally { + channelState.lock.unlock(); + } + } catch(Exception e) { + LOGGER.info("Error while computing metrics in basicCancel: " + e.getMessage()); + } + } + + @Override + public void consumedMessage(Channel channel, long deliveryTag, boolean autoAck) { + try { + markConsumedMessage(); + if(!autoAck) { + ChannelState channelState = channelState(channel); + channelState.lock.lock(); + try { + channelState(channel).unackedMessageDeliveryTags.add(deliveryTag); + } finally { + channelState.lock.unlock(); + } + } + } catch(Exception e) { + LOGGER.info("Error while computing metrics in consumedMessage: " + e.getMessage()); + } + } + + @Override + public void consumedMessage(Channel channel, long deliveryTag, String consumerTag) { + try { + markConsumedMessage(); + ChannelState channelState = channelState(channel); + channelState.lock.lock(); + try { + if(channelState.consumersWithManualAck.contains(consumerTag)) { + channelState.unackedMessageDeliveryTags.add(deliveryTag); + } + } finally { + channelState.lock.unlock(); + } + } catch(Exception e) { + LOGGER.info("Error while computing metrics in consumedMessage: " + e.getMessage()); + } + } + + @Override + public void basicAck(Channel channel, long deliveryTag, boolean multiple) { + try { + updateChannelStateAfterAckReject(channel, deliveryTag, multiple, markAcknowledgedMessageAction); + } catch(Exception e) { + LOGGER.info("Error while computing metrics in basicAck: " + e.getMessage()); + } + } + + @Override + public void basicNack(Channel channel, long deliveryTag) { + try { + updateChannelStateAfterAckReject(channel, deliveryTag, true, markRejectedMessageAction); + } catch(Exception e) { + LOGGER.info("Error while computing metrics in basicNack: " + e.getMessage()); + } + } + + @Override + public void basicReject(Channel channel, long deliveryTag) { + try { + updateChannelStateAfterAckReject(channel, deliveryTag, false, markRejectedMessageAction); + } catch(Exception e) { + LOGGER.info("Error while computing metrics in basicReject: " + e.getMessage()); + } + } + + private void updateChannelStateAfterAckReject(Channel channel, long deliveryTag, boolean multiple, Runnable action) { + ChannelState channelState = channelState(channel); + channelState.lock.lock(); + try { + if(multiple) { + Iterator iterator = channelState.unackedMessageDeliveryTags.iterator(); + while(iterator.hasNext()) { + long messageDeliveryTag = iterator.next(); + if(messageDeliveryTag <= deliveryTag) { + iterator.remove(); + action.run(); + } + } + } else { + channelState.unackedMessageDeliveryTags.remove(deliveryTag); + action.run(); + } + } finally { + channelState.lock.unlock(); + } + } + + private ConnectionState connectionState(Connection connection) { + return connectionState.get(connection.getId()); + } + + private ChannelState channelState(Channel channel) { + return connectionState(channel.getConnection()).channelState.get(channel.getChannelNumber()); + } + + /** + * Clean inner state for close connections and channels. + * Inner state is automatically cleaned on connection + * and channel closing. + * Thus, this method is provided as a safety net, to be externally + * called periodically if closing of resources wouldn't work + * properly for some corner cases. + */ + public void cleanStaleState() { + try { + Iterator> connectionStateIterator = connectionState.entrySet().iterator(); + while(connectionStateIterator.hasNext()) { + Map.Entry connectionEntry = connectionStateIterator.next(); + Connection connection = connectionEntry.getValue().connection; + if(connection.isOpen()) { + Iterator> channelStateIterator = connectionEntry.getValue().channelState.entrySet().iterator(); + while(channelStateIterator.hasNext()) { + Map.Entry channelStateEntry = channelStateIterator.next(); + Channel channel = channelStateEntry.getValue().channel; + if(!channel.isOpen()) { + channelStateIterator.remove(); + decrementChannelCount(channel); + LOGGER.info("Ripped off state of channel {} of connection {}. This is abnormal, please report.", + channel.getChannelNumber(), connection.getId()); + } + } + } else { + connectionStateIterator.remove(); + decrementConnectionCount(connection); + for(int i = 0; i < connectionEntry.getValue().channelState.size(); i++) { + decrementChannelCount(null); + } + LOGGER.info("Ripped off state of connection {}. This is abnormal, please report.", + connection.getId()); + } + } + } catch(Exception e) { + LOGGER.info("Error during periodic clean of metricsCollector: "+e.getMessage()); + } + } + + private static class ConnectionState { + + final ConcurrentMap channelState = new ConcurrentHashMap(); + final Connection connection; + + private ConnectionState(Connection connection) { + this.connection = connection; + } + } + + private static class ChannelState { + + final Lock lock = new ReentrantLock(); + + final Set unackedMessageDeliveryTags = new HashSet(); + final Set consumersWithManualAck = new HashSet(); + + final Channel channel; + + private ChannelState(Channel channel) { + this.channel = channel; + } + + } + + /** + * Increments connection count. + * The connection object is passed in as complementary information + * and without any guarantee of not being null. + * @param connection the connection that has been created (can be null) + */ + protected abstract void incrementConnectionCount(Connection connection); + + /** + * Decrements connection count. + * The connection object is passed in as complementary information + * and without any guarantee of not being null. + * @param connection the connection that has been closed (can be null) + */ + protected abstract void decrementConnectionCount(Connection connection); + + /** + * Increments channel count. + * The channel object is passed in as complementary information + * and without any guarantee of not being null. + * @param channel the channel that has been created (can be null) + */ + protected abstract void incrementChannelCount(Channel channel); + + /** + * Decrements channel count. + * The channel object is passed in as complementary information + * and without any guarantee of not being null. + * @param channel + */ + protected abstract void decrementChannelCount(Channel channel); + + /** + * Marks the event of a published message. + */ + protected abstract void markPublishedMessage(); + + /** + * Marks the event of a consumed message. + */ + protected abstract void markConsumedMessage(); + + /** + * Marks the event of an acknowledged message. + */ + protected abstract void markAcknowledgedMessage(); + + /** + * Marks the event of a rejected message. + */ + protected abstract void markRejectedMessage(); + + + +} diff --git a/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java index d3ee261878..08a3939f24 100644 --- a/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java @@ -18,15 +18,9 @@ import com.codahale.metrics.Counter; import com.codahale.metrics.Meter; import com.codahale.metrics.MetricRegistry; -import com.rabbitmq.client.*; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.MetricsCollector; /** * Dropwizard Metrics implementation of {@link MetricsCollector}. @@ -37,11 +31,7 @@ * * @see MetricsCollector */ -public class StandardMetricsCollector implements MetricsCollector { - - private static final Logger LOGGER = LoggerFactory.getLogger(StandardMetricsCollector.class); - - private final ConcurrentMap connectionState = new ConcurrentHashMap(); +public class StandardMetricsCollector extends AbstractMetricsCollector { private final MetricRegistry registry; @@ -72,261 +62,46 @@ public StandardMetricsCollector(MetricRegistry metricRegistry) { } @Override - public void newConnection(final Connection connection) { - try { - if(connection.getId() == null) { - connection.setId(UUID.randomUUID().toString()); - } - connections.inc(); - connectionState.put(connection.getId(), new ConnectionState(connection)); - connection.addShutdownListener(new ShutdownListener() { - @Override - public void shutdownCompleted(ShutdownSignalException cause) { - closeConnection(connection); - } - }); - } catch(Exception e) { - LOGGER.info("Error while computing metrics in newConnection: " + e.getMessage()); - } - } - - @Override - public void closeConnection(Connection connection) { - try { - ConnectionState removed = connectionState.remove(connection.getId()); - if(removed != null) { - connections.dec(); - } - } catch(Exception e) { - LOGGER.info("Error while computing metrics in closeConnection: " + e.getMessage()); - } - } - - @Override - public void newChannel(final Channel channel) { - try { - channels.inc(); - channel.addShutdownListener(new ShutdownListener() { - @Override - public void shutdownCompleted(ShutdownSignalException cause) { - closeChannel(channel); - } - }); - connectionState(channel.getConnection()).channelState.put(channel.getChannelNumber(), new ChannelState(channel)); - } catch(Exception e) { - LOGGER.info("Error while computing metrics in newChannel: " + e.getMessage()); - } - } - - @Override - public void closeChannel(Channel channel) { - try { - ChannelState removed = connectionState(channel.getConnection()).channelState.remove(channel.getChannelNumber()); - if(removed != null) { - channels.dec(); - } - } catch(Exception e) { - LOGGER.info("Error while computing metrics in closeChannel: " + e.getMessage()); - } + protected void incrementConnectionCount(Connection connection) { + connections.inc(); } @Override - public void basicPublish(Channel channel) { - try { - publishedMessages.mark(); - } catch(Exception e) { - LOGGER.info("Error while computing metrics in basicPublish: " + e.getMessage()); - } + protected void decrementConnectionCount(Connection connection) { + connections.dec(); } @Override - public void basicConsume(Channel channel, String consumerTag, boolean autoAck) { - try { - if(!autoAck) { - ChannelState channelState = channelState(channel); - channelState.lock.lock(); - try { - channelState(channel).consumersWithManualAck.add(consumerTag); - } finally { - channelState.lock.unlock(); - } - } - } catch(Exception e) { - LOGGER.info("Error while computing metrics in basicConsume: " + e.getMessage()); - } + protected void incrementChannelCount(Channel channel) { + channels.inc(); } @Override - public void basicCancel(Channel channel, String consumerTag) { - try { - ChannelState channelState = channelState(channel); - channelState.lock.lock(); - try { - channelState(channel).consumersWithManualAck.remove(consumerTag); - } finally { - channelState.lock.unlock(); - } - } catch(Exception e) { - LOGGER.info("Error while computing metrics in basicCancel: " + e.getMessage()); - } + protected void decrementChannelCount(Channel channel) { + channels.dec(); } @Override - public void consumedMessage(Channel channel, long deliveryTag, boolean autoAck) { - try { - consumedMessages.mark(); - if(!autoAck) { - ChannelState channelState = channelState(channel); - channelState.lock.lock(); - try { - channelState(channel).unackedMessageDeliveryTags.add(deliveryTag); - } finally { - channelState.lock.unlock(); - } - } - } catch(Exception e) { - LOGGER.info("Error while computing metrics in consumedMessage: " + e.getMessage()); - } + protected void markPublishedMessage() { + publishedMessages.mark(); } @Override - public void consumedMessage(Channel channel, long deliveryTag, String consumerTag) { - try { - consumedMessages.mark(); - ChannelState channelState = channelState(channel); - channelState.lock.lock(); - try { - if(channelState.consumersWithManualAck.contains(consumerTag)) { - channelState.unackedMessageDeliveryTags.add(deliveryTag); - } - } finally { - channelState.lock.unlock(); - } - } catch(Exception e) { - LOGGER.info("Error while computing metrics in consumedMessage: " + e.getMessage()); - } + protected void markConsumedMessage() { + consumedMessages.mark(); } @Override - public void basicAck(Channel channel, long deliveryTag, boolean multiple) { - try { - updateChannelStateAfterAckReject(channel, deliveryTag, multiple, acknowledgedMessages); - } catch(Exception e) { - LOGGER.info("Error while computing metrics in basicAck: " + e.getMessage()); - } + protected void markAcknowledgedMessage() { + acknowledgedMessages.mark(); } @Override - public void basicNack(Channel channel, long deliveryTag) { - try { - updateChannelStateAfterAckReject(channel, deliveryTag, true, rejectedMessages); - } catch(Exception e) { - LOGGER.info("Error while computing metrics in basicNack: " + e.getMessage()); - } - } - - @Override - public void basicReject(Channel channel, long deliveryTag) { - try { - updateChannelStateAfterAckReject(channel, deliveryTag, false, rejectedMessages); - } catch(Exception e) { - LOGGER.info("Error while computing metrics in basicReject: " + e.getMessage()); - } - } - - private void updateChannelStateAfterAckReject(Channel channel, long deliveryTag, boolean multiple, Meter meter) { - ChannelState channelState = channelState(channel); - channelState.lock.lock(); - try { - if(multiple) { - Iterator iterator = channelState.unackedMessageDeliveryTags.iterator(); - while(iterator.hasNext()) { - long messageDeliveryTag = iterator.next(); - if(messageDeliveryTag <= deliveryTag) { - iterator.remove(); - meter.mark(); - } - } - } else { - channelState.unackedMessageDeliveryTags.remove(deliveryTag); - meter.mark(); - } - } finally { - channelState.lock.unlock(); - } - } - - private ConnectionState connectionState(Connection connection) { - return connectionState.get(connection.getId()); - } - - private ChannelState channelState(Channel channel) { - return connectionState(channel.getConnection()).channelState.get(channel.getChannelNumber()); - } - - /** - * Clean inner state for close connections and channels. - * Inner state is automatically cleaned on connection - * and channel closing. - * Thus, this method is provided as a safety net, to be externally - * called periodically if closing of resources wouldn't work - * properly for some corner cases. - */ - public void cleanStaleState() { - try { - Iterator> connectionStateIterator = connectionState.entrySet().iterator(); - while(connectionStateIterator.hasNext()) { - Map.Entry connectionEntry = connectionStateIterator.next(); - Connection connection = connectionEntry.getValue().connection; - if(connection.isOpen()) { - Iterator> channelStateIterator = connectionEntry.getValue().channelState.entrySet().iterator(); - while(channelStateIterator.hasNext()) { - Map.Entry channelStateEntry = channelStateIterator.next(); - Channel channel = channelStateEntry.getValue().channel; - if(!channel.isOpen()) { - channelStateIterator.remove(); - channels.dec(); - LOGGER.info("Ripped off state of channel {} of connection {}. This is abnormal, please report.", - channel.getChannelNumber(), connection.getId()); - } - } - } else { - connectionStateIterator.remove(); - connections.dec(); - channels.dec(connectionEntry.getValue().channelState.size()); - LOGGER.info("Ripped off state of connection {}. This is abnormal, please report.", - connection.getId()); - } - } - } catch(Exception e) { - LOGGER.info("Error during periodic clean of metricsCollector: "+e.getMessage()); - } - } - - private static class ConnectionState { - - final ConcurrentMap channelState = new ConcurrentHashMap(); - final Connection connection; - - private ConnectionState(Connection connection) { - this.connection = connection; - } + protected void markRejectedMessage() { + rejectedMessages.mark(); } - private static class ChannelState { - - final Lock lock = new ReentrantLock(); - final Set unackedMessageDeliveryTags = new HashSet(); - final Set consumersWithManualAck = new HashSet(); - - final Channel channel; - - private ChannelState(Channel channel) { - this.channel = channel; - } - - } public MetricRegistry getMetricRegistry() { return registry; From 25576af4b4fa3eecde02b1f8a8d09165b4983567 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 8 Dec 2016 17:53:14 +0100 Subject: [PATCH 0400/2114] Remove QueueingConsumer usages in some tests References #213 --- .../test/functional/ConnectionRecovery.java | 2 +- .../test/functional/DeadLetterExchange.java | 1 - .../client/test/functional/DirectReplyTo.java | 51 +++++++++++++------ 3 files changed, 37 insertions(+), 17 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java index 6a1c796a72..17a01db042 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -378,7 +378,7 @@ public void queueRecovered(String oldName, String newName) { for(int i = 0; i < 5000; i++) { String q = UUID.randomUUID().toString(); ch.queueDeclare(q, false, false, true, null); - QueueingConsumer dummy = new QueueingConsumer(ch); + DefaultConsumer dummy = new DefaultConsumer(ch); String tag = ch.basicConsume(q, true, dummy); ch.basicCancel(tag); } diff --git a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java index f0a35bee7a..af7e48abcf 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java @@ -17,7 +17,6 @@ import com.rabbitmq.client.*; import com.rabbitmq.client.AMQP.BasicProperties; -import com.rabbitmq.client.QueueingConsumer.Delivery; import com.rabbitmq.client.test.BrokerTestCase; import org.junit.Test; diff --git a/src/test/java/com/rabbitmq/client/test/functional/DirectReplyTo.java b/src/test/java/com/rabbitmq/client/test/functional/DirectReplyTo.java index 06b3d9e3b4..1573c5f4c4 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DirectReplyTo.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DirectReplyTo.java @@ -22,34 +22,32 @@ import static org.junit.Assert.assertTrue; import java.io.IOException; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; +import com.rabbitmq.client.*; import org.junit.Test; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.GetResponse; -import com.rabbitmq.client.MessageProperties; -import com.rabbitmq.client.QueueingConsumer; import com.rabbitmq.client.test.BrokerTestCase; public class DirectReplyTo extends BrokerTestCase { private static final String QUEUE = "amq.rabbitmq.reply-to"; @Test public void roundTrip() throws IOException, InterruptedException { - QueueingConsumer c = new QueueingConsumer(channel); + QueueMessageConsumer c = new QueueMessageConsumer(channel); String replyTo = rpcFirstHalf(c); declare(connection, replyTo, true); channel.confirmSelect(); basicPublishVolatile("response".getBytes(), "", replyTo, MessageProperties.BASIC); channel.waitForConfirms(); - QueueingConsumer.Delivery del = c.nextDelivery(); - assertEquals("response", new String(del.getBody())); + byte[] body = c.nextDelivery(10000); + assertEquals("response", new String(body)); } @Test public void hack() throws IOException, InterruptedException { - QueueingConsumer c = new QueueingConsumer(channel); + QueueMessageConsumer c = new QueueMessageConsumer(channel); String replyTo = rpcFirstHalf(c); // 5 chars should overwrite part of the key but not the pid; aiming to prove // we can't publish using just the pid @@ -57,8 +55,8 @@ public class DirectReplyTo extends BrokerTestCase { declare(connection, replyTo, false); basicPublishVolatile("response".getBytes(), "", replyTo, MessageProperties.BASIC); - QueueingConsumer.Delivery del = c.nextDelivery(500); - assertNull(del); + byte[] body = c.nextDelivery(500); + assertNull(body); } private void declare(Connection connection, String q, boolean expectedExists) throws IOException { @@ -75,7 +73,7 @@ private void declare(Connection connection, String q, boolean expectedExists) th } @Test public void consumeFail() throws IOException, InterruptedException { - QueueingConsumer c = new QueueingConsumer(channel); + DefaultConsumer c = new DefaultConsumer(channel); Channel ch = connection.createChannel(); try { ch.basicConsume(QUEUE, false, c); @@ -95,7 +93,7 @@ private void declare(Connection connection, String q, boolean expectedExists) th } @Test public void consumeSuccess() throws IOException, InterruptedException { - QueueingConsumer c = new QueueingConsumer(channel); + DefaultConsumer c = new DefaultConsumer(channel); String ctag = channel.basicConsume(QUEUE, true, c); channel.basicCancel(ctag); @@ -104,7 +102,7 @@ private void declare(Connection connection, String q, boolean expectedExists) th assertNotSame(ctag, ctag2); } - private String rpcFirstHalf(QueueingConsumer c) throws IOException { + private String rpcFirstHalf(Consumer c) throws IOException { channel.basicConsume(QUEUE, true, c); String serverQueue = channel.queueDeclare().getQueue(); basicPublishVolatile("request".getBytes(), "", serverQueue, props()); @@ -116,4 +114,27 @@ private String rpcFirstHalf(QueueingConsumer c) throws IOException { private AMQP.BasicProperties props() { return MessageProperties.BASIC.builder().replyTo(QUEUE).build(); } + + class QueueMessageConsumer extends DefaultConsumer { + + BlockingQueue messages = new LinkedBlockingQueue(); + + public QueueMessageConsumer(Channel channel) { + super(channel); + } + + @Override + public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { + messages.add(body); + } + + byte[] nextDelivery() { + return messages.poll(); + } + + byte[] nextDelivery(long timeoutInMs) throws InterruptedException { + return messages.poll(timeoutInMs, TimeUnit.MILLISECONDS); + } + + } } From 9ef9733bfa5d9bf1f2ca7156fb4323b9e910b69f Mon Sep 17 00:00:00 2001 From: Daniel Hakim Date: Fri, 9 Dec 2016 17:43:07 -0500 Subject: [PATCH 0401/2114] BlockingCell now consistently uses System.nanoTime rather than sometimes using System.currentTimeMillis --- src/main/java/com/rabbitmq/utility/BlockingCell.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/rabbitmq/utility/BlockingCell.java b/src/main/java/com/rabbitmq/utility/BlockingCell.java index 68068fa3ff..7e2d1e46d4 100644 --- a/src/main/java/com/rabbitmq/utility/BlockingCell.java +++ b/src/main/java/com/rabbitmq/utility/BlockingCell.java @@ -66,9 +66,9 @@ public synchronized T get(long timeout) throws InterruptedException, TimeoutExce if (timeout < 0) throw new AssertionError("Timeout cannot be less than zero"); - long maxTime = System.currentTimeMillis() + timeout; - long now; - while (!_filled && (now = System.currentTimeMillis()) < maxTime) { + long now = System.nanoTime() / NANOS_IN_MILLI; + long maxTime = now + timeout; + while (!_filled && (now = (System.nanoTime() / NANOS_IN_MILLI)) < maxTime) { wait(maxTime - now); } From 6a086ffd66f4634d94dff8f72d00ad8af99edcb4 Mon Sep 17 00:00:00 2001 From: Daniel Hakim Date: Fri, 9 Dec 2016 18:04:51 -0500 Subject: [PATCH 0402/2114] BlockingCell's uninterruptibleGet calls now restore the interrupt flag if interrupted during their execution. --- .../com/rabbitmq/utility/BlockingCell.java | 39 ++++++++++++------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/rabbitmq/utility/BlockingCell.java b/src/main/java/com/rabbitmq/utility/BlockingCell.java index 7e2d1e46d4..393a7525bb 100644 --- a/src/main/java/com/rabbitmq/utility/BlockingCell.java +++ b/src/main/java/com/rabbitmq/utility/BlockingCell.java @@ -83,12 +83,19 @@ public synchronized T get(long timeout) throws InterruptedException, TimeoutExce * @return the waited-for value */ public synchronized T uninterruptibleGet() { - while (true) { - try { - return get(); - } catch (InterruptedException ex) { - // no special handling necessary + boolean wasInterrupted = false; + try { + while (true) { + try { + return get(); + } catch (InterruptedException ex) { + // no special handling necessary + wasInterrupted = true; + } } + } finally { + if (wasInterrupted) + Thread.currentThread().interrupt(); } } @@ -104,14 +111,20 @@ public synchronized T uninterruptibleGet() { public synchronized T uninterruptibleGet(int timeout) throws TimeoutException { long now = System.nanoTime() / NANOS_IN_MILLI; long runTime = now + timeout; - - do { - try { - return get(runTime - now); - } catch (InterruptedException e) { - // Ignore. - } - } while ((timeout == INFINITY) || ((now = System.nanoTime() / NANOS_IN_MILLI) < runTime)); + boolean wasInterrupted = false; + try { + do { + try { + return get(runTime - now); + } catch (InterruptedException e) { + // Ignore. + wasInterrupted = true; + } + } while ((timeout == INFINITY) || ((now = System.nanoTime() / NANOS_IN_MILLI) < runTime)); + } finally { + if (wasInterrupted) + Thread.currentThread().interrupt(); + } throw new TimeoutException(); } From 669877fa6cc4e02a9aad78ce9b802bcebf1ac979 Mon Sep 17 00:00:00 2001 From: Daniel Hakim Date: Fri, 9 Dec 2016 18:19:36 -0500 Subject: [PATCH 0403/2114] If someone had managed to somehow interrupt the private thread running in SingleShotLinearTimer, it would busy wait out the rest of its remaining time. Now it goes back to sleep, then restores the interrupt flag. Shouldn't be possible outside of a debugger either way. --- .../utility/SingleShotLinearTimer.java | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/rabbitmq/utility/SingleShotLinearTimer.java b/src/main/java/com/rabbitmq/utility/SingleShotLinearTimer.java index 1f1f6ca0ba..b3f7400860 100644 --- a/src/main/java/com/rabbitmq/utility/SingleShotLinearTimer.java +++ b/src/main/java/com/rabbitmq/utility/SingleShotLinearTimer.java @@ -72,21 +72,27 @@ public TimerThread(long timeoutMillisec) { public void run() { try { long now; - while ((now = System.nanoTime() / NANOS_IN_MILLI) < _runTime) { - if (_task == null) break; + boolean wasInterrupted = false; + try { + while ((now = System.nanoTime() / NANOS_IN_MILLI) < _runTime) { + if (_task == null) break; - try { - synchronized(this) { - wait(_runTime - now); + try { + synchronized(this) { + wait(_runTime - now); + } + } catch (InterruptedException e) { + wasInterrupted = true; } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); } + } finally { + if (wasInterrupted) + Thread.currentThread().interrupt(); } Runnable task = _task; if (task != null) { - task.run(); + task.run(); } } finally { From 965a6a5763a198922e0ca4226e77723d3041d82e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 12 Dec 2016 17:17:42 +0100 Subject: [PATCH 0404/2114] Formatting --- src/main/java/com/rabbitmq/utility/BlockingCell.java | 9 ++++++--- .../java/com/rabbitmq/utility/SingleShotLinearTimer.java | 5 ++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/rabbitmq/utility/BlockingCell.java b/src/main/java/com/rabbitmq/utility/BlockingCell.java index 393a7525bb..94b40ef4cf 100644 --- a/src/main/java/com/rabbitmq/utility/BlockingCell.java +++ b/src/main/java/com/rabbitmq/utility/BlockingCell.java @@ -63,8 +63,9 @@ public synchronized T get() throws InterruptedException { public synchronized T get(long timeout) throws InterruptedException, TimeoutException { if (timeout == INFINITY) return get(); - if (timeout < 0) + if (timeout < 0) { throw new AssertionError("Timeout cannot be less than zero"); + } long now = System.nanoTime() / NANOS_IN_MILLI; long maxTime = now + timeout; @@ -94,8 +95,9 @@ public synchronized T uninterruptibleGet() { } } } finally { - if (wasInterrupted) + if (wasInterrupted) { Thread.currentThread().interrupt(); + } } } @@ -122,8 +124,9 @@ public synchronized T uninterruptibleGet(int timeout) throws TimeoutException { } } while ((timeout == INFINITY) || ((now = System.nanoTime() / NANOS_IN_MILLI) < runTime)); } finally { - if (wasInterrupted) + if (wasInterrupted) { Thread.currentThread().interrupt(); + } } throw new TimeoutException(); diff --git a/src/main/java/com/rabbitmq/utility/SingleShotLinearTimer.java b/src/main/java/com/rabbitmq/utility/SingleShotLinearTimer.java index b3f7400860..bef801229c 100644 --- a/src/main/java/com/rabbitmq/utility/SingleShotLinearTimer.java +++ b/src/main/java/com/rabbitmq/utility/SingleShotLinearTimer.java @@ -31,7 +31,10 @@ * package-private. * * We currently just use this to time the quiescing RPC in AMQChannel. - * + * + * Will be removed in next major release. + * + * @deprecated * @see AMQChannel */ From 289cd053b5cebed01c0b36fc8d7db254d4ebbec7 Mon Sep 17 00:00:00 2001 From: Tobias Knell Date: Wed, 21 Dec 2016 12:01:17 +0100 Subject: [PATCH 0405/2114] close InputStream of version.properties in ClientVersion after reading --- .../com/rabbitmq/client/impl/ClientVersion.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/ClientVersion.java b/src/main/java/com/rabbitmq/client/impl/ClientVersion.java index 33ba8d61fa..12fed8ca6d 100644 --- a/src/main/java/com/rabbitmq/client/impl/ClientVersion.java +++ b/src/main/java/com/rabbitmq/client/impl/ClientVersion.java @@ -16,6 +16,7 @@ package com.rabbitmq.client.impl; import java.io.IOException; +import java.io.InputStream; import java.util.Properties; /** @@ -28,10 +29,18 @@ public class ClientVersion { static { version = new Properties(); + InputStream inputStream = ClientVersion.class.getClassLoader() + .getResourceAsStream("version.properties"); try { - version.load(ClientVersion.class.getClassLoader() - .getResourceAsStream("version.properties")); + version.load(inputStream); } catch (IOException e) { + } finally { + try { + if(inputStream!=null) { + inputStream.close(); + } + } catch (IOException e) { + } } VERSION = version.getProperty("com.rabbitmq.client.version", From 5ce334499d53de84d81569d975fd18521925fd2a Mon Sep 17 00:00:00 2001 From: Tobias Knell Date: Wed, 21 Dec 2016 14:47:35 +0100 Subject: [PATCH 0406/2114] formatting in ClientVersion --- src/main/java/com/rabbitmq/client/impl/ClientVersion.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/impl/ClientVersion.java b/src/main/java/com/rabbitmq/client/impl/ClientVersion.java index 12fed8ca6d..18aece8eaf 100644 --- a/src/main/java/com/rabbitmq/client/impl/ClientVersion.java +++ b/src/main/java/com/rabbitmq/client/impl/ClientVersion.java @@ -36,7 +36,7 @@ public class ClientVersion { } catch (IOException e) { } finally { try { - if(inputStream!=null) { + if(inputStream != null) { inputStream.close(); } } catch (IOException e) { From 99e421ea0e5732706940cff804602ddee17ee0aa Mon Sep 17 00:00:00 2001 From: Tobias Knell Date: Wed, 21 Dec 2016 12:01:17 +0100 Subject: [PATCH 0407/2114] close InputStream of version.properties in ClientVersion after reading --- .../com/rabbitmq/client/impl/ClientVersion.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/ClientVersion.java b/src/main/java/com/rabbitmq/client/impl/ClientVersion.java index 33ba8d61fa..12fed8ca6d 100644 --- a/src/main/java/com/rabbitmq/client/impl/ClientVersion.java +++ b/src/main/java/com/rabbitmq/client/impl/ClientVersion.java @@ -16,6 +16,7 @@ package com.rabbitmq.client.impl; import java.io.IOException; +import java.io.InputStream; import java.util.Properties; /** @@ -28,10 +29,18 @@ public class ClientVersion { static { version = new Properties(); + InputStream inputStream = ClientVersion.class.getClassLoader() + .getResourceAsStream("version.properties"); try { - version.load(ClientVersion.class.getClassLoader() - .getResourceAsStream("version.properties")); + version.load(inputStream); } catch (IOException e) { + } finally { + try { + if(inputStream!=null) { + inputStream.close(); + } + } catch (IOException e) { + } } VERSION = version.getProperty("com.rabbitmq.client.version", From 67626d96a0f83419011d7dcc013b54c5d1f3a9dd Mon Sep 17 00:00:00 2001 From: Tobias Knell Date: Wed, 21 Dec 2016 14:47:35 +0100 Subject: [PATCH 0408/2114] formatting in ClientVersion --- src/main/java/com/rabbitmq/client/impl/ClientVersion.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/impl/ClientVersion.java b/src/main/java/com/rabbitmq/client/impl/ClientVersion.java index 12fed8ca6d..18aece8eaf 100644 --- a/src/main/java/com/rabbitmq/client/impl/ClientVersion.java +++ b/src/main/java/com/rabbitmq/client/impl/ClientVersion.java @@ -36,7 +36,7 @@ public class ClientVersion { } catch (IOException e) { } finally { try { - if(inputStream!=null) { + if(inputStream != null) { inputStream.close(); } } catch (IOException e) { From 09391c38692d3ce9af3f9dc26e316334706b15e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 23 Dec 2016 09:42:43 +0100 Subject: [PATCH 0409/2114] Add integration test for topic authorisation References rabbitmq/rabbitmq-server#505 --- .../client/test/server/ServerTests.java | 2 +- .../client/test/server/TopicPermissions.java | 114 ++++++++++++++++++ 2 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 src/test/java/com/rabbitmq/client/test/server/TopicPermissions.java diff --git a/src/test/java/com/rabbitmq/client/test/server/ServerTests.java b/src/test/java/com/rabbitmq/client/test/server/ServerTests.java index 2478b72994..bf8631a4b8 100644 --- a/src/test/java/com/rabbitmq/client/test/server/ServerTests.java +++ b/src/test/java/com/rabbitmq/client/test/server/ServerTests.java @@ -40,7 +40,7 @@ LoopbackUsers.class, XDeathHeaderGrowth.class, PriorityQueues.class, - + TopicPermissions.class }) public class ServerTests { diff --git a/src/test/java/com/rabbitmq/client/test/server/TopicPermissions.java b/src/test/java/com/rabbitmq/client/test/server/TopicPermissions.java new file mode 100644 index 0000000000..0525676d76 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/server/TopicPermissions.java @@ -0,0 +1,114 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.test.server; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.AlreadyClosedException; +import com.rabbitmq.client.BuiltinExchangeType; +import com.rabbitmq.client.test.BrokerTestCase; +import com.rabbitmq.tools.Host; +import org.junit.Test; + +import java.io.IOException; +import java.util.concurrent.Callable; +import java.util.concurrent.TimeoutException; + +import static org.junit.Assert.fail; + +public class TopicPermissions extends BrokerTestCase { + + String protectedTopic = "protected.topic"; + String notProtectedTopic = "not.protected.topic"; + String noneTopicExchange = "not.a.topic"; + + @Override + protected void createResources() throws IOException, TimeoutException { + channel.exchangeDeclare(protectedTopic, BuiltinExchangeType.TOPIC); + channel.exchangeDeclare(notProtectedTopic, BuiltinExchangeType.TOPIC); + channel.exchangeDeclare(noneTopicExchange, BuiltinExchangeType.DIRECT); + + Host.rabbitmqctl("set_topic_permissions -p / guest " + protectedTopic + " \"^a\""); + Host.rabbitmqctl("set_topic_permissions -p / guest " + noneTopicExchange + " \"^a\""); + } + + @Override + protected void releaseResources() throws IOException { + channel.exchangeDelete(protectedTopic); + channel.exchangeDelete(notProtectedTopic); + channel.exchangeDelete(noneTopicExchange); + + Host.rabbitmqctl("clear_topic_permissions -p / guest"); + } + + @Test + public void topicPermissions() throws IOException { + assertAccessOk("Routing key matches on protected topic, should pass", new Callable() { + @Override + public Void call() throws Exception { + channel.basicPublish(protectedTopic, "a.b.c", null, "content".getBytes()); + channel.basicQos(0); + return null; + } + }); + assertAccessRefused("Routing key does not match on protected topic, should not pass", new Callable() { + @Override + public Void call() throws Exception { + channel.basicPublish(protectedTopic, "b.c", null, "content".getBytes()); + channel.basicQos(0); + return null; + } + }); + assertAccessOk("Message sent on not-protected exchange, should pass", new Callable() { + @Override + public Void call() throws Exception { + channel.basicPublish(notProtectedTopic, "a.b.c", null, "content".getBytes()); + channel.basicQos(0); + return null; + } + }); + assertAccessOk("Routing key does not match on protected exchange, but not a topic, should pass", new Callable() { + @Override + public Void call() throws Exception { + channel.basicPublish(noneTopicExchange, "b.c", null, "content".getBytes()); + channel.basicQos(0); + return null; + } + }); + } + + void assertAccessOk(String description, Callable action) { + try { + action.call(); + } catch(Exception e) { + fail(description + "(" + e.getMessage()+")"); + } + } + + void assertAccessRefused(String description, Callable action) throws IOException { + try { + action.call(); + fail(description); + } catch (IOException e) { + checkShutdownSignal(AMQP.ACCESS_REFUSED, e); + openChannel(); + } catch (AlreadyClosedException e) { + checkShutdownSignal(AMQP.ACCESS_REFUSED, e); + openChannel(); + } catch(Exception e) { + fail("Unexpected exception: " + e.getMessage()); + } + } +} From a3f0c2878ba02d43399ed2f6ac33256685c58833 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 28 Dec 2016 15:29:12 +0100 Subject: [PATCH 0410/2114] Make test failure message clearer --- .../java/com/rabbitmq/client/test/server/TopicPermissions.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/client/test/server/TopicPermissions.java b/src/test/java/com/rabbitmq/client/test/server/TopicPermissions.java index 0525676d76..85e63704fa 100644 --- a/src/test/java/com/rabbitmq/client/test/server/TopicPermissions.java +++ b/src/test/java/com/rabbitmq/client/test/server/TopicPermissions.java @@ -93,7 +93,7 @@ void assertAccessOk(String description, Callable action) { try { action.call(); } catch(Exception e) { - fail(description + "(" + e.getMessage()+")"); + fail(description + " (" + e.getMessage()+")"); } } From aa93b13eb46fe39e6eb0afe83fe64809bd9436d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 2 Jan 2017 16:31:42 +0100 Subject: [PATCH 0411/2114] Emit a warning in NullTrustManager Fixes #230 --- .../java/com/rabbitmq/client/NullTrustManager.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/main/java/com/rabbitmq/client/NullTrustManager.java b/src/main/java/com/rabbitmq/client/NullTrustManager.java index 69f37f6806..4aa0779219 100644 --- a/src/main/java/com/rabbitmq/client/NullTrustManager.java +++ b/src/main/java/com/rabbitmq/client/NullTrustManager.java @@ -16,6 +16,8 @@ package com.rabbitmq.client; +import org.slf4j.LoggerFactory; + import java.security.cert.X509Certificate; import javax.net.ssl.X509TrustManager; @@ -25,6 +27,15 @@ * Trusts every single certificate presented to it. */ public class NullTrustManager implements X509TrustManager { + + public NullTrustManager() { + LoggerFactory.getLogger(NullTrustManager.class).warn( + "This trust manager trusts every certificate, making peer hostname verification disabled. " + + "This is convenient for local development but prone to man-in-the-middle attacks. " + + "Please see http://www.rabbitmq.com/ssl.html#validating-cerficates to validate server certificates." + ); + } + /** * Doesn't even bother looking at its arguments, simply returns, * which makes the check succeed. From fd672dfc440b4b59bfd3b29756db4ea9b3afb789 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 2 Jan 2017 16:37:37 +0100 Subject: [PATCH 0412/2114] Deprecate NullTrustManager Introduce TrustEverythingTrustManager. Fixes #234 --- .../rabbitmq/client/ConnectionFactory.java | 2 +- .../com/rabbitmq/client/NullTrustManager.java | 5 ++ .../client/TrustEverythingTrustManager.java | 63 +++++++++++++++++++ 3 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/rabbitmq/client/TrustEverythingTrustManager.java diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 25fa5a8fdc..2851d5e28b 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -576,7 +576,7 @@ public void useSslProtocol() public void useSslProtocol(String protocol) throws NoSuchAlgorithmException, KeyManagementException { - useSslProtocol(protocol, new NullTrustManager()); + useSslProtocol(protocol, new TrustEverythingTrustManager()); } /** diff --git a/src/main/java/com/rabbitmq/client/NullTrustManager.java b/src/main/java/com/rabbitmq/client/NullTrustManager.java index 4aa0779219..7041505eec 100644 --- a/src/main/java/com/rabbitmq/client/NullTrustManager.java +++ b/src/main/java/com/rabbitmq/client/NullTrustManager.java @@ -25,6 +25,11 @@ /** * Convenience class providing a default implementation of javax.net.ssl.X509TrustManager. * Trusts every single certificate presented to it. + * + * Deprecated, use {@link TrustEverythingTrustManager} instead. + * Will be removed in next major release. + * + * @deprecated */ public class NullTrustManager implements X509TrustManager { diff --git a/src/main/java/com/rabbitmq/client/TrustEverythingTrustManager.java b/src/main/java/com/rabbitmq/client/TrustEverythingTrustManager.java new file mode 100644 index 0000000000..3e44acf00a --- /dev/null +++ b/src/main/java/com/rabbitmq/client/TrustEverythingTrustManager.java @@ -0,0 +1,63 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + + +package com.rabbitmq.client; + +import org.slf4j.LoggerFactory; + +import javax.net.ssl.X509TrustManager; +import java.security.cert.X509Certificate; + +/** + * Convenience class providing a default implementation of javax.net.ssl.X509TrustManager. + * Trusts every single certificate presented to it. + */ +public class TrustEverythingTrustManager implements X509TrustManager { + + public TrustEverythingTrustManager() { + LoggerFactory.getLogger(TrustEverythingTrustManager.class).warn( + "This trust manager trusts every certificate, making peer hostname verification disabled. " + + "This is convenient for local development but prone to man-in-the-middle attacks. " + + "Please see http://www.rabbitmq.com/ssl.html#validating-cerficates to validate server certificates." + ); + } + + /** + * Doesn't even bother looking at its arguments, simply returns, + * which makes the check succeed. + */ + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) { + // Do nothing. + } + + /** + * Doesn't even bother looking at its arguments, simply returns, + * which makes the check succeed. + */ + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) { + // Do nothing. + } + + /** + * Always returns an empty array of X509Certificates. + */ + @Override + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } +} From cf46a69c4fe83fbfb2853fefbad07597fdf6b66a Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Tue, 3 Jan 2017 00:35:53 +0800 Subject: [PATCH 0413/2114] Wording --- src/main/java/com/rabbitmq/client/NullTrustManager.java | 4 ++-- .../java/com/rabbitmq/client/TrustEverythingTrustManager.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/NullTrustManager.java b/src/main/java/com/rabbitmq/client/NullTrustManager.java index 7041505eec..b99d252615 100644 --- a/src/main/java/com/rabbitmq/client/NullTrustManager.java +++ b/src/main/java/com/rabbitmq/client/NullTrustManager.java @@ -35,9 +35,9 @@ public class NullTrustManager implements X509TrustManager { public NullTrustManager() { LoggerFactory.getLogger(NullTrustManager.class).warn( - "This trust manager trusts every certificate, making peer hostname verification disabled. " + + "This trust manager trusts every certificate, effectively disabling peer verification. " + "This is convenient for local development but prone to man-in-the-middle attacks. " + - "Please see http://www.rabbitmq.com/ssl.html#validating-cerficates to validate server certificates." + "Please see http://www.rabbitmq.com/ssl.html#validating-cerficates to learn more about peer certificate validation." ); } diff --git a/src/main/java/com/rabbitmq/client/TrustEverythingTrustManager.java b/src/main/java/com/rabbitmq/client/TrustEverythingTrustManager.java index 3e44acf00a..d4f7e5dae6 100644 --- a/src/main/java/com/rabbitmq/client/TrustEverythingTrustManager.java +++ b/src/main/java/com/rabbitmq/client/TrustEverythingTrustManager.java @@ -29,9 +29,9 @@ public class TrustEverythingTrustManager implements X509TrustManager { public TrustEverythingTrustManager() { LoggerFactory.getLogger(TrustEverythingTrustManager.class).warn( - "This trust manager trusts every certificate, making peer hostname verification disabled. " + + "This trust manager trusts every certificate, effectively disabling peer verification. " + "This is convenient for local development but prone to man-in-the-middle attacks. " + - "Please see http://www.rabbitmq.com/ssl.html#validating-cerficates to validate server certificates." + "Please see http://www.rabbitmq.com/ssl.html#validating-cerficates to learn more about peer certificate validation." ); } From 67bfbb23b9addb27edf601486fa9529063e80a7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 3 Jan 2017 15:25:26 +0100 Subject: [PATCH 0414/2114] Add optional NIO tweak point in tests --- .../java/com/rabbitmq/client/test/BrokerTestCase.java | 8 ++++++++ .../client/test/server/PersistenceGuarantees.java | 9 +++++++++ 2 files changed, 17 insertions(+) diff --git a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java index 991c248a7c..0a860ec8bc 100644 --- a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java +++ b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java @@ -17,6 +17,7 @@ package com.rabbitmq.client.test; import com.rabbitmq.client.*; +import com.rabbitmq.client.impl.nio.NioParams; import com.rabbitmq.tools.Host; import org.junit.After; import org.junit.Before; @@ -60,10 +61,17 @@ protected void finished(Description description) { protected ConnectionFactory newConnectionFactory() { ConnectionFactory connectionFactory = TestUtils.connectionFactory(); + if(TestUtils.USE_NIO) { + connectionFactory.setNioParams(nioParams()); + } connectionFactory.setAutomaticRecoveryEnabled(isAutomaticRecoveryEnabled()); return connectionFactory; } + protected NioParams nioParams() { + return new NioParams(); + } + protected boolean isAutomaticRecoveryEnabled() { return true; } diff --git a/src/test/java/com/rabbitmq/client/test/server/PersistenceGuarantees.java b/src/test/java/com/rabbitmq/client/test/server/PersistenceGuarantees.java index a627abf6dd..904ec69d68 100644 --- a/src/test/java/com/rabbitmq/client/test/server/PersistenceGuarantees.java +++ b/src/test/java/com/rabbitmq/client/test/server/PersistenceGuarantees.java @@ -19,6 +19,7 @@ import java.io.IOException; +import com.rabbitmq.client.impl.nio.NioParams; import org.junit.Test; import com.rabbitmq.client.MessageProperties; @@ -28,6 +29,14 @@ public class PersistenceGuarantees extends BrokerTestCase { private static final int COUNT = 10000; private String queue; + @Override + protected NioParams nioParams() { + NioParams nioParams = super.nioParams(); + // may need a higher enqueuing timeout on slow environments + return nioParams + .setWriteEnqueuingTimeoutInMs(nioParams.getWriteEnqueuingTimeoutInMs() * 2); + } + protected void declareQueue() throws IOException { queue = channel.queueDeclare("", true, false, false, null).getQueue(); } From acff50c6753c28efa9fd250940fd6a185f3178b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 3 Jan 2017 16:27:01 +0100 Subject: [PATCH 0415/2114] [maven-release-plugin] prepare release v4.0.1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 54fd6beb05..0991f9813a 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.0.1-SNAPSHOT + 4.0.1 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v4.0.1 From df0418838f87e5733f3740bbd22b2eceb73d47d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 3 Jan 2017 16:27:12 +0100 Subject: [PATCH 0416/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 0991f9813a..757bb00e8f 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.0.1 + 4.0.2-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v4.0.1 + HEAD From 0a8a947818d226ec7c35e06610224b3a5e610fbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 3 Jan 2017 16:49:10 +0100 Subject: [PATCH 0417/2114] Update version to 4.0.1 in README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index de668e008a..04076926f5 100644 --- a/README.md +++ b/README.md @@ -23,14 +23,14 @@ These versions can still be used with RabbitMQ server `3.x`. com.rabbitmq amqp-client - 4.0.0 + 4.0.1 ``` ### Gradle ``` groovy -compile 'com.rabbitmq:amqp-client:4.0.0' +compile 'com.rabbitmq:amqp-client:4.0.1' ``` #### 3.6.x Series From 0e60f7bf96206dfb4b60cc8fc1fe0c92498f35ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 16 Jan 2017 14:53:01 +0100 Subject: [PATCH 0418/2114] Handle AssertionError in NioLoop Fixes #237 --- src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java b/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java index cbc387fd33..ef0e357a53 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java @@ -78,6 +78,9 @@ public void run() { state.getConnection().handleHeartbeatFailure(); } catch (Exception e) { LOGGER.warn("Error after heartbeat failure of connection {}", state.getConnection()); + } catch (AssertionError e) { + // see https://github.com/rabbitmq/rabbitmq-java-client/issues/237 + LOGGER.warn("Assertion error after heartbeat failure of connection {}", state.getConnection()); } finally { selectionKey.cancel(); } From 9317d48d07051c0cea82c3ba4b4c5a511fc71c75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 16 Jan 2017 17:29:04 +0100 Subject: [PATCH 0419/2114] Handle AssertionError in conn error dispatching References #237 --- src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java b/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java index ef0e357a53..1873b25f17 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java @@ -280,7 +280,11 @@ protected void dispatchIoErrorToConnection(final SocketChannelFrameHandlerState @Override public void run() { - state.getConnection().handleIoError(ex); + try { + state.getConnection().handleIoError(ex); + } catch(AssertionError e) { + LOGGER.warn("Assertion error during error dispatching to connection: " + e.getMessage()); + } } }; if (executorService() == null) { From c75c5958c1cd92865ffeaca33abda186d972d551 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 17 Jan 2017 16:38:04 +0100 Subject: [PATCH 0420/2114] [maven-release-plugin] prepare release v4.0.2.RC1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 757bb00e8f..52f773e7b2 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.0.2-SNAPSHOT + 4.0.2.RC1 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v4.0.2.RC1 From 0f169720b2e0dff9dba4370a7ed173ab1c88092a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 17 Jan 2017 16:38:13 +0100 Subject: [PATCH 0421/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 52f773e7b2..757bb00e8f 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.0.2.RC1 + 4.0.2-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v4.0.2.RC1 + HEAD From 5296842c45b691ea9370ec4ccce6d1a66b63f3ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 20 Jan 2017 14:29:10 +0100 Subject: [PATCH 0422/2114] [maven-release-plugin] prepare release v4.0.2 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 757bb00e8f..b54f269ff2 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.0.2-SNAPSHOT + 4.0.2 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v4.0.2 From f8d52a180f25f79cb45d26af9a94dcc872ff11ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 20 Jan 2017 14:29:18 +0100 Subject: [PATCH 0423/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index b54f269ff2..5a30aee211 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.0.2 + 4.0.3-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v4.0.2 + HEAD From 482fa7355c06c0da6c44726997b3b59d342e597f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 20 Jan 2017 15:36:43 +0100 Subject: [PATCH 0424/2114] Set version to 4.0.2 in readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 04076926f5..e6219790b9 100644 --- a/README.md +++ b/README.md @@ -23,14 +23,14 @@ These versions can still be used with RabbitMQ server `3.x`. com.rabbitmq amqp-client - 4.0.1 + 4.0.2 ``` ### Gradle ``` groovy -compile 'com.rabbitmq:amqp-client:4.0.1' +compile 'com.rabbitmq:amqp-client:4.0.2' ``` #### 3.6.x Series From 9cca417d34ad6f1f7769020c248e9072adf62458 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 23 Jan 2017 10:28:53 +0100 Subject: [PATCH 0425/2114] Add read to topic permission test Part of rabbitmq/rabbitmq-server#1085 --- .../com/rabbitmq/client/test/server/TopicPermissions.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/server/TopicPermissions.java b/src/test/java/com/rabbitmq/client/test/server/TopicPermissions.java index 85e63704fa..8882b124dc 100644 --- a/src/test/java/com/rabbitmq/client/test/server/TopicPermissions.java +++ b/src/test/java/com/rabbitmq/client/test/server/TopicPermissions.java @@ -40,8 +40,8 @@ protected void createResources() throws IOException, TimeoutException { channel.exchangeDeclare(notProtectedTopic, BuiltinExchangeType.TOPIC); channel.exchangeDeclare(noneTopicExchange, BuiltinExchangeType.DIRECT); - Host.rabbitmqctl("set_topic_permissions -p / guest " + protectedTopic + " \"^a\""); - Host.rabbitmqctl("set_topic_permissions -p / guest " + noneTopicExchange + " \"^a\""); + Host.rabbitmqctl("set_topic_permissions -p / guest " + protectedTopic + " \"^a\" \"^b\""); + Host.rabbitmqctl("set_topic_permissions -p / guest " + noneTopicExchange + " \"^a\" \"^b\""); } @Override From 9c26ff518a0c828a8273544e1b16ea357d9930a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 27 Jan 2017 16:22:47 +0100 Subject: [PATCH 0426/2114] Remove QueueingConsumer usages in some tests References #213 --- .../test/functional/NoRequeueOnCancel.java | 18 +++++++++++----- .../test/functional/QueueLifecycle.java | 16 +++++++------- .../client/test/functional/Recover.java | 21 +++++++++++++------ 3 files changed, 36 insertions(+), 19 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java b/src/test/java/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java index 4e5fc0770a..c7b220e660 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java +++ b/src/test/java/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java @@ -18,12 +18,15 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import java.io.IOException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import com.rabbitmq.client.*; import org.junit.Test; -import com.rabbitmq.client.QueueingConsumer; import com.rabbitmq.client.test.BrokerTestCase; public class NoRequeueOnCancel extends BrokerTestCase @@ -43,11 +46,16 @@ protected void releaseResources() throws IOException { { channel.basicPublish("", Q, null, "1".getBytes()); - QueueingConsumer c; - - c = new QueueingConsumer(channel); + final CountDownLatch latch = new CountDownLatch(1); + Consumer c = new DefaultConsumer(channel) { + @Override + public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { + latch.countDown(); + } + }; String consumerTag = channel.basicConsume(Q, false, c); - c.nextDelivery(); + assertTrue(latch.await(5, TimeUnit.SECONDS)); + channel.basicCancel(consumerTag); assertNull(channel.basicGet(Q, true)); diff --git a/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java b/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java index 7de96205b3..77c5e6df92 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java @@ -16,18 +16,18 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.fail; +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Consumer; +import com.rabbitmq.client.DefaultConsumer; +import com.rabbitmq.client.test.BrokerTestCase; +import org.junit.Test; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeoutException; -import org.junit.Test; - -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.QueueingConsumer; -import com.rabbitmq.client.test.BrokerTestCase; +import static org.junit.Assert.fail; /** * Test queue auto-delete and exclusive semantics. @@ -125,7 +125,7 @@ void verifyNotEquivalent(boolean durable, boolean exclusive, channel.queueDeclare(name, false, false, true, null); // now it's there verifyQueue(name, false, false, true, null); - QueueingConsumer consumer = new QueueingConsumer(channel); + Consumer consumer = new DefaultConsumer(channel); String consumerTag = channel.basicConsume(name, consumer); channel.basicCancel(consumerTag); // now it's not .. we hope @@ -143,7 +143,7 @@ void verifyNotEquivalent(boolean durable, boolean exclusive, channel.queueDeclare(name, false, true, false, null); // now it's there verifyQueue(name, false, true, false, null); - QueueingConsumer consumer = new QueueingConsumer(channel); + Consumer consumer = new DefaultConsumer(channel); String consumerTag = channel.basicConsume(name, consumer); channel.basicCancel(consumerTag); // and still there, because exclusive no longer implies autodelete diff --git a/src/test/java/com/rabbitmq/client/test/functional/Recover.java b/src/test/java/com/rabbitmq/client/test/functional/Recover.java index bb1e858c83..0d764cc6b1 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Recover.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Recover.java @@ -23,12 +23,13 @@ import java.io.IOException; import java.util.Arrays; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; +import com.rabbitmq.client.*; import org.junit.Test; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.QueueingConsumer; import com.rabbitmq.client.test.BrokerTestCase; public class Recover extends BrokerTestCase { @@ -67,12 +68,20 @@ void verifyRedeliverOnRecover(RecoverCallback call) void verifyNoRedeliveryWithAutoAck(RecoverCallback call) throws IOException, InterruptedException { - QueueingConsumer consumer = new QueueingConsumer(channel); + final CountDownLatch latch = new CountDownLatch(1); + final AtomicReference bodyReference = new AtomicReference(); + Consumer consumer = new DefaultConsumer(channel) { + @Override + public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { + bodyReference.set(body); + latch.countDown(); + } + }; channel.basicConsume(queue, true, consumer); // auto ack. channel.basicPublish("", queue, new AMQP.BasicProperties.Builder().build(), body); - QueueingConsumer.Delivery delivery = consumer.nextDelivery(); + assertTrue(latch.await(5, TimeUnit.SECONDS)); assertTrue("consumed message body not as sent", - Arrays.equals(body, delivery.getBody())); + Arrays.equals(body, bodyReference.get())); call.recover(channel); assertNull("should be no message available", channel.basicGet(queue, true)); } From ea1c521c1ba32901fda1aa19110436fef9a3a545 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 13 Feb 2017 17:40:39 +0100 Subject: [PATCH 0427/2114] [maven-release-plugin] prepare release v4.1.0.RC1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index c278b5d35b..76cf68f5df 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.1.0-SNAPSHOT + 4.1.0.RC1 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v4.1.0.RC1 From 06b6d85688e606747ef19c14d89071fc7ad67218 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 13 Feb 2017 17:40:46 +0100 Subject: [PATCH 0428/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 76cf68f5df..c278b5d35b 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.1.0.RC1 + 4.1.0-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v4.1.0.RC1 + HEAD From 6427eb253b867c1c974de39f1ed213f33f0903a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 15 Feb 2017 16:24:59 +0100 Subject: [PATCH 0429/2114] Add test for topic permission on queue bind/unbind References rabbitmq/rabbitmq-server#1099 --- .../client/test/server/TopicPermissions.java | 37 ++++++++++++++++++- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/server/TopicPermissions.java b/src/test/java/com/rabbitmq/client/test/server/TopicPermissions.java index 8882b124dc..b045780250 100644 --- a/src/test/java/com/rabbitmq/client/test/server/TopicPermissions.java +++ b/src/test/java/com/rabbitmq/client/test/server/TopicPermissions.java @@ -40,8 +40,8 @@ protected void createResources() throws IOException, TimeoutException { channel.exchangeDeclare(notProtectedTopic, BuiltinExchangeType.TOPIC); channel.exchangeDeclare(noneTopicExchange, BuiltinExchangeType.DIRECT); - Host.rabbitmqctl("set_topic_permissions -p / guest " + protectedTopic + " \"^a\" \"^b\""); - Host.rabbitmqctl("set_topic_permissions -p / guest " + noneTopicExchange + " \"^a\" \"^b\""); + Host.rabbitmqctl("set_topic_permissions -p / guest " + protectedTopic + " \"^a\" \"^x\""); + Host.rabbitmqctl("set_topic_permissions -p / guest " + noneTopicExchange + " \"^a\" \"^x\""); } @Override @@ -87,6 +87,39 @@ public Void call() throws Exception { return null; } }); + assertAccessOk("Binding/unbinding on protected exchange with matching routing key, should pass", new Callable() { + @Override + public Void call() throws Exception { + String queue = channel.queueDeclare().getQueue(); + channel.queueBind(queue, protectedTopic, "x.y.z"); + channel.basicQos(0); + channel.queueUnbind(queue, protectedTopic, "x.y.z"); + channel.basicQos(0); + return null; + } + }); + assertAccessRefused("Binding/unbinding on protected exchange with none-matching routing key, should not pass", new Callable() { + @Override + public Void call() throws Exception { + String queue = channel.queueDeclare().getQueue(); + channel.queueBind(queue, protectedTopic, "y.z"); + channel.basicQos(0); + channel.queueUnbind(queue, protectedTopic, "y.z"); + channel.basicQos(0); + return null; + } + }); + assertAccessOk("Binding/unbinding on not-protected exchange with none-matching routing key, should pass", new Callable() { + @Override + public Void call() throws Exception { + String queue = channel.queueDeclare().getQueue(); + channel.queueBind(queue, notProtectedTopic, "y.z"); + channel.basicQos(0); + channel.queueUnbind(queue, notProtectedTopic, "y.z"); + channel.basicQos(0); + return null; + } + }); } void assertAccessOk(String description, Callable action) { From 224d11c222ba603b02da87b72a41c760016708d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 16 Feb 2017 15:18:30 +0100 Subject: [PATCH 0430/2114] Set test log level to WARN --- src/test/resources/logback-test.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml index 4bd2e37606..ee88f442c2 100644 --- a/src/test/resources/logback-test.xml +++ b/src/test/resources/logback-test.xml @@ -5,7 +5,7 @@ - + \ No newline at end of file From be274a26dd45af4f8e8b1264ffdbd02242721345 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 20 Feb 2017 09:50:50 +0100 Subject: [PATCH 0431/2114] [maven-release-plugin] prepare release v4.1.0 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index c278b5d35b..b906ff9adc 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.1.0-SNAPSHOT + 4.1.0 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v4.1.0 From e1a37512d839805a0e8b49d84d24ae8d1dd53e0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 20 Feb 2017 09:50:58 +0100 Subject: [PATCH 0432/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index b906ff9adc..e2fb4a6968 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.1.0 + 4.1.1-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v4.1.0 + HEAD From 6623c5c1ae28dd79e82942e4578dea81b30f8a6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 20 Feb 2017 10:04:07 +0100 Subject: [PATCH 0433/2114] Set version to 4.1.0 in README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e6219790b9..408ac3e489 100644 --- a/README.md +++ b/README.md @@ -23,14 +23,14 @@ These versions can still be used with RabbitMQ server `3.x`. com.rabbitmq amqp-client - 4.0.2 + 4.1.0 ``` ### Gradle ``` groovy -compile 'com.rabbitmq:amqp-client:4.0.2' +compile 'com.rabbitmq:amqp-client:4.1.0' ``` #### 3.6.x Series From 00bd09379169f3f5dd01047c800d4b084569757d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 20 Feb 2017 10:40:59 +0100 Subject: [PATCH 0434/2114] Set POM version to 4.2.0-SNAPSHOT --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e2fb4a6968..04df74cf69 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.1.1-SNAPSHOT + 4.2.0-SNAPSHOT jar RabbitMQ Java Client From 7e3d2418dba8d9e627a2e7535eae88934e4f2746 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 20 Feb 2017 15:40:48 +0100 Subject: [PATCH 0435/2114] Set POM version to 5.0.0-SNAPSHOT, upgrade lib/plugins And Java version is now 1.8. --- pom.xml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/pom.xml b/pom.xml index 04df74cf69..9bd4d4bb65 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.2.0-SNAPSHOT + 5.0.0-SNAPSHOT jar RabbitMQ Java Client @@ -54,13 +54,13 @@ UTF-8 UTF-8 - 1.7.21 + 1.7.23 3.1.2 - 1.1.7 + 1.2.1 1.1 4.12 2.0.0 - 1.10.19 + 2.7.9 6026DFCA - 1.6.4 + 1.6.8 @@ -456,15 +456,6 @@ org.sonatype.plugins nexus-staging-maven-plugin ${nexus-staging-maven-plugin.version} - - - default-deploy - deploy - - deploy - - - ossrh https://oss.sonatype.org/ From 27e1e7f23278eeb817ccc86fdc8fdf86c0369f1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 1 Aug 2017 11:48:09 +0200 Subject: [PATCH 0521/2114] Add executor service argument to Channel#asyncCompletableRpc RPC response comes from the reading threads and this can cause deadlocks if the client doesn't use CompletableFuture#*async methods. References #215 --- .../java/com/rabbitmq/client/Channel.java | 4 ++- .../com/rabbitmq/client/impl/AMQChannel.java | 21 +++++++------ .../com/rabbitmq/client/impl/ChannelN.java | 9 ++---- .../impl/CompletableFutureRpcWrapper.java | 13 ++++++-- .../impl/recovery/AutorecoveringChannel.java | 5 +-- .../ChannelAsyncCompletableFutureTest.java | 31 ++++++++++++++++--- 6 files changed, 57 insertions(+), 26 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/Channel.java b/src/main/java/com/rabbitmq/client/Channel.java index ab99dcf836..a8c4446f50 100644 --- a/src/main/java/com/rabbitmq/client/Channel.java +++ b/src/main/java/com/rabbitmq/client/Channel.java @@ -18,6 +18,7 @@ import java.io.IOException; import java.util.Map; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeoutException; import com.rabbitmq.client.AMQP.BasicProperties; @@ -1367,9 +1368,10 @@ void basicNack(long deliveryTag, boolean multiple, boolean requeue) /** * Asynchronously send a method over this channel. * @param method method to transmit over this channel. + * @param executorService executor used to complete the operation, can be null * @return a completable future that completes when the result is received * @throws IOException Problem transmitting method. */ - CompletableFuture asyncCompletableRpc(Method method) throws IOException; + CompletableFuture asyncCompletableRpc(Method method, ExecutorService executorService) throws IOException; } diff --git a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java index 8de19b7753..39a2a653a4 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java @@ -29,6 +29,7 @@ import java.io.IOException; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeoutException; import java.util.function.Supplier; @@ -145,11 +146,11 @@ public AMQCommand exnWrappingRpc(Method m) } } - public CompletableFuture exnWrappingAsyncRpc(Method m) + public CompletableFuture exnWrappingAsyncRpc(Method m, ExecutorService executorService) throws IOException { try { - return privateAsyncRpc(m); + return privateAsyncRpc(m, executorService); } catch (AlreadyClosedException ace) { // Do not wrap it since it means that connection/channel // was closed in some action in the past @@ -204,8 +205,8 @@ public void enqueueRpc(RpcContinuation k) doEnqueueRpc(() -> new RpcContinuationRpcWrapper(k)); } - public void enqueueAsyncRpc(Method method, CompletableFuture future) { - doEnqueueRpc(() -> new CompletableFutureRpcWrapper(method, future)); + public void enqueueAsyncRpc(Method method, CompletableFuture future, ExecutorService executorService) { + doEnqueueRpc(() -> new CompletableFutureRpcWrapper(method, future, executorService)); } private void doEnqueueRpc(Supplier rpcWrapperSupplier) { @@ -308,11 +309,11 @@ protected ChannelContinuationTimeoutException wrapTimeoutException(final Method return new ChannelContinuationTimeoutException(e, this, this._channelNumber, m); } - private CompletableFuture privateAsyncRpc(Method m) + private CompletableFuture privateAsyncRpc(Method m, ExecutorService executorService) throws IOException, ShutdownSignalException { CompletableFuture future = new CompletableFuture<>(); - asyncRpc(m, future); + asyncRpc(m, future, executorService); return future; } @@ -347,20 +348,20 @@ public void quiescingRpc(Method m, RpcContinuation k) } } - public void asyncRpc(Method m, CompletableFuture future) + public void asyncRpc(Method m, CompletableFuture future, ExecutorService executorService) throws IOException { synchronized (_channelMutex) { ensureIsOpen(); - quiescingAsyncRpc(m, future); + quiescingAsyncRpc(m, future, executorService); } } - public void quiescingAsyncRpc(Method m, CompletableFuture future) + public void quiescingAsyncRpc(Method m, CompletableFuture future, ExecutorService executorService) throws IOException { synchronized (_channelMutex) { - enqueueAsyncRpc(m, future); + enqueueAsyncRpc(m, future, executorService); quiescingTransmit(m); } } diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java index 98a9cb35c3..56ff508372 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelN.java @@ -22,10 +22,7 @@ import java.util.Map; import java.util.SortedSet; import java.util.TreeSet; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeoutException; +import java.util.concurrent.*; import com.rabbitmq.client.ConfirmCallback; import com.rabbitmq.client.*; @@ -1558,8 +1555,8 @@ public AMQCommand rpc(Method method) throws IOException { } @Override - public CompletableFuture asyncCompletableRpc(Method method) throws IOException { - return exnWrappingAsyncRpc(method); + public CompletableFuture asyncCompletableRpc(Method method, ExecutorService executorService) throws IOException { + return exnWrappingAsyncRpc(method, executorService); } @Override diff --git a/src/main/java/com/rabbitmq/client/impl/CompletableFutureRpcWrapper.java b/src/main/java/com/rabbitmq/client/impl/CompletableFutureRpcWrapper.java index c2a3e5c649..41e1457257 100644 --- a/src/main/java/com/rabbitmq/client/impl/CompletableFutureRpcWrapper.java +++ b/src/main/java/com/rabbitmq/client/impl/CompletableFutureRpcWrapper.java @@ -19,6 +19,8 @@ import com.rabbitmq.client.Method; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; /** * @@ -29,9 +31,12 @@ public class CompletableFutureRpcWrapper implements RpcWrapper { private final CompletableFuture completableFuture; - public CompletableFutureRpcWrapper(Method method, CompletableFuture completableFuture) { + private final ExecutorService executorService; + + public CompletableFutureRpcWrapper(Method method, CompletableFuture completableFuture, ExecutorService executorService) { this.request = method; this.completableFuture = completableFuture; + this.executorService = executorService; } @Override @@ -41,7 +46,11 @@ public boolean canHandleReply(AMQCommand command) { @Override public void complete(AMQCommand command) { - completableFuture.complete(command); + if (executorService == null) { + completableFuture.complete(command); + } else { + executorService.submit(() -> completableFuture.complete(command)); + } } @Override diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java index 5c66c38014..b4b468ef09 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java @@ -22,6 +22,7 @@ import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeoutException; /** @@ -897,8 +898,8 @@ void updateConsumerTag(String tag, String newTag) { } @Override - public CompletableFuture asyncCompletableRpc(Method method) throws IOException { - return this.delegate.asyncCompletableRpc(method); + public CompletableFuture asyncCompletableRpc(Method method, ExecutorService executorService) throws IOException { + return this.delegate.asyncCompletableRpc(method, executorService); } @Override diff --git a/src/test/java/com/rabbitmq/client/test/ChannelAsyncCompletableFutureTest.java b/src/test/java/com/rabbitmq/client/test/ChannelAsyncCompletableFutureTest.java index d3beffc25e..898aac894c 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelAsyncCompletableFutureTest.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelAsyncCompletableFutureTest.java @@ -22,16 +22,37 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; import java.util.UUID; -import java.util.concurrent.*; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; import static org.junit.Assert.assertTrue; +@RunWith(Parameterized.class) public class ChannelAsyncCompletableFutureTest extends BrokerTestCase { - ExecutorService executor; + ExecutorService executor, methodArgumentExecutor; + + @Parameterized.Parameters + public static Collection params() { + List executors = new ArrayList<>(); + executors.add(null); + executors.add(Executors.newSingleThreadExecutor()); + return executors; + } + + public ChannelAsyncCompletableFutureTest(ExecutorService methodArgumentExecutor) { + this.methodArgumentExecutor = methodArgumentExecutor; + } String queue; String exchange; @@ -61,7 +82,7 @@ public void async() throws Exception { .arguments(null) .build(); - channel.asyncCompletableRpc(queueDeclare) + channel.asyncCompletableRpc(queueDeclare, null) .thenComposeAsync(action -> { try { return channel.asyncCompletableRpc(new AMQImpl.Exchange.Declare.Builder() @@ -70,7 +91,7 @@ public void async() throws Exception { .durable(false) .autoDelete(false) .arguments(null) - .build()); + .build(), methodArgumentExecutor); } catch (IOException e) { throw new RuntimeException(e); } @@ -81,7 +102,7 @@ public void async() throws Exception { .exchange(exchange) .routingKey("") .arguments(null) - .build()); + .build(), methodArgumentExecutor); } catch (IOException e) { throw new RuntimeException(e); } From 4bc65ca7ba0b6b4db79705c4bcb98e606073e24c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 1 Aug 2017 12:03:39 +0200 Subject: [PATCH 0522/2114] Correctly shutdown executor service in test --- .../client/test/ChannelAsyncCompletableFutureTest.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/java/com/rabbitmq/client/test/ChannelAsyncCompletableFutureTest.java b/src/test/java/com/rabbitmq/client/test/ChannelAsyncCompletableFutureTest.java index 898aac894c..f0b0ae363c 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelAsyncCompletableFutureTest.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelAsyncCompletableFutureTest.java @@ -67,6 +67,9 @@ public ChannelAsyncCompletableFutureTest(ExecutorService methodArgumentExecutor) executor.shutdownNow(); channel.queueDelete(queue); channel.exchangeDelete(exchange); + if (methodArgumentExecutor != null) { + methodArgumentExecutor.shutdownNow(); + } } @Test From abb2b88519e083193e4cac848d45782aec41e019 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 1 Aug 2017 15:39:37 +0200 Subject: [PATCH 0523/2114] Wait in AbsentQueue test in HA mode Looks like there's a small window (10s ms) where the HA queue is not visible from node 1 (after node 2, the owner of the queue, has been stopped). --- .../client/test/server/AbsentQueue.java | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java b/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java index 9f22b14210..6598e7e156 100644 --- a/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java +++ b/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java @@ -22,6 +22,7 @@ import java.io.IOException; import java.util.concurrent.TimeoutException; +import com.rabbitmq.client.Channel; import org.junit.Test; import com.rabbitmq.client.AMQP; @@ -55,7 +56,8 @@ public class AbsentQueue extends ClusteredTestBase { alternateChannel.queueDelete(Q); } - @Test public void notFound() throws IOException { + @Test public void notFound() throws IOException, InterruptedException { + waitPropagationInHa(); assertNotFound(new Task() { public void run() throws IOException { channel.queueDeclare(Q, true, false, false, null); @@ -96,8 +98,26 @@ protected void assertNotFound(Task t) throws IOException { } + private void waitPropagationInHa() throws IOException, InterruptedException { + // can be necessary to wait a bit in HA mode + if (HATests.HA_TESTS_RUNNING) { + long waited = 0; + while(waited < 5000) { + Channel tempChannel = connection.createChannel(); + try { + tempChannel.queueDeclarePassive(Q); + break; + } catch (IOException e) { + + } + Thread.sleep(10); + waited += 10; + } + } + } + private interface Task { - public void run() throws IOException; + void run() throws IOException; } } From 12cc5d8d2dd4566c98c458a38ce20b82ba8f3ece Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 1 Aug 2017 15:49:57 +0200 Subject: [PATCH 0524/2114] Refactor AbsentQueue test with lambdas --- .../client/test/server/AbsentQueue.java | 54 ++++++------------- 1 file changed, 15 insertions(+), 39 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java b/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java index 6598e7e156..172b527f49 100644 --- a/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java +++ b/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java @@ -16,17 +16,17 @@ package com.rabbitmq.client.test.server; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.fail; +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.test.functional.ClusteredTestBase; +import org.junit.Test; import java.io.IOException; +import java.util.concurrent.Callable; import java.util.concurrent.TimeoutException; -import com.rabbitmq.client.Channel; -import org.junit.Test; - -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.test.functional.ClusteredTestBase; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.fail; /** * This tests whether 'absent' queues - durable queues whose home node @@ -56,39 +56,19 @@ public class AbsentQueue extends ClusteredTestBase { alternateChannel.queueDelete(Q); } - @Test public void notFound() throws IOException, InterruptedException { + @Test public void notFound() throws Exception { waitPropagationInHa(); - assertNotFound(new Task() { - public void run() throws IOException { - channel.queueDeclare(Q, true, false, false, null); - } - }); - assertNotFound(new Task() { - public void run() throws IOException { - channel.queueDeclarePassive(Q); - } - }); - assertNotFound(new Task() { - public void run() throws IOException { - channel.queuePurge(Q); - } - }); - assertNotFound(new Task() { - public void run() throws IOException { - channel.basicGet(Q, true); - } - }); - assertNotFound(new Task() { - public void run() throws IOException { - channel.queueBind(Q, "amq.fanout", "", null); - } - }); + assertNotFound(() -> channel.queueDeclare(Q, true, false, false, null)); + assertNotFound(() -> channel.queueDeclarePassive(Q)); + assertNotFound(() -> channel.queuePurge(Q)); + assertNotFound(() -> channel.basicGet(Q, true)); + assertNotFound(() -> channel.queueBind(Q, "amq.fanout", "", null)); } - protected void assertNotFound(Task t) throws IOException { + protected void assertNotFound(Callable t) throws Exception { if (clusteredChannel == null) return; try { - t.run(); + t.call(); if (!HATests.HA_TESTS_RUNNING) fail("expected not_found"); } catch (IOException ioe) { assertFalse(HATests.HA_TESTS_RUNNING); @@ -116,8 +96,4 @@ private void waitPropagationInHa() throws IOException, InterruptedException { } } - private interface Task { - void run() throws IOException; - } - } From 77564526b3258406fa3bdfa15a8bd8c116202b97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 16 Aug 2017 14:47:44 +0200 Subject: [PATCH 0525/2114] Capture rabbitmqctl error output when listing commands --- src/test/java/com/rabbitmq/tools/Host.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/java/com/rabbitmq/tools/Host.java b/src/test/java/com/rabbitmq/tools/Host.java index a5fe5b69d4..5924e5931d 100644 --- a/src/test/java/com/rabbitmq/tools/Host.java +++ b/src/test/java/com/rabbitmq/tools/Host.java @@ -92,9 +92,9 @@ private static Process executeCommandProcess(String command) throws IOException } public static boolean isRabbitMqCtlCommandAvailable(String command) throws IOException { - Process process = rabbitmqctl("help"); - String stdout = capture(process.getInputStream()); - return stdout.contains(command); + Process process = rabbitmqctlIgnoreErrors(""); + String stderr = capture(process.getErrorStream()); + return stderr.contains(command); } public static Process rabbitmqctl(String command) throws IOException { From c4418c1b84c2565b7ca2d86232a720403e26aaf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 16 Aug 2017 15:15:59 +0200 Subject: [PATCH 0526/2114] Set Bintray milestone package name to java-client-milestone --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 269a56250f..7d21212b36 100644 --- a/pom.xml +++ b/pom.xml @@ -616,7 +616,7 @@ bintray-rabbitmq-maven-milestones rabbitmq-maven-milestones - https://api.bintray.com/maven/rabbitmq/maven-milestones/java-client/;publish=1 + https://api.bintray.com/maven/rabbitmq/maven-milestones/java-client-milestone/;publish=1 From 5f229d5085ef87859aa49d922d5dc9599649341c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 21 Aug 2017 15:23:26 +0200 Subject: [PATCH 0527/2114] Set Bintray package name to com.rabbitmq:amqp-client --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 7d21212b36..eb456dcc04 100644 --- a/pom.xml +++ b/pom.xml @@ -552,7 +552,7 @@ bintray-rabbitmq-maven rabbitmq-maven - https://api.bintray.com/maven/rabbitmq/maven/java-client/;publish=1 + https://api.bintray.com/maven/rabbitmq/maven/com.rabbitmq:amqp-client/;publish=1 @@ -616,7 +616,7 @@ bintray-rabbitmq-maven-milestones rabbitmq-maven-milestones - https://api.bintray.com/maven/rabbitmq/maven-milestones/java-client-milestone/;publish=1 + https://api.bintray.com/maven/rabbitmq/maven-milestones/com.rabbitmq:amqp-client/;publish=1 From 3e9ff94f79a2a5ca02d5797bc0fe2908fb8ddf85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 29 Aug 2017 15:46:51 +0200 Subject: [PATCH 0528/2114] Set release version to 4.0.4.RC1 --- release-versions.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release-versions.txt b/release-versions.txt index a91f634a0c..7a4b9bf9f0 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="4.0.4" -DEVELOPMENT_VERSION="4.0.5-SNAPSHOT" +RELEASE_VERSION="4.0.4.RC1" +DEVELOPMENT_VERSION="4.0.4-SNAPSHOT" From 60fdfbe1d1ffbd06fa22c01397452d1f16340144 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 29 Aug 2017 15:51:25 +0200 Subject: [PATCH 0529/2114] Set release version to 4.3.0.RC1 --- release-versions.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release-versions.txt b/release-versions.txt index f9b866c5b6..2b08f224dc 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="4.2.0.RC1" -DEVELOPMENT_VERSION="4.2.0-SNAPSHOT" +RELEASE_VERSION="4.3.0.RC1" +DEVELOPMENT_VERSION="4.3.0-SNAPSHOT" From d317c9adecd5d26448b9753a51483fa0fc79dbb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 30 Aug 2017 15:30:09 +0200 Subject: [PATCH 0530/2114] Clean pom.xml Use properties for all dependencies and plugins. Remove some duplicated declaration. Upgrade Javadoc plugin to 3.0.0-M1 to make build work on JDK 9. --- pom.xml | 128 +++++++++++++++++++++++++------------------------------- 1 file changed, 56 insertions(+), 72 deletions(-) diff --git a/pom.xml b/pom.xml index 400adecf94..d503cd14ce 100644 --- a/pom.xml +++ b/pom.xml @@ -62,6 +62,23 @@ 2.0.0 2.7.9 + 3.0.0-M1 + 2.5.3 + 2.3 + 3.0.1 + 3.0.1 + 2.0 + 2.4.8 + 1.6.8 + 1.5 + 1.12 + 3.5.1 + 2.19.1 + 2.19.1 + 1.6 + 3.0.2 + 2.3.7 + 6026DFCA - 1.6.8 @@ -185,12 +201,12 @@ org.codehaus.gmaven groovy-maven-plugin - 2.0 + ${groovy.maven.plugin.version} org.codehaus.groovy groovy-all - 2.4.8 + ${groovy.all.version} @@ -312,6 +328,7 @@ org.codehaus.mojo keytool-maven-plugin + ${keytool.maven.plugin.version} false @@ -340,6 +357,7 @@ org.codehaus.mojo keytool-maven-plugin + ${keytool.maven.plugin.version} false @@ -371,7 +389,7 @@ org.apache.maven.plugins maven-failsafe-plugin - 2.19.1 + ${maven.failsafe.plugin.version} ${make.bin} @@ -433,7 +451,7 @@ org.apache.maven.plugins maven-failsafe-plugin - 2.19.1 + ${maven.failsafe.plugin.version} true @@ -452,34 +470,13 @@ ossrh-release - - org.sonatype.plugins - nexus-staging-maven-plugin - ${nexus-staging-maven-plugin.version} - - ossrh - https://oss.sonatype.org/ - false - - - - org.apache.maven.plugins - maven-source-plugin - 3.0.1 - - - - jar - - - - org.apache.maven.plugins maven-javadoc-plugin - 2.10.4 + ${maven.javadoc.plugin.version} ${javadoc.opts} + true @@ -493,7 +490,7 @@ org.apache.maven.plugins maven-gpg-plugin - 1.6 + ${maven.gpg.plugin.version} sign-artifacts @@ -514,10 +511,6 @@ ossrh https://oss.sonatype.org/content/repositories/snapshots - - ossrh - https://oss.sonatype.org/service/local/staging/deploy/maven2/ - @@ -529,24 +522,13 @@ bintray-release - - org.apache.maven.plugins - maven-source-plugin - 3.0.1 - - - - jar - - - - org.apache.maven.plugins maven-javadoc-plugin - 2.10.4 + ${maven.javadoc.plugin.version} ${javadoc.opts} + true @@ -560,7 +542,7 @@ org.apache.maven.plugins maven-gpg-plugin - 1.6 + ${maven.gpg.plugin.version} sign-artifacts @@ -593,24 +575,13 @@ milestone - - org.apache.maven.plugins - maven-source-plugin - 3.0.1 - - - - jar - - - - org.apache.maven.plugins maven-javadoc-plugin - 2.10.4 + ${maven.javadoc.plugin.version} ${javadoc.opts} + true @@ -624,7 +595,7 @@ org.apache.maven.plugins maven-gpg-plugin - 1.6 + ${maven.gpg.plugin.version} sign-artifacts @@ -719,17 +690,17 @@ org.apache.maven.plugins maven-resources-plugin - 3.0.1 + ${maven.sources.plugin.version} org.codehaus.gmaven groovy-maven-plugin - 2.0 + ${groovy.maven.plugin.version} org.codehaus.groovy groovy-all - 2.4.8 + ${groovy.all.version} @@ -787,7 +758,7 @@ org.codehaus.mojo build-helper-maven-plugin - 1.12 + ${build.helper.maven-plugin.version} add-generated-sources-dir @@ -806,7 +777,7 @@ maven-compiler-plugin - 3.5.1 + ${maven.compiler.plugin.version} 1.6 1.6 @@ -824,7 +795,7 @@ org.apache.maven.plugins maven-surefire-plugin - 2.19.1 + ${maven.surefire.plugin.version} true @@ -834,7 +805,7 @@ org.codehaus.mojo keytool-maven-plugin - 1.5 + ${keytool.maven.plugin.version} true @@ -874,7 +845,7 @@ org.apache.maven.plugins maven-jar-plugin - 3.0.2 + ${maven.jar.plugin.version} ${project.build.outputDirectory}/META-INF/MANIFEST.MF @@ -885,7 +856,7 @@ org.apache.felix maven-bundle-plugin - 2.3.7 + ${maven.bundle.plugin.version} bundle-manifest @@ -913,18 +884,31 @@ org.codehaus.mojo versions-maven-plugin - 2.3 + ${versions.maven.plugin.version} org.apache.maven.plugins maven-release-plugin - 2.5.3 + ${maven.release.plugin.version} v@{project.version} + + org.apache.maven.plugins + maven-source-plugin + ${maven.sources.plugin.version} + + + + jar + + + + + From 8c7aed525da271b2efa24f5313f07657e6793363 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 30 Aug 2017 15:40:17 +0200 Subject: [PATCH 0531/2114] Fix version property for source and resources plugins --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index d503cd14ce..5b50ba8cd4 100644 --- a/pom.xml +++ b/pom.xml @@ -66,7 +66,7 @@ 2.5.3 2.3 3.0.1 - 3.0.1 + 3.0.1 2.0 2.4.8 1.6.8 @@ -690,7 +690,7 @@ org.apache.maven.plugins maven-resources-plugin - ${maven.sources.plugin.version} + ${maven.resources.plugin.version} org.codehaus.gmaven @@ -899,7 +899,7 @@ org.apache.maven.plugins maven-source-plugin - ${maven.sources.plugin.version} + ${maven.source.plugin.version} From 81897b0c69fc87d10c04d910f4baacc91e8f53a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 1 Sep 2017 14:54:31 +0200 Subject: [PATCH 0532/2114] Fix a couple of warnings on Java 9 --- src/test/java/com/rabbitmq/client/test/ClonePropertiesTest.java | 2 +- .../java/com/rabbitmq/client/test/ValueOrExceptionTest.java | 2 +- src/test/java/com/rabbitmq/client/test/functional/Tables.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/ClonePropertiesTest.java b/src/test/java/com/rabbitmq/client/test/ClonePropertiesTest.java index 981b7bfd1b..153095ee01 100644 --- a/src/test/java/com/rabbitmq/client/test/ClonePropertiesTest.java +++ b/src/test/java/com/rabbitmq/client/test/ClonePropertiesTest.java @@ -38,7 +38,7 @@ public class ClonePropertiesTest { assertEquals(MessageProperties.MINIMAL_PERSISTENT_BASIC.getDeliveryMode(), ((BasicProperties) MessageProperties.MINIMAL_PERSISTENT_BASIC.clone()) .getDeliveryMode()); - assertEquals(new Integer(2), + assertEquals(Integer.valueOf(2), ((BasicProperties) MessageProperties.MINIMAL_PERSISTENT_BASIC.clone()) .getDeliveryMode()); } diff --git a/src/test/java/com/rabbitmq/client/test/ValueOrExceptionTest.java b/src/test/java/com/rabbitmq/client/test/ValueOrExceptionTest.java index 3c2640d057..de58c84aba 100644 --- a/src/test/java/com/rabbitmq/client/test/ValueOrExceptionTest.java +++ b/src/test/java/com/rabbitmq/client/test/ValueOrExceptionTest.java @@ -38,7 +38,7 @@ public InsufficientMagicException sensibleClone() { } @Test public void storesValue() throws InsufficientMagicException { - Integer value = new Integer(3); + Integer value = Integer.valueOf(3); ValueOrException valueOrEx = ValueOrException.makeValue(value); diff --git a/src/test/java/com/rabbitmq/client/test/functional/Tables.java b/src/test/java/com/rabbitmq/client/test/functional/Tables.java index 73d98cd014..009d8c827e 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Tables.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Tables.java @@ -45,7 +45,7 @@ public class Tables extends BrokerTestCase Map subTable = new HashMap(); subTable.put("key", 1); table.put("S", LongStringHelper.asLongString("string")); - table.put("I", new Integer(1)); + table.put("I", Integer.valueOf(1)); table.put("D", new BigDecimal("1.1")); table.put("T", new java.util.Date(1000000)); table.put("F", subTable); From 4bad11be1e8f718b3cb466ce3dc2998c8c94ab83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 1 Sep 2017 16:24:56 +0200 Subject: [PATCH 0533/2114] Improve Metrics test Use lambdas for waitAtMost assertions (allows to delete a few Callable classes. Use JUnit Parameterized runner to run the tests with and without automatic recovery. Update Awaitility to 3.0.0. --- pom.xml | 2 +- .../client/test/functional/Metrics.java | 218 +++++------------- 2 files changed, 59 insertions(+), 161 deletions(-) diff --git a/pom.xml b/pom.xml index 9b2434e482..74cd30b936 100644 --- a/pom.xml +++ b/pom.xml @@ -59,7 +59,7 @@ 1.2.1 1.1 4.12 - 2.0.0 + 3.0.0 2.7.9 3.0.0-M1 diff --git a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java index 25889bdb47..0a1304ae0f 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java @@ -15,7 +15,15 @@ package com.rabbitmq.client.test.functional; -import com.rabbitmq.client.*; +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.DefaultConsumer; +import com.rabbitmq.client.Envelope; +import com.rabbitmq.client.GetResponse; +import com.rabbitmq.client.Recoverable; +import com.rabbitmq.client.RecoveryListener; import com.rabbitmq.client.impl.StandardMetricsCollector; import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; import com.rabbitmq.client.test.BrokerTestCase; @@ -23,6 +31,8 @@ import com.rabbitmq.tools.Host; import org.awaitility.Duration; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; import java.io.IOException; import java.lang.reflect.Field; @@ -30,17 +40,33 @@ import java.util.Collection; import java.util.List; import java.util.Random; -import java.util.concurrent.*; - -import static org.awaitility.Awaitility.*; -import static org.hamcrest.Matchers.*; -import static org.junit.Assert.*; +import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import static org.awaitility.Awaitility.waitAtMost; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; /** * */ +@RunWith(Parameterized.class) public class Metrics extends BrokerTestCase { + @Parameterized.Parameters + public static Object[] data() { + return new Object[] { createConnectionFactory(), createAutoRecoveryConnectionFactory() }; + } + + @Parameterized.Parameter + public ConnectionFactory connectionFactory; + static final String QUEUE = "metrics.queue"; @Override @@ -53,17 +79,7 @@ protected void releaseResources() throws IOException { channel.queueDelete(QUEUE); } - @Test public void metricsStandardConnection() throws IOException, TimeoutException { - doMetrics(createConnectionFactory()); - } - - @Test public void metricsAutoRecoveryConnection() throws IOException, TimeoutException { - ConnectionFactory connectionFactory = createConnectionFactory(); - connectionFactory.setAutomaticRecoveryEnabled(true); - doMetrics(connectionFactory); - } - - private void doMetrics(ConnectionFactory connectionFactory) throws IOException, TimeoutException { + @Test public void metrics() throws IOException, TimeoutException { StandardMetricsCollector metrics = new StandardMetricsCollector(); connectionFactory.setMetricsCollector(metrics); Connection connection1 = null; @@ -103,15 +119,15 @@ private void doMetrics(ConnectionFactory connectionFactory) throws IOException, assertThat(metrics.getConsumedMessages().getCount(), is(2L+1L)); channel.basicConsume(QUEUE, true, new DefaultConsumer(channel)); - waitAtMost(timeout()).until(new ConsumedMessagesMetricsCallable(metrics), equalTo(2L+1L+1L)); + waitAtMost(timeout()).until(() -> metrics.getConsumedMessages().getCount(), equalTo(2L+1L+1L)); safeClose(connection1); - waitAtMost(timeout()).until(new ConnectionsMetricsCallable(metrics), equalTo(1L)); - waitAtMost(timeout()).until(new ChannelsMetricsCallable(metrics), equalTo(2L)); + waitAtMost(timeout()).until(() -> metrics.getConnections().getCount(), equalTo(1L)); + waitAtMost(timeout()).until(() -> metrics.getChannels().getCount(), equalTo(2L)); safeClose(connection2); - waitAtMost(timeout()).until(new ConnectionsMetricsCallable(metrics), equalTo(0L)); - waitAtMost(timeout()).until(new ChannelsMetricsCallable(metrics), equalTo(0L)); + waitAtMost(timeout()).until(() -> metrics.getConnections().getCount(), equalTo(0L)); + waitAtMost(timeout()).until(() -> metrics.getChannels().getCount(), equalTo(0L)); assertThat(metrics.getAcknowledgedMessages().getCount(), is(0L)); assertThat(metrics.getRejectedMessages().getCount(), is(0L)); @@ -122,17 +138,8 @@ private void doMetrics(ConnectionFactory connectionFactory) throws IOException, } } - @Test public void metricsAckStandardConnection() throws IOException, TimeoutException { - doMetricsAck(createConnectionFactory()); - } - @Test public void metricsAckAutoRecoveryConnection() throws IOException, TimeoutException { - ConnectionFactory connectionFactory = createConnectionFactory(); - connectionFactory.setAutomaticRecoveryEnabled(true); - doMetricsAck(connectionFactory); - } - - private void doMetricsAck(ConnectionFactory connectionFactory) throws IOException, TimeoutException { + @Test public void metricsAck() throws IOException, TimeoutException { StandardMetricsCollector metrics = new StandardMetricsCollector(); connectionFactory.setMetricsCollector(metrics); @@ -190,12 +197,12 @@ private void doMetricsAck(ConnectionFactory connectionFactory) throws IOExceptio } waitAtMost(timeout()).until( - new ConsumedMessagesMetricsCallable(metrics), + () -> metrics.getConsumedMessages().getCount(), equalTo(alreadySentMessages+nbMessages) ); waitAtMost(timeout()).until( - new AcknowledgedMessagesMetricsCallable(metrics), + () -> metrics.getAcknowledgedMessages().getCount(), equalTo(alreadySentMessages+nbMessages) ); @@ -204,17 +211,7 @@ private void doMetricsAck(ConnectionFactory connectionFactory) throws IOExceptio } } - @Test public void metricsRejectStandardConnection() throws IOException, TimeoutException { - doMetricsReject(createConnectionFactory()); - } - - @Test public void metricsRejectAutoRecoveryConnection() throws IOException, TimeoutException { - ConnectionFactory connectionFactory = createConnectionFactory(); - connectionFactory.setAutomaticRecoveryEnabled(true); - doMetricsReject(connectionFactory); - } - - private void doMetricsReject(ConnectionFactory connectionFactory) throws IOException, TimeoutException { + @Test public void metricsReject() throws IOException, TimeoutException { StandardMetricsCollector metrics = new StandardMetricsCollector(); connectionFactory.setMetricsCollector(metrics); @@ -239,20 +236,9 @@ private void doMetricsReject(ConnectionFactory connectionFactory) throws IOExcep } finally { safeClose(connection); } - } @Test public void multiThreadedMetricsStandardConnection() throws InterruptedException, TimeoutException, IOException { - doMultiThreadedMetrics(createConnectionFactory()); - } - - @Test public void multiThreadedMetricsAutoRecoveryConnection() throws InterruptedException, TimeoutException, IOException { - ConnectionFactory connectionFactory = createConnectionFactory(); - connectionFactory.setAutomaticRecoveryEnabled(true); - doMultiThreadedMetrics(connectionFactory); - } - - private void doMultiThreadedMetrics(ConnectionFactory connectionFactory) throws IOException, TimeoutException, InterruptedException { StandardMetricsCollector metrics = new StandardMetricsCollector(); connectionFactory.setMetricsCollector(metrics); int nbConnections = 3; @@ -293,7 +279,7 @@ private void doMultiThreadedMetrics(ConnectionFactory connectionFactory) throws executorService.invokeAll(tasks); assertThat(metrics.getPublishedMessages().getCount(), is(nbOfMessages)); - waitAtMost(timeout()).until(new ConsumedMessagesMetricsCallable(metrics), equalTo(nbOfMessages)); + waitAtMost(timeout()).until(() -> metrics.getConsumedMessages().getCount(), equalTo(nbOfMessages)); assertThat(metrics.getAcknowledgedMessages().getCount(), is(0L)); // to remove the listeners @@ -322,8 +308,8 @@ private void doMultiThreadedMetrics(ConnectionFactory connectionFactory) throws executorService.invokeAll(tasks); assertThat(metrics.getPublishedMessages().getCount(), is(2*nbOfMessages)); - waitAtMost(timeout()).until(new ConsumedMessagesMetricsCallable(metrics), equalTo(2*nbOfMessages)); - waitAtMost(timeout()).until(new AcknowledgedMessagesMetricsCallable(metrics), equalTo(nbOfMessages)); + waitAtMost(timeout()).until(() -> metrics.getConsumedMessages().getCount(), equalTo(2*nbOfMessages)); + waitAtMost(timeout()).until(() -> metrics.getAcknowledgedMessages().getCount(), equalTo(nbOfMessages)); // to remove the listeners for(int i = 0; i < nbChannels; i++) { @@ -351,29 +337,18 @@ private void doMultiThreadedMetrics(ConnectionFactory connectionFactory) throws executorService.invokeAll(tasks); assertThat(metrics.getPublishedMessages().getCount(), is(3*nbOfMessages)); - waitAtMost(timeout()).until(new ConsumedMessagesMetricsCallable(metrics), equalTo(3*nbOfMessages)); - waitAtMost(timeout()).until(new AcknowledgedMessagesMetricsCallable(metrics), equalTo(nbOfMessages)); - waitAtMost(timeout()).until(new RejectedMessagesMetricsCallable(metrics), equalTo(nbOfMessages)); + waitAtMost(timeout()).until(() -> metrics.getConsumedMessages().getCount(), equalTo(3*nbOfMessages)); + waitAtMost(timeout()).until(() -> metrics.getAcknowledgedMessages().getCount(), equalTo(nbOfMessages)); + waitAtMost(timeout()).until(() -> metrics.getRejectedMessages().getCount(), equalTo(nbOfMessages)); } finally { for (Connection connection : connections) { safeClose(connection); } executorService.shutdownNow(); } - - } - - @Test public void errorInChannelStandardConnection() throws IOException, TimeoutException { - errorInChannel(createConnectionFactory()); - } - - @Test public void errorInChananelAutoRecoveryConnection() throws IOException, TimeoutException { - ConnectionFactory connectionFactory = createConnectionFactory(); - connectionFactory.setAutomaticRecoveryEnabled(true); - errorInChannel(connectionFactory); } - private void errorInChannel(ConnectionFactory connectionFactory) throws IOException, TimeoutException { + @Test public void errorInChannel() throws IOException, TimeoutException { StandardMetricsCollector metrics = new StandardMetricsCollector(); connectionFactory.setMetricsCollector(metrics); @@ -387,12 +362,11 @@ private void errorInChannel(ConnectionFactory connectionFactory) throws IOExcept channel.basicPublish("unlikelynameforanexchange", "", null, "msg".getBytes("UTF-8")); - waitAtMost(timeout()).until(new ChannelsMetricsCallable(metrics), is(0L)); + waitAtMost(timeout()).until(() -> metrics.getChannels().getCount(), is(0L)); assertThat(metrics.getConnections().getCount(), is(1L)); } finally { safeClose(connection); } - } @Test public void checkListenersWithAutoRecoveryConnection() throws Exception { @@ -426,8 +400,15 @@ private void errorInChannel(ConnectionFactory connectionFactory) throws IOExcept } - private ConnectionFactory createConnectionFactory() { + private static ConnectionFactory createConnectionFactory() { ConnectionFactory connectionFactory = TestUtils.connectionFactory(); + connectionFactory.setAutomaticRecoveryEnabled(false); + return connectionFactory; + } + + private static ConnectionFactory createAutoRecoveryConnectionFactory() { + ConnectionFactory connectionFactory = TestUtils.connectionFactory(); + connectionFactory.setAutomaticRecoveryEnabled(true); return connectionFactory; } @@ -587,87 +568,4 @@ public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProp } } - static abstract class MetricsCallable implements Callable { - - final StandardMetricsCollector metrics; - - protected MetricsCallable(StandardMetricsCollector metrics) { - this.metrics = metrics; - } - - - } - - static class ConnectionsMetricsCallable extends MetricsCallable { - - ConnectionsMetricsCallable(StandardMetricsCollector metrics) { - super(metrics); - } - - @Override - public Long call() throws Exception { - return metrics.getConnections().getCount(); - } - } - - static class ChannelsMetricsCallable extends MetricsCallable { - - ChannelsMetricsCallable(StandardMetricsCollector metrics) { - super(metrics); - } - - @Override - public Long call() throws Exception { - return metrics.getChannels().getCount(); - } - } - - static class PublishedMessagesMetricsCallable extends MetricsCallable { - - PublishedMessagesMetricsCallable(StandardMetricsCollector metrics) { - super(metrics); - } - - @Override - public Long call() throws Exception { - return metrics.getPublishedMessages().getCount(); - } - } - - static class ConsumedMessagesMetricsCallable extends MetricsCallable { - - ConsumedMessagesMetricsCallable(StandardMetricsCollector metrics) { - super(metrics); - } - - @Override - public Long call() throws Exception { - return metrics.getConsumedMessages().getCount(); - } - } - - static class AcknowledgedMessagesMetricsCallable extends MetricsCallable { - - AcknowledgedMessagesMetricsCallable(StandardMetricsCollector metrics) { - super(metrics); - } - - @Override - public Long call() throws Exception { - return metrics.getAcknowledgedMessages().getCount(); - } - } - - static class RejectedMessagesMetricsCallable extends MetricsCallable { - - RejectedMessagesMetricsCallable(StandardMetricsCollector metrics) { - super(metrics); - } - - @Override - public Long call() throws Exception { - return metrics.getRejectedMessages().getCount(); - } - } - } From c3f1cdbe46daab3d8e843a4ad27a869c0b864f2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 4 Sep 2017 10:35:54 +0200 Subject: [PATCH 0534/2114] Don't run AbsentQueue test when not in HA mode This test fails sporadically in normal mode (non-HA), whereas it's supposed to test some queue behavior in HA mode. --- .../java/com/rabbitmq/client/test/server/AbsentQueue.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java b/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java index 6598e7e156..d92fa2c3ad 100644 --- a/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java +++ b/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java @@ -57,6 +57,10 @@ public class AbsentQueue extends ClusteredTestBase { } @Test public void notFound() throws IOException, InterruptedException { + if (!HATests.HA_TESTS_RUNNING) { + // we don't care about this test in normal mode + return; + } waitPropagationInHa(); assertNotFound(new Task() { public void run() throws IOException { From c23917777969507c46cde8393e935c622c474a42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 5 Sep 2017 14:53:58 +0200 Subject: [PATCH 0535/2114] Don't blindly overwrite SSLContext when specifying URI ConnectionFactory#setUri always set up the default SSLContext when a secured AMQP URI is passed in. Now, it only does so if the sslContext property hasn't been set yet. Fixes #297 --- src/main/java/com/rabbitmq/client/ConnectionFactory.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index b5130edbd5..19bbf436cc 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -226,7 +226,10 @@ public void setUri(URI uri) // nothing special to do } else if ("amqps".equals(uri.getScheme().toLowerCase())) { setPort(DEFAULT_AMQP_OVER_SSL_PORT); - useSslProtocol(); + // SSL context not set yet, we use the default one + if (this.sslContext != null) { + useSslProtocol(); + } } else { throw new IllegalArgumentException("Wrong scheme in AMQP URI: " + uri.getScheme()); From 1ccadd22f644dd8b54fe3c59dbd4b46d4811f53e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 5 Sep 2017 15:51:31 +0200 Subject: [PATCH 0536/2114] Change condition to check SSLContext The other way around :-) References #297 --- src/main/java/com/rabbitmq/client/ConnectionFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 19bbf436cc..2f32452dcd 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -227,7 +227,7 @@ public void setUri(URI uri) } else if ("amqps".equals(uri.getScheme().toLowerCase())) { setPort(DEFAULT_AMQP_OVER_SSL_PORT); // SSL context not set yet, we use the default one - if (this.sslContext != null) { + if (this.sslContext == null) { useSslProtocol(); } } else { From 0c131167bd150894e5180da489de1154197e3335 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 6 Sep 2017 10:16:44 +0200 Subject: [PATCH 0537/2114] Set release version to 4.2.1.RC1 --- release-versions.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release-versions.txt b/release-versions.txt index f9b866c5b6..767c6a0d45 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="4.2.0.RC1" -DEVELOPMENT_VERSION="4.2.0-SNAPSHOT" +RELEASE_VERSION="4.2.1.RC1" +DEVELOPMENT_VERSION="4.2.1-SNAPSHOT" From 0608364e41cfeb91e187eeddec3bf0e1156cb69b Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Wed, 6 Sep 2017 08:18:58 +0000 Subject: [PATCH 0538/2114] [maven-release-plugin] prepare release v4.2.1.RC1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 2e29849e09..9ca1ffb2c3 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.2.1-SNAPSHOT + 4.2.1.RC1 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v4.2.1.RC1 From bacf7dda1da8daa0e48d617736b08fa5da1b91c1 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Wed, 6 Sep 2017 08:19:06 +0000 Subject: [PATCH 0539/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 9ca1ffb2c3..2e29849e09 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.2.1.RC1 + 4.2.1-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v4.2.1.RC1 + HEAD From dd555b7b9c8ba1616dd9e5d05e9fdb59950a808a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 6 Sep 2017 14:16:32 +0200 Subject: [PATCH 0540/2114] Check SslContextFactory, not SSLContext property References #297 --- src/main/java/com/rabbitmq/client/ConnectionFactory.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index dcff5c7f84..ab90871a21 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -230,8 +230,8 @@ public void setUri(URI uri) // nothing special to do } else if ("amqps".equals(uri.getScheme().toLowerCase())) { setPort(DEFAULT_AMQP_OVER_SSL_PORT); - // SSL context not set yet, we use the default one - if (this.sslContext == null) { + // SSL context factory not set yet, we use the default one + if (this.sslContextFactory == null) { useSslProtocol(); } } else { From da0e0f0dcd95c47290c4edf6d37afd2b33e42466 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 6 Sep 2017 14:45:08 +0200 Subject: [PATCH 0541/2114] Remove unused property in POM --- pom.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5b50ba8cd4..88da4347c0 100644 --- a/pom.xml +++ b/pom.xml @@ -69,7 +69,6 @@ 3.0.1 2.0 2.4.8 - 1.6.8 1.5 1.12 3.5.1 From a8ab9fb0a952eba4dc4df8349f27da3b636ab2d0 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Thu, 7 Sep 2017 13:54:31 -0700 Subject: [PATCH 0542/2114] Rename this consumer to avoid confusion with QueueingBasicConsumer which no longer has a reason to exist and should be avoided. --- .../client/test/functional/DeadLetterExchange.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java index af7e48abcf..5b6c7a565f 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java @@ -170,7 +170,7 @@ protected void releaseResources() throws IOException { channel.queueBind(DLQ, DLX, "test"); //measure round-trip latency - QueueMessageConsumer c = new QueueMessageConsumer(channel); + AccumulatingMessageConsumer c = new AccumulatingMessageConsumer(channel); String cTag = channel.basicConsume(TEST_QUEUE_NAME, true, c); long start = System.currentTimeMillis(); publish(null, "test"); @@ -562,7 +562,7 @@ private void sleep(long millis) { /* check that each message arrives within epsilon of the publication time + TTL + latency */ - private void checkPromptArrival(QueueMessageConsumer c, + private void checkPromptArrival(AccumulatingMessageConsumer c, int count, long latency) throws Exception { long epsilon = TTL / 10; for (int i = 0; i < count; i++) { @@ -697,11 +697,11 @@ private static String randomQueueName() { return DeadLetterExchange.class.getSimpleName() + "-" + UUID.randomUUID().toString(); } - class QueueMessageConsumer extends DefaultConsumer { + class AccumulatingMessageConsumer extends DefaultConsumer { BlockingQueue messages = new LinkedBlockingQueue(); - public QueueMessageConsumer(Channel channel) { + public AccumulatingMessageConsumer(Channel channel) { super(channel); } From c1e2f80b09eb36b0d934bf2e7b29e89e82e6d0cc Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Thu, 7 Sep 2017 13:59:00 -0700 Subject: [PATCH 0543/2114] Assert on x-first-death-{queue,reason,exchange} not being empty Part of rabbitmq/rabbitmq-server#1332. --- .../rabbitmq/client/test/functional/DeadLetterExchange.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java index 5b6c7a565f..6b53b34d8b 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java @@ -536,6 +536,9 @@ public void process(GetResponse getResponse) { assertNotNull(headers); ArrayList death = (ArrayList) headers.get("x-death"); assertNotNull(death); + assertNotNull(headers.get("x-first-death-queue")); + assertNotNull(headers.get("x-first-death-reason")); + assertNotNull(headers.get("x-first-death-exchange")); assertEquals(1, death.size()); assertDeathReason(death, 0, TEST_QUEUE_NAME, reason, "amq.direct", From cc9fd1ca2428d35d9878c2ba64310c7a31d1d8ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 12 Sep 2017 11:09:05 +0200 Subject: [PATCH 0544/2114] Set release version to 4.2.1 --- release-versions.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release-versions.txt b/release-versions.txt index 767c6a0d45..d9af2288df 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="4.2.1.RC1" -DEVELOPMENT_VERSION="4.2.1-SNAPSHOT" +RELEASE_VERSION="4.2.1" +DEVELOPMENT_VERSION="4.2.2-SNAPSHOT" From 7b247fa38b1ad479878f757689254fce0a4df834 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Tue, 12 Sep 2017 09:10:42 +0000 Subject: [PATCH 0545/2114] [maven-release-plugin] prepare release v4.2.1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index b3294dda1f..5727d73f4a 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.2.1-SNAPSHOT + 4.2.1 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v4.2.1 From da9d52f698ba2967da3eec3f1dcd287fe433f4a4 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Tue, 12 Sep 2017 09:10:48 +0000 Subject: [PATCH 0546/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 5727d73f4a..fc4522d02d 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.2.1 + 4.2.2-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v4.2.1 + HEAD From a7ef76fe37de78bae11c31aafee8da06fff4392f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 12 Sep 2017 11:56:09 +0200 Subject: [PATCH 0547/2114] Set release version to 4.2.2.RC1 --- release-versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-versions.txt b/release-versions.txt index d9af2288df..acc8f7662a 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="4.2.1" +RELEASE_VERSION="4.2.2.RC1" DEVELOPMENT_VERSION="4.2.2-SNAPSHOT" From 8327c6aa4d58780c18a8d56e90a64ca837846560 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 14 Sep 2017 14:47:13 +0200 Subject: [PATCH 0548/2114] Remove executor service argument from Channel#asyncCompletableRpc Even if CompletableFuture is completed in the reading thread, client API (e.g. CompletableStage#then*, Reactor Flux/Mono) provide ways to control the threading behavior. References #215 --- .../java/com/rabbitmq/client/Channel.java | 4 +-- .../com/rabbitmq/client/impl/AMQChannel.java | 21 +++++++------- .../com/rabbitmq/client/impl/ChannelN.java | 4 +-- .../impl/CompletableFutureRpcWrapper.java | 13 ++------- .../impl/recovery/AutorecoveringChannel.java | 5 ++-- .../ChannelAsyncCompletableFutureTest.java | 29 +++---------------- 6 files changed, 21 insertions(+), 55 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/Channel.java b/src/main/java/com/rabbitmq/client/Channel.java index a8c4446f50..ab99dcf836 100644 --- a/src/main/java/com/rabbitmq/client/Channel.java +++ b/src/main/java/com/rabbitmq/client/Channel.java @@ -18,7 +18,6 @@ import java.io.IOException; import java.util.Map; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeoutException; import com.rabbitmq.client.AMQP.BasicProperties; @@ -1368,10 +1367,9 @@ void basicNack(long deliveryTag, boolean multiple, boolean requeue) /** * Asynchronously send a method over this channel. * @param method method to transmit over this channel. - * @param executorService executor used to complete the operation, can be null * @return a completable future that completes when the result is received * @throws IOException Problem transmitting method. */ - CompletableFuture asyncCompletableRpc(Method method, ExecutorService executorService) throws IOException; + CompletableFuture asyncCompletableRpc(Method method) throws IOException; } diff --git a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java index 39a2a653a4..8de19b7753 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java @@ -29,7 +29,6 @@ import java.io.IOException; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeoutException; import java.util.function.Supplier; @@ -146,11 +145,11 @@ public AMQCommand exnWrappingRpc(Method m) } } - public CompletableFuture exnWrappingAsyncRpc(Method m, ExecutorService executorService) + public CompletableFuture exnWrappingAsyncRpc(Method m) throws IOException { try { - return privateAsyncRpc(m, executorService); + return privateAsyncRpc(m); } catch (AlreadyClosedException ace) { // Do not wrap it since it means that connection/channel // was closed in some action in the past @@ -205,8 +204,8 @@ public void enqueueRpc(RpcContinuation k) doEnqueueRpc(() -> new RpcContinuationRpcWrapper(k)); } - public void enqueueAsyncRpc(Method method, CompletableFuture future, ExecutorService executorService) { - doEnqueueRpc(() -> new CompletableFutureRpcWrapper(method, future, executorService)); + public void enqueueAsyncRpc(Method method, CompletableFuture future) { + doEnqueueRpc(() -> new CompletableFutureRpcWrapper(method, future)); } private void doEnqueueRpc(Supplier rpcWrapperSupplier) { @@ -309,11 +308,11 @@ protected ChannelContinuationTimeoutException wrapTimeoutException(final Method return new ChannelContinuationTimeoutException(e, this, this._channelNumber, m); } - private CompletableFuture privateAsyncRpc(Method m, ExecutorService executorService) + private CompletableFuture privateAsyncRpc(Method m) throws IOException, ShutdownSignalException { CompletableFuture future = new CompletableFuture<>(); - asyncRpc(m, future, executorService); + asyncRpc(m, future); return future; } @@ -348,20 +347,20 @@ public void quiescingRpc(Method m, RpcContinuation k) } } - public void asyncRpc(Method m, CompletableFuture future, ExecutorService executorService) + public void asyncRpc(Method m, CompletableFuture future) throws IOException { synchronized (_channelMutex) { ensureIsOpen(); - quiescingAsyncRpc(m, future, executorService); + quiescingAsyncRpc(m, future); } } - public void quiescingAsyncRpc(Method m, CompletableFuture future, ExecutorService executorService) + public void quiescingAsyncRpc(Method m, CompletableFuture future) throws IOException { synchronized (_channelMutex) { - enqueueAsyncRpc(m, future, executorService); + enqueueAsyncRpc(m, future); quiescingTransmit(m); } } diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java index 56ff508372..cd73ce5f0c 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelN.java @@ -1555,8 +1555,8 @@ public AMQCommand rpc(Method method) throws IOException { } @Override - public CompletableFuture asyncCompletableRpc(Method method, ExecutorService executorService) throws IOException { - return exnWrappingAsyncRpc(method, executorService); + public CompletableFuture asyncCompletableRpc(Method method) throws IOException { + return exnWrappingAsyncRpc(method); } @Override diff --git a/src/main/java/com/rabbitmq/client/impl/CompletableFutureRpcWrapper.java b/src/main/java/com/rabbitmq/client/impl/CompletableFutureRpcWrapper.java index 41e1457257..c2a3e5c649 100644 --- a/src/main/java/com/rabbitmq/client/impl/CompletableFutureRpcWrapper.java +++ b/src/main/java/com/rabbitmq/client/impl/CompletableFutureRpcWrapper.java @@ -19,8 +19,6 @@ import com.rabbitmq.client.Method; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; /** * @@ -31,12 +29,9 @@ public class CompletableFutureRpcWrapper implements RpcWrapper { private final CompletableFuture completableFuture; - private final ExecutorService executorService; - - public CompletableFutureRpcWrapper(Method method, CompletableFuture completableFuture, ExecutorService executorService) { + public CompletableFutureRpcWrapper(Method method, CompletableFuture completableFuture) { this.request = method; this.completableFuture = completableFuture; - this.executorService = executorService; } @Override @@ -46,11 +41,7 @@ public boolean canHandleReply(AMQCommand command) { @Override public void complete(AMQCommand command) { - if (executorService == null) { - completableFuture.complete(command); - } else { - executorService.submit(() -> completableFuture.complete(command)); - } + completableFuture.complete(command); } @Override diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java index b4b468ef09..5c66c38014 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java @@ -22,7 +22,6 @@ import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeoutException; /** @@ -898,8 +897,8 @@ void updateConsumerTag(String tag, String newTag) { } @Override - public CompletableFuture asyncCompletableRpc(Method method, ExecutorService executorService) throws IOException { - return this.delegate.asyncCompletableRpc(method, executorService); + public CompletableFuture asyncCompletableRpc(Method method) throws IOException { + return this.delegate.asyncCompletableRpc(method); } @Override diff --git a/src/test/java/com/rabbitmq/client/test/ChannelAsyncCompletableFutureTest.java b/src/test/java/com/rabbitmq/client/test/ChannelAsyncCompletableFutureTest.java index f0b0ae363c..c94e17a7b0 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelAsyncCompletableFutureTest.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelAsyncCompletableFutureTest.java @@ -22,13 +22,8 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; import java.util.UUID; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; @@ -37,22 +32,9 @@ import static org.junit.Assert.assertTrue; -@RunWith(Parameterized.class) public class ChannelAsyncCompletableFutureTest extends BrokerTestCase { - ExecutorService executor, methodArgumentExecutor; - - @Parameterized.Parameters - public static Collection params() { - List executors = new ArrayList<>(); - executors.add(null); - executors.add(Executors.newSingleThreadExecutor()); - return executors; - } - - public ChannelAsyncCompletableFutureTest(ExecutorService methodArgumentExecutor) { - this.methodArgumentExecutor = methodArgumentExecutor; - } + ExecutorService executor; String queue; String exchange; @@ -67,9 +49,6 @@ public ChannelAsyncCompletableFutureTest(ExecutorService methodArgumentExecutor) executor.shutdownNow(); channel.queueDelete(queue); channel.exchangeDelete(exchange); - if (methodArgumentExecutor != null) { - methodArgumentExecutor.shutdownNow(); - } } @Test @@ -85,7 +64,7 @@ public void async() throws Exception { .arguments(null) .build(); - channel.asyncCompletableRpc(queueDeclare, null) + channel.asyncCompletableRpc(queueDeclare) .thenComposeAsync(action -> { try { return channel.asyncCompletableRpc(new AMQImpl.Exchange.Declare.Builder() @@ -94,7 +73,7 @@ public void async() throws Exception { .durable(false) .autoDelete(false) .arguments(null) - .build(), methodArgumentExecutor); + .build()); } catch (IOException e) { throw new RuntimeException(e); } @@ -105,7 +84,7 @@ public void async() throws Exception { .exchange(exchange) .routingKey("") .arguments(null) - .build(), methodArgumentExecutor); + .build()); } catch (IOException e) { throw new RuntimeException(e); } From d7805120fc349bd348555d447db03952450d7ece Mon Sep 17 00:00:00 2001 From: Jannis Oeltjen Date: Thu, 14 Sep 2017 15:19:01 +0200 Subject: [PATCH 0549/2114] Add warning for not supported no-local flag Add warning to Javadoc that the noLocal flag is not supported by the rabbitmq server. This is the same as for the immediate flag for publishing. References #303 --- src/main/java/com/rabbitmq/client/Channel.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/Channel.java b/src/main/java/com/rabbitmq/client/Channel.java index ab99dcf836..6279bf881f 100644 --- a/src/main/java/com/rabbitmq/client/Channel.java +++ b/src/main/java/com/rabbitmq/client/Channel.java @@ -1126,8 +1126,8 @@ void basicNack(long deliveryTag, boolean multiple, boolean requeue) * acknowledged once delivered; false if the server should expect * explicit acknowledgements * @param consumerTag a client-generated consumer tag to establish context - * @param noLocal true if the server should not deliver to this consumer - * messages published on this channel's connection + * @param noLocal True if the server should not deliver to this consumer + * messages published on this channel's connection. Note that the RabbitMQ server does not support this flag. * @param exclusive true if this is an exclusive consumer * @param callback an interface to the consumer object * @param arguments a set of arguments for the consume @@ -1150,8 +1150,8 @@ void basicNack(long deliveryTag, boolean multiple, boolean requeue) * acknowledged once delivered; false if the server should expect * explicit acknowledgements * @param consumerTag a client-generated consumer tag to establish context - * @param noLocal true if the server should not deliver to this consumer - * messages published on this channel's connection + * @param noLocal True if the server should not deliver to this consumer + * messages published on this channel's connection. Note that the RabbitMQ server does not support this flag. * @param exclusive true if this is an exclusive consumer * @param arguments a set of arguments for the consume * @param deliverCallback callback when a message is delivered @@ -1176,8 +1176,8 @@ void basicNack(long deliveryTag, boolean multiple, boolean requeue) * acknowledged once delivered; false if the server should expect * explicit acknowledgements * @param consumerTag a client-generated consumer tag to establish context - * @param noLocal true if the server should not deliver to this consumer - * messages published on this channel's connection + * @param noLocal True if the server should not deliver to this consumer + * messages published on this channel's connection. Note that the RabbitMQ server does not support this flag. * @param exclusive true if this is an exclusive consumer * @param arguments a set of arguments for the consume * @param deliverCallback callback when a message is delivered @@ -1202,8 +1202,8 @@ void basicNack(long deliveryTag, boolean multiple, boolean requeue) * acknowledged once delivered; false if the server should expect * explicit acknowledgements * @param consumerTag a client-generated consumer tag to establish context - * @param noLocal true if the server should not deliver to this consumer - * messages published on this channel's connection + * @param noLocal True if the server should not deliver to this consumer + * messages published on this channel's connection. Note that the RabbitMQ server does not support this flag. * @param exclusive true if this is an exclusive consumer * @param arguments a set of arguments for the consume * @param deliverCallback callback when a message is delivered From 9635f5d97a54e32f45e575e39043f9f9ac475881 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Fri, 15 Sep 2017 08:43:50 +0000 Subject: [PATCH 0550/2114] [maven-release-plugin] prepare release v5.0.0.RC1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 494583be75..26c870abd2 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.0.0-SNAPSHOT + 5.0.0.RC1 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v5.0.0.RC1 From 29d5ba7e291643afa2b46f59422a21430366353c Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Fri, 15 Sep 2017 08:43:57 +0000 Subject: [PATCH 0551/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 26c870abd2..494583be75 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.0.0.RC1 + 5.0.0-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v5.0.0.RC1 + HEAD From 3145eaaff20c528902a75fd0cfcb19de360cef47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 15 Sep 2017 10:45:36 +0200 Subject: [PATCH 0552/2114] Set release version to 5.0.0.RC2 --- release-versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-versions.txt b/release-versions.txt index fb8a98a21c..784f5a2979 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="5.0.0.RC1" +RELEASE_VERSION="5.0.0.RC22" DEVELOPMENT_VERSION="5.0.0-SNAPSHOT" From eb239fd096abed06a7620602b6a30126d31f277d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 15 Sep 2017 11:54:02 +0200 Subject: [PATCH 0553/2114] Upgrade dependencies --- pom.xml | 8 ++++---- .../test/RecoveryAwareAMQConnectionFactoryTest.java | 7 +------ 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/pom.xml b/pom.xml index 494583be75..b21488490a 100644 --- a/pom.xml +++ b/pom.xml @@ -54,13 +54,13 @@ UTF-8 UTF-8 - 1.7.23 - 3.1.2 - 1.2.1 + 1.7.25 + 3.2.4 + 1.2.3 1.1 4.12 3.0.0 - 2.7.9 + 2.10.0 3.0.0-M1 2.5.3 diff --git a/src/test/java/com/rabbitmq/client/test/RecoveryAwareAMQConnectionFactoryTest.java b/src/test/java/com/rabbitmq/client/test/RecoveryAwareAMQConnectionFactoryTest.java index 6b18952b25..8f8354b2db 100644 --- a/src/test/java/com/rabbitmq/client/test/RecoveryAwareAMQConnectionFactoryTest.java +++ b/src/test/java/com/rabbitmq/client/test/RecoveryAwareAMQConnectionFactoryTest.java @@ -45,12 +45,7 @@ public class RecoveryAwareAMQConnectionFactoryTest { final Queue connections = new ArrayBlockingQueue(10); connections.add(connectionThatThrowsTimeout); connections.add(connectionThatSucceeds); - AddressResolver addressResolver = new AddressResolver() { - @Override - public List
getAddresses() throws IOException { - return Arrays.asList(new Address("host1"), new Address("host2")); - } - }; + AddressResolver addressResolver = () -> Arrays.asList(new Address("host1"), new Address("host2")); RecoveryAwareAMQConnectionFactory connectionFactory = new RecoveryAwareAMQConnectionFactory( new ConnectionParams(), mock(FrameHandlerFactory.class), addressResolver ) { From 3bcbf5322d1229a731032019fdcba81222d3234a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 15 Sep 2017 15:28:28 +0200 Subject: [PATCH 0554/2114] Delete tag creation scripts Now automated in Concourse. --- create-tag-dry-run.sh | 10 ---------- create-tag.sh | 10 ---------- 2 files changed, 20 deletions(-) delete mode 100755 create-tag-dry-run.sh delete mode 100755 create-tag.sh diff --git a/create-tag-dry-run.sh b/create-tag-dry-run.sh deleted file mode 100755 index 179431fb93..0000000000 --- a/create-tag-dry-run.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash - -set -x - -source "release-versions.txt" - -mvn release:clean release:prepare -DdryRun=true -Darguments="-DskipTests" \ - --batch-mode -Dtag="v$RELEASE_VERSION" \ - -DreleaseVersion=$RELEASE_VERSION \ - -DdevelopmentVersion=$DEVELOPMENT_VERSION diff --git a/create-tag.sh b/create-tag.sh deleted file mode 100755 index 5c1e0ddc4f..0000000000 --- a/create-tag.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash - -set -x - -source "release-versions.txt" - -mvn release:clean release:prepare -Darguments="-DskipTests" \ - --batch-mode -Dtag="v$RELEASE_VERSION" \ - -DreleaseVersion=$RELEASE_VERSION \ - -DdevelopmentVersion=$DEVELOPMENT_VERSION From afef8450b46874e03a731093004b998d8e20c17a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 15 Sep 2017 15:42:23 +0200 Subject: [PATCH 0555/2114] Configure Javadoc plugin in default build Otherwise use the last stable version, which doesn't work with Java 9. --- pom.xml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pom.xml b/pom.xml index fc4522d02d..19840a64cb 100644 --- a/pom.xml +++ b/pom.xml @@ -914,6 +914,16 @@ + + org.apache.maven.plugins + maven-javadoc-plugin + ${maven.javadoc.plugin.version} + + ${javadoc.opts} + true + + + From f2ed1dcf1f601cdbaf7fa41b0dfa681f23be3b98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 18 Sep 2017 11:35:31 +0200 Subject: [PATCH 0556/2114] Add broker version condition when checking x-death headers Those headers have been introduced in RabbitMQ 3.7, so checking them against earlier versions doesn't make sense. References rabbitmq/rabbitmq-server#1332 --- .../com/rabbitmq/client/test/TestUtils.java | 30 +++++++++++++++++++ .../test/functional/DeadLetterExchange.java | 12 ++++++-- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/TestUtils.java b/src/test/java/com/rabbitmq/client/test/TestUtils.java index e335da6ef2..a43db542e5 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtils.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtils.java @@ -44,4 +44,34 @@ public static void close(Connection connection) { } } + public static boolean isVersion37orLater(Connection connection) { + String currentVersion = connection.getServerProperties().get("version").toString(); + if (currentVersion.contains("+")) { + currentVersion = currentVersion.substring(0, currentVersion.indexOf("+")); + } + return "0.0.0".equals(currentVersion) ? true : versionCompare(currentVersion, "3.7.0") >= 0; + } + + /** + * http://stackoverflow.com/questions/6701948/efficient-way-to-compare-version-strings-in-java + * + */ + static int versionCompare(String str1, String str2) { + String[] vals1 = str1.split("\\."); + String[] vals2 = str2.split("\\."); + int i = 0; + // set index to first non-equal ordinal or length of shortest version string + while (i < vals1.length && i < vals2.length && vals1[i].equals(vals2[i])) { + i++; + } + // compare first non-equal ordinal number + if (i < vals1.length && i < vals2.length) { + int diff = Integer.valueOf(vals1[i]).compareTo(Integer.valueOf(vals2[i])); + return Integer.signum(diff); + } + // the strings are equal or one string is a substring of the other + // e.g. "1.2.3" = "1.2.3" or "1.2.3" < "1.2.3.4" + return Integer.signum(vals1.length - vals2.length); + } + } diff --git a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java index 6b53b34d8b..56ef879fe3 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java @@ -18,6 +18,7 @@ import com.rabbitmq.client.*; import com.rabbitmq.client.AMQP.BasicProperties; import com.rabbitmq.client.test.BrokerTestCase; +import com.rabbitmq.client.test.TestUtils; import org.junit.Test; import java.io.IOException; @@ -536,9 +537,14 @@ public void process(GetResponse getResponse) { assertNotNull(headers); ArrayList death = (ArrayList) headers.get("x-death"); assertNotNull(death); - assertNotNull(headers.get("x-first-death-queue")); - assertNotNull(headers.get("x-first-death-reason")); - assertNotNull(headers.get("x-first-death-exchange")); + // the following assertions shouldn't be checked on version lower than 3.7 + // as the headers are new in 3.7 + // see https://github.com/rabbitmq/rabbitmq-server/issues/1332 + if(TestUtils.isVersion37orLater(channel.getConnection())) { + assertNotNull(headers.get("x-first-death-queue")); + assertNotNull(headers.get("x-first-death-reason")); + assertNotNull(headers.get("x-first-death-exchange")); + } assertEquals(1, death.size()); assertDeathReason(death, 0, TEST_QUEUE_NAME, reason, "amq.direct", From ff8ef23a6503f9c5225b112cdf8704324cee75c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 19 Sep 2017 11:30:03 +0200 Subject: [PATCH 0557/2114] Check for null blocker in RpcClient Fixes #306 --- src/main/java/com/rabbitmq/client/RpcClient.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/RpcClient.java b/src/main/java/com/rabbitmq/client/RpcClient.java index 52091bb427..61d881f60f 100644 --- a/src/main/java/com/rabbitmq/client/RpcClient.java +++ b/src/main/java/com/rabbitmq/client/RpcClient.java @@ -190,8 +190,10 @@ public void handleDelivery(String consumerTag, throws IOException { synchronized (_continuationMap) { String replyId = properties.getCorrelationId(); - BlockingCell blocker = _continuationMap.get(replyId); - _continuationMap.remove(replyId); + BlockingCell blocker =_continuationMap.remove(replyId); + if (blocker == null) { + throw new IllegalStateException("No outstanding request for correlation ID " + replyId); + } blocker.set(new Response(consumerTag, envelope, properties, body)); } } From 9e78a19c8b552f07d63a20e10ef38fc52468a1a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 20 Sep 2017 15:51:54 +0200 Subject: [PATCH 0558/2114] Flip ByteBuffer after read retry References #307 --- .../impl/nio/SslEngineByteBufferInputStream.java | 2 ++ .../test/ssl/NioTlsUnverifiedConnection.java | 16 ++++++++++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferInputStream.java b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferInputStream.java index 2734d81b40..2f41ee1cd9 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferInputStream.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferInputStream.java @@ -73,6 +73,8 @@ public int read() throws IOException { if(bytesRead <= 0) { throw new IllegalStateException("Should be reading something from the network"); } + // see https://github.com/rabbitmq/rabbitmq-java-client/issues/307 + cipherIn.flip(); } plainIn.clear(); result = sslEngine.unwrap(cipherIn, plainIn); diff --git a/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java index 7a83e8d173..d3336dc3c0 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java @@ -40,6 +40,7 @@ public void openConnection() throws IOException, TimeoutException { try { connectionFactory.useSslProtocol(); + connectionFactory.useNio(); } catch (Exception ex) { throw new IOException(ex.toString()); } @@ -55,7 +56,7 @@ public void openConnection() } } if(connection == null) { - fail("Couldn't open TLS connection after 3 attemps"); + fail("Couldn't open TLS connection after 3 attempts"); } } @@ -63,7 +64,7 @@ public void openConnection() @Test public void connectionGetConsume() throws Exception { CountDownLatch latch = new CountDownLatch(1); - connection = basicGetBasicConsume(connection, "tls.nio.queue", latch); + connection = basicGetBasicConsume(connection, "tls.nio.queue", latch, 100 * 1000); boolean messagesReceived = latch.await(5, TimeUnit.SECONDS); assertTrue("Message has not been received", messagesReceived); } @@ -94,13 +95,20 @@ public void configure(SSLEngine sslEngine) throws IOException { } } - private Connection basicGetBasicConsume(Connection connection, String queue, final CountDownLatch latch) + @Test public void largeMessage() throws Exception { + CountDownLatch latch = new CountDownLatch(1); + connection = basicGetBasicConsume(connection, "tls.nio.queue", latch, 1 * 1000 * 1000); + boolean messagesReceived = latch.await(5, TimeUnit.SECONDS); + assertTrue("Message has not been received", messagesReceived); + } + + private Connection basicGetBasicConsume(Connection connection, String queue, final CountDownLatch latch, int msgSize) throws IOException, TimeoutException { Channel channel = connection.createChannel(); channel.queueDeclare(queue, false, false, false, null); channel.queuePurge(queue); - channel.basicPublish("", queue, null, new byte[100 * 1000]); + channel.basicPublish("", queue, null, new byte[msgSize]); channel.basicConsume(queue, false, new DefaultConsumer(channel) { From da7187d6fd049539778dbf43895c845f9bed4787 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 21 Sep 2017 11:17:16 +0200 Subject: [PATCH 0559/2114] Increase write enqueuing for persistence test --- .../com/rabbitmq/client/test/server/PersistenceGuarantees.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/client/test/server/PersistenceGuarantees.java b/src/test/java/com/rabbitmq/client/test/server/PersistenceGuarantees.java index 904ec69d68..4070393600 100644 --- a/src/test/java/com/rabbitmq/client/test/server/PersistenceGuarantees.java +++ b/src/test/java/com/rabbitmq/client/test/server/PersistenceGuarantees.java @@ -34,7 +34,8 @@ protected NioParams nioParams() { NioParams nioParams = super.nioParams(); // may need a higher enqueuing timeout on slow environments return nioParams - .setWriteEnqueuingTimeoutInMs(nioParams.getWriteEnqueuingTimeoutInMs() * 2); + .setWriteEnqueuingTimeoutInMs(nioParams.getWriteEnqueuingTimeoutInMs() * 3) + .setWriteQueueCapacity(nioParams.getWriteQueueCapacity() * 2); } protected void declareQueue() throws IOException { From 5b92eac4ffa72e58f67e12aabcc7b7a2ce35bb9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 21 Sep 2017 11:27:54 +0200 Subject: [PATCH 0560/2114] Improve ByteBuffer#flip logic when using TLS Fixes #307 --- .../impl/nio/SslEngineByteBufferInputStream.java | 9 ++++----- .../test/ssl/NioTlsUnverifiedConnection.java | 14 +++++++++----- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferInputStream.java b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferInputStream.java index 2f41ee1cd9..f494814ef5 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferInputStream.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferInputStream.java @@ -66,16 +66,15 @@ public int read() throws IOException { } int bytesRead = NioHelper.read(channel, cipherIn); - if (bytesRead > 0) { - cipherIn.flip(); - } else { + // see https://github.com/rabbitmq/rabbitmq-java-client/issues/307 + if (bytesRead <= 0) { bytesRead = NioHelper.retryRead(channel, cipherIn); if(bytesRead <= 0) { throw new IllegalStateException("Should be reading something from the network"); } - // see https://github.com/rabbitmq/rabbitmq-java-client/issues/307 - cipherIn.flip(); } + cipherIn.flip(); + plainIn.clear(); result = sslEngine.unwrap(cipherIn, plainIn); diff --git a/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java index d3336dc3c0..ef65a5ed2c 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java @@ -95,11 +95,14 @@ public void configure(SSLEngine sslEngine) throws IOException { } } - @Test public void largeMessage() throws Exception { - CountDownLatch latch = new CountDownLatch(1); - connection = basicGetBasicConsume(connection, "tls.nio.queue", latch, 1 * 1000 * 1000); - boolean messagesReceived = latch.await(5, TimeUnit.SECONDS); - assertTrue("Message has not been received", messagesReceived); + @Test public void messageSize() throws Exception { + int [] sizes = new int [] {100, 1000, 10 * 1000, 1 * 1000 * 1000, 5 * 1000 * 1000}; + for(int size : sizes) { + CountDownLatch latch = new CountDownLatch(1); + connection = basicGetBasicConsume(connection, "tls.nio.queue", latch, size); + boolean messagesReceived = latch.await(5, TimeUnit.SECONDS); + assertTrue("Message has not been received", messagesReceived); + } } private Connection basicGetBasicConsume(Connection connection, String queue, final CountDownLatch latch, int msgSize) @@ -116,6 +119,7 @@ private Connection basicGetBasicConsume(Connection connection, String queue, fin public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { getChannel().basicAck(envelope.getDeliveryTag(), false); latch.countDown(); + getChannel().basicCancel(consumerTag); } }); From 9d2a75a505f3bca5782e759ac98b52e042679bbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 21 Sep 2017 14:14:33 +0200 Subject: [PATCH 0561/2114] Set release version to 4.2.2 --- release-versions.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release-versions.txt b/release-versions.txt index acc8f7662a..c7cbb4969f 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="4.2.2.RC1" -DEVELOPMENT_VERSION="4.2.2-SNAPSHOT" +RELEASE_VERSION="4.2.2" +DEVELOPMENT_VERSION="4.2.333-SNAPSHOT" From dfab3117b7d37dcecb8b2a8e3677036d23d3117a Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Thu, 21 Sep 2017 12:16:41 +0000 Subject: [PATCH 0562/2114] [maven-release-plugin] prepare release v4.2.2 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 19840a64cb..90921e2593 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.2.2-SNAPSHOT + 4.2.2 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v4.2.2 From 3296c4da2843f08a2d10886647bbfc82cc4b37b0 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Thu, 21 Sep 2017 12:16:47 +0000 Subject: [PATCH 0563/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 90921e2593..4c358d0922 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.2.2 + 4.2.333-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v4.2.2 + HEAD From 804f9d5dc64ace9fe3edbcee4fa553e5b1b1d4bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 22 Sep 2017 14:08:25 +0200 Subject: [PATCH 0564/2114] Set release version to 5.0.0 --- release-versions.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release-versions.txt b/release-versions.txt index 784f5a2979..1d7938e9cd 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="5.0.0.RC22" -DEVELOPMENT_VERSION="5.0.0-SNAPSHOT" +RELEASE_VERSION="5.0.0" +DEVELOPMENT_VERSION="5.0.1-SNAPSHOT" From 51e11dedb26121f57c5be83527c890640f9b8f5f Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Fri, 22 Sep 2017 12:10:39 +0000 Subject: [PATCH 0565/2114] [maven-release-plugin] prepare release v5.0.0 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index f770a0dddd..6e6712fa10 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.0.0-SNAPSHOT + 5.0.0 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v5.0.0 From 9d905a118d68fffcfd15273a2963f145fbd4cf82 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Fri, 22 Sep 2017 12:10:45 +0000 Subject: [PATCH 0566/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 6e6712fa10..6c89bda91a 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.0.0 + 5.0.1-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v5.0.0 + HEAD From 4a77ed1cabd05d5adaca6c8813aedcea9da9dc36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 22 Sep 2017 15:20:40 +0200 Subject: [PATCH 0567/2114] Update copyright date in code --- README.md | 6 +++--- src/main/java/com/rabbitmq/client/impl/AMQConnection.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index e6219790b9..4e9badcc6c 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ a [Maven repository with milestone releases](https://bintray.com/rabbitmq/maven- [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.rabbitmq/amqp-client/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.rabbitmq/amqp-client) -#### 4.x Series +#### 4.x+ Series Starting with `4.0`, this client releases are independent from RabbitMQ server releases. These versions can still be used with RabbitMQ server `3.x`. @@ -23,14 +23,14 @@ These versions can still be used with RabbitMQ server `3.x`. com.rabbitmq amqp-client - 4.0.2 + 5.0.0 ``` ### Gradle ``` groovy -compile 'com.rabbitmq:amqp-client:4.0.2' +compile 'com.rabbitmq:amqp-client:5.0.0' ``` #### 3.6.x Series diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index aeb5e35884..97d4b7ac8a 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -34,7 +34,7 @@ import java.util.concurrent.*; final class Copyright { - final static String COPYRIGHT="Copyright (c) 2007-2016 Pivotal Software, Inc."; + final static String COPYRIGHT="Copyright (c) 2007-2017 Pivotal Software, Inc."; final static String LICENSE="Licensed under the MPL. See http://www.rabbitmq.com/"; } From 21028f9cd4d84a09e4f63feff10724a918e4815c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 22 Sep 2017 15:23:14 +0200 Subject: [PATCH 0568/2114] Set POM version to 4.2.3-SNAPSHOT --- pom.xml | 2 +- release-versions.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 4c358d0922..d09e52c8ac 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.2.333-SNAPSHOT + 4.2.3-SNAPSHOT jar RabbitMQ Java Client diff --git a/release-versions.txt b/release-versions.txt index c7cbb4969f..d079228ee2 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ RELEASE_VERSION="4.2.2" -DEVELOPMENT_VERSION="4.2.333-SNAPSHOT" +DEVELOPMENT_VERSION="4.2.3-SNAPSHOT" From 55d6fe2d96a58425d1ddcbbdd80644de57fe5815 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Tue, 26 Sep 2017 15:12:07 +0300 Subject: [PATCH 0569/2114] Handle alpha version suffixes --- src/test/java/com/rabbitmq/client/test/TestUtils.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/test/java/com/rabbitmq/client/test/TestUtils.java b/src/test/java/com/rabbitmq/client/test/TestUtils.java index a43db542e5..0ef6d16878 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtils.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtils.java @@ -46,9 +46,14 @@ public static void close(Connection connection) { public static boolean isVersion37orLater(Connection connection) { String currentVersion = connection.getServerProperties().get("version").toString(); + // versions built from source: 3.7.0+rc.1.4.gedc5d96 if (currentVersion.contains("+")) { currentVersion = currentVersion.substring(0, currentVersion.indexOf("+")); } + // alpha (snapshot) versions: 3.7.0~alpha.449-1 + if (currentVersion.contains("~")) { + currentVersion = currentVersion.substring(0, currentVersion.indexOf("~")); + } return "0.0.0".equals(currentVersion) ? true : versionCompare(currentVersion, "3.7.0") >= 0; } From 96c6cc3a7d1766c1015fe0d9ca8d7eaba2523a55 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Tue, 26 Sep 2017 18:48:03 +0300 Subject: [PATCH 0570/2114] Simplify --- src/test/java/com/rabbitmq/client/test/TestUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/client/test/TestUtils.java b/src/test/java/com/rabbitmq/client/test/TestUtils.java index 0ef6d16878..bdabb3f941 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtils.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtils.java @@ -54,7 +54,7 @@ public static boolean isVersion37orLater(Connection connection) { if (currentVersion.contains("~")) { currentVersion = currentVersion.substring(0, currentVersion.indexOf("~")); } - return "0.0.0".equals(currentVersion) ? true : versionCompare(currentVersion, "3.7.0") >= 0; + return "0.0.0".equals(currentVersion) || versionCompare(currentVersion, "3.7.0") >= 0; } /** From d291d3f3034d99f59b0f2e17336a1e85ef709fc3 Mon Sep 17 00:00:00 2001 From: Michael Dent Date: Wed, 27 Sep 2017 13:30:20 -0500 Subject: [PATCH 0571/2114] channel cleanup --- .../impl/recovery/AutorecoveringChannel.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java index 2ce488f00d..d9fc475370 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java @@ -67,21 +67,26 @@ public void close() throws IOException, TimeoutException { try { delegate.close(); } finally { - for (String consumerTag : consumerTags) { - this.connection.deleteRecordedConsumer(consumerTag); - } - this.connection.unregisterChannel(this); + recoveryCleanup(); } } @Override public void close(int closeCode, String closeMessage) throws IOException, TimeoutException { try { - delegate.close(closeCode, closeMessage); + delegate.close(closeCode, closeMessage); } finally { - this.connection.unregisterChannel(this); + recoveryCleanup(); } } + + private void recoveryCleanup() { + for (String consumerTag : consumerTags) { + this.connection.deleteRecordedConsumer(consumerTag); + } + // TODO what about any other recorded queues and bindings that were owned by this channel? They will now cause recovery exceptions. + this.connection.unregisterChannel(this); + } @Override @Deprecated From caec3f77a1b54e818b752d707e0d236565c5f2bb Mon Sep 17 00:00:00 2001 From: Michael Dent Date: Wed, 27 Sep 2017 15:07:35 -0500 Subject: [PATCH 0572/2114] add RecoveryDelayHandler --- .../rabbitmq/client/ConnectionFactory.java | 10 ++++ .../rabbitmq/client/RecoveryDelayHandler.java | 46 +++++++++++++++++++ .../client/impl/ConnectionParams.java | 10 ++++ .../recovery/AutorecoveringConnection.java | 14 +++--- 4 files changed, 73 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/rabbitmq/client/RecoveryDelayHandler.java diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 2f32452dcd..8a872d42e1 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -112,6 +112,7 @@ public class ConnectionFactory implements Cloneable { // and longs safely. It is unlikely that anybody'd need // to use recovery intervals > Integer.MAX_VALUE in practice. private long networkRecoveryInterval = 5000; + private RecoveryDelayHandler recoveryDelayHandler; private MetricsCollector metricsCollector; @@ -960,6 +961,7 @@ public ConnectionParams params(ExecutorService consumerWorkServiceExecutor) { result.setShutdownTimeout(shutdownTimeout); result.setSaslConfig(saslConfig); result.setNetworkRecoveryInterval(networkRecoveryInterval); + result.setRecoveryDelayHandler(recoveryDelayHandler); result.setTopologyRecovery(topologyRecovery); result.setExceptionHandler(exceptionHandler); result.setThreadFactory(threadFactory); @@ -1077,6 +1079,14 @@ public void setNetworkRecoveryInterval(int networkRecoveryInterval) { public void setNetworkRecoveryInterval(long networkRecoveryInterval) { this.networkRecoveryInterval = networkRecoveryInterval; } + + public RecoveryDelayHandler getRecoveryDelayHandler() { + return recoveryDelayHandler; + } + + public void setRecoveryDelayHandler(final RecoveryDelayHandler recoveryDelayHandler) { + this.recoveryDelayHandler = recoveryDelayHandler; + } /** * Sets the parameters when using NIO. diff --git a/src/main/java/com/rabbitmq/client/RecoveryDelayHandler.java b/src/main/java/com/rabbitmq/client/RecoveryDelayHandler.java new file mode 100644 index 0000000000..4c578aefe2 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/RecoveryDelayHandler.java @@ -0,0 +1,46 @@ +package com.rabbitmq.client; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public interface RecoveryDelayHandler { + + long getDelay(final int recoveryAttempts); + + public static class DefaultRecoveryDelayHandler implements RecoveryDelayHandler { + + private final long networkRecoveryInterval; + + public DefaultRecoveryDelayHandler(final long networkRecoveryInterval) { + this.networkRecoveryInterval = networkRecoveryInterval; + } + + @Override + public long getDelay(int recoveryAttempts) { + return networkRecoveryInterval; + } + + } + + public static class ExponentialBackoffDelayHandler implements RecoveryDelayHandler { + + private final List sequence; + + public ExponentialBackoffDelayHandler() { + sequence = Arrays.asList(0L, 1000L, 1000L, 2000L, 3000L, 5000L, 8000L, 13000L, 21000L); + } + + public ExponentialBackoffDelayHandler(final List sequence) { + if (sequence.isEmpty()) + throw new IllegalArgumentException(); + this.sequence = Collections.unmodifiableList(sequence); + + } + + @Override + public long getDelay(int recoveryAttempts) { + return sequence.get(recoveryAttempts >= sequence.size() ? sequence.size() - 1 : recoveryAttempts); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java b/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java index e0eb8a5d78..62f91b8a98 100644 --- a/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java +++ b/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java @@ -16,6 +16,7 @@ package com.rabbitmq.client.impl; import com.rabbitmq.client.ExceptionHandler; +import com.rabbitmq.client.RecoveryDelayHandler; import com.rabbitmq.client.SaslConfig; import java.util.Map; @@ -38,6 +39,7 @@ public class ConnectionParams { private int shutdownTimeout; private SaslConfig saslConfig; private long networkRecoveryInterval; + private RecoveryDelayHandler recoveryDelayHandler; private boolean topologyRecovery; private int channelRpcTimeout; private boolean channelShouldCheckRpcResponseType; @@ -102,6 +104,10 @@ public ExceptionHandler getExceptionHandler() { public long getNetworkRecoveryInterval() { return networkRecoveryInterval; } + + public RecoveryDelayHandler getRecoveryDelayHandler() { + return recoveryDelayHandler == null ? new RecoveryDelayHandler.DefaultRecoveryDelayHandler(networkRecoveryInterval) : recoveryDelayHandler; + } public boolean isTopologyRecoveryEnabled() { return topologyRecovery; @@ -162,6 +168,10 @@ public void setSaslConfig(SaslConfig saslConfig) { public void setNetworkRecoveryInterval(long networkRecoveryInterval) { this.networkRecoveryInterval = networkRecoveryInterval; } + + public void setRecoveryDelayHandler(final RecoveryDelayHandler recoveryDelayHandler) { + this.recoveryDelayHandler = recoveryDelayHandler; + } public void setTopologyRecovery(boolean topologyRecovery) { this.topologyRecovery = topologyRecovery; diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index 2ecc7c878f..cccac5e5f6 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -487,7 +487,7 @@ public void removeConsumerRecoveryListener(ConsumerRecoveryListener listener) { } synchronized private void beginAutomaticRecovery() throws InterruptedException { - Thread.sleep(this.params.getNetworkRecoveryInterval()); + Thread.sleep(this.params.getRecoveryDelayHandler().getDelay(0)); this.notifyRecoveryListenersStarted(); @@ -525,9 +525,10 @@ private void recoverBlockedListeners(final RecoveryAwareAMQConnection newConn) { // Returns new connection if the connection was recovered, // null if application initiated shutdown while attempting recovery. private RecoveryAwareAMQConnection recoverConnection() throws InterruptedException { - while (!manuallyClosed) - { + int attempts = 0; + while (!manuallyClosed) { try { + attempts++; RecoveryAwareAMQConnection newConn = this.cf.newConnection(); synchronized(recoveryLock) { if (!manuallyClosed) { @@ -541,8 +542,7 @@ private RecoveryAwareAMQConnection recoverConnection() throws InterruptedExcepti newConn.abort(); return null; } catch (Exception e) { - // TODO: exponential back-off - Thread.sleep(this.params.getNetworkRecoveryInterval()); + Thread.sleep(this.params.getRecoveryDelayHandler().getDelay(attempts)); this.getExceptionHandler().handleConnectionRecoveryException(this, e); } } @@ -561,13 +561,13 @@ private void recoverChannels(final RecoveryAwareAMQConnection newConn) { } private void notifyRecoveryListenersComplete() { - for (RecoveryListener f : this.recoveryListeners) { + for (RecoveryListener f : Utility.copy(this.recoveryListeners)) { f.handleRecovery(this); } } private void notifyRecoveryListenersStarted() { - for (RecoveryListener f : this.recoveryListeners) { + for (RecoveryListener f : Utility.copy(this.recoveryListeners)) { f.handleRecoveryStarted(this); } } From d4c93aba3301269560357eafc60eecd705b8ca1c Mon Sep 17 00:00:00 2001 From: Michael Dent Date: Wed, 4 Oct 2017 14:58:12 -0500 Subject: [PATCH 0573/2114] adding javadoc and test. undoing channel close change --- .../rabbitmq/client/ConnectionFactory.java | 13 ++++- .../rabbitmq/client/RecoveryDelayHandler.java | 39 ++++++++++++- .../client/impl/ConnectionParams.java | 7 ++- .../impl/recovery/AutorecoveringChannel.java | 17 ++---- .../client/test/RecoveryDelayHandlerTest.java | 58 +++++++++++++++++++ 5 files changed, 118 insertions(+), 16 deletions(-) create mode 100644 src/test/java/com/rabbitmq/client/test/RecoveryDelayHandlerTest.java diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 8a872d42e1..c7c7b4d40c 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -77,6 +77,9 @@ public class ConnectionFactory implements Cloneable { /** The default continuation timeout for RPC calls in channels: 10 minutes */ public static final int DEFAULT_CHANNEL_RPC_TIMEOUT = (int) MINUTES.toMillis(10); + + /** The default network recovery interval: 5000 millis */ + public static final long DEFAULT_NETWORK_RECOVERY_INTERVAL = 5000; private static final String PREFERRED_TLS_PROTOCOL = "TLSv1.2"; @@ -111,7 +114,7 @@ public class ConnectionFactory implements Cloneable { // long is used to make sure the users can use both ints // and longs safely. It is unlikely that anybody'd need // to use recovery intervals > Integer.MAX_VALUE in practice. - private long networkRecoveryInterval = 5000; + private long networkRecoveryInterval = DEFAULT_NETWORK_RECOVERY_INTERVAL; private RecoveryDelayHandler recoveryDelayHandler; private MetricsCollector metricsCollector; @@ -1080,10 +1083,18 @@ public void setNetworkRecoveryInterval(long networkRecoveryInterval) { this.networkRecoveryInterval = networkRecoveryInterval; } + /** + * Returns automatic connection recovery delay handler. + * @return recovery delay handler. May be null if not set. + */ public RecoveryDelayHandler getRecoveryDelayHandler() { return recoveryDelayHandler; } + /** + * Sets the automatic connection recovery delay handler. + * @param recoveryDelayHandler the recovery delay handler + */ public void setRecoveryDelayHandler(final RecoveryDelayHandler recoveryDelayHandler) { this.recoveryDelayHandler = recoveryDelayHandler; } diff --git a/src/main/java/com/rabbitmq/client/RecoveryDelayHandler.java b/src/main/java/com/rabbitmq/client/RecoveryDelayHandler.java index 4c578aefe2..09c47593e0 100644 --- a/src/main/java/com/rabbitmq/client/RecoveryDelayHandler.java +++ b/src/main/java/com/rabbitmq/client/RecoveryDelayHandler.java @@ -4,14 +4,35 @@ import java.util.Collections; import java.util.List; +/** + * A RecoveryDelayHandler is used to tell automatic recovery how long to sleep between reconnect attempts. + * + * @since 4.3.0 + */ public interface RecoveryDelayHandler { + /** + * Get the time to sleep (in milliseconds) before attempting to reconnect and recover again. + * This method will be called with recoveryAttempts=0 before the first recovery attempt and then again after each failed recovery. + * + * @param recoveryAttempts + * The number of recovery attempts so far. + * @return the delay in milliseconds + */ long getDelay(final int recoveryAttempts); + /** + * Basic implementation of {@link RecoveryDelayHandler} that returns the {@link ConnectionFactory#getNetworkRecoveryInterval() network recovery interval} each time. + */ public static class DefaultRecoveryDelayHandler implements RecoveryDelayHandler { private final long networkRecoveryInterval; + /** + * Default Constructor + * @param networkRecoveryInterval + * recovery delay time in millis + */ public DefaultRecoveryDelayHandler(final long networkRecoveryInterval) { this.networkRecoveryInterval = networkRecoveryInterval; } @@ -20,22 +41,34 @@ public DefaultRecoveryDelayHandler(final long networkRecoveryInterval) { public long getDelay(int recoveryAttempts) { return networkRecoveryInterval; } - } + /** + * Backoff implementation of {@link RecoveryDelayHandler} that uses the Fibonacci sequence (by default) to increase the recovery delay time after each failed attempt. + * You can optionally use your own backoff sequence. + */ public static class ExponentialBackoffDelayHandler implements RecoveryDelayHandler { private final List sequence; + /** + * Default Constructor. Uses the fibonacci sequence: {0, 1000, 1000, 2000, 3000, 5000, 8000, 13000, 21000}. + */ public ExponentialBackoffDelayHandler() { sequence = Arrays.asList(0L, 1000L, 1000L, 2000L, 3000L, 5000L, 8000L, 13000L, 21000L); } + /** + * Constructor for passing your own backoff sequence + * + * @param sequence + * List of recovery delay values in milliseconds. + * @throws IllegalArgumentException if the sequence is null or empty + */ public ExponentialBackoffDelayHandler(final List sequence) { - if (sequence.isEmpty()) + if (sequence == null || sequence.isEmpty()) throw new IllegalArgumentException(); this.sequence = Collections.unmodifiableList(sequence); - } @Override diff --git a/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java b/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java index 62f91b8a98..40a82f2ffc 100644 --- a/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java +++ b/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java @@ -17,6 +17,7 @@ import com.rabbitmq.client.ExceptionHandler; import com.rabbitmq.client.RecoveryDelayHandler; +import com.rabbitmq.client.RecoveryDelayHandler.DefaultRecoveryDelayHandler; import com.rabbitmq.client.SaslConfig; import java.util.Map; @@ -105,8 +106,12 @@ public long getNetworkRecoveryInterval() { return networkRecoveryInterval; } + /** + * Get the recovery delay handler. + * @return recovery delay handler or if none was set a {@link DefaultRecoveryDelayHandler} will be returned with a delay of {@link #getNetworkRecoveryInterval()}. + */ public RecoveryDelayHandler getRecoveryDelayHandler() { - return recoveryDelayHandler == null ? new RecoveryDelayHandler.DefaultRecoveryDelayHandler(networkRecoveryInterval) : recoveryDelayHandler; + return recoveryDelayHandler == null ? new DefaultRecoveryDelayHandler(networkRecoveryInterval) : recoveryDelayHandler; } public boolean isTopologyRecoveryEnabled() { diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java index d9fc475370..2ce488f00d 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java @@ -67,26 +67,21 @@ public void close() throws IOException, TimeoutException { try { delegate.close(); } finally { - recoveryCleanup(); + for (String consumerTag : consumerTags) { + this.connection.deleteRecordedConsumer(consumerTag); + } + this.connection.unregisterChannel(this); } } @Override public void close(int closeCode, String closeMessage) throws IOException, TimeoutException { try { - delegate.close(closeCode, closeMessage); + delegate.close(closeCode, closeMessage); } finally { - recoveryCleanup(); + this.connection.unregisterChannel(this); } } - - private void recoveryCleanup() { - for (String consumerTag : consumerTags) { - this.connection.deleteRecordedConsumer(consumerTag); - } - // TODO what about any other recorded queues and bindings that were owned by this channel? They will now cause recovery exceptions. - this.connection.unregisterChannel(this); - } @Override @Deprecated diff --git a/src/test/java/com/rabbitmq/client/test/RecoveryDelayHandlerTest.java b/src/test/java/com/rabbitmq/client/test/RecoveryDelayHandlerTest.java new file mode 100644 index 0000000000..884b7c3ad9 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/RecoveryDelayHandlerTest.java @@ -0,0 +1,58 @@ +package com.rabbitmq.client.test; + +import static org.junit.Assert.assertEquals; + +import java.util.Arrays; +import java.util.Collections; + +import com.rabbitmq.client.RecoveryDelayHandler; +import com.rabbitmq.client.RecoveryDelayHandler.DefaultRecoveryDelayHandler; +import com.rabbitmq.client.RecoveryDelayHandler.ExponentialBackoffDelayHandler; + +import org.junit.Test; + +public class RecoveryDelayHandlerTest { + + @Test + public void testDefaultRecoveryDelayHandler() { + final RecoveryDelayHandler handler = new DefaultRecoveryDelayHandler(5000); + assertEquals(5000L, handler.getDelay(0)); + assertEquals(5000L, handler.getDelay(1)); + assertEquals(5000L, handler.getDelay(Integer.MAX_VALUE)); + } + + @Test + public void testExponentialBackoffDelayHandler_default() { + final RecoveryDelayHandler handler = new ExponentialBackoffDelayHandler(); + assertEquals(0, handler.getDelay(0)); + assertEquals(1000L, handler.getDelay(1)); + assertEquals(1000L, handler.getDelay(2)); + assertEquals(2000L, handler.getDelay(3)); + assertEquals(3000L, handler.getDelay(4)); + assertEquals(5000L, handler.getDelay(5)); + assertEquals(8000L, handler.getDelay(6)); + assertEquals(13000L, handler.getDelay(7)); + assertEquals(21000L, handler.getDelay(8)); + assertEquals(21000L, handler.getDelay(9)); + assertEquals(21000L, handler.getDelay(Integer.MAX_VALUE)); + } + + @Test + public void testExponentialBackoffDelayHandler_sequence() { + final RecoveryDelayHandler handler = new ExponentialBackoffDelayHandler(Arrays.asList(1L, 2L)); + assertEquals(1, handler.getDelay(0)); + assertEquals(2, handler.getDelay(1)); + assertEquals(2, handler.getDelay(2)); + assertEquals(2, handler.getDelay(Integer.MAX_VALUE)); + } + + @Test(expected=IllegalArgumentException.class) + public void testExponentialBackoffDelayHandler_sequence_null() { + new ExponentialBackoffDelayHandler(null); + } + + @Test(expected=IllegalArgumentException.class) + public void testExponentialBackoffDelayHandler_sequence_empty() { + new ExponentialBackoffDelayHandler(Collections.emptyList()); + } +} From 7559d507248254b847a536379471af014f024305 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 5 Oct 2017 11:49:54 +0200 Subject: [PATCH 0574/2114] Add integration test for ExponentialBackoffDelayHandler References #308 --- .../rabbitmq/client/ConnectionFactory.java | 8 ++++++++ .../rabbitmq/client/RecoveryDelayHandler.java | 19 +++++++++++++++++-- .../com/rabbitmq/client/test/ClientTests.java | 3 ++- .../client/test/RecoveryDelayHandlerTest.java | 15 +++++++++++++++ .../test/functional/ConnectionRecovery.java | 13 +++++++++++++ 5 files changed, 55 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index c7c7b4d40c..4074f9d448 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -1069,7 +1069,10 @@ public long getNetworkRecoveryInterval() { /** * Sets connection recovery interval. Default is 5000. + * Uses {@link com.rabbitmq.client.RecoveryDelayHandler.DefaultRecoveryDelayHandler} by default. + * Use another {@link RecoveryDelayHandler} implementation for more flexibility. * @param networkRecoveryInterval how long will automatic recovery wait before attempting to reconnect, in ms + * @see RecoveryDelayHandler */ public void setNetworkRecoveryInterval(int networkRecoveryInterval) { this.networkRecoveryInterval = networkRecoveryInterval; @@ -1077,7 +1080,10 @@ public void setNetworkRecoveryInterval(int networkRecoveryInterval) { /** * Sets connection recovery interval. Default is 5000. + * Uses {@link com.rabbitmq.client.RecoveryDelayHandler.DefaultRecoveryDelayHandler} by default. + * Use another {@link RecoveryDelayHandler} implementation for more flexibility. * @param networkRecoveryInterval how long will automatic recovery wait before attempting to reconnect, in ms + * @see RecoveryDelayHandler */ public void setNetworkRecoveryInterval(long networkRecoveryInterval) { this.networkRecoveryInterval = networkRecoveryInterval; @@ -1086,6 +1092,7 @@ public void setNetworkRecoveryInterval(long networkRecoveryInterval) { /** * Returns automatic connection recovery delay handler. * @return recovery delay handler. May be null if not set. + * @since 4.3.0 */ public RecoveryDelayHandler getRecoveryDelayHandler() { return recoveryDelayHandler; @@ -1094,6 +1101,7 @@ public RecoveryDelayHandler getRecoveryDelayHandler() { /** * Sets the automatic connection recovery delay handler. * @param recoveryDelayHandler the recovery delay handler + * @since 4.3.0 */ public void setRecoveryDelayHandler(final RecoveryDelayHandler recoveryDelayHandler) { this.recoveryDelayHandler = recoveryDelayHandler; diff --git a/src/main/java/com/rabbitmq/client/RecoveryDelayHandler.java b/src/main/java/com/rabbitmq/client/RecoveryDelayHandler.java index 09c47593e0..045c11045c 100644 --- a/src/main/java/com/rabbitmq/client/RecoveryDelayHandler.java +++ b/src/main/java/com/rabbitmq/client/RecoveryDelayHandler.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client; import java.util.Arrays; @@ -24,7 +39,7 @@ public interface RecoveryDelayHandler { /** * Basic implementation of {@link RecoveryDelayHandler} that returns the {@link ConnectionFactory#getNetworkRecoveryInterval() network recovery interval} each time. */ - public static class DefaultRecoveryDelayHandler implements RecoveryDelayHandler { + class DefaultRecoveryDelayHandler implements RecoveryDelayHandler { private final long networkRecoveryInterval; @@ -47,7 +62,7 @@ public long getDelay(int recoveryAttempts) { * Backoff implementation of {@link RecoveryDelayHandler} that uses the Fibonacci sequence (by default) to increase the recovery delay time after each failed attempt. * You can optionally use your own backoff sequence. */ - public static class ExponentialBackoffDelayHandler implements RecoveryDelayHandler { + class ExponentialBackoffDelayHandler implements RecoveryDelayHandler { private final List sequence; diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index 918177fca6..2507f80952 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -48,7 +48,8 @@ JavaNioTest.class, ConnectionFactoryTest.class, RecoveryAwareAMQConnectionFactoryTest.class, - RpcTest.class + RpcTest.class, + RecoveryDelayHandlerTest.class }) public class ClientTests { diff --git a/src/test/java/com/rabbitmq/client/test/RecoveryDelayHandlerTest.java b/src/test/java/com/rabbitmq/client/test/RecoveryDelayHandlerTest.java index 884b7c3ad9..b73870784c 100644 --- a/src/test/java/com/rabbitmq/client/test/RecoveryDelayHandlerTest.java +++ b/src/test/java/com/rabbitmq/client/test/RecoveryDelayHandlerTest.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.test; import static org.junit.Assert.assertEquals; diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java index 17a01db042..1ad6feb960 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -720,6 +720,19 @@ public void handleDelivery(String consumerTag, } } + @Test public void recoveryWithExponentialBackoffDelayHandler() throws Exception { + ConnectionFactory connectionFactory = TestUtils.connectionFactory(); + connectionFactory.setRecoveryDelayHandler(new RecoveryDelayHandler.ExponentialBackoffDelayHandler()); + Connection testConnection = connectionFactory.newConnection(); + try { + assertTrue(testConnection.isOpen()); + closeAndWaitForRecovery((RecoverableConnection) testConnection); + assertTrue(testConnection.isOpen()); + } finally { + connection.close(); + } + } + private void assertConsumerCount(int exp, String q) throws IOException { assertEquals(exp, channel.queueDeclarePassive(q).getConsumerCount()); } From 84e8a351a9698a4496c111fd203ebfab15d3afa0 Mon Sep 17 00:00:00 2001 From: Luke Bakken Date: Sun, 8 Oct 2017 11:14:25 -0700 Subject: [PATCH 0575/2114] Add GitHub issue and pull request templates, update CONTRIBUTING.md --- .github/ISSUE_TEMPLATE.md | 43 ++++++++++++++ .github/PULL_REQUEST_TEMPLATE.md | 43 ++++++++++++++ CONTRIBUTING.md | 97 ++++++++++++++++++++++++++------ 3 files changed, 165 insertions(+), 18 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000000..70b54cd818 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,43 @@ +Thank you for using RabbitMQ and for taking the time to report an +issue. + +## Does This Belong to GitHub or RabbitMQ Mailing List? + +*Important:* please first read the `CONTRIBUTING.md` document in the +root of this repository. It will help you determine whether your +feedback should be directed to the RabbitMQ mailing list [1] instead. + +## Please Help Maintainers and Contributors Help You + +In order for the RabbitMQ team to investigate your issue, please provide +**as much as possible** of the following details: + +* RabbitMQ version +* Erlang version +* RabbitMQ server and client application log files +* A runnable code sample, terminal transcript or detailed set of + instructions that can be used to reproduce the issue +* RabbitMQ plugin information via `rabbitmq-plugins list` +* Client library version (for all libraries used) +* Operating system, version, and patch level + +Running the `rabbitmq-collect-env` [2] script can provide most of the +information needed. Please make the archive available via a third-party +service and note that **the script does not attempt to scrub any +sensitive data**. + +If your issue involves RabbitMQ management UI or HTTP API, please also provide +the following: + + * Browser and its version + * What management UI page was used (if applicable) + * How the HTTP API requests performed can be reproduced with `curl` + * Operating system on which you are running your browser, and its version + * Errors reported in the JavaScript console (if any) + +This information **greatly speeds up issue investigation** (or makes it +possible to investigate it at all). Please help project maintainers and +contributors to help you by providing it! + +1. https://groups.google.com/forum/#!forum/rabbitmq-users +2. https://github.com/rabbitmq/support-tools/blob/master/scripts/rabbitmq-collect-env diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000000..4bd618567b --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,43 @@ +## Proposed Changes + +Please describe the big picture of your changes here to communicate to the +RabbitMQ team why we should accept this pull request. If it fixes a bug or +resolves a feature request, be sure to link to that issue. + +A pull request that doesn't explain **why** the change was made has a much +lower chance of being accepted. + +If English isn't your first language, don't worry about it and try to +communicate the problem you are trying to solve to the best of your abilities. +As long as we can understand the intent, it's all good. + +## Types of Changes + +What types of changes does your code introduce to this project? +_Put an `x` in the boxes that apply_ + +- [ ] Bugfix (non-breaking change which fixes issue #NNNN) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) +- [ ] Documentation (correction or otherwise) +- [ ] Cosmetics (whitespace, appearance) + +## Checklist + +_Put an `x` in the boxes that apply. You can also fill these out after creating +the PR. If you're unsure about any of them, don't hesitate to ask on the +mailing list. We're here to help! This is simply a reminder of what we are +going to look for before merging your code._ + +- [ ] I have read the `CONTRIBUTING.md` document +- [ ] I have signed the CA (see https://cla.pivotal.io/sign/rabbitmq) +- [ ] All tests pass locally with my changes +- [ ] I have added tests that prove my fix is effective or that my feature works +- [ ] I have added necessary documentation (if appropriate) +- [ ] Any dependent changes have been merged and published in related repositories + +## Further Comments + +If this is a relatively large or complex change, kick off the discussion by +explaining why you chose the solution you did and what alternatives you +considered, etc. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 45bbcbe62e..16ee8fb67d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,38 +1,99 @@ +Thank you for using RabbitMQ and for taking the time to contribute to the project. +This document has two main parts: + + * when and how to file GitHub issues for RabbitMQ projects + * how to submit pull requests + +They intend to save you and RabbitMQ maintainers some time, so please +take a moment to read through them. + ## Overview +### GitHub issues + +The RabbitMQ team uses GitHub issues for _specific actionable items_ that +engineers can work on. This assumes the following: + +* GitHub issues are not used for questions, investigations, root cause + analysis, discussions of potential issues, etc (as defined by this team) +* Enough information is provided by the reporter for maintainers to work with + +The team receives many questions through various venues every single +day. Frequently, these questions do not include the necessary details +the team needs to begin useful work. GitHub issues can very quickly +turn into a something impossible to navigate and make sense +of. Because of this, questions, investigations, root cause analysis, +and discussions of potential features are all considered to be +[mailing list][rmq-users] material. If you are unsure where to begin, +the [RabbitMQ users mailing list][rmq-users] is the right place. + +Getting all the details necessary to reproduce an issue, make a +conclusion or even form a hypothesis about what's happening can take a +fair amount of time. Please help others help you by providing a way to +reproduce the behavior you're observing, or at least sharing as much +relevant information as possible on the [RabbitMQ users mailing +list][rmq-users]. + +Please provide versions of the software used: + + * RabbitMQ server + * Erlang + * Operating system version (and distribution, if applicable) + * All client libraries used + * RabbitMQ plugins (if applicable) + +The following information greatly helps in investigating and reproducing issues: + + * RabbitMQ server logs + * A code example or terminal transcript that can be used to reproduce + * Full exception stack traces (a single line message is not enough!) + * `rabbitmqctl report` and `rabbitmqctl environment` output + * Other relevant details about the environment and workload, e.g. a traffic capture + * Feel free to edit out hostnames and other potentially sensitive information. + +To make collecting much of this and other environment information, use +the [`rabbitmq-collect-env`][rmq-collect-env] script. It will produce an archive with +server logs, operating system logs, output of certain diagnostics commands and so on. +Please note that **no effort is made to scrub any information that may be sensitive**. + +### Pull Requests + RabbitMQ projects use pull requests to discuss, collaborate on and accept code contributions. Pull requests is the primary place of discussing code changes. -## How to Contribute - -The process is fairly standard: +Here's the recommended workflow: - * Fork the repository or repositories you plan on contributing to - * Clone [RabbitMQ umbrella repository](https://github.com/rabbitmq/rabbitmq-public-umbrella) - * `cd umbrella`, `make co` + * [Fork the repository][github-fork] or repositories you plan on contributing to. If multiple + repositories are involved in addressing the same issue, please use the same branch name + in each repository * Create a branch with a descriptive name in the relevant repositories - * Make your changes, run tests, commit with a [descriptive message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html), push to your fork + * Make your changes, run tests (usually with `make tests`), commit with a + [descriptive message][git-commit-msgs], push to your fork * Submit pull requests with an explanation what has been changed and **why** - * Submit a filled out and signed [Contributor Agreement](https://github.com/rabbitmq/ca#how-to-submit) if needed (see below) + * Submit a filled out and signed [Contributor Agreement][ca-agreement] if needed (see below) * Be patient. We will get to your pull request eventually -If what you are going to work on is a substantial change, please first ask the core team -of their opinion on [RabbitMQ mailing list](https://groups.google.com/forum/#!forum/rabbitmq-users). - +If what you are going to work on is a substantial change, please first +ask the core team for their opinion on the [RabbitMQ users mailing list][rmq-users]. ## Code of Conduct See [CODE_OF_CONDUCT.md](./CODE_OF_CONDUCT.md). - ## Contributor Agreement -If you want to contribute a non-trivial change, please submit a signed copy of our -[Contributor Agreement](https://github.com/rabbitmq/ca#how-to-submit) around the time -you submit your pull request. This will make it much easier (in some cases, possible) -for the RabbitMQ team at Pivotal to merge your contribution. - +If you want to contribute a non-trivial change, please submit a signed +copy of our [Contributor Agreement][ca-agreement] around the time you +submit your pull request. This will make it much easier (in some +cases, possible) for the RabbitMQ team at Pivotal to merge your +contribution. ## Where to Ask Questions -If something isn't clear, feel free to ask on our [mailing list](https://groups.google.com/forum/#!forum/rabbitmq-users). +If something isn't clear, feel free to ask on our [mailing list][rmq-users]. + +[rmq-collect-env]: https://github.com/rabbitmq/support-tools/blob/master/scripts/rabbitmq-collect-env +[git-commit-msgs]: https://goo.gl/xwWq +[rmq-users]: https://groups.google.com/forum/#!forum/rabbitmq-users +[ca-agreement]: https://cla.pivotal.io/sign/rabbitmq +[github-fork]: https://help.github.com/articles/fork-a-repo/ From b9ef75951e7a88ff2f9f1b9fb02dba898f3199e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 10 Oct 2017 15:01:51 +0200 Subject: [PATCH 0576/2114] Add support for Micrometer Micrometer supports metrics backend like Atlas, Datadog, Ganglia, Graphite, JMX, etc. Fixes #313 --- pom.xml | 7 + .../impl/MicrometerMetricsCollector.java | 193 ++++++++++++++++++ .../com/rabbitmq/client/test/ClientTests.java | 2 +- ...torTest.java => MetricsCollectorTest.java} | 104 ++++++++-- 4 files changed, 287 insertions(+), 19 deletions(-) create mode 100644 src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java rename src/test/java/com/rabbitmq/client/test/{StandardMetricsCollectorTest.java => MetricsCollectorTest.java} (56%) diff --git a/pom.xml b/pom.xml index 149af55524..e97b1fb15b 100644 --- a/pom.xml +++ b/pom.xml @@ -56,6 +56,7 @@ 1.7.21 3.1.2 + 1.0.0-rc.2 1.1.7 1.1 4.12 @@ -633,6 +634,12 @@ ${metrics.version} true + + io.micrometer + micrometer-core + ${micrometer.version} + true + commons-cli commons-cli diff --git a/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java new file mode 100644 index 0000000000..9d837036f7 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java @@ -0,0 +1,193 @@ +package com.rabbitmq.client.impl; + +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.MetricsCollector; +import io.micrometer.core.instrument.Counter; +import io.micrometer.core.instrument.MeterRegistry; + +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; + +import static com.rabbitmq.client.impl.MicrometerMetricsCollector.Metrics.ACKNOWLEDGED_MESSAGES; +import static com.rabbitmq.client.impl.MicrometerMetricsCollector.Metrics.CHANNELS; +import static com.rabbitmq.client.impl.MicrometerMetricsCollector.Metrics.CONNECTIONS; +import static com.rabbitmq.client.impl.MicrometerMetricsCollector.Metrics.CONSUMED_MESSAGES; +import static com.rabbitmq.client.impl.MicrometerMetricsCollector.Metrics.PUBLISHED_MESSAGES; +import static com.rabbitmq.client.impl.MicrometerMetricsCollector.Metrics.REJECTED_MESSAGES; + +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +/** + * Micrometer implementation of {@link MetricsCollector}. + * Note transactions are not supported (see {@link MetricsCollector}. + * Micrometer provides out-of-the-box support for report backends like JMX, + * Graphite, Ganglia, Atlas, Datadog, etc. See Micrometer documentation for + * more details. + * + * Note Micrometer requires Java 8 or more, so does this {@link MetricsCollector}. + * + * @see MetricsCollector + * @since 4.3.0 + */ +public class MicrometerMetricsCollector extends AbstractMetricsCollector { + + private final AtomicLong connections; + + private final AtomicLong channels; + + private final Counter publishedMessages; + + private final Counter consumedMessages; + + private final Counter acknowledgedMessages; + + private final Counter rejectedMessages; + + public MicrometerMetricsCollector(MeterRegistry registry) { + this(registry, "rabbitmq"); + } + + public MicrometerMetricsCollector(final MeterRegistry registry, final String prefix) { + this(new MetricsCreator() { + @Override + public Object create(Metrics metric) { + return metric.create(registry, prefix); + } + }); + } + + public MicrometerMetricsCollector(MetricsCreator creator) { + this.connections = (AtomicLong) creator.create(CONNECTIONS); + this.channels = (AtomicLong) creator.create(CHANNELS); + this.publishedMessages = (Counter) creator.create(PUBLISHED_MESSAGES); + this.consumedMessages = (Counter) creator.create(CONSUMED_MESSAGES); + this.acknowledgedMessages = (Counter) creator.create(ACKNOWLEDGED_MESSAGES); + this.rejectedMessages = (Counter) creator.create(REJECTED_MESSAGES); + } + + @Override + protected void incrementConnectionCount(Connection connection) { + connections.incrementAndGet(); + } + + @Override + protected void decrementConnectionCount(Connection connection) { + connections.decrementAndGet(); + } + + @Override + protected void incrementChannelCount(Channel channel) { + channels.incrementAndGet(); + } + + @Override + protected void decrementChannelCount(Channel channel) { + channels.decrementAndGet(); + } + + @Override + protected void markPublishedMessage() { + publishedMessages.increment(); + } + + @Override + protected void markConsumedMessage() { + consumedMessages.increment(); + } + + @Override + protected void markAcknowledgedMessage() { + acknowledgedMessages.increment(); + } + + @Override + protected void markRejectedMessage() { + rejectedMessages.increment(); + } + + public AtomicLong getConnections() { + return connections; + } + + public AtomicLong getChannels() { + return channels; + } + + public Counter getPublishedMessages() { + return publishedMessages; + } + + public Counter getConsumedMessages() { + return consumedMessages; + } + + public Counter getAcknowledgedMessages() { + return acknowledgedMessages; + } + + public Counter getRejectedMessages() { + return rejectedMessages; + } + + public enum Metrics { + CONNECTIONS { + @Override + Object create(MeterRegistry registry, String prefix) { + return registry.gauge(prefix + ".connections", new AtomicLong(0)); + } + }, + CHANNELS { + @Override + Object create(MeterRegistry registry, String prefix) { + return registry.gauge(prefix + ".channels", new AtomicLong(0)); + } + }, + PUBLISHED_MESSAGES { + @Override + Object create(MeterRegistry registry, String prefix) { + return registry.counter(prefix + ".published"); + } + }, + CONSUMED_MESSAGES { + @Override + Object create(MeterRegistry registry, String prefix) { + return registry.counter(prefix + ".consumed"); + } + }, + ACKNOWLEDGED_MESSAGES { + @Override + Object create(MeterRegistry registry, String prefix) { + return registry.counter(prefix + ".acknowledged"); + } + }, + REJECTED_MESSAGES { + @Override + Object create(MeterRegistry registry, String prefix) { + return registry.counter(prefix + ".rejected"); + } + }; + + abstract Object create(MeterRegistry registry, String prefix); + } + + public interface MetricsCreator { + + Object create(Metrics metric); + + } + +} diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index 2507f80952..1162bfa357 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -43,7 +43,7 @@ JSONReadWriteTest.class, SharedThreadPoolTest.class, DnsRecordIpAddressResolverTests.class, - StandardMetricsCollectorTest.class, + MetricsCollectorTest.class, DnsSrvRecordAddressResolverTest.class, JavaNioTest.class, ConnectionFactoryTest.class, diff --git a/src/test/java/com/rabbitmq/client/test/StandardMetricsCollectorTest.java b/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java similarity index 56% rename from src/test/java/com/rabbitmq/client/test/StandardMetricsCollectorTest.java rename to src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java index 0616baddb9..5aa6a24cdc 100644 --- a/src/test/java/com/rabbitmq/client/test/StandardMetricsCollectorTest.java +++ b/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java @@ -17,8 +17,14 @@ import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; +import com.rabbitmq.client.MetricsCollector; +import com.rabbitmq.client.impl.AbstractMetricsCollector; +import com.rabbitmq.client.impl.MicrometerMetricsCollector; import com.rabbitmq.client.impl.StandardMetricsCollector; +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; @@ -27,11 +33,23 @@ /** * */ -public class StandardMetricsCollectorTest { +@RunWith(Parameterized.class) +public class MetricsCollectorTest { + + @Parameterized.Parameters + public static Object[] data() { + // need to resort to a factory, as this method is called only once + // if creating the collector instance, it's reused across the test methods + // and this doesn't work (it cannot be reset) + return new Object[] { new StandardMetricsCollectorFactory(), new MicrometerMetricsCollectorFactory() }; + } + + @Parameterized.Parameter + public MetricsCollectorFactory factory; @Test public void basicGetAndAck() { - StandardMetricsCollector metrics = new StandardMetricsCollector(); + AbstractMetricsCollector metrics = factory.create(); Connection connection = mock(Connection.class); when(connection.getId()).thenReturn("connection-1"); Channel channel = mock(Channel.class); @@ -49,20 +67,20 @@ public void basicGetAndAck() { metrics.consumedMessage(channel, 6, false); metrics.basicAck(channel, 6, false); - assertThat(metrics.getAcknowledgedMessages().getCount(), is(1L)); + assertThat(acknowledgedMessages(metrics), is(1L)); metrics.basicAck(channel, 3, true); - assertThat(metrics.getAcknowledgedMessages().getCount(), is(1L+2L)); + assertThat(acknowledgedMessages(metrics), is(1L+2L)); metrics.basicAck(channel, 6, true); - assertThat(metrics.getAcknowledgedMessages().getCount(), is(1L+2L+1L)); + assertThat(acknowledgedMessages(metrics), is(1L+2L+1L)); metrics.basicAck(channel, 10, true); - assertThat(metrics.getAcknowledgedMessages().getCount(), is(1L+2L+1L)); + assertThat(acknowledgedMessages(metrics), is(1L+2L+1L)); } @Test public void basicConsumeAndAck() { - StandardMetricsCollector metrics = new StandardMetricsCollector(); + AbstractMetricsCollector metrics = factory.create(); Connection connection = mock(Connection.class); when(connection.getId()).thenReturn("connection-1"); Channel channel = mock(Channel.class); @@ -78,8 +96,8 @@ public void basicGetAndAck() { metrics.basicConsume(channel, consumerTagWithManualAck, false); metrics.consumedMessage(channel, 1, consumerTagWithAutoAck); - assertThat(metrics.getConsumedMessages().getCount(), is(1L)); - assertThat(metrics.getAcknowledgedMessages().getCount(), is(0L)); + assertThat(consumedMessages(metrics), is(1L)); + assertThat(acknowledgedMessages(metrics), is(0L)); metrics.consumedMessage(channel, 2, consumerTagWithManualAck); metrics.consumedMessage(channel, 3, consumerTagWithManualAck); @@ -88,21 +106,21 @@ public void basicGetAndAck() { metrics.consumedMessage(channel, 6, consumerTagWithManualAck); metrics.basicAck(channel, 6, false); - assertThat(metrics.getAcknowledgedMessages().getCount(), is(1L)); + assertThat(acknowledgedMessages(metrics), is(1L)); metrics.basicAck(channel, 3, true); - assertThat(metrics.getAcknowledgedMessages().getCount(), is(1L+2L)); + assertThat(acknowledgedMessages(metrics), is(1L+2L)); metrics.basicAck(channel, 6, true); - assertThat(metrics.getAcknowledgedMessages().getCount(), is(1L+2L+1L)); + assertThat(acknowledgedMessages(metrics), is(1L+2L+1L)); metrics.basicAck(channel, 10, true); - assertThat(metrics.getAcknowledgedMessages().getCount(), is(1L+2L+1L)); + assertThat(acknowledgedMessages(metrics), is(1L+2L+1L)); } @Test public void cleanStaleState() { - StandardMetricsCollector metrics = new StandardMetricsCollector(); + AbstractMetricsCollector metrics = factory.create(); Connection openConnection = mock(Connection.class); when(openConnection.getId()).thenReturn("connection-1"); when(openConnection.isOpen()).thenReturn(true); @@ -132,13 +150,63 @@ public void basicGetAndAck() { metrics.newChannel(closedChannel); metrics.newChannel(openChannelInClosedConnection); - assertThat(metrics.getConnections().getCount(), is(2L)); - assertThat(metrics.getChannels().getCount(), is(2L+1L)); + assertThat(connections(metrics), is(2L)); + assertThat(channels(metrics), is(2L+1L)); metrics.cleanStaleState(); - assertThat(metrics.getConnections().getCount(), is(1L)); - assertThat(metrics.getChannels().getCount(), is(1L)); + assertThat(connections(metrics), is(1L)); + assertThat(channels(metrics), is(1L)); + } + + long consumedMessages(MetricsCollector metrics) { + if (metrics instanceof StandardMetricsCollector) { + return ((StandardMetricsCollector) metrics).getConsumedMessages().getCount(); + } else { + return (long) ((MicrometerMetricsCollector) metrics).getConsumedMessages().count(); + } + } + + long acknowledgedMessages(MetricsCollector metrics) { + if (metrics instanceof StandardMetricsCollector) { + return ((StandardMetricsCollector) metrics).getAcknowledgedMessages().getCount(); + } else { + return (long) ((MicrometerMetricsCollector) metrics).getAcknowledgedMessages().count(); + } + } + + long connections(MetricsCollector metrics) { + if (metrics instanceof StandardMetricsCollector) { + return ((StandardMetricsCollector) metrics).getConnections().getCount(); + } else { + return ((MicrometerMetricsCollector) metrics).getConnections().get(); + } + } + + long channels(MetricsCollector metrics) { + if (metrics instanceof StandardMetricsCollector) { + return ((StandardMetricsCollector) metrics).getChannels().getCount(); + } else { + return ((MicrometerMetricsCollector) metrics).getChannels().get(); + } + } + + interface MetricsCollectorFactory { + AbstractMetricsCollector create(); + } + + static class StandardMetricsCollectorFactory implements MetricsCollectorFactory { + @Override + public AbstractMetricsCollector create() { + return new StandardMetricsCollector(); + } + } + + static class MicrometerMetricsCollectorFactory implements MetricsCollectorFactory { + @Override + public AbstractMetricsCollector create() { + return new MicrometerMetricsCollector(new SimpleMeterRegistry()); + } } } From 72225371bf848ee0ddeebf3cea307d0dcaa4a10a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 11 Oct 2017 14:24:36 +0200 Subject: [PATCH 0577/2114] Move license header to the top --- .../impl/MicrometerMetricsCollector.java | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java index 9d837036f7..2b612e99c7 100644 --- a/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.impl; import com.rabbitmq.client.Channel; @@ -16,21 +31,6 @@ import static com.rabbitmq.client.impl.MicrometerMetricsCollector.Metrics.PUBLISHED_MESSAGES; import static com.rabbitmq.client.impl.MicrometerMetricsCollector.Metrics.REJECTED_MESSAGES; -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - /** * Micrometer implementation of {@link MetricsCollector}. * Note transactions are not supported (see {@link MetricsCollector}. From fde1b09a1626d7dcadf46676b2c2805fac3c6480 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 11 Oct 2017 15:22:47 +0200 Subject: [PATCH 0578/2114] Use Function instead of home-grown interface References #313 --- .../impl/MicrometerMetricsCollector.java | 29 ++++++------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java index 2b612e99c7..5782804f89 100644 --- a/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java @@ -21,8 +21,8 @@ import io.micrometer.core.instrument.Counter; import io.micrometer.core.instrument.MeterRegistry; -import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Function; import static com.rabbitmq.client.impl.MicrometerMetricsCollector.Metrics.ACKNOWLEDGED_MESSAGES; import static com.rabbitmq.client.impl.MicrometerMetricsCollector.Metrics.CHANNELS; @@ -62,21 +62,16 @@ public MicrometerMetricsCollector(MeterRegistry registry) { } public MicrometerMetricsCollector(final MeterRegistry registry, final String prefix) { - this(new MetricsCreator() { - @Override - public Object create(Metrics metric) { - return metric.create(registry, prefix); - } - }); + this(metric -> metric.create(registry, prefix)); } - public MicrometerMetricsCollector(MetricsCreator creator) { - this.connections = (AtomicLong) creator.create(CONNECTIONS); - this.channels = (AtomicLong) creator.create(CHANNELS); - this.publishedMessages = (Counter) creator.create(PUBLISHED_MESSAGES); - this.consumedMessages = (Counter) creator.create(CONSUMED_MESSAGES); - this.acknowledgedMessages = (Counter) creator.create(ACKNOWLEDGED_MESSAGES); - this.rejectedMessages = (Counter) creator.create(REJECTED_MESSAGES); + public MicrometerMetricsCollector(Function metricsCreator) { + this.connections = (AtomicLong) metricsCreator.apply(CONNECTIONS); + this.channels = (AtomicLong) metricsCreator.apply(CHANNELS); + this.publishedMessages = (Counter) metricsCreator.apply(PUBLISHED_MESSAGES); + this.consumedMessages = (Counter) metricsCreator.apply(CONSUMED_MESSAGES); + this.acknowledgedMessages = (Counter) metricsCreator.apply(ACKNOWLEDGED_MESSAGES); + this.rejectedMessages = (Counter) metricsCreator.apply(REJECTED_MESSAGES); } @Override @@ -184,10 +179,4 @@ Object create(MeterRegistry registry, String prefix) { abstract Object create(MeterRegistry registry, String prefix); } - public interface MetricsCreator { - - Object create(Metrics metric); - - } - } From 4d9c3428a762aef6303a8ca868de5d5c2c569c3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 11 Oct 2017 15:24:00 +0200 Subject: [PATCH 0579/2114] Remove unused imports --- .../com/rabbitmq/client/impl/MicrometerMetricsCollector.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java index 2b612e99c7..a134cb725e 100644 --- a/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java @@ -21,7 +21,6 @@ import io.micrometer.core.instrument.Counter; import io.micrometer.core.instrument.MeterRegistry; -import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import static com.rabbitmq.client.impl.MicrometerMetricsCollector.Metrics.ACKNOWLEDGED_MESSAGES; From 479957836d0893644cb9a59e684ee46ac990bf22 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Thu, 12 Oct 2017 13:01:48 +0000 Subject: [PATCH 0580/2114] [maven-release-plugin] prepare release v4.3.0.RC1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index e97b1fb15b..6b1783d84f 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.3.0-SNAPSHOT + 4.3.0.RC1 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v4.3.0.RC1 From 57fd829aa478126d30c69c4b44b2a4a021208e7b Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Thu, 12 Oct 2017 13:01:54 +0000 Subject: [PATCH 0581/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 6b1783d84f..e97b1fb15b 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.3.0.RC1 + 4.3.0-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v4.3.0.RC1 + HEAD From a37298154941c73a3944b2e63f3067e8c031f7b0 Mon Sep 17 00:00:00 2001 From: Dmitry Andrianov Date: Fri, 13 Oct 2017 11:08:15 +0100 Subject: [PATCH 0582/2114] Fix SslEngineByteBufferInputStream to be prepared that read() may still result in BUFFER_UNDERFLOW --- .../rabbitmq/client/impl/nio/NioHelper.java | 7 ++ .../nio/SslEngineByteBufferInputStream.java | 65 +++++++------------ .../test/ssl/NioTlsUnverifiedConnection.java | 25 +++++-- 3 files changed, 50 insertions(+), 47 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioHelper.java b/src/main/java/com/rabbitmq/client/impl/nio/NioHelper.java index 2c1c037328..ef073a5e6c 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioHelper.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioHelper.java @@ -47,4 +47,11 @@ static int retryRead(ReadableByteChannel channel, ByteBuffer buffer) throws IOEx return read; } + static int readWithRetry(ReadableByteChannel channel, ByteBuffer buffer) throws IOException { + int bytesRead = NioHelper.read(channel, buffer); + if (bytesRead <= 0) { + bytesRead = NioHelper.retryRead(channel, buffer); + } + return bytesRead; + } } diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferInputStream.java b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferInputStream.java index f494814ef5..9d77a6f1a3 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferInputStream.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferInputStream.java @@ -43,57 +43,40 @@ public SslEngineByteBufferInputStream(SSLEngine sslEngine, ByteBuffer plainIn, B @Override public int read() throws IOException { + if (plainIn.hasRemaining()) { return readFromBuffer(plainIn); - } else { - plainIn.clear(); + } + + plainIn.clear(); + + while (true) { + SSLEngineResult result = sslEngine.unwrap(cipherIn, plainIn); switch (result.getStatus()) { - case OK: - plainIn.flip(); - if (plainIn.hasRemaining()) { - return readFromBuffer(plainIn); - } - break; - case BUFFER_OVERFLOW: - throw new SSLException("buffer overflow in read"); - case BUFFER_UNDERFLOW: - if (cipherIn.hasRemaining()) { + case OK: + plainIn.flip(); + if (plainIn.hasRemaining()) { + return readFromBuffer(plainIn); + } + break; + case BUFFER_OVERFLOW: + throw new SSLException("buffer overflow in read"); + case BUFFER_UNDERFLOW: cipherIn.compact(); - } else { - cipherIn.clear(); - } - - int bytesRead = NioHelper.read(channel, cipherIn); - // see https://github.com/rabbitmq/rabbitmq-java-client/issues/307 - if (bytesRead <= 0) { - bytesRead = NioHelper.retryRead(channel, cipherIn); - if(bytesRead <= 0) { + int bytesRead = NioHelper.readWithRetry(channel, cipherIn); + if (bytesRead <= 0) { throw new IllegalStateException("Should be reading something from the network"); } - } - cipherIn.flip(); - - plainIn.clear(); - result = sslEngine.unwrap(cipherIn, plainIn); - - if (result.getStatus() != SSLEngineResult.Status.OK) { - throw new SSLException("Unexpected result: " + result); - } - plainIn.flip(); - if (plainIn.hasRemaining()) { - return readFromBuffer(plainIn); - } - break; - case CLOSED: - throw new SSLException("closed in read"); - default: - throw new IllegalStateException("Invalid SSL status: " + result.getStatus()); + cipherIn.flip(); + break; + case CLOSED: + throw new SSLException("closed in read"); + default: + throw new IllegalStateException("Invalid SSL status: " + result.getStatus()); } } - - return -1; } private int readFromBuffer(ByteBuffer buffer) { diff --git a/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java index ef65a5ed2c..77e46e54b2 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java @@ -96,15 +96,28 @@ public void configure(SSLEngine sslEngine) throws IOException { } @Test public void messageSize() throws Exception { - int [] sizes = new int [] {100, 1000, 10 * 1000, 1 * 1000 * 1000, 5 * 1000 * 1000}; - for(int size : sizes) { - CountDownLatch latch = new CountDownLatch(1); - connection = basicGetBasicConsume(connection, "tls.nio.queue", latch, size); - boolean messagesReceived = latch.await(5, TimeUnit.SECONDS); - assertTrue("Message has not been received", messagesReceived); + int[] sizes = new int[]{100, 1000, 10 * 1000, 1 * 1000 * 1000, 5 * 1000 * 1000}; + for (int size : sizes) { + sendAndVerifyMessage(size); } } + // The purpose of this test is to put some stress on client TLS layer (SslEngineByteBufferInputStream to be specific) + // in an attempt to trigger condition described in https://github.com/rabbitmq/rabbitmq-java-client/issues/317 + // Unfortunately it is not guaranteed to be reproducible + @Test public void largeMessagesTlsTraffic() throws Exception { + for (int i = 0; i < 50; i++) { + sendAndVerifyMessage(76390); + } + } + + private void sendAndVerifyMessage(int size) throws Exception { + CountDownLatch latch = new CountDownLatch(1); + connection = basicGetBasicConsume(connection, "tls.nio.queue", latch, size); + boolean messagesReceived = latch.await(5, TimeUnit.SECONDS); + assertTrue("Message has not been received", messagesReceived); + } + private Connection basicGetBasicConsume(Connection connection, String queue, final CountDownLatch latch, int msgSize) throws IOException, TimeoutException { Channel channel = connection.createChannel(); From 6ce7efbe7e9d9e8a083e71fc4bfba7e4106e7857 Mon Sep 17 00:00:00 2001 From: Dmitry Andrianov Date: Fri, 13 Oct 2017 11:37:13 +0100 Subject: [PATCH 0583/2114] Just to be safe, make sure plainIn is back in write mode if we decide to continue. That branch should never be happening really, but again, just to be safe... --- .../rabbitmq/client/impl/nio/SslEngineByteBufferInputStream.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferInputStream.java b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferInputStream.java index 9d77a6f1a3..debefa6d63 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferInputStream.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferInputStream.java @@ -60,6 +60,7 @@ public int read() throws IOException { if (plainIn.hasRemaining()) { return readFromBuffer(plainIn); } + plainIn.clear(); break; case BUFFER_OVERFLOW: throw new SSLException("buffer overflow in read"); From 3ab4f5d7c8ec48cf09efd9d3cf40b064873a6d1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Fri, 13 Oct 2017 14:05:48 +0200 Subject: [PATCH 0584/2114] Remove rabbitmq-components.mk It was accidentally committed to this project but it doesn't belong here. Moreover, it breaks `gmake update-rabbitmq-components-mk` in the Umbrella. --- rabbitmq-components.mk | 324 ----------------------------------------- 1 file changed, 324 deletions(-) delete mode 100644 rabbitmq-components.mk diff --git a/rabbitmq-components.mk b/rabbitmq-components.mk deleted file mode 100644 index 1db00fa4c0..0000000000 --- a/rabbitmq-components.mk +++ /dev/null @@ -1,324 +0,0 @@ -ifeq ($(.DEFAULT_GOAL),) -# Define default goal to `all` because this file defines some targets -# before the inclusion of erlang.mk leading to the wrong target becoming -# the default. -.DEFAULT_GOAL = all -endif - -# PROJECT_VERSION defaults to: -# 1. the version exported by rabbitmq-server-release; -# 2. the version stored in `git-revisions.txt`, if it exists; -# 3. a version based on git-describe(1), if it is a Git clone; -# 4. 0.0.0 - -PROJECT_VERSION := $(RABBITMQ_VERSION) - -ifeq ($(PROJECT_VERSION),) -PROJECT_VERSION := $(shell \ -if test -f git-revisions.txt; then \ - head -n1 git-revisions.txt | \ - awk '{print $$$(words $(PROJECT_DESCRIPTION) version);}'; \ -else \ - (git describe --dirty --abbrev=7 --tags --always --first-parent \ - 2>/dev/null || echo rabbitmq_v0_0_0) | \ - sed -e 's/^rabbitmq_v//' -e 's/^v//' -e 's/_/./g' -e 's/-/+/' \ - -e 's/-/./g'; \ -fi) -endif - -# -------------------------------------------------------------------- -# RabbitMQ components. -# -------------------------------------------------------------------- - -# For RabbitMQ repositories, we want to checkout branches which match -# the parent project. For instance, if the parent project is on a -# release tag, dependencies must be on the same release tag. If the -# parent project is on a topic branch, dependencies must be on the same -# topic branch or fallback to `stable` or `master` whichever was the -# base of the topic branch. - -dep_amqp_client = git_rmq rabbitmq-erlang-client $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbit = git_rmq rabbitmq-server $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbit_common = git_rmq rabbitmq-common $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_amqp1_0 = git_rmq rabbitmq-amqp1.0 $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_auth_backend_amqp = git_rmq rabbitmq-auth-backend-amqp $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_auth_backend_cache = git_rmq rabbitmq-auth-backend-cache $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_auth_backend_http = git_rmq rabbitmq-auth-backend-http $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_auth_backend_ldap = git_rmq rabbitmq-auth-backend-ldap $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_auth_mechanism_ssl = git_rmq rabbitmq-auth-mechanism-ssl $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_boot_steps_visualiser = git_rmq rabbitmq-boot-steps-visualiser $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_clusterer = git_rmq rabbitmq-clusterer $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_cli = git_rmq rabbitmq-cli $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_codegen = git_rmq rabbitmq-codegen $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_consistent_hash_exchange = git_rmq rabbitmq-consistent-hash-exchange $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_ct_client_helpers = git_rmq rabbitmq-ct-client-helpers $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_ct_helpers = git_rmq rabbitmq-ct-helpers $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_delayed_message_exchange = git_rmq rabbitmq-delayed-message-exchange $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_dotnet_client = git_rmq rabbitmq-dotnet-client $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_event_exchange = git_rmq rabbitmq-event-exchange $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_federation = git_rmq rabbitmq-federation $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_federation_management = git_rmq rabbitmq-federation-management $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_java_client = git_rmq rabbitmq-java-client $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_jms_client = git_rmq rabbitmq-jms-client $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_jms_cts = git_rmq rabbitmq-jms-cts $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_jms_topic_exchange = git_rmq rabbitmq-jms-topic-exchange $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_lvc = git_rmq rabbitmq-lvc-plugin $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_management = git_rmq rabbitmq-management $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_management_agent = git_rmq rabbitmq-management-agent $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_management_exchange = git_rmq rabbitmq-management-exchange $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_management_themes = git_rmq rabbitmq-management-themes $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_management_visualiser = git_rmq rabbitmq-management-visualiser $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_message_timestamp = git_rmq rabbitmq-message-timestamp $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_metronome = git_rmq rabbitmq-metronome $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_mqtt = git_rmq rabbitmq-mqtt $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_objc_client = git_rmq rabbitmq-objc-client $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_peer_discovery_aws = git_rmq rabbitmq-peer-discovery-aws $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_peer_discovery_common = git_rmq rabbitmq-peer-discovery-common $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_peer_discovery_consul = git_rmq rabbitmq-peer-discovery-consul $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_recent_history_exchange = git_rmq rabbitmq-recent-history-exchange $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_routing_node_stamp = git_rmq rabbitmq-routing-node-stamp $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_rtopic_exchange = git_rmq rabbitmq-rtopic-exchange $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_server_release = git_rmq rabbitmq-server-release $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_sharding = git_rmq rabbitmq-sharding $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_shovel = git_rmq rabbitmq-shovel $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_shovel_management = git_rmq rabbitmq-shovel-management $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_stomp = git_rmq rabbitmq-stomp $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_toke = git_rmq rabbitmq-toke $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_top = git_rmq rabbitmq-top $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_tracing = git_rmq rabbitmq-tracing $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_trust_store = git_rmq rabbitmq-trust-store $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_test = git_rmq rabbitmq-test $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_web_dispatch = git_rmq rabbitmq-web-dispatch $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_web_stomp = git_rmq rabbitmq-web-stomp $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_web_stomp_examples = git_rmq rabbitmq-web-stomp-examples $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_web_mqtt = git_rmq rabbitmq-web-mqtt $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_web_mqtt_examples = git_rmq rabbitmq-web-mqtt-examples $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_website = git_rmq rabbitmq-website $(current_rmq_ref) $(base_rmq_ref) live master -dep_toke = git_rmq toke $(current_rmq_ref) $(base_rmq_ref) master - -dep_rabbitmq_public_umbrella = git_rmq rabbitmq-public-umbrella $(current_rmq_ref) $(base_rmq_ref) master - -# Third-party dependencies version pinning. -# -# We do that in this file, which is copied in all projects, to ensure -# all projects use the same versions. It avoids conflicts and makes it -# possible to work with rabbitmq-public-umbrella. - -dep_cowboy_commit = 1.1.0 -dep_mochiweb = git git://github.com/basho/mochiweb.git v2.9.0p2 -dep_ranch_commit = 1.3.2 -dep_sockjs = git https://github.com/rabbitmq/sockjs-erlang.git 405990ea62353d98d36dbf5e1e64942d9b0a1daf -dep_webmachine_commit = 1.10.8p2 -dep_ranch_proxy_protocol = git git://github.com/heroku/ranch_proxy_protocol.git 1.4.2 - -RABBITMQ_COMPONENTS = amqp_client \ - rabbit \ - rabbit_common \ - rabbitmq_amqp1_0 \ - rabbitmq_auth_backend_amqp \ - rabbitmq_auth_backend_cache \ - rabbitmq_auth_backend_http \ - rabbitmq_auth_backend_ldap \ - rabbitmq_auth_mechanism_ssl \ - rabbitmq_boot_steps_visualiser \ - rabbitmq_clusterer \ - rabbitmq_cli \ - rabbitmq_codegen \ - rabbitmq_consistent_hash_exchange \ - rabbitmq_ct_client_helpers \ - rabbitmq_ct_helpers \ - rabbitmq_delayed_message_exchange \ - rabbitmq_dotnet_client \ - rabbitmq_event_exchange \ - rabbitmq_federation \ - rabbitmq_federation_management \ - rabbitmq_java_client \ - rabbitmq_jms_client \ - rabbitmq_jms_cts \ - rabbitmq_jms_topic_exchange \ - rabbitmq_lvc \ - rabbitmq_management \ - rabbitmq_management_agent \ - rabbitmq_management_exchange \ - rabbitmq_management_themes \ - rabbitmq_management_visualiser \ - rabbitmq_message_timestamp \ - rabbitmq_metronome \ - rabbitmq_mqtt \ - rabbitmq_objc_client \ - rabbitmq_peer_discovery_aws \ - rabbitmq_peer_discovery_common \ - rabbitmq_peer_discovery_consul \ - rabbitmq_recent_history_exchange \ - rabbitmq_routing_node_stamp \ - rabbitmq_rtopic_exchange \ - rabbitmq_server_release \ - rabbitmq_sharding \ - rabbitmq_shovel \ - rabbitmq_shovel_management \ - rabbitmq_stomp \ - rabbitmq_toke \ - rabbitmq_top \ - rabbitmq_tracing \ - rabbitmq_trust_store \ - rabbitmq_web_dispatch \ - rabbitmq_web_mqtt \ - rabbitmq_web_mqtt_examples \ - rabbitmq_web_stomp \ - rabbitmq_web_stomp_examples \ - rabbitmq_website - -# Several components have a custom erlang.mk/build.config, mainly -# to disable eunit. Therefore, we can't use the top-level project's -# erlang.mk copy. -NO_AUTOPATCH += $(RABBITMQ_COMPONENTS) - -ifeq ($(origin current_rmq_ref),undefined) -ifneq ($(wildcard .git),) -current_rmq_ref := $(shell (\ - ref=$$(git branch --list | awk '/^\* \(.*detached / {ref=$$0; sub(/.*detached [^ ]+ /, "", ref); sub(/\)$$/, "", ref); print ref; exit;} /^\* / {ref=$$0; sub(/^\* /, "", ref); print ref; exit}');\ - if test "$$(git rev-parse --short HEAD)" != "$$ref"; then echo "$$ref"; fi)) -else -current_rmq_ref := master -endif -endif -export current_rmq_ref - -ifeq ($(origin base_rmq_ref),undefined) -ifneq ($(wildcard .git),) -base_rmq_ref := $(shell \ - (git rev-parse --verify -q stable >/dev/null && \ - git merge-base --is-ancestor $$(git merge-base master HEAD) stable && \ - echo stable) || \ - echo master) -else -base_rmq_ref := master -endif -endif -export base_rmq_ref - -# Repository URL selection. -# -# First, we infer other components' location from the current project -# repository URL, if it's a Git repository: -# - We take the "origin" remote URL as the base -# - The current project name and repository name is replaced by the -# target's properties: -# eg. rabbitmq-common is replaced by rabbitmq-codegen -# eg. rabbit_common is replaced by rabbitmq_codegen -# -# If cloning from this computed location fails, we fallback to RabbitMQ -# upstream which is GitHub. - -# Maccro to transform eg. "rabbit_common" to "rabbitmq-common". -rmq_cmp_repo_name = $(word 2,$(dep_$(1))) - -# Upstream URL for the current project. -RABBITMQ_COMPONENT_REPO_NAME := $(call rmq_cmp_repo_name,$(PROJECT)) -RABBITMQ_UPSTREAM_FETCH_URL ?= https://github.com/rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git -RABBITMQ_UPSTREAM_PUSH_URL ?= git@github.com:rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git - -# Current URL for the current project. If this is not a Git clone, -# default to the upstream Git repository. -ifneq ($(wildcard .git),) -git_origin_fetch_url := $(shell git config remote.origin.url) -git_origin_push_url := $(shell git config remote.origin.pushurl || git config remote.origin.url) -RABBITMQ_CURRENT_FETCH_URL ?= $(git_origin_fetch_url) -RABBITMQ_CURRENT_PUSH_URL ?= $(git_origin_push_url) -else -RABBITMQ_CURRENT_FETCH_URL ?= $(RABBITMQ_UPSTREAM_FETCH_URL) -RABBITMQ_CURRENT_PUSH_URL ?= $(RABBITMQ_UPSTREAM_PUSH_URL) -endif - -# Macro to replace the following pattern: -# 1. /foo.git -> /bar.git -# 2. /foo -> /bar -# 3. /foo/ -> /bar/ -subst_repo_name = $(patsubst %/$(1)/%,%/$(2)/%,$(patsubst %/$(1),%/$(2),$(patsubst %/$(1).git,%/$(2).git,$(3)))) - -# Macro to replace both the project's name (eg. "rabbit_common") and -# repository name (eg. "rabbitmq-common") by the target's equivalent. -# -# This macro is kept on one line because we don't want whitespaces in -# the returned value, as it's used in $(dep_fetch_git_rmq) in a shell -# single-quoted string. -dep_rmq_repo = $(if $(dep_$(2)),$(call subst_repo_name,$(PROJECT),$(2),$(call subst_repo_name,$(RABBITMQ_COMPONENT_REPO_NAME),$(call rmq_cmp_repo_name,$(2)),$(1))),$(pkg_$(1)_repo)) - -dep_rmq_commits = $(if $(dep_$(1)), \ - $(wordlist 3,$(words $(dep_$(1))),$(dep_$(1))), \ - $(pkg_$(1)_commit)) - -define dep_fetch_git_rmq - fetch_url1='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_FETCH_URL),$(1))'; \ - fetch_url2='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_FETCH_URL),$(1))'; \ - if test "$$$$fetch_url1" != '$(RABBITMQ_CURRENT_FETCH_URL)' && \ - git clone -q -n -- "$$$$fetch_url1" $(DEPS_DIR)/$(call dep_name,$(1)); then \ - fetch_url="$$$$fetch_url1"; \ - push_url='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_PUSH_URL),$(1))'; \ - elif git clone -q -n -- "$$$$fetch_url2" $(DEPS_DIR)/$(call dep_name,$(1)); then \ - fetch_url="$$$$fetch_url2"; \ - push_url='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_PUSH_URL),$(1))'; \ - fi; \ - cd $(DEPS_DIR)/$(call dep_name,$(1)) && ( \ - $(foreach ref,$(call dep_rmq_commits,$(1)), \ - git checkout -q $(ref) >/dev/null 2>&1 || \ - ) \ - (echo "error: no valid pathspec among: $(call dep_rmq_commits,$(1))" \ - 1>&2 && false) ) && \ - (test "$$$$fetch_url" = "$$$$push_url" || \ - git remote set-url --push origin "$$$$push_url") -endef - -# -------------------------------------------------------------------- -# Component distribution. -# -------------------------------------------------------------------- - -list-dist-deps:: - @: - -prepare-dist:: - @: - -# -------------------------------------------------------------------- -# rabbitmq-components.mk checks. -# -------------------------------------------------------------------- - -# If this project is under the Umbrella project, we override $(DEPS_DIR) -# to point to the Umbrella's one. We also disable `make distclean` so -# $(DEPS_DIR) is not accidentally removed. - -ifneq ($(wildcard ../../UMBRELLA.md),) -UNDER_UMBRELLA = 1 -else ifneq ($(wildcard UMBRELLA.md),) -UNDER_UMBRELLA = 1 -endif - -ifeq ($(UNDER_UMBRELLA),1) -ifneq ($(PROJECT),rabbitmq_public_umbrella) -DEPS_DIR ?= $(abspath ..) -endif - -ifneq ($(filter distclean distclean-deps,$(MAKECMDGOALS)),) -SKIP_DEPS = 1 -endif -endif - -UPSTREAM_RMQ_COMPONENTS_MK = $(DEPS_DIR)/rabbit_common/mk/rabbitmq-components.mk - -check-rabbitmq-components.mk: - $(verbose) cmp -s rabbitmq-components.mk \ - $(UPSTREAM_RMQ_COMPONENTS_MK) || \ - (echo "error: rabbitmq-components.mk must be updated!" 1>&2; \ - false) - -ifeq ($(PROJECT),rabbit_common) -rabbitmq-components-mk: - @: -else -rabbitmq-components-mk: - $(gen_verbose) cp -a $(UPSTREAM_RMQ_COMPONENTS_MK) . -ifeq ($(DO_COMMIT),yes) - $(verbose) git diff --quiet rabbitmq-components.mk \ - || git commit -m 'Update rabbitmq-components.mk' rabbitmq-components.mk -endif -endif From 2bf5296ac7af3a48da8aee937b2f66fa3ee5b0bb Mon Sep 17 00:00:00 2001 From: Dmitry Andrianov Date: Fri, 13 Oct 2017 11:08:15 +0100 Subject: [PATCH 0585/2114] Fix SslEngineByteBufferInputStream to be prepared that read() may still result in BUFFER_UNDERFLOW --- .../rabbitmq/client/impl/nio/NioHelper.java | 7 ++ .../nio/SslEngineByteBufferInputStream.java | 65 +++++++------------ .../test/ssl/NioTlsUnverifiedConnection.java | 25 +++++-- 3 files changed, 50 insertions(+), 47 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioHelper.java b/src/main/java/com/rabbitmq/client/impl/nio/NioHelper.java index 2c1c037328..ef073a5e6c 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioHelper.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioHelper.java @@ -47,4 +47,11 @@ static int retryRead(ReadableByteChannel channel, ByteBuffer buffer) throws IOEx return read; } + static int readWithRetry(ReadableByteChannel channel, ByteBuffer buffer) throws IOException { + int bytesRead = NioHelper.read(channel, buffer); + if (bytesRead <= 0) { + bytesRead = NioHelper.retryRead(channel, buffer); + } + return bytesRead; + } } diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferInputStream.java b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferInputStream.java index f494814ef5..9d77a6f1a3 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferInputStream.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferInputStream.java @@ -43,57 +43,40 @@ public SslEngineByteBufferInputStream(SSLEngine sslEngine, ByteBuffer plainIn, B @Override public int read() throws IOException { + if (plainIn.hasRemaining()) { return readFromBuffer(plainIn); - } else { - plainIn.clear(); + } + + plainIn.clear(); + + while (true) { + SSLEngineResult result = sslEngine.unwrap(cipherIn, plainIn); switch (result.getStatus()) { - case OK: - plainIn.flip(); - if (plainIn.hasRemaining()) { - return readFromBuffer(plainIn); - } - break; - case BUFFER_OVERFLOW: - throw new SSLException("buffer overflow in read"); - case BUFFER_UNDERFLOW: - if (cipherIn.hasRemaining()) { + case OK: + plainIn.flip(); + if (plainIn.hasRemaining()) { + return readFromBuffer(plainIn); + } + break; + case BUFFER_OVERFLOW: + throw new SSLException("buffer overflow in read"); + case BUFFER_UNDERFLOW: cipherIn.compact(); - } else { - cipherIn.clear(); - } - - int bytesRead = NioHelper.read(channel, cipherIn); - // see https://github.com/rabbitmq/rabbitmq-java-client/issues/307 - if (bytesRead <= 0) { - bytesRead = NioHelper.retryRead(channel, cipherIn); - if(bytesRead <= 0) { + int bytesRead = NioHelper.readWithRetry(channel, cipherIn); + if (bytesRead <= 0) { throw new IllegalStateException("Should be reading something from the network"); } - } - cipherIn.flip(); - - plainIn.clear(); - result = sslEngine.unwrap(cipherIn, plainIn); - - if (result.getStatus() != SSLEngineResult.Status.OK) { - throw new SSLException("Unexpected result: " + result); - } - plainIn.flip(); - if (plainIn.hasRemaining()) { - return readFromBuffer(plainIn); - } - break; - case CLOSED: - throw new SSLException("closed in read"); - default: - throw new IllegalStateException("Invalid SSL status: " + result.getStatus()); + cipherIn.flip(); + break; + case CLOSED: + throw new SSLException("closed in read"); + default: + throw new IllegalStateException("Invalid SSL status: " + result.getStatus()); } } - - return -1; } private int readFromBuffer(ByteBuffer buffer) { diff --git a/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java index ef65a5ed2c..77e46e54b2 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java @@ -96,15 +96,28 @@ public void configure(SSLEngine sslEngine) throws IOException { } @Test public void messageSize() throws Exception { - int [] sizes = new int [] {100, 1000, 10 * 1000, 1 * 1000 * 1000, 5 * 1000 * 1000}; - for(int size : sizes) { - CountDownLatch latch = new CountDownLatch(1); - connection = basicGetBasicConsume(connection, "tls.nio.queue", latch, size); - boolean messagesReceived = latch.await(5, TimeUnit.SECONDS); - assertTrue("Message has not been received", messagesReceived); + int[] sizes = new int[]{100, 1000, 10 * 1000, 1 * 1000 * 1000, 5 * 1000 * 1000}; + for (int size : sizes) { + sendAndVerifyMessage(size); } } + // The purpose of this test is to put some stress on client TLS layer (SslEngineByteBufferInputStream to be specific) + // in an attempt to trigger condition described in https://github.com/rabbitmq/rabbitmq-java-client/issues/317 + // Unfortunately it is not guaranteed to be reproducible + @Test public void largeMessagesTlsTraffic() throws Exception { + for (int i = 0; i < 50; i++) { + sendAndVerifyMessage(76390); + } + } + + private void sendAndVerifyMessage(int size) throws Exception { + CountDownLatch latch = new CountDownLatch(1); + connection = basicGetBasicConsume(connection, "tls.nio.queue", latch, size); + boolean messagesReceived = latch.await(5, TimeUnit.SECONDS); + assertTrue("Message has not been received", messagesReceived); + } + private Connection basicGetBasicConsume(Connection connection, String queue, final CountDownLatch latch, int msgSize) throws IOException, TimeoutException { Channel channel = connection.createChannel(); From 82d0fb0ad9cf96d9c3a81926985e78225292d0e3 Mon Sep 17 00:00:00 2001 From: Dmitry Andrianov Date: Fri, 13 Oct 2017 11:37:13 +0100 Subject: [PATCH 0586/2114] Just to be safe, make sure plainIn is back in write mode if we decide to continue. That branch should never be happening really, but again, just to be safe... --- .../rabbitmq/client/impl/nio/SslEngineByteBufferInputStream.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferInputStream.java b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferInputStream.java index 9d77a6f1a3..debefa6d63 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferInputStream.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferInputStream.java @@ -60,6 +60,7 @@ public int read() throws IOException { if (plainIn.hasRemaining()) { return readFromBuffer(plainIn); } + plainIn.clear(); break; case BUFFER_OVERFLOW: throw new SSLException("buffer overflow in read"); From 7d69564f3b96e31cab676fee6471d01f9ea448de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 13 Oct 2017 15:52:50 +0200 Subject: [PATCH 0587/2114] Delete queue in NIO TLS test --- .../client/test/ssl/NioTlsUnverifiedConnection.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java index 77e46e54b2..425ecc35f0 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java @@ -36,6 +36,8 @@ */ public class NioTlsUnverifiedConnection extends BrokerTestCase { + public static final String QUEUE = "tls.nio.queue"; + public void openConnection() throws IOException, TimeoutException { try { @@ -61,10 +63,15 @@ public void openConnection() } + @Override + protected void releaseResources() throws IOException { + channel.queueDelete(QUEUE); + } + @Test public void connectionGetConsume() throws Exception { CountDownLatch latch = new CountDownLatch(1); - connection = basicGetBasicConsume(connection, "tls.nio.queue", latch, 100 * 1000); + connection = basicGetBasicConsume(connection, QUEUE, latch, 100 * 1000); boolean messagesReceived = latch.await(5, TimeUnit.SECONDS); assertTrue("Message has not been received", messagesReceived); } @@ -113,7 +120,7 @@ public void configure(SSLEngine sslEngine) throws IOException { private void sendAndVerifyMessage(int size) throws Exception { CountDownLatch latch = new CountDownLatch(1); - connection = basicGetBasicConsume(connection, "tls.nio.queue", latch, size); + connection = basicGetBasicConsume(connection, QUEUE, latch, size); boolean messagesReceived = latch.await(5, TimeUnit.SECONDS); assertTrue("Message has not been received", messagesReceived); } From d4067cc235a35a3dfab13c02fb188a4ac2e44654 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 13 Oct 2017 15:58:42 +0200 Subject: [PATCH 0588/2114] Set release version to 4.3.0.RC2 --- release-versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-versions.txt b/release-versions.txt index 2b08f224dc..b38aafc8e6 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="4.3.0.RC1" +RELEASE_VERSION="4.3.0.RC2" DEVELOPMENT_VERSION="4.3.0-SNAPSHOT" From 97fd5cf5acde38966cf9134b1068785564e45f07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 16 Oct 2017 11:17:51 +0200 Subject: [PATCH 0589/2114] Increase reception waiting time for TLS NIO test largeMessagesTlsTraffic() sometimes fails on CI, increasing waiting time should be enough. References #317 --- .../rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java index 425ecc35f0..abf6376c46 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java @@ -121,7 +121,7 @@ public void configure(SSLEngine sslEngine) throws IOException { private void sendAndVerifyMessage(int size) throws Exception { CountDownLatch latch = new CountDownLatch(1); connection = basicGetBasicConsume(connection, QUEUE, latch, size); - boolean messagesReceived = latch.await(5, TimeUnit.SECONDS); + boolean messagesReceived = latch.await(10, TimeUnit.SECONDS); assertTrue("Message has not been received", messagesReceived); } From 5ad42b373f847b1b786e728f653e245497857f7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 16 Oct 2017 11:22:03 +0200 Subject: [PATCH 0590/2114] Clean NIO loop condition --- src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java b/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java index 1873b25f17..900b72b3fb 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java @@ -67,7 +67,7 @@ public void run() { boolean writeRegistered = false; try { - while (true && !Thread.currentThread().isInterrupted()) { + while (!Thread.currentThread().isInterrupted()) { for (SelectionKey selectionKey : selector.keys()) { SocketChannelFrameHandlerState state = (SocketChannelFrameHandlerState) selectionKey.attachment(); From 3d3adaddc592043994ae13f905589707c3a6dc0c Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Tue, 17 Oct 2017 09:35:56 +0000 Subject: [PATCH 0591/2114] [maven-release-plugin] prepare release v4.3.0.RC2 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index e97b1fb15b..2ebf2dca37 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.3.0-SNAPSHOT + 4.3.0.RC2 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v4.3.0.RC2 From eb9e9969cb67f3b5bb40acf8a3c592eb9787bbc9 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Tue, 17 Oct 2017 09:36:02 +0000 Subject: [PATCH 0592/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 2ebf2dca37..e97b1fb15b 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.3.0.RC2 + 4.3.0-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v4.3.0.RC2 + HEAD From f80e0a6fe5ca1eba98a798dffa8b51407c5297e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 18 Oct 2017 11:30:42 +0200 Subject: [PATCH 0593/2114] Adding log for CI debug --- .../rabbitmq/client/test/BrokerTestCase.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java index 4fd4198d68..522aac574b 100644 --- a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java +++ b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java @@ -20,11 +20,16 @@ import com.rabbitmq.tools.Host; import org.junit.After; import org.junit.Before; +import org.junit.Rule; +import org.junit.rules.TestRule; +import org.junit.rules.TestWatcher; +import org.junit.runner.Description; import javax.net.ssl.SSLContext; import java.io.IOException; import java.security.NoSuchAlgorithmException; import java.util.Arrays; +import java.util.Date; import java.util.Map; import java.util.UUID; import java.util.concurrent.TimeoutException; @@ -33,6 +38,26 @@ public class BrokerTestCase { + @Rule + public TestRule watcher = new TestWatcher() { + protected void starting(Description description) { + System.out.println(String.format( + "Starting test %s.%s (%s)", + description.getTestClass().getSimpleName(), description.getMethodName(), + new Date().toString() + )); + } + + @Override + protected void finished(Description description) { + System.out.println(String.format( + "Test finished %s.%s (%s)", + description.getTestClass().getSimpleName(), description.getMethodName(), + new Date().toString() + )); + } + }; + protected ConnectionFactory connectionFactory = newConnectionFactory(); protected ConnectionFactory newConnectionFactory() { From 07671208ac94d0e17d64ba467e5ad1edea20a31e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 18 Oct 2017 15:32:57 +0200 Subject: [PATCH 0594/2114] Make consumer priorities test more reliable The test didn't check higher priority consumers were actually cancelled before checking the content of lower priority consumers. Higher priority consumers could then "steal" expected messages from the lower priority consumers, making the test waiting forever some expecting messages for the lower priority consumers. Problem appeared on CI, after 50fa0efc03b284c986b15426c404861470d3226d on rabbitmq-common and 9e7cea3ae6dfb89bc14e562812420ee846486220 on rabbitmq-server (stable branch after 3.6.12 release). --- .../test/functional/ConsumerPriorities.java | 62 ++++++++++++++++--- 1 file changed, 52 insertions(+), 10 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConsumerPriorities.java b/src/test/java/com/rabbitmq/client/test/functional/ConsumerPriorities.java index e9c24dbf0d..13430090d3 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConsumerPriorities.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConsumerPriorities.java @@ -16,13 +16,20 @@ package com.rabbitmq.client.test.functional; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.IOException; import java.util.Arrays; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; +import com.rabbitmq.client.DefaultConsumer; +import com.rabbitmq.client.Envelope; import org.junit.Test; import com.rabbitmq.client.AMQP; @@ -51,24 +58,33 @@ private void assertFailValidation(Map args) throws IOException { } private static final int COUNT = 10; + private static final long DELIVERY_TIMEOUT_MS = 100; + private static final long CANCEL_OK_TIMEOUT_MS = 10 * 1000; @Test public void consumerPriorities() throws Exception { String queue = channel.queueDeclare().getQueue(); - QueueingConsumer highConsumer = new QueueingConsumer(channel); - QueueingConsumer medConsumer = new QueueingConsumer(channel); - QueueingConsumer lowConsumer = new QueueingConsumer(channel); + QueueMessageConsumer highConsumer = new QueueMessageConsumer(channel); + QueueMessageConsumer medConsumer = new QueueMessageConsumer(channel); + QueueMessageConsumer lowConsumer = new QueueMessageConsumer(channel); String high = channel.basicConsume(queue, true, args(1), highConsumer); String med = channel.basicConsume(queue, true, medConsumer); channel.basicConsume(queue, true, args(-1), lowConsumer); publish(queue, COUNT, "high"); + assertContents(highConsumer, COUNT, "high"); channel.basicCancel(high); + assertTrue( + "High priority consumer should have been cancelled", + highConsumer.cancelLatch.await(CANCEL_OK_TIMEOUT_MS, TimeUnit.MILLISECONDS) + ); publish(queue, COUNT, "med"); + assertContents(medConsumer, COUNT, "med"); channel.basicCancel(med); + assertTrue( + "Medium priority consumer should have been cancelled", + medConsumer.cancelLatch.await(CANCEL_OK_TIMEOUT_MS, TimeUnit.MILLISECONDS) + ); publish(queue, COUNT, "low"); - - assertContents(highConsumer, COUNT, "high"); - assertContents(medConsumer, COUNT, "med"); assertContents(lowConsumer, COUNT, "low"); } @@ -78,12 +94,12 @@ private Map args(Object o) { return map; } - private void assertContents(QueueingConsumer qc, int count, String msg) throws InterruptedException { + private void assertContents(QueueMessageConsumer qc, int count, String msg) throws InterruptedException { for (int i = 0; i < count; i++) { - QueueingConsumer.Delivery d = qc.nextDelivery(); - assertEquals(msg, new String(d.getBody())); + byte[] body = qc.nextDelivery(DELIVERY_TIMEOUT_MS); + assertEquals(msg, new String(body)); } - assertEquals(null, qc.nextDelivery(0)); + assertEquals(null, qc.nextDelivery(DELIVERY_TIMEOUT_MS)); } private void publish(String queue, int count, String msg) throws IOException { @@ -91,4 +107,30 @@ private void publish(String queue, int count, String msg) throws IOException { channel.basicPublish("", queue, MessageProperties.MINIMAL_BASIC, msg.getBytes()); } } + + private static class QueueMessageConsumer extends DefaultConsumer { + + BlockingQueue messages = new LinkedBlockingQueue(); + + CountDownLatch cancelLatch = new CountDownLatch(1); + + public QueueMessageConsumer(Channel channel) { + super(channel); + } + + @Override + public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { + messages.add(body); + } + + @Override + public void handleCancelOk(String consumerTag) { + cancelLatch.countDown(); + } + + byte[] nextDelivery(long timeoutInMs) throws InterruptedException { + return messages.poll(timeoutInMs, TimeUnit.MILLISECONDS); + } + + } } From 9344330220cc1fcdca6939c2a57c9be1f5416a7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 19 Oct 2017 10:15:26 +0200 Subject: [PATCH 0595/2114] Remove test debugging --- .../rabbitmq/client/test/BrokerTestCase.java | 25 ------------------- 1 file changed, 25 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java index 522aac574b..4fd4198d68 100644 --- a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java +++ b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java @@ -20,16 +20,11 @@ import com.rabbitmq.tools.Host; import org.junit.After; import org.junit.Before; -import org.junit.Rule; -import org.junit.rules.TestRule; -import org.junit.rules.TestWatcher; -import org.junit.runner.Description; import javax.net.ssl.SSLContext; import java.io.IOException; import java.security.NoSuchAlgorithmException; import java.util.Arrays; -import java.util.Date; import java.util.Map; import java.util.UUID; import java.util.concurrent.TimeoutException; @@ -38,26 +33,6 @@ public class BrokerTestCase { - @Rule - public TestRule watcher = new TestWatcher() { - protected void starting(Description description) { - System.out.println(String.format( - "Starting test %s.%s (%s)", - description.getTestClass().getSimpleName(), description.getMethodName(), - new Date().toString() - )); - } - - @Override - protected void finished(Description description) { - System.out.println(String.format( - "Test finished %s.%s (%s)", - description.getTestClass().getSimpleName(), description.getMethodName(), - new Date().toString() - )); - } - }; - protected ConnectionFactory connectionFactory = newConnectionFactory(); protected ConnectionFactory newConnectionFactory() { From 89cc23c419d8bbd30b6de90f5ea6d1ae57428ebe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 20 Oct 2017 15:16:18 +0200 Subject: [PATCH 0596/2114] Set release version to 4.3.0 --- release-versions.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release-versions.txt b/release-versions.txt index b38aafc8e6..b0219ddc23 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="4.3.0.RC2" -DEVELOPMENT_VERSION="4.3.0-SNAPSHOT" +RELEASE_VERSION="4.3.0" +DEVELOPMENT_VERSION="4.3.1-SNAPSHOT" From c509efe9e0ec460ce99c56ae70f68932360c6fcb Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Fri, 20 Oct 2017 13:19:14 +0000 Subject: [PATCH 0597/2114] [maven-release-plugin] prepare release v4.3.0 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index e97b1fb15b..396ddeef55 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.3.0-SNAPSHOT + 4.3.0 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v4.3.0 From 53ebac3268b5a92722525e5f387e9fc1b6b3359d Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Fri, 20 Oct 2017 13:19:20 +0000 Subject: [PATCH 0598/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 396ddeef55..36aa584d38 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.3.0 + 4.3.1-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v4.3.0 + HEAD From 7b726cfc6461ac7dc282a2d914c00e34badbffad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 20 Oct 2017 15:42:35 +0200 Subject: [PATCH 0599/2114] Set release version to 4.3.1.RC1 --- release-versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-versions.txt b/release-versions.txt index b0219ddc23..9eaa5847ae 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="4.3.0" +RELEASE_VERSION="4.3.1.RC1" DEVELOPMENT_VERSION="4.3.1-SNAPSHOT" From 6c90460f53e0678d76e1f2674761875d5c729576 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 20 Oct 2017 15:54:54 +0200 Subject: [PATCH 0600/2114] Set POM version to 4.4.0-SNAPSHOT --- pom.xml | 2 +- release-versions.txt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 36aa584d38..8e218f2839 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.3.1-SNAPSHOT + 4.4.0-SNAPSHOT jar RabbitMQ Java Client diff --git a/release-versions.txt b/release-versions.txt index 9eaa5847ae..303387c85d 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="4.3.1.RC1" -DEVELOPMENT_VERSION="4.3.1-SNAPSHOT" +RELEASE_VERSION="4.4.0.RC1" +DEVELOPMENT_VERSION="4.4.0-SNAPSHOT" From 51ff9547f3671882f19aada7c1b8f20271305f55 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Tue, 24 Oct 2017 12:10:19 +0300 Subject: [PATCH 0601/2114] Strip a non-free ICC profile from ./doc/channels/whiteboard.JPG Closes #322. --- doc/channels/whiteboard.JPG | Bin 1983585 -> 1944358 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/doc/channels/whiteboard.JPG b/doc/channels/whiteboard.JPG index 7c45bcdf710740968af98df23918ffc1efa8f780..eed267a5c10e1db56536cc2ad9586dce864410c5 100644 GIT binary patch literal 1944358 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%0Dnw-5D=JL`tL>j4KRdiZY8jZ`|^A<6? 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%0DVN3DzheCj^vChv9*-D~?@4^-sYaTO7QI{o z=N}!mWkko%W+%;0wC(X46F?Iuj+{ZM01n-1%RytD$Ng7`itF9?| z=x|vJKbup+hjG*SAtPJI#q(xgEEL#k+xw9UJ1ILFQ)3}N`bIBkt~5cGO{#2BxF%*6 zAVZ0s@kWYXaTA2cFzNNlmj|N|J5rB`&XSa!c2v$#YjX-eYGSbU7DkSZdoz--tk3kv|?Z(IJ~UAG+C zF(+N64(AJ$y$)O@EhIk3c1V1^6=s<8?l9ln&=Ojo_h=flBZod^VpTpez}e^)FZLG* z-x#%d`PGOhaZ)4%MmcD^f@K1F?)eP_;ICp{Z8mQzK4K|N0#fsyd}QH>n*hAY2!X}? z&=$&-iXFZkQWId~q}uY?_sWaPR0rF$QTJF!5V<-H@j~fQoAyE@y24cP2fHMX)vv&p zcz03@jZWCrUa^rae%Vnh83Es8D1Xg2a(u`9i=J?Y^1Bvtq7qcHL##~XN^FPMomhI- ziDa%liEo^WhBP2Tqo&(%m&BE|vhe35Uqu*pceL zlT;&W9w=RXv}|Z-d+&|H)wBeV=w7lCbA7ak;Fm>KF7M3(1@*sU6qogBO4_l)Q+bG0 zef8)W06RP#>tR1aBroS(|MP=mBki{9dT2$CIM6F z^q-IfLjD6ZV8A`XSMUy$bTU2`m&}PIO=&audh_-UPUWr<2_z0kJaF^BwJm_x63<=j zxwWk(@GJ=gFmt`&9$bXo!70sH(Bu)72o3PjwaIKjJI$XDfql zYq5eJ20YgQ@DrL3TmM+}wyq_WbF<`_k%tW877tcos2AI&&xU?b5nthUZ+n(&-Si&U z@y5%s8ozyeCV^@PxAW@%{hd}hJ{*4o1kJb3GmyXA@L(_zIpZ{S^D+^c!481@a#veN zjLdz4ens^&Z9Th^!-;2VRm~`o+l0>PRE)Aqi!mG@cr6U)!Gt~Sb*j0af>A0n-v3hR z{{5mG0;Pbp);*Q-=4K259T!PDP@tc|&<_9O;Bn{Y^FKW?3V#(v!3*3}$(gOx8>An% z&>r}Nx9Oknt5rl1`O?lwPBSo3m%a1@1t(;^1!dToK3g{E)&^^(kNpqFne)t$Qz0BdJWDX1@#-4%RwTK^O;G$#(#R8zD zVhj-&7^gx2b&fAW{Bnb7S)Q!9xD ze<-U0ytwRzF#R-EIx*(;>ry>Ho~16x%l&nKFHI_t)sR}59RYj|M;E@X*i>kmE%TmJMp{x z)b(;VIZMluOm=~Qxb2NoqHXzwSjT~P`G9@GBfFsAZ)kp5M&$}QibDqMntIg39Zh$$ z1B>Mn03!WecdiuMXV*Q49FY0Lgu_o;c@F%~=C3%u zl{?FQTD!q*i3O&_ieLo1A8=C>?o`&pswDmE1b~>>wQ7tcbQ`PQYdSo*Q;u3GNG2L;er?(qd(w;fs|Mrr` z1%Sj^v9KNBqa}nzRBN{Ak5$I3L?4uSG35ZCE~4u&BD1(3xK6rrN(|uyRu9Ts*F6aN z9kexffInYs8hK_dPD|dddcI;oTc7A9ZMFTPYma#lu-PZ*OqL#)oSI*J!geZR-4Jl1 zVN0iMz9qkZXqJjESfCJ*#a`>7N}Sl9P-%QW=0WRm8ao>*3St5_)*_6o`0VndS=XVtKq6H~em*pG z;KTm`Qk1eVHvcSqe%C2cwe|r;t6d8~D=c+B=}1*yr?t%&xQn|Q=S1$^;oqxBtdqi^y7BzJ0kHzMA%s15t>;2s7YLC&gS5= z{vM&%AfWsY{G_I!`9J*D|KCXW{~q@K?>lI-CJpU45t_JD%s1H2$&@XxF}AgW2!tEG z=_d=GiSLGbGl}-6>joq5KS;92eg3YWEKufdS*e;hhUa|vNpRk61b>m?*Y)#Jmz=U^ zEbkm4l=8>`Bxv~_&KXg`^^x7{Lv`lF&6o-&h~$&Jop#w|DO8$o4Yva zb3O7Xp+E*nq@&+Pc^K*7(2EP6nu|H$lRuKIEV9!a#@U@dc@3Y7o5C+0c>a>DQug?^ z?%GRD)5U`S08VF5haFiwGhHM_?Vm44w&(LpMv4TlA8t&l+4}U0+qzGd!9bdB>RE?z z9wXw`o>DpYVwnkkI6*460Y=p*rcn8#n~o`o60K-1X%s?QFs^6MTd^(6MHaMTrf0Iz z4^gGEYYYb*R}n^5gXa|I@7DtV;sV`3Y_$904Zb`GvwMu<_~4vo5nd=0=iNv0T{_kA zkQ>9zUe?iJ!C|f{@$et6eF=*{*NKlk%@p1fYo}M9E~%Y@Yu-FTZRIj`^-=<7MKf`q zTe9r0_@jVev}-)YMXnJ{F@c?|8o4k9EA-r@+RCHsAx8GIw*1{ejT));K$WFvS+Mw~ z@m;;!hZlP~c3u5mQK zeFQSJNuD29Z1zTuw+V=Md0ySRoz{4Si#k-4vsY>5_91 z>k!GL&$cPHxED>glra!I1Na7b?23M6iKN@4RoR3)MPA8WHwhR0X%l`qh+HZGgbz5| z;3p6B;P45@4H`6P~@okksL+S?+uUK1t#O5aj?$Ewv zy9oC10|~{y%e}%R;k~~MvY-?a+y{ifyTaT509${yn&P(g_BDT6IUf&da?a2%M$o}g zFc@Di{h%2dfP)c*#7_!iCj&W{i_ORmz@JW#$`;1GZWh3%;e>Km{Q-Adeh9YAgv<%r(uBNSPk7d zm!3R)bF&6U9eXl@Vp&CZY<&)yCix*KBVKH$$Pr2BC-y`fJ@#iihi0x<*F%jR`4r3J zR|G)RtCyL;`_qfFaCiHhv$zOz#^6%ns=V#M)1f88%lLz0%LR21;w12Cq^A;vd;0=1b+Oda>1Q*xS6 zKTfQW3E^Hevpccpw@wf6aDAX6A=6@Qr4%tsB`F6@uXtE0oe`+?ZRqLPGEPPyF9;nE zofehw*;wTG`wpQZw3hJDl|`ozr(%Y~ipJO?W9yQi+TyL4&xVrdgs~uxD?iFAWl}U3 z$?-`cs*3wR0Pyx9b}FQBViAOBWL;1v!f#OtHGqsJQFZ@ez*nOrp*?Why#2*fN8f=Z zEK0XUnLdiBjdP;k)hzhLciUscHXJ7@ZYnccp4qkXAD|3tBiDsg)chGM24% z+-0!S@UY+JB3H@vWz@LB3iCy?{1O(%9_|7%5pCwEoB2g(+9#RgLnlmWe!#U;W&4P> zj(-&v&Zo4^dwWn@cBGnDY;vY70v8p8gKbKjid|wlj>ipv+o<~U*z_El{K|H6^B7%8 zN#6kajI70PCH_Knt6Ch_;H15CwjRamAlqdka{GAr$?7QWR{6v zAx5#yid;|%KP}e9Z@T{Vv2iOq>^}e^AIr8N(YNA!^;#XvDIOKGCI+<#H}-(!X<~z2 zG6`hlikY4LfU=Wp1k+kA=@|J+f?QpxWn&J=y8~g>gA0)4jhe38VWm3r%R_|0mDy!} z&K#uw{#4I@^#1m3QyJ?911DeMyadxB#%S;m<$K~bpK$5I~^dd$|#~{`rmS>77 z)qi&5LjKCkTE|l_|9dPg!7z!4Zh&byF87}@^5l-2zC9|?h-~So@Hg}EvOzSxuO7t6 zCMjAc1lw~2kBX2slSZTj5p#3#blnH==>uF0auZL-Yn`RS zh9E^JN7DC?X+>zdscfxfU>6D5rQR?SJ4=|~3DJX<+ z9buS~lOu*Nl~Qfi@zVj{iWTnJKgrZ+PL!I^-|72FKp%H1(A6#%LS3S~hwS<^3FwLk&zSqpWjVe3vojjJBZ>@D$dvfiH=dao~GH{!9UhCg?i@csjQZgN36 zv=l`4CAVCLM&)-AX8oOu+3ShxNVK9LJQtrzjnFBm+r?Rd#V!0k@>GWld_V4_dR#Ib z|68WAP_bBAypk~iVIwkX)*o$AUzbkV#^B7WCLwD#OiIi>(roya9Oj%!2TuVVI;v5_ z=7}$>@c*og5Q{Pa%vyCRerJFI%>>aqi7g%))~vLX|2^Nj;nJ|Lk*kE7Wa+Kn@N5|_ za=pne0Ajd#rXj_#F}B=xG|het-xRiO8nc&R6oE?n;@QGGO2 ztQ-1DX`!rfCN2p^*ROB~7#nBRr5E`#%XPoKJy%^``6l%>MmkuD0S)=u-UJo+_qJm& zEIb#21>=ry&8?hI391CsrlM`qpHPW$Viy5+gr_`H%M+LNm*eYyY@4ErPu}r7>wl4! zvvc58Gpa%y+u7CoUV@D>Liw#XLb8dxiLTPO;N8>vCdWvW3$9%E>#CK?TOZ$zW&Ws= z^<9U(HS-v>SDHxyGH(`0?=20f3PXSG#@uO**XM6NB8CPbziw-~<#WzX*%tWR>mSt` z6*xxPR7(pq1AkT878ms{rwkYB^jo}Sqv6F;N}I$`SM9P?{_bKCV!vU(V2EJ5fMXdn zJ_RFzdG%pH&B<0prq6PAQp!p9`E(1P@;!Cpn8{2J3^8ICxBm90EiPW?Q-+Yz82}L!4EP<>Eo8cD>p5(35Xk&cbVHMQ0gGB7)I#&Rm>zqzCKNdEdkKSCV&&=h4FZp@3H%-Sb z+w6kI*w;#(#r5c{eRYYo`)M0L<~gT+UV zZqeS4<=@0?A?iwwP6ox5q(Lb+s6MU8@NWDu-p*k&>#T}hN9oi{b@RDYk*ptjUlq1K zVhy}w&+>6sO+z#a8L-fnuWu~BnNVH(M2w@7ZDe^qjW}(sC+GhM_{1X?TsU{8GD96( zm2K&YFk0S#wldha_q4i+O=$dS<7h5S%a@)0hSQ>dxTwxBf4WsZYpQA3XzBFi|L;Ss#uv^1#uL8b0Go*>#w4PxW|Ny^_&JvLmkNW4OF>Q} z53U(GwlBjg>kYPvAo(!1U##VPV^?-WM#TXBaOIERen5ix##m23U(U)H9It|MuooK| zHG#yn^6&u$2PfOT{Z($yrD~Z#VNN4rTha=`mEvP%*vnOQ2$YKE{133~eq=d%^@|{t z-}98AXIIm|8ztkwp5!?k$_;XuDNjBV+qy5Xe3~5JltbidR{icdS7CR= z3^xhH^Hx6{(wYfg(YJ&WDteylt8Y@FQ5r0Yy~wq@0bLSgiX>dqw9Bhz8-OQ%^mirxiUGPsjRMtAS{f9ec*s*-D}g-M$+uot}isB*~)<-$9?&lV~gJ zYeGedroE!;=0927iZyz@~IA1C(C%u5itZE+)5iUR@h=h56A zqa~w&AcZaMGkDv#a2$nnkpKJd%2W%Um)$#vPH3(;I^g?IG7%qNeMtSyGeCu38B;AXr=Rnjjc=AvmoZdHJDvl!)2a!FV zMMoiSU11Ej`DCh^mX)h4lm8ftXmt;aXa467L#yXp`MS)zpe-B8N#+k2M4M5pMJ!K6 zX4oq9>Bov$I}4{{(IF2DGo^CI>Zi%kE7D928rA8-69Jwgg~LerzU60uE(tK_bPppqU^sztg&RF;|T%aklSYuS8b3B%U~mEM}?#h}|uw70*t z(L6V@se4)d@)opI7W!xmLLz7-yd&s1$K)`O_~PMT(VlV(+^Ih@m5vCJXDBJ^<33um zZcwKuesCqvV)WO$`8&}K@)0EbTxBA#@M@&j{i}-&s|k9p7e`8#4C}7U=Xj_gL)??E z7bGZze7B`X>EYO9W>~mP*z+%MsCg3Zq*#kWEJ;{+AOMoJi@nI_0vEC$%c?FTX>R>A zMJx_4DMqJ;K!&QeS|oF^QnC*Nmd?JxAeb>yEaj)Z2S zN*J1`GcBp6DZco1{AV{gUmZ@ELiE$PPwi}+#%#ftbfCukqPq2VU0J@UV=8qb`W0@HrVY|+HAou3sy%gD;b-97swbtb zTnu#nJ|+pwk`z_mVcm@#^$LnKYvHG+Qc_&H!%DauswDp7S)uFfSU-RLlQmw1+fTkX z@IxfzTuyS=-FgU??ME=z{l|g&Wr-dE#V4JF0zSiS=wi0{8_dsMC|*4ZtT9%2uG}9@ z<+k{daX|V9W0#BvX^q#GK9f!Hf9yzK^&+i1O%2BG0tk6h3)-%Jgnf^g3qN{5@D@tM znI)=Y2d7nq1&PITgr2>5_iY5LEUUmeOq5;#E_~CZJ+RU>w$vQGBpeFKLGMkpD+$En zzP*a|9BJe-b1<I9MDG9W z2vt=IrfQF1CL~*b6QTfYeeKXbie5Pg%&p=}{go519@(^qvKfhYwgT%=JfbaiP!mI`{JGF!F(UK`)SSY3=gW2a=tPN%V=|43cY5y$5(mhYwBuu3+@Im4C>i3b)J}X?W&d1M_T?Lc1+#aR0;VP|# zy}gE-!VTa-kx17#ly1OnwYEu?l(Jd+9^a7bd?tx#pxAShfW6RrTy#Rlw1lt($Kmnu zC1Y~AZmUL=)>u@$ZQqk3M#A7`7MK^~X6_jxBJvNPN-Ts7o8h0wE)@mHht(m5+3a=z z#@Q1yS(jw#*It=52YjI*t5(yDL^;4N4?uj~}HVdoRxv zChN$cl_E$8Cb!gy(n|5M!#}G}?F`kxhVhvYzLA)EvPamccxa*7KVR|skGM@g5hF=b zl5<|aGpZcoU-?GzV<*3SNMED8@Nb-}DMDI&**{xug^t15nr=9#y%6#WDHfQ~fQIt# zm$^ohMv&TaL;4cm{;HwSUPnvBe*k-4oOulg<^+d1`brX>Oq9~)63T*j!_m)HAYb3d zCz`dUn+NKfNjJ(OtE$psFvK##0nt4*bN+`z{aA38GQxAqfJgVyv=pPy*V)|CrFz8z zeTHz&Mn{3X?hO2uZs_^L{b7rxjOUH_uzEXU+Q>eN|L;kWyAqo|J3(95mxHWEObRYu zTBNX_)UzBTN%J9uLQyPfVO#NkgOVJ81RH`Pi_+% zFSb*0pFNc^j(0D_lFOSR1VxXsgdn(J86!?7FJ~n-Vm=2q+e(;E6zAnrKKUCo@4zWz zB9j_TPpG}ymVcQ)WS2u+(sUvgAt~RNtTQ&GHWkRshf#0R57R!wa)!95)BUbx3(5N& zs71X{;tc=C^8$M;@3-f6sp&DU*Jg7D_Iq^()f$A_T4*}8PZ^dmA>qX=38*FdH~B}X zW&ul&Cn1^;PEJ(#6Pr$`p|Z->?`XfS$CEK7)wMz;5Ao8QPxx`EiW~vWfLdDQWYbew zF#of2y-2YoP0jE6;o&jtT%7BjNFPv@yS5_$h8~G-{5!Gt(WT%zv=G=#GC>pxF^(yu zRJ1Qc8Rs=C6Z(Rhh{3r$7BcsxvUEFL$?^d>yQgBV$-zry>w|U?BIMN0eS}ykK*Ir^ z`Jy`Oyn;JAy^*-g8TH`;?u~1?a=;;!3`P?;cUPtLRukJL;#=G`nWz6nouca64FU{cpzP9ql#)_gmA3FNcMxcv+%%~eJRsXmq= zCvfIg+8gIqUZL4Ye8J(%oL1W|nUB!Ntctr+9>hL=AHKLYm7HVU0GT(kB`ixLWplN-RAHGW(`Kh%p`W z>qu^nE+(XmOW5VG8?2Mg8M_mK^`=ADWU9}q?BqvgwbVgx8Yd>gW$UxPV4nW~Y(;-P zM0BH!C8S><3!kD#e`XQ!4>)?tx%FM#s4!W~h+7@gQ2NOya7Wsj8&5o&5y|7>w7)vf zBp_ZJjOd+sGO!(ATYjdK9ny+Y0DfSx*y$}7U$s@2Kq%=UcbcYK)-L|{Au*!bk`453 zTq8R$(mzcL7aM{$HOyrKMEU!4Q1RDVJ-#qXvTrS|Ps2Qkw>)JUAc4{ydA{f+eezjp?wSwTxFdg!$H_|4pNVbs+tIVFdItJ~MaYPX#HTq}AuK8*sLNv2%c$Jzw|;8E zHLYp8p{W(Bszi&=M)N_T1qY+n*0l`&35Rm`F{Yfs=vv2Mrr z4x}H~n?1pOJUr8T59%@*$VMcd{yGbBtWathLB%p*K%uY~;-}XUpw*;dUr{O3y-tw& zm=b)=uJ4(4L{qaKB$`BtL8TuEe_rJlk0?kekk)R%e4-&B`qi z4uKbDCh*RpO*>C7Rh?~!*sgX!XxvHk@eE47O(paz&}i8qBz=F=<%m+S(JM8Ks5Y(0 z?MOMW7)|o-Vv7~OtJV(!yq_%{;nV*ZsJ8t3V*V|3M#iOJ2;XRc2-G7W;S>*V3l*O4 zGR>-JccJF|;Biz!<-nJe1m1dJvoS25G+q|0IhyF+!>R*paftg$3Af!-HJ7Sq=G9*l zm>?M$J5hr2(f8gU=4bC~!Wwt;^Lrw@M?89I7BXzT!N1rj9Ig8uzX*+fDCyk_qeiAz z|5fC!XvcaNWv19_Qe-7Rnnb@hQ9z(=)4f+4Gr$vbz(I$-5N9g^`h5SBu0rcn9gQtk zBL*3i`FIOChdVMj`#31g;JjJxErOX_Y>o@fV~PLAalPMVqUM}0&=|3DY^{GaL5gam zGJRq}&>ih=P!4jMFD9e-P6&r_MS}gi?m3kWHa(KcF^xxPt?)GH>Hvk@v9 zwkwK{dN+B+#R_!0Q1%c`!5S9gZD}5jUpSn9xhqJlg3z3rsaN72k1&Dos1>-tYJ-qN z^FI>wbF&;g#rrN&Zm|rkGW15y2u9AoQN~YWpv}7FFzA_QVOkMwQeknmue@}n-a=R` z^1v%5oOVpl5ry%SWt-PxC4!@6jmNt31`A4D>hO4QtoZO&Hy7WIo#KcoKdS*}0mgl` zq!IpkZmb9QAP1VK3YH;T)@qE)=W!m|CgxO2#hwo$>~^NyWQP_eIeGj)#nnymuT#Oh zYu#tijiN>uu|Lx7NXYHqg>ClAz{YIob z+T+W0#6r!ImD#}^DoP=N0#LSXgwOXAg{yB-NSRt{?uomVvK_}pw4nZiSR+a}$95Dx z*dy4WU=VXSZRN6C{5lma%U?j$AjEQ-iykk4t@TGV=2Q^OBT(q-pU-bKXJsBgCf)y? z!$KoJUe#nUk=ITG?yIU%WR}3c5#1i#Oghn|L9@`q%p2CaCd#M{SGAG*_iAgGxI)iq zs0GdR6MsffGKVs-{|OWaI{+T&V|IVNNfoC8?`)qondxp(4hVN3T(thww|bWSMpO-X;B0 zKS9*8LJxe2=7$quDyDYhI(}?;Znzt=m{v`j)A@C(lC;G-I4vN-7mH^SP6#ChemIbj zbhO>#i`*dqsoPp7iozUIO{2;`+LvoPShGv&qqdjC<=^2r{MrzHLOp>Gmj}sJW zM7~kw{W#+KuTn}XT55kptd(N)d;4Sv2=2B8VTVEtc$EhpNj`j|GN1hIc` zj?^k=iKXMkm25)Y4O|ZjggeObB{iQf^NuS+LDl5T$X26j$Lu3p z_q+LV>H2qjh)GVf8`afwhLPujgz0M)XZ&z`vY-?-x%ZuN&=|9r_Uk;4bE?8c1qt}3 z&GY_bR{+uC%`vO+as!Heoc67p^w^1W@k{$2gGlo+m0Z625P);<}_B3T4A3zu~&*d$baR(3UAGaS^Qd1`NcsZ2Fzk(=D)LqTVR&V96 zJE1Ap!wK%ASp{0Niwq(IpC-d_yu>HbZ#sR{fcME=M1%umYEmkQ%vKelpr2n^(W<~A zTGf!*{*6U<$}!8`wT>X{Y1y~w&6ztC)A};$DO^Ln?{vq--@w3g70T9w>}GjQ*bPJI z^sRVlqlcL!+XQcXWBy9AO=XhPK0dMU*gPPHv$)(MXqRc$ETORcu8+OitK#qzIbwI82;hz}<^vgJqOjEkuf*;C9xbJ?0FDUXwy6_%j{WhbdwE$7^C z=6u^BxV_iTV~G);wl3u>fuI~QMN&V#ncEj@MM8?uL$QQ-wAhs4FokSuS3-U#w;%zw z;z)t-NAHA_e2hpCRiAmv-$a^f9@C#%SiCXxZLuP&1l??7y@k`IXI>QwEZX?>_Mai^nugI^uirn;=a?_t!*yPL$}sAv9MTfI6pXn&@f?d% zB*(GXkD3pqo?uJq3Ma3c29S5fi@EU1 z%_Wli^Bn#M2=xWjZ^ocn@f2muf*MOLU*Lx~O@$SMPFuD+`;cZt)FVs0{ue2TSbtczd& zp0FiJ$gakUIqR>%HYp~ww6>amvtJM$o)k3_IY+7O`8doM@3Aw7!dv2T@un}vZe+po z(EU1|E8Z$F926OS-mOBSuMc|`5j8!$=lYq7ZWL&v9j&0 z$ZoEi50VS>9i&^!Un>=;(pok=nHUI6smaXYk5$N^f)_I^n@Xy~GV=y#XtKlCOb0Z1A=Mdo+>u46offxENv^v+XFxUjB@dl0)` zk8pbwF!5<-io0^#=O?f2?RHn0Y{VY*2syoDm%aA=PGE7QPus}JtHx{xN0nmi5q?pw zqG-I!bl#A7IIwE1z|3{E7_hlRs{f_(cbl^tWhqUCWsL-|k&+@9|JlEX|NT9WXKe%1 zTWmAU57S&^8|@2!Dtt~#UGPn!ly5mkHcLJ=<#YXPeYw4*HOE)MoiZCV&h@EiC)b7) z2xY-Ovw)6g6$Bq#YoCel@%hhM7nRARBi;)`vL%(t89z&;no|o;9OZYV7 z>s9Az#tFD#@aI7sr-{LhuJmI~!=Ld<=M+7hTEbi=QjACdEKd`9K=d-Ohv3VdIqJY#HGb9a+|9}L3s(1Sxg{{cX^(o#jH zNA-@*X$UMiCBe|Y^&!ahUDi8CuXn#K-+#ac2G1nWET322LT!gfjZAenq?M9_ug0-D zX4zpn2JzM861l$%-;#&g|4wyYHXB{@2T~>b1afka{_rmKp*Bfk z$eh68e(uacZq+SJG^;OOh(8{&QfUR&UX$so-;=M)8yR692+A2j=1U%juE?bx9WM7r zZ~7VCA@UxevZ*DN-`on~5|=2}URA1>wr9hx&82p6d8GDRMVnDE5qKLCmV z?VMiEjXS0zZdRBgJ&&V$Z9+6{p?>cVqmc`P-fQG$bsD`7_l=`K9{q=yDfiHmC>J3T z;Ac1};3{?8Uf=NNiBQw+Nm5Fz&|Ciz#+4o;SMd>3y83ne<)eH2>9aH^f`g?~2s&Q0I{9~Y`u346H%GAN(VSb0 zK9iNx-=-?yF8srklUyGbLUn(Xs$`@0avL#;PWK73cnmy(Vcl_nlQ&cmwvS>-2B3(LFb#;i| z2A47mgeJ7n0zh&f$I@PLyy#0-BASrhsC$wND|tb;Y-S)owjJb0fF}cEO(fQ^3t}Jg zJcJd_HCTLE2(z^q;qc%~iZU^QjBrPV(<~hz^LaVX%NSU}qD`ZBr9wbP@T{#!DhuT3 zK?xGi676x4*cB%DS-k6m%d=)?S(Eb`V)|1B8|22aBPofK`i{hiO#S8IM8{o8cfP~w zRYz^!^7u>inVfulj;Krl?GNk)F`<<_grW7V( zi%eCD2J=6mZ$0!ybXb%gvwYM{$}XKUhwWfJca384|Dm!+q0-*W?!K5IJ3s+Qu9QEP zRYKAw*CU*=aaJy#&@1!bLB8bLT{)`NrZ2zBbn!yMZ-XK#TB#_P_asXdlI)pV0e9_w zDIT}mv(DufrXL7Yc%07_NFEgb!bDf?e!iVf-b$C>0*bt?58BLeT)X6y5;|^dzkRA;$8PN|tTo{Y24>!# zi7BMZJPkK84%FzB>z8XrB<$Z{m^^OjUNqX#;lT7soFWJ#i z?ySv0AIWvW~l#4&2 zr1!fyFBwnW(on4@L|+OR?!>$H_h0&l@@=~0uk>zw7N8lk8}Q{_a3N)EP>GiLA=_Lm zrJKRXZa0dr;acO&C;7w$GRtLjzU&aF-1f5JfA3u@YSbOu^vwEjE`ttZ5XGP@ToEKY zk~+yW1h<1;K1AND01UKR-#UA?j(7R$m2Uk0?d!>5`R&KBJut7#kw_a1Bl9{3|(5`yBSl{dzLM^Q!xC zG6}53QyKZ566u*FebtbKgyqP4r|+Mdb8v5}bvYI8ssZpVoSO!YR zbu+>X-myg??LOx|dpL^Z3I3!weRBLIgU7ejysYl{%vY0F49!=Zgf`5Rn zz6AP|@LK*<%I_ofV;Q8UPf&L#`LtZ~&z~-_&S{q`zqv?3 z61ncEBRzSE zty&=3Wr^HZUNnO^<5Sn0#Vk2~a*}&H%g-lr>S=L^PbtChI1bP0cn8Sb6Sc?z(-(;$ z?6VRl;}2=7-$qzd4ADB1Xd|zEYA2^Pk}TryDuuUUnPa+w34g$dSFR)oD#pHSBh10T~UUB*hmn(bVF(<3$JDf}Hsv&^$Z z@O>T}E%|$upwE?P+?^WX4v?T@z!sQ!s3y~FiPTJ@h@(vtN|eNu{k&8l@@PM}4bt_wZwrh;}C42Cg$7+=~PKq%7X zKQ&T=$iLOsBcXk^U`2c&h4M24^5}RuOWh~cs{!Hy@)g%2%7f`c&&WWG7o141gJS&C z#Ztx#wlNNAQ}yDKmAS#4k)5m6EU}G3yk!W74nN1Y8T_r(ByN(?dVkcob}xsE>}I)J z)-gY09&Z&Gvs~#8H9|Z4+283uz^Wf)P9IhNr;}z}OZ1qZe}KJEVgp1Iq}k)Tg3XM~v+VMg9`dX;RuS3CNDs3yF%%YB z$3JIpVQ+sKMmNji^Rw9FGUSMOHBjS>`@sA)zW)KT9j05R3}z7&(XNgR)e<$uA9bKy zy6!`uc=ri?o~+jsQlf)2Ia=d{ig>|E&WsN%FyJ?b!r3oPH3FNM1!D%zyn_!v3j*Qp ziC*5?j8TT2>{*Liu6rR8I;-sJ>*H?7e^v?jV|&iO(2N>SPOj>9)d*VoMqLTqc8OOKTZh*$wVu#&7LJP>2P8fbpAZNB_{fKfPk}2jp zxJDf$EY(sAh_jB)nhDs1L`LV+eF) z)#wrQ-U}0bg13%gS9mgzj!B{tc>qRk?p(}%n*VM1tEB%^!eGXrYtjB5ejV0I6Ym|f za%@2=4o3;+8B0q%_iUDyW9VAI#u4=8R+>!tkUE&iVVFo*o5YQXi0I)MJ2&Z@Il?Cf zcRMEH-UHsxM4Ow@J6BT@EVx7a!|8ZQh;nG1D=`L>CP*r|gtBDf{iAS;YcVh?2TXPs zTCYlvZI?x}WHoN`E3PJTMSKJo3*O=WoQF1Xd6&)3d`@jX^IFbeiViCQ!{3%N7E|n= zRDn*in$43ynri@z1-m?(mHXJ}39O?zgL;t91s_hPYnwI~1se|j*A3L1LZ|1PW1~yJ z)we~@fIa-c#NN_Id+OA^>Hw^u4nh9|gl*(`Hkg?Y0(N3CJs+~63X1t}^$Y&wPFbE0 zK^KE3>!pgd&Biu>n{hdVxi?K&{(+svPaD+|0OLD6-8&skEezz1tGTsbpHqozVPC06 zHrRN3ekjSS$(9wG;M#e)^HaU)aOB*HyMTQN=9G5#`~PTri>SD|E@~HoySoQ>CqQtQ z;OSU`ciig?_tInDJXKSk~ilc0()|>az?Xh8|lQ<2hfoWjt_n||_ zR6GeoIr|3Up9fShY;)^c!r{>H84?6g7n?t#MGeqb(v(-Y}tMIPc7q zYT@v98P4H5A)Pv%1UMRbZA31RoZPlH(HciN@J=tHqj&k@f}f2|nUr{>{pTl-gTp{J zUiIfDMb_p3u{dANP7`?bDc!!T?_mo8apphLQuR`~U}u#Mz+Z-XY}FT5C=k4|O4*$0 z)cv91f^fWF89U&eRo0=smd$|Bm}Yhc8p`YvtzY3%;RxOmFqeW*tJPvnVz--kpSFXB z>!IybX=vI7#0By0tvR$cO*-_Amcvj;jLL6RYnjz>Rm9e9fE30NNwfBB&;_-sM)8Es z+y}<@f^IQ{$j`Dueu?_S+Y0K`?I0x_Jn)0nh9M)Nb_-aSPJr9(qv(883*G(@HmLZJ zBdiWZIrTETV$tF^_T(ow4N;{Fioop6SE>^;tb zli0I_^Zqa5)rx;FLb_w_)2;PF67>nU9niv^9Q$jDsT#d@_=-(Sw zYztP0ukrV3vjzxeD9_4j-A+(>?W@)&tgH+TtWuxIWYHL^@KuhpT_`nksE5~}<8Bu_ z>ui@NI#n^`K!h81T{6u9Ai|8xF+(I_2xg2q)Ao0AB>0?&sCH3F z9qM%QYo@Kt@5g>m*DJ#>PR$1RN{k#&=dT$#0&5>bT(n|C-VsaB-1}oSaU4cn02e`J zHA;zp`Rk1LDJxTp5BXn|=Bm#Ot&y4S=Qze3|AYf%Z^Do$UX7v{!V%TxgVB_sCqigM z%{>eLDOYneG$wts6W5#%InR@;dH43EbRlMMsB>8 zXjbSVI2rk$xmVY>1t^+LvcAk-yKwR0naGJtl2}GE?-uDW?c<$C(E4Vf>Z|8?0>{da zvL=Ovigmu30eA=_hd8dHAr$@T)t7ORGfZELfNz;vf|JZ;*V*qrz z>=YfQe**EN#WWgEmJkD@#EPFNT-LqXt-%wH6e|1y?>NPWhgOkQOJC3F#*vsTcaQ}6-_WEL=>tjsOSIR&0Qq?DU?H!0 zEm_%wh2PfbHZ#7MFU0=<(^s>193=Ix&Pa(8aZ`qAyh6gImnl*c4g|Pe$+rL8J{;`_51Vr0QH!}amzHjTe5n~ zUPO;}G;$_Wx`i%xn0T8~%eJucYsmSOWd~K&7t{Y>^1S{*#X|-MH}9PS-3|ML8L2(B zWVyCR-GL=?+!V#lUWU2qV9xmBrO%5+3xi{OarAM-?LvF7V{jx0O`~mF)?#FHHS>#w z9o4Z^#;F8^7~b!KK%R;3iNhXhA)#$9jYY8xI{?k+kvGqz)_~lEV5nxcR)>T17_lL| z=b-Ao)sWth$maNZe|hXJd>)-LGVNIB{eR0mDiFSw@7#UIk@=H6tJo6@cSr01BgG61 z`Fp3u`@e&#(KfOGh}~$YOKhq?Gh5k&XTvX5_iZc+JBy4%g+E<+4R9o)1S7n_ZsOUX zN8dII4Z6Fy8b=vEssG2kTr&Lsv6uW`8_WOy4`D%)tu11dMgVmO&d=%573m{)VJzs?f!!=g5j-f*#s$wo!EX-AlN$Z7Yp(4GFMm9l0cz z+$&=>0%x}oMZCXpzd~`thWYUrcoTO%*H0UdL(qb^)-T4RwhNJi8qalBbS|JJQBP+{ zLr(|j3H72wE9Cx+;Kfdn7bc=2G4-qd|5!z=&$Qr$d?Ur;n$voD^}1GSOJY}bCBY*T zMI=YKG1}xnuT2=($k8?LV^}KSFFF!r1x#!|{gs$sbGO%#7)oyJ4)ZZ7i-F%Jt~Y_? zd&wvkn}VY*+g7#_LSu}(oAp>iV;@^!V9Qevm~~)>(3Mqh`F0GSTYvIyGW`%!8FTGG z+$9I@oZPBL$6xvbxlt0ph>myb<$KcE;zd2q>y*SRhQTaxAtFl|C|r3zRl1s zi`(d2W08ZG*Ws-IV(<2$$U(X>qhf4*ng!AP+pO|6DeXPg_O2REpAHcd*RI@9e_QRR zqo+i})i#tt;WG^-^j9p00a0JZ6!(J1o&}+&usgvsARv2!^o!3b8)nh%*`-Dn>W}6t z4G6_OGzrKQUKiCL26t_o{3G-=-&8+_CYmULdjth4-E*8Jf0LMh!zmed7XwV4_1~+(6rQcu-BX$h6ru z!-&!i9y?6xgKMLFw*=vVeUkn{%L`{5-xw(qz51f99iSOoI%SI)9=bZ)7oTIE!)ptE zke0>m#aX}XVr5-l5LK5=64-K8%i=b+s*bIFMbJuK6L~Dl$33|eH1*T~6Xuqk{du3^ zD034y4n{J?8t|QYNF>mZF1utRhYe3zGxreg;t{6hJVS(Uy%iOA3JZl?B#Ti%?JuT; z%VHD`NF#<(oXF3SYRs6w8ip+EZa$OX+C`px4Pzv+M5aCghTW=xnMBmU%OdRLot$^U zk|jy1OU)N57Swjd_LTl_)1@R0&5Y*mss5*lUC(Gg#%`n+BKCIBYPF5jJFS5`8@ ziE|!-)wf_P(pyhyXR;{xec^GoYT05+AyrKjp)e^kJhRJoS3mku0P28Jw89yd`l7O` z7F#^EOUtx$^KHr&97xl1MJgO=xiKjfxfJ&-{6$V`!*4lPbk&#w9o0jkCD z8J2#7(Y&K^y3#!NsCCF}Vl{w1qtN~TVB#LJh=VBSgQV%d@^frekpHnr5lBXaVD4EF zqRYwm30>GIOJ%&%R~m)8YNUQ^h9xMTXm`U5yhHRH5C;nDFEdmSIKB|nU2TAM5GxM?Y6DM7B(GgauHui$|A^XUP{ zVM5(FL$)shb^2(C;#K&X`>c}xPq)rT%)jN~DW5;dx^pN+!=%wbkP<$HY%{Dp{Mezr z&CyQMDv-gGskzg#PRW#z+!#vIOfWyN7d-sub!f=FD4+jS9e^4=z!qBa4|D=b;3;wV z5=ok|L*}}Gfa=&6}ysB{I>4*YPP!>dRo2Gngoy(hOv(i#OjpxtfU}|>8 z@HDQlnAk6{J-7*D?!Ge7z>rITTpYol$uw>ifmM+>C@3Cz4gewP1Ka*um--}s=-H|- zxvalfAP(D8$F}NU6Hf@hP}?Hi05j>n@UxqJTRH+w))0Pc0SQtHYJPJvuYh3$B1*G@ z0^L`xS}1)*>M#(E)G24u%;}+PexYSHtd|CNWG0ovMxlz^&kCcRP*V|AAEEy$IbeSG z&m#;74UFEI3ChsjX=GsK`y&MN^uQ;N)3p}nC4&`Nc_xV6(uM~zklc7MkwSXS9H|Cp zfe*V$j=y@YI98&a@I1AF?eRn$27ePJ;76oBB|eQYx*xvVnTTn?I~lMkQ|Lq(jC`BY zJD>F3ei@rlGyG{b&ktK?xZGR{FU?tSq?f=mGaKFqcTRj11D_mVLgac_w;St4hT*cE ze*HZR**+exle<8U^^n2ie)p)3(Dx{m6Wew*V?mvGbhvW3 z*T!SlD!a0NIDCn_NjZl}J3lGmE32-W{PHHv=f=ggaMxMXY-JH2&*)^$TJWRwC!)4n4hm?FLAlqbu7W4Wz) zU#CvEFUKx*Q7Vx-)G(>GQB(#~&hP2uSK;r4?J^nz66;)?bjjD0la;|iCuaw%YuV*$e!AL$Jf1`PPaWs);ut2$+Dj!mn1`O`6mHgUPs0Q_Cpf)yU*W zrcJX68iAu1eEoSQYG+Shy?cXc=jq4v7@vqX%T%M0;55z4M3N?!(D9meASl#NTO&V2 z)ZB-uU+UrP_3TnX^)($n161;% zHW|~m=5m#^?_?b&oY)b=)iD=TXOHo&C3w555_S386hQBiy}M-Pm4uo^GM`hM2_Pjj(7(v{b!p zrUuHyxwEmPdU#KNVg$7k{W055`V)dzT zo~D_qWX2|&;`Lj5&4X^sV|Xb{`+yyClY!CwXlgh(=>5o&*ta4I@p64giqOn4DL7Ww z<5w;CW~f|1m%t*+T9vvJ6kqPaOI`)k2A)(i{#xZ+t9M}Rx_4k*FRp+h2NMp??10kl zk?*5w1-iwy%5uJK^c}~{f57;Xo+mg7G=LE#C2v=J-SYjwfUQoGM;?FA_2`=OEUO7u zMYV;mxI&^**1=4g#jf&>`f&29KVm}A&X(Wk->idV7QKQ6R0O_zz9mhlZlY}i2douw zxEMCFn1*hrU}sGRTqf*$8J79h2`(M|ox%N46Hx=!4?f0(gk_9asWQ(yHY0XMMF65NSEEwX zS^#|~p?KGi7y#{Oih^?|O*aX0SBR)T|K#8A>CHwwe`@|6u<4{q__L@V(Ep4wM-;tZ zO0OHQIlVo<($oi_Q^)EbBaQXnO(aBNjKe=-p*ff??JLh4)t0jx6x*a8xt~YvSwG-h zQi*Q_g3CLe%XC;4OzY4H((wTvrWJ%FC%H?7n+8}mU3!YdSF+uIbf~+n z!#$-U^+~N){hlT_*R8MecYd20&}Es&Yh^NJ+r#$9#B`I_n0GuFVoQi9hJtlxk?*4X zk!(d93QAy5&h@W|6E?g_pIoFljy;(k<=euP@^F!e;s0U2%gP$)DJZrW&pIHKqLW#N z&vm!1hvPKkQ5CzW-g*{_;+h_tQVv`RH!az=05@(+vQEVhMGJ&5RFbFq0Vs-F8>h zIGqbSCt|=QuPRYDSMCCF)B{^4IJ>7$=;j8Lny3`;)6vL8z^`_kJf1qc2^FW`B$E1* z=xd*53x;)OOE|?CshR+8cvz;clYd}nK+^dh2UbYK8R$@8{`>Bv(?;ix6|dsY_5Wbp zO$o)XCEp%pfD?lff|BFB%H{UD3^=lac~bzOfWH;>eynJi^(FU$c9)3HK_!7`j)x(j zoODklBL#Ry0iFJUlbZ8jpLxS|EFVc!x$0+6fMtTPpAG+Hcl z^i^I%9646F9cK{;bde4d01T_fSy8(Kj8{aD83E^5jSt-YHO z6Scp3V1&O+q!yU@a`Een!w%DQ*sJd6iK>WnfEf7H?RODxXfQQS2vgsF!G5&EQfV;5 zOq)F}HQgAGo)dQhwy%71#z4R2&_C}wsAP;?n1X0OV-l*%le}_(ty+@3M@J*3p?IGH zm1)hAKn`kvp2~xgW?z>1jeee|^IZfHkRk^< z^v=Fw3H2XR)@SzEV{B%AG0n`grT}OiOOfAd39YI1g^ma#)aZVE`+WoI{^Sp^WBoPB zOj%S;vUlj7aClHrH{GUPDOO-(DEzAlUrLB>+7Ib6`7pwY{2C+WnSwuIP@3JuQt z43x$e%>GVD%Q&Y^rJV{s)eOnAI_VJYjCi;6)_mptA^hDb9^h}KUnBKBl1vD4HM*Pt zsv%a9TwgqHt8TIX+=i#jGhoV!%R@zdXP_X&{!ikjAfz;hWMPVcUwp-jXC+#25_vxX zU1n3F|0Zp{5lfV}p_iNO$VIk7Q8*(|o*oB=T1vd4RgsZGw(6yoY1X~_bc3grrc~FX zd`c_Rp8K59C74kJROjoFj6%*Hh);N2YJHfge^5!npr1RQ78JxH(prE*(Y)!hi@Re~X+VF>;=K+lDO z=ZNKuG_{uF6{ChONlX0|ZdB%eth`$_my`PiW5(~dRy0ufmvh_ouCPgKz>vt#Dz!sN zGVxLkqOU-;C4HQyQRy6SSp~kcD_Q&o+Oa2dOG6t~)sxv@AzSFc=v9W6Ky9Eh4Q8Qn z)sh{1#`iHH+$rtX9?D;23IDtU6%vEJNva#_8hPYdM)1c+l-T_DAs%WLPoiuVC_eON z9%aR4A~+lKx;;X+n~Yh-qg7TBJbDr<{V2E3xXN6y z0cKP0g&rPRhoFQk6nGH9pmN2+OxwQVO{&TPUDX_Tf-6Ohqx{Kdv`x}LX?2?QPLXI@ znK-B0VDs~s9Ho=*%&vl2TZ70WwOpEEPAuPicWVQML&kT95|0sn+9mwkOV3f4!kk}z z;zz&iX?cFs@|mL)Q3t$rgLJS$`!*}PQ1>8GCY7es6P?lJ0gQ{rCEhfdy+{5(KbjNs zxH!k)0|G{DqwV=#JG0r+nznH)i}5Xniz8`6nfeN? zg927|F=Wb^LNkNAqMc7PI3 z?G3P|{~Ak{moL(8wPsm~LR2PB&1%E3iVe{&NfL>ogvED8 z2<+$@W^qc}G@U*AJQGkwii+NnSFh$z*X8)Q(6Or80x}ga?8}ipo3ssaPUqAD--M5@ zUeY_4y6tz<;Je*}Vm3WJ(A1NKGQX3)O}uY2sh^cr_Z7Tb82E*vv(;5#7?nr*nCtGy za+l+C1Oua^bx3i$52GkMK0?C8Ys{ns;a2iWr$U=g$9k_2k;BC3?=8U*wNRIa3&IxH z7i(u4zIRPDS#6zI1V3=ZbgCcRlH{NVqUVZrrB-~vinLNVt^QF2EfexW{W}dMcYDa3 z8&Yq8Y-?N(a_S$I!?6`ghL%Q^YflZprh-G5(;IOq>715ZWE`-|lQeI8peoR;>YOXt84LzAk$x@Kpo(`vm29=-& z)1Dm&onH9xy$dcZd%Y_yvpm%p`SFcab6DMUq<<`l{s#j^Np+^T@%;ybVHTZ7P=kSaK>!yOU1fm025zF(Dtmz z)1X~661nzj)qiV=c00|bg;DzBDBlHm79e`Gzo}DR&N4_Z91Rp0q76Chv!a-A^jUv> zg`(nu!nlmRlkFFJQ*;Gq3`wEa%!#pHt0W*j9gtZ3GjD;~%lTx$_Xu6ya=VoleejHb`wy`~ za(e5Xy|+1rlG%OiHXO0pK*pZjUnLU}gVBQxkRo?$j5Ny2&mQaSTS?5mmD3s&`y5Vz zsRT2#fxLb2S1<=i#fUh3nYZ2cjPXQGKE=|cN*OE4ELAmV0qeKH3NcNDCxr)@t*Q2B zEjn~6a)*UAYF{#lxmzjHsXUWHt0}PDYnE}83(pP=qxlqOGHo@qnbJeLVy^K|kdY61 z10M*6>+$s#21je`fu_?1xlsvV<(_Y>qzUF6Y8Ie%#?q=!TI)g5mWBM*naokj2(mDB zwkea&ro7SGNbch_YHsoryaig-8p%6VZ1VUKUmP04U`FXb?x0*tHT_4V`0m$)R#0tq z$~3wboe!F#F8ihsl_DL4WE^r@;k6n;sNA5;Hs3U0EEhSJU<>Dh!ch(l;vefzS328Qv$z(UIWiFI6<6B}v+s@wN zb0#7|k8C9OJw-_$kH{Ygc_Y;cg?l5_$ zcz_ym0IX><|&?P+~w&m3zMpNzFhJif} zmtI3D`u5^SybYl(7&~QWE>^BvB+=b=mdqiHriD-WMW&YZy?|RB3e~unH(Z|7aA+B7 z-UAw}vo6NlV?JpMr9}Io?(WvI(g^9(4zSxhU+8-GWuZ_a#ut%ZA6b(B8y|aaT^?Wr%L?ZxrWt_)ENo+Hl+_Oc+F(&}* z=?eOc)^rxCMRKfjQs%ifWBr@p?P{5*q_I`kc_EB7sK;?~T^npmu7l_|mVAB2bo0Cd zI&}Rooo%qOjIKeT0IdO(r79%z8kRR~HU8PGidS|$abA2I8az1w$vw)66;ELFj5vj% zj8v2T-Hy@|rQN|jLxLJ><|Ao`r6kN@#2{)u)Q`+iT-X!LF_os#RHX+J|M0W-u@`j7a#K+)Jh^km-u91S}rZ@m24igq^3blfY7#=xh*=c!?GmlBl`HOY}*&D9(h)sfi3Vq zSL=}gRF;P;zbarAtNIck0y=aQ*|*7|f5oAlt&CYtyIQO!a6TuETy8*MVl|a{=|V43 z#0a@eq|AH zBH9jRK#W8;&k0)~&RoVt4`2A>IR97v>ul;q-6kj^H}Tc|yGCkVwz-i=;3Ms6XYekr zeX>2o+DM56PMHX&#Fh!qe1jMWYu*psd!(ksjyRpbrQ&Fdtc}+ObP=~c7R9SK$^vNG zlKVf!>L<5T19_ll1HC(&=)W0Fe7!PWhT3=MD|z>gjj$K+p&RXxH^xPK2MEW7hhCx0 zoIz1yva|jH@@B~xgn4tm0CK_k^WjYqBQjLjD#|*uQ${Uk-$(o>4H9?z>#VnE?A2U& zoUXCd=+8r=QJ1BohW+)r6hp(ZKXJ5n+En~LRFb9xWHd1iXFF+?gC$T+jkgMiAKp}7 zZuktJBtI`b5%yV?bJPBl4qn{Cyj)C2Kk`) z)c#ImnFBE=AO{-JIW9a?jqOKY!!w*^OD_P*)sg#~K87MSE_pu_}dd}JUjFYi)*!>w_^w)18sq)Z( zp-klfZxakELomK~Q3~=Mp&5faY*K*Ie0T@%nibX6LeoJ#hCudy!O2FRFQu1&!nbbs z1J+iFof=#ebhmXXH8p1e^lRf$)A?);s;ZfzmxAMw+Pu{kHc8xN;uWUij8(yS9!1OI zB}K;N=YujYuk17JY<`8K<lD)DfY2*AaZrm@A5k~G24TLifORdt z$BQm%B{yy`4Ot%Zp>3c3LmyEQzCH27WU{DX6gPRiuJ#zc$6lUo*A-nz07GXom+|j> z)f6t+7lOIpt9irp{^r#ok8wQ&XN9q!+sS~uTcA+8**0ZafT;$%!g)5|2=1iWG=oZE z*fz=g5c)M$*CvJC(K9$yEzzcazugv9Cn@KSB^v28`Oa!=wDaJ8PDf141mthK{J>;- z!JVb1w*Vg=_l@~79?J=o!>Z+I-J$U21Madvh%kf6Triau3SgajEe`i0L@Efe0(STIIDZLeDbR7$2#SY;PJEnU=rRWEA2jTK_3~_r!6+Azgi4+ zx-DV*d^7#-753n%BSBdDdeLthj>El_@q`VO1r;(x6R%q^Pcn}gPS27!Ahi_TWuaAxq@X_S#&_Y0rSKeQ|<&P1sOJm!qSv^ zkxKWuoPwFN^y2c42xn~Mv$U&qLSDN37>k@6%1pqS3h$s8<=i8?k=Cy};f+T{v_BFx zm1IPTMz1F6ctlqxeJ;(wNRuGzw{Pst%Yb_P#hMFCYM(D^D8Lx`nvb~Ci20U^JCb}#>vG=@>x>pqj5FvGY=NCs6h17E4)Xg- zbLUzHpH4C=j2z~)W6)E6vy}drnB48O`kzhvsj||qZ?q4w-Y#HTeqP4&t;YKypG!ZL zIlp^4YP&7JAA5?N`CwD%lsuNaY_42&XT5pLx&$Vwydo&N(JD*S4tLlHr$>MNP6-T; zbHE^mY%4So;diz2W7SoDzdpVVF}q}(bl7Vmtxh}4V;I$EKd%2$Y};AkVM83bo0F9f ztn#-@8;4cSlBd3MlhQZ=#`xNDi1MRg)=+J517VloTo<9b4DypPpNFru)kefzjH~?L zp?5?z1O|&2e7A3D^$D`-wP2TI@E|HUp72`Ucn;zQCy+)gMZ5u_tsc!!JJL+F?h{WG zzj;DMZA`I#>dtrjd2K5nIw_LJvlWe5-Rrom>xpoLq^crQozwtlnu?#fG#8m1G|o}M zWFGbpRuW0*4Oe#ztbfv-QUjk3Np!b0eAERG zoFY52G*U2Fy?UQ_)NxeHuP>C5VjbaR4_Upc;T$(|#;r8lL%WjIck>IideT0EC3uLE zv_x3x6tQNdM%y7LpxWmzn*O~+D&+_-4ZN|pbenV<*K8WbZgQ$>B>%7l&t``^?Tz-X z3w84{IoG3#hHwmaQ6&`Ej>ce4&QLp8pb-f55w%VI7z{;oXOcE?8MwOs*59}-e+4tX zMq{};-QL->!_*DSbqi!LhIT>4F!p<)Xj(ybw{3}zet9NKdtqmI$qv)xUCU)UsPk8J z=|M2u4_w9xpmm}@RPYy_nf0ZPv&D0{DuXKQ`Kq#h_S2M@kFi)ry@IN{p?wB@qhFUd z`-S;%L}YeW0N!_Oi0W0uAz2ogRB9xnqMb9nc=iKg7;{YxGzvAMK6bVY68n-NIpJc=4h&j2=2eTCN~Iam)l@9M4O`ybYa%|ssytyNaA?&9k9y)m>^1+Zj)Io} zjeEL?MKX}5;CCf4ZCaWi>)=z6JNQ5qObeeH<#}(fw6v+QY6q8bSsKo`72G)$@Af(Q<_^E4dZ7PAU`JVd?q z&nDJ^{swyS&M^57B$;^fFmsoV90$(0+hnu>wZrNcSrlY{=PDS~{Af{s(P-|lAmZwxeBG@? z!Zh~S93kv;b&?{avkjcy!3-o?(LtXxh&PLNpn=G2QLSVK)8;>x#N@xEw77Jho8sU6 zYuj#Z|HRci`wk1wG!d-x#rb^GEvYxaDZZXAu-Kwpe-f4S-7^d4>q9(W-CKIZ5Q|u` zci{3uQ#C+wA%k;~KuH_GNNILofkrN;ienCQyf|q}REOAISy3~h%D|+)K%_yVb;8f1 z2gYA`Pi=V zC_Tr;vdDc74vy2G&Ax$=5=0b{V)!<>;AX7B!5~9v?66Pg3vjs%~@auDBr^m6CS#TLNMpL)k?+-FFq)$tA~|#jvb3Vzhr&@oCFWk z&MXF8`&2whWrTj!U5(^gYm?a0F7DH~p`I&OFW8-(#ZhLNp}}`qvCg111w&)0)EHAh zO)Q~!-Tpl$~r4-Xdd4d+dG_^=|DyfaKCwzMU^^?eMOx^F-}8CMZ679Z}UKW)un5xLb5qu zK2(1+CKkf_l2|~<10feK&uV++;cvWO&$0EEx^=1v?nGws#xgDIB)5;hZ&Z_so5PGj zW{sAItLBQw7KwV1Wx07IH? zvmcDF_Urd^W#&tr9fw~tf^`k9q*ApPGw4%=6vsI3III}Ywj@X{>P7gN?I@`NUNN(! z^8nXM(AZ+HX_LSAtPs#v-+M0&Wf6|J%Jpx{CP(;3MCA^3~b2XaZ~+S{E==T z7Yad6m47Rs^&-aPQ_o|Ytp@J7aQc*NjymYu8O;$zE<8Cd5*!k!Ys%BPGV?d!yeH7B znw3%G zCvidC`puZKfZ#fk3=@q^2f3r7)XS*2$T#g`YA9`fz2hFSZGVMCb$IKaP3|SC@CmDn zXvw5%m#b1!+w0;sMij#!t|>f?i*0%T`446gUNb2^AhWyBYLP{2gW-48c&pSfymaRn zqP8$l^nSN)vcpB-+1W>ZaTH%eA(h{HL)n>yK;k3;6zbzQYFzooH_YA_C)`?D4h4h# z2ZKfWYp_oljm_VqR~qRrQzLN)Rb~D!oEdLjyI?tNzl@(IzunrK%T?MjDFi3gTu#$*IUPnQwF)6)(e7?iNY*GT1rvzb9_8eZG1{bQ(a?J1G)5(Rb|X6d zd&qZ2=4i=nR3?|6G6492ReA8y>qPx^s1!s%-$AXp_0NbZJVVN#9df){s#y`mloUh> zY2h-2;AleLo#`aa)SfigXfy8XpM6%$OW!=S7EdSAbXJYVnwu3JKD?MF$e4Pj zu~%o_EhxQ!Ar-bHIl+zglrqjJb20{ME`<{2VZpG=~-OBHT%kgzjKUJ>P8LV{T;Ot9Eu<=7x$ObnnQ8RWbk*&l6( z(rfDCm&Ic?I?KU?L7qwv0UL zI6H1){zh%XAn`fqM-gqxx%6mnfu5BUxX_^h-_D&lA3@TT=aeKgHY)l86?>X5x7dPj ze(+!53_Cz`&1>RlIhpUm#oV212t^2`W;}SfRIv;(F|ZC!Mw~-_Mh7Wv9RJvlU!l$^ zE3UBj(5WO(AxyLe8c28{$6B#BS30@RniLoNv6P32M=uw`7t(Ej&yRZ`AQfp(7c~Ks zDl2#p3~F^>8275o@)k8;l36d2PHO@zQ0$1Wp9Qn{v7T% zITS*>`0x@Wq$J;Dv0{V0o(#{w-SKMRPCQDCvE}{Xzd!d_K;&pxb0j##z@u$Ffp0!PQD0^DlfuDn2p<*}V(+ z2DzXFa}Jrs7ElB!I}VCb0apt4aVKr+3KVnjBIM2(EM@{DV9C8RO4H+<4pS|x79Mj= zxb&*5myJ)u(Dx1?CahrI=aO5O7>B-?H&h3|;t_$1xL?bbbtm6yamkT~x}%e6==CU} z0W58xj?U5epuqYd>3J8wNTZcUcBf`-^WtCCdUgx4qj`WWJf8*QhDYo#=$K95y?m^F z+h~@aMA;x)FqUqFTIOOE@_#Tt7gFfdTM5XKSSklZH(LcByFak~lwah^k$#AL1G&aI z58`LquhrDUSo9Oq`ex~M0b!_NkSLtZ?Qv0$jP<}sah&T8isj#|`^hmo1bL6Z#?@74 zjX~JYJ%x&OXB#1P7=Dj>iUzeUW7eKzP|6>o6p9VfX}^f~Ln@gtWy@`EAV0so^HOS< zaPYfP=&2sEfylCplFTSv2lQqpyzlzA?(&24gCCsPRl^mH%E)?a<-Yw8ZzXsNRtopoY!6U)A>G9SFg>H5+UfVcvJfs`|xy^Ppli<#jMmQzso%8Z<|FFVElU4 zs(5B;i#c^@R54bT@>#T~wIs=lxT9-Cujc&P^Ajk1C?1~X7>Wc{3%@(=AGcXV=Q=Dc z_%B2O1+$nv7SdXL5ny;dXI-8z&M+KyIjcU`RpTSyy=chyWE@VUn$lj@sIhDn^cfGl zNxV_5b}QSQ07W>fH_dQM<&%u&OQV%>Ok?ZTy4%CBP>8q8kVFnCYqDr27aTzpe3wQ> zD&_?C*fJjS>cP5m&((kD_v#~c_`3wY8@9ak>d9Bq@aL)**c`DbkR!am_fgn|M)eI5 zwtg_K&JNw+Nct)PrwGydbw1>$Y~+x9P~=z#v8Dd`60eF;Jxhc8{?;dY<^Bgl$iJ

FJ!>m4u{7C(Lh-0%M-iB)|K9U2|DLeudn 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 !U%2c8gUdxnI(dT*2f&yvH`A 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μU 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

;a)xo~0D4)Y6LdPw_<_oGoS;vd~ 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

#{A6>7r_5&X;|q%MM3gjRPWJ7hbr;IJU6 z!S}~RHe|R2k+eEJdiw>L6rVUA?VjI`0OzQ*^@gPB2$%^skyaV21679B!v+~Gm0~hT zA+U4Rg9;L?b24ix(+bell49mzA@kE}@b2Gr_88--t5LD?6SaG3HKmb4PLgD>W9mLw z?nwJ%tKt?ssP9IRCYMrlhIyr6Jc*_|0%4A1VnI9%0pF%n;Q4(5)Ub%m@|hHuAWDoq zDghV@e>m^egrZV-DZ>t~$|^jjvw3w|#egSwEs$oxz+CaL6UQBRYk{U(x@k$}8yjYM z<@BtXBb@dGo-b!`jDvQ0~J}L)2qtU#Y)VqVnhV7-Vf;_u;X)%0};skbR4lQy0SEeT8k`# z32VK5u=#}kqz5=7CyeJF_{T<9wqUVV+-T4U*pvES>!|EVKYwC*9@yxuzdu^*@0vL6 zST7{jI9&VppXbC+o$q4^Z@w<2-ZQ@9mD0+p8K+ zK-x*;XzXr|IAmh;WM!cdjPs9BEsmHZZ#<20YrTsTF*jsc6!|0%SETaC-?_)OI`$D8 z8y2cZWU*uOd+)Bbu`nooAzQRrP-uvb4d>0G9+!R94Yj; zKeSNjmlm#|HnZ#>&GX%XcbBKXcTHKuo9ra}qs+V`z`kH;}4V z>D))Z2iMMeDKi$SR#i}ADAEf1{KmjI4hv*s-x%%GYc-pCjN;9Nh5;YUPa=cm#~1DL z#yueW{{ViAo(Gdw(_@}8s_xOWjB&At0Ya__$m5gSsRaQ7P?E-yJ$Vot5+vSSsbg>i zw>z<%kOy;CYo}ee>A$ArykWVR}RhC1kG? zOp(UlE)L}@l{<<3OnU>=`fWQ&TJ7j&s`V@|f)+9PY@2v+RAc}TZa>de=LHSt&lNil zGWkZ!W*D>U4-j7LKAohFm>Q7zdmdz`sKTKu%4I7QO}lfGgX%f|06j$36IE)Xl6^vm~2*rz5Mu7n~lJVi%azs%>j2g9Xk3Z`*H8bqRh}zst=(>S8b#)HE86FPHxFc%vIu))Q3%!7ksYbBv#-R9fuj}`6AQpY1PG=uN%W{<#$BG z%H(=LFW{$L#A7{`3{(J;LuFwhFetXHy; z)@yG(7Hr|>Xy^Jp8S>R}yEx+~j;e z`@}FbKOWur~SH)%~;mBof3aEBhFS?83yCWmV@$p{9Os^S%iqL2*wPq`kz^ZDrZ`FXUcB}BJX;GKxCT-~Qa61m) zj<1FbiFGECL=@yxJ)Mz(JWRs_KGJ`D=kwKyTo-nVXy;rA{M_N+x2W()BcA>GBoie= zM#9SQSkt3>Tds)J$nxB={{ZB_bMMC(1EA74nb{?yVsuyCWm+#TIKgecW8>JKz<=kf zBWL;XEc3h;CkYb@qb-K|QUTZucXNY}^V23`mFB5pf1O+e@}5!=0Ox*3EEBl|ob(Ri zFmRSsctlaXdv6$x{#oa_AC%{uc~AXB4gnbd0DhZk)7EIvSFoBo64BgKC~qn}_2Lj z<1ev|b`uP7NnvMEHOOpq_J^z8y763qDeB* zMNMs(XuHOMx1!&^s0gpIn}3ZMzOK3g`EB>ItJV>!`5Rfotx6 zFxOI+R1c|He&1#o{@pN2^4u(x8dPx!hMaH^s2v7(k73W%oPqY}O**Xq0LabT4kwmr z)uv--^;s8#C?IkP?mpci!VVJ$D$S6+^_7|{wBfQ1gp7WTKvxRqcXchs(awEY=-QR0 zlETMQ$b?pPLL^|Yq=fGMPkp6(WOw`YTy`Tj<%Q`)=xrIMfsg3Q+c1tZ?gwn-emV`B zyrQl7-U`-i0TEwOo=u|*yc}c?>gW#$!Iahm3Rim&`53N^^AhB*%c*U=0gd@TZh8_L zkWdzD&Jl?#EG9O=ok`9)@0^T(Na>7mPR$vy0!r`@vOyF@kymyAE&Gq|z#s3>s@34u zB%4)Kvm>(>I3)(}sZmEf`{4R<(x9s)O3?Y0wL3Fju~I3ej=H2Zgu9q}iYOce_iXn) zTJl7$ETt6l<#ydARP;X4hAzGF{fO#8=AAOP$=Z7?ax2FiKyS}-8z4)&w&U1!9PjJUP1MSm5N^-`$ZQ*$JPlng%)QTtbLV! zy?JR`D3Pnk1dS4Q4c{1U{;Xhe-=2WQG)t390VxUcED(Y~@)P?w;aGe0C8BqASxpKx zDmI~SyxtGcqav?XYU%vKVFb!Sg&{a$8UFxC$({@TJGbAf>qTP4>Ota~lw`>)fujl$ z%C<@ZGP{&ukMWMN%RVpgyxusM!ge)ElWUYCipx_=5w+;i#zyEE?koqW3=^~xI?wAH z74F3nmfs0ht!B%4%|CWC5O^5}0DF7qqaehldul|M2LeY<$*gc8@YPu5nky5{9E}`c zvMG(*B(~nn2X5Uho}6thDzKMHOod`~&d|GZO1HV`zKj0=F{sR4tZDJjYj2bpM#GE- zV!6hBmyWH5yp?sjCKQ~&levxOOf~@hK>o^c+W=(sU_nrs5UMIsd2MbB2hWDP7J_+j zrAWhX9mzepC!Tw8)%2>?u~x*=u?l#JB_ZAux7CItCvV^1q2z-|o(SiyB=DDT9pHq# zsN;mjwcvboZrN3TpnTAgb* zDoTb^3~9bpeBjBr@E7jB{@pOKK+k=yBUe(1<;M1A+JNIbU00Au_s$2nJtLOI$#iJa zB7CY-2axHr4=qZ`h{BKG$EfE3k8ZN6umsdZj}%2-DGPajL`uUYpB>3Oe{O_wsPK_I zVogdYX0kNhHRMGPFB1mOC=;__b|;VT(38asHzchVHAssCDntJO(Gf(AgBZyNdGC?N zJ-U+IT8^84O?$M%b<(Ek89Y|Rugz_VYIaEkk=X||8v_`p1H zaoBVRgyw+?*y6Hl#;);vqsn65`3(s^r4ldnODFK=m8jFy^!;y4{%@n| zA^!kQ{8?E}(yH4O;adm4Z^un(JTY08%%3eCW)VpwaAAr^*s|c|h&{(l5^3>L zr1mv9JEiqK;xpkQ8yANoE|L*~cAduNwRZ@K22OKb{(P zq2ON-M1patcz&uyJCH_YoE(Q%#&`jUC#;5xshOsJAABz*{!v!Sv8`c=<%fgjw|z0@ z-AhtWIE-c}mIya2oNWk0cTjl^j*f~+w5XtZHaEosv_=@~vmyum#5Qy9!OwoMe}{e@ z@s^d~ixj+VtwZ9Pv~KyDMxmxxmL{DGh8|+dcf>J~f=_O?9P`a$)Vhnqa=SgFByq|*Zqj)PO?ae^{WOxi_M(t8*>wS(BOH2Af-mP_a}~e zu(df>y-RI8HWFrvO5yy(nNO)yFS3F8&*!U8IaXVe)rq3J4XIM3QnIaT%sj&&;3yrj zkKQ=^bPc(syopv?ff5-5v=KlSW#=JN*+}==4t@HzF#z!ebe7ccxo2pF2uzTaRU9D$ z01S-e9*dq`+BJDJ_hIBpt`O!+5V_%$V+TIuW4BRBgfwu;Y}5H#P*kbr?~*yBz%jR{ ze(ZJ~$nT$V)wOKvk?V8CDRi246GIS*nM$GB8+JZ|IVAi2x?{3UL2S{0*s8WAAFVlD zVTR^-m){4v9CXJ{iiVn7QWMygMMhZATP*~upQU-pQab=fJ^C%BNho2Zz#*|6=xd!Z ztQBbdgETf+^CHX}AcpRtff?u2V>ZMy7a>=y6Y-$g`_2TpmWZ+?lII4oL2Ub8(h5e~2c<){tHNPDh5iu1|m zp`k{4O%!Y`QWGq<*FqU9$vxDk8#tD>^@Up@R58l45uX0!lI>i^7{gKIidR+atDN)i>h|cgxh(A?$h0*pvRM*I zUhG&X2*ycbc-igm)FKovl{-AYB+$FV0!F5~rAc$f3> z3iaNxJE|uC06Jy2w6ixQcVmL>={#V4$5XHuu#HG*NhN~5 zuRxK;;y`Q$UO?a+anl21E6M6wGcWGwU9sC=NYAM3e*XZGo%uh^mbH@^k?TmyQZi4X z7ayog581nsw{J^e7Bel!5sLc@#~U54MsRuWk>3RJJ7cFZ!CaUc!93I^%dXd7i5Y&Y9rMS~c9OArj zJbPqTDY;f6FkM3OWX65C>Y=YZwwfyzOQ?mTLj+!EKt}DTJ7k`D&sJV{HB(TBPlC>+ zG|H74J0!ZG^%hq=fsfib{{U_}nxt2!vjnh47RxfU5XZS63&S%GKsff#Rtzdu#SOa} zUY&YKjU=tITYgk3IRt_|IKeqN@1C;?T3MxIPuBGtWg%CRvyG~t2K6jp9CAkh{rdAy zr4@fV_1`AIiY8d_{<7rpv<#`|`n|fINglTwO zFphE-Kdi|&n_qaGPoE;acb9xpgU;n2k=(G!!RMrMBvoUpMj4=nx12Uxe92dMT$N*= zT90BgkH1-Nu|gKn;PH}8^OMq8qkoh`Wg?r(tt0?6TTxdS zRgOQ}NA4ixbx6U43=`Hm&E%BFVP;`~@97x!Q=Sz25!LZc1Xp2-yk_i91hvY=zBtiO z1g>#_alz*UzgO3(kL`|{8b!6b{{Zt* z>I;mqfR9T1E0TR!_CDP}U?Nt)wX}*V;UPY3W+1LGqCj~r8@VI5_Z@iBwa69%(wC0X zb0aK-^N?fq&)l~ss)~7Uk2?OG8^{Y0l0Y4&aNCRRB%Q%={yLJRDIbMRlBq0faI*jg z`J-Qc-lNo!*;rFovvymS(ZW}%jpjo%6D~xuA5??x2e|0!+It1A)nPDBQDmwM6|WIL zydgYp{*p)^Zj;sWs?DeDM2)sQ_G6A9RY7caKYwCB$4=+7WLXf(@rMCK!AWh6`?Jq> z_QzHLlxiD7wxbKyyQK*rNAirO(?>7NgXSXbTn*mmj1k|ef@sczQDJAAbS)*BL|YnG zamii3NkhRNS>Sg!8kTvr7=&tgt; zdmJ47yY-IgMrG3|Je5`Fmav4CZO+k-LZ`p1^2gZs&rQ76`5OY1ve47ut`#a6gCYgT zukP5#vClm~B?(2`mF(!XfXAT!2a?N2R_{)YySW_sYvf>z*+OZaR{zG zvF<(kHpE6su#vu<7GThpak#GBu~Il0J;pu9ZicaCo_T>uYg6)}!SVo}Hta!MWApvG zol{sKA;FTFX>6dFSdra?k`Pe2#^%mI-}gBqrXEYy(_qEPXH@~{w3b5@K-gu@GFKkQ zrT1z1`c2yDb_h~Q2c2afaGEkVVL{2~vuEk*_@b>eF@GkL9yP z8<5jOhDIHk3mhmO`3FAO=#_vOBa7 zxf(p~PcM&83Ct1vIz;0UbiHfNGmw`)%huQMwEkXImr z>Gf}9`c-?3?&=SMp8;)By+_4ur&q6daGR-F^l5 zHQ_%1&8JKQ>zdUnVx4_X?Px>87dYAFs)({Mq>OF~2U~U>@Y7kFbHtH3nOVy|d+j5f zpZz-w4mu+6*87X+_TC=5)i1^Nw%~SUl*i?7ss5w%>Y!LLYhue2#H>|z5+y^Nfs>pJ z5B{b)B1>Q-an0zMlbX>VFt7xHkM_Yi$OHWJC3)7yomyseou-tk>|7Fr@`!lcp#JZ- z`RLV;5@I!sOfV*Qz?D>!hRFMY@BaDgF+JDRn$Xb$g(YZakI2lXRou-n+(U21G2iL@ ze{P44#j~Z?4h@S2*2xHrXKv%kAGZVV_Wbn9P~L35Vyy5o@g6zjzXyZV3l!U@-2P-? zfj|Zuw<<{bzZw4keDo7JDUs1dAev0W9OPM74zDJ5;GeMI{xW zx`o;lv2w28xtHt)I}y}WBAPj49%x|kv&g8yl2UQ{pps9k*k_J=^(8a_nj~ytjwxKT z4rD8k4sv>_9pnufF^a%Y!*YXwbN+Ge0sjDgda+h1R!1STZ?6# z72>r?mS|Z$ETrHM!ux0ax&o{mqWrkJm3S2_8n5SD#ijb1GQLTRd6UHOuKTUJ>90ntU`2PTL+pCdEDUDZZr~ykhbJS5&FQ*DPVt0^m zdv_T3?bemF?*9PAu~?RMfhdHUV5Ot;hzzmk*lhI?j`-)Ew)82v5!zpAuc4LA&^_s31 zB~t_BbRoc;6v0NIYS$p;J5xs0h#Ys7=y2dC1fr0CS> z>GfdJ^y%>{GLzyJ{{V+R0nmI0;maE2y0)V&d7c`tH1Nn# zOehH=ICq`E%_|Ln92}hW+De&_vxY~>^t6SPjPb`{cn5*UR}^HV%9A$cCk{^H2|u4< z)q|DI)NC23*i^G~i(2s*<~+YerhFmrhr+4wL%{kMjQk&?YxlG*JjW2!sKabik=1DD12)wEJdJqR<0CZ1sQu5`6$dU$0K?onnp17HZZP%bGb8 zD#}jW5&7&7{{U02PJiJC!&ZEEKBIfY+MK#fmKt`_*UR!`W1p*XoNW|>k_kI0>^K^1HO0|>nq3%26^k;1{7Sn85 zTF}_kt)wd~t&$N-5tD#V_8kc%oUXMxcGh$QSOXZ*=m1%4a-^ZvGF2F(76fuXzkl!7 z5Bwyv7Nh?F!~^0=*Mv=04ME2i9J`6{?T>xG@rUC+i{UQ>T%)Aw zj@cN;@VW51&x3v*YW^(OYFw-0PZ3*brh`#9 znkW(6Lad#T;hDJhVf}`dw6Uef3+0;C#SM2}v(v1|f3SF~QNtmjyaITVPanZuNi`}~ zH9D5(rwsP%?iJ>EgFHKc-L;6yea6uYVnLDaUfM+egNQfU>$gVj{RA2cPpD=q-mO7@4?Y)3%MX<`kqSkXPl6E;~ibq zbzK7PEkW^%!d^4+m%_EvybaKAR{lV(eP&*)G;$oxVVjn9takP;uL??8#w~k%D+X?mx#~f){p9e);z4 zt#NM)#A{v^(lzSrt$G|wZ~$=t`hm*Re+~Wycn{%~Y(xx~0%n(61bgC}BHBqXY#}&NG~n4+oF&(OpJMdBH-0q#T^~JY)X= zfAQ2&c>DGbFK+F_zielp_r`jcs_MFmB>G;9r0B6v9+juTr=;^V(<~7L4(xJRf$mRD zNXR23AGqt@-OfL^L%}q5Ynfus-NjDjAcCZ+7(ZeUSLT7OYeY0aL=r|Y3x96BR#xRs z?nub{jt^J$T~amYJb&k}2+ELq5$(rUbzMal5By>H&*Lu*fAI(K2ZX#gZKLqMm7?9$ zyj7-Ejv4G~kr+cpijB$@WnGL4l39lRl;)8eN_ymczXn`4e73aSSH06KeK7%|HEefNg-Jy%sPyt)4X=>vnsFfvPG0Vjs@ zAagwv4x&I-B@E2O3>Iu;{!TdR^Sdj80M9uc`uCmRj*z~fz3aj=)dP{x^Un=xQrNRH zSFaKml35%oqJff0JOBs3QB=Z|9&wNNJ$Sr1=Q-#5b&To$FYw;2tFE7?>ol#~VIfGP zvaHS{Ay}$|k^wj;{{XAg%YQfgxxP!u7IHTE`Pq!~oO9bf83b~()2&LgOQ|?G3}DVt z{Z~-OyjG9S+9ldI?D})>jQeM+*fGW%9OUubeYypuU)6Lp?*V9{&J;exiy_tE%d{iYn^5@PJf<$US@1 zQCC&fbzMajbzNExbCHgH{rbD8qOPl|>bi<5>bkD0sG{)p?~bA&zF|mj)4>IH`~CC( z0NLNEy7L|L$UeuYqW7;c$^8C$qnvTqy+s#*W2+9;4DE#gdYJu(=c|~IG6v(G-B2Nv zjAVA_->9PWXWyQ^>Kr6;7RKG|GJfaV{{X4}I-97X@aG(N>%pCacPAX0J64xg#|Y&F$Wks@J?6((O~(JlA&F24hZM& z0nh&cVCYvnWmXL98D8g=j~tRteaBS;$1HLAQi(SYF;{RUk+|G>U zA1?(mtadmAhHT>)AMelm^=XaM%0+17u35~h9AsxXzyux+PD$=a_UZ(7GZ|U~4W|VP zyqN$4>FjVaIl%t_+oD^{SlAEKfqtfMsFHGV?eC2BQ4kb}f%o^>TUgCK*8T@#@F!!T$irKW@F71)fiKK}rJzxL`_4rORsUovIGFasNMKHvLf^n2U^ zO!kfdj-RrG%@md8o6Kk$Hbq4dd7{XOC7HfB&%;ut!7n$Y_w`wE13Y?i@Tl6 zgY0rL4*Z2?5y$7hnIU3#AR&8_20p-JpL}&3<8w&9iI9?BG6qP-Fh4oyskpJy3g_J0 zQoOc(wNWj2Ao?6G2KZm8Sn)sbgX7PG@oBSH@g9*#*MTM5yiDp?vxX#r9Q(#d0DuS` zY9HXHo|WS7k3KW_izIPtcl78+kEYyKRr&I%u=#DBtaidnAHXAw_4Mmb(X?usuB)o) z`aYdn{-ajC%Vg~e8c6^IoCV|9bsvX(7vVn&!D1f_czaLKs@S#jHejV$Vox+E z0o6djAOJYP1GidVS)|Dy^1f)#1yZM8)#j{=d;uLg0yxGa_e`XtR?d>zZG!gby?-f@ z-dQ&& zdiwg(yTi2y%UO4Ds`zYU+~DIF=LhaO!+cNSPYrml!&-gaQ%SGlSgXIxK{TLwk*gf} zk+B`na-i^W_s2_PfROGF-=gpMtHaFk4wh}&cGMq~_C9_^e2DNpZxd<0Ct7|Guc+Gb zAg3f#(yi!L^9d@hM|9zGGN-Pw_(%LQYDwZ~JX`TkSY2zxH`#SJn@?uUQZz*sW!|T9 zfLI3r0!Lxi%=kI{J74%`@wdjh?y2G!yhl?~v*&37#O7-&oS)aqfLL-vDeQ5{89hcL zSSwdp>`gmYW-Lc9DH+OsK+blLu*Yt+)TqY5VU_Yv2LAwt=E<(9tNX+{LucK`UyA3? zi$4Lp7vq^cF>hF_8r;(2j+AmiP9}GO*)kcQB%&4E2i%@m=EsLwLXTHOH@F-e3kF8=_T z91!G=KnK|O$3h-90_FNL+fK5zbE?x|YmYI4S3dk*{vZ55@o7_7)t+rP#7iw@vt=!9 zD-=!Zu8b75zwyf#r`Fa;ZKhtg2tsi%}qty3>4Ch6op(O0B_Ces0~YF~^zb&Ijw zAdF!7WZ{PIS3PzvoQ}Flvo%=YnXtx18y;0$g$)m!_I{x{kA5}QHOMvZ5KVHQ^JtZCShqC^FZprfePl#Y<@4%efW&7R=dI1B{{Rg7 zOg z@8YL>@1@6TI{;wOkaIs82T z01o2rmErSNrrS)UjcY;$G#h_S6_uLP^&-9Rgx9OmYJV&rcQAfZeIj$BN!OLNCXTn#XkyZ zHZ;7ZX;}m>5yaqSB&@G5&r-VKMSDon_7oS zkLD(l886thND|>rRw%{*k+Z{rk&bsBvyTt_DeyOj?rM6jo#8z{OSwDOmfUgFh?!$o zAdmK51v=4&%EtDT1(1MP0LnX@^V_ff2>dCh@W0{3ijm7WyQx}?-HvQJPr zgX-?eIUIGqHGeM5LMSzBULUFFw9PzG#zACY%8aZEyllBFalpXHJoON{8|cd|$VgaA zOfB_lTxGp`XTLLhW}e?u_t9M) zE#y_?XzMMjG+vsqjx+pC;_I(G1;KM3X>f`|YVHIh3uu+`Vu>MoMoCFC@j!j>d_PfI z^738>(uPHgjoq>JXahE0CAd6kVE`ENu<@ly6{g*SeuAn{#Z=Q61+_-g>^qawqP)oF zujNG0bL5vejDTgMX02^PG~w8}Tx-pTUp{nas2=@<^T!B{9(4uL9Z>E*68+)|Hbd%> z>1gg&!^r&Ek=_7&zo#HZT$U|yv1yfz+wg``*_PCZ_DFSJ)NQ+rV6)%vf9vn0oErvd zFVr38Li4>0awkPyRxixvIi)HHSyL;l(jT&uzRw>+o482sO74!!4tdJ*1);T1y$Y93 zGvK(*lcQrjEgVerJ&(T(N(16oS)wIS^!Jf>i9d{92d2!ouoKYJ7+SDfKVVe>5Sn%&6YKa||3o-c2Z zJ>AvP>pXr-8`OjmrRg8^lHgbXbK+h0T}Ro!UtIq}QRZP1b}&kx_MLF0gTe)Qv7b>J zA9q7y6}4VidKut5yG!5BI34VzD%~`bYxJQe08EX^o_s8^TvU1?EDM_$mr#`=1-)c!FJ!U@7&~3s zzN0>q(LlYM*EyGrds1C}DW@UUbs~GWGT@xT+mgax$j`>m<{sMb`%k|7oZ(z=D@I$h z;Vi}I{PjW2kSaBKsA;or&RHUd-6Bch*J#bO=KVgC_-z~{DKV7LLGMXkSybX(ro;Xs z2Uwx{%`%PGG;&qeMcDZYYNt238A9FYlhNT>Paq99$MHS-UvoP(vH& zfTS^EP%IPFq_p+X*j1F||Al}u$`YK2XLg_F8M__z7m(f#Z9KQ9QMZ4EnPJNEEv&@U zID|3Mx|3;y8<_&|$}r>=0Kij3RvuBUhKHjoK5Jtg*q8OGoCpOi@hCGl|<4;Iri@>XXy7YWGjv}ILy{CjWCo&ZZ%%IA6+FWUQ-H4idIZ*v8?OzeCWtdj(>eXf}?Bn83!Z{KT{>)z1CX=5}nVqOm(!kX4Zq56xeH03Iox2pdttQ$m>=_;0v;>r*dwWR8&{)?-{2T zB~4nIKxu33?lkz(;-uR`$_RTQMs0Xi z`^inRGqCYtMwR0cREkD5r!ZFj@^J@qWUL!s;Qgy7>G>8%v$NU`N0lH=k4rb9%*N(` zjEvwWngl($bxI8p`hwIjQlqUw0JajGt0I||A(S_ zIqmVw%YUnXli<9!@7rN0*V$%9(1&@asaJ;zjf$>lya7&}YEh#a5Q^h9fCVki9od;x zKh@%dz!gE3qa>&9yBVe(o%gQ{CJ27Abg_p>;a2^HSOzu)~^Lja6_CK1j-BAtv_4M z0zC!W>a8LPg0G9ktapo4 zY*xg++5L`2M$wO`y#~3@o}(Gexo(sP+G~BSBO3{HY2E|rKi5n=_doi;hD?oGroWK& zeJ)93s(uUHJj~AqwtB!RkX1f_pT?JbGxCq(qpsyT67Fcl)%!U494l%F_f^Z?Z^?}Agk1$%$#ErAF-ani)iNt z7I;9L%?9ccj54FD?(}!AB{9tk2eW(}tg>_Cv8pC}9W}(EkCt&Xdv6Lt*YUeNNYtu# zTqLHh8wd^x@0a7V_GYJlih!a|;eZ)ahg{$MZvll9;zIbj=hgB8UJ=nI2Tmih+T8k!TtOVo(`N}H8R&C&0F|Sc{Zkozl1sdU1Cq)xK+5A znQPD>){4GXDdcfD-2JF#hw*=EMse9RrG>XqM___&FPU(%ob})1O`V`YOptf+*b1cU z8mc%s8U+Gi^>9?bFw1qQHFBm)BpyNbhF=ebC2i$x)Ebmv-PB{K^Xx2(+iky3>SbKG`VZw#R#kw$cV)@K z8_|0hQrG~rpFT>midfosdF@kOefDKUr(oh+@#=!F(eTd-)@HK`poE-4^pgjkF4>rQ90o)CIHmFKj|w zKFZh`((Ech=)O${r3#xapDsDcI{s;~G5ZppG6#%_ut(+V^$P{qVnROsClS`Qm7z%LOwP9lnCEb#&bpz(WaOqwup89vh~8XF;(n1+tgImb zP{(OX!7SE*9%vm`1-%K%T`r)j+O7eyu<F-O_17Bz${BGa_t02v$u?c+XA?ypKAcz;s{eSczte+zd&2-Ka@IGTUXoul>;~nVALw<(R(D0 zh-2RVg|2xPZHncs$Wwb>_Kv5}xeI0Ona03{$z_Ej&%gSiJ;hk4)^H{cjQiC?g5M|& z0@})QHi4%i*{?D5Bh7C@e?RTt3FF7w6+Ym5%Nmi7<_H?vmcnyG%OqN=I}3F+k!!HV z3v+=zbK^I;N}NU3TjhNbGw1#Ewc6t|M<-Fbv&!vfa#_NHH^&cifsE`nTjKv>+`leV}4bm$B~#-;px14Z$AbpS2@$z=AXR5)Kx01TyR>ZIGH?+ou3Fx zk@K&@@iz4LuVQuUFd%f5T^`O*g0(iZR#95T7Bh`p{;ED6@fiICL);JTG!_a9Q{{)# ze8(D51kmABnS_YQz3xXK z?!LeJ{gFnS=|FS3n<^q{a-8J;tvscfpgmCleQvyVqac=eukt?&q>W#{Co=v;56<+OGM2<(_5V- z#d%z79Sn(>ky)wL0$4crc!6%5F=G68Ig=ExQ_5o7B%Wome+m}=zOdgQRE5pBmPJs@ zb!CeQRf61L8kjj)Mvqlu?oTZc^Z%|kjC7#b zyMZurJ7xtR3>gJsG*ry34&)sy)v%1bL_MZNTxV19qOykFfITAp5IriTL;OlU5aPRe z@Ry$zM4=nbqk1cS%d&or7nrR0p^Z!`eSn>xcQ`Hd%V=GO@G&J?lJ_jp=SXRG(XmjR zwAJ#mE}@K=1}~=oWTR@=P~2|)3Z`TOT?lpNrnF9*Ttraf5}0q_0+*9~(##gH-=vPh z90p=9QM$9ufqu2o;ck`MwmnF0&l<^lnIdvWU_~xYpD> zWY}F=_(?dkOtNrJs#F@gpVi_){8)@}d6Y0oz67t}5$uqE%EN|Yzu3sXO_B#~fHOiA07%xr}$xQ%I zPDjtpkE1A^i=qgU_1z_i`3NN?xk`JvKLm2>a>$#Hp;LYOKAxdL(uw&DP7@3R6*l~x zB?Yc0^nLQ4Qg>`rYAsMcZlkp#I>f8@#ashpnJ4iUicCx~HuL_#3h;CJ4@C`v=0766 zu}l~GOy;R4Iw@}|Y^s>btt5+yDnC<>ayvtX=RbG7&6Y!(}@3Tc_{ zE@sE>zU1jF?4b6k@?9cE^CY3N-5A7Viy-D99_=_O$f_u}R(~FGKSr-$m<#?(`7PZ| z!UFRE6hw11wcjZ%!bT&wnZI1xB=)g0l^tEWzUsX*^0oIL%3jlK27mhsPJfg3xL|)? zBaGLY`HPnB<^~o*rs~D|4W{xF!NoAGn zKGISU^bR-Nl`x550eH*jd+3%{CY19>Y|52h&Tevza??}g@m0YPlFCqN#8>SS`7lE& zRa?mKl8HA&*^f>fG97RrCu7d6wLq+B-`-=*tI_KZ=+o?{VRhcdeTI6R{=DH_swi(z8MQ2Al@*48n2P-h@&l^t? z8AOsj+nXrYudhsmL;xNrRAt7Lk9*$LWO0t6l?KVm>{U-u+$M!QpLxva|DbTORfKhp z0OPH)2dDNvr!S}vtf#C?x+zSNMj1%h=hm`C-aAjl?dj2!pg>H+D4(t!m4?*HKVNWR zZxk$e2Hr_Tw4I(vKg6z8hgW>={h?H{!1jdXTekh7__=HWa{h$Wn~HGsgGT}zcA|Yq z(ET`m$Y2}JDdp#W$eG^s2L{XAPb@eTf@M%aC#(1ZsGwSWk2V;BUgM{vj zAN=#N_>7l81}N6Rj$g>M)T56%MCu!cQ&V%sUhI_+NNZe$j$NaA0+@ny*L=~+o-dZK z{|PrmH+s=2vyqx=yQbb~I?`~BxX+p@$y!ayzS@>jd?iBa>-@44{p2k>#HVOE zI9@E~TIZOc6tSWm5$?Zg+~xOo!ko1zhvR#jZS#`;K0w!zqruv;r;R=72yTuATrY^! z^!?LdGI{XY-^}v6ptIgbECpmo)_~`<|8G^bV|V=+d&0>je_B5Hw!7qS4j)v9Ko0}^ z25eZa!ubN~)xv7viy-82fjTE0p%-wkr+ECNN4lMp$a_Y@Z70d9e*l|A36l;Lsg-CN zB#~iip)(N6j!?dO%uk0ER;@c$xA$yJ1XY*X-Yp1&D~D?FeN!=2<@~1DKy4sp)NYkY zjG7eYnm54*S5ndaW1kbesEs0PDzMl16_-!Q?OBxmGa^pEhzgp6XRvCMf8=Jc_X$Ji zdA7+4r|=>q?!crYs-Htz=qYbr^rOKqZdc97TIk(rq1PJVU5BlGXd&mgoTTm$%);|odhyCkaxw`cF<*4& z!y_U-2JPkJlZlu9P|;R}08plj0IgF~q2c$kb-)@=)V29VKcUpY=hUUj>L0SoO`N{y z)t6pMVMeG;zBitzYsV3A?H~5M8hXa4+XYs826ePUlxR8JV%FztX^SYjqeq`|zR7L* zmg*JdWf$kyTV5sMRfV0N^db$yMfI5+wz)NOij%YcVEu-8HE##GASsPRR6iW^shWoG zgFHE6a{}bA-;sz=(ph5PvXouqEDdX8&HZ4`21W{wThT=KA4wyG4}VsF7iYwjj~gi) zO%-*y_;cDqfRqUq)HKfxIW`ln+?Th2ye9t+=%L_Kn%VCdKPUpI8WPFLKc`b#t=5l# zB>y(H{{Ft)KVvcCvG{W#!+XdwD!6g1!(1+k7hP|yJ6hNV@9J`Nzf4J&0gX`&RP()- zM#6S4Z}LrnJ4Ks~$>tE4sSD!bC{z}J`&RG0;P_yvi>^y4qRrD6D)xAtddR=4G@M43 zYfwsnZh@KhO0ii~^qJmz7kBsCQZMpbI&OvmW?YrhAFEES{W+Tb>o*14*N$zZJzsMW z9`C+Tw`+=jU?fTvX4GiH-+q2*#VU%vg_s;$U5h``qYwqCvfWCbz63IBQ_C!Ini=kX zuFK){RnBX2rwEFAHi>ONNYaeIX0JE>@sBt80&Ju4e$;1`LAB6hBc-qYFqjags5?bB zY~rH#e#eu%MJUHuXR$g!u&DlZ#VVV4KPbM##~B^PD+;D4hpfI+;ePH#pQwBHZQ-5c zLusWJ25R*^4;`n7@b*|olW_gtP28nVf$u^Qd1HezYh zKmzpw(!%X%F6Te#wNA^mbpP@uifGRO{u90hblJ5jw}4=h zwfT*yDbwbtWUDujk&Pqx)9ey~!Dzz-ApUJ&M3)8jOevxu6KnPPZ5{utyeXvz+O)Dr zYKSm+CG6y{?)2N*ilqb*-04h8Yo%e$ir1fl(Ji++G`2(zk(|{pm7p)0J|xzh3Thom zF%ukg2k=K9Gd8L5rZhd_C77OHI~XS|YYYe?8nfgp3~i~ri`}+<0oFV*s~OLnn-uh^;KCI;Df{}tNHYfdVR;?1 zF>OOER8$m#7H{Pn;C;%rs*vo5<3eXG0!o8Ey6c}VmEKjK8xPT8Kk?cy&NuSZZBM?q;Qc@xYq!pBA0Q> zwwc_rSG?bGimBN0OA_zS|BRipKq+u7ht3}W;~^(7Sh=-LXH^Mg?;Mb60-099#ijdt zgE*f3Rn4TL8Ey1~@+l*!e}=~DCOoY4abNOy9xIwnzub89+dZukjuU{F{LTAH4fUZM zt2h^?8}lsi^y1OmsGCE>B(4i0xT*4@bCa6Mr+}mi3Y?yhiIDTO*++5{=ebI@rb-v= z4{Zm$lNcwmR^}*#BFNEk75^-RTNJ;GmcKV?&u=kDinUnzOrcs+Ir?V9QT(6_UQz8) zJXqDAo7LGb|AhGiYKyO?f^vi3jPZka)7~zn2_4(e@L?R!xR%3e{`q;s;1x#$<(Hhk zgA_ZFZN1=>uo(ltC<)NtP^P<(>N{xqk23$zPYr_KA2OEb?8_{bhxI|MAY4Jgm%v|0 zZzg0XuAyqps26~ochtbPX~6j^=Zq{1XHsGwpn-uwg0bpv1y=tQjJWwoy;`rIPiQj8 zOq8;P07_EFu31MgUo?PtvnsD6uxdzk*Q59N3VDQh)`vX64e)Bpn|~0kyZy7l;)I99 z!xj)OMiK6VJ+F8pZv@*a+=}&@4sJZH7-I+w5u7lr6bLycb;l zHbC`!-Y{`ANCpguqd)l_RAvLD9fuPGncW1+iK^*U)30#}G{UCwMM)tf(`O&=A?#xJ zgr-u`{o+{~4NoB{n!~hj)#{u+jT7(rw)s-~T>X$s#VRIVW4CjcsHX_ly3+fKBnk5w z)p7;uT0!k{|14XmCQ;m0jvozB((hiSr>3m7bbnUmp>k30Uu2A_aXz3qw$4J0@#x0o z0Yq7~-TzzmewGO`@>va46C*jXW%YxnEmv4d-SOHLm z;~_Z+;zu#t=DN)ZIoQ5L7QSq(k^j@uG!2ih+1+m8T8$N!L$vp+9y8LaE&Zwf9}kU^ zTb52O51@Md^-td`>Z>@qop&T0d~2K$i-k6zm!FCr3$qUH22g3C$?wBFaAjh&&w!On z*lv*de<%elg+m(2J`$|KCQIEcLNUu`u<=5ierqC#e>G2r>061s@S0MXJHFS_QIS9b z7Ws2bU7(?LQrlR(njc^Vi@xGz=vz{}a#5wxM%Ekk33n}mj7vRl>n5+6s!KARS6Hpd zBLZ|+i(N@DuRBCFrB$YIo9>3PeJh+)(Oz#QzvFq+;1=+(pF;Q)vJg!2Cop)^b*h%pUJ9$5Lv?WeDlupd4<2Wu)?n z_5fx|@Kw)tB&NJtZ<$s@>HH~vVq{App8D34*%QPUQ%FEqTw7VmrO_qr-w!j=ypNi193xr1D9^SHBZBR8ZQczV&C3lS!n+G;g1Z(VG4`ewexD&+PQW@VNz#`uPpnC>rN ziwwYBmk+J)?cZUM<*t^vSfJogpob7;?q5vZ3By%bvfQSXI`h1Si$$oK3}q!N%ttGi z%XevW?Hj2Bqy23Xkh6F%pDKzq`M+ng!a>NkDn^K00j8Q^ND0AfdC`Riu$tz-F*X^e zm&5=E>YG)Ln9n0_B&uyKU8&4Zz!X!cW(>U!;3AboF5< zkylRGsBIM^xItc#Qt0HTFHhG-Nwf233m%*b3YSmWB{5pb;a-`NR}*3SeZ7H%xwt#z z)cacYhCdy-d*y->NAATzF4Izg38W%Lg<4vx<&HVLI-akQ4b>mS5;rEi%yZIB7mO6Y zto_!3t+%pM0_MkK=NcY7HTxfU``Uy4LxFam(-xIEcp07xwq5XFjTUW$F0Pb7DTs6) zJ~RMgP^Tf_hPAJI;=+P<(SO$BdHlcD>h(AP3k+e5=kYwz@sJ1K0*J`|leemECw6hI zMRH8)j3u*%7Kh-H?xU-uIsq6of4aDIMd9N@es)jIMRT50&PbQ#DS|@qf&L}vg+S40 z@oIye@RlV()ZI9j&3VOx^uud$Y>;Go9vPbO45El;utYCUeFytUOLb|pr}JFge(efD zN?Tlhn8fFKB!;M1DT#avd~T_>+?tf9ao^CIZJ^W9!bM2hn$~s&>KY2pWoS`QO~!q1 zQo&VS($Wk%w*mEZ_B=2v9h|K4wiMwdcBZi|t+Dc=*8QX9wnK*}d4($L#Z~OSlTT zw5xzov-Lu*(n6yOmYj~dGNFRTGSBU9r0_wH{9IoKQ$o|WflKS3`r&(Hf1bU@qBeI8 zUmCVUl#)19EGh=|!hEqz_Zu9k-t3tFP?W8$J;g4<)+$Ri`0l-(a>@d-yLcOHrNBH* zc86$5&z<^K`tud~`9}t2r3(?+>&fN!_9Q4LIPKfV6bSL___pEG*o9MYPPdtsUM3I} zMt>~$Qy78tS9-K-Q^O5bediORFtYr^F{1Yy`KWa!Krzr!?StHG_zVi9=CxIar*No7 zurHFE#?!$`$HKJQq=7pnc9Lv?m=tfShojsGU+tIr_|yswO8{nDTtu%0jqw-%O`s=Q zc99C(tYcp+@8Z&Jq|L_b4eNzkLRfehqoG`r2N)-NE1p=Gh3|#IsOVhIb;{MU%iGdB zfz6ppN&2~t9M+)Hl_+8wL5dxXniGVZTd=qGfFAWf^h~DwPil-RuUtryF36@uZUFL* zhWqvNI1LV~2Fr^_0X8=H`mY!Aph!?CCGGxJ5$Iea+V!IaGL`tyW+6BPwg}`(<>lZb z#sTELQ|E(gGPg{z1AP=@Qh0L?8l-yV7WZ2PC7J*7%7dY7Sk9F9t z+itf*Qj9wT>>^c&Wa+I1(LH+P9~ksjQFmS73m)q}F7$bv&2_ck?N)?EMKlKi$IM?U zKwA9Oz(3+HDM^H-sm2ofV77w(F0hN(9&FFL{zWz}xNY?6@ObjOX6y?YXwAtz`o1xObKbVRGStl4yCd>QI%!c z8#P)$0ze`kswUskzXUpkoV+m>;LtW%KP*Es4PhA zLVtj3gYCeSDkRaCS{O#P3*z1LO*+1Q)n}-glIoQp;nDMm(XkP>9-5^g(Xkt-w?Lj2gg9w7=?6mU5XlIE)s$w z!80ew1Fv=9N(`%^>eMO=)HFTbPh}tSm~>y#qZkRo>qSsQZV&dn%f30y%|qu*%C)4N z3@@I2C&R7teBt!8l3T_9bYIkVMx(p-bqiKo559}G>J-XZ@+5tt-P$j5oDIAfGEKz5 zsFaS?huIH+Y=X`U5SZt)K6)mLWHFf>{AC@Mthlvg<-9w^m*87enAG+wFkD(2ay$BN z&fjH<;X|+Ksj>$Rj3kc?koB}*jF{cOXDI_-Cd>1x&OUzEcn{@PngNK`=`7hr z9=GpYFydil=PC2RCReT>{1KRbeQhd0_KCCddH!@`nYzFLcJxZ@^=dxlIYg6-`2G>L z@L!xviO}6-c~A`2Z!XT`cMI#GwMY0Tm}t-jEVP)oO6wC=+J0In)a&iKJ>! zf3PIq!a=yp#~X~lZO41;6WKpsa76K}DdVp{@Kmu)EhiNiUj&^vV2h-Eq=_uOD50T^ zFMcQQqyZha(tl{G^Nps1g*t{E~~HetS}~UQpB>39(H0G0HiBZt6V6l}h%OLb@Yl$STPi zbrc+6I&mm4IoK0#-keZNO2nN7PGl9C)&SuPUP7B(S+{{&*vys0PnU27NOsMDOdQSr zLhO1(-lNA_K@%5occ5<}jnR6eS!<>OV>L?_r5$aKZtvYmxiFYOUkzyqT`lkzGv9;) zlkii#?HUY9ksr~%|1v)}ar@pea3K?K9*E8OX)=LSYG%S5pEnfdk(t_Fc{)@5oXFcPp62`x|1psbt(%1#5nU+_T(MuH)nr3NV`d)eSK>KPV^dILVY$TA7{GEhv_aX#O)ViTTaZH|(PM%E-=t$b>b3&# z@~mi?H>+ZyH`?RKJQZ^3!HPo2^f3r`+jB$5y`tKEm^pXX(YnKSK^CUSnk0sM4sX-s zePw6rzoto*&K1~cx#4eBKhuSUS=}dsx$GJGEK$PQa9F(1#8af_n_+7y)W~yn!Vo;Vw|sECMqa8vbM@f07%)HkaBZyLApd*@9Ml zqE9W#mgeVKiCM^CfrPJraLtu0w|g#1IS~eHc#>!O!P?Ss*My`mPE=JphSCd5Lj#E^ zt;s+QmX6U(U&xGjX_Q0a0TTo^;@-Nx76A5}N)`SKjR#9?!F$yqd+Lz?P%4mbdkQrS z-J7o}dev(+;%lQi0`gkpCi<@zQ{2H>51kCj<+e^9wPF+uMVJf;7e zvJ;i>2h*K8b4$Y#kk=V$(xD-$L+cT1=w1so^*=0yV)zr)ae8~lgv|SX0ntVz0Tecd zHFL3A+BT`#n$`4d;eG+oQu9~BYg?BKT0?p!zK*k+7oQT|aISNF<7=X9{Ep zP_X#LSF}CwWGm0T!vqHG*VCPdwzPE4PoS3DhA4<}2KRs7@M1??$qIoGKp?cN>c%{c zD&}jtHurbS4(y!j%gBB^%9*~kwKAXmHo^qO1$ITo6`$`nrJkkS1MJ|wJ}umDk+0lo zOEbSVrWI>g1~`dMqr~T{>wB0kA4yLu_Q|vP^BZtd61HEGJrzQHx6q|LX~OJ<(Y(LQiq&j0dM}TT36{b>gYp#0NU}-vA;U6t1SPy#7oyhSS&rY~ zh|WPIxzfAK@JPV)yYQds(1NRr6c}?-#qR$@sgJ(;cJvVcQjBD*)DY^MkjtmZuYS?{ z(0H=0LMs-O{usJJKwgN(opIEY+zK)fiX>I;k0l`5PCLS+TdT0(%+`)SnJ`r(`}4hq z3^trl%b@Td$~QO=T?p_PR?rhUDezOLiF~2i(EOs9i}^QLuB}z$k-#%BbI|4wjBW|a z^sE4iHq_bw`=Id>7~uqTs&^#UDV-viz@8fspW62;wN4@#LC$JNVAo(FJx>UK#gOI7 zetbtzKIh5Ps349UHimw!tK=6V?k39k$~>I@SuD*k1VlUO=Lx?-W~!kjJ)pD!SMpkF ziQQB*hF7{bi1VA%`$PMmAP2iWCZ0}-yIS?C^88ZvNGYomo|k8|C|T`@ar={0M?$#_ z03uVyDvyk3Sa7c%as?$o@md7=n8~N_QBiONL}bdFYu>M$u`75IY?ZZg{NQrqrPzk* z433c|KM;NGpCGtQ@;iJ6a|vdl<}LLYbYYPTTtHN}1Nqvbj*&=+IJtZsb4KCMD;Z$U z$M^}_eYazP9IcYG_6}p?gsHlsodqCD8a!ojH$}^F)|3-v`hTvJWlg%1dlZ^DL zgP_ZLR;*DI^D2O2#5_F;ycRKe%}Czb`=Jq!%to~|;%nT(-JY()GC6BR%*TcJo!?SS z`<~yTiPKixS7UOFH^$&FD*2(m{+;cT;pd44y+@!S7dc9s#;YvOL4IF-%{q-PXtV?2 zs$hVY+>by5zkL$`+hHN0h|>dE+~Pkj)2b67#dueGbDXN4dV**y0i%);%LGXNz8;ey zZ%ypfeTU}CD)(-sIawbX^xysI?Z0Ih|L2J2QOdTsk+%z;kSC-X(6p07I{wWF&Fj=G zVIby#tH{&sp$8$Wr(Y2T!xtbO5+>d!^If@<>qP;C^M}~0nNSQl6_@1A6@j~ur!vZx zgXI!U8g=*xa4vDd{#X+S{Hh%4w>Q-#wXDAN3sLae6xIt*Jp|K^Q-3D~0CqLSW>Z?ft@1Ymmv! znByypO+RLmV5=Z3*=32KJP}=23J2OKy&ki%%KH!Hy60iu$l=R>C?oKXNk85cm6#fQ z!=7Nn3s z4OKdkxdq+AZx72LlsdrA3=zU`pg2_e=ARJ9qPI2*3IZBfG72}f;}o9RKVIwrrLTBx z^(si7FEW~zaD2OR84rP*HpYCUL7W996KRV{eSovr_mAxs-X6LZ$LSBYWzv5nWB`O&2OG*0k$WXcl%G3)!p9EaOHm31Ok%hQb4! z$#(a@MKCI#2STfj)=Zk}%YV4+Z6-TMudj{lVTy>rKb}6xKH*iLuMPGR{cOP@1I}GN z+xjpe?pIz7qxZ%3p&iZP1257!x<1kuDayb z*PXz`FM&e7Cq+6cCQ-9q`^be3H?oVqF8$RlUp@2NjWC8@>5v#NYM#&I_zZp!zdvMiFH&Xj48^ivCZd>C|47HOVbHtZTjMn@NfCXdTjd zLBdlNGgv&+>_*hUPSA^uf~b7>UYyYRKPfnCb=BVh+k_sw+yFg_&o=qX>=jSxi}i+e zt_cRU;=bl##Rhr2ZNl4704A(SjLF1GXb2ArlwgUU3 z;;x`rpQnU^ANuHTBwjWG!m;U5Ap4gKnlhTfQ)`$xZKw_FAx%q|<-t<3E$@?7e??Z8 zMO8S=mWU71^xvbm6WgIz4mKi?!5+c#OCa!p<&yxO(Qq0Z&md=FEI$#7@f(%ij#6TX zW$nB23(e9@LNEQ{i$rTvv+qHt+$A?<-b(f|1E#r>D$j@%yfyIWh%0(Q;twaPi6b9s zF)I4Ezk=zQQQt|zbC2I4pIy+ryxcZTuNdn%N^RtXZyQt(|RPkPT~HfU5v?d74US@RgPs}eJ)sMatr4T4@Y24-5dl>ZQyBJ&vqw#n0+ zg>HD=4w~UTY0N)`)gAT`w!Dq0jCVQ+3^9?nsnDNFOX^iJn-A&z@PN#vmoB>k3kpjO zIszATs$`<~3Ibk%9K{+~!ZG*Dz_kQ1Ic7@p-~WAFZf*I&2boPp3S=+n8pV*U=?=ti zGdOE78$x^MJ(k1PxnE+n`1`7#btKC6vOs!0_fqrYkURAJD)(}6R746ilH;K-RvfR$ z(deeW8kg*3>HD|l6mDEfn$Zq6}&h& z#B1quM~*UcWL-?v`<3>We=t&aESnN&o|BD~_;0+IX1HeAs+?eJrrD1?<$OU@>{v0` zcy@X6D)4MoUfuu#+Gy}Mj3!B6c}05kv(!9gTnk2`U@|F8NAgbgvqO!+o%@AENS{G` zemcUrxx+BNbIw+m;Kt=Sws><0`ZpE~1smEJbV0t98H3YvD}=)n&l$D)9EYKc zo>3nlOyqaMYrf9nn|FT%q*JAEH}C%Oo#_wsp{JneH2uaSu8X^-wqD5$QEpV;58|t$ zsk6pwb{7qj#rW9kRPETgI8t@YA&*N&@pHfDLRMNB1$T_{x1@ZtIK%HLx{*zc>fdc-X=%TlQ%7T+Mi46*5$K_!YUc_s8H(G!y}4x*EetK1|77^b$XwNck>u=;?YwQ~ z1azT%OPWQ0MTKIX!1yU&9ekQi*k1)#ecm>(RLvib{(uRBh3*!#*p0ZzwC3#OOPsX5 z4hR+^MN9|rqBN*X!|88n;Gd4<@$$#RNp9SC^lMlUajVn zsDq!6iIV>ag=M9lqr>Y1SW(iHrR1D7=L#?B^0-pJmJ(7F9J3zPgc`S<1~)8!f%f%$7>f1UP9Hvs^q=nF}XLS z_0BLXxOy=739__+U#+iuwvi)XBw896mQgP5@<)01RRUmu30o`$4Grx5T*ZI7Xi%pc zvu+-P!*3C8vAq45()SU5J_3)BpuWRbS$!YHk9i(lohTq;T}{e{`+diBee$a$YWA+@ zuoY0`??I+;_;xouuEIY>&BsM6<}0QA*ZdTF`T$&-n@eLPxc&TH;%`d3grvx+ge36= z>uZG-jspMDfoTG|6TXZfa~hwCzM;ZT;%bURt>XH>gMJy`NBb9-l^^mP=hi26HmCfD z;vHUjgwInDcu13Hg^bD-XeOwE|DoUjt(VM!w?b&P#7QGS?M7%&Xm5l z{U2N8{|P$(pD%;sSm@!9{xKv8;`x8<5q-T!q~TKn$N!C2-TNs|*QciMj(cnD&KI~C zRtI!4r!k~a^6dKRpRUQ2v;fQ7;a)d00J*N=nlDmutgCDBpv%0J^XY&Y)6r^>w7Swd zL0R09*YPpjEp$U;L9e>%-{d8<2ALIG;-q2^LN&HSk-rwtfIVP|X>s~1To5crlD-B7 zcS0Gdz}vmlxM;7iwmqUoU*MHWuS4KB!iTI`%Ga6p840!V1Iwimz-{Y@=bo1h!pYs_ zZdNzVwXr9HmpYX#<_+67@K9NCDR;384R-8lkMuk*xI$Ap$*Vh`fsjvuNW6-(dm#;j z6Js%97f8XY%e)^GM07vUf0!vh#Q%dSO*v+nm*fI`p0<`p8`Xd(=AoN^G@hpa#WRlC zen6NWb8Qq2+}G;$D}CjHZN^paO}#6-CN{N3n9^PfWk2A-nOM6ui;N>967nbg6FT5@ z`4JH@LV&1N%ihh$2gW#Z6gY`82~K+!Jq@le%ju#~ zu6G@JLWRtD#fYI`WNZiGmafg&yMJ?spZ~Yw)>f`4wVTIyv$np>R5R~RJw9*1(R$k5 z;TX^yl*%zGxE)|kuDwN1vUMgJNwH`)<))OH$yMNqPl}p{i!T;*ee~jYac2u_wq4?$ z{bs<*a?{o@aJnc*fu*!+QQ_rL{d6c!G74nx|4PuyTf*7#a6kIEeeJ9z@Wt)zs2CjA zqua~q16n4_TuJ)~uh;14_B9QUvHfpN_Jdi_)E`||5D5byyRhUxlrrH%N-a&wO#9zv zSstR8*TN@Y#e$%V?w3G&Vhe#}klp7w2%r}JYP68AyQ^w9`Uw^WS1nFK&3=d8Zu|Nr z6Umw@<2MszLLrgC_&w)x zN%1=MmAghg3Npug4ti6ck<){+L(Z4nyPKBM{vXPG(W(s+_c0kamL=0$Tx!Kqfax}) zrv^MCcG;8`UR`r1Xn#U1-#&R~v)~BM$uVm+7^u9e0#CG2JYH2ze%Uw3d8OFq;X5)H zx-zYJ2T*Rcv7cwRVXvA20a*?5ECObB_v>GtQ9T@$E+D&H@q^A`>U-uvm~eLyMD@32 zPj(mj$|W|{CJ+ykfC%fOM=TH%I{XrLK99`^aT>w0PvCYgNmT$hoq*#GDR3JXpNX)( zlMvachf&fF(Y@e*gWxN2H3Ql~B!$5Rfh2r?qvte=TQnIpl;SDQN~jgEk5gto7_!eW zpIK24Cb1Bs@aiBj`*d5?jdjAh=xHf>b6ydte)wTCp*5FG30=*H9Ws=q7M~t%q>#xO z_#?5SxrN>6qv%DhjplE1ovGh~tG?(mDt*wa9rVms^KfjA&XK4#4S2 z++iAKh%@6r&pc8HSVig$kRTtL$)6VxT)Cu13skzc%jffX`f=NN2IF*43+=GurX_5< z@|rLN_vY(o{>Lch}}NIY^xB0oUAjOTbJI0IDE6}xLx zA7392asCmZ;9l1THX$g0Ye~?KusgL{H?zCfzs=%|`VCVOuETO`U5Sqra!5oMlO)I* zYp8|CD5o_rYi|+HVw&edXV<^0r~p~%MqMS#l_vk#g|nt8){|B!-VEE-&rtl!42zvf z$i*Boi-v3yQ1&EK4^st>y?waKSXw| z%Y~0u1Lf-e`&Zsy* z^@X@>u!e(u#QGAVrLenNo`-Np16%b9y>N(Amj8-UJ~N^0wn3=qY4RtFvY+4gItkH` z4``uM4_w`X9o2Al%#uR|gWVetVR0N4^53*FXt^)|CPfvE99hI-E{qVu2-=|xF?9&V zt5pJ!%x}j{P;2KmXa1pM$AvUTCFg6Fl*qr5;hp&9C1H50>P3|YBWh-vE0zyq4OEKL zyG;!1O1QmG^%MwT?fM#3z?={72%so!|8<)iB@p^5r8Irc17Nfo$A6e6)=#Cq&;31# zTfEI`kWi6Y5p#a++fOr+zdzTqrXrh%qg6QeTx2M?J(4oSAh@B=-09=DtMZA>8-f{K zN$t1=do&Fbq}0qXR)k5BzWE2ttNP=pW2orI0S<$VG`s*N3@HNK%^y&SuYL1BKYxvs z<#K>T&w;DbRdN(0V4mtb_lHKN%8j5JD}$UPc7uFtn|E*)dUx=7I$WQyYv_&sMddPV z_<*v46h`T%bX5LV9y1zkZT*VLpjMj6{=Myi&S%O5GG^5WgOpXQ8AS2d47Hz_X-IU6 zEIZ!tM3)H17z)8g;b}p48|V3g6ZL5Oq`nhW5ThRtdPj?>VAhP!mZnZRhX8(L4g~XK z)YwD?HcmXNdY$+`UBNBo9n4X4^yKYy{00%+%z8;D)sDh`LQGqom z(yy0g{KgUFV6HiK`|v*;^b1&;JwfUTrLOM8B)#}^lH19_KYlp&$5*)7QH^(TBG0hP z6g!=>`vVc42?IT`)v#7p)2hcK$0WZs=9Me83jvncTe_(FzW%^;M6@6nQwdSESfNRp z%j{_8M`bGGZc7wwj1$QN9lqRjo=dMadZ`WN1?Oo*b|Nx)_&%j$*+x5a)z_g{YS!LA zIt7O&O7ZS@EHE1bmdCj3+I1(XOHNDSpr;sUBVn|w=a!I!?s}P)x=jURV8GVF`B@cs2%LaigRxK2 z0O#&cQNbnD=+ykp2jGy>@cx??fu+l*_lOEirt$-YN*^o1;PPyYZf(6(o}V_g$0HHE8GB(G+{Rz-yd zPwAc5c<-N~q>Ub|Zz^j#Lld(3WIJhWv9vm5fpO zZ!0#%n2uNiF~A)0$sBj-z!*e4lXsF$N<~S{e=eMi>eI$X6~W$eGl9=xj)2;_Y%ogE ziD8ywI_gM-lF5~1Rmsi(CvO?Yey&qmwY$*Eeo;mwhDy&^5H0zGE*X2PulL|{k8X>N z#6L4sPA}KUl(B8Gz@THC`{RuJ^;kcbg#a9-G3wRcW`S*2wBgH79hf|(B~Co-F(fJb zgOA5VE84dRCU$Fgfi@zQgkY!bPy0?d7|wc<#Cm*}pb$p}rEw6lH-F48O90aNBa@c@;O7*UoN0+*^0E&ty@(pm4>RovP8w3 z8%r?Ck_Jf0Irkm9PCi~~B43zEyxEx=5Sz;oa8!YXVm{*?Os`sddWV?NhpTC+30d-? z$GOkboQyd9^(3;q&m=Z3Dp!U<8_OC233XptP!tdta!xz+Ex^H0fhfXUEr{l-l0gw! zBwsL=h<47>d!FMwW80*&O{waJ?Dl+svJI8tq6~=|BjC1v5*fmaAeTxZ}$TIX~Yx>WYI3J1u3&u}sBcq)`Qm zD5GVGnG+&Ub=ykaLWli}|T7SxDu3 zE4EUp9eiQ9$YvhLANl9MRQ2akYMc|PUCXsAHe^Gb?#p|BjNs=zSjresrFWObw{P9A z3SDRz)=Aiw3nF@Bjk^S1?5sQey76x%OH)N8_`I+P)I$H&BlPF_k`nLi}c0aU{(rY!GS=01@hGZ)CV}?dPbL8cfNjO#?{tR_$zzACk zD$7zg)Qnaqb!N2%#9uMv<+hLr`n!y9Iu}%_V^pH`b%8w9?9h@Am5{oqiPflh^Sw3W|TpYV5LeH-FOi+n9@p0=TDPOE0ccFWJ^Ln|Dh2Wi_If=C{&-97N7pZ;av z$F-<6Jw7WnCdM{wga_v*X%$!EV+E;JL#1OXO# zBLx~p>|>AFzatpxcwktWD&9zM$r6Q@)bS1WSR9f`;Q{u*_Uf$LikvDXLvjmtV^d-P z4#p!T$Js}=I`QNvQVWRoB{PV;h^x1nKx{95IsLu!)vwmg63|ue2^zgiW;7QOm`7#@ zB#tr(&PMRODEH_)IG0dCHMl9k9KeerGS9#IFi9N!^VD~tt7@n%#dLCw3&>-CLBkR- zHj;SH+qOEnVv1_eO?rbX3re`AeG(8dB9$b@2i%Mw&q73_VIzdGZ_jQ>n%&gV^x2%t zHF-v0w5r=yW#c)|K3F*EOqME3OiHS@7i5bc%@qV>;fcp{yPduN06yJ54X4kl!B(jJq=s6GBKbimouglshzQKcSQ2sv>ELcG3C=jidX3>T z1n`j7j^fs*ZReSzXWbJ@q)M)T>0>_L{YgE2UsAaqrSnxQP_75f%^ZQ!CUK7~xyzG+ zbB<5jsT$#tE~dGMd1X|;s@ivo{{V{}AHnuMeukl_G;u1Ji4rE#@iKv*ED#P!$Q);`tZgM9 zT1wDB%;Eg!u#BkkOk)E%QGf|fLX39p(>00&@gH4T&ZTU~|}W zo-x!Kv{Fe*wL12m7eW63FJ=I#0w5!E7E*B8%7qv?`}8747n-)xsN3pQZ^8HK06hRp z-r{_P*w8(9l!C7}Y_`xRV&%KXwNlJv8xL zT!}@x@ywzXGXnNbGx~=B4_6=GrSa+TK$kva%aUZWJgB5UrG^~s-TC^nob_@SrV+x9 zS>l$&dUM)_q;CD}?wV$d`qywg9mna(IUV{i!6l}S#2%XPIcel$J_HsG?sDdi(x&7Y|6=RJt+)Jt(9xdnSMS+NylVL7Dc zSCEcE%1$sd`+>$iz4~ExlG&D3d9BTI)sqFg5J+RLN(^uH_Rp~g9T4>5isDq?Ejs{{ zUAF$1V87|ex%KhRduRN0L}dXH%1rAJ)T{ZGZ?r*vVIYCXWs!cRb_cTi0f2g8Y%!6R zy1eywBF(kN@yDcNJYf5RdL{JXD%h(8?6Sn{XJU44jB~JL43!^j=cUohAo;7uNt$w% z%C73ge9zjORd`T)hR1%Zgr{A|Pv0Ngs}j9A^#L>!PSvDzNszH|Wyr~l?)qgMXZsGl^5U^P zwUwH!XXRj2+Y2v!ioJ=?IL>l%(pW`<@ikAa042hjNT?0w1V zouEo)C}SQ?hVwk3$pubH+w`&j0JLB)w^jsJvn^O-VJy&MJY3dI7w6vbDm0^lE3GoK#|x{9jMwQRks@{SDE`bIV#(DZhG=+ znpE0!R3`bYMb<*g8BnO@{Y@s^dV%%>80h&U^YwDVqtZwZm=rJ*z+jmMfob2W39%&*L3O4OG*Pog|i-jmRb_Lv4~!{CS>c zKXLZp{kjv*dR0|Ka8rK9Hw6mmPTq8w@rODxT{mAT2Fnjetl|;x+>q${$ zuU1%${QEo|M5alfV#K+2=By2?clj`S;ch7uuN=qFpNieT61d|dxt(hTDr9mFe zp6YqWzd|NZxHOIusg^jkS*cA6zMnV}%$Onk$lD5YoOA7y{(3R0M3$acd8xzag^k>K zXzlI@_Q%}ksNzIHT8XUlO2$VKJDt`5ZWb_j&;FmDikIdkcAgmxr~_;<7Z0=(gZOM7 z{Pf~wAT+e{g)IyzN~;w(J#&qq%Dix$!SCw;frHYC4S09bQysdp-EGq& zFARfvqA}#5`bj^#jye$}e&MMic&~ zd*J&oX7|rYSe)d@ISc;)ZaQBTuamOqyl6Wwr9G6Xt7SutCq8BYx!{U=LoTQ?%imXc$sYagXuTNp~rHZF|jv z)UXE<$nx7z3}Uv?gmgLg?X&NX?a>ixGZ%>7aSYu zU4v1E%;{f<*0ZiRFER3Sfu4EE&%ak0qfJT+E@jpHi9wZufU@8L==c8Pw+E>`5U68} zSJC3N6!OctRyd`W6D!tGazp3p`*YE%=?!Zp$d)#cLag!th81Iw4+Fp3zg|L6Y4xX; z(+J^bB>AU(gx$A(J7YfB>efjT;{>TS*;t9}R)5zkCU&WO@HU=DJ-+?=FsgAVgf*wq zEma1EWrTUAYq0|2Z19P}FqN@$bCwArxgic-Ne|e5F`lH3tmf2_ z3XxT+A9S&wOG-x!Q2zi%IN9tw=dUShF~@mhp0d=%au^7e88G-*fcN8)PI5Y65QLdk zQk@l9WoDWw!!yBLlJd^)^m(}8KlF}q@6za2C^aaoGklztmwKx^EK!_oX->m|>Emh0 z9>YBJ)~xZ;)zUpSSYoti=Ac;9$@mVCI;C?F~Z{@ANS8gOBzjOZ<^*PTn3u) z8=~_EY4ARPe>mOkj=a07OLk3+)MBYrDM;Mn6_vOpn~Zbx52TN7qmJ&Q7OwObX>|Rv z2=5P<%rnMEt|>A|I3!^Eb!wy`EY+)FDO{Q;7_@n~jJ{f10kT;8qOkp-bbAQn`3Y<# zSwl{;rF)PXv1}&MPi0WSmJD8)I3%)m=u-<*y*!(NZI+XsRV$#C^cM_yXGi%b*zkK^IU$XwU_W>vLk z;djGrYg2+a;j7{aYN>)9vP)`I-5fLb;`QI5mguD&q*H=E-Zz&QLQn&N4fbp2jELrK+N^%AYx`HZtJ za^caRhB(R3uRuO;IOe`I z`%fi%m2D=}o*~Bn04=>m09I0`z6k5+>66UzO>5%qD@-qdo3m)j~GRoQh`RTX9>mL!c-+)ol@yzvg4R$}8 zhPB%fW?7e9V%5U??pOnBAgESJAQI&^5dbw8V-i!n&?EP~0ASRJga06F*Qe+t3y_rN~~Y|C=3 ze-e1tRSF=p98G2_+4P*K+p~g3c_e^A1A?pLYuMC3j-MN8=|$qVrPQelZ?WerS%Dc< z&T>u<86QiI`0IUqC-^Jj82%pkFHzN6b7|sjPE{6iCM_cw z2m}rZ>F7K1yl$w=jZ0BBbkF|WaU9P+ZEd^gd)%-jB0r-!{dcqAd4RgdbH0dXr zaE4l{&Wx^@!XRJ@h9`F%{rBI%Eg!+2HvS*#!&^c{@qAWZJ5F}Oiy4zJ$Y(ea94QKl z31WNo)0VtBqj;y`_PgQzdZO9zrl84E?wc(|u@Wi+v5Fkzslx&YAb@k$srWbWHa~=3 z8u1++L&h4Hk0aC}RH|fA3Q`fdDij{?wEbr|#{hM{jj5paZ889ljLfdH^ar@(*7a*mxb&kG&HXbRFtJ?V1h8RGshcY#`BHi4Zz*jd+}4?E}^abPt`nk;cpR3 zLQPIXHN6_9(*&~=3-bve85{AJ8ObD`u+1Of6qFhZo+8v&U9gg=kuS~B zDD?0E2b_C!qfV#117MTP`TYJ1Fw(VJRVs>X-Ml~|1P<8|>Urw1{{Rd4&&1Zhij(mI z=Z&TCzlYLk?c1WdfcaQsiVcy)3@l2vSPUWL?rwhB)`R>)&946d5IPry^nVY-U&7X{ zS+6#=X3CkYHxOu&1+QA#B*P#rYFp4bF+ns zRUNX9%5cP%0f=l42pG?VJRwql{w2DWi&C7rd|FS4tvwkQoNDpO4RGc|7t$G3Fn!}?0pG3F8sgUm@>bie2UV+FT+ysVoQcFouiiN2 zU|$0~JEKG5I{qcqHElY*eKL54m!`=#>)v8c=V(U-6Z$d_10?g;X*_Z3EptstXQ`>o zB%DiKP{y$-++@yuCLD@6F8QuuGCe;SG7e};PPY3$R~6*cQMrrk|$s89`g zn;7(#LJ);44{qIe-Bzh>BC66)R?N<C2R+^9Zf6(SIUwh8b-QgQU> z81Ke<)kr)^A}2o|zpC%p*xgXn>)h3iuYd;^Xpo#z#6dG^6bl?U23yxalC5wEAGH` z_L)Fp0bJv6SgU^z-VLqe?Q>JDXH(PHT)%GJnl;ikSj^m*22_+J{_LOg&s)2~J{<7x zhrA7===5}-+01lN_fUE#j|w7fm={{Z-g zuWgn7A=c39%8@0*KCS%9-ZySJgdhtyuzuin>s$O$_(Sn-zwrmJ{7cdNWvT0ne^NHI zvr1`OQK<&evN%*O#f~sY40+lzbI(mQe~KR)d^_b)pTip7xV7ZOpFN~Wa(kqVt2B%I z$GFZu!1aNxWfwsX1J*(P{`&R#ZRIK!H({=(^BfR=XanW+5gpwG%Xd>Yq(KtK z2;KYlH*BB2efn2wt+cr-Y7&O3>i)S1jTA3sIT-?i;=3L^@FI94 zM3&uV(%@+(TQ;X+-eWuu!hwPIAC9+7wd@ytCe3zP(#ULCZ#j1RyE(|(-_wt7yAHqh%0QCBqN5f1Le$_IZ!(( z?~cc%nueF8>i!9_quZw}u-h9aieef%z#M>~#yLLVe{6M50qrgBwA{9*v2dng(T`q> zQU3rAuJHc=2YNL+bR;@{lRc{NGst9k*Ue@~h&aGNPBWeub)vpBLE=pZ_|@?iiQ-Lq z_N7}_o~*tc(lY&w z^heW`8%jvjvq>Y5Nit*tJLN}iwru(iopZ-jb-Q|Akv5@975RDZR#_eax9W+XBpmv9 z!3VMHIAL`*v|=Oa@#?&3(ys3`U%}UY*Bq12CSpjOb?*@{WpV!ihrTL!%i;BB@L|$c z?xmS(N2h8UbiX(pu2LfEHvu2iqqngmq#h;s)$yxH{w6Kfy;DTc=MCY3s?Abx&}L*g5UTS*~f;43;?J7o4r6>N+l&QS7)b4d8Uo zZ@-8@>Dtf7a+3I}kBV=2z8Gea=B$anIPyRVBBlvIr*Eg83CCRr@O$F1@x{TSc-Ki9 zPm2=KHDiGpH2EPOpcW^~w5mY>HzOd7V2-pufIJ)HYaRwod&0Vp%C@4CvzYI^NgAsF zuD}mVI4s<9IUR0ahQA7YL*TE8ns11;?-NsH3-czW31r-lA~G{f%rLLD+i2`F$vp)s zj)vgpx&CszZkKoB8r3G2=K^53@e`QnBf8R>jlEanfAM?bT?R|`bsah#de4&vprInB zu^&VpR+$%!SozJym^=@y$2Ou2vNl}v6Cg6zTURy zz+VJvnpeOrXF~XarPQpG>kiOpmRsiARE|KcDz-kDcnpB@Fnjg7nSFh(BL$%RSF5jU zd*T5>q!Q7%6Vs@lmWq0_3_yA%&p@*Z*K02iI00NHMM z>!I}ziXH^;=YaHI6Kb9;uKE?-UG)7a^wLN#%ga0AP-`B;N*p7u@)Lq<9|eI?Y--Mc28f zxAP6N#VoJ-#acB0#UKD-fh1=+I3r72QMdvE^;#~Mt7$gQqSmyMN!(16+J5k~-^V(i z34CGUnfymbT1wv(;M5iqEoh>7H8>>$Y%;EQC1`-$lX0|@yE(@~{5zjf_?z%&#$O9& z)U}4x?`ef}eSS9ir>wwd<)&E&lp~Q5z-I171_=kJJ}>a+@bTfl6IQ9?+tcY*bs3-K z^vf6Ht8-9Pe@o!9vMKCT5~n_(-D4AceenMPg*+9n>7NDsD`UfNt71WKU5RG3N=@NJ zsUjaPOei}eJSaKjl6uVdhP>w|wk*%x0eaxWdlv$T}= zFj#n;G*DCl-!lHQAzyZ5>`!2GliRISBvNZnA$qS0Th^w^&wF;U?v~;XRN78Wh~tDK z(3Kdq^~mzixRJAx>(H)s-cgD!}Nd(wxNbSZ~(a=R263DBb%GbNT7y%KAV8 zQT2R_ri)8n8rGUg6~15q!1 z^c5{LcZzD#kVf^QGEXEJ42l_YiZk!*e?M-ElJ=jYX}W!At;wtEL8WI{Vf{$t&*{T4 z89*5QAY|Yj$EZ0>IT%+{cyuV*YF4JavP@z&45gSh{h~1N7BSGmNn(JfF8j)s$9+;r?7~ zDQ8An{;?6x7_(<2gV=xT($6UNlyoy7L#Q)Xl34uDE@UjSFPL&whq2rApJU%W4k^@H zF-sChK0E&a?bKUmJ}Z`4tv!j{2;=h^RdTC>7=Q;Ifg}9&Ja($3 zWrd{qD-+DyB&!&dZ~BaU@IJ(h{{V5-0|}9pbY*K;lvdyJOCl+rv+rDv09h8s%lUP0Nw1fR}24*siWS+y{DZz?2!(-E?v3xlxZ+_=KG=k3ryMt$T}jaJ5| zsZS-%)pTuF?|Cs>oR^8DvJTROdT$>Sa7*Jn(uD zAqf~tVt}1hB#7S)hB3=jDwPe`9o&uIY~*xnnBdavRkx=3)dZVgO%sKY$N&a^a-$<3 z`OjBZYWJ*Ln!J`Y&oamS>O4YLS07PapMUZFx))KaUROQPAmoqE zeY!Lt)ojXE64K37l@MizM@%Err*(kb?04mWq`^IashTtX$Fs65D(9F=ubmS@Le zeS!Y~&rS}NrwVG)wV3Q~?&>5iamY}3DV{Tq-2w8&c292Xk=Bx89cnfcf4YV_$WOPw zMYOBjrixSigPW0ltAhRaVEzZdhj4t7v zWczpQdKR&u49i+`O(d9DD6#p5G|t`X4*-$F4CDejZ1P7}#YQ-zu?!N7&sn1*dt=b# z{{YY+=h8msqW~e?RI;Fo2^;3*`O7i^G`45hu*e%6F$5^jr?KiuG~Golw9i^7A8RW( zoE_oQ05(UZe$DUr>aBUU7J+!{31(ffC{yW*l3yuqPJpZu zBVtT8+?Mv-IRNmzQ4&>dC_364mGp{BVkDYi$1_5hjLGbZfBo!rZ92DWyi&lYvvkH zGFZ08ykj`WpdZ_u=cO@7C)Qt2s#wIxEJ!A0i6d`yVn@HQ9ZUTF$c@Bu%(mx{p_g&k z93D}W`vKd&I*EgX#UZmklQrofjvLT6*aEilz_(^!e@DK0k4&cU-8!Y9^yit|%r+3P zU~o%?fXa_elGR9Nf_iNBE69)x$B!)>WW*SP9RU1v&Elr;7@Ctk&oyO= zZNYrfSBB#rmHwWG{$=IRiEP@AcrG%A+bJ#Ou=KJV;ITXbjDg(rPNA!`a=|TqIqv~3 zD~Q)_!;DDnp5KgQbST2GXfIz|S!bRZokKHLg%~49*b3n?c*aiL<2?(gX_fx~RYkE{ zNF8EbkO@O68@A+;fsQwOAMw+XW;rFTJYHncLu3_qC-n#fZVjJM=eJ9yrxXTC^(@#H z9>%&g0)2?%sV-IwpzAGr6T@h`!(wSXqK<*XjDMyV12{b~j#Rc9<m9FhdsUt#Nop;ND;0&AHoC~fk(JK_k8Y-xSz?=Yhk`ULesC;X zilAeFtDFu_a0%z20(nGSRzWmzwy)(FBq}9I%)W6bt&Aq&pILA4I`-Pc`jQBxOsgwK zs`x~idv5Q6(h9K5)lnS(04`EmGTv!0va^1hl6eic_VI($dtW0CpouM6Y{@*JVH9s= zU)#5i{myg8QUFX+DV;Rwq$1sU1%f243JQMNlf<)m!nF5}FbdvbBqP3Bs$Bxbae$LD%p z8A42|rzAE`7-O*LM+(UIkg~&UT9Z_TC9)~j3r>Nb%Z;7Ss4{-%`x0@_ZoPOU{$RG1 z#J*@%jfwttw89WweFM84=b=V|`{bJdd2Uy$;r z@}fv=EQ>dm2$Ol`ffyb6=-{maGr;00gPEE?KhnqD9l!dWz4PyMwaw@NvdiShD3T(r zg;n+pJ+c1)pT|g(@J3zPL3SjSA>5EhG;=8q!0tKvKp6zF`yAt<;eq3=XV(ymGX0ItGDTa>m3Gj=uOE@NwTi zeyO~s-4sq|nIt<`IVwk}f_=W+{{ZK!Vm4xeCY=@w0yXo}9J1}t?P4-{rdu*1tZO5o^BWipTl4Su_s?GKl4K=iXwb-o3~YIcaNK`>$KMC51QQ!g z8J(j{hrn`9?BpmG;cIhUxld&q=MIE)-d* z{yX$Axm=kLObm%S!c~sk$UtqNp8Pj%dlBqocZV&s%?zgw3l0nJi zBkk4`@e9XVFT;<8H~dwvIr(bLkwXMz2`tSc1d0^Tc4i=dlkL`Dv=oUP4WMI^atOu< z`~LubzHt8l9v8I>TED|j2uG+TT@q)tYGjN3K|WMOxTU*rD(!+lf3nhkA##kw|$;$2Ca2GT8Fjb|1B^}tY`BnN`0x$T~~i{Y<|^4hhit}@D=r8*;GVGxx)+CZ7_VynEQw@P zwYs$$-do8lZs0s}WF6j;q@K#(->r1pPNM;we+CcV{4dB5+;hRj;>j=bkFIkFb z5&C7sugZ4s!OlI89cBXtJAVkY4;Wi`ulzu1V+&bMn}cNJ(;K;ElQQ) zPpVm4YOZ)0Cy#!W>e}{`plKGh4PNY2H25O(XSF+oiZPI?3laudjud;I2V8~xVO{Yq zq2WCX!G0gPGE~*8*=G5Alyffl$AH}{6r{Wz7*UahGw+P>146LkG)rYZGQV+IA`NPA#r0_S1d=v1?;Vm5t z#s2^qC~LQCytB!u>l(~yF4uNDShMAoa#S;S0DJW6lr{-zmFKi?72IFeb2STJ!iJ7s z_KeI#7&G_PbQs`&^*XXgREV=Og##p$fCpN){{Wjm!>92Eou^gt3Tks)u#iP12%f}9 z?yATgkPx{H4o?6can{duNue>i?~Xu0!1g2GtfUdj`VGD1t>a0ydtV)hBj~u>#lI7m z;=~rYEw$HacFbo4jAy3*0K@OY9}xIDzlrAYWI}6=u3h;@bSex_DIcb% zg^iU^fH*w^uYU_(7=y&ubx()MQ^U_{Pde6_ZU&N*F~~kn59lrl${^dq;4i+t)W89J z61A_6-$JgdW(T)EPuY>26o@*}&YYL4K z^4%Co>0aFSj-L3V;Ma}3FW`@y z@QiW%LGd%nsba>nG7BOd%ebtB0z$6h5a*m=dv%~T+_*~f7B~L@;)M+!=7q(x-BsK? zkuAnUK!SX`ckJ)rUafvViXJA?b#D;c)*^I-(fO-wV21(x)M9za^sztp07*S>pB#AW zMeqm1eNV)?$&zSk#L|4FW{lXev}CMm?4Y(e#z$_sy?z_~R`9;H6`cw#Gh4W0WLxIv zlO;{ZaEX)4JJfnfU{sOpI6ZUjt4qZmDfpf=pNSgnkR_hfTD#8z2&+RHk1=7+R7BYy zszD>L+Hy>NCe?T>Sv21mYu*shMV6&!Q`;B2Yv1{O^CDbHk_n7rBZyP$9}&D?@eYNr z5%|YY)F}9VS)N@BO4A;FIvHy#Z4xqX{{WgeC|MkU7=4HXt3QX0Kly)!HRxU{?POU` zKEx=?^9RcqW(++ojAcf7$t03`(cTNu^$&}m7^H%>iSl0#bl8?EWr%?whst#Q5QLWA zK+nMK$zs*U3AAB0ff{yVShE($=Q$Nn zv8^oyW$=BEh%fw8M_#$zT8S=bap@p};XF4uJ+a&^`8#h-~%GS{OfpA^YD#~fiWj1JY`9E`z;z)(rZ^!0bduZ5l_@E6062y0Pl zQQy}FrXIx8%wn$qM-LQ2B_6yeEX)8TsXS+B$|<%1mG3ow9e9SFdzy9@GRt>+&m_j# z1Be;wK%8d_=>Q;+j(*3hv%vfGqeqdX@a0B%1g>HSfAxNPXSK+uOGHf*TF6~QaW2i)|_t5|`I`MH4IhYe)r@$4zw^Bk%7~v%k4X8U6AT|U`5DQ| z2^$1rp%-q@K*Ig{?;SJZHjB4St>POMyfvv`oI^^ryC}alY1!PewK9Jzo41paNCcRiLB|kQ z=!;s?CYo5`)ayv`{{X0~FeQDt9^Fd1mY((!2<|}BNuMr1HFq`+4hOzEK_7y=Ee#)+ zgTwTMLEfgq-yIm=qcA(B>~tX&Bjg;ox}{}91-@~z7X;D zfp6jYpHS9nRF;Am?=-V2c|};EX36x7gN*gEE!2YUmpwaCEY+utqn0z-l#CJAGHU+- z!q0;>y+Wy<#C{~Hr_-`*SEmiQ6nUBYnZ!lkjt2H5e}0jwn%bsH1}T z#UhPB8<~r<9Cv1BEKl6@PP3rso*~kjj=iJN)~V+v3)PZ%^Zx+Kup^~QL#LwmA-B)6 z4SSj^5t0Gg50vITRxj|^#G0>-eg$}E#U3KiTf>^JsZd$5rOJ*Pu_TpN5-PAb+D=q+ z)_mC8kNvvv1GHdn{^zc0{vv)nRrnpIcn(*qO(gM7y&ji7uc+EstLb&XF7vwNG|V%x zBVJ2BPXL2ll*+Z4WoT+wbcPI==i%I*iz@iP@q}tKuJaOmBA3E)l#vp4h~3CNF9Ms zPot)3wP|V9Bc)2T3k`bp&?HeJfE5)7000004hK%$De=nrB`q^i@r~HK)tG5oF~HNL zd3fzMuhl5>x@S=ZWt4G=gA{;R6$x}-|F zuB)p+0APLo{Y4c4jGwvBS9M)iQAJ%>Rn?_{1d;#)Cp|?K-B(^7M{+;6UiB1SW1RKx zRn>JARn>J}S5ZZ22P2$){{TH*)pcD(6b!6hGv>1GIUoUs?arC;tE+{a&T&x{506&U3~w@7KLpsuggc0i56tqKXLPkt?FKo@}5fc?ibi z*qjal>Q-PF2JGAe`TKwNeY&z%+M&F*n=GShXk@D^<73vs$`J4KYlWLjF${TN4$)3&4G;b_c;Te-0{!aD^|tknu@P7 zNibcqNfK>c-sA#KIrb#u^U+-l8O(l|ww?GJh#4Ecp^W=-Kl6^K2Pz2cN536K5G?Vi z54bQV3$y}3Jn{Yd73FW6^A@;#0qV{ess8}io-lvEQaq(g0G_qlz!8E$;Gh1?bgIS4 zQDqUqEYYiNo5~wrJPhu^<%#r#1HW2Y7RI(z(o0{@A|%X=+=Wu2L-*V}!=JxIw3E9>w*ioXQdQb^ll6b>N8jz#PYX)OQ_KhsBt#)glY_mF z9e}{c-~4D07N&qXUbUGL+~H*ly^BU8i_0s~LKi6`nLt1D3o!J8*eFwlV(zj){1~(P<>}XNp6XMLTzMg;Dm-d*`9eTTsI@ z(_s~ZF7Nq~nDM{Y$n3>E&PI91w?#Z}CZAy}G;dJ2F%ac8N3@wAyH0!$6ztv@5e!G##fOkIV63y;OF0|!!c6Pv{K0{4@$QL0q^}MAK#*3cSsN< zNs;Pklx0=BVSn}N83sb5BOySu+WtpXX0J59Zu29@!$zQzpOeN19Q89sxQxLHDv1d@ zSl~83!@nQk{rbEK+6~8S1hTWNZdrzTz&*2{$8MpwG5JYiK5LoJmd#V^iLs5`_Wu0< znZj5HqL#JQ{Z^g6UKpIltjE&lf`7+gbIy8|6%i!zJpyKFWG4f^a(L&YRAQPsu`I!6 zoet>Pl%k;kfEW*8a(8}uJh_rzEz{4P)ENwU*%83p2+r<##~k!dU=A>i%mK>ziDtDW zP=@lsypY8aoq0ue9OItY?VhGfNZOO6!Xq?$H?lcWT&{2jxc>cEB-}@e`82 z+a15RK{&AX9>nr_kaOik(d}H04&&e3hU$X>`ns73{f<)kE(EF}YXUAdpAo`}5Vc+7YEAS9+$F1Fy>~1!XJ?d71TY zJdh8+eD!9HQq)yufLK9gCXz)ixJC{BnIvH69oMFa4J4-kHknseA{v1kO% z29XFhGIpT-qYI8({0@&UfJ&CO7IsbBLYrCW0=1>H6wo9>W`;b)B+@XK%#DY-jsVXa z@$7S+{ap$ynx2;#W%8v)@}!V6ov4^p2RSRrJBh(Q-1TOiDy=EzrBbxjfiXF0{{T_< zHt*CJ816!-&NIAI<@;#K}tNfaCX!Rnk1DK<*cOylIMjx<)=~7Pv+aKqvrH%`htW9#1u)`vv z$7AM7fPt|X3!E=K&NGgf%#ON-P`}N%EF;_mIqVt7umha^`ng3V1Z-H^BZ=UKW}9@5 zAR;ROjBE{_Nc>}}diSN$s>u{(Ye%@eU}jc~@DM3I$8tO4jOV5>&Nc~NIjg4K!*pW^ z-sc^GKW>*bb&|^2nT?Q6V0A;fC2k2{baHt74zDt&qJkRkH25Q1Nb-rc*b_;x%0b9t zc_(jHPO=Ee)NI8h!bOrj@)R2tvRznkNIk*MN87(e$LCkCA(l8SCg6WaZj&x?v>?IB z_c`boMDlBF9tNpi62`nTfJnmkMI!~2{@#ejQBRtYWtQcbwIOVp%^n0XIUB|upAxo|sy z>cR?)NNc!Jx+E462kn^MZ4`a3GVdCp0}{ojt92^mqq%%U$#C7M+l%L?}G<~C>} zEzUp)zjK3(pKSBe`D$YQ4LBs9ElYfH%UQALVd)CP)12|NgV(Y_bLKSq63=GM_$;HN zM&TA{S1lxQ=e_~qnB?Gfhj`n@-X8dQ;U%-<9adoXtRm_4D9aRfRbNv_D=iymVR|a9958T_6b@2AIOG1CG2pL0;~M}aJA`W~BW7jI4_jUEDa3p>-%F$xF( zcklV@q`ngTWbntvPXJo+2Ze9OE$P-4uB{E)MQ*IE{+7@fuGd_ja2J!Dv06j%P7{?y#j-iGKo>}I5+LV<{ z<)Sw%EKyTJFi{GOZO^ZePquo7<%X{Mb({4pybmz0=>gubkT-VEB#wW#8P7dVV6jqj zZeancB@YZ?gGC`c1t>cL+>V8NIS_~{)84Tag-FoK1TZ)#ono5X)RRo4Q)ut1Wo2Nmq2rgoUYL4j!{Rj z;Co}G-zNlGJ=tn$=#uI-f9F1BfCW@x3#h_?JMsx9->C&4ka=E2mtL2gY?#VQ${J@d z@HuA5&wpY60IyBquq4y`$y7xnxn#lK^OAihZ{&Tkj;gprr5NqBQB|mMY8j>T6V=*H z#{_}Ul_9zFR_`S*l>m8A$5ufrN})YWxjZpG!#x~?1z$CbI&^g`&1M-4Ah4wg-9Ib0 zEC(fV?g#sHJ&JW~FUrk%n?{C3O2jILmPQ-SOMO6h1Od-{_ULI1Z!)~q7N5>J5!IAC zmvfA=D`RnBKWXWa4%*y8tvEkYu#O{Z5=gRtN~hDDcRAxDzeX^a3tI?nLZyi1tzJ1} z(#Zy4O!G9j9fk=6pSFJ;xa#djQ+YmSSf^;1t30*90!aS=cbGAO_#;2ts3TgiODr)g zRqP1@E8Cc$C63mRAKJ>?72`d}L@YD^05XKV_|`h^(!{yj0;p^=BYyT@+=B!0)F%mG zj(R2RpDhKMWRhr6Seax=2xeW_Rqe<7W1=VWt7au|Tlax6eZTp;mj+NLS%q6XA*qZ#xT1}#1Dw7$=c#!=}r=M0q z`*i@4gmR{ZTWx`M5e1^E?^ZIS1U>^eIV^GQpKgmqu^otEa10S4i{?Qx#6je%F~QxA zKlkg_dNW=!$gzW{RS$NU?-Nw8yZ?5s|pS&pBi5&N`wY z1ce1SHASxtnswth?qVfZKdA@@nE=PPW1RKvyHU?>NFCOkCPl3isuu_kZ!x>MJmHAP ztG69l4VQ;jnx~mHuO{0t%k7o$Jw_(%$)5h_*bc9TQy#Z1*;QR;g<*_C5%S%;h>?jT ztl-aur*hgpBR&^ng0ZQV*0*A>y++FtRe}``dYj-{>uZ;CwGFp?=n>u&%J;UZ_R4WwKm5VV17YA`0 zLFYYoB$U`pOoDb>E#<)_Vnc^#CAR>0Cntf=IL-}ZAqlpd#7#tW@>Q7D$H5sS#Dxuk4y2X!{ml#;kkEwp;vyP{< zkyNu*K_E*C>O`({8kJ5;u*-4nj9~u&j;ym3vm`JWRocWdNh~meWOX0ugdenh*ylY} zgH|PPBTI)-sT`H$fcKa3G z+#hk@seWGM)n7^>wE31c*?t*#cFyPXk6=LH5I@gHq{?pCX`Di^D?HVlnKmBC!H+%u z$Dv>?Eo~~-$Qx!FuPa9z{{X6mu)q#D`!~4gVJ)T*hH7@@cp}o#=&%t_6myu;cVUij z0rht$9s6UbYa8ILdy1%HXxa$w#tOnfE9I`v*&GaK80S4pXiw!=u>)+xK}rSzi62M} z#z^-)d0m83(0E=M5(OlZtW0MaenACu_QrZJFqt`&kcj1h^%>f#fn+RcBxMVgY+$MS z2=^yB_QyUvsl*i$vaC(;z>TGRqnukayl@`@@Y0BHP`ujs`-J4Cj{hfVtfAp zPBKrwNbJ|M1l62ZFtbdoBtD1OdxjsdpZxn{s!MSW;Y}cTWrDcVrqiVofeEY>N@a6` z3D4BS)scXsp(>s zm;D#c?3l>L0U(p=>d2#>!HT5oEw+urNhHzal`Yv+{^EQ0nsTvI5G^3{{ZxWb>m1rPSQm1ys^ZO4TvN@U6eml?)wkv0Dr$y$2H2d;)ZI` z{{S>e0T8@+LVmL4fcIZeOy}D@Tk|p6lGM>@^4OJB`H{mAj7^{16R=_U!u1AGbWnW6 zcP9Q@Uo@`PLGuX{>{%lmqNw-dtE_zL>TMAQ4N6y1mRSIf0tW9OlbjYDWap@=M+vj0 z*B*7-kxk~P%I%6WyK^I89jDuz=h*dfi;mO89kR!tz0CL0WZ*P3`NF3n^ z_L5bRWQL8CVo1wGmZTEphyMU0IU8}?{{UW~-#q>x(=Qok)Fww~YQn=o z4{ZMczIqN&6DeCqBk9$oiKW!^%W^8pxMJ$y=gn3G5?A-2&1JY%;TTP+g1yV z)$F!e=2kcdjy9)!0CD?rKfZeM&1)l1h6%dY z#pva`Vncoj&i?={37S|5##EdPf%n1S^v1O7KZ>55p{mtVCKY7J+QB}TAQSa--yH>F zPawTGrQ+Kxll-i^>?-Fh%2;6g;4$|-7z1h$NGJ=HC6C0BBr^Qqf^nJbG2V;ZD;_yL zw|39BMMDfi#aQNe-5{{R;Ie?o*#xX^03c&M`kPjmvUtM#$eiRU z^q-;{mSSSEFd0TL#qfFm0Jjw0*fy+u`T!@`DtVGgU7uT zzotL#+2`y%!RsBnAvJ(RDRF%bA&VYC2O+kB%O7*kSuJYy6XzFEES!zwVxPLa=G{EE{;$*hJsH4OFIhM z75la(f}oYmyRA7$Q9vGKk`s&)Gl9-My5i3q{{Rx2{=M-qcx&M`HG;Wlk~^}AEd2D( zAO=52c+PMbjGu0>PaOXM5jy_>#7}|RXNPos3NH&!cUZ7>R;ypi5~zK&;ztZ!H^z5M zfI}arXvjTl@O$9RZ-(9hioUU`$#Y)RBUvw5fdPUU)bENVdt{zZ!=ah(}U%$lC|Zr zEXrX7@(E_iLPukchK3q3)qzAdYtLfqyf@{Ll(0eNvIk*;4l&O{L@5$*luN2oIt|pV zryVgX+LC7o>5MC5co{oco0ea5_Uek+fLC03jbIy7G>wApS35G_xDq)z>73Hjn$WXq zACsyJ7@&l(X=5#bjH{kmz0YCE>gew*7b#Up*mPYqg)IssXtNsw{ANQffJDT zX~`l%X2G*o(`<7ak5ynB)9TNpliYjs43*=nAoJ}@R?5ilD2xE5TYy6SE0f>9UL~(G zG^-_3S&$Ym*(JQJE>8B()<0mirrBaD56MX1~6HHJGbXNQTcw)@y9$X(f&_v4Tg|gz>xn z-@iTi>Z@9?wyU6uJC-LZKuG;nc8n@*$JO`;uTGg)<=O0CT|lh61zFp4vMCq{sz3#I ze&Bm_z~BN}Uwc)S*0~BSb!t|JbaP6~Kq1CUl?NqH(m@%|Imb#Ou!(ZD*yEadO(97t z)f;R{&nTh2hjZNH-=`6$lAlV9f{;84BTfJn{6OY<_v_PnL^T@fAWenLcW} zI>jYs_4>GX0h^Y`zifMZ^kD8qg&B@Y@-%cVO$72-Z!U4`c+tBd9@zZwy-y5rfilZc z>4j`SRHU1wJg_N_LpO3i+Z|P@L>i!qTD$82T?JCYP&0*z^YpfT&U5dcrh0Lhs#2_D zsUoY!XGaX^!_=`WjD_5NIRihQmg$_O?g<)AER`UN-Kx)Od0G}8XX(zvouzy3$7Rkx zJzY1+2#?7mtvm{~tVtx|H+5oo&u|8CPJgyK^%6Q)E?co$rHc^ONl%yRYO9YgAoeSs zGtY7mCbEBKb31lZYAs49%MTk{;>e^+rIo`+o+)um?z59w`R4iKEhKC zz8cLFd87~CO5`!aro)o5UVTv$VNqf~5_MefHv{rb##QA0^Zc$P^j%c#lbFPhH) zX30B1WNZQl)CY0*=mdcy&@DwJi#Fnr1qB_M22Mdk-HH6?9UUYWA%8StOH9dY8-wx!ASv zkG7vV0h@5sDH{YlPC`lp~mi{BO z$@LH6cf|Fq$y_Z>M@yW~J&#i?GXWg&5%mzvN8}!QE8sSxRsR5mUj;1nrfRhHd(hG` zFPL_uftoB4h?r%tGwU4m_v3by2k?{QoT9rb)B}2r>k7_{-;=g z(<$C$rkbam@RB}Q1}F5?;~~N2oBDViEVgQgc^}j-2X#=l#1`x`1Q_kZr}PV=Eb0i= zA+#sc?kCI-v-Vvx7G9Q_=Qf4^2#Ak8I;F~V#tiYJ=Hxu}c=3r2e%{#U=}r;ZoC0}1tc zpo32~q^lL!-O@d(Lg`vML<{rYoGKTdkjt`Z43=3S5yrm3f}HRVC*SkaF=*7xSNx{=h=n^6(?VodC(*F6&T-rv4EqkK zpxRNBRFbZ@Z6cG%uVDWG%gHbig~w%Ya^IYF2BSvIbs|9tvn+v1ZeW5O9vEjB+B%)A zR`UF$`PpV*&A#HV%whha zB#_piG}~1fB(Yk{E6FT75_D{+C4X@Q@J@Q3Bypg@T)lPH1LSR!XPFy%ywo6L00WWV zp&+qRNuEIOs6!lKyw*|&AMA##(<7JR1vZRP2P0#6Kyg%FkWVl@*zXsn`Rw3?2Z_ zZ1vXKR)l;ZqiNn7ni~-|p2|0?t4F)ic7lI*s~>C=@6S!4v2pdsrA!2Nfjp}5xZdQR zBp@Exl=6v8~)`hIa z%(r&eMm<)n_zR=>3*m>sIVku?UeT)R+MJuO>u%7)HHo7H#aI)`+DXEZ`;XtPQ}CK3 z@t^VcuK3ozpQ+2G#Ai2aGOD%do)0C2xF^c|?(*FPr8WbYj$Hfy_rxPiC zKFR>{Fg$IL0kMhXo_PNNJ#QZh_+P`G2=KG$o)D!xR&KJLPf?yQlG#^Y<-h@zxBz1- zj`_(vW>c!-8ukDi=R9%Ic}Cgl*A8V1hJesPCT4i^JmqF}(!3gFWon6BSC8eTh9&iv z#!3PE)Q_b90Oa&TM`py-nPOVETBMI{gOC|Xz~ufo{Cfe>@C%JjYBtDjRRp^N6llib zm+S}a-JYcRIV;H>m;t?N!ukGHwk_ny$1Kgx2_DPa@z+!mz36CYfKq6xg{t-AjwqhM zc%xq=6EXzJME z^h<kA+=cJYAsNXFtwW6L=GeBT?2zZnC0DEKlxc=QZNeCQ4MpB;q zk#4s^BrMw_oZ>fS2PMWc$o`Yxq9jO@$^!ee^>_KpE>E0X;OyfBf82V8N}?7oJdaA~ zoT>DcK%ja?;BlODpZ4jG$!>vErIKt+zGZYEFv0z#=eKeO20e#Wk~mr3M67t)0Le4k zO3ym7`DhDBsDp0N$Ei=%yT3(9>@Tf(OEe8UYvy@s61zxyy5rKMbC0)7;;T-)ay;{S z%w#b@!-Sob;jm9CHv4C)HLBUSdc2X#729kjn94CBW?V$_C%y*?2Y##If>b9?)FO#v zn6+7+>&G0m56nd{J=i~W1abcWraCej_u|o{uW)7vBMOfsp(F@f3aEG_0na%gcjyS} z>QdCBax1n$)KSF-WZ4AH8)GR|`cCe{gN~afiLKYshNG-k^5mXikr|^B7~GsnkCH;} zJO=HLe}0AvgyC6L-o@yuvj(x|EK*J7ez0;f#~9oGIQ(^gmXc}$Rgo)AS~C!_AZrmK z53I5FKVmR?CdQGge5=hIQ$Z|}n8Krz3}g&6X~tV0e}1K}q-s=Y$qPX&>0W)aM^%gB zCjH-H2kr!%bzuQ;P|%uWCcIZK&GRcFR*E-dNk9aXwMZBs_CNY@)=4p%pNHX&Yw3isxYo%(dD@h}g65`G4Tp#rT0}H#b$n}0YBF>jQGF283 zznI1QZ3ySHF#5OsmpuMDBLrnD32al`k4&4-w+5pvcZxgKs}@nW1cm&u2h>OYI<`nH zO{~oxnnbl0@FqDd2MWrd`an55c^&CyeT45NNXT+>bDntW-~oXPLk3mLF`CoWfCgJLIX-R!A1vo% z;~`3)^V5g7W9RDIvtBu&T6+j$7(_R13+m%=J@P-tOC!_kS1Ua|Dn(}mF4?w7U4FS; z4hhG%Z2o#CD(ad-wNEnPmSZE>mz9$z)D#@xgWo+aN@3wWWU)uX_pVOq^03OSFt7T8 zIg0u`$cWAf=bi^b%>_7CDQ1;okg87kDGeq zdmp&(p0n*UPrq)W1$2wb1)6zW#sV%jIXL5gAP#Ur>RInqnAU2sO0dUMcD1cj5X|zkmS-l4nG=6^CZvFaN^7-^*)9YBZZQ5P(EK{*+dVhK6G2Lv8^_{s0Oz#te=FAX=-*c-Qi2UZ7Njv?9jn1*bt8kFul+qDtrijt z$cevX8;?>J$+V1@E1$9q5l95z8#in1zVSD39ZE%`E!FT&SN^ z086#60DL*|R;f+AYv9cz#W!^EG<-joIrsY!)xIC_Zja#^Lufu8 zt)@$UVI;<+2tjoOBC57TYIFD_@775jd1Tb5jntabMI)}p1je6Nm{0Bi`fxcu-8QAC z4I@v}*XNA#+?C`+WFAwJGDiOF54b;1S<5BzvpS6zxH-)PjwEC$prJGxblRoa+7V`1 z5p5(19FxerNP&CrBkAMRJ7d36E}?f*y+#_kd5XWy#%xyG<;Lq2euKL>4W3Gpa^H?R zR?)>RlUC()SXG2|?zNrLz@a@j&N*Ykp5S*q7iPtm)3oYy){EsJ&eX9nhDjN|l=8FA zJC-NEMdgKw2FJm3y9j`+a*4vMUo^^Xw|PADUeX;j_R zEs|O!G1>Q*D^AP_x=S7;UO>b5CK+m<~LF_dlPS*Tyr^eC9oWwjc+kw2Zdsm?IqazO4ej(^8V zqO#9Q_4<=T^8WxhlEGG+;7Zu_IZ?<5l0fg1p0TagQv49h3{|G{n|?hq0K+?+0k>;6 z(~R-otLFY+KtpC)_3F3Ih>WsIWBpb>lu$Taj@al)g`@x$QBw4h*^TaeotU6~rKCs zJ%bQ^MS3!f8hwNbI@gR!Ns(D_$0sUt>^hMsz=UR_8cnH9Jl2vJQI=`*kH~G^pohuwtWLNPp$Ur)FBp8w<($S%)8E_8s~JNQyA|*5-B+(4810QP?XT zMrRzk-Pj(-^V=O{wCH?>t30;r&t^K&gAQwCD;~__-#xhP@6zb0$9GN|jFLc$^80q` zF|i2U_IYPMwLJQ`C$Z{V`k?+@1ufHCtRdYU*e1xq`jm6YKVgodNmgpQotw;PC59{K zq{$?a1z5;A-dGcmdlBwC^dhvjrF7b?BbRCkPSzpuzXg8eWq!x+(Cs&uT4}?Yk)cSU zWrQd>`c#3RN&f&po{KO|D$6me1dftMtSQP-mN@xo0OXQ84mmv(C=4Jf+qF-|8jbxz zG`~h#i2y+<*{(AB&gil3djb)niIh;|f5=eQ%h3Aj{>!D?F45Hgy^2D*T zF?@}_?Q;>kKx%+&<^!^9~qNvl6tjisLJh~i7w`^@?cJskK{{W;6W8Xbis-StVOZXjrx8 zurW$@L}zbHsX^?+1f1g|jCAh3YOzw&=uK@6I`OC`DOs6_IVI#{>Tk*G9G0Dr=TO)d z;yzdZ07FdbBQcC^DEoLMlfnERnk-R4BYKj0&Wf@|-nk?qOqW6U>~c9Bx-d|b=*2j( z#5N?SF6KiTVd6gdIp;YU=w*pTVAEWVTk13p;fD9NUE%a z2^wRV)Q;qR^Zx*+QK^=l3rf}Gj+DNiHO}U+ak@PFAHW#LzIr4oNvqY8xst}3lSz%Z zMDrY{x`ysC?~{?xT7lJT)xD-D4Q|0v6_Xd~#2I(&1QJwj{oj6%4QKh3@k?HM(9h+| z6R_EbA5%UvjQg*@LP|_}%-2PM4oF)5WBFy@b_%bvkT~oHJ^E4Fnk4}gk7G=sPFSR# zHzlB1hF{Px+TXckPRzvLA;F13Tj--!#I$V`ul~t6q zamxp#)=+mClxNb|=O0NP{Z<_Ka+)j49p*q}5l6LI%VDHnbvu7O0%VnJ6IGW|hTW@A zEt`J`AU zmr#}r38ei-iY(#VZ)}tMfbH$qwvDYuTGVFW4cg=+HrcXlLP=>0uVK6%2Tq?PG7}gU zugIfUs}`T8)dCXgq^qg=wq%kSSb$sHcE^5;jjKf>E~6ty4YdlfKK}qo$Iw5|LD92Su2Yah9dQe?O)I`e+~6?( z0OgOrQ&UhV$KK&6mO%n*(v1%3WQ;NLOt@x34HFBzHM3-N_1h+%f(-EUN?skqKIr3BFDX0hZ#AT^zHtm zp4@c8%=3tzKP;jw;0V-imLNvpBMY2?@6Z;4Autl0*q+nsRbxIz_~agBOrV0K;Y>sx z-*9?{F$}bt^h@PEaU*Y@Pt{ds+(A|Jk^S?JZiKfY*kM+*am@3w`SaFKBmk!*ob$iz zGtW~BQ_iclI4ZZCW5f>}Vy@~)Pnjb}DBme9fww18Lx0HWslY3tlO<#G(+b<&pp^jNpUc@9sK@ zCW}wjtXsKtCy&7I)Ck8bD3RhtmUbp)bq|QnODY`tam#Jb zZs(z+S(4n%^9>Tt$YBqcVsLUtvghn_IP2P_s??byWs=XEnIhfwvE+pr^qhaTdi4sk z*kXb@Z2RGn^S6I0>dXE6dmQokR}zk86%msHHdoj^Zp4<{axfQmct79#bp%lfgs@8s z*UV0`E>0JD$p}XW^Y-d$=2op-6_m>H`k1E0M*gjY@z1wYBrLSzj(JSBK;~6IJjMWJ z_VNcnVo?mLC7?05PeB1)!ji<}1CL-m^VPN$9y<}12&51~KGJs%#1DSwKmC4)NXeE> z`BR@vi@_iP-~IF7uTd9nT~x|gmMXXbv4hX{<2?+CR~SIpcoqm?Hq0v47A5kZo&C&Y z{y_fx_v&?d_pE6e=XPe_^u`WO2lX8P0QL^uT&)C5`$kIoNCVZ8*kc^=@6{~P$F?CH zfR+GNuXx?G8&h2ar!}XYthPNh;aGpW4HpY=3Y5zeB+2C3sOA z2*)Ld9P`2V9QEL}`lT3bl|wg|-PuO~;C=c62}TGCW-d{-5bnL#uqVI!bz{I8zyk}s zF&twc?(O%_IqDzzr@suQQv^u3k{yAAllE@>9D8*sl2Zdn8wVLj1To_ygMu^M4v<91TQ$uoy4ICe#m@+X7!PvN=0}&tcY4qW=H|-WN@Ny{{H{$5`<; zhf>6oMWcG6i!Q{JXUjXN4S~05#rfFJkk)~FurRmjl>XqX1;DV$p9C0Rdu|j|V z&p5|Sy&H$91K5A{I<~vnw_`Z_E6!PXCq$)VZ$j#eYPyi*h?9xOZzCac7l^-u&j4$m z64zUoR@7=~EhKr+YC{ZEqXTM{jZpzbU;ty1dz|Nys6H|L71ulg;Cq_#YM1^X=uvA> zzLTSTgqCKjy|$3WH#DrI`dNk*ROcjt*U`L!>6~NO_Rmsa;ODXJfz$oHNs?t^)W5^O z3u+ecV`vI)c0-y>f_lWq!-ex};J5JetoX~oo+j~ck2LFE5p7o7%i+Bx=dhORA`+t9 z%P*!w9UrK<@(7DpyXx636;&(`cAo)ym9|f$wCVVN;zAX4_M@?4s{R>jlB{R^qr_8G)5;6e6 zfdnwe?d*8yF9CcO@OQ&63To@3th$z~co{D0x~!r}thi01%wPwn-yOLpt;#ZHY$iQj z`)7{-0H3#9QSo!*r;fZa{B=|KMHZQ(X}%QIJTE4vOH|cknmI2>j3cm+${S(wgpn~_ zx%DW|sC2fHNE3zZb!%N3#5-2Fw-2h(8@9{4eV)k|@WWNK-;KU3(sa0M4I-w>^1XS_ z4IFE=LZ49}w42LwxZ}4ScfNDq8T<9ke*ium*zo3rd`quanY=-2s#S(-=)W|z(T~@F zHkTkd2P{b$CjbtVINO}#9{&LQbalus0CZe0@c#f#ucr8T3eDPTJ?{ni%H^EoHKAC9Q!92^||v)7DpzweH% zK&6?K5KDTq?~XtA>L|E#;%D%PJXP`I#hyCw{i*{{*R4ltW2{}W;yFZ7!v0zy*osm$ z9f?12*S;724&%~bzw=%#gG_7N1=i7Ygcd9!w&5GkIgyz-7*L^m@Otg}6`2$(Z1n@2 zXN=^J_Z)w}SG$PgEZ<1!n~oRGuRIOmtwQK)Nd80U(i*4o4lj zyWgup%8d8Nw^wx(P!$YRl6@y53`gUizx(yhUN!z5^xqczSheCq;;mYRD?&E2rbjkn z5-Igag!bN^hC`IcI0v4(M?7HlS^og;anZHTX~N=adRCpR+x{NSxC_#?x< z1MqEq3&WaxG$};59$ZR{+>_4GGs_?I)>cSXMP>l8z|XnHa6i}{q#u3<=c+8EunaQ2 z{{S6PB$-_r6e!zKZ5k~NV?+Qr0WLIj_0-Oy^av9@vRRIG%6Vh`IL8T+agYesDS!jX!udwCtkuUWD1MU9+ zkNkC&$8(8aSGT9^XfmJsKp!Bd>JrW;91kxXob#NIYM0{xR4eBoK(|gxdFNLDF?UM_Ub?}@6>7-K2F>m=K}5BvxaFSD*HmVSYtbe2*=}`ANJ~8fz(1kaDo+Z z7wkIs+p6lih?Ss%NCzYw9(#3nRn>JAUUSAV-=4kdx~`&%x~{xGa&QM;^%ParbTd40 zERx8@6FFvPBn|-o0Ac?Cj_32yJw+9u0oY@l@zvc|RvZixGtV4nzfnbhQIL%y=aPqT z{BTGA09UCxuA+*%uB)o*D66XKx~`&%x~{9L>L{zK>dK z9EAtmXM^q3!~&!qLHqR!NDPdT;iO%=l=}jE{{W2j6kaS4tkXK6-zf$|{aj<8_V(-6 zS2IRc!hqRuS0#oH27S5bsX~Rx00MbGlhxf?s0tKZ0hTT5CzJOlkM_XYuNh5*w=c-X7wYfi z5 ze*XR{2v{|6i#(Fa5~?+c5N?r+V~{X1SbG2m_UKoh6|h#sfTK>aVo*ejAv_fX9uK!g z!Skj&d*lp+;<#A0%Msc$=5kcAB;x=KWBc`b#!5VJg7%&-E!s>r)&P|(bDlHp(acI{ zF)9UXDpei=@+^diMU?m_LGbOKYc4JolH zi&PcbKQYTXi5z4VC-&#u^v0c5r9w4&?xi6{oz?wL!Ff3!QU3tft8qsI1IdKt;l2uMO9n3-CjC#9s&>D<`siq@Kha06R7TJ^EZz<>s|=NTaWF&Q(Wgi?^4R2bLYk$-o`G`k(~i0Rt+a z+S2(gT10432w@lvxSmJYjQ;??T2Bb7;Hj!dXx4mtdFQ83>OQdx#sY%`dF zJV;l*0PH~LJf5#eBduO=UQNsCj!O->c9XzU@Al`Oh`1A#1B3vSE16`G-JTR7f=4jq zG42Kq3D0l+`Yx)rA#a)AY zaf(|BTD-*x?(XgmMT-mMG{OFC$MfeCNy#*_lncXqh9Zrq(FgQlvM*}} zkHy-J?eaU81%aoxKm@2$MgZ)%s@KC0Y`6B)wi-|sr*kgU=W8++i zeN=JeH4O%=K&pC)AQi15+NTx#@!zFX>q=aujT$dhZnZVq%s#THSz&68tL+d`lr%z7 z(%NsuUhZC=4Kcpa1Tz*+5%3x?Bg2&IXnQbHZx3L(#zewnA2K-e6%*yFKPQQ?_&pMM z1V^v@NUFpNLDzpX?^X6ALbcmJYU0ly@c~!bDUUEjk(-cQqk*r(W}+hFYE-eLsGHL5 z?Sb-p;VUQKS+PTXg`oheUa$g+k}2J)4T$IHkwn{=>g|y-)j$pqiwQMEwL0wU4Vu5$LBa$nNvB-XXs!V< zn_n>HyKUR$+P~W}C*Hj`w{Y+PUgseZxnysel?K0G)F49Y8III40uRAY@^=~f{YH9K z610~8q$yRC9QL&iI8a=psTaI^>{R2h@zD+J*G1w?EB$*P6w6h+lrQ@m^&-dLTe~1| z+efu~Gp)Y_@wfLH=7hRE3`d*c#4$H|Tk7u=*KNyiHy;XcmyerkP{(z^!mS~n1i23C zm?v-#{J8lZbhnyS}G71fL>DE3RjAOeh z{J>4l6NsQ}tGsph(4gGQZEKihlFQ&Chg|317lD^314--YMu9Mf(3Oh(K$3p&pluBq z?|H4>`W`OI6b3?ULq(;E9Ov83N`_o7~v5ji=AA?amM$|)1?{?G` zNg}wS5@W29#h*{0Upqp{d~%To)Qz%|DIOBTHs^j(FU%6^#WnMlRT3EYG(tLJY(8$Z zOR~UieY)B;Ar)_1v+X@+H6vZQk#;%wL0aGxrkUW1G~)Xx)~hBHKXoNWy%9BQ+d^O~r1()?Ju}m_`mc<6mZc6^&bn>0RPwd>TCsrTQ+n^KXv%X^N zaxZ7-0jKu|hY}fiL@-ihPe^sdAX0$;Dq;q~oKFMk^%)t+20k;loX~QXX`*_YV5niZ4nh2&e6SrnzUzQOm-(_m6&youy>JrmY2F zW~smFeb7IVNc=x-Dg7jK0*}z}_p_4IBzDvl|T=3x8(rT}r_# z#=*o`>mugUja=xgt&}T|+x;!9VilE%Nql@)9@@pkfS8c($OCW|dM|vFGhU@){e#M- z^Q3=18zOdAs&?b^NO4{27xblhpZVUo1!72K(7e@e+n zPv&+W`lPBqM$sCZOK#V_Wt^rdsViE31_WnXk`)@_`y%9vTs=<2PMu1zJ5khN2ICr1 z6*r2Z07e-q5kHL&&~`U~JtXKGm#bH5obSJoV0tHf7QDy z6j=8KToPg&VuT={Pkj}7i~l0uIBYzy>`Q>J_SE(v@_YK2f_A18XI_q2vNFI0XVn^& z@-QOA82s%FSqTl%mB%-qGNnehB&G;+wr~Tp?9zQwPhn~Lr3-kk*FnNzF)C~wXFEfM-+pO3KxG>gNX^6wZyCs;nkh=nJcFoA)Fb!(}LRQ$=2TndI8lsd~q81FT(3<1sG@a+8Vr9Gg{Pe*jb=YYAlN5P?sWa6M-ttiH z0b}>Xm~9%SH4|RVI6(DS{E%+$g*2S7hxlK`i@>>E8?wN|TbVB}*c++==@FNSOn%ki zQw*-eMd@8FhO`l!-Jc138>ovSb#%(54a%+g#oN$hr1E0d(KrDkibdCR_&vKpTdfT0 z+*3oTrPeF0VKx;E{HM@cpV$yFQvpY1W)0>8$qXY~0zzH1=BA~0E01x)DN={jk$~$1 z`zjsPn$clDrly%QufXm9mT-iHGeYGvmHI{|fF{ zZ3o`m9&UddMy|*8yLE)_Z^jwc(#>ZgP2HK|Y(wQuG=U{eFOX%A4zl?R4k{N*FfAmx z%Uu}|!SiI8=WqG-_)Ia6hiXt+=a^>%(WtUC zWWR;G4cF~W&{dCN>$9Q|z~XI~7_8&40I4|tXht30ca0}eu%1^a*Lt;Npa0&{nz6pi zBa~gQA@lfU&87#~&CS*a$J&?Juas(cU%Q}E&0N}0{u41RNL-HQ-AvRE$^Xmh)BGza z^CWRiy{&V03G~VP!Z>mD?B3U4e{N;Yncwg)Fe)oo#o((R+jP6! ziUtcLDD+7p#N#}yqc;3f@Ggd8^sW^!DmPJ$%paJZL)dLUzF@@fl7k@I!!?Q2usiII3H=$E3VzHq1t`RQfr-0!A{s_ z2{8iol8$@v+uVp2UZ0@iwUVvs#o9VOw$bNvgWRq1!l zxxImzCCt3F1L?|FNxRX=vXQtupN3`$>!YcZ>NmFmT=0ojL0|H$K|HutcqWB+cp<%YMaxs-rwSJ;JWg} z9#!G1A-ef6b}JTHh3K|DURf5$V&(1k^%{~AMSu!>KJ5N7|CspvNCb{;F>>d6n*g{w!Mh-X)Bhdjttg zjZZiQ9Ya!;mQ6IiP_j+)wg&T9IaM(iD2&`3dl=Hn{L^K|TTjYApPBm&1uH^1)kyfj zQ7dC6!+!_U#zGsFOj1h%;CEl#31zL!U&~hQw|&wvYT+7@()R{zd&py9+mr-g8?Ub* zzgj@^IvLf!iJBUd8XBm2KS%DQ9!kfs;%1@d2uwb`>|1q{9zIXm4a&=g(!sBogK_GY z*n_GuY{_k#4>VaL4=Oh>5S~}Cd%2@SM>e@a|;)kvE@oFcRZpUFtYEqHQ!RXvsl;6X$N>}D-(>licY;+P(oetM*==R zuOz7&i8eP(6mkiBbY(Z%e*F%!JP}L{xe`QqjatF8+{&v$naED}28)Sge7Nyy7t}rR8=|9kw(zHt+EQ0P=qcjhFh$)v$$#W?6V* z@$36+$a@OKX){`i38R_#f>IQhk(1RX4k@F2UcOa2g7@-NC|n}}83qy}S&y+qJt$3m zZ{7ul>d#`;n28?rb^mNo3|Um&5(2tc=~xbxq}lXP}QVCfZT-2$c8`36ws<#ZIuET3d;ohz>&c3{E|b9>E@^yQt~@G8w_ z;NhtDJ1{fRBq@1}zM)aaAMW~-UQuRux2Nk((-u4XMCIeyz|w#%G~NwOw672W{8{Ri zRsxW$nZ&TuH^~ZK7R&USR_`qDHP+GLg~z(b-S0*!Us?D=9+ZTegBAv>M!8~AJy5e` zA5lO9;fSJ&43;4O3e~=nwC`%v1;tanA_Q0aJQE~)2&%tv%N-r`a60;Ug(uKUU2dNmXkLwvwK z&?s#m{GP^#AeU_cA!9G|g=%Ib+Chm8!`nXdF)|{wVa}kgKqNA~r$A`Ym5c~R?xD2u zfc4lKq|6u;#5HNf7}Sf^G=8mEJ8LN_>XK^x*vZGLLL8_1yU3tWFVH%-DSR@432m%+ zUl)-M8Xcwgo|C<(aGLX>^PWJrldBYH6-i(*UtW6n)hT7jkO~iNOumuK;}U2{%L$!_ zki~UAUXkSy4Q-YdJ0;G@+d}4A=4gmv5mVdoV-e{5ke4+g6xM4hbXAA?QB{_#gTaTO zZ_5GWR~EP0tSEiPI=`en zm6+tL+bN;m*w~k*V{mdbFQ2l%uI*8RGB!y|7p;y;DzT3qBGah@3?w1ioVFmn(aN;nRqPZoomq ze{(vY&50=wqZUgK>auOEVEzhzmZeE%LxqThwZ%r&T(A{%J0JY`~9_HI|jNwXrhw z&2kdWNc$7XZ;^o1K{JlKxLWO|f6tmG9VL3goKTc#?y7NI;H-c<=m6_dTB|&+L+m#yIzP+8t?2 zEqQ*8cZ21^=U6W$Q(MIj-^TpQGK2zP>NOHEl0dS;#)$BW3+i^z=%H;Xx@Hm8bZ0kd zQ@L}A4s`q=cnYLpDV5+VXVE}gd4y~MJF+$oggPp9HbT%bP+r#5G>DuEIkU>6N__=% z$*~NvcNsM;>Wq%zxo7Xp+=Q~CqoK6D~`oEY5LydQ-Qm9F~=*H(^|b*wr!*u zLRsaPlu&ubByE-`3di9g>#5+2fc>xMnB21oG>(f~`KehcbOwHXsW;~*g7f~C)eo~m zO~2Ds%5>{z$)y6NRbRbJdq%2C7Oi6H#)fexcgCr>53~_k9YpMrGRxo0|`8ape>6LsAM25Ry1kVk*-wsS~h&i--(3+Xl0I+u%bQ73cqc;PiI&|W%Ivd~IG zv48Gw`kORvPW5RDv`zTc)-Dq1yvip*`aV6TqNz0gLj(KIH?9K{$V@8C{>BrjBFNws z?hN+4l-XmvMO1^nBjJ5ya09Z?y@$CKEYD?4e!xEU+Q^txBzDUfPi~V?f(XQ|tV3fc zAoI7)XY}JCOU^u*R)?v=Dkq?N5B}phnK46wbh*W>uU9+yBe<4>Y0}@eqrzgnN37l< zwS{mzOW{%Sx%V>@m8R8Y{{gt`SVSAQyR1=*t&44b&pA_TnI^N?cU=M#<*7yYYga8t zC3%&XC9+!B|E@LTv%X6gi5UD)yRNCO{5tMW#sU#`{3k#R{l}E;Ouc}kcwQyR{C?Th z75MH7E%IVCrlp)P`zTt&vnMO!DjD}IN{L^7vl+l}b!!+Gn!FP(C9&vfCssr(LvKfr zz1|G@TOAQhH1D&AUKb>vq~2|*IujV}NfQY_;FF};vi{?X!l?VH_EJDMR?#tQu(kp0 zT5XM@d*W}m9gDOeV}6=3RUVrx%b{m2K5P#KMLoVg89)x`v!`0gTMUX*m}bbA%RDS>!;QWqsR0PF4cP4;Q?L|q}!xb~2Lk0DjlCl^uATF3M~=j)dXBj8s!W1_;0 zuhmk)Y$H)hED@n=$~%0)M9(Jn-=`D39b?J~r|i>mwZodZnw-BsnEO|-!)eJUX+d(v zdecjtCh)O_Vr|__pNT-^+U0uDxDO9WP=#+q|yL)6g+_PJiY4-{r+x~tr zgLo-x&fT|x1zDe4e)T@?yShvXqHCys;3>>hrb0_sIh#yg(Wr=#%4BP2<0@Q1jyXzN zf3hz+jM{5pNv4%}35+#G_>Vlc3ozXRl6F_GZ6+JbHRIyPCL@V2N;tA_)0gQnf?D>i5CIE(3c`8n<`mr6bokH+n5$hfXG$P~4izx}GD6Fp#<9_An@5dZp{^(y$WQ z@?1DP!Z93lB5V8*Ep48eMBmOiMb$wfsQ+M*mgm^gjSsF)@wP?|;=Zl9O~x2-WswKexZqZtJ~tYy41L zzX_5R+4AP^E1~0D1aMl?_{=NPA^ZC4^cTp8v-(7T+ajElrzJo90+ud4EP;N! zEqr+3Zr8fJ|BEG4BTH7?W3^zC-b#b{az>#08Eh;d>9GhDE~>^P>dF@(psV={L#^Q5 z#}O@{*{K?!ar$dxQ(-0TH?u@=9sC$QGxnn&6tW`4=pPjsit1?zf9JH{{1d}f6UNUB4er9`@XyJ$E zk0G7p`-M`6#yf^J~nd_lqHU)p#<(z=Vor8--P)x({@S zRpuMWWVBgZjbYmtXM;Mckg3i*%_T5?3mOvoBs6P593NM()Q6x1(z2yEH#ntYHW&p? zR&4dZnWw9c(-&WBYA{E-C}_dh(s1VV(sy1ePrYY}WL!;eiOU3|2I)Xe^JtYoMHVt{ zHM5>kxLN=AEbt79~#)=D#)xl zGYXC!hOMwg{kS05DdHo0>_xfG;6437R;Q^is@GiEe?hBJC6O7B%^-gTO$vw)@ruE} zq>$_{)qMO81vq|wqoeS8Agt%Z281OhSApKvTW)e@@ zjZ3yVYDckGPxO5Myf2>g>Oa7S{bLmW?Y^#+G2bt!uBvGZR-p6Shw4PW?yL>#M^vKPg7QoiqYPvh%7aZ|0o?oK4oT=Gkf1&rDe zay%9ERR>K4Tb{$1T@E&%6`+bO}`lcxaVYj+n% zuBTMI(pEviBLmuHsi~Py#SdFoO+gH~2e`rfE1p}s$hAT$%+_JoT9Fq2gDef)tdL!{ z{t(j?o%-~+TTaHkZ{$Mt=^IN>8SRbHifHaZ0yRH>-RWj%S6I+*b1W&z0BHnT=i)b{ zHdOT(^LrLmXG#GJj@K)!z{85M##bVlR@5w>bCJ%qev=C%~iMj&SE7O?UUWu*mji5bl_!Kqe zVR5Yp7-KP}mnfI<91UPlhkgI`Kw0Zr#bl~wUvr5kNyNAY%%rgNwHvjfhrUN)Z4?chT=wQcTVZ(Z5+m-5HAP^g(-@A50Fs z8VN54(uZX-(vao-`R%ZjnCw8rp~jQtn<8WF$!)sgwDk%G0qmA`rZjkKXl$Z~#g=?u#SN&8I-v;@nZf5A=b!<5? z^%K%_Q=!Tf>nTB%sv6<{Kniv5`^~rOWt%Boq(sDyR3GjC_&;XMYX#(b+U`P0*WXH5 za{M&=pa5D6+dV%$g=B%4EllREBK{g(lwC5SRXkUKa^ki~?hmM5t3zz-g`h} zGrY;&wjO!Cdr|+~?nk`VB&oPIl~b{XmXGc8bKBZ&%N3S%3wH9aU?BZP7OS%68bA)xbnTS+VuUj@JW)Os0}}5gCsoN8NXik5@NBeAz9k zX;MrX?irrBiUe)cUYM(br!aj$B}y=FF=zx~y!d%mAh66Zdw5n6-(OjO|Ivk6{Pv*M ziNP@_InT&HSB?{jgyF}YIpw9nKaw4=MxG^Te2;^Lw$5qDd1liCb1iyrPs5oNYGYwB^^zlYQxUX|KI6x#J*9Aa1wIL~RAW znMM!Binz2}X=aJAqd{zQy*sO2u7=4XcHx{CMfPucrK{&oGg4l$k0}M=YNe#kuQD^E z)eql7J*W+>zox^7Wie1QraNn>-&W~-R+DAXW*&W;$Br?kll2LID{iZPBec`%uPHox zwZB+qR7l-+bxtZ=R~%0HnB)_AIO#mR4_)daInXUZvKeU-r!6+ZlyRmAyw^dUiIHDN zS)os{B|eqfMlpulI@A$5h3bne8R;5qlpwA)E3z_S9Pe@J)@hY$)o;wqp3j3RgIfe4 z*YEDe@ptW{NCJp2128S*&&EPlLRk)n!E zJ=x2Hc^3;j{qM%%O&bV_&9o*||1Ip=F@${CEXfE;SE} zlu0J^#3mwk>==WZp7wGS&W4P1A$Dp${5E)aHGE;7r24@YZID zP7xP>uLwBLE9!RZy6X0Ly){bP-^#6e!}Z=Ov41QM@3fUoy8ebG_{!RGuS@33Up)o8 zd0m$&GlP^3MwwSFUeDt+yXQAgz8sAg3Kt`vaj&%{Tl=;I+?Gv8Hok<$O57|MQfN9H z%%|0Mx)A*|E@l*8>AHO-yiv(Vm76$PJ!8^iM}dR4Cd2h|Xct1ChE?3vP)|tDD2{LUV%lB_ zS^TKCvrQeZBLr)X$1H2im$p+L1!v5)a~aO~v@M!15h@rUpAwG!I;933Z6(2p| z)K}0^H&y@InbttN|0*%>E7vgdwM}H-HU6JlTJ|Qpf&`tgH+Em@U_(Qn*c z@OOLk>{wW`0FeGbU^EE$<@u+lxXsZ5VYSM9L(y}RK0tu_Na!&=2C{0V!V#Hz4lH?m_1QV zEA>eUcq{W_v=}9WoUt)tt-q5+w7Ed4Y1sbhWX@{;dO%D!EJbuB2uzayRdbtK*GKw@ zZRyAJ2sjs&EKFIGb!hyTdw2Kg5aLM3z(1lKVyFILq)4=y=IJMHJ`$m8BbkvBl>8Qc zxxg_qf4Er3EzQde5t-1SuLli>roQ~5!W&XUFEFf~PxQ3YbL>khDH3Ubm6RzR076p; zcFXwp>#23rxFj6qtX@=Kit#2Nz9W?sp}!jD5`F$qzk-u-iC6Njx{E)a1>$~$TQF~rRf&sVUhs#ceA^D5|WQFw@) zB2aT0#dBn7Y`$G=Jh)y2-VD(UbbII9pGPiCzxJ;h;FHI#X1M6HeHY7zvfXqF2T`L5 zhO{SPbde@M9HXplWs0HFH;b=K=Z`K>A2b(0itj;e`y3Q zwb06Tf_0*rNNJi4A3I-+!mwe)L;NmMcMx*zV8iU3GXW>mH7sFSN_V)~j_-3p-QUem z*=;k^`k7neJJh<|wG~fhkv7VCBlj)^mjB$@I(X?sGWJEh9GBRo>Vr!fvGkm_q6+Gt z-PDk49i51Q?fYq4BqS33V)`9TkQV{VGut{y_migX)mHpc0@u8=w&H1Xb=PJRy#)*< zB@m_%*q}zTxhTd?mZg;WtfTYWK_yy6}rxz8fUA=rMs6siQv8 zgQbd7^xHt(_M!)h$%G$;Mw(g{pG6zD+_aH37v;wJ3M~(ixDijB^+&Pp+`)LKPfjr} z3ueX9N{$+#S4}!9WJwJ6abKfbsL6^M?c&|=T-rAsdQQDqeE5s`(^X2b<2m2|HWbEr2fjsjFruUNM!rzkbwA1^Z```V;w)E<`W|Bdn-Vpb*qWFMi3N zP5dif&!&LdJJbH5brX2jGoiOfO{uHkcH}Ds z7D0DpYHN#_{Jp!zzZAA_5#{68{=kcO8@y1URfCk4n+$cp{sWY{4Th_x{Jq~B{rXPs zc89q=rnE7Bvwx6ycsQW=VcL5l8tHd*_#Ig~Z^bm2;pAODIiL2bI6n3tX{#T{^VoN{ z8<^^e0&RPndCEHx?q!2)7Fo$g^ba9kp9n&1Ul8Rwt{)wpO<(o%zos(5NN$MifH5GM zn2<{(`0Za$DY5}oO$9nlUXYN zG8&nwAwR(x7d4ofTnR1lo%Amxt^iNbBWZbi_paY-N)r=#f7=;Y5b>oMqusjfHk{6D zk+#}$IRWhg7OCm9h{U*QyIzHMKL-0yw>mtZ*8}L3pX9rSJ z$%#hi@>i3);tmd#jHMJq&_DZfuFJtbmV|+h0>`~8H zFPp7TwCWH1@~+C>T8V#3W8?8^ibtYmwAf%@4I@oZ1>F4IVrsv=osD*$BpT@v{qaU8 zQdX5QF_agH7x7m%I;H(ouQ%HlCb#j7D&5r@^xC?K?z8WZr0&l2W^#9A+SKVY z=yImjuKei$dl8U6h&gN_BW3h@HA(Ia^a_DsQBZsWAgNL+0AMFErF)i1MW9v9Su zRPvfN4Csu_C+g;c%V*%qnCc{MrziOpM$ z=oHGHREPViVEn;Pxkvk^YTF@SdTz8_!)dQVM^O4`1$ z?SPSygX^r;Ji7w;f{FocCTR>|#Wq@A7-Ds|8pg3ve$rV{$)C(6x$-qoJ?>pj1k2^s zi)Ue*?pHKY>twn&-{>j^(exm^_!R6%mUIp6)RLvyww~8zFQ{FVb|23t-f@teuK3+&$Q+`sw zkGIG*Ob*W$gaP^be>}5q<;O}Mk8GjdfOs7$Rc%BdLkXpFA%{d!XK z2ClnZ$k#Y}x?(_+8RJzWm)tK>G)?@GRMp!VCD{H0$Tch`e!6gC;m8QF&>tD#7=M-5 z4v1WTeu&pk*H<>P?0jQbf{A^fJmru3%yNMq024nrOQOsjoDh%;v`7+YE3tXZ&lo{& z7U23CN*w-LY9N?Wt58$gN@eSc1I#~Y{Z-QGRYD#stby`&^dtZVRR)1U!v$4L&XkCgBzodKmu)sJ{-w z^`reWd@{bLYr>D(BfeWPYtAViGH6hY>nGsF2ZHaO|4uhRAH*Sz=%7AR6lHv*KVOh# zm3hy3>Ag3gOcT{^5)Vg17nj_vECD-eO}8p4>-5rCOW*G)mnqj~TVtXss<2*cM&6pY zfgZXI-Y@>+t-g@EH=k!9W5$T=d)&D8%tYz$#1d3vT(%x%b2J|TTBoJGAVq57ch-i` zaKdnMVH~3jvxS_{g1KA5MQnGa zF8BpWFp8XX{v@Vs#;z#<*j@GYr$plp{aV2tDaNppa;U7{{T6|q~+rR{2sEaK(b}oDZsE7 z|2jRSDE=?BPWnQk`ZA^Hb3ZCC<_Pl_q{XpLeC7V-IWV%vzXN!R^p5TUX_Y#jZeE9f zU}tO^mE5v^3Wxk(D(=A|S|rkG-DXDE)kY|Qjzp&GKZ8jtWJ(DHB|-E0+BNod+xFr}izr>!(NeM;>?XB(j2-E&^c^z{Fw2jh0V_H(50s;fxu zIEK4>FN|#d)9=%i5wnbvMjk%Zp%q1+F=tQEh&w20VXNW$FB0D>Zt)%iM=6gyUxG5~ zcmMa+RX2wd(fNd)>lH<}|38oE{~1m%QQi1qD|NtQMMgD3!N}EX|Nj?nToO@|4)~wF z_9sI+rWK!;%q^l#OP)Rhc?jUH5UEvHrW?3~bsYTMOCA7ZhMYxC1jlZaq~#-d_Pgiv zpW2g-QS$!q_e!6_wG`O&en&+Ax!wtYyLloX{?AZrw(3g?e$W%_ub}^fvalxC$gHX< zW`_-o2<)38xDk^^RH^`M^6`=0U!*ZsRC`7smLqN8t>-=RT{qV3f>scZlwwM2?4K{JjBhxYUm*WbWE@bC`YJ zo2SwJerpFdKv;N>>}eA-_e}O#%4Sr0U$3+>B^~l66-*eg3)K?X3SWcY9i+NsM2Lg1 zPiB5w>Gf#j$GlCuLy~T)Qj{!k8@@7*pb^E_iOdBP4fcKu(9P$QOji~Qwq~iTngB}v{6i9 z*g$1gB_)LcnbThWK6$Q}BAt3Xre`_ie5ScvKx#fO)zt7CP-n`lY`3^sQx0N z9oaTslEjU{dnCpogX$;$<*>Q1OBdP^8Ww4D&7sZqJD}v9kNTTOT5CfxW*KFea^7q` zZ}OM{LpG}^xK-#gB*r`F_G-3c-!ZUQgBq7W@RtIfsAe)@uJ%&Fmhyx$fzcgV64=$f zaSBELvlun<5Bum;E*zBx>VA0{3q%`lJsGjlOZ*W6QmNnuz7jJB+_*fHV7@LL__!nJyP7t|BWas#h=zL2y z4Bh#BDT-1ud-Zp@02X6wI}3*TNtbt@_{c7(lbDJhOK+7!+q*cTBmB@FG+ z`fiYraSl4>_QCy7T3~m=-eAzhtM^#8y@5FbKS>cM$K`Zjz_1c`_W)YFWw5;GT1dvg@~>@reBF6> z*6q@h$d~C41aZF2QlcTM=5bU!ow@1-WOZbRdhb1fSUHSeI;-=}4rYSXL!%+j-e1E+ z&&vnk|5AHN4*dQ)b#_kTDZ4mvr!7TDlr)lR#eMxYc5?(64*a}P%47V`|C~T$(2RTG zn%0k2R6~iOo@w@DW{fM1zn|$|F@SxyJ7^?4DU?h1#dl*3j9o|mi|#Yi+`U87h4+9P zrPe>owLG^~e81fj{t|i1U%%lkwDwx(Jki&ml_UxzSX^m0k_TT30`|HtI{O5l{vTt@w!QY^u)}$d6$8ZO-L7tt%^rX^UC9R3pO90BW`|72`Mb zG*3R~Sv~lbrQ;Q{3X&^VifOo3keQC+V#!*J>=ha94Oe*k2(9aBq%=uQh{D;;4}IO) z{{Wkz;Fjs%&3`H-QCLHoe_-|buEO3P^={Pn9RlvQ&z+Gq#P5N*O#*aBEvIgwLX8wL z2Z=zJ7F5pWi;tO@?bh+bG))%1X(4aUTvKDs2gn;L)++6_=C>|uRkW+k-%8^AY%$22 za2;Vb*I;=FZGe3Y22xAD<#+Ui3L4mwo8(5|!D%rpAIie1UIg^-f=di$nmJ;d5RNW# z6d$8ld}}B@u<7)j8*O7%kkj9x{{SRmZ|)v@dnl}a$PZGDEoZeay82pHkiHW_p0kUp+h@?r;uQz)Fss8l2sss>10K~a##aKycAJ`O)_a(p!Czs+qt1YEj@Ci1G8{2<9 zp!Q%zXw|^z0{l7rH-ZieMTT}N^M$2bj4*qZ9OsQ9`Rp>CnDJYM(u=IF5u-Zd%tt#LH#4|by zWEyh3czg#PS|^ddOET>c%skWb#c;5YV9*a57ocM&msR?bk#+(zqDc+OEbP;uAQ zTPHeUICB;MdQJTkg?9H{uE89Bp(Y?g4Im>k_~>g{VneoD@gE=ocfPtdnVj79spOyR z;WlBbeP4L2vitn`R2#IrGFUTiyvl9h@S>N=bTB&eDwW3zVD7i~AK;($KkE>|7yA97 z&7C%Lv){sEKF`wk)`LyNgUYkEmwS4n)L1kKuEl?agJvXWbpvzOnq6gk5@dKFyX4)j zM$CW9WaM%vukmF~Pz&2=p62du&m{_n3jc}9K{t6sx35kKs`^R|f5xAeu4jLou%xuc z!fB33JHHll z!^P9dY^^&!{qQ@XokBUmXaKpS#xF0dVQkVh{ljCnA$A;??4XUq+A4lkrVDDT#V6gO zZ$+j;#X(3?k>@g;D|+08EEdl!BH40IZW7zloNxah08l}%zHSv%vz!cj_dPn-H0?iH z@RizjYFDvR$bJ6+Gy_4{t4Sh*&I#xL02t|n%j7S2;hH*y9}m)}bn<^E^RtF3c)Hd+OfnJ z(Hj=q@9R5BJayZ*N}IN0ogt$X#Y|kwWE_Lf`ZeNJ%xZo2c_fAolaYD!b3Nj8DlY@Edq~Hxz2e#zxU~l%KDwHc3e?y zT4q5C?K5p0SOOZj{W>MS8~KAxh^X1muQO+mFvi04|lLCCH4$ z4EJQ4&81moF(;InS7lxDNI^eGKev+J{c-Q{H{$^MeNP5yVKryfqien+tS!31Q^}A? z3&O)2KHz#V03?91ZG?jGpmrs&PGkJ16mMlOlN<=8c#*3Y(N$u`&*!A+i;ZKY$ z{{Rpl8oWQ_uNy%Ylcnlfh`FlMebwsxyhcVx^$*xzDEh@E|mE)ckmd>2kN;C;RN`LFy~L8|!2_~`gW;WRI8Yf_%SlN%Un zdDfk~8`0!D|NM zy;hvVM#h^6-~sYVV67atWNOV;P^@CA&o~sD4`EUGUwzW_As?uvy zw3Q^&>H4x1*pcK^Z%*JrDxfO@NNkS2utI0D?jGZvA}M z{x3W&t7<Qb{8QrnC{evz#5S~B4Mkin^@SI0=(iuomcdC{4`O5%-OC~!O!Q*pwUt!-pKAT?JKsd=>lf!MQ z%@Tm9A<@TgCBgpy#!kN;y`=bO;hu*rUoJa;&2^dW&FL@8!v{PDV1AIK06Y8i$M}Bu zKKl23%l&!T$gg zTGl1f>}qKN)U-vevVddA=5fqMRpSGIqqo0X=T1r*MLPBB(HdTvUO2=Nl@6jX0+e8K z8Oa#ja&hnP)BuqoeB$rIcN*7;oqK(nO%Tz}c*yP7)UTL-3;rN$U&FqQ;$I7R-$S(8 z%hy}bR+GbWJ0!9VfdLEvcJvP{a6hZ9(eZ~*@fXE^{u=%tp67=3h&)FosaoXPQLf%? zDa_5~w#@P*QID(Atb5ntn7(`!v->_HqAk}6Sw8mzNq0I{lrw-`~z?*9OegsPg0 ztoE(V6}kb#KxB`6xnKHZo_XnmfWDDxU-)JR^8!`hBQp<`i7K^$go;@=MLd}s#z5p? zc0K<9J$Y+OxV|E-ES1N}5Rk)7m=L>1`b+`z?mPq0I-JcNh~aseW|kl@?AQTM1+&LM{2BONp!_n? zG)T>Ou6VLBV#cd(3hU@+$|}bw>5Bd+y=v~}vzLnKutOReWKMpQ&ts_tS=O6>mtVeAJ_bD^6? z7stFl#(0YT`n|}Ow3f590}~zm(D7BaF0wA3UdtacNTYDfQzT`WV}8Umfu!u33FbX`Pqbf2m-o$iZT?*_{=^hQ59dgYgU9M?&4BRlwhTEJI+z+`O zN>@(#O&Xo6V@$Iot6Syw2wkGj36{nf_b0YJ`pyVnTy<(J2j2Ru9@e>}#bP?pYgIJe zYHdhYt61t0$2o1K_QxJ@4$<2`@6qvyn^&57AWIJ{gJicY<~J+G_AQb@Z}5Bd^5fz! zi>C26{{Rwi7wZ&fNv+hsP7N|DQtzoO(U5^-V}a{ThHwY3Biv)@gj*o+55k)0SK%DCOmJtcb{ z`Qxm$E7Ubu-K*iABGmOwV(!~dyrb-icqXpb|WkJaMp0Vi>CZSTyNi7J~e8UkUBMbg9 z^^S$R`m<7IR));wO8INI%PI7$bA``r9zPv)36m@I!x^%hS~>*o)h#}62;73sWN9s_ zqV`j2`Z2Ju{{W}El5vne-77HHl6&_AP-<~k*%DTj8Dd3msB9R*pK_x=o`<2RREk@( zY8s6RBZ4_>T88z{RVdIM>Odc+nK&%{+kuY#avzO>iJSLN|mfi!)l*NIQ_rXkLu^88VIyM(m({9M$ zAke<*>_Ob}IXoXPw$LIbd_!`;I!b*|)Dwy(ZPBWv&uF zDnyI*EUGl78EgcvBe3&d9e@f>0rw|8Sv0}4#V&!FW!M@KwH33ED`t5kxXCym^eC+z zEiP*`YrPwucq}6zx0c=i0Jt95!Rm5`#h0@*lB5zyBZVri^2wZzeTnA>85!iBnglHi zias>>ulTvM{6t*Pd=*l*m*7T;q|;KAW?PY_Hp^zl??`u(J2@P81oe&9_!;~{c-9RV z_|L@iSdQ&-Y1h>?2Zp6U4q0Yp&I@-WgP+G=L~LG$tqJR2j8a01rY4BxqwW#pQcLs5 z&mVmCO2*|8scJDxYAXx`)uUpBLV)hx4`Ravb(iqey{7lM$K#KZ@EV_oo2k?$rDq17 zfWZEK{Z|ah{3=uaPK)9VeA%p87-m|Uft**t&yyP!!k{O2_V?+u-@;FaDx_L;I`z#y zuby7S5l`nV#g5gHTmWK}1B45dIOHC>`kWIV3`4r8YOvV<0GxCgA-dfx?nd7@dA)bVxwXH%nQ zIH$K`RFliBtUR*CxXdHC9{qKc3syFoIiQPCTGIKJPX7QhMUhDYLOC0`*^jUXr4-?w zDpVz}r^+LjdtTGfJk3!Uum@?$JdA{M!0ppO3OB;q4L284Y-F2=eJEQNMeeTM^?mU6mKlW9$M2D?I`;nbI=j1 z32fZT|)GdBEf!G3d!=xCPdH<{*#gZ{Yx{_hRl;`@K$(b-6Vf7qsvCmE^+R| z9QWg;!CFbmM{XyrEVpKKdSVre<*vqF#6)LmlgJsycV{>q`ru#U58{5i;$I#gg?|k- zRrz{^RoAsmE#x+Zt;${+`!ZN8M{IFe}Mif*E}^`YL{zh&lZsj zIO{cS&V~bmzI)P@E`bPx36na3*J4{mMtqy zy-lO?U?j4nX_6epf=jaDi35@Eig+);g@1-$7I^bf$g>L9t>M^wz#*2yPqt9m&pS6Z zN$$VftiSkx)!^|T@gbo2PObJ4($k@mYZ`%XCMS`%2SM%t;E;G?N4HM=b>o_H{0h?k z2YfQqwOJq7X4IL_2k|Qa2Ejk^hO`D3A_HVbh=dQbUwW1f_JU2$QzKu$qQ3MXW{rnJ? zWSyXfdF3XckwhcSBh1g#vI0rn`Ch$P<85uGbeH+9SR_a{Ir1x`kn9;V%N%E(bN1@U zqpN3Cj%fVo+6d%iG5{Ec_Q4odTpVNS_Qy@MI+{EeY(kGO&D~iZPc_MsY#&6Sv4G9n zUIU&>l|Q?}Ihc10YAzXK!8KI%HUm6$$4!qs(ym{cw!H1YX$ri*WxJ2L`h!0gI#pT0UCtTEQn-ozelH>Y4pEEC3A z9b9vOd2OTLInTdCPgNI5jGOhW+nUn5tZBSOBjaKgJ=pV%aDKz7^yuP=U2ZwI2hQQ7 zt{m8uFRy7v`T;yQ*ngg>z(R!;^8WxYLca8YZQKkkc}i6*rgFZ6&NImeJtr~61alEO zY4OKg7-K`~jzV%)gtJQ|S2Yo3gb_tCR(2c`tUx$Z`RA-VQ_UJ&$Su&A1aW0`1NR4o;L~yKo2n;aU zAPnw4gN$>}ZiGngj|Ma-m7%nRzS}$yYzr-M#ua)YP=`HM^DTO0u|_JlU1f5}w2Y zP6_009r{?6^~?H-PgQSNyQmp+2Az3#>6m?XUWjwYQ zxH;vCJyX|`8E9#7Uq_W*NYA9Q0k?MbSMQPd_B~RfB?hxgM(@qrc%+u3epPb^`q1aI zW3dOYz#p9TGTw?wRt+uXva1qF6_{aF8}Yj{=Nm`>mBs-aV?6Xp`FXVYCOaeBgr9om zMO@)_75a!EjN%_Ht8f<^KO+GwjMObKCgWAP2~XrHmxp}vc=^` zG>hj*X0rq39#QHMWaD-_1ME6oc0|8fKs6Fv`H~4vV_3`OM;sx@B#-?%A{k|tIrf@> z)RB@ZXiEi=hC(;{e(%3t!XTkcK!!UMJkvF}E5iv3=4; zf!8kJWt^W%uUb^s?C1% zQ^Jggacb6GjH$*%h(RZxa5)~>>R1MKZ8mu5iLON(%FQpO8y=Dv`*HU@ zSP?^3b1i8iQk$K|6zw@-{fQ%}p^8+IYq~NdsKU&XwjlFwr>O=89KM>A(u13H0zuAc5bcx_7mBJ#s%CXyg9>0M-{$)_E*NO;|$<#1=>)Zc;$U zEUG=se&q0dvC)vn6UO%?x~XS*SoQ#ickjp@v(esA)809yDHJSF1>CQ>F`Oa&p!<&J z@6fXOD?${vA}lgYStE|HX(C+UA`#pla!Kg+h3*4`iZ@Two=NF5K@4&mY?36leAb(C z=Y`{NUi|U+={(6gT@P+4h4+^%(4Dc%621d5IRJt7>DYq2&IFivVwqMah+zw7d^=`l`)YT}~dxlGn8sukuF=GJ5oU>r$ zH>bWZbN1OUa}+r37D=21Rq#Ftda-gu6X!|@vBPFz9P4Rz8t+>cU6q4 zPkZH7TJcCdZ3GOArP~0m55M-uSZseB{Ab|bjeZ@`{w3*mbm|(DG}Novr1487R|J`( z41IeW3RSXpWarjNcrWDVYl4$k^D*FeILQ+P}h84 zr)gScm`s#yO=ryWSpt^w0uR=Fuv`y*`RYv*Sn%(NB9hOC^%@%MIQ7L=bdbbB!aRsb z@<4vUefnq)4qZxGjg4{}P2iKjm6>U}ywx@Pc3PTSuB@gicV=R{fzKU@R`+6Y{kq7X z#6ZWo6q9s_&kQn16{Ak&10KX4#B+~x)*!Iej%dw`79PWv6ETdl%3ri(djW&U!05?n ze6-QgO~$J2iL7HMc5}lXGJg2SS^|P?43R)phs{=y_NdmY5l|-uSRODp# z>#uaVl=!+j?0#4iG;zF$j?k(^WD?4Af(VR_*v<#BIqT>5z#AHZ{{Rra64rG^1?=l{ zO?J%8BQDd2#?)V_oVYuEfCsL9%ibKo-lQ)X;ye15mW*X5ZF8J6I;~xIUtS7}jA*+gMsmMa;f!^#lQ6v#@2%)LwCcPEJAhVoasE$Din^o0J*Y{ttU@ZTa5e%+QM>vF zK~siCl1QYO3uGxRB&R-EbwNK&4;^v>M z)kc@YdYx(SX;Z-qJZuXeIw^wf$wnZc$Sr}6$FHL`^lcwY*IKR1Ras-S?P>mfgq9t> zAS<75@18m;33Mvj9a=Xu=hiKknJn5!Qe-1J-?7x7Ks}d|dlAq*o1pazn|WbJP^KGF zM$;gUL0IOItm*pqgZwkEX-|Hg3p!*{!xo_suW}cWH#nIG36sjGDr@LNg&ah!n?Sf7xdS`+6E7( z0zE*Ea0fjWbj?|GE3?s#dl5xEY4Z^u)@E~q!NLCkW7SFGi*2hc3p`R-#v$5_vY-w1 zG5e_F1oAq*{-->8wy#Fzo3*Ef(g9v14Lrp174eb5=OYIm{{0TsW}`>uFr;q`*sB(y zEyqJ$ViCk7keK5u`?HR5{{Z37S5(oXHIwGebVjY^q}2}GG32q%LV@&*4wPBd;H}}d zZEIRGMr4S=70GtU%o_@fiZ~13pKq&oM!opv)?LWZGU4Z-Qxm@q(7eh%E{`m#tP z?bU(YEdKzBp}TJJKB>(uH7(4O-D#TJuEc8i5$*lEmprk-=eYd!EqxXX4`fujieAAf z95Ux6f9enZQ=EgG=cS28)tXCM>zQUyURi3RERgY($m~G-=bW79uWR`UJeDdN=@f+# z#4?@k!}q5c3-{xms6B%OtzZ%)ESFENCb9BG(v%RwW*$drTy|1P;fnq9&t6)o3@a3C zba|Fx+|Z?s$IH%3mKp8ufu58>3=#?LUU>|q<^atCldzxV09w&82A<3^1{ zg;gd`Nnwo02GRh}+Z_-f1QV4tYLU<;u@FrPS!tk-m2!=Zm}UbxIQqEg2{grcDPK10 zYEF#SS!o02w$p?vzTtb4d-U3zck1Zo<#6^Tk=iAl2bshAcA-7;JtY15;(y{l#~%

lHI3{EIL|-o<2QIOz7Xvsgj{UkCl^adFox;g;a@$LHR(3-~ zt;g{v;y#n`?&Vq!18W-m_7>EdT1t{l8ZiYYk-@?#8QY#)t)=1X)ph>>3+Ub;t4_w9 zUsHLlPZY8sbPMU=s~&UC)7Q`X8YSO~A0PGm^`(w&TUeeX6H21JcbOo>Q914E*h1%w z_QzLvXW~DO{uRwOgQ)mb(zUz9%ckpbGz;gb^)ze_cAhy02dv_|NSMb$GQLMg#dlTp z2UXgC4-pXrNCt9w9er1B>pm{<{)^(O`bMX%>6%rGdHD+SScxUthd5?qwC>LUWbk?G zD2_+79GfGJZ8Io`w&y}J?A^bx=lu2a%UZvv{80WNTT-(cSk*NPFxS)Q*ycJas;ROx z0F~~{c+Lqq>#4j;<#TE(O*QO)QZI*je>y{sQidKlcLc(MO&JOhejQfF(Pf|;#)0VYGxg^qg zxm7XEwnBRn_;;qPx_+bM57pG}tf;K1N>tq( zj6dl!?La^z_b0A^@mGyJ8R4BC$kzNtTSTMtTj6UGma#jmdGgT)OL{ms&fm{pJ^m^9 z`%L(+@tec*cwQS6{2xnCma;COh?1<2C@!hA<6?!zJC^BH-WtL>mBZIHdRDeI8rJ~w zKK_#((*1u!wc-B&gC7cfRbnFd_5DV9tyA8ps{}G9mF1xugJ3bwJ-cEmcgWJMu`-fDh9+7|*aqqzf(-LRvMlS!^)-f_ob3upUAgBZ_vpmhnye6Ck{clvGCQJf=&%oPKOE zOHQ#{vrHjaBqw>;+jo*O4iEPH^`vinZ1`iQd_b?G+VKq9qFAq8L+O?xG#=CPiYDEZ z0C3stefr+e>eW&hl08PXrnZdNUq+M7jtLO@;%NZHWH$%%{yK9=E1OGDvaeU!Qh0N_ z1kvhIr7JVi64=}lXiVG0NUfH2W7|FP-#xL?7>nvU-Nup9#4}vXzFne?GLBTLo^hXS zbyXInt#ZOtFKUy^=6MzdQKjq7hQ`A zGj3g~ylv0#IV0`U($!qC9j!XZfFhP?_tuVoT#3J8Hs1bN`<};-&p_E&Ezr}G%Mz;2 zCrLmVfr0Y&zdn}FsD3k?^(?ZQ(nW5paYcOZS)?i%S)bBjTz=Es{&^TZKq?B_*tZ^z zK1O*OIpIHFn;80l{2n>ZM{bZ|GznHj^FF^iU9}9CAh6p+fV5I`?mM0c{{VibvzT>R zE0}D}d1ho~SqJGTUBSJG8+gDyNmAt2UTUM|-^fD#Zq25=nchKj&N1o!ZQ)%R^%?CAPf;?LBvvt`Ov5~2GOn7|wDjD~Aebzb*M0$z5)MiA z06n@|(j|~!v81ira;RhTF>H*ooGwl>yM4QUbJdecHTt!)BoS%=EUjkZ?R2iEgph6v zy~olIBi}uHE6ZzEo=q!MniigM*?$`~-zx#C+LJB9f4x?^*&{&oj;`2UQ zC&Yz^eY{{d_RmMlRbHrXW#bM%~r^z)Jr0Q5@8md$z+Ubc23$sXqOYbXo3eM7JV*kiv@LCW?MG*1SU zl1&YSujGm2lhVlD!5?P(_aAGrV=&%z%ca{Kb-#nex)}hSgj?fXOGRCI+_8rq`06L3ri;#` z^2=<=t44vmxS}yZQJjCJzd3dz+zoTGv$VLo649EfQ><4f=^bO7{ zz^-1Y+EB~p7sz(ORT$cd)Rbe?>uGd`r(!z-CTXtNF@;@1QrJf*bLsy8 zv}3U8d>dqlRhP{X(~ttzcLOkCo#29a$J9n!KW?XKBa(qi@mR4!84sA#A^kPZKt&#) z!{0dv*mPtn1sPo)=DRhdim^!JEhUO^`tmp^fRaI8{Cjj#*Pg>xhCppqg_+Nu?YnCX zG>irhAJRMfW2IDtvE7xYYIWtP#o&b{C|O^;gy;7!ANzFC+ssJq#MYXe(nUFDI~q)J zyo}{UXX*#P+n^#70g{{3)aR10xa}kP5=R=UDSX2pb_ef{G2b5jOD?7?Y8r<5kbKPB zWr;yk1Vm?KNB-g8vHKCwW;?Q4UzL(ECe|Q9kcS+V0OKbg@6z`YRM%(OI<;GjBu8Z2 z&cJ5}9oyU3W811$i-tP?0MBbgo_&2oaoS%SUL+X@C)LkjNYCe{HVY-77Dy*X7_$ebrd*Cr=dJFqgiUCwrk+eC5Zy9jr=PY4f~gXJ-zeM)nKzr z!%QpICIx1ZV2U+JVvp(C(r1u(!5HuF)c*j?9vxy5mFYaDR{6KoV#G<#M2?{PK<$H! z4x`*JMSh){ukw&tGs{uiY-DcSjM(~pSoEBYyLk68L|KAJDO+|_^A$E)fJc`O;|dAx zq<%V%EjG1H8LPIS(N|enBofSHAdW|xCM3?y->N?T z>U(3{^p?2Bi+WpjQg};=Y}bi#D{gIyf25E)vWO?KMM_QDq=vQpI>(;=MVPw2?*S2YKHflmz_;ce{IaibZ0xRuR&G21yF4y;iZWH#=^ zz(mLwF4$jDX#StK=cN{18&8p-RZ0X#QER!3L;=W=faDLyM_5Ct->)TfiJm7_I~U3x zTQ8{-9FPwuoM+ppYsYThp=LOe#1XtWMsO((t1ouAK=#5591Ex;?e^hb=L(lB+5RK`OxHuO8jHW^6-Rw9;B4y2i+o z1#k-%K9o5;wmSij&U!W_hAH8i7KQ*=x0xXba6ubbXVSwx`+ho{AOxfkmb<2lQA-_p z{IvP89AVZZCki76_U_7(dB;6T90tVZV1z*w+a?OT9r^S|Msv5=f9ug{P+hq*Y2q5O z1rhnk#Uo}IQeAVFAZH3rIv&)1T#HKP*S&VF2N?Y;`TV^Z5a4GTKLRy-cDdP)196i_iA|0LD7GO$mH&WBz(L zp^ke@8KDumU5cmF0-o*tN8hGPepxBpo5>Zcd5g9{yUXM1P@VSw0NhC*U^)W5CS6_| zh8g6JwO>pOU%yrUL~BkX-jU_5cp0{{WV(UhU|TX-$l*h`Au+BN@g3_vja`@^sR8l2S`-$|1tNZH0*^RC}o`o=m9%mMB2>&IsqeN$7!I zIG}|qK?-fbc+_NLINmtt9migvcLtYoav zgNH%bZ5@vzwnsym!k|Jao{DJq+U_RdcSRE9Cj%hrb@otq? zSw;~^07`q{9248WxAy9mMlqsIT0(b%LE&QKf*ag^dbHPuTeDc+_5_Ln-;I!{&h4ii z&$#dXx|QQ;BP$%`kZd4s91rSjj@)+l$5n(-SCSPn$gV%;SdhGAZNdKl#y|3ZJ!qeV zg0lFt#S`h)l4p`wkjBIP7}F{t+1(1{=e{yCpMC9WFEH6=fQ8OiOzWd9(l;;Ju!w_SC7@1I+dHJ`j7trl2<}TWeFG# z#Hho9GWhPf=NZRy{{W{%ESn_S=V%ND=Qsx=fWLmc!z2vKrTNQ@fX9#Vp5JbThEXC+ zAeVorfg>r#f28NW2080LE7^=9nE92~LUu${msuAW$oJ3N?bnda^Ht)p2|i1xbuNWj zfzPqQ9^Lw_@+^@r?ZFMWdYkNc;AfuwNxOIfPbzsW_xpc-fi+UL{lKpQfn0VY*ysNM zv$t21>)@047~{Wx$56`hrA^QQGjK*u0}PCuf%eZ(7V1~gCsA92n({`_?z zL}v=Tb_1~L4bCzhh6(hz817C63GO)l{{U{i^Al)b!w-$G+%|h-o~WWPm_n#$9=0HQ zvBpo|j-rZV*!{8Cck0$B9f=sp$NrrTlE`J|H)LrFsoRZ!4(BJ3NH`8ta!&)kdWtL0_R03?eOpO1IaQi7 z=CZe&85k;XdF_rc2;lp4VFx$^(cIwRlb)bi9qXgWpD!Ui#>aO6{y(=?6j4cfHPmCL zwn1W8%fw7=v-=VU2mAC`5*czx3xIG3zd8Q^+o3BYklV7-U291^o1u->N0c^)w5*81wwL{Ywl{x&w^BPOy@ojAfn$kEAkG2L-}BV{SR2?K#2#_guHrP@{2<9@ z_5-TSsG*X7D$Ei2QaF*w+^gw86r8d490C2v{Niv}mBRW@eDHtALdGRjL27mLe9}Np z0R)|^&nJw3xaf${Q8UhR$CHvWa(cBC-B(ub{B$ICBeO~y6(ma#NrqVw@~ns45#R6C zD2plx>`Rl=yubCJY11`$A z2kvptS13?}Xuv$<81K(fMMd`REx-dg{B0C?xz^?y-CY2*=-KO?KUx1Rq0 z0BrDj_wA0|MHZa+pW{!7z7x^v>c0;D7eVnts%h73Y8rU)B58Vnk~KqFAdXm>B@z=N zv1g2?6oBOI>tpD;vTGh6)AbaFdfz!(J1JJe1ez6a30D~-a-4&M$8LBh$I#$?ejQ1q zuxv!6DvJye&Pm+M*q(4c!;ai^OmL|&nTUHqPWj_apz;A32ZO*J^T$^K8QU05Iob^0^17 zqLZi*9d~Y(pDak+2c&(50OR}f`RYLG%)k-3exaU6LfEdh=uchdl@eqtx+w}c1Yqr9 z$UXTSjPZ`5h`<2sG1rX2S1fQo{ZQiro(I1_`Ra(t9Fc?mdWtF`w~P=M++)99f)8V! zp(kiSxo~&~IUTc-f7|~6Jx|n8S6+LLI`C&4{r=r}8CjSPN}M0T#(($fD6i_!02mw( zVfN}5-nEMo%<3|HwHa)4fDhldM0FHZ)pZ}Jy8>QTNXCCWANTLoGi*6*kVpUpB=r!6&rwAYjSZEUC=vm;cu}3dZ2hy(`*mn2wo)c=(=xGBk5)1>{@joJ zbWc#pBE=YYJ6AlhI0N#39YqvXqBZG74&^0R)KzwdKIb0UJooqNcVMuy@<18kOMl>Z z>i+=U+uOfTtYKbK3mwh7mLv`UImpQ2jyjX5kd_3M*m6cQ`QZNm zzka3aD6HDMiN~mn6OM8J0N8rJs_Nc%o<`hoJ^G3-bKAf8>N3PS0me^0l5@x3+x_~N zpv+|2j&^w!gk=gVlAMrpj>L>`aoC=sig0r0DpdW*?gv+#X-?vb?+!UzG za>^JH+mH6|)KN$aZS^Pz-<)u*wrF!()qFZoAL<2JGlL)BioP2xK$xsW0~&C;$6`&z#wv`BhsXH9CA*1 zKG?@pD>B)VVUr`s17Xez_T+nGp5FaS6hO%&jAU6Ht2!4YRNxJx+Z=O_{{0Z(F<99H zt9J!*G5-MBj;=^nh7#Bd>xg-wq#+ZX${6hDAOc1YKcBZoGVTB#+0R3!WmsmF9w`?- zg2ZDyVB>?-$s)VTsz_vgt;fCr{{YaAsHleD8JS|6%Q7nYn;()f`+@v%*m0hviQYw+ zv@aglDiz4}f$lNvdiB{OZ!z2|90C}C0Vf0f$-wH_T1cwPBvHKb1tlU30cIY+o(6v> z9Yq$gT9f|(GF|(v)qod~i7O(5?HR`>?lb;6nkv)j)oppYk)O_D{$$Fr#}Lj@Fg}tO z)6c&|JG2p3v}3T*L~zU>KAz=@e&9#A!Rd68+P$wyS)s9~)))xwEoStc-pq_Ya{I3!{l`~Tis#M4XXXS@qmb|SNOCp>!c^J!m!S?%(jsh|# zt_qrKBS@lVwqvbO5$4;LY@p|H$r&JzZsYUNcLNPl2*i}5uF|tayW4EhFvwT$hTZDi zILAgLLE3d%@v6e@8ds5lSpgX;SF)}+80yNg{H4g!7#7m`V0m$Z7t8OM&){*#L*}wn z;LcH1(rVUCdl;C;;ZjH|i2Su<=~YqR2ZDQJlhGGvhLn)WBD?u)BOY23+mCDk!Tfu5 z0_o5E`lZ<{!!)&#o+-lvA_u@RpJJ_yZXj?z{PiGtWU8jh#RPzm;TtMf_NX6W_vk^~ zP*aRY2tPHyoaMCzNMzbpX z$|nRKPZ=NFoOCX0q!6yXB1e}Co_~j7{{RjAQt?lP>{xMP%#UI%Iz(?alyJ=P1b6=c zsksVBGCMchvrpqL(O=-dRJR_tr}%lQ>s1uCp$6eM>MOKpNZ_#NBx3;ezi4<1!z=MN z-;ZI?po7JBL}tZ^)GV?Ei)e~N+aq>HG1+oYx_=XBnqP~&CpL$#Xu{1D0El${ll(0g{4Zz~*Z6QAA&xyX ze>$=)*G&>5BF$KOBlWSvx{$?y;eC~Q3;3zhW!1h5czPAoTSlJ0iYipAsfbI>UTZS4 zFbR>6zz#jQ=Z?BlN75#TvV!>C$vEpoYaSNy4~;*B ze++0;w3}MqkAGf@?z3*qc_fCEXynHnL|`UKZ&ASp6zg>b+h{#{d zjc@@283dD)k`6cp4J{>pez&x|)x1?tNW31*Qegw&8=sCR?5uO)SMd4rnzoDMkBHah z*L+132+3MN_A5&woI@mra2e%A+M|^_lrhQcq`XC@9})N$#o7fsi$=xBS~%ygUE(b! z+>OjnBREpvjz&KnH%W!9%N@BU!OIk4a2RKw$o~Mhppt0WyqJr~uK`ntgZWB6-+Uf% z$rG_&K3m5N zvn+D3Qh+cc{Vqcj*L^*ZXef#ouCo$jVBm=kJ1FiO1MSkSTS?QrL*ba0RMR2WMN6MG z9eZ^|h#oVvB8K`hJMqU%8=CFKa_;;mVN*@~B^hKpb5A5XW`DBd4}#2id1X>pWS1cJoIJv*{Kpaq&i`YURb}ad%ni@bX+u z@hic$JQMs9=rik)*3~t6^~8r<)oRo+$sd^^avCzHgoRczPBwsXj*|Rc@Ry1;dVdae z{WrsA=&z&60SiH=nloY6J+e+nkLB1l^OJzQ4l~x;{w@f+@S{x8mvv)mVG3B0US?Ez z5f{vjbLK1dX2Cm2$sPLW?Ga#)!hRjCJqW_tj2WRgF~ACK5#avC0O1Zs7;*2`meq=2 z7Ooro5n*3YI%7!<6xvA~$US_|n&STeh`+-J#NQo!Sih*y@sds9n(I~#7f$|bJS(Oj zB}9_P7+sFa+oVtk2LJ-T*q6nhf^>cq&Eai+C~r+z#vrp|oPKQATA6 z1_P1XucR<)a6-NY+r;Y&obPl}-^WOw(Iu-3EmFgDY5z9*4 zJK`}CcL@i&_ahnW9_NQ}7p1xX01h;JiVkT6xQr5b?6d{1;(x$&d=FOkodW9moYjS` zJ4=047I~M-R+2Z{yUURDDn&zY8DD+C&-PvMDWPrRXzD~m%`K`CsN*$qa4m;<+TJ!$^#na*b zkK#>M&XG>WnWtR8Ud7!2O3hkDNOmoFg9C{1g6uiS&U$9Xmq^0t{s+bulmMjmJU0Mw zjsnyEI`NI4j9(i(E#a>P_&-(BZ9yf7n(W$qaZhfGlz%a0EH=m)e88u$2c6vY-8A5q zH1pzEqFAIAFvZbRQGN;O&23wv8;vQ_qh|iMPz<8`4#>%aBVPumB!HuM+%N@GpS= z0MPJ0hi=b|ruk-MwI$CklD^=EDRYHnKzA%zD3!?az&atU!)h+m=4)wJg@hs7q4`sm{O2vS8 zU=mJpdcDxtTrGP}@jcF_U1hh~I05fZyWD}*V*dcchJ`6NUOLrhtyM#BvY-(k zoCqMXCo8yiz`*---Z54*NaDVe&*n5?qLvGsA*T_QSaM%KvgY>A=|3hkOn3C6?u&lxx$fzl?csI^o<<;QG^BU<&RF}-NQ zk|Sf1uK6Q=20g}4Jw{=7n}r3*w50Hj%GP9(G_?$nnS^F2q9_OtFL(&aHo9>TQ-&e&>2eMbIx+TGv`=cab!ij;_{EDNihB{4wWn_x}JL zW!1zn)rv-nS$D{&mgkJ&wu}aRp5I~CB(-EsIt#5miRF%2Jej4Cq*6*70yi1T0sB`z zuej>zbv;U1Bd2H>a*rZSav2SHCE1lEE;ofd704t106h!6<@6BH8UX04RB3M8G~=^s zD$uJ~u{%}VHa32Ma7Y--e@|}xeDBa_hsS^XUq{SZ8lIo0U!P4aMVMBUK~xrK;>p{V zE9PggBN#mO^bWC#zn2g4S?h@@OA?81J4-$@BAk*)R&(3G-1~L&_uyB7{80Y@{7QAN z68M8mp0<;s`P0rmMq1Jruw0o~f>5x)iGs1n0G_nd0E4)6Uo`QZ8=JdpY7|=_)Mt9onJxf}NV0hvIp^{%MV<*yql$>tv0v`VT6DFpWbgLIN$)TDRVDZYa?|DWx zw+KBYayMXPbJh=ar-MwV4yj&4W;vYB(sq(XRuup6sN3 zEyg|b)IlDvh)@=mbyz@LAc|E*IcIh(cM-T{ySKi22Fl{X+O0s!;ocoWSv3vDH6K&U z5#>vM&<+RNqGpn;I$obNL2v1;FKZRCk(dh&D%_muY5QeHQ{D!P?&%{F6Z-GaNYI0uq@liQ(UuO(aMWoq;4QcH(;Njnst zV&^>m@XhVVetOiu8~!X=_(}XV_>;!9{0~2itmzOM@#)lD&E^urVc5rXfe9hDXKpe{ z9dXZvKlp|CJ-i=C_`kuI==gzG(Gpu$uIkOWEb?Rrd~>sg#~+@RR_2um6&)U{k$bCH z>0~y!iQ)k`_%EmR?7_cKjhsOf*D}dE$?Ak4?}OVNhC7bmev(ozEKs{CwPJ1R%^q4c zJG~9JwpZK?^~SV+jGuNFR(xeYrGoK4oN=hddld37e5Rw z)}Z>DYdTZgc@lwig=4SoQNo!^5sSO~9W#E~SH4maeE{ zRj(qenO!TP70{1KV*Su#*bb+!dKmR79tDrl6C$HV8_nF?kdxhyumpDNmaTsjpAW5Q zb5Ev2si~gnOCK>DaQVAWszCd&(UaSb-6&t;lSyqtrQIjOy2ps&jQpZJXp12w!YLT# z`97CXk%N$WFy@|#?eSlS>Nqx?z;QhWO6xD1o?5dQWtN&FjNL{0CnF`D&kvr!0f0C; z>AuNDVdhydODjaI(!V8#EH-D*amWWCb%<$`-Ls=<7Vb$tktU}DTDzuNgMX03?b#SV zOA*QZcE?jw)v4IE9-C(BR=n08C9yPEHVX11PT=8t$WLxKJoS0#y=@n^vqeU5Rz+ec zWYlZXnWYzU%&J@TghL~dj26kxKK}rYI`srmXntGFwk3gx`Iv?`li6|YgW0=qckui9~*M%eAA+Ze8BMle+}ubK9eX z8CrIptIA5UPg?x;AhN)jm(Q$rNHc&~fIS1*fA#B`KZ?oqbp8{3O%{Oz-+6CCr`hw! zO8RV8AJj-B9m||7gq(tZzg-7oRIxP!*xmrVW)GywG!S=3=K zT00V%7zpyQ@5vrmJe6KZBxIi5Z%Wnd>RL9VM8RrlBh%fZtqUNMb=p_U5=rO`bGTmhDP? zLey)hNvXy}SlsOpZtp31*hZW+kd=Y1PUDaJx;z>9?`hU!?lzRUFgmwP_ zfZrZ`FXBtOT|W`{eyz8b)Z!rZn3Wi3FaH2jdB>K#?!nJ~wqK3^0ElROSNuNfJ`T|9 z>V6;AwJ8c)SZj$Pvs5uH2?@FPv~1Cy06buW&t21hMbhqS5zDO6i&KJ|!z&qL6IL?h z@TvP-k_pa1>s;wS3_Km--A*G@!jsh#CjONIWOtzX*7TLh$v-qm81MMG#4K5&amHZf{8> z1Yxy7K8QWbz2fWiFEn=z~x*k3l76>{iLey1ZRvB&tFaS zdh~QXR@27}dUc6zOq#i&A(PFJH>HH9l~a&F055(zk6h6_E3bGKJp*0P;nyqKu-;^P zoJ(LMk(>Z{86M}~p8Z_zUxPck4M0-@FX2b!|JwqVk=^N-d~bAVK={ zSoe+oBY30ug7LPS;Gc(-piMk?LsgqCN3Qw!*$vkHm>dzKG zJv6jB3FUU5;SEOlzm2-7{{Yntwm&Oi$Zzs_NwlwtJ`2=5BVPQPo5M_*3u}t*zR*Tf}}S(kM9=R;_vKhb$Ko7M+x`D?h1J06^<|czTA7qG=j$hcxXC z-@*x5tKveehXV{SM=0;=#{)c!bVF}d>olMGoC3?{vIhhiC48>%;qj-%Ux?P*O@~#F zR@GxN+ode+5vy6)vPB^WZWVBLa#-Z|>!rRid=t_98~hIH^UXE3*EH)DXSaH7v$U>^ z09jRbkpT=7eooMN1dR39+6IrOcseQn0O4&5PSYH#eES$ZWdJ3Wi)4d?+-K}D)`b2i z{A{$phRal8uO6#=Th%FxGzy}XhC2W{M!5u(R}4-{p2t08YapG*WqB%|6QgHF;`;6W z(d0Od-_yy&{=P}a@aZM_{{Vph01DUCWRljerZd4_3?y)Auq@0`W5R;Ot6{Q9I2?|* zEP^|gt1ZT!BzPJqljw52*|z&}{{3Ko33Qt}2fz;rX?nb`sNSU;HJDXIF(hnqBUU5U z2313M$ZmewkMnA8thKwkh-q!hwxw?^yxANs+(pN%0qQ?bTG{}Bz3+wFUY?6b+X!@L z;%CiAQ0Bd=f*C4lhbs)`P<+4#XD0+?_5&R`)1D~xD;JU>UIvjCNVn~D%I@^1zDFeS z_893TRONjkD=nz&>$Uy|Yevc*EXOXbHCsriV4 z@bNkAISuLz0ORk~;d=9)is>hLZ<%!qYe#V{R-}Ja$a`(haHH5BeCjVmu+y{Mzsjd*SqxS82nMqraS z7$LTtC?t#=_Z?yylSy+@%fR@N{{TT6!HPdKJFx5zq(2Sz;|D!a1ddipjV~B5zIk2v z^ZY|m@juUMre6>L053%s?Ee5JVH)v=MP_E&3Hn)ao|#$k&&TVDYJFo-*R?99NTd`s z1R+_hE@P3ljHn}(`yX#^yVz6Htz4}Kl?Az=z=r%9d~yXcCe?=Na$Rw@#%FVuVpmB zIVoBxTWc@}ocBDRsEqN}ma(lUY4|9+6|Slg}h0r1VcWSs)hu{9-ru-j%bvy9 z0i29`d-ay11B4af{8MRXairCK&-4OXcp&s269H*Ig&z;1_=P^Bs9V)6QPHVLfZIy` zZHrFrmkT5M2Hx$?IqW<2*S;O_CXeAtP{pBDuSU3$W_xeCUpOZP%Zy~_fCnDNIc>(RQ+qe3-ltIDyip>%;`m0zQ!C3bdES~vr43y; zY)3^IP&?(fa!e^+!cgvkio}&uTj1AIpOMhW`MXjN@@)Nx{M6@H=C_TG=&& zX0jU7NmEZPB=S!0wmAsna<_1E$J_DKGc;nF#>y;NmQ?cN@_}_+WRRau559l#)K%=( zYYC|IYg4ISU}uya_oe+yZ;Z5n0fpzB9P$2oNXjOlk0j$&u^Q$Y(lC>8WBz~`z$Er8 zdwu%HCAo4>JjE2)djR@NBdY2ZXs-9lO%Bz5J$9$ai zQWcOw$tBaKmeMDZlDg;TtBH$`EDYx^eIa{oIV5}ZOG8qXSSwc%T87|PveCVmHFS`tX$Cm-`nbr?Rvme^#XhLX zYNS?H2tH*8o0H2q2bKssb_3r%2{M6ss~Xkx(M~xXr7WuxOzGwmo#owBpYkP9wOd+z-7P5TRab0kpT(vrQIEeY(Zq|@cTt>d0Y zWf&ihsyHCjwK;9UMo~0_%@pMTqcP)YB;*W!d-SqX07FyMG}hDFm6V@MsH5hcc5yIf z+aAIDww~dRIzLFB%Iend->n^3BbjQ%>miaUosLkqx~qHVAbvWwdSm5fjqAaEjHmQe zvd1DbVU)2Xo=83Vf`K(PNcA}kizHAOK2-@J3mk8gJ^ujTo}fVU**n(Kz|@bK6TYE2 z4r*2#q*n(Ip4&h@kN&+VlA=WN>GRrqGshd9LRnM~F*^iI3^QlH9Dd%9zjgtr*0&VN z5v<}%&n(-O2W+ckmIU*Rk`HK&;(0vL8QYEzk&i3E)I2RwhC zvr7pLy3S^=BE+usgifb=NaG_4INDD={{XjG9Fgj@wIqVztra^^vPCOc%(moHg3E$- zpJE6caxu_ym>u0Oj=g8IGseP;My{@5c4R1fkW_<{_Uqc_FDb2F3Zh7nH=7xgXc!Kx z+^AukkICqokMjZK)4&qfh?uh;H%a|OcIVrnZeEV2k$$B%XObWq+)~k58WlfUAYr;k zKVgB@CM8nMI!QgbL{Uh)0i_uzVjFS{OgKFA&VBl5Wtb&LG1a0gSx~|2?SnG&zFg$; zc^Ehc+oW1-a%vhJyV_XX=5&E01!Qn=7t}JiUic@U@zz0NnL2#t3(s#-4kU`ak&h-w zh{}=9UufO0|@yGRuhB{^vwPriB2eD&(ckm_1gD>90* z+f{ol>U05j5>x8Q9r`Cw(#5N-PRygv-&%doQfP{c%pO)RJA zVZc6ScK}BKk<PPmbL9tI2uW6B&;K|T5asO0B!-hmD??#x zxteOwHfA^=5ROJj!S)>(!lRT%omO|cw{TISh^G zfuzSuAt{Phg2>r6S9+?j^&ESgcj^*h2!Nq>uFxbhz|v0l!rCfwug7;ilxMf+j{Njg zws+a7HL50#o>aV{N7Bl00|WHr_RdF96r)0ws+KIs(CT0`Y!2lic_(mDj2}n`zkdAm zO&BIwqe%g^ErK4@PJG;>eJg{G2Yj4$Lnx*dL-NyGg*KeBD1!Y-%f=rWPcR=)1b>dA zv1ZNCA+M&(X`^DhLxRD{&SOmaj(yGtY%FJ5_?f2+PhQcQkI)EZ3UUE;6WT^NCk#*7#Sq~ zdgcEB;p;^hTLH?sXe`35=wp?98Ki=Qeeg6P;(vU3hNjpzYF%h%pSFaoeyK%IizTVjGdT&R| zvueS!ww#i<72>LQg+ShrLEvuucIi+U((NQRrJDN4UPv98WUd+cEJjB?hdgwAFwY*M zur-98k+_-A=2FLV6~M_*KCV4IXgOY`rC(a4mn=_KTZ@2HAvL@93Or=j*Um5B?#xQ5>=<>?S>Rh?LIvv8|-ok1pYdT z-HBzbZe2L9kdvvEkQTsEjjDULKX*KIDd5VAdr;|gpHrIb3G(qHkVfMqZa%NTKe=;} z*FOIM5nmAH_sEi zYaU+tP^f5RkPM6=;{boR-#vWw`0B~yfBqsh{5#?{xh{*R>D6VgP1%|0!9Lk0NQfS? zWE>HKM;&9isZyOXS;>GsNnA}@@L5^9q2do5#C#Uv{u{m*Rq%&`pI_DKwa*z|z2?`B z-j1QPqZn<61Q8*XWX^NR9r4Fo8{;R#HTb9ScHJtPR9Adg8>pkISdCg&WpKt3E9Ao- z6#A7$bIwN{Z+4QZNkT}M$!c^Xp-n3SfX4~ih-2p@0y!ieJM^$Et90iOu-hm(bRpg+ z-N}%jqbJfnt`2%>x25dE94FOdvazN3M*BvB=M0`QdwO(VFf?0sZ|d52hP+0%E8Eg6 zOI|%bSb&zJ2IMM&SJc1|!-Mzha(pDv^<6*XiK(N(HnpNnJ~e|A1u&>zFfvL#AO{_o za(i`_d}jD>sl)NckHl>rd8LO|MuS_?#T8bDbWo7_URvc8g<{*u8SR16PX~Nd)Y=N3 z7Vrmv+AT)&OAXIAM3t*eD&u6plYq1vx#@e68Z9~Ie5!E5n^gj&VDQ!|WU*-&`8R2;tWF~zef!{eNuA%Vm zzu~VM>C3I@mtJvN1sc6Mtc6;$xCA2w<~13@7XZoZ2V8Ym!9Fa#@gMmw{5f`n(?rht z)}vB*p_l|N=2t76k_cWq<2mV*qyZ5^KIO_=Bl@MvATNCe=7pwV16lBoIj7E{dQMFu>;+ z&Q5dJO8jW}vEj@A00w+#;4cj^)HOX$0Zw;+)Pl4#xM`$kByJ@}-K+GHd-TWndhmrk z6XC~;ykW0dtv`pNqh30cBXnhTNrv+>a%0)(U>gmRc_SSS%`1x48rE2XnpI`TKQa9siYGoD60`sBai z^8STS;%0@Y&dRV&EdKz@Yw8Og*qTu79Iq=75!V0%j11#FWuF&*BV72e|>QOGuV%0g!i>NRG zq>WLA0)x0N+;QJ0o~Rm?Do7X~ulD=lBIUQbkhh_2@0uZ`xWp18pI&-md#1iS@Lm4^ ziGRb#h;$DPYI@-$yU6aW|eBORxzNK%{1wXjQe!GLg{tWQ{0K>lkN8yhPNi`ih3zFE3T2KQ` zISkfhc*62P9*lc*(twg^s$M@?^N^Yp}l07>4 zar`e)eWJ5c*N8qNMz83yH^ld-nYkx4%wVPUPk2egY7+ocGkO7P? zBm{RO9nO01eM$>bXyVM0Scc{GQFWq;CW)m}lyZX{F!d<*?bi_K+I<}x{{V@nh^gst zO&uYwAOsUD?^?^es3#rC1CB@?`tJzoTGOb<6wt&S6i)kG<+m>F;YT2hf>icBvN-Ck zDf=p94&`$63Sy1z%@9cqfC>1|)dOCS&FQyd8gBPvlPE>m=fma7dI+EOB zXu&0gPb{+R2*}(p9^d?_>fos%aZkkCe;xJj;*(eKj*p}3dT)UKTC(U;Y4!78SXE8$ zJk~p-1_S}QcpRzk(3Cz9d|iDbK^YH*b%)I1y5%&c|JP=6wPTz6;`o`)T%(#-g zjpmC^{_WMORB#8NG4;>c?S;iUfAIU_>Y6NeH9r{F@ZE{+&V$PHt~y7M5V1beleFaV z*4prIz%K~+FXKP_ZE^LV5%|8e3sX#!Q2jcz42WZ~Y8u!KT;#48wgx@<>c5Czhrbp4 zN8x`4*!Xd%U8ARIv&`Nk(DZxe3l^ec4SBZ@tzvX<3t$=23pq3=X`H?f2xk6=~`E70`2Oxy9mlPC)I_ zc+WifmD>}om#t;ylJCozb0jShfiv`u2aYLN8K_eK#jPsmz(LV>g7x4y-e-dkd z7W`DVuia=@OYo~t9yD~1c=H{Q9Em{(ZdilvIUQ(iN_7qo(if)F^|opc*-Ddu0!ci4 z_@BPhwltV*>DpRe)EanXSp4}#h{Um&)Z=E+jk}NEC#xE)KR04!s%|{RrFh9?jy7S9 z>bcMUanqP0md#eVU1c>4%M0yt>g0}NAoePI1K+8t8W77-RY8mayPv=3u4(=#{26ys_#vctwkXq3 zJ{;E}+iBgSDlEBE99TZN6~edM8SmFl{H#=b5X`jFTGmEqm7DZg3vLH!;XlW2mtWHp zQjRDt>5*8{Rkq11&ALB*geTnO^W1&<7qC5rr-HLx+Y7sAQYVoTxWD*wj!C{QYueP2 zL1Mjn3bMfSuaJUCFeEX$65}VZz!CIZtK;v6-Z=30$0>YO@ZuV} zubp(WRwLz_lWoCMw1sBd$trk1amQGX#4Q`*tT(FbKM;H&T77nB4AJP5{Ka~ZHr0j` zjF9hwU59hr_1Z5k$%$)(Htq3InHd$%cBmM}A05EPefpi^u~yvHAkyTDNMu1)yvzu) z2|JnG5roO(Jb~@gLm-^2*M1Vyu0!^c-R4YjD~r5i;6ICgIPm@5b5znSEP6}VpH0#0 z*>?@Q^yO&dC5t#wxsaXBo=NK=_*wDO{s{PWYr|eA&}>b2O_E3}`Jh*kvALEBgEycf z5LJ~=r-G-yU5e1brCo>QC4=T!wodwRcxv~6}* zhs&CIhWX@TrD1e#>dFr+IpA~~Hj?J@xexH2S|P5ou0zLHXCHkyTvgzo3)uMC@n2Kd zJ|TGZw3^gpj{WUAt)jEb8xpRx)x&ve#X_{7ZgJLc@#5#f=lEBk={^jOq@FCLX{Xah zg9IrW#7dcDvz~VizLy7*dtvwavb-tq8^HPwxmM=C9KI*iBdz7dPgIsal#Wx(jA2Y=^T;Q*dv%X(QqtD}C$HaC z#iyfdRUGOyD7DgmJC7cac>1nn@QnWe6g(T^s=heTydQT~)n2rb)t^+;<&?(K4Xre9 z-Cu5T_v>+KKNS8wYBwiu2mCfICzBF3p*E9Z)59(?BfmRik+a>#-rk_a`HxZ3j#T znD~DZyOzEcuWZe#Sz}Qe&syF0k3$|75j1!JJ%JCIi=7{KhKjk+2O`)Q)jd~IQa0il1_4!Qv7i36| z^C+&ZZCSU)ELF?NmHz-yvxC2Hx$M85vMO*SSFK#tB;v@6%Z<|xSv!_1-2NBS_a~!} zjV1unOQ~0$tc;Ng!BxN`^#;&8XS`$T=?BfpscMtjiYb{k5h~RoVpb>85sCC5A6KyZ zb8{-%>rhv^8p$zU6h2e1b}o{g_Dy3(vb?MMU0rHFik zxH&$@9^LxBOAy(dEqIF}Jj-%6Bs6Y6Yi{QsZarSu>RmP|8l_dM48mC4vq@n`6 zho?CE@%ZU!z`;^I8&R`5R~BcURc7mM7n+bY`Pcox27YjfE}qvIZ*{36Z_Ga^oWh1mhn0>3Us>H9=M5Q$49S z%R5Y5RRm|wVtE<;soeegin&+4r?WfKiqqGz6wP2pRHBA&Q6+n}2LN%7r3O0lr;|<_ zb*J>$uq)+Ejh{8#0sz^b`05FjVvbp9PYT?OiEUnH&z#KIW4!XDdkl38nPb%=yIyw* z6PAiVaT0zQ42B<^^${;sESRd-H7QL4*m%#)v6xtmh6pR32=*tpS4znUj*CI_uMpi$ z8FK{6TRTy^6Q5T&$NGhU!x+fGW*x~Of<3xxUrL4_1ZrA9 z)9XnVqT%%l=DygZd~Or{^Y6DKpYhO?>S`7*Fuy3TD6t@#ypfau<0u2EK3EC(?ZPn0%M>z9t6=Vk`f5Q4jLRD@5~v({eaBH#og}jhd8#Wz4czNzL*RM+z6Kg(>_3nhCLh;b;0~=caG+F{I#rg{n-Lws8R2szlDA8rB=Mg8H$`OAXO6;@iJdFFu`c1}D`YY&dYqqfbJc>Zsmua!v&PmWg+oHLVmqRD zW0eb>WtRsd9Su^vLc-d&4V#!KOmZtQnV0%gINHD8C-2d7#WU(UgPUeaRz+y1LzYy= zNkQ2A`-9JZrfQZo6H>eyqP@6F51NhkMKZtLPZ^KwF`k>%0pS{Cidt|Jkxn^`kmdZZ zEw^EoHvOmaLF1xy?c!4alH4~1kZa2t1)T^Rlo8#qInUd_L8P$5sp-}oB-BlLq+2zu zKvp?MHlO!jsPqjxO3Pwt;%oM*u#8Q={{W&gFgX}(fx!#TJ^F;o7KlzA#-AKE6eaA; z)+{c-WtVGuSPXJU^bR^XuB6(&rFH-#G5Jzm5T;Z_NBY3FKquedp`D?dQ%00EIF=<0 zsy|Q`IassVf4)ce>K3G}sLK-0ONI+HQH_8w`aoWH{{ZRIiImWs?uN8$W#cbS8$qL< z#exCd+C~2WxOOUY(KOZ>G`Z|gN?Ov(Hs(ZdvIKFr%m5Ed`-S^-mYR8Vr#2ymQb}5J zBkwH#0JwxXz#i?>c_OnT!Ai}E1gl;@nrQx;Qg&BH_H1x-?bAmXS0NjwX!BH~9hO>^ za|6cqp(-Vj`=EX@`0s|u2k+If>5HgWyDf=C%R*S>mKfuZ5Lef{mN*+n82z$Ugywv&t9b4~?cb!K$xAiZ z-%v;`%_3NW)VrEkQ_6}^#Dy=CHv@s+IOv*I)-i4xbsF`jXndJ$OO}z;<-t+IaeQL6*8MpTkY43bBFHxr+1baammJIM_wmYA-Xda6H76}v_X z_x}Lb^VNV#G;G%3ZD(aQk||iRd7VqM%Z?DY?mz(>dj;>4&qG*fouHQ8R)#ZWWr9fm z0Qwz(9KZHG)cyUBP)T+%;#q}z{(LbmK31}KLby23cTvFrjOU#7QyVQsZ9Q~J3Pjbm zGZ+yR;iO^NTkRkIy%y4qp%q-P)GngN@#4zZngZmOEW3B9JnjR7(GkI@*p?=Gfi##$ z%QmSjgU^_;&z7;D+CQlKbS%}HcqbFXEl47Cl4}8q%M&R2jz>F>Z~+7F)v7GmnkXex zesd|7Iin{K?-^ER2Mdp}2c^an2PpRqCc9R65va_h!6HgVBn0gqU;h9uJ&p+b^*5i3 zQT)YuW0VK3->e#T+H!{^?c6@yC$$5_X|<0!FF$aPXX<>$-&P3jIrlvNdcH9ttTIPP zBO-=GbCfN&E*XCR0AezFgq{;qU!9L^5Jw?}7C|EX!EDX}&OP`ae{XVnig}GY6_lX6 zeeEpG9DvLN2K1pP_7U&UP`m>|7GBFYly=#azR4nuxKvg5Iq#fj-=?wGhSr3;H8m5} zpKOL9#DtxynLfks+n|!Dz*5qh&5Kqx)O45T%g0&eA{CSz`oZI9_6MS3`I&W;THbBD zmMlA1m1XkTO0Gf2W*PSATHiS&Y^;Hcz&x-AIVl_yJ>uw>Q2_TWcg`x_{9^c=j{#=QtiK4Y6sL-r(31-7b zgX-svxjpfYgf>%Cl(R6?U1fB$X;7jVfQ-K8##A>90LML#+o=#kKD86o0#h0hV`~tu zq;cPdZNs_gCzi5af@$KBS{P4|vK)qV{;ZBM>;?h+^>iLpiqvP`<=nr_GqFCb@WgO9 zJ;25~g^+?_I;RiJ=~SP~I|wd+P~h=_yYHX3w^vU#*&}6DO7d{d7X~t&-*;>dz+;op z&`)9rq(LjwWrUHO`p(>qbnQ7z(dL8cRrkQKg`n-^HOT? z{O6r347Nta$1Z)254XR!K*}!056U_jkfKK=_B&m}A4c8}AmlLPw;c*Dsn`u-cSc98 z8b6{)-vU$nvcBB?`i9ku5g4V8v_4Mu`KcsgN=CiF0A-k-!===1WZYXUkR%c^S*qYz;d54TVab9Aw#ZLKz#}r_u@JlfJh5?t;_QCh-cg((4n9m_v`yw(VvYZ%; zXM_3UzqeW!;T?;&EO?^zrjMI zDLl8Un!2ba7^_MH# z2t`7rB3PSqjBr>If3ZI2^VhN}U_8pDV|~a+?c=}xy#_y8Xy;XsN*6FJ%v1nIGl9wW z$ZkhamYF1p48lsw=%0Fqd0CDzf!nHyD8~qhn5AOoRKR@ly+o~?| zLkXAJvk$==eI-D`Pb4~IkV;?x}(T)B}|YB;~?Yl`RAz=x?K@QrQG1=wS z0LuRWey)t}gCvqqe6HWeZiT|bO~dUQ4&`M}zhjTTx99!(v6{|fj0IUX?w(#ssm2BY z?hiivW1garm|*QVW1Q!nasL3;>X`vx_yyD*ryaA<%w}~$hswz+>Q^k@*-}miZ1N6A zw^QV?+n;_1An<S7Cq(NcIPJ?5%%guMGDv(k09jd{kiHmjLsz!#HcfX zp|=7*z~i_6dX5*D2M*;OYTXWt#Ok8ZCj@~84)R)mPc`CLbiHsoU;+o{Pp z01=y&~8SS63#~pf-`IAo`S8@@MtVsZme%L)!Duh#g zBxHhk$Q`;B5Jg|q?#>2YM#fm<89v|pb?mAnWyH*~VC~x9>`przXYJHvyro(hy&_*% z9>5Sl`}6+*+3nSZYTq?JVWUE43hNsrY7dlgyDgu=ALMb-yHA!tC3x;TkMq<~#)~c# zC||2+0|1gqKiucPzdaCsp2f5F>WZSEP~*^R^RJh>Cgkf1UyH*gMD?!4naj*2)Vo_dNXb10Au0;Rk5 z+A;q5IsV`MS^BPr%!S)HNb)wawpjMyf;jts^*V|xl z^PYdlL0VffLFHAME6Q+8teeV>!#G|tNZd1?4h|1)qKLLE5s1M)z?={B)DWekK^Dx* z^96A7K$}z_`#~rF06FSamNu4DRt2MAu0F(ofAk}%LCDWhMP0Gn^d$aaPcAeMCJ6}n z2;;E~+fF&%SYw#xc}UU0NuhtrRfEvBs;l zQ6t!>KEQhpI2{?(UZx!7Fx+$85B{%Lk&-#a5BcgSp=a`Qp~Q{3!Bg~&ypQ+y>L{eo1M}1hca7L! zyN1%IA;+=f+n@Y>x{xxwXzG0@k&k|@E{_gFZdc$GZvOz-j-rY|>0Vnulhxf?c;}u6 zZmk7fL#Yf1^swiH)KOl0cF$Ik>)Z*>F^_JjXL08v*kiX>^%PJBEXr5ZtN|Qg`|^MB z?f(GQpP`pK42=+3ijB&o79eK>Jbrp0cJH2|pk-Eh$8*r`kG>}pG-`yGPzE24#F4=F z;~atQkN_w_*S>C*h>{Vtm^0v&INQNFKaMf}{ZG_Zygy0fJqzbWvM0kIG=QMScYnCX zMn65eB$5EY-Ot~s)VB9sjG=M0i3fKd-#_Q5qLlq7jP+;=qiFv4Jmaf#y>g5I$mDbH z$m(9AiqL(J1m^=icnKiq8PBoLSM>_0UB?3~*z8>`B4x*kJpN z%jKYKu`9KU5?tW%&Uxf>@A&%;sy-_yjRYvXDwW0*em%eYKet6FK$Q)tnmEL9OB8lw zJ78Jc3nA`%a(K@Jt6m10#ECeJL%JyxMp<8awsOP~k&w6^_#otUddXwv5P1V>Y&!`! zRly;L9OUtjZm(uzCQ;E>>)j^ZcBP5a!x!`l0{{U~l zUit<-ETN>p+NZzV~KgS$&I(c!}c%+}qmR=PkY!U$NkAHqZ{{2J}Q2`s~Ji^6&AQT*f-{1ZJ03BL} zQoETHpD_I|#@z7TyW<>n>@L#8#G}STvU=14a7f%g2e|xo=x;Sw8OC$!1y3J>KK(^X zIOCOUSo0?Hk=Pi}pdMJj1#&x#lNPa9?87sKndXV(-Q>pEbtADE7{EMZ?bN|xo;aP6foTDj z7E%#k7%hYN;~;bxvmc+QU5>`uF9~we%3@@1r|8FT@9*u`u+JRQ*p6AFvoVl)v%=fF zrN_~deGS<0?bmRb%r97E}_(L>|kZ@1DG9rT$iqqDxjp zD>GLyfg+!E37jW95t2vT^#odkf5~ghEw@4pteb&S;5XcIgnOJEbVL?j&DbZZvHX{u z(_M|S8HUV&zWcXekbCqp;D_HC?4U5AnbqPiHKQM%qC#Vg$Mmo#wm%r^Wl)L>dgfuB z+e-PI@&M%V*bYb?0VLI6d8xrVi|EmtNjfr#e8H4d_U+#tx@YnRJ$kjdCG#4pFs+^d zcly7- z<%R(3oZyog{mP)=_Q>QPZl;#2J?jp!wP^f-Cz}x5?)lEfLC2>DIQ#UwQQ2}UD_}?b zxgaex5(XY*c@C_lPaKR8amO7D%Ewv3%ty;-O`BDjtGqMHBPG%}fGz^?AD>Yk!>eL= zY-(~Cog|hv<)j!f61i=leZI${jYw)mwhEQuiYdVeBOtpv`an71x#!!cCWkSkMz_se zmT1C=zfZS5W^ynTcO3Nr5T!RaVq0!1vdZ-udiLj&4$(2o3>>Q-c-(&2$LFtCOw*{| z`LjX^Cuc9UV%;!y8y)xd3%B-mKHVD!n7V+k@(Ck02=eespWX|5k^T=+)t+ng?MH1R z5(_LII;_nSMzU>2XKV&zjGep>aC#%kYly&34X7az)$^pOJh7dMxh*3F9;}~zqZvIb zUp^}#GxIfv>O3<_QaIIE5Xv#!0iB}*Jx-BPrB+WZ%~|KL>Kfd|+GTQZ0Y6CW03EpK z2`3{}lCrbv6DSZ!2c;cboM+sD^%d>VGy)D1n%0@e-`|=!C-e3B(n`K1r zk;0sY&wiR}Iz26B7@^mr7UCFMHg1j}ihG^UPf~K##-f#jxf4?M2Hb$phhJCBJBV+*qAmf4c0tXoC zmefE~|X zq*4X1P8MS_x9U6B&h`T=>fgI(9+Te#s~|6YK!n;E=AK&9?TW39xXY+%c9ZHtqp=@w zdMPLUdBie#%vcsH$Eah}$3BpGQ)w@#pARh8 z#?48w^K8LGF0m@t222`zXM7`&j4p20Yv=g^?X#oHek95al*A9F& z@h6D1&;BOg89X`SyH+63wa6%3it|p<)09_?fQXVG(=1LfF}obG?bmKyuQb*uv=Z21 z6BJgCPFgqpz?>37j34Rz_0L}r{tMFacf{QnU9EiB)#22mvpmtt@K>6&cx6Z1{;H0B zImYkt)wgLOaCKpQ_#*2c&ImEw4vSy-n^2SDU-5zAtqa3dWw9@Zlq}Y5+zA{Mi=>iD zrBADY<>PKt@%iho!kI)Ggfqr%$Rst|NbrrG0Cgw0UH~6%an`EvzrzZC7Moe|1I>B- zOQ~3EQ)+AyI}*5%m@9yo1yM-_M{~&}`9Eqz@%%x4hGUA8Or1LH}302 zO_QsicT&PVmbdj(}M}Np|FhUtoW3F`V=qwI>Xf zjj7K0Mgz#mV`1u5N8oyg?IRs9mN{Xz(KAN!85UTjb=|oD!45$G0PcR>0cB)sFx!f0 zqh*s|d2=jn7Tl2Qla|i~zs5R1la=m-^iT(dB(&1ml2u^u9_Lxr+^WmMsS!OlP5`{$)LX;jo9)26#xzN;SbVQXZp5$(p(SbdHN3_V12 zd(%tv7KzMOxM=OL$@1ND#liYLUc=j?PUwcQ1TCh#KP@`AnE;AcCul>E#ZLo2Zrw*b zL1K1kcRX{fsIWONAKe&x1N}pyWAf`-lC+hDA@e0&q_^k0l>=%F^1~;&#yIcNc%!FF zUt7`nv)Ne67}m%!WRFXR?!!LE{Pl7nG#$Y`doe|%`Le|qm1cdALnM2Xce;;g^Vk#b z{yJ8VU3IAxq!nw|kx}Cjv&RuBpD#GUe16b+iX*5c+cDdgJxX~hVbT>QBtFGPdxPp9 zj-;H!6m_6@+TWJ@q^%RS)RB(e=h)%69A_N#Ayh{S#nfc9sw@+Y-MZIRumbD;M;fo<$;W4|8bM`s@`RR2wu~${8RkpQLArL|^N^Sk_*!T9& z)$NXo)2+CQ!p(h*q4%t|lWHBq8w%q*dvy;9Zs8CkX%@Vb(=nT1i9T46%m~k{_s{P8 z=Zy5KcfJ#1m(*-mE9EjBrbPpXX7}6MJd%C-WgV*%)`cZ?uPn;ND$WUJ8?d{%&PnxT z5J2g6*v=v^x zdMN|5S7}e5=7W;>CmDb12cnks^prJ-A-2{gUzs2n*<=He5dNQR9y8F;#-GVdlS>tY z3zc;+vSp9#j2=rb|ZM4+2SjKT#0mVX`rt9A_Cm`Rh{a zUj%+0>#^z3YMvCM6`3wG&dF6>+%G2)?br!CjIa3}ZWq07)hMk?3e9FI+&AhHV9(M! z`o7=as4P0$s*(KMNUxj32p2y#}Rk5ZdEH^e*x0K5(usC^zpss%mp9!t_ zwtZ3!7D^h^IGSrpM3Kt7N+uMIfg@qN%Z*nj->EBq3?BvRuAffMl+N(PJedq7;IKyk zf^yjn&N%$B>v_p@$oZ-@T_Khi3X}O~(lDpX0~qWNsC(z4H3pRF31V2%jAh1WuV9o7 z+$%61fO}wY4{_4m)&s)f4-M!;{{YRHegSIzJK(>=Q?3nEX|?3M$nnJ}3h~P@?u#DW zG4}vqXRM}&hja}eQmYP?q{Uv{=yuerwPScZzx5tD0Q5I@VlYN{C#ScyZ#|{H zI~gJw+m2!ize{KLE_xEojJ8d-%+?+~^3As@^5g-4a8v=601o{TXK=a{G>taY%?d4P z@&Ow&%@(JrI_h#sZlxuSvkBg@2EwdCk075(bIv*F3$}!@Z`m#+B3lGZMNJ>?< z`T9pBmIL;;ACuKLmW&+`N1$40|4P)wU@c8oetM zPO{ps35GdV%b3|;8{?KP**~^hP-tQTsM%NdW08ypD~sN^yn`fz>m{qxWgg)5o$Na53KrMM=N8#Bt0 z%T!47EQ#t^SYW6J)y_#hi0biOZR?OnYf!5YnewL6?FBz*Wh8GT@s19A7V7tS-%eR+ z*?Bz1B1zD3y}d5Gv49EpTw~iEK|9DOy>&3nW(0*p%UnoYtA|6D2ht9GLy&u8w?Vlq zl~T`Yo$_`v&#<)49kaObiIa?we)#C)erU89^!HigrmpK8sunwuOviH|W1e%)NIU{M zQDR#+H49Y@tCPztqDY{at1o?_)c*V)`@Q-q7GhctsWc=5W-KBzFvB)moxo*t z?Vo;#kdWC+BC3~kMXNRIG-HB8=Mx_jJ2qIb9oY9E5zlOObXtzJ6y91TSakK4Mu7;# z`#{3E_C@c(B=ULc8nf2^Sj4+g^5$SX_smumhBl^1EJyWcJdT5kz?DP}lTY&!ZGkL; zuM9)pL7WrskGDxrP*A5Qmn+1skjwgO^GX1iDbCHr=a0YObaKM7-$<-ohI<8-Q6dA> zSY<#UV1e0>+wIq>rQEHd+tbrdd)4A|Gue_=-x?kdzR<7rW4RvVta_!9Okbd9;-1W^r z#NWa%6MRhgNuf*Oy4EGtJSnfHuSUAzetKY~Uun)a#~C0o<0No8$2C1q_=>wh1a}a z;V%hatlFlp1-REygHMl7w|GT$fsLe57Dzlu23(Re?A>xVg{x~n#Qy;C6Qg*iT8!!b z4y$>rO%;b|#35TUM!bKgzA$7505ICQ;Psbif5SZ5#pcz1F8G!`ZtQag#b@)QvmSC) zoPi>3V};sqr?=a#v8_`}tx-Hbr@XO8U1Y5*RgOQHo)%#!Nn;8(1;7g2W8Wv9i)rq- zVveoi5&r1#n!gw+{}BfscC4&aHO(uNV=EJo%Ga=(6qmi@Zg zP?;edf$!VuS; zP#N6GH_XSi;*@s(03YM=)C=lVni{~-!Vzt?uLy`CLu$QysXb#YVdoO7<@vKQIU^h* z3}k+J>5Z4Iy`--+v+6QVQmfkFd3$io2XzOxL&%jIO|K=ZNfWG%5s4xovW@@;Jaf)l zx3)T#^VoeQlgcR^R)Kj+{{YO)H+rKP{fc|ABOr`pqE1%Y2+`9w3I}?^I#JvW<|$Ur z6fXn;jCKP9rM2ow9+uFwt0P%*sTGwt0eNLVcJ~MW0B$-k**3LfG?Px#w1o|r6EQ+I z?Ffm+&|A4V=wFkwb4yvOOJG^0sIij=^i>fyJ1IFPP2aQ=pKh#2Rgj2KRz~yZbasXb znM89^IA)CSP)Gj&QB}F!o|ws9zFox3nrt>3<-)#3WF3a?N(27D3` z00+y@lI-UT9AI|bzOQe$UM`iYQ?}D)-PxyUF&*v^K>7=udWhp0`*lbUC8|{`YcN!qA&^M`R`R1_qv}TbnB)D4?hjK{vmM#23EDM^TJ0h{shOcd zc814chVSlufa+S3#Wd>4UTGD`Rgl6$S8#C3WX=aaj@=EW+)3%`X{O$?lYcSUGkl_& z^Xxl@0m(Q#2LyBX=+Xx$8mjg5-8NaPJDDQ+DJDU@EL)f%Dt?#s5~H{s^VcmdmcBgx zFlxyqPd-d-{HGpIy(Y+Jo_6Dd(T!zSPpmdgwTy>+k#Ck}-f(!wU~oR?spwLlPo(j*@K35m zD|wz^VJf4ZNcPH)tJogHr4CoRU=-RTjuMOUSzne|Jg42e&z>wx8!>ID?5FB%_QrAU z4@GJ8tVEXOWP+EHz$Wrc+mPj@E1om%27egq$>_qtB3(snK^3Cy7+g4CVH*B@@PD>C zVWv|ntF*C61lpXzyr&_Uscy&Bj0XFR0o6!MCIV9`TpB&V(yGA)fwIdu-7Ir9Hl_#l z`hV>1cXf(Q0i~+>k*AlpIdzb*naJC*NjNQ!+%P{KW?F`sUTW4Nv^5D>L*(6egKH=} ziDLtTbHT^A=bo{v^(Kj+h4E>SY~XAqdlymc0q(z7=c*-8f@Lj|v`{r@wOVq;EK>(a zW?TgX;S?z0w;x%?G1U~ZJWR=QSmQ}9H_iyysyusez!Te&F^qq|SI1lCq>h@`v1%D) z^5c2kyv^Wcoia(u@0@ejuXY(& zAf&O+WB&l<@Jkchk=v?5auJp7 zyU$w9hhtJ%H@dpFmw@~S3Vk^okIz!-7h#Ac;U~z~Ns7TGfX=YO2GNoZT}kXXKXQ5+ z{Yhg|sc^M&qD5-U<%W=d(vWA5`+xJEi<)}Te4Bj4a>*kJkqG@Wf%G;o2R*xE-#uKF zjoc`wuXyQ61o6c!xfB@KCIlEc+D3Ti->7DZr?m~1nk2OZ1#K)uN}*5G%zcSGaqZI- zb-Ai}eCQb zzg*o^X{^Hol$t%~7>_v{aqb5m*y{KwN;T>9nsK7qc2q1M%Z*VNac#i*wvO2E(GUu- z_(8NW!LF+!SO&FXO-mAwE*UYm+t`jl`;L{=rL$S6sa3B?SW0A+mD&%h)CL1!{(3gl zmtR=4^=7MPIGbbwg6$XUfE0O!kEOvU3;65W7IUf1tWL_>_I$OW*&oSfkF_LO>ict)E;Z{?$kRh8shtef$Wk-kP> zIl=5dw?pc&t*v~^Zqn6_BijXd8xqFfxm~%=?${?I@6d8Jd0>HKkV9ddw3Qum<|ynx zAK$A$1{0~Cc-oW~?7(G`Q@X5kvt<-_C$>QU06yJe7BsY(F3nzFB2*h|OFSk5k+Ail z1f01}GvEFB>76MinkeOAWdM=p+_B}h1H%KJ!?t^VI`AV4h@=*;&P@YNyEpBL*3bNc~kIs%jaGqP70h9EG{C4U})Fz$7Q-mxV$p?7e#Gg_* zI4DQ$+ux>EYt~;AQPd3c);0G=WU_XwnLj{97-i3Y=^ZH=G_vdQ&1S@~v^L0*0unsN z8OjfQd!O-+ucApJRrAxBTbEBZTgqlXFOm+`9FWB0e>`nG{(2t0IO4cj;blRv+;lA9 zPx}j&<=FcU-;S8ZBDtZ4x+1>vpCf!V-bobaIU^qb0C9u)>JXnNs_DPXAv0QvR*adY zd=V!k6d4?k-g%Fz6V+4+K&0`l+EP}g-#8vqG*W<(Mu)x_c5lW{QkWu$8y7=twdO5r zG987VhICdOjt3w6^(W||nJ zbTcjWVig#+*F`^IzW)6Z^@c4ah~b_~Az)Z$koi$ZpHbj|53uffo(qyiQJ`xPOJ1zl zsc0g3YM-?keg6Or#y!F5V9JMtB;Z|^zMPgFYDBH%NeB)k3i(-E*o^Y3zwe%=fqhv< z8gyjhSf+6!Sv}Q>?~HpMtkY|x_ZFmu5IYA_0|5zBxD_k(jC%}pbX6Ij&uF}uNTTP1AJxV!HrIEUvC3(#{isldpa#p2%aM0 z$VlTJX>c+;%#sRqRjJ9Wvw1(q0p zjPHv2Wszm9(A5d3%Ee%?cNN;8=PZa+f^(36zg=&C%96Z`R?ySYe9ff*1{Y|~_S^?% zIKcMnmVO*8(SIA?739SGS;-_887Hc6I6r(Z8?J4NFFhXL z*X#CIQo|g#Vks?6kwGGc{=vBGh~}rp>2MTE(qOhn}q$n_k%y)Bx}@ zqbh#q_jQ+PP|Dg9!eFZo>3q3f1voC3DoE(b z1ZG&?)7cM&0Y>jnIXvVHcIYFf>9O3?($!kGt?Bm3`TLq=bF#=7NuA6$0lie^NX`ax z)@sy+R)9=F2jsa|_N~33X*+{IP)F}Sa+ytLjA6xlUUg#TWR!2;JWfI0>~KNvjE-

H~Vm%}Y~Oj)V|Zw(PP&5sbWT9@yF2IKUrZdM4vdExDdM46<05&pDnvo#~y@1MZyg zgE;obP$+^3W;1zKPo52F-0n!-h6Knx_WuA#$ozGn^0wPj_H1iE+5q_^kjNKRuAePD zF7@4}uM6&)KsW@0^^@FZusrn3N)~kJ?8T)@zbPa|4gEHWD&->@1Bc(IC zRE8+6hK$EO)tHbU88RauPz=0d{{T+BlE8yXn&PCbZb;2)>T3D!2XQQM_9Xo$o)1(> zTTLo%f?5}?X{L&*+nM~J;72L2S-AR@gJk|kC!F=Fe0%Vdz+Nn!waelyFU2 z)bB=OvXy+hAPuty45VbJKX>j&u={i*B-XW|aY)ms&{}#e9jtr-@J%n_b5PPe2cb^B zDlw(FZR<8ZVpB9y3^bB~!V{dTsLxu4zr!z%o+j|@8WoK}d>`Sc?LCVcdd)3)9zejo zhlqf)$G{<5mH=Q5yK;$o+LCZ6{=0yx#CciCZO!|EC)57`obBx{{Rg>9e7{ito9|+R?Y1~ zXiW0lYSD?Cx$`1$q2fZs<{iX)_vfvNQqP;9)2y}L%<{1|rD?p?KtX2+;~P&qNbV1E zdXko#X5BWG=9Xj=7~-sm5tUHol)wJ~z1#8BG5pk8-1Al|8_5`rqTS_Ji9-h5pp3Q- za^JhHblBE58oQR(cJ`FLl@S1a@|ZzF-^|9+x+M@qt!}G_QlWONSqD47?hZ-8!5w`1 z@DIe_5_og?wfL{%zZDCxX;)d{gTtvjhCMxy7{kF7hYDGCvA`MJe*k?61qPQhC1eo1 zyC#kp8Cr6q(;^Uf!Oy7YzerQSnjWL8q?(?Erg)CpSrBG=Yb}@`{{WL=vF*VJJPwxa zp3`0pqw1;;FH%~#*o|zG_$(gY2HxLG1($^DAF8(x3c4v$4z6UtH_ece^CBaU1V5= zRN9b27mqs_J9i&Q2Rn~F6B=n+c9|V(3hx;W81kVbdoyIP?ht2=-Dn%2Nm(?VExL6w z9Cy9hF5*zpORLKFYZz-?xRNQ3WP|||I{uh)$8SG!IOtk6Eln-Ei&ne6R{_E+1(s4a zkr>Yb57mx;C#KD=K!RwNqS{MyY_TM%wn)L?D31iTJC^%)1Euz>NFFN9sTEhamZ!A@ zgheu<=P~>3+v+*SPX|3i%Ji^DDTEY+DxW)Mx9Z$0JZd+I)kme5j20)k951*%2!^=S zZWf-TuN9_&(MfhCj(oCv9lq=U>U6I%>+?%$A1!1BY0F+uNDjf7hH?Q4Mn-ecDORfK zmZE}ZjH|ZIiId!`lMqZE~E24u8F76U#@D9+f(`gZ-t9Sv^k zjb%oO|OW^p-ilng!ZrhDC2ODI{F9YB?>> zJGXw^_UXN4`P=%O@m`8USx{DtMj6^RT=|&e13Yt+k8Xv)IH45V)FclDh1DzDiA5** zR|3r`oXsL0?1zzt$;#v3jCJJA1iEC)M{RoW%7RHNDBlx;8*-9zRO4^ISw$+fp5=&R zoSRD?ZMA0rMEK;#l5w>CLy^=eMp)q&btoaGeDthRq(7wW&FMwm%Qv|_v+dAAU=0Ex zTO?_B!0wS3@=$)VM=Qi+U~;PCxo_!Xob=)f(O1*rttXX2X;B`+mfi^i4JaPO7Hbb0Ltx}bwEC88aG(xA=RLE~b?1s*K2q|TL1Z3crqc`d zZNQK)$F>3Kg>$CdGFO%<86%B$`N{-S9PU_)5O$UNw;$|t())7H4~aL{@;sYz1ao?^ zF_r#|1LzCie`EIO(?<}cT}e`$O;5@*)sQ51A`Cpm2N_^+PdtC;w?w@E05Muh_q3FI zFw2;oPEfG=TX@fIj;|f4l+>kqD^rPg@3$Cskg?m8+Hlz&xxgLs-=WmCIUJ-?$vFif z`DFkm!|EKKU)m`(7~o;eYv4+@60OIMrvX^Dh+i zn%|o|Ydcq5`D~+;gOBgKrLArVbk(gi;{E$l`K@BJWa2@)0geHX{qex+Smv)^O=}Zr zts}EKWu_(LILSkvIQ#qcWDt_Q)mF50YwiZ}#pTS+UQM$EV}K+W+N2&z58M8F2CtGl zK<{o71&L)*ACLe6&JNex11~){2@NHtfz!RzY*4Z_mF!Z^R$?gXmKsh9J#J&fLUyNV;OlI+gJwEi>5?+eqZe6oSQn5u}G=@7& zjDU}JC$Q+2_(k#a;bytD>3*qmD z+66rmN_$d7)5-ICgo_k5Z%BJFDfNXvNyi;SOgaxi_rmhkE8h5$prqPmlv+U~@<*3N zvh`a}sZVX13lAl^&yz54g@$vy5uLd9CqJC@6jfH5>JtLGiJmf6yEqEd0gROXrTxpC zH%6@}p}Pcw^x%yM+gfeK1Mm*s`+ffS_UZ^>uYXvqA&5;CbLM4}YD@y;H<|bMJZIa# zM82lc4FOKpK(1)452d7vt6?p!*j<%0U7KyKj?J5J-eU3OT@AY(uiV~D$9WJB)g-qqbfjFKZDit zNvTI2d2W?hkbvc22xs1*G*`=Je}PGK*qP8bC6L6C8d|w^@B^%yfGCjh3HqkU5TQL}QSSFhLnUz~{eS zX_RWkUX||<%+OCf&OS&SPZ`_#WGKi3?mM2bn=-#y!a3_UU~nXNI-P^34=yP_C~Wal?g*RX)6q=OeMtM9Vweg<<)4?n`OP zEtnTF6hnf%;A9@;p4~#=o`8mtwc&^~`w=`cG|wVHP92ywckcbe9^F^T`GQClp77ha zSFbk65kbQ#P%(l1@_H#EiW@K?ydKiYzIpu2#Tj9=k;YX)`{S$rR?9;slD8$JU(CaY zghq^`)LD)*w;xYG-#slv#KN_xSFqAgO1wbF1a0b# z-_P>u90iaL<+}z4+=0|{J&i|Mf?2GUmYgghvm}H4CvQRH>r=*0)VRUO>sG`0(EDA4bJB87u*(s(=NV|?hF+W#7+ohAl~Ttl5mmx@lj_*jbO$ zf;j`WJLL1zNOb9beG;pi5*QS2l0xkoD8}V;*q`@3Rf)-=sjZKhO2)&FOv{(C?DPP_|`y*aBp+z+4P(5_T** zZO0?Nd-Zv$Yt@PctktzS;$jzY-yrUGd!ffU&U#t$(|J%refUJ9{!T$hI z0ow=mbh=$VOGWR(Go%NTR0DO8#_-FA|^} zDly=0J@cRT>m!D0@ag{mFU*INJys+GySQWfvF+;r06k;(H0Uqfg0oN*;Q(Y6#BCb- zw~(ZjW810i2`bb_nF=tKo;X|`yN_gGeZR*|3X?5H)REQ_F0dhvRzj@Ad8om?F%geT zH@P|d^fl}EqqrTv`ZVq<7=JQGLCZN~ft>K8_YSUP-)UtvN<-?9lNe@cBweIFP7kZ{ zG0^Oj7{wD^WSq>tYr2*)$PRL(k&JtNy3S@(07dD|saCgc#QLb7$(5p-Nf4DMxGR!2 z=Oh0BY<1;19d#+}EXCwOw&XF!Ldxf}A>#w_(&Com((J)@F(;S;d1XmgZQF_DllcC_ zr#?uADCUMKW}3AAT+ZXn%X`Q@xcg(%@1C69(ujfrEo;EHqlqkR7S7z>*1=v+`rf zkhdBC0JIJVP*qmcC?N9MtHB}pgA@9tE!h=M`<(ma=RGk%aI9FYNm=gdpD{J4qb(ek zCEdC=Idxd`ou2r}80yICTA^ZTEhw*5&c+qlr1MdR5H>rJ?glaW>e?2Cn5VDjB=SKr z!jM)^F_NC&v(kFXth(NAS)O7alznajYLRZ+%N91)LmkM`-^ z7ZLbJ%#^f)%!%WUOnRgosVYwJTzlvH^&P5|THG~jC(PEAtdc1#q&j-ZE_ne@r(&O1 zzIss-iKY|=W~->9RfVfx-M!H%D@ge}b09ef2ar4Ub+@&rRzEm1aU8*RSP&S*On*$a zI0T+Q9bD1ghBvs(_2iY>M=Aq5gV?$D`{Z%>>iDYpm29-tq&F;B`G5-pUDw}e&PgYn z5_$gs9aKsnWGJJJs%rlLEF+$BBM`FP|ZcF6@ zyKcaPA-6YdkNou8$W6_0f9J7fiz}{Ub=%I}+@Je-^?P(OQI77prqEoLhToeCS@kS2 zV>oQ&u^op!yXUKS3JfR$>VsLUXh4EFVqoEz#+WAuE%zt30O^!9{%|yvYrUO5JbbLO zxhBEegT_Z7_T&tA&t6FyE~NKlno$H^V~DI|`RWJh;C3I_j-P+a*p3-%Kr2ILOiLWH z`DQl*2aez14yNoYDGcl*6zS=}EUz1^-eL(PW&P~_$b;@VJs8r`dkB^7LakBMgI&yy zzzi~Tk%QDr4(YX6wE1AtwQ5X|$u;Wi5r%TEiVq;K^<)Fw9*u%HtI@G&(t5E=8b@go zxGukZuK+3bJoG%G5EZEQCY;P75&6=D63C@gdU6pP9-cTY{sHJ3^=m;qvdAZn`pjjt zs-eQjP5~-&fZgyqbqt2d)F6>KATJ9Rs9br`FI!0e07#_XQ%dT6Q8WJBcggNMbWK%TKM0miPM?15Cf4@=Ag>niKMM{^~Ped0r3niSzF(fouJwZ~-OJ`Mz z3O1?79if>gfW{?}uriq7jQ3%W&q~Z?RuuM@V{R2$W)K%LyG9iG!9m*(-vi&={rX=W zNLEEr3X%a=ipv=iFn@Xb=h;su@777RV~#joU(?G-v5l>s;C+ETSjlNFHG{BL_eET` z0QVl}Kb|^)_=R#(2&<~er#5CW2tVbLQ;Bzvq>_{@-={`_YOIBW8BR-*aEJDlU(dfiMf|tT^vx?mU0A0+q$jusKHq3}KpaXk)(B1u9!I2h0~~kB z=cbTSO*csmHNh-cKw5PhOYo}PV*v5TVV;Rvim}NuK#~BZVnOIs=O;h?FwRF*UeXc5 zM!KbTs}{ zbjWGQX}oppBxb^r?HcV24{(@1o=<*HQLRenQFtMo1?1R`Wh%_s1ZN)p-SLlZfR>&W zK?O|`NAfWVqlPk0C-kn&j^m!-`+w`w%0Dxy3zpJD1AN=ZQRRbZbW`cT_e}b;?s_%! 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%0A@#Cyq;N1hJDNz2)X3@pRnqc6g-2M-OsC$gYEsl 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

=*Z)-rux+`jRt6 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 HK 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%0Dkx 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%0DuR#ufM&-k2W1#v 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

m}_@jz38?g%V4kKUv)_B~D} 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%0DsG?eOb!x{l2b2$3QqtI0=ET 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%0AQa~N~`!SDV$QF5f_&YsobmpA5~ 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�E*iX%}Ftf1h%a8fCDk(l>>)nS}xJoRJ( zB^*h@cGE>mNGnz5`FN!AqY<{^>f`q}w3+88BOc!UT9aF=W#=-BccK`1P9%_pNN!nL8qFI{klaN1AnH70n zc`Q)yagR(a3VGio*dW*N&x6cyQ#CTAVnCvVfwa53%Eds@X@ z-3b%4NljpowCqf4=4}rbKB+fwcX5w@evB2M5JFgQh;>NOYd}9)SzK6T@>##>m`9{z zx|QyG^vzD6CXX{bH7m}6-o(uiS)~Yg&JP$po3ZFhFoe)A!)#sUO93v>M9{+NbjCv}J1-kwc__DbDn4 z5Z%T`IOvF!kO@P7!*}c?GDs!E7D*OpSTn-h@035&ll1YC`08u4>DAMcl#c?~vk+C? zTyKvJg~I2Oe*VMu_2AYuJF!h_?7E$qWtM4er1A!{VH?zARqjDQaxgn%s?*=jn^AU3 zm1%kG_YzqFnH9#>Sc&&1l1b0lj-U{s2dYH|jdmMWBUqxRJ(~gvQD-vkd3X*O46awW z$9}|gu4)l!GuW#XhR6=prep_ltbO6n?RWc}=i41+tkTC_H5xDFS*sjtG*Px%#A?|p z%uYrJAm?^E#Wfh_H=akdrme?Q^J3sw#0uC%nB%hk(lG7s)FM*>MOIO2!cmR^L~jc< zYUeEkZ2W{R!V~nJpdWF8)@gf1(rN2epr2HiP19m`O4ZiEmRhH7(+f;S=?*yDPgvv0 ztk#iIq_rczYU267I14~k1{HzemT3F)g+0OQSWJtmR-IEdjc2gt@cpP<(HOlR&NnR>4$r-t@ zPLP4-1sh2u5(=sIB$LNk4AIAWO*yJ-BCUC>#X3m!LbNPh(FZrOU_;PaHnkXI25D`Em&$Vq70iHPA~@_% zaKw|JezNTzjVQGL0GziJ6;^7Dvd5~%U6`=LD>9wHfG{0TxbN08LgX}Ou1eXS6;&t6 zQ5Tdkm5?t1i1*1IXNz-okdgUor%64(CUIx8Ce6Wvc8s1fqwG3K0VT&P6x8WOcI`{E zt4`@6?}WxY$kkVF5rF^@ILmX6=d6OD75puJg!;wHQ#`8T2#ZLy*bEeAzyy^cON_2F z#(C&?{$4v;qQW555?K~opQcbjwCyHECk8e>n;rQ4^(1qqnSJL+w_+rd%81J2Vw3K? zdXRg8j@=Vl)eGGAqN9?HTxrctNfJ-_c9v;Kf>!eKQ*Uku0{|V~=eJ(TC3q?_JZoO# zGLj%%$tDKX033iZ!+rg*dc?JzX2cejAr!{!v#*raA^kZ>87TNTi+6C{&)=sFtbEnI zLJe0+)O6VH796x6Gr#)42OW=WW8bXqO2+=3<+wGpSkf19W{{WY(r7da@ z#edDzmaIy|kcHQ4yP*Rrqq__h$>*c>cxSF;(`(v&LqbJon{9Ixfx>}^)DS>ChGE;^ zC!U``@X1P?3{2N+tGseB8(mM;5znZF{mwqFii1<8jV0R^67TZBB8GQnK~)%*-zh!D z5BvM)s)Da4fU!t52D4yVjyj25p)%Fo3pzwGk5+!HcU<@O$3W_Ds6%$Xj}uze&AH=B zjWmWStQGZd1u=l2wpaUe)@?qoq|&z#Wd38Qex+?mDq&Z1;i3+w>EMnAJ@7|Y#jcSh z$O1tc8rwApYN5;lvAoA2tkm0DGfP0^v8DoI^V(JICd`g^#~e|%%Cj=zd6J?%0BPOWV%D7}ML zwQ?qO&NoE-ZDM8h9$r!EXUI7Uamc{qw?o{o<9q{a>f*)#uWrl4|ls-!jWb=2JEp{Tp2J6yw-u z`}ITsngQh~)h4YrucKX#HlsLKg2TlhodAH01&=w&{-zxLi0Etb%R^nM4R1EAl1uXT zWRc8u))F(r9(JC`-#+7}^1(a2&KN8;N104jm01isu__b*k&nS7^%$2-wANs}x{Txz zW}2*ID=0Wqz4QCIBdY>RguucPeA5-k99g# z$_7a8NOpjOu;bM7DbK&T9k}XgVX+>o6`M@;1bZGhK4W!q$Ldv4`^UN9emW*f(k8lQ zp$LNIT5QW+^`(j!!#*4yd$9Ug9G--MCYPP`;E5kl9gCk`A zGI;3O+O#&?N|pz;6>72AM-mfNaM;+h_cDF*2|X&6E3TDV3bM-`h-LDouQ(3!?>m{> zBMhK+8RMp~%~)vl;(LY~Vo-#NhZh#vG>RRf2;fB(k`c7G5IG?@q#dWcp5Xj{QeY)yb5~^<-4C#4}34lq(!u6{lAKTm6SJJjgP%zs)%1>?O%$)Ii!t1- zSc_4;MUpQzDGIK3f zuzHP9M*EgDAEa^!Tpm~5xCf4f$7o6CgzgPmEZDUfwOqA`{HW!DSZ5e!1HJ*^^ZD)4 zn^)}Jo^VpV8JgqFT|Z9<1{Y>?$@d+<1Ef?Wn%|4BQJM>BPJ+Qcov8U={TA~E^Xt5Q z(_jmU3EIK90F3qGc~feX;EAD4PA8OJ-b*5|P21Bw_WO^2Y;_5gU#BM+*n31aNN+w0a*T_uPFkp4dGjTctETHZPHp zmEBafcCRmmRA6%}XZo?Qch5&b4A(SCE^2BtcpFk?uUAc+w9M=2%K|w;kV7xIJyCEc zl)wN*$h9n2tWk_sCcWlOACZUL$2-vH)%}k^TZ(t_D;PD1sq)@ju^cRoo?}8srHc1% z!25JXx_X5`)J!j8OFNw`NTed;{-Hl_U_Sjt7nNpd?0+(QpDb1vLl}~1l=4d_80U^M zNbjDapkZ38G`bVhdFGD%bFq$Akhltc=6>sr#Am-=$1PWsQmtX0RzbS#hzg@A^+qxD z?(LD$+l!kOp@L?W;`5ODS89=$X&2ms$@~4fQ!SQ){aWn}N>@CbMO>&GFgGhP8OB%d zoF4sH^vJIJa6tzc z9_JVt>L}c&hbYCSdDZQyW@+VBjwXm4<(oPBxX)~R`}BMeP}8NWYvpA%rIq2DNZ=Fm zAo^H$I6a8QM^;fdVGCxg4l39XwRx?|*JQ4;Tr$;`-4P^Er_8^X zV8@&@IOht7xd$W>&q0%@&ZY{NDn^izJ$UM&4(g4#&`stC| z0k%gqP(2Q-*}Z`Wox`YMtk(4%M$Fc0`Mz2@Sqe8t7rJLSXCHj@$bhI61EyTqkqqWo z{PzF?!2O2P`i=hpX~5~$p9Dg!TRMYPpl$HL1F*h$Oaqp}@CQnTiaKm^PLui3yxvcr zrl3`b=jd>AwekC#p)cx?rmdwS60)VK5(7>zHX&(KB^No%0q@wJ$Ec?%^s`rwQjS!y zN+hvk$|-0#k7|01VUBV4%V(eQ($u`LYqub~rByJ!!eoY^+nF4Gm;`#5dlt^peZ9K5 z{%A-MjfrQORjk;M28yg_mXzm@`*0MT^&BSO{7dtKqS?6aV-Xi9-dg&%F#CJpV+X!^ zu?QfhC@Ms*x>RP3caVvtzUq=jqZ`nsM$$dF^<^mB5L| zbjkMaJeGd=o*N>mim2{jt@=3PQKt3b0XXXZI+lY+8FJ2uim!2!GT z(8!vcmfPncdk~qMb3+)2#F)c6FMm^ZQc1_ZP?&_aPISl+wap2jbbx2?%H{gGhQ{xWy!(wuy+POv<&C3XOiU7 zya|`5<}9Brb}+HBeK?IjqusO4djZ?1l+so*^rEjE(`l{$051cmoo=si{q`S(31|1H(EQCs{WvEF)}D}Vh)Zg3g9f&k~E^t(Q8l?~gKq@L3f&2P&w$lk4^5$7sF?pu@Xj-vsbsxt~( z>!?1D9+w$J+N&don=^e}p=|mWADsSr^()zb=5=9s4T!?dDtY2aq66WIMZ@yF1;n4ELQKRsgC9%=2{d11F=SR^XVD(#T%IgG9{u2b>W zO4nMIiCTDQywE5ySa{8Y<;XwM3cQS-+~9kI&=OarUO4BqEV4?DTBKB^{Sf~Eg*=8i z86@NJ&^b^LP|`c9P_;%`t%+IXKv23nF!jqQ!9S(NHr-vuqk3dIfbWsJjQLem! zEv>&m?~urO-Jh|^=*g_j9*^?2ern*7eTtK^g5j4e=vT4^^o(Hp_+j>c+E?PHkyThUj2Z^lDIi#0A+u<2R%nx zwMVR4-^|4F66-Tz*4L|p#sLc7j@|Rsg9^Zat{*KTKx1oH^xd+xJAO(;;x;_94#h)q z2M3{KujNv7MiT0Q(3*AF<`TzXkdvMQ`jju!I$>fcL^Dvb&;-=1EGA}vlnw{_LNz{x z_ax(^610`7KAa+!Dyp7jWuhK*E}Rupoc81K?T&^?C>&#|$E?S1Nbx0D=lQRf!)989 zfhj?kR#JT|`55TxRsLqGYF1-4sHL@QQO9JedCD+05z3()9{&LBdI~!5(7C7MOqT47 zBqk=6YU10rc>ci8qi9D0^s|I8C=}o;dYqCK!vNUuZiP`fwV<;FBIT*s9b?LMl zO|3oaOFLhh>qjL^2+5qk5)ZjwX77&J>L@Fuejk6Cq;7<}D@QbqxJ*^Hh|zoQ&vL|% z?bU#dr6+VtRbs76PV%-fYr1?;`WI=*0B4W(C#OxPITG1~Pr0O7QWucS5FQYm`+hs8 zvFU``O5K`u)ufhr7DSRsCn%BQkTKt$IwlKRdulFI&(pqE0VL2YXZ1gzllM=z z`OjJdXR3~WV3(RfWU!_a42C%Zkl=t%3S4Ku?f%_)8>84oo{@@@#zVXZeRq(0SvIa2 zRCm~N3FwVZlyT@k%d1yv;>ll_lVEK5ZMcVg`a>Sg{{W7qp{Lz?8nuXAX!U`QV6iUK z7(u(qciYL&?iuQwz{IjjUuK0j*KexW3${qw7$RV$S8p-Pf%f$w?t66N1g#}$qP=Q6 zP%5lSl1n1_tOj$qa=1L7{kl+sc8_rFll6a&mh*)0AxjG+`U}=}M7T-vm5D(U zsK)ldJ-xT&mBQt&7o%8Rp(HvBYAXalBpKu+amx--=6KysQtR56)F`Z zq_)w3hh@eR@10={kr;1c2YfbvJr`<0Tf`cDNgfGl$+B2jFYC$^k~Z?*SRcQRd*`QM z34vKgVeY*~yKq8u)wOJyLJCPmnyhXA|+~LXRIqY%% zdV}YzK@`qRHfNSiiYwsBF6P{!N9`bczZmC^-FYOMl)fd^42um3D=zahTFZLZ3m8AV zXSwNwk`mH|tnkF~NYck2`nqbuzP-fl*vZ;d9^8-j>)$(0Sz)haPAu$mC8UXq*_U^s zb$sw~`wu^!pHCTzo~Kw$=Axu_S`-=C=B5J<~q{UPvmsj zCaB*gl~Q##gU?y4DBh8MBuD`TM()QvoDeAgLqg={oB3ki-zGOp{{I6_VpK$2M0<4GurKr<?;{rw@kE6>&jm$tld=cNCk9JW)Wp?CIYtYWHtjWJ*b?eXiZt9tl zBRqERfsCK=&`@c&EL_tp$66_4ffi|FwJS)caUhRkz-N#M91e+!^J*GKpFFhc!09lN z3n|0odTgq<(;z;bpYPD})4IMJMQa{(Q_Uo#){yy+9&-JO7#`qu{PkR+PV~i_MoFw! z5y>LXRur}MOB)QRQ@{!^bM8LpqpRxi-n|qsM)F&;brLz1Ji6i>VDBHahWGyfJz^Gv z&uTmK8opANjgl$bE5;Rkw&Rb#zD{%0#^v|~bt<1DRfq#6#(=eL#dzMKgAhj}80Y+S zGE>VzSs(Kn>#Nz5=IAf1t?}O7KkQhA6Q9~n;BaZzy zF6_l{%Bzx2d*eH?*}eKh3=$eOCX@9{)4I$dLPO;Gi;_>MHb5ZY0(kf6yOuoIC8bJH zq*_p`51E02eO{6~kh~Hx)RGLMJSGSTwdUHeliY?ABoanS{{VdS!KH?c zX`*XZVV2zF3l`A3$VkYQhy4|9%H8?~Ilga0Z$6ZitOjk)qs)d$SY$BCC(B{n=hEHt z+pB(J7~E2!C5!V!SLYH|5*ggC7!!_0eIa`e;EsTtrK91#_VkN0$>pr`p^hnIiI!#D z*kDn+p7=atJu3OOl5Jj%6qWARrxec8sc$QH3Rres1xx^tj7rt<6qq zvT7k_uw$!b?D@>5MZ-D}K9GN_r3qGPqSlsNyp-7_xbm*$x(Vd@Lj`cYp@Ik89+*fx zC6NmuspU^{*m#T5^2oCVpm2|!(IFsYW42Cux|A+zs#k_NuiS-NrMWEWqR7(dF0YH3o}xTB3Q9W#wRLwZW+dT*CIbpy6_89HoJ$PfY zUdqL4C?&L6#5LiM%y}duD%l{YKWzO!o~N2Cf6OG3IfQZ3jH@Z#xNaB{1>{H@*kEJd zJsD+WmN=!;^!JQU6mv30#7Dh&j5bLsxCbX3p8YJOKb4I^D#c#Bnvz$V&zNF0?8SsH zw+^q2<-NmjGws*2Q96l=bf%EhiA;2ELR2_8?!c3sqp>*8M#(BosalTZyAi=EJv@7Kn%r{v_ikLLV^P$etZt}Se8Ge_ zt#Q~n95g|=RU{)2I(hx)jOJg5e4{zP?p0UeyB#sEBvwhjF zNwFO;M6QpNJe-Zm-<%GQyBsxDWs~NCU5FXV#Ih!MKXLX48T;p@7Uq>?jtZ4kr--&Q z8DOY>r5l0d`=8s;IJEGsv(*<`#jAG`2o+|jAvRG~Es}bB#T;xqp5*o)W7Jlx<4RZ) z&ufs(8q!Sr7|Xc+n8-W0KTmGFyCm{z=1R%BIU)^2yu>_gn9M+v${u+H6Yft!-k7$$ zrObxZWoAX5B2!R|uGZSaIbh!F&sM=4CIBS~6qQ@U^V_SUnCzC0BQwf;xn)M$RaZW( zr@0-n3C~CQP}0)gMAO2l;j=WzvmMDaQGym`jr2XUVN0OP3i$rdei+Ot^R)7HDKOJ+tg88L!!*J9~Yx)OL)pMO?+F*f(RGEWa_IEEjE{$Ic4_^<$sN z=}L@Bg5IFDC$00Li$>q`H7bQ>jvO7tp4cRuj{NnMLMIe2n>+BCHZs9mK4>9WEr!}A!M$_2L(oa`WbkaN)R zrJ1eUv8H)+v>XF+KRJj--?Yh&_~3dojyrTru+3VdLADD<8Mjt?(D{t6=hZ4X`nL9L z`bq7Mt}wozsX9mumaE$a+*RgRie2Dg$2>P6?K$a2Wi&|=yp3kB7N*9uT0&Z~n~*=6 z);FQ&{lUucK;7Q&{kp zqa2W0fn{jql3q7PH+r`5ktiUKzf!}f&8Xg|H1Rl+IRx|8uj)Y`?O2(QtdHC~pK;Rw zBuXJ2R8h#HZ{`+7JFrJQf#a6T6-O(;at`kQ07eN1^VE%GHnCkb8S83@)0b(iMfy=~ zOk|&ON2H$Hxcv08#`!C1G0v%3XW0x@Y6U4}8U0K);Ka%H&mCItGyKJkI;2HvTPqZ^ z#L>Hr+hmENW6G~^;{cymOpy|TGb%>9E^0FBR)q5dVP>psK$~HNF3A=q##pzy<0^X| zno_ZDePY#VWir7$hG%?vD<~riT_eU+{{T_X_Qyk7j;lIEwy8rKBxo1S-yu->E08@U zkEbL1ob(jdtj!^{O2qN%eq55q))`;QMEcdpz#sguJo{s%MkPZCnzk!mspnCbP)hJS zt%@<#QH5Vm>8EGGG6xHR3v z=0A2-9f|kOf7_#x5|_0n*Y44w;2RKE(_UL5zQvvtQXoN`Fir!WevbbDp1BuAmbG7u z`uYmtCAVTaQPWmbLZw49CU8dfBP{;_>GRiJYPIzpPr*K98=W2&p0djtlzDNM5%IZ- zj_cg}5!WyHcS?=EJ6x{;g3OXK`FHLonI!7*hY;lYpmyY7fJO#$(kg;BkBr7Q|kbM#kd2jnpdKxXsuT-fmW=KP{I*gIF z8K%bd%X5q|I0HS%&sK}iPeg`j;C(g)-A-5#G?JAn&0*T`v+&pxR3R8d4jG_h_t^V2LcfPx#G4mjtn8>09>#$OaI+VN();##^j zD2K{ZwWw=y4T`5FQUwH&x7oQQf!t@LRNT%4mF9H~UY)VoO}pND58toJb>@q6M~ci^ zZH-!t(yRc-A$5&h0&xx$WtmCb6r49~bmpbmv^gs)s!MCg7AOAzmv@Q?l;Ce{`XrOs z4CAgb(Di}gO7^NifRvum8nH$dlT2YVmPVEUask;jG;+9wayVxf;_(DW1Qsm)Os(7=higY z?p|Lig@d$PP=c9RZh}yGwmE!MDr1lSVk@{oo_gz8ZeFI9+bXZeC(JATaUKx@90F~GCqJ;p# zBpjfPfoJKi4?mJ(<-mQSqE$><0PDWW1{7;Jq;ht zl4hf+1aJ9^70U%*GxWlPkQk1{ND%GG73Qm|&mPbzUNB3m$4iW-F(tLl@)&Z&BJ2FW?W$9{UlD|}t}$FD&?ucUZR%~@kem2F9&dDY`p zlWPdw2rR|98+qXK(jRcf7(A{`eQu36!&*r1j`7}Nae%vy)Xyy)MpdJE8s&kS^F%zv zbvrQcoS<{hem{0P#jjXcZ|Sq@6eWGv8RBRcCMMhU5y@kYFh_2+2ZW>eui{NQ?X5uk zrjem)f;;W1JHx0-9A|N@oz6FXCpcfvTUxc-RZP;uID#3AOK0cYZbEqT5QVlbOS{(0&Bv&A7|%tadK9AmUbU#w zlHZu|#}V@0TzXx>87Ry7{q>q80dx}K{K0oN1e~VL1@UDd~jqg*IIabYfNvX<0?pWho?sK<-Nb6Gk zP4RDuJVU8Xr;Q>FD@>srl>~YN$!SShc26qBZ)f;hv-=*Fg@HdNfpA1>A;eQCd z9X4}XD%#zZ72}#oUvQnI$RKSSPp6Fa$GfdjuG+@&<@$dsz+dZ?ce!|nDWQ-@>~YqYb;=(=a?LvlNjm1^*oOJEEh=EyhWgDme<4nBY`2D zh~D+6R@2Ba{{U1HK!0VCxgdA<>v8yB$9^`~bvciSb)7#@Sp;iV&AL&?40tx#! zFIT1U65Xo0t)CIuh>zxKgd`RD^7b~*SJTfKZ1y9!U2RG?r=w{`d8XADO$JyeNOt)F zvSWuNjm4MWJREhMj$j*F7mU!^T7`O)T+R-AdM7_EYP>4UR%>vx`H`&q&0kk3jAVVm zJtC$*>1e((0{9uz6ng?vCYJ7&rtV8?QJwHu{NvSf})O88wvpdB4gqROD@O-9-`qfCuP%<(1=$vO0E9k+! zVJvwrPY9kk%FJ!cG+!|ZEM{M&r;KBAe@SfP^VBP+&8cW`)mQ~9_Z4hYtrU+G)+AQp zSr;l?-tcq2UY*w>jgIN_3=?>Nj0J6PDWKXnM~0c7^)-=iLiNmx$zX0K*jJK>XY z`K_R0SoZ*Z9>w#(?aw^}Ko|iSaqN=W8oTS!PXyvUEYOlS)2UTaB-3sPCXxQAwj8id z&!29iy{Ab|J9V`h>u#rzu}1Mm1H~vz6$qp&hU`v#BfffOW4B{iN_3XZR$$0vW4c+? zoE_{iNK@%vcMkbINn(@Ttrco;n8jM65gbTmi_&*U$bI|byYwAovqw;pD3vVP{YdQ3=8!mSfyWF7 zZP@SrI=+h2sddb9xu(hy)J$bYkn+2b00CppMh1K5q3pBAHB0p8io~(X<%pE*F%YZd zvu6r75_tsrPdz-D%1exJud@{>{1s;2rzP52nqNwJvv)hxex+j&Q~g{VV|w$|$s-F% zO4Sse(o~A%`e%~i3p4soTCHV z)NnW)anuy+Ty1t==GBp70x2}=Yxcan?7Q z#ED+bxPruF#uaB#^(j09&JTR`kLs@`lc@p>ii%6#HfjecG?L?X&;WSRj!&{Lx4%TG zI*MJgYS@}5i^-Z*n_#T1FEPe5=_S2I{@tfMrC z*>lgoSxF`8amrP4lj-_x>$Xy*c@d2LC#%nwL&NCywD!4J z*jqK{g#@t5vJI?}kE_r-u^hKJ#~l)o=~lHEEn2lJN~&7CvHB#04@p@4{YSaaZrJKY ztxC7WIR&_FL1}dOtXFbMSKOl>Zhv40lA}JZItOy84{ac?rcg;0H^X{1h9f@6%5TD> zlanK$=PWaxp?0-rRM)r2h6*L#w4P~gir-R_JCFO1AC8?{V)tg$AfXh}8wI7oSDSI+ zjKe>tpQvNorPO7i4!M4fOD6qwtudY>1_KFxh0c9oVDd0KannI0C6kFjQEfuzmnpMm z+D`EAv?|wDv0Yo}E1p@g#?nD$fi5|SEQ#orDBl=RM+A;X z-1Uyq*RDO&p{!E>05_;S-zp4FRa~~&CT#CyVm$*HU8H1=I&B88Nb6K5nKsvIrwA3L zjIy>IqzAQl}P=3S3V zxhys=UV^P>aG3yG^AFb+@##!~klF3+&qH3g@K~HY(dsa@lr~nBJAPe<9%Nu~DyTUz zoZy3!dvvJkBT&(Q`Q);HFqYCzlEpWfkdkI5BeEp8MUkWIXu*d&Fmusj4$mRllSW=n#BsboSJME-qm=3mriGKgaiKo zl^8~E?fvuCcRElXC68-uUb|e>-&53NZ8$Sc4QQ~@?p!2L{r>EJ-LcV8-ZZsJwY7Tg zuJl&i&WFsRN#Ub1eMgRW40HZE3f0M){STLjSg0vUEb}sFGKc>FNr3uGFACk5dya>i z-H0?gjV&)aAp^PuVi(Tb7^vJwm|!@1;s2TQ2yCLIpFF;v#3nwI9V zCSmzD18|@3>2FBm1p9Q~RMuwF-d$m89b;3nONlF}X{4VXS&4%jA>P6vryMh}J(@Mh72X)q#)?`}I0}qB*9>@>rCpNn{}{O6<7d zPF0X&a_0vP!5udpR&2tF^eE$773GCvhCpP3C?p$d#r5u=IohQ9LJW_%JzJ#d@Ftfv zs47u|RkaZFV2-9%7*&V}kdx{ixz10wL@V4~YUtHGnPd$L#!@$0?HD`^95T2a)Z}jW z#~m-UlWLm9V>`zbtzg+NBD@V5Rt7V;AEiR@0mnS&s2b2E3yiDg(q`2>M)mEOl8&1* zO4ofY4DQ1r;OxYz@WHrVg>5HXYT8W(o;9u*e7tO;DPUZJ-lonJ;N#zu$?2Vqa=rVS zpYw$jrHL~&S)ktWvv-x*K;8Dj_Z{=lb~P2VrD)VF+=@w%`7j$27TD+MV#5TVamNF` zdRvQQ3Vw8o7XSiyF7m>1t@5FMx+tS?Gy95He=jvJP=1G zlaa?km$9lmx3$!DO@-y7RTdW0+zo)B##m#P=eKNi5{68anQD2o4gD@=r$DO;a@$5| z%$tbwSw;zrakOM^z~`dv#a*I;+ubnPPcIVJ~1! zdEv0!068J#-#xl|nsuS5 zA)ZE#+=XPdEK&$r<|;$wLF5iG{{XK-KnRJ9O1DqbH2LZ3T8%wU8y8zpdY9`XGeH|3 z>Sa58{Nx05;R==Hj=UBolHFR@R%ohNCFr$+$t%Gc?G3-3qduSy)W7GXy2bl&O=eoc zgI|uH^16}vyI@I4;i8Wn%9HB{-y@zxKRfc$T)#A0hV4}$O+!(qDYaZp8tsM^R?g5t z`jh~D`Unvv5DuPJRN9kNig~N)(i#!eF)LfIxY?Aqq`M*gHDv@~DI<<^+!_r8+6*?P zr!w4jm(HrQ7b^i@(^O3Ur$2vJ zw6?3rTQUbE?FhK^##EzVZQIcdVF*mETKUfpUZbc&mSkH^Ew{CT)s$@uAjbtsP|T+w z4Dr({*0iyvZ>4r5v09_sp;eWQ$-iWofv|F?kf00$&U^HdXrr%YzMXSf)9>iFrvCtx z-7k|Z?@^N`MZ$$u1Qa~u>OTEl^13~!=Uaa>ZYkk+uMP3GFCqOe8h}9zq;g3o1awgd zVoGtS->IoT$k3S*%?&<3o4W&)j?|Ji_1rRWp?C@R_dO43(Y!M8MdA1Xy2e z!YErSEKmZtX~AM&aU7A1XR9Qfs{jW|XQ)<=wM&gDoOS zjsV$M$WltoRlOi~&p7t#T|!8--x0L>o|KetEIY4Rr8xnaTMCGvMWfJ&TMV8K`HA-+W)MQIKjFuvei#n)A^4Ej3sN7XZDtQOntqE(wdX9;$J)aNh zlTlo(m+4QsO7>wqMJ+>|u_rl3ZNu;H*Fj6D)}L6JW7YK=twL0uTG9a)=$*3d8wK^W zW71cG%iI&sP1csGy6%~(PNuW9rxhv0e^PWQmRZsBw2|rrV;ytpHI5qYV!UA-k1e!#ohukxtTN=nnFR!)5^EZ6mm?1@-=8f(6omPQ^-;GX75(1lkH<}G-1idGD~V4) zp+FC6^0t?x&^6|z z6jt@QO?Yflh%`$xBYIS*^s!9uPyqbrt#RXRLr{ZNuTF=C@9WwWizY3@2F-*ib%{V= zau{K^jj{v7FGc9OXNhXwU0cK#XVf(ZhAT5eRFgee#6?2HzQpiJIXg+@aC+ZOgf>Wp z>EB()Yh5R@&UMca=@xap775D5C0S&lO6Z$xRvnIIi3m9?xa77KzWrd|5Pl@5f;>Gc znp4SQS)4bvc;uoC&{UIQkO@fzm!IBv`;LLY5}jR@MFMH_1}D1F zk^cY@G5-KLt)=LC9F?@ATnf^nh_>7<{{Ybo7&zJva!Jo8w^(nCz9F}YT4;2=HfmaM z2_=a9;;~r1zv@m1&cqCI6!3G7{PnfZ!H)}R%R9KUr%G`nU!G`pO#3ono+3gbvwMQ8 z`Rh+y(CbIy8ro=@EiUB*R@5qtB@>TPjo%xIY=9ht&mIHe+Hdl$PJKhoM#-%r2F@+*LPDqn?L&Zm z!1LB|X3mrYG!)u;&}AZ$2uyH=Z>m8d{{T<_0F>|f>#)FS(`$N#>ok2SmXtSC9`VmI z2XBvm_(lB9NMw>fp5=r)&DCvn>cN!7Y1p>H2!ax8w!445ly)hm#S;54h=73EPmBuQn(! zGzgGM{#QnLDvpJwcuKCB3>DU-a+pk(DFNj(HtfIu03wlr?~IP*lh0ZQ<4&<#{xOD? zEl6tCVKc1_IW9GpGBbLE<04I@Z3OVUSc8t+Crt5Xlyuo{S=8gx638ikPq!dTr6k#o*l`bgu{A)O9PhB+))uVQo}QVU~H9K6Q3)^uXt8$`?8A zM_Q#DO~3J-YRe_MwJE|cJ_lmwD=v2Hncf&e$N;D>O&GtqVyiKNrhyceR?si(y>_0&sYs2q!@7}&ng zkK7w2eUC%K;m48`N4I)Awj~fjJ#Y)QepndWE`fG9stZEW!7irnkXPO3r3Nl## z0G6>M3K$4B?m3X3iPZuOM)9?s{^T^(oR> zD${*aSz2+Jr+EWbge&gA<8V88$5{&}lDdw3w`?e4w$WTPW%;cd#I;0b$dLJj{Ux4X zR%9pXHnn zkNLizJPYOvGfWHHhy%>1a>@*QkT-lEzdaEki3?39b%egvdeSVmT+2MR9VDu;%ECCE zeM;-JZ*2A|;~4fG`Z#&jb+?+d1vMCF4uTg2M=bt=iwHS>JxAGl;GTMy!?iRxw0W%PavAA6gpz37O$~xc^C3XQHsPLR?Z-?G zpEO_dTB1fB;o;Rv&8H-7=|&{rNsbEuRE~wz$?FP(vXk02+Iz_IQ+mj;!wmFXtZNt> zhV{nJkd+0y7j=So;TO!iL62Bz1hk)lUwkB!(%Ln>){@7`*0*9eoPE z&GtNY?VkNT)^z<=&6)1ky6{D;O9NYpsi`rD@MDTL?7gr{1|9nzdMs%XYC4p6Zrbt^ z#N}o>a~R~aBqXql^%QzQ2a$|p)8C>@FIcnAXQr*PN!BA8t$T`+%BE*1!HS=36~N~h zoTpR$z#M4$2-G%3bLP{nw+iWBM(b?L*H-bzgmHXnjoxVS?*n@ zXkDp3$lcyZ=2ndidw}wMvyJ2q@)okka?%R7Bjbh6jB^^;?RsESDDL{Ax zf_~)mds4mp^2LSJC)Kqzsw1kp%%!G%gJ`h9Kvw{Acm$tsZk)WfpHI}Lf{a?Woiq_u zVH~9rt9nM(h~;Vcs{Rtg&{DViQQ75v3U5hTkcNkdI5Alk(cV>oOab|4H7ewK*t$*V=FRn%m%j=^H9EkHJ^F4u}; za(52kFB$GnO=#+WB>{s_reLcaW;*lNRr0dOF{qVCrN3$82dng@l*KgFC9^`LQ6sx* z5TG%aJ3)`O+_wZCJ@L?%G%9WgQBoEzYj;h(G19COVJsx8I=W;OnrOzvH8RWPAj3rEcwRCA1a$y}MaE?xByj%#CHZ*u7pm|n zmCc1RuxPh;NvFlsNRWV>wdav+dHDO?#E8OG4Yw zm1RlRXdO$U1Gqq~jK~>yZ*V>R`gHNvn_iY_Vu|$bCbF1=mHN+sqCeX)S2XV$9|+24fr(^rW2?v(nD6VN?9WBT1s|W8J-Ci3m8(8$fSdYB#_wv0!Yq1$4edy zRkc~8o;ih@cEj1B4UEGOkba(2lG$ka&h4YNI=-ya)zs%!g*@v|Agg*zDOp(M(s0KE zYW*w-8T<7l$**43g;~>2^KKN0ixQK~0&=m&fRe`?u_wQ54m!7z5XVJug3ZlNl{xRM zRWMc=GU3&OW;S;B9>d*-zd%QDNGEZpOALr6HR)dqEX|g|cT>XdKBWYYN$991KdCjk z?MfKN=u%5;t2-CirMM+rHvxUSj--N?qjoD-<7x?F%j}Y2Cebv=cC2!vWaN*z1EqpO z5MZSw){eDLGDq@c-WTShB`Z3o>NBr7WBXKN{rZ`88LaqB>NT|Zti186)t1!iEkz!E zC4S7!&Iu>%M^@Ral2^5;+cP}KN=k^EL!9kmia9v``TX^4^{Z*x1h(}PU36$Ck9n;a zW!O&G!vo5=ZZUz+JureoWQPQFwCYr&Yev&_mzE5y*O8CiT&I!jbfR)y!OV!dax<_QEfqh`t}Ac9nkAUx-vtNe7@B#LhlRg_aiT5;{NBa}v! zqGP!jP2Br}F~L6Lj+fp_$*NCYK`Uw!Rz#alODrIaE_X1Ia2-H7IQPf)>XkIhmr_}Y zj-Zw%6j-uPAz#x8gY1Xa+4{OsiNaXjw<{|7sqR#uiBI>R*NnFDZuh3*S;x3KpeDwfHfSm{S)QoJ|3ve9NVrcr%M zkbZzU^>;r0-5v94nn~2Yc`Zg{&r&|M$>N2?C@1_`S%?#o&#%Kj=SnI*wUqpJX=UM zYn30U=l02tFbMYd@7A%#5{cTI9NN1SdXB1e>zaPXmc$2SlEzmCGDp?V?*9PCR_ajN zpGWhhhs=L4JP{x{a6fdaJuDA(=Q;L0M%y(CQd+XgutG$Y-XV#kAZ=Fwf)6~AoPIh_ zESDagYW3t48SKO*hHJYacV0k0QH_A^R~<=(3(Tifbt|4lX{=7xA!JfSa0psA&Ry6z z1V{&`oaA-kw6?YCW}$(pL3yl*l}D6RjijC3&+Y_{J-V8$(R}I929Y4EO}Vo79$wBIoRu&@6BFcDXQmh4-$c>r~DD*B?O)GAok??meF zUNi>h>Xk?&lYttB{CCGpXSpSMak6={OBxl9NLa|>RPH$UVuO-1$l!6($n`1TT4bjj zD-@PNtsRvQoX4I?9EHK>-=iRsj6PijvucDeHt`gpQRkDta1PVA)BU;vK@hGbJC@bU znP%B)oUobZP(iI>Pi_V_hUJ z#~d~d`6*d=>&XX_AS5Z0yB()@u-e~X4mwiWg}F5ZR#{Ez(h7=>n3}752>r8NIL}NPchoD< zr3E{6URuT(qn=e?S393~I0pn^W1oJpD=lzo6{;f72Ir8>W0(n4J9=0*a0u>uemW+M zHpR^{4>-j$RCpw@0+bsVgRm&pXzDeh(AaIO<7*6DaQr5!Nr%EU+Dl~SZEwvPF z+6W(8u>SxH_vxKIQl(vL8C<5Zs!*vNFE)E^BvsXZhlO%-bM>5(-6nf7CaYcLwqsFS zX)rEgjiWhy4*17p$E)8xWBycE!PAzrB}tgcv7j~Oi)q|gvi%1ZRsI)oT!pW#Q z&2niZXsl44UClb~!HneKupEF#ZjPVDI!dONDd_iZgL$Aa*_bSG#uTWSxj4$WAy05V z{rXF1#F~Zmksv{**7d|@SjHhhGO}a1&th^;KHV-<1>=k+pYY|&9vrsNLhpWgghgH~ z>OeCd!yS?V0Xhu%2Y{kls}Q`8~wtP{C-wP%sm zdhpK1c?YzS$J=wS?ap!EJ^F9wm?_Y)V&n!$#`l)2f$N|>l;uv<_Rce(excfyK`N{@ zi57*4tlPGH=Vz}J8yY5F&g|b({qd2|b|=(q*oeT(X`WSD?O6!@QOhwP0I{CjkaSJJQg11i2nd?hje&ky=PEL%V8n%-C%&o zB~WwZk}wsIu*XE!%4`UNy-0Nz)aqN@o@{I+m1{-h%8_Ge+ZaBDPpF*p)YHYNE~RF? zMCxGf73^7;(vpr_aQ=QxzAAuf>l!<(oX^Tj(r3@zUy);*lyP zs6!8!-$^a5PUJsZXWwsSIRN&@ZkWLxb=6%VTXrUP0VkbFM^ouo*E|3|=REc7)b$3e z*DVIKVP-2<2-JxnfFE11Va_}8l2^A&jHVt@HeDj|E}y7cuk&zVtT0uO9gUxK$;%$V zcKr0cf~JpB(OWeIS7~b2Vj5Xok`gjLmm7{oFne>-YZM~8sZdEKsW^F5J-TjTk>fu~ zMi)DyAJx^h>(!Oxg5_Jb;#)G9P)K7Ht{}YOAzyA zU<(|&f)A|7PH^O7(ZS=tP#84{t-XU@I~HCk2boU8C}cr{nA?!6-#N)0Uo5XvS4s;b z!D?nxD?5-ZqwuIQczwR2_y?%(SzqL|;FT6&>Wxc>7c-!g>Fjr_LPgS`HVkE&P zr%tdEo%I6Pl6N6tVBVHM+E;#`9KHl9MQ$&46zO@b8Z(exqC9gPa zl1GCev_)7Ps}36(DmxM1qXtrl0HxBW%j(p&)UjAhnbaN^%wfClcI9FWI}zL14zdc! zET)M#g)~W5&Py{~w9J#ooX08JGR}Xe8+x{=(`o7x≦jCPMh0eAJy(e)Jv2?@Ek& z9Ot2KYu9x({{WJ2Er-q0cAXL{=sO2tklqbm`C_e@t5uRH-cnVF zlq;MujARZ^wg&`sON;g(SuAMcjn=G)(d{g-NPQ(X=h6PyAC8vdPYG}bDbyEaqjyDn zbIVW^F}=oo2^Sy$MsmlGr>JIStzKy~@daruSzw#btU7v{S$pkrI10b{>KhDgn^4(v zr#)#>HIno}Jm7-q=vj{C4yJZjzWD(K^~HO zs9a=p1z(nuI<|gcmZ5YKc~M~ths&yy^oAc$>^d%Hl(bDXI+eWXq)6;RD*|Fc#^cBw zdPBBx?a+I&iW}KFQRdZqhg(fGP^3l|nVwVcxC4+0JnbXDR>l>rB;>&?4viuOh@**f zm2JZwkIs4u?5$r@Az>4i5ydPOYl#nhFmhXrk5F&7->+>obe7ajsmPNm%j6kO*hwb= z8Afo~<8D7a5htP$5f-GkV??QA=V(Pc&m?-B((&fRMh63(i~CM}T_*DMNg-B10MjIC zS5U6|W0(}$OBUtJ9>5NvhQ&)4Dww84RD(WcxIzuf!){W2VGnE(j<2-Wrqr~nmmx^% ziJkIMWy>mh3~D}{ckhmhLWy~vwT%ZvzviM|(*XZK0KZyQw5tJa%3o=WA;uJ+Pz{yG zx4%x*Uy}a-%}wRUG&c7|6iQPuGU3O37YCId-76O!y=bgmnX7JSb8w(^gGBTT<3t^*&NOB)|vf%+7sE!1|6!ALpdhEK2$^={Jh2$SX29ff zdLAU6Y2}kpq-C9KEJ9}eW!lFfG6*Nr*^Y94-5&SsLk#v3lem5S#~^2rw*e#vJY)<3 zg*Y4zqJ&DhXf)NOvE*Gd+P9kS$0<@aIRS=phk|${XWQGMwK^o)o}F0f%~nYOYHt&v zSodI@b`OtGAdpA5MGKxp5LT5P)6`Tfn_1X;k0&5|fyZKcyHnI|Kb<3Kmug!PrZPL(XOF+*B82uAuZ6%35wo~)mWsjG~1X4&m^$Iss;U^XYNl@2rt%>v(~3t#puIgF$%m9#6Fe$#Dm9CS2rWk97yc#O}0I$;3%@n%tVSv$pMBl{{W12E9zIIfo)wBjO7ai zf

y|L65B(~yOs_ABLIX+(PrZNYFWy>e@?U3>Y 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 bp7Lx9x&10TCw#HF6Wa?gsM>jq@W21rLQ6o+ literal 1983585 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 A~@PHdn_32B< z2Ay-ky?4<#(2hvf@hLf9wBJ)3$2T|qxQy4-G_QUM2zPO>{&=CC;a{fMmc(XO@_C{& z44p>>uj^*MV)JC4`9N2*Vi4_58gNQifu9M!-F(bUf>*74sHWSFuUGBI)e*1rFHSvC zBwP{X-SCEjXT23XPIHqz8%}NZE05@OkK*@NL#NnrcQ$G7T2HOdXC8{goa?mjybC}> z`aH%t#oP=+VpkEG-HzNP{;mRN)a5D(RZ26A0ZcDD4NM%fsQEG%#%fxesq7$C`|hq- z5m#5PcPS!pDt+FkcybZoUxoZiPj+N?cl@t(;!#~4%{?8|HCCz9@m}EuTJkivsJB&q zNgrzqP!uwgrvPuT`7Jz^=wV*WAkOTf27S$!#~i!zdJE$U2DB!$q7y#sS4m}f!M$7 z&V{&?Z)$wcVWLZi_Lq(Y>q@R9Eto=GQ{=WeuR49)!Rw0;ELFn}o{;B+YBnnyo_4bU zE3~)#!RzB92D2g*QjdEbdiC#D4}N?ct}q_8V?NBAV>_Z$u}dKAtoYOYK$CmRSUc^` z6V#cLkvG`pNv4SUeLrnKBI8dU@9K&yZE1b4G_(ngi%ML)lzBN|e3ED|uj==4lvGOw zXGx;2RAR;ba1XQ89GP`e(KQv9(81>wN}a%p6aD1eGVpWFfW?;irsIRg>@8B?VdJ3oZRT6J}&X`{+&?=bt^wG8_UZY4OZBgiKE zq-4Q8+;Z5Xk>wkSE^mq|uY~4*ND_U2&bwzkf~``-7xv$#;lQg4FB*97^^hRVVHv%Lg(T1 z;#1d5;nGb!nH07o9@4$76r*Mi=qS3r=hu|w|h$BzPZ-zooyvOzpH2JN}q%^J*G*p++vrn z3wN3N*_HTzw|>wKq5=*zx#!OZlrFP2E;41TpL?3_X#+{pJJRbV+5^V4$Z60pvWL1F z68_R%Z<=mSdUK7gv6@7xGrP3*V}x-WT2$R@%$)q*ww~Ak ztNm~}mlviFSplf=SA(iYogqa1RlCUyeU$p!47GEUvQ4t;cUA4cYfchj$dN zcJ+?(Dkcm5Lf6Mg$Pbz6`z@c=O-~ISt$Gvp4YPOhM0dYxW79ULV0a(_J5VCg)^aHA zMmP)w7X)6$xX`Ycrh**dRvtCP$qBKQNGLP`S<@yx3uQSY(5RJcXoS3NO?h|MvDFPZ zD1%`i2{|HRFrS^uNc0c@5y1wbE(>H3G?RImi#-ty#AfPz=LT~2eb00nGe<%?OZ~8I zIkFtc2OSpN%-K*TuH0y8-BMBH*f5YL z*>GlwoClnk$m@XWNXL(zu$W5>cYUX+{}rKaK4dA6xBWZ(kP4~fJx%cG6_(9zIfu|g z1Dj3>Xc>cwiAR|`hwgWTGnfM~`1AT`gaY5XKA&dtIW?|tGj~ttUd6qXM^@)tWnm%_ zs3#sE!;DJj@5F(YYR%c#x6sbUQ|BQHII~OoHNhd`s`8v9raP$pz9?BLTrTU#s#Xn> zOyXA-7~%87j)EH{)%}jp9XI?BiL^&Sbj^aVgqT+D`N$FAm$EnKW@3Yk+<3-WKN?>1 zZlCuHrT@Y5U0!-r+Dgafi)d>iMudSdVKgKkSW>M){qK{(PC@qt^p|sH{U0&lOjfDj zq@vfaDl_w%MitKSouc}eLT$r8K}QXD*!OLhXRD|5c9{n1!qMXCJx?xhna#|YUwD*( zxgiGCsbDVLakE0Y(mmtUp$_{T{kcyD<|Y_jJyV6!s%L_0_GOY=OUfI_lZ+D&w$*CU>P!{H!s`s)jOixiWwd;HDvPBzGg)9xWWs7FaL+dt%pZn#7ZDm_87zW??xmD+d4&wUk znwd18)^Sl*E3D3_6IQ)QEg2+pj$suUf5Pmv^r|xxZeUWhn*_ zDZ5tmJKEQ47l5J%aZhVDF267GR0y()nK=p5yICI{*1&*|;j~d6rb_1ZA~b~YzHjQF zYg8T#5oMVCp{gFx82 zfDFf)788d*D)d1NFUVW_*rzry$ukPm=x@N47>lh*y&#wxi<8a5t}Kp*kxPh2h%vW; z7IxqQxoXSuIh=avIsLU)Or5q_j?KV)>Z@avZ9ngbS;gp{*m8TS-9dwMrr1c~XU_kS zSSoBV-CND3vOaX86|efgtMBt>tmAAI_E47yy<%=_Y+tACO2UjYgYA}CVQRB1{|1lv&3zYrI3F>5mGr7sTDlW*AzmJ&|DrP=im@n$O({|AAKnG2r+Ws?ZZ0N z^g%i?qPp80$tlJL%3&WQ!?nW{&_{#ix&qfKJhSPK4(#3=~M^5bLWlYobiSai zZwy>^)IoQWV8S@X@WJnUr{dO?yp0VKS1s8bVoF4>+=LdKkZjQUASyUMoEnWp%Rh|+ zoR2v^R_Vt&RPRBtUCv>mwO0)TfTf9zB4egs?}R0=4UIE!+Y z;5!#*3(`PD%(PoK%$)K4Pejy7)V=rxK3Lg`WT=9>N#*L1QZWCX+0RIV-J@XDAjcKP zJ<1x_Qq^*7)KJic+ClehrrXLs#K zXq?~|5Q-MvY4c07#ym&Jv5pmjBn3deA1Y=S+29{Tu#=$kOpgzXW3Q7-%^Z_v;-qGa zDk_aB&+^Bn@AgzE-ccKQh=7w9YV2wt)dE%cIH%;~hReMD9E!-vdVA^~!sy3RD)*m9 z>%iHkcRs9^3oMI*j)pViOYjQ@ZQza(wMh|p1ep?1p_U9F)ql)Dsomb}uGB6a^}oMw z^)qacwBn z;q0{A_TUD!eePgIFphAt+!@KdjFkm1aL992}ldZd+#yG)3JO zfaPJG<2e)eu&;3(BA&n5pl(N&jy7fFrHJa1ovP8e)!?+4dKeuNHF*c+Q##!1m~*l_ zG*1%#yR~{2TgujKGli@<9+6`o`qz3*JFJ< z1{kg3sOng9#RKC&pjAlKBU^vQs-rVWGVQn8Sk{m4n|%h+o^#+%2{+O_mK-oxu&h8N zdU*!^GWKH5i<+_QW4-<%6|s-rqS>*{p6hIl(3m4To=i2nqTy9(=vqzjY|JZD((@=s z!rk!ZlSoFC*dGKCLBP^_1lZd5AG2hm9j)NlE?v)dnFb^LN zpFnXHa&97T>`YVdBHX82w1(5A`L4SGj28cEN(gN>7l6c(abDt(y^^!p;9UpG1lYeW zgFt5M3HEGql6kq{r*UN4ttx>p1n6+mj4$74kS1~Ft#VoXgSS>ZvO=$ ztWdI(_!Wb({nzUpUW4TW zUCfS~&=U{%J4|#D+_NmFz`@FZ6E+(drvJwxa>E(w3TbjhF9;HNDDpbwjloQo<7b$m zHM*b}7m=J*o4-P8${ZYUCseN~@%Df{@1q-LKOd;O{AeOshlX$GR0u%Es^=;*K5&~ypd%M2VN6eF&M|69@i(f|F z=bKSLVzyyqlj_~yHH?eBThkPPGNMEjh;)WK*+n0gmdM-1;qe;XoX>V8gCGYhawxo} z=3cA!#NmNOiz>hl*gj^6#BH@AVUty$-jr}#a1P4yJ_}lG^Ul%k;sYMGA*nKrtgf}h z3`D%bIqExHsm#<*;9S5`kT5yD9Zyuk4+p$!{M?9D9BmAt9`YctYwq3=r3)rwxOVR{V# z9bt`2##E%G_&Fp?9OD%tRJ>;Oi(SJSs=&o+1wJUU#BY^tku3R7YTa4XOtie_uQfZH zRHx6%i*VbPdb965lTQA#lpR>9fP8yWBfmF1%Cu)wf}ydQ->WvK`P_TIj=#>vVsN|J zYM{Fuh*iCpW@AlK3R)7W?(*3~j+$uu$VWa=#wFiV z)5iSI@3W2)vGm%!dr9;?RhCw4w@<_wu7xGEWQ_ju{RU_GEnALs7{3K-h_+6T6`P{= z)0vywdi3mb$7FPl^M1G?y;Gt4yP_4^(%Y!gvwV(Vq5FFgxv(hO2{s~0NP(32)L!vP zGH2QPi^T!V59oMltkf;fp;_N|H{Z_F_t5$U5)omh+QLJV9BbsJF?6r9EUWFOL_ z+R~*fMOd1cniyvGN2=*sE&acT;eubWUoDa(l1`(K(YDQ{o?%q#|E|ANYGP4 zdGD_@%g}DNMR3<>#ezQejDdwN4+;)=9Ok^1_rW^-`p0SFORawPMFQp48?hogH}S+V z^939j_#|~Ex(hFbI!&gdEv@dUsaXcPjo^yj>v{;)RG|sAfiIK0I3v_oQ|4~zXnAiv za+BnN>ULM&89p4i)}+(p)g`|M+6x8G@We9XEu8nKTHoo?E~Fme;Iy4% zlwC;3TTk8dx1W)@IuN56VbBh><`*9iY&7Jv)nm20nmb#$2q|z)$X0G=D4eIu*kILN zSHRjvtE<}GTgC(G2)732*8RiGrwa%mljaozjPx~goUL?pQm=}hvW<^m{?xSo&eLsD z%R|=PrSq*4d16x>VZyYtWxzy>xFl~McQsn#?(b8*enI%*;MU4mJeRRu+pW#Lt+nuqZ?lF;E&)J9#m+|3 zcnARCn)#DU*1jNLN-XX5PYqbuU#k6&$kW5Xmqo_J*jEp`kP8fCjN=^rA7^6LdN_Sv z^H-haxs6-Nltmu+hD?zLW4meV*n8G+e9^i)@LBd35miPqHsFd@wEKOvwW7~7!Ef#5 zLIhKuBT%GrSaM0|YIM85ZA{xWtTSqH#u{Ze1qYa|!wdtrYVr@vGgTzInhjd!?@GM3 zn(i&LNg|mFT|2J}5Ism=yvIEB0<=ng=6k6x5&;}33eFi}^Q4oL8#aDbZ@Q&$LF!Fn zkEEP*xcyGZ+3A{n+{vgUbJ`UzYc_YspSlKepbR$^pr@ws`w91C`o%BRDO_D`L-6lJaP8Z1rOZ z5-X^_gk{m2bITza3eC|@2m`ULAalv98e-lQw~J1nb>)TOM70h?aazisF_^bSY<#;H z869)huU}|WTIrVGU|Tzxq<=2(v}D2N2I&eDl`Icl005FZS9hmq+Hx#2w5ee%$Io~g z5hOsc#?LDRWOp^tS?G2@+IoHcrll>EHt@;?l&T7sW%-_FBXI{Mhs}@)8O3x)4V<#A z7WX`|MUbpkPFnEks7cs<22;kvQYY-5?{)Mr_R$q>ngnVG(0 z9Gy+rz3!aOQnIq%oxE$+v7PoO9P}bDs5urrTXzYquAc zmMr#qb<}G#vob`stluabN#U`(GLD?_S;`VJop{@Gk@$<^8La;RW)F!|T1j(ZE}5be zr!;bfxLHE{vPjL0s=rU-!5Phde}2q&`nAvP4R$2C)Nf z;J*irD^#_$v!7C%#Mi8gZE>Z$6-I1+=oLBRoSbuBUOO;_A9s0aq4D|dc}|5X!M}Z3 ztvX)%`B`uIpQC#3#b1X$4bm4=*F1IM;x!AOmq^j(lW}k|cEpPQS^{(PoD*IrsD98| zl=__4S`UUb9a~X!X{@yCmspRQP67ptkl0V0$&fo@r0`$t>!VyxsKMebYQp18ylCWT zG#MBZF*so*!~Xyhj>@b*txx#3+fGZ5m?xh@*IvGSAaR-ie%%%?xNpQ5$bY%pu9@aZiPo= zk-ItcJbPBk3umdkxN?-=HA=H@*G2t#wsO7!*LAH&;ck^CwQn>xdy*(xYez|C?nHo+ za-Vm0NY85Rrc0}U`h3vNmXaOU7i__2X*X_FW=@;Ex(bhWp3i@DA%@8%w(=Dwh&i@S zvTepT0(s9|_pKWZ7A4bk=~_Km=6IH2X9>g)8-L5fKVEz8C)*XPpG18gR=%r7G`ZWi zam{0Yswij;rPgFgA(GKbyPROMu5v>5{`Fe95yPqmW{%AyxZmakJMGhE8RcQod+ixH z?~WQYA06Yw< zfPk>W4D}!Z>?t|BNxNEDMTU+h2-k`#y1zYYU ztl2o@1EqThfc_t!1o&PZFe~X=qSz(1%ya-$XXP4%?jdJpG=b)u;GbE&ZfdcG@J49RZL)vrbDUHh>-5Y0l8wc9Wc*M19LkKyNo?ffa=PY+pG-|6#Q*(aFS z=0a`Ix_s`SfJ*LSyFm0kDk-+>`6c+j_;19+6;JE@ONW$oRPT4`b+66n`={9Jtt`^v zzRhr8x3oJ|Bx|2EO}C^?j!(JZk5gT2hUKrc(;bzhw~;K7MR{{LjUmQbATg6895BOU zhLvpN`Ji%POK_BP8i1qSr|gMM(x2XXYOGpbtnlJer#=4FtDk(112cw^yq z91LeaHvn;(>2Oz0j!D%mwA)krx#buUWadD}r_0-lC23BxD_L7K&fqkXsR6;;k&rQt zIr>#{66TSeZEI$2A^y#@(~;p*A&MJ(?{o8f`Q=}}K?6OiOFqGHP6riPWR5u4%1E8(SYuHsLo1ctuw$+V3{OheRS@aSw^q7*_XbS5!oY~6 z-Me6B;zY+gvG=&FS_LtJORGpMTTz?)O5!*28sX!{KpEJ}(e{r1ocmVgq!Qc8))0`M zb@3)=P#7=X#@zhT`;2kjED z%Os?dVnV+z;ClZ64L;`HYrDwhn&suUju?azS-S*?lbj&v!?W%OC#EZ+x3w#$fVOei z-cK5|$Rj&2K4CE+oJdbKLThm|-2VWigjAj^yi)masyV~B7&ryF#cO2Nq{>*=2|Cx<)aA8MthWfmU?i?HiaUy`Bklsa=(Yv^@OWkuEvd2mtNv z-nMOYn%|)|Q^j9pkgJMf zGt;IjQb`9nM&dg=KM}!o_KinKONJ5M$+QR#<=wVa#uPJs)7!Qyqx0>fz0_@%;$__{ z7$Ay0>Wz#9bNou3M>x$=i6fHQ3wfn!;7>411=q|(GMp%J#y~wYk~m#^1Q(*p4XGL^&Rjnr|SB)4k7$kk*0pqmGJj$L=nIl}y6B885SD2qUT(7kaSbW+K)93x& z=F43)Llp6)q_d(Gi)ZjE;|2c!+W;SWu#ihEQ@!9wZq3MXA|OJ{KjoV!`@r?jZuL<% zIJllUwAHe<4lW*YV`+d~us}h`2aJyOdL@oMD@%%dOPKD20IbqBc1BJa9Ch5@na{l; zIV5N$yvFM0=-yk1yw5&m8DcrYd0*Wb;PeD`tFS|Ap>bvNfuX5gxs2 zt(l%3I(C9cA(p z#}xP;3yY~^5=_ytP`Ml_+nuN})7;hMx|TT=Boa@$Vu6z%yW>B+9088l>&LBQHta<1 zEK4WZl~yR_c90n#&MXcOIBaJlupke5xxEd`f2=ZqK~Q-08SFFKsX9U$NP(SIrQFiR zISuA#?q}23@y%Zm#t?4{mc|tDIOs9$S;?7PdIF%c6O;TP2^F_F92;2-KMCW)~8Za@QP+&9?9bB;&TDfey*sV8vTfzW&7zb31!QNm=qRArVy_e+ooJ+_mDB>H#jPQhaN0I385 z2;@>{3%qKJl#raMBv%n3rLZaCZzIikX`Jt5;Ho+%qU zIL>j#Pq%YThaY8+2P0^~-dne+C|@o{U`!TDCZpY zqJRo1r*K2J4BqDypb$A?-1R?N1}z{M7#Zu_=9eIo&rY;+K!S=WpaP00paP00paP00 zpaP00paP00paP00paP00paP018I=&TuvHyNI1~xAmDsdaHP?vzKVxqs*ShYHYZ3xo zrMyK8j=9P0R_rxBH&w7ptuIir)NP$ZEVk3Eia{9%DoDYqaFSQC$4fH7)T`{FRxVwW zP5sxodWtBiJ3@*mpaQ&3(pB--?Hj6x7SicH6TgZ$+Be z5=qZf)N*;_sjZ;7VB~xzdnjhPy$r2u3U;egwx0xFti9*uA3Zyu0*nmx?sH2;6^Zw0 zSSX^304So00PxG}X?4HaD#_4<`!viY3poI)p#fjie8hk|oSOGK@h=BjUEKU>)Mt3$ zHa4P1S9T_EF_@|2`?y|Dat9Udwd&@!jG;|*Uzzzogw&l(Ha8t8wJO!7_3D+Qri)9b z>$p)x73CkS1#*5hGfCh}i#uzCw7I!pi8FvzG4qnZo7aQeIy8YfVIr zzSn)_vomrR8;%A#{Gz%ruu`g%K3k1(a>L}9iAFbVD5c+>sM`HE-0S>5Vw!h?wA(oM zVITzV7&&j4kL6C(?-Nb%-R0vjRe}=1o17eRpT`x% zd^(t1>DtB9U45!)u2tl42nQ%IcAlJe^%bOPbJM9+uj#Xru4hjHnBX#sI$kd8Plge) z(|ua}H}B~55C|ah4_YX$Gwlq$JQ%L8ZL_%&O~`$S=zaRurDxl-9d7wUlN#(eBy}L< zeKCsAt!q2V{-2S-mZcgTt7PQ9=`f=(R%W((ai z2vTv8k}?Q2+|@h>)TDQYm;AG zrKXiM@*E<72|Wf*IriqW{5@>8J_@n71O<%_PBxCGpQrS$SI2%X(KPP|-dKy+uQf^G zCJQTR14}Sm5&-&j9+k~$dbf$ZQLII#+Z3~~w}=VK#^|bW8CbXR^v2PQ9Fty-8v!bm z9G;0iTkL*woN?}7h2jX|sebyeB8+1TH_bU+sXN(e6yH>}+f&m{r}ph~D+?&(mL(!f zn}vO%G$52Je~T=;Nc742?$uj6NUW?@2)P52#0;_ZHEO)tjyJS+KS#h*#73VrcX`WK zZI_bt?)P`;WQy{sWSKrZ*%0vyc_)xFtCKF^m6Rp>iRo5 zBS@|cYRobuKzMA9N%Y4YSFw`P=XDbPR=)G|j})^7g@y)AJ1WtZiMuGfzr#+Op7B}g ze$%VCIbX9lz$5QvPd?oD_N?t|S%%k1DQ!G0eKN0=9{dul!AlROYivexmQiiD%fi3T1C(N~S`#}5ZMhg9U zepRN79wl|?!y=WHT?(>>Q`8ZVY8XbzC5S5oQX!ci zG?MuudgkNRl5ZR>iq4oD)J40JRC0L!wb8NL8!_kxYs>V#KK9;r*Cx7&jJHfxV1FEAo8p|$6^5^dg$TBsxu@kAwSKF6{{X;tJw~v#jdl$s z0yI;}JK#nUat?o=(zgK&fq?`OkVRnK#3%8Mv}P#E1PtuSl5vy4?c4LLFtLN5zOIq$ z=e4mh!lj0nEacKo*R{@lbx#@DKqtG?ZLe)gm)jaSxC1;4D8@+V91-tOUwHn)TLh0y zHz|Bdw9&~2&kE#j1$u|U=tX)pWa`>QuB)cW6p+F$Fbs1P8<2ts!Rk78uDUp^G^!_7 zpWXgP%;r2jp3uTnjsqOz+S;P#cmC|ti;I3~{EL=GR??wqpUjn)b2rrHtyTq&plys+ z8kDh%jl~jC!Zte-*yGo&Z`TcaZZmi4eSTMqr(X{qSFBP^J=3<&&-2_Xp4W9vOHP4X zP14Syz!q}ORY#!62a<8yis)#mr8ve($z66d%y8AQ7QA$-N?bn^J%E|oK>S7%~QI=I{bxESfQ3x0(zfn`2F!`m1 zqp1wzk2`_%;Wl{q9xL$gkdi&JNVQjXm z2tZT}45&ZSuF+8IP4zd1U51NoL0#|te2QyfYOT0LH+MPfO>H*Cm=?B;v7Qf3dhu7N zquS58Ur@s}XH9*`s%))HD;a?b0f4=L^r?J^M0*5i6FJ%kAC*f*OPrrmSmCJ0XfL@1 z6j4%a6j4P06j4P06j4P06j4P074dh(pN2mWJ|q6o+Q0T6#E%sCb{jKqJ83c9+(V~H z5c3fibPlAk+r7}7FlFi1zR~Sm2Zm%9{xa1yVQ^%(xC&s1{lqE?9f#<@GMAw+R7ShR# z+(jbE1Z8l>5~P%qJcrzVmChdxe0=bo&5ZDBKk$-TSwu^u7xT|EMp!DsQQ1~W4>B2Y zNX8EYXY1NUVCWf6RE&dGv9&E{shjYdCWM@*POUfHRF<0Gt7pdgZ^wU$x)+F(M)BW* zWwiTKOZGiMtmTb&E-?^A-Mv8}OofyK&rDZoKkX}_S=w69b>QzAT-!|uDaWTgBPPCme?Kx$ z4(hUNo(a=6i7lSb?T`tU7gDUM+^8VngN$Sm*0k>J6XGL-%mcr%67179|%4=+d-)6 z_S1M*Q=4VHXk8?Sc7J&NL++Krg=3Hu;jw{VRV(JzT$0>ml~ObKb^I&EzBy?NKf;Tx zel?PNy)6TacDeH7Wb+W0#tvCX7|&wdXBFta5WF}3479nDK`inpk= z(nSG%nRS*_D0A44U0R>Ao7zd;TU}k9 z^*sar8biSr_L_m4L-D1W*)oFnnrhpmq?{8Ok;YUEl5x-yGh8=~ziK}Q%i*uGczOIm zb2PUeTT28#W-~+ri3+rwqLCol{Bk%vbL=bdC*f!ImF2{~3({`nyt)@RO@6;8!!e0dG{{Rje_eSuhi=n{H6n7F?EOzq5>u`>eBa8#UeaieY z@VxU?MxGvS+T72GzaPE;r{>@bpP26Zj=+@#w&OL|XdfTG80fzV;&`=d32&|vdG^|*ZE*`7!X|iQCCJ(QKoS&W z@m@Ws_+P|-5dJFoD^jxXy~F6*lf!dye`P(#**u7&1!GCZBvT;6Wr)Wh^vT@N!1kprzgDO?@rl$+W);d@3^QI<}Fe*utb+&*z9*y%YhrX;y9zw>9hj9{B$N@WLMnB+zSmU9GLOjJERLUnCGuatH5J1ue=i z&A`Vv2fb}L-U&gRnI0}!J}Ik?&#g{w2}b)ZUeB-T^V8`O6aN5chnePq2g<695o9>$ zUIfd@(DiGNd!_o&dWr&j7F>&uIQx6_5LnC zwV)vj0d3}a@KRqqf-#JA{&}krM{z7gZX-n6m~~Yukti7Bo)5Ctu69S!dsP^m?D9z+ z-`UN&+Q~F!U=ZzLFLDz&&p&y4dejidE}L&9khN&8EM&w3%?#5>z!AddYMlN9t!dxG zU?jdWJ;OnL2bR;LW;pj}0weqkbI-37lMt5|Qbt1GToo4&YM?rffk^`@N`MP~Sf?2` zZ3~T7?POgqdRAZcO$;im6F(eV*S))DUPX24fZ$HSajNyx@ zUzM3p9F5ya6{j?=bV8)GZ(|jsjW3~*=e)g+^|#F&*CH7NN1=#}4T^hbHFXO|a`D;T zUHP`l8%MYRB^@@E``eUr*m{bu_E_h%n@+a6vlli}8Lg7$J-|rLOE%x&UqQ(Bt(YKC zFA~-`ZC`0tT!wijJmq9R-ut-DK<`TCu6h{^V*5OHutR!dGBMcli!KKTLpBImDA#GV-7XRRqzjkP(dW)$gM%F*-- z={374?r-m8(^X5y154*QUZP_l%7TsZ>^Udiv3zkf(D;|ld+Xt8G6+grjjlqH@=GeH z18z80192U@*Q(h>An@h2loq!3@-#J-Q5j4PciAP zw`O+KU&<+j`!URLc&RXbIlr|-5vk2E&H7I&S0eImLL%;)`} zanxY*S}I=1`B-Bm;tq1DRBo0Ul3F{a+`kX_9;b@C`T!VbR69 z$8Z5x^2T?ptfz-9iuLQQ3L7gSqTAX+w;_RMlI2}c1|RDmqYxQ!{p|Z!P?p+##gkgc z4y5a8KG@ynW|~=X$}*m2+Bx0cxur{V(=MH^G^-nPyL`pNT9}h6@6(P6&U3c4vbLHZ z)m%N3;Bwq7XyJYp*lqokvFj2}jc;pdI+*3RW-ehWJGVv8P)IoyN-L`;wvSbsTY2Y- zA{ewpLlYG{BHN5-kGw}S58TqLtadzdDTMj`pL^Wk_HQSX|pG?S(j zFnz4)ayVO?nZVjna;<^Rc5+F_-R80MK7qUwzQ!$Qc_d7jo*57kF5pMX zf%lRz{6lJ*_{>cAKk!o+Wbt3_H4D!c-@TRmw+d2tBDPkykq$`Pksm?|V!uZsx!b4d z*GnAtdYlTeTw^TPlL8EZ+p87N4UyA>S>fcTbMf4PQq1_58D44r>8Pvp?{B=~=PM?k zW4Z1mOcq(DbD4lSMSZ{pK7{k@nyvPjeCeZ-#I*9;rOn0F#lg!zK!{uKGM-5}uESYD z4aD-@Pb8Mp4>CyZND1aE0I9baPBYi0PqUx&m<{uB#Ikt688Q!x$`av zRa6c}Q>zv@#z3N^Q+l7T#A-Uc+c$U;C>^} zKWQB+;C1K3eSU31Yx_y9;-5^1Q@V)Uz>h4j5AO0g7&#a@1aVx_ zT(R8z{{X}cUT4DCnqO7LN>iQOuI{>Y>GEHpqpo<%$9mSUVGoHsQQ|wBbE%7?92&&d zcX7&$0F5OaEJ|`hkWZ;K`oX159;S31Ls8SU3wy}Qyt7Yuz%y*xRG;~3M0gB20hk`5 zza($;&3nZ&-(Oo=>UWTNn-cEk+x;0!50%vY+?}O}By{($uY3>tMrb|)_)}`y?wc;Q zY&B?nb@T^o6IY_O>ZXbo$u+? z`pZ^GEvB1WX(o!+#ZTI8u26Zw7;cI)7kL2ZuS)p$$Dg%yejf36*nAyf;cpY7+L*5H zBtL13dopj3M2(%mF$%0k7;+6@{7m@kdGTiJQ}}Q2y4P2q#JY%w`&MmHCIbe_ zf;#8st=BAZB8|Uf3;u4 z5#zPMkUBoXPnruZM&3bMQ?3$Y}Z038naIE4Xeg zZkc14T)eq6+`ECD`2s$Ab+4x0Ejr`G5k)FrM`{T}Zi|_*x9)OCU_C}E;Z^lV=sYQz zM~bp|;xSOQ-pTK6nSo<uls(P8#9^a?9OrIxgbaRe{{T0)6`^pq3w-c20`}_e@#UHArxy?`Awt6%Zsb1z zFmIPVGt#q#gxB{rEiJ2y$V05KTsF}u2Xf~)-k@>KM4ivS!$LHop%tRo&AFMcyP3aigOdRBPTvty@bTbqK-B&lKHzIg8UsCghl?;@-4k*^_})~&@@ z?@sG-T^OX1Ufo_=+(@r0y`9Xg$+1*mfa}Qlze=k$+!x*zhI_*$ti+ahEpD>N!|xEk zc#L3$>yRr_(cTOBnmd`qHjx(*%lo*>vt$f^7JB4#st91by0J^^2;;L|-dvJ0$8!XS zksxq-x!@My4x)=&LRFVT1MN4{PL}C@Nz|cqdr7U2*;*uQh~qtc#vgbb`(m)AV{xJ+ zS9b-j2nr)sE%u|F6yq6T+jc9ZzSHNnj>}G(NuKp@wp!b|{{W@P#WHsR_emcxBOi@t z-4~NhLbtY{i-{l?HqW*zo^#}r&ra>v-n5HJ1?*61=DN1OhE|zvt*#JD_K30rAz6^sY+nr*s_4U~B2#eP-Qn zEiQChYnX_)6a33MkCs^(kIq-2#&(LMb1tNpXHdG1>fYAkUAFHh`oMFNnNTy1pb^ul zHEpeKA6Nd*wX(5*Tiya(l><;3x5(X5GuDJ)jW=o>Or}&knw$$~zjY8t_$}FUq zL@YjVLBJRs2N>hls}C!!MAA=UzNLBPS;t{C7AtJ%e%%y@CRPV>U<{n+o!L0-1yr!P zW%IQg6t!`33hEKf8#K7x^9GRe?~V$L{uO*&$z^`d`h0L&toz}GAtBf*<(dBg=bnFr z5<&E;-gWy%i8KvoG_xb1ljZVDsU>lr-R@jA?s3wt;^-pk_UU)JOGy&R;@xbmWEig; zI*@ywhqs}sr&730Gg{S-jcX2|lE)f7;ukIE9idr!;CJKSHD#>Y6oT5tmevB#ad8#v z;iL?6AyfPtdhPxtIiCBT-@8;R8|ttVbB`NWCF2QA4x`{t=#ybxU7 zMRNZDWLsEEtd|T{SRf-Ihd3Y}HiMjYt=rqjv9uxV=D&8nNQK9irr5?#8ecGA`D3AM zXLlH`Zh0UY^X!aGVW&uK&z&l~j9lcYjPO`=4sdTw(TxW&Gq3B$Xeb+Qj+oAM^=pVBLmkpmXq4*-)A4%klUq*2xNzHi1)5OaNRc_ z;Op;OzhJe}bc^jmH-^soH!&5TE@$4`nl=)%RQL$AxI<}9oIRIJP?da62zandhx|m)a_Q@ zD>w$C_qVrGVpWjHiExg&3vG<-AmElfdkXDtt*$Qg=9WuKn?R}s&7wjT1EJakSju1? zT;$|eKQy+VXn{4`JIL%rX}#ii5ec>JK%MJd(*howbepwkr1K;@-+sB2Y)(CAtFLhB4QJ zQGR1ZCf4R0*4ly6T6>)~#iVse0@}_ed0|H6su7LMF@v6~(A4vxH>%besx^q(9j_N@ zmf430!FnF~Al09?A!C0e2H#P;Rr?x5g%&`ox8{!@DOM#&Q{O!*E4kyeyOz@Ei>uZO z*K1=Kj6oY`%Xu@NxWeOcZ|;hxO%rBOzFB9wx|2_i7BI%mq)bqgk3K3PJL42ucsvE&WPI`=iZD-)*N$GYL}@1<$H#e|}%I8aFc z0G4GullEHU$`n0!u3*SL%8b~Hb=W!o#0qKGBXT50Z zSCQRV3B#gZ&c@v*us&nkuskih;=l*->TJbli4 z4Z}R+9966GnkS)NQ)30)#iol8HYi>diI9Do$-;StKsvd{%Ybp7)b9>m+*<3mcCa>! z1V-XJ$(Q$pHt+doj?ezz=~wPF{nvK$$eL!8E#&QMJd#d$au4rSIy9qcE~5c|3L=%w zwyiw6tgUHn8o)0@ESDE?kOM0!034~#88+ssQ*IV$A1hj+bvr0$O=;({m|g4^(#>N# zKH)3w8v*-=J!BQgCYc9_rMA-TH927Z#nfVs{s}J1J6agBxhyc{Nejr!0n{FA)a@;9 z;IgxZ;_eGp5^Z~n$qSp3S8|pM)B*e>6`!fw{{UwAZp!<}(@YmPlEFNhvx3G#cW*$W zF07ehlk)W9rVB%kQ?t;?{=%@(Y@xY(_+!*o;0-!$P1%`)%eqL~UaHK$yG^(!j%zE# z8kNP?wdc+*(m5_or0`iNX%rKP5E1uC`^Ru69qV{$_8OJeo2bdH&vT>O?}y8n?oF}{ zvGw7;VYyp52cfFgUL2m^Pt&y()mqj@yC&`DBPfNj<$wn)2LX;wDVbe$XO&)AYFY+` zC5_bfS5~X06onSugjZI=KyDpdKQSAZr#)&b%WD`!H*rmFU0q?0!g!^Y?&S*Z%pihT zbAlV3cdq^&9(_3s7jw_4=$7{rNgS7v`7>CTIX3bs=pQ^Xf;b#jHSE{xuS+w&r6!+o zV&LiUGNH76xP9{+lQN!*kPbT1lYI`T)VtKeo*^7CT1NV%#IU@Nbk|wUs=APj0&>gp zwlH^pwN~tB)KdFZIxxJFDJ2%`cPqd6(aPI~`$QJ9A2mZPdwiBvIE*nF7{@=u>yb90XKmxCq>{#4sU(Tyk~=88 z$Zl=~cy_fcOEM-2bZm3dnI+5J>Q6L>;EAy4g^v}=!)jA)u z*+YDGd9``OMUs@Yy>@2p348r#ir5%X14kPX5Ul~-bRbT~YcYUHrTXe~7TV)sd5=B3oPqQSNz zKl;BdT#>)c`3oF?ypi6n*3jmY_nIH4++E$<+E{7uKA+SgIMI=l^M9kfqx zX0b$JbGgd^NN`iG6fpGWu|@ez?F`z3*}xqpmSYXjP+`m`i<#z)Q5+LABrJI!({q_uMcd2Ms2O$XWJ3LAFocLe#w0Cz-ixaR;G zi$=N8(czlU!?yZlZ5g?^o+J_@mibr69av|mWdqu*-C9R^tm`KCRf9{1$VT&YtESAd zb&(E1z+y%nara2+#baj7Wfq&cTF+C^BGPpT9b#C_?Q?SI%;MqYes>HrDGBofoQ|2Q zS2j9(>lYU@M>(=ti|MmZ8-f0>X)=`u%T`mBQ}>TgO53)#)9oj;zmc!3CRm!n-g|p| z$#E;6l*)=eVh_)_Z5;HiXr;EgxNB%9)FagGV;3JJn<19tXOnJCd(^9sc>I-ROzLqFs1vhNi#Y>#J;ejd-T-Gz#+DW8pdVQSF8@}NjakrE$ z*B>JJkpcpq;{@~Cy4^}EomG6~YjUP#Na4PZ{ytx$fHRozdTuAT2CA4R9wxBUE$t+U zH23>-5$g7({KgzHjzB`NPK6i}Jxx=ROH(+_uB970NVPpO*7Hz{PcjHyBU{!GMH!TN zaz^0fJL8a7_`SHS>;C`=L8a+QaTVU957{l*t`_j`RRElchB1a8eU~LahZT$BO+;CU z^h?W4L*4F3oDzY5(c>`HH7@KBcc8fN#KvW@6AE1 zr1!eCqC*C{wzu)keSfBt3(0Y?Dy(~s7iR&9$of{st2OdoY3U3aUFNB%T}Z8YI1no- z8)I*m3<|FdtQg~=6<*0KXYp!5s9ay5luc!LXSD{?C9=~QK_h5ylOaxfVza3v&X_^P zUQXv&9b(sQ3nrZUfqlj);A0GIRC&s$tVNWr*>`8m8-1u6KBwng-d--DXKs%7eqF?> zZ=spSGWhD@eq5;s6<<^FCGgcQ?d+3Fmuiyn8;rv{Lky||Z4 zz7QE2`dgtgNpmRj@h8mYML&5}e&`s%>zY?N6)tC^HT3-sJKH;0F56AN)lz4i;_OP1O z^^LWRuYsUs0OhOa9Ts%p}vp6plToXrJc7 zjFG@naysUerF}|tns+1c&9%B)MLpf^+_vv%VYs-OHb=LgC3ZU;Hsy6>1&QMap0&Ma z9mJQqA|#fx6}Xioc^}J;33lcX+54og${2jRyLPIxO<_2=H@bt}!5*X}o6Ug99I`ry z)+k5(v_bb>&UTVdwN}?PyA5YXp3}_H)9leinvJwTv}C(6iY1djF$7>S0I~iN(w)%} zjor=o^vk=sEj-k=S)r8J+{HN?UETL6I3sosInH+b^I3K=y_|ONgQ@CQaa~StArkCc zsMY@fcjrbhv19&OjE&y)N_~G%eIV-AS9+D5l%*C1wY6Dg^Vf!C45xD_;I=W3&b0Jh zV%6MSC7u3~k*C`3tObabuL7JaHVz(4{{RT+I%1zXjBVl@&vkcTw(~(0Iy9>kZu4ytTFlBB zL}ZN09P)X<^c8Ta7O!GdT6(japJkQam2AXX?hPQeR4!OC*kqC01=&Z;BP8+bT6U|c z$Es-XPjRPe7Kn{$C`T6`X^H;g%ou^V{{VQ7JLakBsU7c%w9B8jS?Ut$^OA-@WJy$< zG}4B_GJ})|r#R%-Rdh6|ykleMY3XTsaWg?@1TX?4$So?lKXh#zG04s7mr=`h{{XJx3K(n*W6di|MQ@4Uzn9(fIe!ID z68u%u;k&vP_IFa4XPFMbp@9LEamXhlj=1SxQ{1HYHhO)%pwurWONhnK*tV)Hd;Unm zP4b4v&QGV|Uo`j+!Mdl9JXt1%;p=FwFWwU0>2nB^VyP|jkV2jY2VOWdL9KYV!}ify z-V4dT*Crm

sn9r)JZ;7&y=1YkE_RWbU-s>BPb_$8*81Xr!8YKKD=3`}rSO-5bWY zvye$~E40lm&73j?jGa|f99F2UVh1B3>G1%kVKrd$C?4umWikI`IG!+SV2tvo8XEbC4r|4#*BK^aUefxjTnwfV76ervKn>exi6Q-qBtFEh z8s_BW!TqAA?-B{QY zx(fAk??=v(y!*Rg^*$9WX3;j?V(9bA*tIyqrd+(3>=rxa+L-P%zhb6E+Ue;zyY$K_ z)2~qrHXm64CP+@0nEzNXkbE91t43c`83|I`|LW9>kn!guU8d00E-)x#BYx&+7III zK=a`Dqs2i^2{(Bh6z(7Yiz=hnNYSf4<{dJXN zADt1*<=R(X^JG>ggY=e0SXho^-%{*;^+~oKIxv;_nZ*lh3F`XzSSM>Bl1f?FFOs4n zwlK4P5uh4hpC2V4f)ev0SrXJM^1eFrOnA{l>DcZjMLrFYs3VlZQQcK6nJhZBYi|2h z49o!8-CxB37d@pPYNd#QW85UYrDx3}XUg9DgP6#h5~QK&~A;Mm25XtInVxs#SQ%(e;a$?UreNm zuAaj*rmTN!)O9h~YGB9`TUw1YVqhSLprSdPWIaJ9M{ zFYbb%>|rL`{))JXw{h}xJN|!K^i@9{2z0VMYv0|);|n0g==X`7ffevDCb>lS(O4&M zRmqNx$U4ILZtCZa{nIhoAFg-f_XAFnTXRkfP7F*Ezs*#Zsr}h!Pre0h@dKE@X*=8r zG-2D_6V*VQ|9a;uH{)@AJPFjy`y?MItUZEw1pwHWUd#{Vb|pFio!WPZu*qIQi&)cB ziL13`&xI{02o&M|DU7i%K5mspV}Ho}c=?pk52ydekdKAXjrN0LP%ieVUsv6$da)4= zY>jA|F6pbfg1joAtACcEz(pAc6XcZ~c_R8iGgnqn1W%gvbBEe>OCs4!Ayaw6;-TN& zbJJUcq+)%9=86m667f#6M+f&yEteYji_kXARs8s?+@H>BB-n|1krgVTpEY$MdEjYG zVn$LCX32Ze=Vtg?!V^O#uXmJP)5j^K6(ih1g)Fhh*c{^Nu4d%vBm0&af5puXz}D8R z>cWj5M15vMGpRj5L#a!0MY;ZEFm?%L~2f!yM z1M1G6E`}T^NKGMQT>=TzeVdge;#d9TZ?({l)tHqS=B`MyAZeL~A&5s){9tYiv^uEG`Yoe{g!LN;th$!UR`Mr>M`uHpX}!%N`ZN zr}gjW7rof9WkxpMsD2y6zYuJ3My$iTD^h43tNsTU1`_RdS`!6# zTotJs^YG>f!3SH#y{E^k;}(^>-Z_hn3N@C;IFKEYwjxhgYN@#~_g(`Qst+97mjh+z z#ok%9l3`Gr@x@z7uet4L9-3QuH6uv{Fo3emA-neaTH@jF#ax!T&X6;S1BOb46ETh= zYm)Yuv*i5FcChsGe22i0dIXcx=^i$7BF0RA@1>r=3OPlf8TMtU)NR%7cFHr>GRJs2 zx|nX9{@1EmmTmf^eQ}WwNQN%u0a=0_$qd$JT3b*tIy5X-6rugxp9F_f7`cgE-CCu8 zFFH?IbJzzX%ZtPQopr{n@d+~Ux3Wb?_P9nqG`SK48rvzna96P?-T(UfAKbCJmh6We z_+Bn@ET2h1^9EmnYa*b~uoJrl_-63#{38HNon43XhAJ3@?vmi5b~HWg{=CF@Ebxp7 zKIBS&wfhFs2~}OEa!+1a&-xalm;J4Hxx1&pxOl!jD2xOwVO2E`3fh56>!JGZ`S5s~ z4L$Vcx6Q8eLz(BQN8#GE9%W{`De-1~QNQ^a zhmGdgAASsTPW}f1D;0&C(V0k{0-jahw`vW+@;JM^m6T@4+;#GTxbO&6 zOg|Q@?1R)46(LsBmKyqBsZ&asd6ZOz+z$c(8!qeoGW|GYKs-&tJ1b@g#KP7*Ml1QV zNeL>cvmg(snPRwD3vKb+kb4QGw)xI~aKSW>U+z$Ko?2$Ue_U3;a=BN zEP#K`@U#>k?-QffaqHK^jffI87dAtMX9(<-MOEvr_ds0FgyNZ#duDAJ<~9@l_ZL6= zNsYt(@wQ%#4MEmT_05g#tqne4)=(ZlQOp@;2cG>nm)1%fU&^}6pWDid@gAayoZkeM z>1&>aQE3?E3x4EOeX(|U4iK_k9$-3pf3x2rw|wOAHNsJ)Q+>)O{Wu5KHL4$scBtS2 z$zk?-An%odg@wOIq-m@7>AvPF^lJ3u2@H7LNVRxm5{>}mqi0vL4<0pG`S?7v)UmI$ z=LN%vWny0i;=IbAG;=)fJfCbEXHFn|ixclXI3H#of3l%YesJ1h#fw>LZp!OkNhPe6 zzo#A7ozD_2ro}4IxEMR~9_C+U0&v$#e&2M6-@Vy6(w)n8RQ9>iZmT^kgHW{J>$y9# z7By9cGumdGM(_(=f6BuM+`&6F#5)AnZL;qWCX0m^>Fd68yt2!lm+z$^e{NWfF^w|8PYxeH+vaF|b8~qV)+67% zrLvIQ)yXGfWWi=2uWD=4vjHl4T2r2^8e`%6D3?+c{$Z~^Zw;!S)?8l)zW>qtF)lMg z-SaZ-bZFGeIwniVtiiiV`cSag5|h}Ij?K}fm2gr6YpXtQY1uBFm4Dk%>Mo6Y6`zfm zYm2*SZ?yw;k{4P}Bx*?}PC8w6UN36jA#!C;5|)j~L26+l_^lFvO&7;Jg(6%6U9oj4 zdAzUbxwB{PzAB;WY(m++>NlZyaSM5o6tLG5FZr5)?ia5j&V#xuWrO-GTcZThjYI%> z>$O;#b3mMIiJ&jd?7Q-?-!$)F=rq37|nI2H!zdVYwXin3DMs>p^0v;svhv2yfXq&!^dt#{)-$Q~pW6VD=K_@zC`nEhw z$3MIG#Scpl$luIW;zmmK8`iSPom=AMDEdqx%i5t|c0zqEau&i!f0RU?I+BmsrHt*N z*KyfQ&R#_rcCIBq-ASbR zoe&;VW~3Z~)h8^b=+uUP>j)d1#NmVnP?etQE_7KXvzdX96|;1g<8XUi394i)Wqu*- zkC31)QXFduI~Id?7%H4x&6=TqR+*Q^u4?h7$t3%J%A<4oStECp85%_c9riq2_=_0S zzf)_$ZTtT+Pah1ZFj|EU+!=ES(Io7`ej{&Ga-UL(l}CoN|HIasj2rc6`>rR?`GWzv z^_7RGkUX7U6=Q9_FvxjO7uQeJXS>w{cieKhB?a_F80t1fZruRyWltc{gJ-YoL=Q{V zR&?+$wQ6Pf8uv0FWA3;ou1#`J;0WDQ;YA$|Nrq(JQYHBxN*7cGkTgoy%1 zV^WZfK9KB|O^)eZiSarz*hika~uZn7V7G@ z78X$@&LPo<)DiY28aN(j=qSi}u1IL6FJZkV8hLT4T}gO09}hWQfUq~3StPR)jbm{C zC7?c?6g8)u8{>97cHCBJPE`8JGr~WLcr`+zsrGtq^y^8p*^FCf^|j=b<{de4zQ^W< z2_M&QT=jbr4?#ppA!@~Up=RKUb0 z6k32qY+|dR7sXoxcc^}sh?H2NgS4R78S4lMV>1cKabD3JreoDzV}$-i4?!_Hw|oKZ zzkAwdaX+*21zE-dyXoDW$ujF8?7Z^Y$yy(qjK@HOodi~C!Ib-|346Bi2!m>jAG@M; z_W>384NY@Ia?b?21J7f0S8ORE!>HGeD|rE2$jWw70=e#`(<7Zc(ri^W~r&t z$=!M?txeKm_pY97rrCjwh8QS58I}5OKNGsRPei>YSVnjZ_=^Pp0OA8J)4X{6>bw{m zxpfvQ0>n)9Pt^^i+9Yk^rPSZ!W*$yT`)du!(2w{cgNsOFuzgV+h2HmVFQGW^cTh_@ z3n07VTeg-MU2tW%$^r$zRkC2JL;YEHJDHTeGNoB`n(k551bifPCvHd3QvbunYLRJ0 zdmqNptr?7XtzA}JRvmc}YHGZi!UbS$ea6&8qXICGTf4&;^sAT$MD+O_bC|bZ( zrk=wgA%3GRS|6P7+}{DkTAF0vKwRH`4$6J^DR%*k)(({_fudqZ$dhPu42%?B~w!iW16H0GZeTf>MLArKE zXQqaayE%qtobGV(5kdpXzpQDf3w4E~dpc2fYIaKK72sw#DR%yTgAhPF_Se^~E{ zCFHWuo8W_v=a|`=>HdSeeXo;{7be~>F^B=nz|NBQq6KRd}5<}4hCndB^%Xqby^yyKX3OdD|6Ohqg{`dXH>A;hI7b2b&LS(Tf z775CnPI@X{9@`X5&DqV_k=b>7lf3sTk`k$IaTeBbIWAI|AgS{l%9p@Yo(Kb6nAB#} zn+9BX_IPhF0L$mV@5l8*cKy!FX@bypj9MFt3*!FYA$$a)JlllgS{ak%IIht*jVEN6 zDLr`6cm7oV|JtDcA1^wO0xpxDf+1}@KsRFp{z%y^D>1H}ySP8zqjDMdgaDW5+OXCo zheL&T?uO!0nKj3IdsY)MK#HmU zb)6t|wPJNxT#J6JN#>tt72*13Q#3zeOA!7;S@q}UFQCI=QhQfy&if11UntaYLXcO% zO}U?Zrvi$qC&P{=9v_FNe`5xlFb<=PCBRs1)cfdtCSH=K#I9pq^3O8;Z5bCT|AV_* zGCaPo>SK5)`}L>V&k{4C!HvH?D!VYmQ=!>{K(tn_np~6Uawz7OwT|-VrrS=omnna@ zCo{DJ6D=BAa$aPd_Agrr(u=q75`CyGsX%T?&xf>V(-5iezSoO+Zw-xb2nZqHG@UO4 zcgSune+&y%5K!HXkNoI7N+nt?VeMkQsyMf}yKFPP6zy+SQY; z88jzBDTB@%VTZp_ch$vU<2)>CfcuqOff6K8?>}E$Lw2%xcrg&#XiL7`jj~X(C~hkF zzpH?wfa!}0+ZCEsPuD66lA4s7yTJS(V-N|P2la*B_q-6UioW}arGZLcfoW6e-B71( z;~Q2=Z&pLY+D{iB-VtV9jPe!i6mjwIm>r4BcOqKDgZ1DBhP8F49%5z?JW-FU0ykAg zhdr33+(xnhL3>xUJB~6p9VF7tTf`0;*YlBz;Q`7vTe@axvS77u7E-aFB{?str^F%% zPWdkbLoT1Y-%u|*tN++vJ|w)oDfXt5)~gLJsL3l5#uwSbOABvYz#%mFLLyHwH%?XT zU93$Z3gj~iLJ_l5+yoaxvAy_M1An#5dZc}w9V(NIxsbA#Gg zmGRd;j&bLQ7dCDoA2(^c!=tKvNT$}))0Fazb=RCD| z%>Fr^s&`f*8N*E8kzSYH=hNBaDxlcRhzH(vNvu4Nm9{@CRTBS=UowQR1F-#!q5ym< z9w<^Ty`D}=Vni6D`!IbvDdTjry#~2iVHGD{(p`}P+G$jSqdw%s;mY|!S-7-8{|nX= zBuog!G}!5CF)pe7UN!uhnzIKk7n}xgECv|GmZfbPOB_YqsdSr#Q#D4Bnxs@ctvc{txbFe6j2X#9V2H0W8n<9*c3e z9{t*rIGleH5-c8EB{LY+$@~B*lc8e#nnb58-j#u?9gTGm{iso;aOUcJSJf_n%U{ES zF59xTXAqFF;mwO3Uz^8K{#~&!tBbcWo2hXj>!6LosrLqat#`@MAaG+#FOTB|stR_} z?s=}1*?8LKKjH837jAf#>>EfLyv*FU^&D1kNfL6nN0Iz?ZfjMmO2F5s7ceyYU>E`> zir^{_!cWP*&B^Kd{yTHY% zUomKl!VJnE{HrOrA~z+NYsmI6^xZq))VEMp;N7M<8{Y(KN_m_XnKUH(D1y8zE|4HJ zEVfvpIU7N$V^K|C5tP3gXrHRyzulaI-S66NGrw1YKdTH_h+R1yF?3%9%xa&N3tQ;? zvLz0NJ9AOjW`-CmdQ|lMS~|JjQ@@fo^ei>{73^g#bZW#->VMs&QgV{nXiiQ@G3PsS zNH9NgkUo(`ipxE-)0+HYL~MMy2SWoF`P_FQPX;pw1Xr9E_+15FJR-1O3d8fxrRUQM zDF<9pvz8x8vc&Ue^xFa936;VC4lxE&ZwCz9>S(#k#_GLEvYyt1c@GKzZA0UYd%&nJ zN%EpZIe^>n)myM{nm@f?95ADRU>Ms(&W8T7&1esVs;CMhdQ|&Vovg)~8pD>0 z{N=)h2Wh#7&Dmrhx0z+vJI)`B7T!P8z<^?X#wdUL@*{1a>m7Izzy!3S9%|tU3#a|8 zvKorb$k5uMzAU+k+twHskSq2ZF8a%mcn2$b?;aCBP_M_raJu$yqOhg9eyA@U93H*Z!+H%o%#S<@dl4T zIK%#qlxAwJs?c1csuNpa<&Fq55^r@F%U+zvh_PcG6V$W@=ZrbVEt?-HNIXuWLXLyb z+a-i!uH?Y_vR)o>X*NAV`%V`*Hv?Y$2WD=>y=b|jLJeh)U5MUtVZCOoTe~FFrNw9b z>{>CWhN2}6d0>6VHNyPzRrxXG61#<_uNP`$V|01=c#|&r^{fR3xHMe9ImehXxHsbSMmc^QL2WX9qPTfZ|*+_nh**vG4!_}PmT!*|Q-<)Fm z-B|_*=P^Z>ue9hP>%MtOIdU3wedfJ9sCIimS1u%;tzb{o?r|{qHO~MoJM%)~^2mlM z!ZN9p<5w`OTRbRDB4)p>V@g+=g+*Zce}6@_xx3-TFQOd36r8bU2U;iH$b*s#~41yReF9?v!rdm@7WzM6#SF_AqdoP-w~X2UA_<;_|r z#jP55b>)#mVCdi!4rq4FoU${z?IUgf>(aP?pvg5?A~b2QbMp1GM!XvGJYxP2kXuf^ z|C>j8xs8ZKb-~1+qb#f3pg&67{2k-)|1RUM|ApjG!fN!zp58pjC^bXP>^7RV$lD>A*f7kr(5r`o&@8SM1A;+hM%h~H_QdL6& z=@q$@#ug?2=`Ia)E(I zWdk6;z0k^{oiks|nnTQ%&e5aL&QILawW|;)ugdTl9q{4zC;ajYxD%9OZ6EMwJVaE~ zM?<*BR1lmHMe82KegVMU#;x0K<*E5-Pm~6?A zUXI>zRD&H1O1Bqb2(21~!)G}{HF#(wz%JE#3}&z`M!RW<-rLIe6ckY}F44j5n$Ka+qIl;1=`%zV2Ms+`SF@2K72N3xH3dui8L_LF;|P?4gz@Z4vG2*86*aZ zAF)D8Oyez=xt2668xiKLXAdWw(A(^MHDEJy(FMzVNy0Fz;l?*bEcCxST$DMc9nT9A z1*MRtsH(lJiR!an;vE6kQk|)hsG=#D>qpD?xx5`2DBVT5CTi`I0@X_snLc;5nE6le zlV+QuE`gq3vqKd}+5!MXTx*d+tc$jN9zN(Y+lXW=$Wb{xmIliK*SPo;EH6#@6#~GP zIm*H)w`>Xlq&Qg%waLcCpY+NE7 zQNUm}F*o!*>=N{2!scU^ z&kVCpr1w3~AJ13Gek#3+GCSj?H!AyDQHF&V z$%j>DV(X;=l>k5OsKD`7*?!;rXkh+HI+e9^Yp4Qh5cicn!+Vu-R*}L_5VqY~%))-p zLt>&wT@ErK%cYaXU6<4VLsl!jfgtZV7(jLdE9`dM&0!N-OD;^5JH+O}U z_;pBn6NbF~8->JT_*S$NARjT5f_!9%PEto8c#XVo=KwlJI{#$ zD|@Q_`C1zq{{{9ne4eX!SXZPgv_MJ{z7qJP`;$C5fpvx2Z>-PB5quGDgG(P&hb=bp z9~`?{0j-q+;+3;@nYjIae#jbC`#%Xh+eX61C!>^7MdCcB^9_L%17<0(D>6e*_i8s6 z%0qkryd~z2$ig2AK8RL7drPRkw~@H?s8btH`%W^Q&IU8w*)ZLH%ytGib2suS z6mlcRueVy$cJ7{_B{?@YTT{$&bv*#**^Z5iUGPhSpgRg22$_3@zrw{7tGYO2t6k?M zJHCmXybX=|aSUIK6A=r3c;mgUfgx{ilC~VuP~XHhNEer(zx$~5MIM&-i+kf{K9{$z244KVAeJYgexh5{=x(g+6QIHbgK6ULoqVhvC9-uqS_stnZyXmIu%Iu zi_yHl;$`F3v*A3j;W#^1S>nn~LTTJG;cR2PS!YctV+%vzcQrZbv)S0Ue>V^#!rF`T zNcRkkNGkJLlcrB1pz_LKA`Qf(k5klnIogT-dap(Ay#oTX)%7qZ!{*Dt4vH;V6#v447mJqico>jAptP~uM73=D)=<6>- zN9_4P`5cVtqaXm<*II>yU;C&DKdZ3$)sGcvE-JHtmt53&YYY4~P^NYCc6Z@z>dTwz zQ2N)}P9E>3e%yhJp-sZ3N?T?;eI4U<+jyRIHsNa;N%x#m^ibG@mGZOZ+gvAp$4qr6 z!wcRt!!!q{W%l=3+S&7hxzA+Zeye&gFH`CxnRg@5(k-$M$o%seN8|F8?~jpu=LTe9cwQZUlA zHG!2`EZ1JKy$Mw!)3u9hijhffv^I{GGNbD4NOw14LG2IQ9j*$UHaDt8D{Fpd{~1&e z7mJI_yQ;KUX!YLm=g9SoWPPsCT%u>=)tR?sxCGt-71kS3S9m2GnU-P(SX@S@)#RS2 z&ZM9@!&EI$ix>@`q667}KantSbWxzJ%IMIyB$8tz8CZ2Hp&#CwFs*wns?A`ia!e$13R!al+AFQ+1 zG9Zkvo=Abn$OWC1ZAsCfd4ZCB?b$>TIzDP@VV;UI8&k_E8v@nE$G~k#N^hDzrArJ! z9AfGPYh6mA`LUtY$5bW!oOa;iL&c$FJk&Ga?}BK6@Y9N+@oR;W#ZP50+}9*9+M2Ba zHmBox2F8xX&SKFJkbNRXhM=R*hr9mkpbT57%16yf>7U&Qt z7VZMaJ}$I;j&a3iI5h`t@`&aXmqxNh{@9n6`=hPZ zIa}01BZK-WS*{cED6UQDpud|1E81-q;K;T?ukDRDD%b%W41iBdc3(wRCLG1w-sjZy_wttjA8%i8`Ax>7*qXTzLuU^iaKVtBp z9zXdxAA4;}ciDEr+d>%+k0}R5MB;34auU?BuZB$BFg0I#7bQG~Wo_ZMb&bqHCqo`b* zXx-tg9J)abQux%QY4xq(aA)A~i66VEaoQ5v7vsHC?xHVF^6MibUobZ+@GrG$tSjOL zb<-8o4B2+vF;Y$>k3Vr@?t)s*M6`1Z0w>n%Enz2FgbkN+N;5C$8O=y2Y?SOmAQ2dhe~SOSpyv<|>9-4GVN;nmuF$*YrsY=I-yJ zSI(*BbJ_O}iGtMQymszorZyY%OoMB&UBCd2_M4i6iyk)%N`7z5Bn+g93KZ^9z&Tsj zOZ}1$MaTh5!#MJO-#=CU(KbgJy5f7E!xvo?I;@R27igo_KQ=)<-$(U+oq$9%^XMOB zMQh!cDLtazlpVIMjbQe7f*i6F@zL?Kl&xoXN1IZYH#IT6fXgIH8tttJUVw_ULZy~r z+YLk-y8G3$Ns&59J~(M~JkT*Gu^5o9fUl=nT-Pv1_*a3TK9tJ}eiBXo7iP0q1o?K$ zvC14fX#Kn3gtcX>PZP9NE?N;MxZMQFv1JGWVzoMYw@^p3Do0n2Gqs!)5kG}2wDJ%_ zj^T=}ZkL0#%Z_aKKNa*R7!^GAER6EqMnkT`CD zWD{&<5a@?jhKI>FULwi2yL@A!9o5su9}1&C`-KHq5xq^vTWc!MRLVMs?*wYr+{+(z z<*I|--Z2^0=7$*@a4t9TbghE45P?FR}0rVmJ;WJT*xu`$Dh9)qH|Pk+F4M%-+uSt?5ONA-@_ zB_uyP;lEBd=eM`?Ae153{cdPU`O(tMaR;s%J;Zqg(+h|l1zhAn{XJb=t&%mVYwk%zh*{NJA!0FE#$!{G+DauWAYGG^~M0iGV`Okm7OEEb4LO@&W z-)tQH58`LwW|BwKdeDA~;W}fxD4E~o;_0{rKItTEVAtCYxt1oGF76QnAxR%8CRxA2 z#_{U-Af{2aT4x|zF9@9jj`e2~>^$9%eWgPN`{Fg~vTkMa`~qK6AWJ%qE)M0T)8u~? zcI9uT_H`3EGfPLjyz`eGLDUvDnmJ658cEorMgALktCTix|1j-?fTb&pP)nZA%@F`h zItS-3O1D#0`s90!sxrbyUw`jy_nDmm*$!RFLUv?`*YCjQ;H#wVF1oyz+r83d8_(%u z^q@c!n=RYVF$aT%6FlSujBk1l;)-yp5Cf46(2V$1Y<9Ly4Mv?}SgaQt&r;8cFZs=c z6Rd2QC&)`C07gyknydKwm&Ojmg;aj8MxInp65rp&q{DvOJe#`uA?3Zh){%DXjr zfV#Xj=QRcsHPeXrNM#EpS*GNcNh12HZmImjPUWZ1Crg_j$+xRi^}tt74_SJ$L0q95 z!-e;dz41(8Tfv-t3UrJeN|tz7?nIX6cF(b23#Yzo{&${d>ou+VB5$`j z17R>Hnr7!EBBk5aWs-f>+-B~;C{)S|KUo1!3O^IEEk2HJ@GO`c;g`_fUk>28d5xd( z=?_G9k4C{}fZJyy8CK?AT-etP3~ZGfdNZ7Ge}lt>m9vd{f$fo0LqyOP&q^w7DA$h? z6*+_3N*@fUXG5uf?W&ZQH_~rh3>qBb=i_;u>xe6mm?-vA8vB9pO6*?8TG;x5uptZuEUf3N+$`;)Rl&o|EDg zcCQYcH`(aX<8`{sQF?2(&VMt&NkE+1Pumo9(p+%-=~X;a^z(7o0V(6@!1{wNI$X)M zrN2HYZ

H%!Y*D^!#&g^0^&g)T7g;gJa@aDAlO@uNLqe5I(ROlj_F8}bT0Y>kx_ldiFT0MQJL`A)qaWv$2egI$S)WgWS?Y8%BR= zMIQnAYY>a_4=q@+ZhJ9MVwzi*B#l;w%o!aw$;Z<%Y{$F<$oB6L8pB4@>!Yjtn-J&S z_BI5gckA6wLPmdo$k}T_7W~HwyBx*TZ3)(Kg913MClU#i@$NKkq1Tn@0ORpinug#OwbsA$-xhhYC;}o8se}qqdne@FjgqvQN>Q|?K zD|QX#=RU%i{SU6N1v3LCgHgIN_ul?fn(9B19cNy!PiRDvpg2M56|wa;(QH#$<=?{2 zD7RJ))26<@h7<5#E{^=t&bxBB*Y~}q6}-jMcUr-a%MvX(d^FG`WYh*{kSF3|RBdjO zG~vcRx)hKct(f`Q`BP{YXU6hl>J3zCJ0T4NWOJu?JO6rCSRvjq%x+GX*kGQ3cTXM? zHR~yt0XO{a`W2YVcRaQ5X_$&^0De_E2I7P&HX+^el7ITTW@Ya3cb`S%^OPi~k-dPT z)Nk*QLW?;k!VCH$B0)jMVITdoN*l>}>jK7~uP2MeQswJ*lBNmkr>*uYqohy#$@IKu zs(FkQ#NlE*UL+%xe(Ts>PzY!JVTr&~%*XXT+(_>D35@q`k(NsuycAg%%ly&Tau`%D z|Jav}_ZZiX2%N42UbTyc!-*|PM1#<}w3yQ279#p)^)$>Bz5g~Ao@nFQLE}awGuiN3 zTD-Glsd+vX=rPM-6u}b(`c(Bea?sT`&s9&Q38s?cC4bz0OMW8bFudq%Fq^>WgCRp54bM4bEE2&QteImdz!$1SV`#(pEHE1MD0OMYYly)edRkmmG zkCd|j_bn~>bw;a76D|amDPL-Bn_LGaXSP|dPM2I)0v};bvum|8_U!tbPs#+hx8)h6 zI3DCI)m~t;~Vx}t*+aT`& z`n1j(!8`rKW3$FOMfS5o>oPnXDOy4YmW>LG#!uwFdw(@iZR!0E?Ddbq)9XVPVIu)3 zXTPuV-OC)B*E6}Z}b7t8~!q4csT0CYqYC4k%XOu^4RJPgZ#PR=9hxfoO=p9~u zyOjC^(}5cMe4~%p`z#huOvP)Ie9a;1;8bOwG>J_Q$S;5fgKL5s6VAnymg-R#kU3oSmLm)8O^F&l>Y( z(kzIXf|T%f(uJu7PBcaBpR>hvJ&)AMg7bXsP#qaThZc@hZUPG|fieu!Hv|oaggeiO zc@gC@ckIZwXY_L(%=2a&Y0Gu$!hbY-%_g!Nw%0g*hTxUh6-vx zd*eQC#xRz%G`H(Ym35z*pF?7rit+l2jWZnG31`GWiv&M=p-WWf?vK_{8)2I1dlplS zR~5Lgd4AcpPL_Y0{Jd2Vu9vyCJseR$q#c<+@zBh;f{$%;I#*@Nu zjPTXHP(S3Hj+_qPRWj10)Ij(>tUgKKk<#cuIwA_o_44bF($j|tNf^>>|Jk8GU=Cu`dMK{WHXNI{t@%fiO{EZzl)K_jvKs5jI$O4in6*>Q6^(S{M zMH|~A^_~whd`>2%v7Wg2|yoFl&x9s&0O>6RB8V19)WN0!pT)@cL4_312=80>bTJd8`H9c>8%W+fBd;k!lkzo8rh!N zX}m}L=3Yhv-r?=@W%M7fghXw7!P2gtgZ$o2kBWY_=BgVRf#T3K*9baGuql{pvV$^4lGKZbq8_Es}!6Ek%XnAneSq*t8wyrmE{twpvPe_Wqcguo zoHEGoSSMG9^_aU~9r3IjUL6TYIHnOc#T^jjT#>$?ngeh-}&!StGhMQ)$BXsi) ze|OAPR?&lX{r6Jk6R(kS{$i-CEg|rCuxUMcY&&%{J?r-yoN>C>(&dI(XJr2KFOg)v zJ=EH-Z_D%3&C|Js$4t+$YRD0*IuXR%!-+({cZqwRPo_woGqK^fm}^j_Cd;TFj#AKZ z-rf_YM=|m_jcFd8uH^zLuNK(bI*4g|h{%}=E5N`NB?BeUq}&iC z?mI__-s?fkX$4YlLK)MwOc0=pHczKwJQoj&jM=>juE^EaO(EJI&bbrn4@CSxpE8@Whjf>%T3 z8oW_{`tw)%Ydlo=Y{eb`XO*H%2$TA=x20vyUbf6JsYqP4 zu2234x92MtAwltA)Vrm4O7qT;>CE2Rv`^6JXI@DD>g5zQAq0)%xPI?&0;gfeW)N-3fLDWIY9DSV|dS|yn|c%cAl+}p?7%1 z6yqQ2cASx(lEue_eh?(ohq`Il`HR>*XCx{6d`7K6Orr>mDqXr4&zGO4xFT@i>7AXI zRq%lbhNtR-)*8m*i{AY;bPY4TZbhll^PHTMrb+-b+LkWqk&Tj$UAtuBCfhwl5l!!h^H0$G-_VEx*~XX_Ic$#`p1#v$l4e z!2LZXc{E~OYj3EJe5All_~uB>Nbx?}tf2#sg{N{qli51UgVsKOHQBxr0y-cd^&@FU z^lB6VC{dcuR}$|txCPiV#4%_XI-2tl4xm6(HoRv#PP!fH#Yv3(XLNqcHE|Mu?5pzs zX&I1s2(Kq9yG}eAAhBIp3ZvLn-0l;MA}3dciCq~O{RfBA2+&xF^a6U}KzJQDhA@N4 zsyt2okHPZ9WnIWyyq%cQD7v zR<4+$%5%q;xws?a`?dNUsh{xMybh=6$2A`*=+b+}>>bW;XPKuA43$`Z0VM_E0Lj!& zu}&y1Nn-4zbswFF<#l2$(i*+y??D0M|G_oYujzlKpah(Bv*Z!`cGa)R(cBo-WEr#| z(8hQ!{jq_4UO&Yc+RydE8+U+nGClGfe;d+e)p>C;Me8;jZL) zc>zZS_wt=+gx=}p-W_b5pDS*wbrO!4y15kQa*UD|jN~#t7CGJ3X|DuVrNUNMzf~>= z!(N$yh58dD2mISfh4F`SDqE|U9D&WEoXzj7Nr6{*MqH{_D$&J17i=qz7hMKv-|o&S zwwT!cawv$l&h4_zB39gv%7jN>W3$J&ie;d+Q6dM`RcRhArwgsJf&O2B(6q6Y#^OKR zcXM>Q0ERv$ix$q(1B&tJk$w+~lyTpua$m;j3txHXLiQ^qywxGJgfXtw{JU$p<6_{; zvid2KAN6JL_Ss-yJ42OCD+tKBZj&~dQd;`m_X^R%*)sU@MGwpe`X?)J-9`MWNy668 z6iwZm#+&XV(5!cH2RQN#N%Ih&uFJ6-a))_~cbx`5)#4PBD1daVL&Dt3Mpre{BfN_n z-{08YyvX*m|BC3}38i;oAA^w=f(0@?kkE5P!TGUk_GD~_#3$ZEH z>b@Ch$bh6RiwMuO3144yXOYd`MYh>99`rO{gqs!(BvBO-Oq937-ktxoe7^vT)7A;Xk9+AYo90!bZm2?^ z{)0=_+_BIl);HEBi3KcoW^x10{If#)yCQf#HG9;D8O)s%im`|e`GSw%BtWw<=vf>` zMj_Dtam8MPw{&u9)vSRDE$}vXc%4OX5bxQF%-O0-2Ey+sUHEdt)uZVRS!+gv#&Sdm z#;`snqwWQKkoWUzpKh}+-xX!xsXytG#11Jo<|OMaK3<-fh!*rh&+;jnSb%b4oY>7* zs&wdhW%F`f*~!yTtg)Cu7Q(V}eo}bX6nTC!_YBy6h<1Y!D@u3B73CV66V#e9n0c$z zQ){o^(s%_p%I(n<=|sl67<9je#fEh>fLm5b6aC_ICZ>GpUhQR35N_A-^y5ZpY+@>| zMLZtPU&A|2K>cxXIH2A?NEq;<>Y3dST?rXKh4>uK&_v)(aZe0T)hetNc256Fod^hz zVfxn<=}+5q`5)Zr1*r6>&J&E(uGLWAIlToRC%2>pQ3{HT`rU1c1j_#KN{t;Nid9&h zUBYr+=y<>{H}U1W`zo;ve3E3X`MTmIT!oP+aNt7vjryQD?5&1B1G$oja|&|+2=zYyt+Dhx7?DdbI@b2n8?ubwtD~zMdB7p$ z5EwOdqcTX9km2y~D(I|DJI%ZwO55;j%|_7SN#l*q3c{Q@i7W83=?TA9smM49DqbD- zu3xu-f-z!iyaFwj0-|yT2FO+XFQgKT)vuCwWRfm7x5vjGa4RRn?@+*sx-t7OakTUo zy1!p)VS&FPV!A@Dl_=KXzMU_U38j2_LLW6vri57+76ljTi+(z-e@dHfWXOZ+t7V3e z;kN-Dr1Ii~B2Mh99UN{a&!Ra`6&}9OG=kAQWSvQV5y}<4QwdBGizYqA)BXJqj`G#u z(RL>wVuLeu?B9hI!HUU=xoX4lmKBYyyV4m=)n$qrGAU8D{adWBcA41k!b`+H+N=<( zj|*wZpONxo7z#~$1c+WI+hab*!I)T|c~qREa%PfFUskV0@v;d^=M|jmTommSRsknf zF{6t4C%>THZu_%%A1fELuDe}>BrT{98PUz%1fN53i4Roh?3|EK&DO z{XrAo{^+PXJ=vi~ymm+4{Nl(?d~U8yS4+~iXb+*jp%vAr_<<4^fFr<94TdKc@nbsd ziVFCkyQ5RG5(-D<;K0W56^|D&p9Rv zoD!V9VTV^$VPpTnVYK6A<28D*R3hG|VUU@~yK%@X{sJJuZKu{rP@R1=?%j=DL6Lb> z+=aD$>OHXsOfI8SAZT~#q?S@elHHOb?fT}20b^T%@l&9P!>%8d%K2{vJpaLAkJ>u& zG|;*}E%S&m`1T1^p~D{euQSc;?FkXvWf(pxJ2YTr6V8p?MdTaC8$h{P?@P8~s?ND( zQqv#YNjxMf$2B+vVQb{}Q<}n4GMIPxX!Ta?+g3YMZgAzFqAsuTGCzU@XhQwVg9w7; z72)sdM|Wit>G-O40iU9Zg=;Ssl95q52#6F%y?z4A^UPqz7Q?ZOrE%<@R}B?IZ(U|j zAc0tn%}qdnn&>d?N%P+6%BT9Tz5k#_TTSb%E3#QxuMoa_`7qGJJiv=;K)Ci~q5ZHY zi)z8w_QiPBmbWzq+NL>Y)lgff^#!S}1em97u0!j&`(v06?Bqo>qW6zqQsc#B@fBgS zc*kCl|NF7#K}lxXn{L&6*uN8-dWjvPD)$iwC`~#d+z|e#fE+T`mV_`_m6+gI`_*Ph zJKJ`7CZJE0W~Snl_i0FYe1;f5A5}Y2G4?!1pj!BGwfON+>yZIi@<_#f34btZnK10= z-xM;KyiY*Qh^(H#=sYwS5c^K?%9lRS+F3|6e_JW0RrB+#YQIzVMd9gGpXC=-5-7+o z%%C*^T&Hm8f%_P!i$Jf@JLQsi=CHZ=lz-y-R`5=-zWM0CvT>sOvk`D*4#hn}!8dH7 zrC!-rC{>3zvA4i2LSd>juX|@3LG3jUcAUD>*l@<|@RdaLDzb{g>#nzbLUv2#$}?{uZNYpGN%n~E%!{Dlw_gj1tGCMVezusY+ilRyS;MIoEhTNJ zBuLRq45bbpe&+%YCcLdJ5CwV6Hj>NO^PNGOlAS9)H$jmMj=yQ9y2t3+MyHS+X6V|n zls@~E5|q0OamFvJ3NO^I4dUUuY-q`jSh@FR?Ug)VsaM>O+MCyTirIYSvoRUxE;p`E86q~DQJB&@VGST6<#Pm_8EGF zjvk(}U%Hju$BfRO#ZH?%zH+?{h%#^`+~eP6kX>2lm!N3*nQnRnoNsU>=XC|xyVA!BO@&MH%@ z;O;zH>wON-5J``m_pR>A-RRi62G)%`dk7iOq~m#5d}nXdZ~hr%(A)ly(h_Xf9YZZPD$gAq2ZYe1#Nn3`~{y1#z$RxRirGti3yTp zYy9rxhtRLcQO7;02R15IHc+xtws*A6?lwu485*GG{yeK=WwVdZ2TucnmK=TyOd@Wj z;k6jq0lTgJ(2t-VY9edSa?<61i7%MqlfyxZXQvg&ezxAE_DaWiq4iB!Te!m8F^@4` z7>kU~iwTD9_EzYUO}ZSU%fA!{L+Z+@wvf$6F#Q(Z8JEC_ER0KvE@MPbyc1(Y^hO0k zpPP>bDnF@l&Ux_Z81sB4yhQwc8e$D5)%@y6ca9}ad@94S$y4hHat6{qq#mYg5R7!}rJ6aS~c59o|YiyOVJI% zlQnp4#d#j-+e`s!-B?V$R>#wHmX>>Jjlu<)0_r!j{EqvYMy}YBzlhUpNaYBa&5{cc z?Lrr7O`8&6L-FM-m4Y&sMAFiEs~9I0mHWw!V|Ljtg=r}ZAgEzLsbm{oUop{mQ{sL6 zd$k`?)zIM|V|k=8CHFe~ufw5H?%j6}=S-~JdX9Z~81xOfTw~QVhOE08Y{Hgcd131u z0-o0s^5C0sy2Lsq9eK+0kHv6NmOJ^jJhsi1MQ$x^lwFq0ym{6iBnyJzPq|Kxw5{xw zbMxl1uJ%I(_Mt$8?=ladW?`dli>bR6?`-dyp@lTRx&UkA#@b}B7y*QoKX$KA0)sCt zAL>~y9AqLvJ|J5VT(l*4ozD?$O*~{JjJ&&#Qe;~tIU{lC=tb?BjGMRun(*ruKtL&C zLVnUKWFoRY1v=ihrPEhbNw(G3V2<=%N(>MkE)+r&C9E+e9IcsmQ1>`+RAdzS=@tdd zbo?g+smDKkV=vMj#mjw;lW}rBQ8NTci;a4abUSH&bx%A~9v@+{q*O^c(K_w<=UWng z;zYoavZnay7ywzzg_^p(G{4%6Q79eL1sd47gc??12}VUlJ(MJ(;M7Yt-GtX{=iKgS%ZRS6po-={PwDV7lLFuIv-gz%Kc#!d8x1TqBEKPTwM=Xl zss#TO{)F!(DZK$_AG`C93wv7QCCs)+Xku=pm!NU#6FA~+!I1EsX zXv49JM~uvx3&%JM+$Rl6hlXFZR>JTxS}~w^kT_Oe1U=mUUI=V@^OX(CxYbo)FAKb{ zh#^t}%zs^JFtOwhf1y=)30vn4{`~gsG}k;I*QL+2o=4Bd&c zEp}F1wP4G&1n=P|(LvIZS3pg~T2Vr-%}UaZAgXCbB{U`Y*Nkspjr8y^(=ZX-LEZM1 zY~Q;1i-KMQe11QZ*h(<(h6`0U0+&#+3+hUG{VH*_e$AAt2mlMIyYbVK)e9=W6F`RO~j&O{>VB;?oJ|dC+PbFIdmkY^b~t4Ipj~o7?K1j`jP$h^ z1ufuAEb~|J^%Q+xgiPT7Wpx-^U2)n1x&7GW+UB|61Tl^#baqUmIV3AS{GLM?7HO_l zuI747zU-2EOx`Z{F%pjydI5qJefmT6l62P0{Lk<`)MOV+1gF7Kv(^*N?g;qN!&gMU zg6(@13GQ8P{>cWuqwZZ8on(bkA7Hf~!DFkaazoKr1nyJ;bG<4RRpGRM_OEQ)0F3Ge zgGZ0vd(97&V-Y68kHdAo~I_gJTP z(4o6F>x}EuP0G{Sv$-cft+q`)j8@}$dJjw=v@Ey|AHLekT0FnWIQ11 z7B2z49g=bYM+WvGg)!+L>_Qh%gJdEX;bqCa3V9TG>)T$jr|U3fKUs(r-)B)|qVhKq z5Vwq`=fmI>2G5Q@6f7^oM@?$JILUhT^$iVzMfuJ&+16@=s;s)UeQVk2kpUc16yjdC8Xxg)2JBD2ITRv%HelmI@NI&1G z3*cSl7emvlN~pFa{JJsIO;k|sh>L&}nGogn{IZyR0+p3qXv7%J=NX^xn+8H1d;RyK$Iets{d z%eE3rVjKCp>ybNvU9!`G$tw8i7{t?R5_oB-`uFkqiEsXrg)y;^Pvt_U*zdN^Hnp&@ z;fCv-bW_UbvS)12gJ3(VF4e-XJM_L=^sNj1!ZzY^A=9hCvsiyNS&6rm8Hiig${EJB zN8Vc{Bf=3QgLX(>39=|e(@o5+pL@YV&Hs}dzkT_bWRti%bPE(!bw7SyUOBphHIrMg z%h6+gnm0Fj{*VTLdl~U20Y?BE&i`ak(>D(raq^pmZmgRH(Qk$LAIs!w`N360JE}mQ zyNy?5gRb#g1@JGh4RzKDT#rZaH2@hYV@PBwBzj)eZsowjHb7%51t4H2mZ0!e&{t4N zmHKep6L;*_Ar;add{of#F0|yhoi9(-thm>!oF&1w?r*t^ee#1knH88*W~YTNVfg;Y zhz*kEkyECQ_rXcob95~=xp`)60<>6Wd-4% zr%*Bcg{-VB{fT#DUoykAlE5@Cf`Jg$FNgd8yqq?1E(j;L`5yZ2PTC!`Mt|Ep-JooOv8gKPNmK-D5yakGw>rPraL9V)A1Slc4LfbvpcOCiRn#(D zz*(OE81Tl_EdZ1%5^3c`2Vs^7!0pDT9cLwet!}yYWXxI>>)U)c>Ou28-@N+|4lyl) zzDo1tLj--!hbU0it-3f83jc0`G{+P_9E8Z!Ux)fh4b|_5O{;QfW4^pu$?Bl9Lm&HE zPNMTjD;R45B~F&=wvyR(5YGJ*ZdM0uKUD0>AT6(d3Th?%ZMNO<0RzB~x3WSDmd9yR z8aZE$A=`>WGn?ffR7sk)j_(!_OZvtsPvwo}`L+E&IFrZZtx5FZz2oPuu|Nq+DLUpB z74f~AqZqCugOZ8zSsmxaKGW-G;dxpT=bJj&ocK6d;g_iZ!SNZMOg^J2`#TZFW1%*I zMOPO#=i6gONXw2gQ}4obQ@Io5LddQmT&~k<_U2lqAZQG3m?Es&AVkG*t!ZxFf?iN` zHPgl5p%Ze)yB@Df_1YfY@EU|hDt|HVITFk1^H3K{O4PYjbnV&TW(o&$bE ztxqN63U8?(A~h*{HLsy#?CS#b>c-G5c$Qy%po`}#1;an6W{sY`WTx2@?KgvBIIaN* zK(+NXT#)cJ?4xwkDISFwg^Kv0Es*MtfIYbAG$!IP!j(axP+p$}Ak>nD`V|bcl9tm2 zk#~8l?SNImO8H+>Q^JFzj|Hd~17~CIh8|V>pV^{>2|HH3uokw3?6mnM06sg?J5S|8S|Uv9~}SFo|xT=rytnA{yKvI!oxcG_h?}$*cq{9ShEf zH05()vo2TRlGwe?tqe9FiY9R<<4hJy(D30Jpq(dKxXWl0g@5)l_d-mIa=sUwI&)-60ZIPSbV(9H@^^FuR_c%k56CeX)Iee3 za4h2Cow1+@S;@ccAGME73i!E+_bNFpOa{}MMW1M_z?k!R27Ol-n6ra_bfh?M(5q0H zMejKlI()Vt{@h^`y;4m3O5W?T7yoX?#+ylm3a`k0>$x9U(8XI3Y&GIS|m( zZm_RDcSUHTeqf@1U$p>bll&-(I47NPfnLg42hr`p(FJ`#mhxSn^j-lPSvN!wXU*_u zYVTfmBf5S`xh}{G6Q2JG+2A6`y~#)Aqj7f*pR00_70py(S3NR7R_oza$E=@755iG0 zb=%8IAx9xw&^FqyJ(*ADq79t>N@1f?zn|>Am#XUI`Il~{_O9dWL!Up6BKO<{w{#YP zHFy{zqc4GCizjLcqiD=H51#=(oaNQavl0cH?I(Q<()$n2^+80H$75VB5oH~{&T$=j z9ymwAUYr4+<@Hcy%^;(zs5#m%b5!Ix803$8WQ^I|n(0>l=Ge#eeM2cNCH6tSqfUc+ z*YhLP>FgIff3-qOvQn&SD2%u%mp4k=(X~PCG=W|FlyVqo7z*97tZT1DQ0$!JAzjU` z$MB1o0rUZwJut0E;c&QqpG1txRlBj6D9+Pn-7ReV8@0Lmd({KBus{-r7k1(#HoTdQ zIN!_IQh=)Izdg_!h*%&8XCHEl9oErc3hllYWGvCv+>oABevn@BfgHHt8Q!K4nS^d zfHlSIboc=Qi|A|x9gI!Mu+uJfZwU=ko#Ihu-Bo;{oeCc0ddnH{9S*(!GkFP``n>@? zP+&296lLfgeer--A6!#@J0F}O*$lCF%mEYAG`EGiNcGcHjMAI+sD4J)A{QUxC%3)6 z(R<4h_9%MwQ%1YE#i&GG!}ltawfh<}3h~TWgXf6*mG5nd-+Uba_^g@&$UhG~&^seU zD<%e}RBw#BtzX1vq+N>yNX^N#!2XvMP(w|`Mxarg6O(~m2p5HB|9R-77b2X$X0YH5o?NW}kx6O8R#rsP0~&k_P@<1#0g^G z4Brm;C$OAQs}%b_ub70fGFN|FR1G~7f3d#{|IYUrH+gS_lGH-XO$|QbLjRrP@lTPb z?O(QvV@kV-9)=t8j48%(Pepq^_JZb(l)b3KpF|%z>9Y+VlU~02+BN|^b1tDlcC>`8 z(f$3oK^T2NSaPoG-(YayijGioWS7K7c%H66V;=f${KKS=E!LR+adHQc z{lS;1Zq9W2pzW^_@88ZsN1HCTtYp+Du3GGu&Jl0?aqrJPCd;us{`j@ijoGBCc_&#^ zjrAZ~AaX|D2HIX+%Dapp6xr%=UDyB9cA*pa~bb!G7o2A#w zs)&nYWwMkRKG#Q-b)7N_Ko7AMH9)$~>}mfDOk+u8Ak9<;-tdhmcHtr`gB^1erHcGE zHdzC#OS4?8%mLPxj?rgjsrg?jafck({qvyNI<+k`)0ua~tcNMZ7=7wUlNmDXA+baR z3FV%7E0aAB-fOMKRYj_-J}LIrTD{*iy%qfb{gd09TA!SOP{dHgGMgsqs)Y4+A>Ez? zp!qMG;Bv21DyJ*g#01p5f!&vk?}dU!z+X+38`;(WY^NZky#!tFb8q4wr`bi)4nQHB zWT=KEhJ+>wd0RDGU_IOj*wE}Jbir3~=Rddzf37(et!1N=3uf*QdW!b_29^ol4M88u{>GsPt>~{R5=~pyxWr+zXret^f2YL`6 zVE6VYv1hLQF-Iqt2QYK07KXeu9Llg%-KnLeRQ=nJemX?> zf%gNj?dX*mEhG};j9z~cRjVTpzgH?11u-W0MRbt{9=TVxmJQRjmEVqH5BlOfh8-Wc zpG1sK3P#I4btgWvMmLf6urH>qn68)iauEG#jBFAY(|xlzlWX*KJwX}TfoHJR7fS|J zZ$?+FW#}IAKp>i6e37zqEQ*-9RwSfq%Eye!k>ob36Ct>^thcn=F0Bh_;qy=?*STpA9 z={Gpk*m-nBOPPi|VYEn4sQpmCuO`Y}c?3-6Bk3-v;Et}3?)Z`Bah zkqRihq=5WEU%z($?45^lV~Z8r;IPPN$YDBoa~aB~TX`VGo$8l;MzC%19Ori=z}l-O z|4$SABUxpp>Kl$Uf5wv|Q%B0*;;{9cocP=SX? zxbU^WnQj$bM?-s;m)wm02vWq4l^{v>P~Kzs2cm~EY2$5({@3=})@E%TeE*AatAB^& ze$GdF9m?L=ooN_~D9!E3!%g44@>6PgFG!HBfhzo(p;X!F?&3Vx+1-;-&&hpVEBJlx z2Ud|PH8p@tVE}+TPRe2TAX){P#v%+6yzXzz)b*AxtXbk|eQ%PrF`&<#Ug>azM@2Kl z31}i3Ko!bgQP|qzF!#~T^dBQ}HQ?)c866#RbUk8igj;C(*=ZJNfk@p2VjCOr+7)@M z(pO-$VaQH9e3kl>Wg9l?^eiCM)Mg7C?p`kDKl|%j#;So3okt6zxW%mf#{Ieyh)r7E zDL{ck+)wsr1-7fB(GN2)l->f5sO6VQB(BWhhm*62yhXyzrBSSxHc!Osfhj=FC<7&j zX4It%|A33Ly74$vt07ypC2LUYGskyou+r*Zu^=fhS{$gESGJ}SduIDU&Aq=rvuvro zsTKjPC4mhucV8>&4u#)Q1C*7d2K;e-ztMxjCL~zA%qkx`ACb_qKFRQ_i{YKxK+z>$ z_DeYLH#4L@%hwQzr-J0zc=?y+;Ykf|tnu zmDY^D{Q^G{C^>{c*BRHq&2$j`aAmAW1V&3mm9e}7b<7N>QY~M?x5r0aHPP#84J^;Q z;+4q7Df3p%;+`J&8$K@lR*4{eRi>`m$Ni7ksa}^GI{Z*F)K_%Odr*KS@ zhM+VU;wL!hcu&4~-RpkThqU1{-au`*x(b}{VUV|*=v~zOJ)g?IYM6+xY4v6Grtp~g zzE3!LA>j!}X7al1>miJg-5*GiQg$#gXCP6m>gM>VmU`%cor8sojt+FVN7)+~uiZFY zRoy7J*MgfVxmLEq{n^Tl6YG0Dff(QL4cwY_qey{FmywLE2k!|rjZ1}@Qif&TU>2nZ z%`HV}y#YQ0(D?z97L#%*>y}s8kx_q^Fs8mYc5zceG?_x+e|=wJ-RkK^y6O{dF<)s9 z#Zaw}`h_yy^nEK7)1?`aj6&IV*@nXqxUa)vKFG;G%5SCflCDPC`q$0ji9o-)ply*Q z3oWk}A{`D0!~yFEOYH}6JxcEFa}4vixXXO(2>Zx7U6|>(9piH?-^r;^iA|P|_UZaK z;CGRbHdA6#7q9NMyyJbT1wNoZvyM5~>|oIF>`C(3oh~hoTE0@*94jq)zp>AK0n)>x zAz%Tc)gcKBkzLK?rcDV`{+kkxPnAAVCi?I*oKh?~VI=qDJ7Ky*9J9#nm+oMQ2VGsc3l^cit^a z0lE4hP0o5NtEwcbc!o9c4!yjVKf_2Bu>>Z17eyG%Nqike`U?+=P9Fg0X`Z7=(aDH? zGFaE%zc_9yP1ELLEHYYZVxG_08l=i93KL)<1e76Sd3Z7^lt+odM%ZcYD-BdICrr1t zB~?k)Wg=&}%;GRM1{s+*YR_#PDDUj59FvY)-vrU|(6@Tqq2RYd2+DCo>EL1E`TCu? zDPJGjeDkd(^nDR-)NCDyySBtGRW))~>QZy7)NGh(O&I2mNXnDV^pLWlW;i1sP-nDYX7{ zzxbsvipG|#=DQU=pj290Tj;%19k|V*Xk8)o%6H^ILkzy)r)ub}?Qj-9)_BMC zR$4OiMdz!!#^;S`SMlfv2ivbL;h~J;{wm(5^oTmBHd+HdJJ-#-zA3zqY#i^LZOwjd zG8|q6F}!~g@rzZ`tSD@sedP)Gm_f+?RQG-HGa4(w+IGCz9}h}q>~_73y@j}ryQSp< zNC;9$wHwhF?Z&ho0n9V*;=@*I3iSM`XA3B0<%bvqj&XEGfT)(*hlXxuQ($WW(c zYz!?;43XGZuI%KSqV0Ji1zE1*pNj?+>^1>Enrdn|X;hNYbr^a?59~g8d^w82^0_Z* zjLeh~iu?_v2qa27gELE&A@~n2dMOH-%+v+Nd*09Z%x#@@M~)i$Bf6+L(DHgW_0J0C zPp)f@r#ftuN|%-BtnA`dV;~eWwn%?yk(Upez}4rwWAKB2;uXIEA&R8oRLgR=CYt6- z@`0}@78A$_s7PiktHAI*eH7#T@~^+8>}u4$AYFua-aMX%bXdwzl`n~iqlr9`;*k9P zp0Q)sa3#EO>K2v^iN@n9Or0|b!HeB&_Rm#u`V}L1SgFwt@XYH{3=7knCF>ZUT-mk| z*0|6_AIK-dNSLxNk}tv2<+Hl_*q_T=H|ogV(9FpEp(RU}rO|VOSdDy;CPYMnOef_6buoxgajA+njn|W<@27D1fD`W)_&A_-so!Y6LQ$?8Um=UWt+BN^%6Q%A3BKXZ zS1R~rKbGj{$hJ4b8CrHY<3p{*8Z-z^{+Rs$}^AiB_81wk&{w-B{dI%HmVFgljVa*<$}!`mU#`nFCLD0 zt-o6$c%bAG(PUtI9~6ad-1I@G^p}h_jirTg*4lc${;}VSUwM{4_GaAy_S`6}*=Ef zCu;opO%vZ`ND=vZjNrRa?(F47AAu$>p8nfv?urVLEKEc<=eDB!q{YBl*m><(v(0j; zLgvHb$5DlfzuWZ_XsggJ?|N=`^$o*K=KGochShb+7TUzr7Cfi{`?#~PHLs4js@%F!%wa#7!V|!ZPB<)prfXi6L9v{Ok14jTT zu>qpS$b2xYesh_Drc83xEb+qms@ji`-0*IipUATZU+BhE&$AD88p}sZ8Wo*cG7DTL zh8?Xx&5)m#fT%Gq2|63+Toep4sJmGjpx*Nn(EC3uqfhZ;@KCrcVgPAUlXKkCeZ^vg z5ywFi#fe(X^D(bQBNadrSxcyjuSJaUDwK%m!f4H#qxs71ZE(5x8!$N7kaei2mrRDb z8*@bBW0a*uvBA8caWp5h$JDCH%6VT|96R&r8fTx&*uQns9C9Qc!htK?n8O4keUnrS zn~y#vvUcEx-wG|Ot%koz<>ZN+m$1A}^y65Qi*3cboy|xKs%kf|~|T)ZmEilR$&G^R7OUvX4<4p&%crtJ;iis;8AzeNpj9pFz4(VUa= z-xtN>G}(&+{+*pu{M^0y7NyDrd5W&mixU^1s_7|KqOdKho!Zz`YysPno@s1&!ouNZ zg=-_eqvrfBM)l$A&es`Hw}T2piW0!=Q{9&KtQo>>mfr%$8DfcuwNjf2kCoEi%W;`i6ZY%!nuj=pxjDtmXB=m{8wMlSH@O#sWe{As^Sg+c_ zD*Lq9J4R=|d+o}7V>D`>zVh_EUE888(w?S1bXY%=1+3eJ?4cKY0E-%zO z`ekLUyRh5d_s@M>s5(vPW;wN-|Bf}d1GJ_CII?+&2i`1udMh$ikq~E{dTG|mJ=7Qc zCL(3ez>+IX66#P02D1$Yl&!86zABnmojHPBSkB;p-;!yyWFLaV+gvt1vfK1O`tU^B zFukP~kDD&C*ffnu$^32|8a(H!UHfEeIlumW&Co#J!>7aq=w$ePdL`9fI5LtWzFFz; zpa-TEfKMN({C91sxO;$zeUhY`~+U%>K*uW?!M-}05-sg{y|RC{aJZ-e~z}T z3Br#^D{68_#ZLWml-(WCo^EN8j@fu@{<<*NVW(%q2%uhH7y7NH1rX5m*XnJqn)3U$ zMAIZpR=HFLX~K4^Hi7Biu0{_7LDr7cXFd|RYlXGF1D`_;_hTg)D?8ej2NBcu()PzY zj=&h;rZJl4c+v;wV0Ca+swqI&qm)v57FK>Lk|^F-W0?sRpXu)d5|1D*@rF|W(qpGC z;no-VqoOlcik)n~by90(@$uCB>?|)rtxnoGZgt2M{yVdrA&xBZw+086*VNp0jbtvx zJz4Xa;$&NUfkUf0_?sZHWkZkq!CAXTpV4&(MIVfloO)?es+HOST&R5fTCr+^ShU;q z`$b>e8tLm1m;eHB4bSH3ISpWy#4>k&nA8?QJ<@KH9_Xq z=)t@p5;wYLPw2O(%a}qWYcp>AuIVq2XA3N>p7>*3b7vKzV;bsFW?1L@CQhWzE2-T0 z1@28J+a_oe`)OKp`d2oP5v~KT+Wk}uL&o7K$RVP$0U?PmM6hrRSarq|sVp`uI8lz{ zN!vthKE?%3_nbg*5-1!dT_@76RAEwgjr7sy$po%UNLx@Y54S_niT8vG+vBP?C&@XY zoFk5kX72Q>G+5}=Lgys4_g}o9jC~`VD98?-CPyruTFKmgVsyoNIUV7S(ggKcCeE+MRBB$jThSb*oPW!wu}D`C@(I6Wgyw zwZ??m6c?uiKbkJ*8%Emnqb9#H)`+=C4JS~OFH+no%g;dyNFR#DW_V$^ApG+8jST=6%`Xwt(!!qF_8QeT%r z}^dYnyHq0+KB6NRX_IX&mgEWOG=aYF+BW?RIz~$6h^ej2gxqpY+~T1OS1? zJ80U)Ut0VM2j+$kiG-bClR?d1vCqN+JEZ#dm@_}2e;jG*MYdwyL2Z~4|H0|Tc+l~m z3eH5!DON@~3-k-Bx3xZzr~g#7$lvV9TicXL=2+n=z-3FYX65{=&?W3*&p*j@VQh3o zsg$M~=E0D6EIBel^g;S#^spR6mHTOWq%=Fz#bmREr)$>)=h%QRn3d-vo!(_*!LMAR36t^W7$y@|rv4SFQC#B9S&Q7= zEVxQ?Ju$a)-vJ@Qla~`CAF_+ywk{&xeDcJHmFTmHR43-{4VoC5Zqw)q<1bMO@q_ST z1cQ(Dipjc<#pJ=smz&3!me#mK8}f{+%NBIsxP5~PtYKvO&eWM#j_q{}jrm3)l+>A% z1MuhIK)X`X&(VOFsu8rvN3WBab}n%!1@~Jq-o3~VQXj8#yluL0@)lei3pMfO15+H* z^IHL`v}+Cmn!NnlLvu5YFj4BXiAj}Y=)Suj17#q$vSTlaeNnma>;y}$84pCqGIZO0 zm}EdyW5`Pf#rd{6sgdCoM)cj8sNSB$U3(0A|64Cnv^Fd>^6d|Rekvnr)Hf$-SVL~W zv$}j|(Hz>?5ZmLv(3-JGW$a}TvI>v@Vi8lDYAb$DO0L!#e%8%8PD_pw_PaEAkzBB+ zow`@P*E_q-WH*$@oY?r$bG|yUh57^Q)77fLEp1ud+9rlf7Uf40`wbQv?S{F4`nv?0 z9)PWDb7OP#8MXB=Qy-3ORLbL*j6+7W-9k^%4)-jQ$6AlKzm2x79kaO0)0Sj|MWfkw9O4x8ef#l4)YCbN9hyYPiorDYYooqZh_swlAs?dOhne*hV7of}YkEr2>mk6-BG`_CxT?QT3fbm z69g4U5#2ym^ogp~FLgyXo^C{}W75gS&;q@t;rznmXt8vEe54XKlTC{VKyQN1taK@! zIdT;|=DOvpzHn`hS`=({6L-QQQKmyQ7F51D|0Lh$9ZrtDihPOcniIAypB+9PW>P7k z@eX79M1ImG!%avS@IxijS?pisX?o--Sj%ztt6+j$V|?SD#IE$#cip=G;HZa1 zc^-8K7B-jw>na#r`6?2Psoyp#1xs{dfi(GB@UhL^E}Y)3VkocJRmW+a3Dv`SKW~7+ z+&6|cbxgfh!ryVf_Ml8s?*<>8oER+*`ka7ZMZ@nw3@kSRm3=3BYeBiXPH#(Q5ZHcy zH!ErVm3lVF_w($zk`tgp7u#WA!^Mza4Meo-H2U%HmPLF-s)1f1VS_>10ry(DM)&G^ zI`9F?)Cs+K(|d~TcgOiB*2G#~F<#uWBCI=JqPG(NHNC{p3Y*B1I;!}RfEv-oI{@+L zXHlWYw_?wvAjM+9e{e;zRvx@_ZYyy6-VCPl=ORoEkK0x-n-pPS)oS7NpYy$jIfLT| zQKNx=Hyn#7&QfNdEi5dM&$e-(b?GDi0B=n|-kJ&Uh9>!b2FX)+EQ;|~<1b_ajcBKN zpD~uC^mb!IHaXMGkVCCdbq6RR^0w~KCE~%|N%d;k)yf;zP2#tAxx7hjvyxS#Z@0Yc z6xW9jdFN$SfkU9WtIiZ=Dg~106jmHVuNv3q=UN)t<4Rqlz~j{QheUMnE&K$xdnTCN z7jXU)S@gjs5|x1P&RL$OYOhv$IjK>5H8`z*95;KnM1$GBgbmYJwVr36!)TjB^5U`b z;nS%6&!?hi5t2}-MWkFSZ%F1DRsM&yv-)cDjlO&+6lif;+*%0k?$APUD^N7JOM|;h zixUcz;85J5xVw9C2u^Sh?%&C8&CEYAYc8^Kmy0*=I?s8|*?WKRJ8rLtU1clCsYl8k z@@KW`T3Xf{I>WN8E1yWtbB~P35vuhSG9|<;Yw!|epV7_=W9it9PxSmY~(+j`^wYe(t$2)K$%~QmH=LBEBSp~ zA9hmpuh0^z*^3MbtT*(6l_w824JVD0V}s`nsarH;UQu{B2aN*G#wuu@)D~a4>l?!< zYq^B(<+PC2?Q7#;334yjo`-EuSd8)aw8O4tC0DiqX442losq9Ro|jNy0vB&gsODy4 z2wNN0c|xyzs4{EGn{D#n^MdRG_oyWpXQ7J`(EZ{G@_$ zVA`bo@+dyJZ9dQp?~zJqZ-@JZ|NM&xtv0E2teOMcOQ~D%vj)d$nadL`D=BRi( z`@Tf7XDB9+nXCM2D_7v?mM|QX7w68h@0DP}z=8ewpcPCb0QytMdNl z(ERf*rJ{}rHh>No;)T&TcWFC?)tb6p`?HATWgQ)Y*?8CWcm8OtZsLr+EuyQ^9?3Lc#JT<#Zjd+aS1ao`=QpaGq4u~#{PcrwH zuD7J?tik9m^`E#Sa@3g$=B_=KJ*~@*ipoy9;t1~&&ibss&AFF#HYo6__S{_6VXLv% zqbyPl(ePC2P^tKIhSf>N28e_`d8xcG!45n*DMww+1K7%`ej|hBPTx2m3Z2cjhxSOK z`QdE(hR=QoH9%NZY7Slcsk0c$IDB5+{Q)bZko*J~I!n9tB+>p?2c6gc)g~pRPqxWa zmE{yWr7F5t;bD4FI(k7V)&@U+&A!oF^vXY+80IQCU^M5t}#3XJWa8vVb)+kg|D86Pb(zjK)3=t7+ ze4w>(s#wT?i!HpGbh|WE*{_ zW1_GXh`rQXVQ1?in@-dkX?^+o8LCWXq4A8l8uJ&qIdb3a6tj?ilnq#Z03YAND$|Re zQvz-5!&ZN2&m#uLs?D*986Ajp-z}seaIka`=*^o{jGNiPXPosx{O`o7b(hB3uXjd& zO;apYkD+ab{C!K2nD)$ir?U|&x`713Td8n>!V&0sb_qwYm;{akkLn(li&i@Ju4O3N z1uN-RK+Ck^KW*^sg|YZ#e3|CEOr4*kp9iuH=hN*2ju2<&OZB?PJLkyEEvlrlem({I zg3OFhpQg*{Enmw5aQ? z@9;x=Y}87ENkL@;X4xh;bo)y|Lf z!$QZVdq$}Zs(y9fMNx)v$er=ly%L_(rhV)FVFtEK3Hq&I=Jf3V2>_S@n>~8d_=?@) zlkO0dsL>m4YNM@ehbT4(W8%?ue*Z?^*Pyvya+CeHK6CqBtwPDK_?CzzsUhJtQ~}?4 zkyT7i{oNY{c!YN}n?x>u8{4wo{&Kl18&iVGMzV1r z+NwoNFwL+bkE;psPKj=@p8^y~Zg!`QQe%dS7QPW0qIU2a>3Xq9T(p@2edg5<%Z37e|&q*~&4 z6rEHrl#t!_4~^GaXo=c2 z9^&)#_{eDoYrT8yhh2|p-wNPZBpSS-<7D;zlr7XSk4263(OQ^{lo7oRoeB$nI}nGj zcW2x;zEy$ObF+Z2W?Qm;;Gz$cW0QgFnM1!)q1j}af(w+)A@(PR6x{;Zc>i;J&20Pz zrW=VHEU&j+*iodrc-Ne0egK{Wv<#n6qOJ@BEG>!K11sW;vJ6x9gkpG0)RNTa_OGYh z&x%HkS~%0i-ffPvZs|O|ryB?WA{f$hM>ku^sCPZ}bfw*yFu~gn0Y@Bkq;Qm$sApO) zH*xEJ*nF87G?&7Y(8!znwTyNI9=)!)_gjHI;oC|6`{ncOL28^k$GoGWzT4y(yBWn? zqz;#KZCeg^3#~fgJ?1T@Gcv&cy3)0;lc0mn&jTU85GE#$^OC*!YSh)<)METiH=SD| z*Pi%i0E87v_)`Gx4{{h}_}sUsTw%u2I#OO>4?N48xt4(5r9NtU@k+NhoSy{;);_7j zSzArT$jh}S+(vDFZOAfg^X0r@X}YI*&a&TK&L;ADG`fq-HM$GcM`)K+BuDjN;h^ZR z<|>d-JI6VxEGxJS?tX9}CECZ@h{fBq4g(v()#C;N3HWV*j{=!CbT5-N@xZT*Zy~5j z-!`%;W+?1eCGhT)9_chf`?DBh6t?V}%o27dww8kFT-JuPXdUH? z>ZZz%TLykym8zNiaPaXLktBn=_=hYV{qmbfusJ z=AlcyvBEetp=Q0xqNuSZOn?t{{r8mDno_PpQQP2cJSA=ITN+;3N;dC|NrCkEK{|~_TO72|) z+$AC2=^*H@$Dp^B4(u<(B1ng{PQDb~z_8i`7D_E0aL$I)&++j~z(4J2JK~ng)XiAx zR}77_8PfD^E`r0NVQdL~7GHDZ+2oOl&N{V+*)?qvYH=N^TuV2Y8c)Cu=mm)in_C~&f`K}s6cmWJ+SxO2a3B}TMAZ>(rZeyqre)!?xc=m z^BwA>0y6rhnwK||9kn1V!Qn6$$MLe0{kf{y-IIW~egdJJs(Bk_j(7*;<%yuk?~Gsp z3i}8v7p$R#A)fNK)8jU0;}1_*$@+Jqk7`H8xYs2}!Fg+Q!DT)cr8AetP64Cc>05x+ zURI{FalXg=y7e4^j#dbow_kDI+Q@~a0w=+7xf;t#w*GzSP4Jy$l^1mPa*?)o)? zMPJNkEtZYPK*pcIu-e-hKuyTq)Pd_g#J7Ds8&|MZiRE_ARRNt*tYAoMIB{2-y~c~` zU_(B4){XJPW>>dryM;^tWVyOu=|~aWQnL~v21;ODQN5R7&pHfGKkz-Wr9H20le6_L z7<7Hz%lF#&Si)R{OZ2ZIw-IRwNuzq4F!BP|Ljy4;YIDrDqajB6UGNV?+`iI|7TN#H z#quKNDxWer+L!+UF2 zrqu)|5tDC&!EW?qV*Hrb5E(cj3xUly4l^} z%wL}iA`1=sh~)Ey6i8j9GX^j;jf_1XwcChe3-4Ha=#<+Vp?V!NTcSnp=vvL);-$zw z9eUghl2xh9NLprxHDGZR@MUqfOy#;r3_BMWCDoNVTr^akgy+$y2I>6pGa`PtDa(2K za3{HmL#NUhbyu!Z2*Mo3&KBu+Qr+pgFTlwhv_Uf~<);c)Zcn?${(vhOaSob4)p(m}1`mRjyy3F~A2*_aN45xKSmIGrJ70q(#)8Tca*t!QneG6waNY47_Ih0USh`D`BnU{HZp1{ z|E{-7-A`qVM##Vszjqst{^kRM9^?!^9q3cXZoepa1i$6^@-37VHB9JWx}|6a4i>?y zUCWex$An)1+hRv#WbTEaQaeNDHr7cyt?^#_xgmi1*^$?*M_8@=5WciE1G%C;OmCGI z${%YZxK6I?e5I}Ic=Nn(Q;Iit&!<#9rXTE_$iq*H&b=MZzVof4`)SYfwGT}j*gkyc zUjDU+jXM0nL{-AE1<#DN@_g?k^SqjTYv+jyfuShh7faQ<^yb6w#CS3WsV_)jedAhz z@ly0AC9M9XDj=NS1IsmfSN{lB%$Yz{er!!gNLV4594~d9z&@&CWfwk z58t7M0tvfkvQXOXn4#!4m*;d!l$rUKXOf$+JKpkKJ_(+wU4lGiu|6-cf(a!aq1W

E_kd(fNy$Wf({wK-80os>dBJ&T6BWZgk0*-RGmB6HDg5SEzz;++53LnA$=tgco#1tAJ8Z zic#ki(3 z#DQO_^{5lytLNd+zUj0O6un5r&Vf!^=eQF#{16WTP_e2`-q@Uf5u7(uk?WJPxn^t^ z4!@u~{@ZX6(;HgZLB@OAWo;$L^2y#f;nbp%*t z+fwCu?6|yPgMWtU+NC-B;$98rPI~)qRbk6V(j*t#5&VVHe;OnRDFWhpS|DZ@s7xP) z{di|M%pb9D!)}zu$nxDYm*x~$me4Gi#2O{?&v6r<(9X5yPJWLvwAFqVhVCkP!y6%o zUtb-k(tgUv_htbMZQm597qrB;j0tTHDzgLs1N5z5-}$5=ki%7y8?F4Aqxl*pH186! ztXHiKv3*YAIrsNnNBYAE$8LfB4==M#?d>d+RBha;R=;uEn7SNqR9P8lg4f7GH3S1; z0d)5B8DgFUN^eQubF7Bm26|FAOI)kTJ!gv%E^wLW`WRX_7WHvg!2=wSzo70jgD3-I&;O|adCpX@SdNc=w1_kD#` zMKUs|B$L+K5)Z{^P7}JcKfIgI#Oszst6yJ!y%$+oAc)82;GX*SqvhfVKK@Vt2(h`L z4m>Z3=_$fDexK1s6nG1ZJ|w7ePY6jS+m-#hM7u+r7QX;>vfn?kT5e(a+Rhk->CJj` z+82xhd15wDX+xUNLPMkG10w<`Ap^{2DpIE~!melNSWQry1=AkjoEsSdP|$D(+IW0# z(NNu{EAU$P_3=+3(T;=f)?(Y2XWEVdlwK|m_6o+2vTOEwenY^97MrLHlMoDS?g31G zoT*dr>w%lwOq#)mmliT)S$roZ?wZ%{ZwoFHQA;MEuUzoUK%LxEqUmSHsTX3;n{i(< zPYOvdu9*503-PjA;quxxpKeeK@)Le8BN|-X0jF9>GpJL1*v7kHshAA%`{-QSPcpzx*OuwR&VM-h~Ev_HqA^nFr z01_ic6(2MYmG)De`Pu62f| zN!1rMd%FFV3W1mVHyurH3_ zam21LHP#tFvVL%&uec2;jQi+S*ND1W+j+np%#65a>OZBaLW2>72Zs}z+pOR7Tv0Oz zA{z7tHNU>}xp&>&&&zlYCc^^oDJRp}@AXN_SwlVL!; zJ~<_5vjrmR#N3i%eWN!jmL0v7T{|efhj)i}{iG@@83_}fW2|qQzCM!GK>BEk%|(jQ z{=V%i25vZXo8i88V}?_`j`?^Bqv1!5-S@&Mbk6X7@GKqP;KY(PVF&Z|{cVJmj@s?g zZmP=a`VA&dirtRuPy?p&v~_`PkxEXj-EWIZAtLJE`5M6Qhz4f)6ALuYjCTTiuSI-S z%oS$oVvpU$B@h-W`=(7gD;;?l@n`y4@aZQGCGht{edn39J5Zb1!6w1V#xHg4Pq=fG z+qigt%3~GbTesmBf063C&Bs6jzF;{RXFa}I>}QP^Q=tzTf3?XDZgG^0HSG|oQ^8v? zyBYVq*l2ls7!#dUsb}vsnCVeW>)`QOzw3trf--yl#|Qm?K6os5rP5wj157U?i4|iG zR!zoGp{K>(%tfG+uTH^Yi3-R2H5!`__*`6gGzH!y{dJ&N>F)Ui1=mP-&J}62UD`{g zwI2<#T2cbv&RvgL7dI!D%vatE{3GT3^~cC>d+{GpKsk^3Tb1v3 zIDZ;kUSco54hqR)C^yOWNO~5{^e0L#u-CV$H)|w!U(tE{jquM?7xfQFXY42bWplXp zlvs2XzuDRXsWFgy;N6+SYG`(AoF782HtED9%sw=e#ob(+gV$E3Fb#a1D6pR!75eWj zbL9agClFFSP^y;-c@;dHcpxRBKf>u-5wH45G& zp9q7Cii1t-8X(%uOrB*iFZ&7HwYU`**GOeYgU&WGPrjuX0^PEa@ z%pI9C5We#B{Wnd;ze}UMHKnpYQ{z4XCRF$;nfa0yZ(k>(z$88o4Vq`T9!=Nst9Z&x zvG>6S%8G2&sS^xW*c1baKj@G+v?Q(N(A+?CN)jEJqWC16lwvqG;EoStdyHbvx3Vl9 z1)JV}=3shA>49@j9v#@cbs`lw$ylt#f11ANt7!LJ_ z!0tFq$*BJTj%q}A4Z8!P6#ls9Th=LR{HwDF2adR5uaMU;Bofd4_+Ybm_peBYskEhgHD%Fv37F4Gy(^97#_;hV(1i|c~Lh-kemx68uj$Vu~*G}#iE6Zq*U zl;a0_Ig>C7MYL0tMUq6D*7gSP3I@C@G2W32gJnq6pqf{XGPU)`lT)0eUQzH~B$N8= z+E-{ZZ5LBtcf-=!TPo&6hIFORjg0hYg4s#lrl!Ua}dX4i!&seP0AxgFV8Ycz*27yH%q1UMEL8vCvw`3Hct{3 zXyb^x{)FCUNTW1gw@v_BQX~6E&%7t?7MWe!$3r$F+!w{grGQ%CsD>xvT&G=rd6yjR zqTI_5q2Vb_VvN;pfBk5KG2{3a1~C&WMlc`n^Ak>PN!&>uc!AvY%kcp z-vjm-DIrNpO1yryceOsZs<60VlR04Uc*(_B&=(X!R%#t5?)%8l3;1l*14E+orsGn$ z4#KLYCAR(g>X({7Q}oGBV-glQE%uL?%;r6t*TejAj~q|Z)9F389VFhIm7HLexh-WA z6#7QnRVXq6yh}-7HT!iua`gW2;V!+Gycg*jYa^ zaklTF=w|@wo%lGU-OoA=hvy%gg751#BNI0|7WIado@#@vrdP#&Xo#EoO>gUS$2fju z2l%in?fw1sMV|sZM6SeDx`G)Apfm|xh?=_d%=b#{53IYXM&5`C75G=I21lXvJih4GVtPfrMOYXJVcF>jw?|Y-H6s`*+}YCjr)5fPZ(EcZ=D^zGTXgj` zeN@e+p_iP(lz2?%gJDm`@W2Qd&Cl;wlMydiwT*_;YqALkktEQa*d9Q6fs@Dg?{83@ zP|y}ucn^F6d)GsBPC2Shw>e@KG+5Xs&KU4z0a_FatADZGuX8528q#W-c*(Myji~bx zkpoC5sl)h^P2$1&WixW!QM+4RYzvj(ngK@jEPwmkq@be`W^Kiwazxuhx$DK3kys1Wf zm|$S{b@gzeCV#$A1IhX_K)e!^#iVawhKV2-NWY)R&M&1Om5y5AcI27kka%mN@-zeP z)OgS?4%_R1r<$6wQ>6R+2&5vjdd(q3`JHLQ>FRWoJk7(W{RM>l*E{PNd#bSZ(qs`+I(0p6$Xsas#{Vt|i5<$_o@Z!2Q z=rg5MBfs?T}Gi=cpa_BayRt^q>3I@l0qqs1yjNwY6R?T_RIJtUBowPGQH(Tlpc0X)V6 z=bl_AyN4{~+jI`W;@D!7uoa_A66O49yw-7IoO|545fCqgRT2SL7rl?B8Z~rKRor{i zr9wUp-rwiPu*`KIkG_&Q{nQ!Sx2;Z@ZQW*6O4Magigs zybW^bv_TXew&+A&oe_JvYPQW5z9}?Z9QMTYQkOl_6I+e6r`={o^?(nHvsTnTXZjh# z*U9B7{Hzf5r$sp{_qBR9g;VgX{vDOlCAznVJVg*ulS^HVANi-L*Lsa43*$}~-J3P{ z6B;vXw;Gp@qyBi7cg%46z-VLCy|x9}Y}XqVJDZnrA|z>{f@X*|X=vrNwKfK2QnTNy zsMk>7@x&3}Lzn%Fi} zgg}2A5dy=g^;~>C<5EVV>4qKq^aqJ$q=$036A}S|tK!Sp>$ub~+5G}+oxd(YGP?By zkrA32hKlRo6^aP%xjPPYxa(|xwK}2u&PNI8G+*9(U_`RAyyqqrRZV=MpI;5QHa`f< z+Er3v&||AYV^Eov6EWL-&+yKRY;8G?j-Tb_!PnUtXNAO(fECk3OG{q+KHM}u#CtbS zkG`Q{hW%+dTGmMmdZA2>d9Q>W+vi4iePDnz9`hwu-Kq8If6cNGjOXbYIdhob%w_r% z@1$#i8Y1!nP^NvL`B!)UTPuEA&Z*;5i&gmXfiSI&g$~4c^J1{$_=WaY>Duyr_uP+i za_v};n(e0y&!Ow8q)zMX(7<;uga^q`NrC`+H8`}*#^Ee$ZRk09BK9p&qxNI*p@!V| zckS|2_J>TT#J+d^e;?(t863Whm@|ks(Q`>yO$hO;3d~WaU~4H}-S4S%-zVjV`_X`v zBJ-iN(#s=%Qc2zDAf%7ZCpsGUbn|*zrm|Sgd4N;}iO#hbcWrqGLVE1iy==>W7Mr-S zGshGpIpiFk;4q3-U*i*W+cCupWP<0p{D71kU{8`!Qe9t9oa~^uC{HB9h_#(8+gUyu zUpd$y2$z&PZ`NmCq8bdmDegYaYn-sq5@UwHGDrY5VD9_dvjCGgEE{T?6KFVOp}V3s z6C}O|qod;*fy)3}zwKgN!6DPiQ(mNPqvx zyV&44*d%JlEJOh-Ss?>TUt{X z{Awo(r;iIrIRLpBt~6~h--uv=IYw@#4+nNEn}RFXl%f@OZN*AnvC!rSG4P<6sJYI% z(Jf0h2^pBt)4=Jk^TuSbq+!~-jp7aJi`i;UO*r7!HG$CE zhjTu*$}IAfO#s9!tYfYj8n3A|e8nl$n;N+W8dT$)n;dxQxH)oCAcIvqQNy(e&T#4r z`!X`I;?x0#crDXM>8#JLbM4{!(=jWKrzu;O3i=t_CPzm2p<4ek!G9X#Et7G_!Y!I8 zH2C%ySK|(hbjrOrrbqpF_Of z<68oX`hvI}%ysVAN6&*iBmcL4T9|mWyu|pi?04E3x&y7DyRl^d@0Jj3$4@aB}mR*8f}%?ekI&Q-?+RXGb>pm@cBO zmfat9BO6QqPHwX!K6i;q_Zcdv?p|&zEA!l!;8$p4dN{?5N=NoS8#4gc2pJo3)6Sk6 zb^55DMh1LzzW^=(gnvD4O0(Iv|1kNbs%CfXF~#Y~uG~;V+Q{2CJ&ZSssTtd!&ghu~ zcnmc-7`C;~rs*b=QC42FhXl4K_dd^Ue@#1G)%|n^J^cl-*$wB4mLU+7?Io=ZsxV43!996&*nE#i1og+C?D-AbAPHntj&_^Fg;~gB8!#=OCwsTsG!C*ai2?l zS>^**xX?rgyQvl>pTnW3;PTj`XxG~7zvo3i-8ymhoku;YrK692h6uDmH?n!8F5*Y3 z;iTJHuEwZd>k739k|(0%ZhiN|No#XQ-{O8=xexI~f^RS8C)p|{~+jI0#*RGr)^HhOkF*g)d zybl5Vi-j%Or6$$7mY6d!b8~ea1;Q1`?i3hxLwb6ax`qE`f%x$3{g>_crXjLx`IlG4 zU_plXl0}eGxtuB6(Qc1Z@Z0BW8Ok7kIitB+{-}MJaP$d&FI%#sr#lu&po9X=4tL@R z%l50L0al5g31_(csm#i|LuTqxFD$>2vH^<;K=i@@fNlvWAZvwFI%DIj6p6Eyl->p_Y;lY@IDl z9`Qd;fbr(Jzl4WRj&$`4@=wY+VO4xXSEluaKi{{??&Xj9as+(MjANvWicXU=j4IF& zcvM+RIP|qJC#J{Q6I?SWl9FsuTdmajI)4JA7?&6XKZkTCIR}cifhl93m~{Q7!tPzO z(~J8(1O;5!#u9BsE2*`e`3M6}mEGRT%C8BDe-dxic_X5~T0;TWpZOY`xpp}0@T)WP zol_)XVnW^ya8pKQiF%sARt2`hw3Q`^zhpR|jFlABQj7Wq5Ck}=vyO-O&K;$vRMaUc z*|zPQb9YR!QgZ#+u8WSjd_s;WbUk48iN@mf9eLy(nNINr1>J$yHF9mVH1O{(x_%Y^ z@a+ovw^odw^GE%C-GJY$#+e#y8K5+GzKyb$L$Gyz52Nq`n@4oB^^I`s zD8Fo*yi(jl8HA_(m{=IFH}yJ@+8BrnQqbF?)SqtXI-(Wd!3Q|(GT?*DS0rFlgA3uqqMMx z6oplqw=Z)#ldi~=V%&X!OM{9osBFiNRdoEJ(n2y0&0^N(Bz4Tqu#-VFf8LFDLSt+{ z%D?9iB~7Uo5WOk}{~CP7kw@;>-oy|Ei9ZX2X_-6W5aiI_mi_w)vUKmxGeG92s zs*6ps9M5H?f@<90?f#q2g$B!aHcLnGgN3VX@#WALhdVF@s!O3T5Swasz}d)<<;`r; zm(zgHy|V>zTji>($1?_HXSGj}CVD!$VgBSawcy0DU{2sG=5KhZLfb@=TmwA*cDCQK z>UT1f96zM?L~@v3(*MBsWDA${OT2(r7`OcZ)hf@ZPO&v{mzyXSs1bhZG7Xb#*UMEf zsR=%Dpi4I;7)0e5rZTKeb)ERM@2lhLA!+t=Y~G&KXzgF1O}{PgZ*+H*sa(I40iV4L zpSjz*h9-ocNDR!Y&Fi$*WRUrS0Qxp_K=Ldt1Ej<@Kv(qqN1B%j^z-Yk7{-b}BJpTh zxZM7z+Ptiy?;-s6?lhmhy)AZvH)9@ybBvqm?5x6(xzfr(PSE(~!GZ$8FnbMan@i>W zN-H%9<1TBKLcc5dvD0|&3MO5L@6Y(o8St8@N0Ss*X{1ZZl?jJ>nSKwabjma zCD5+p1A_n}U{!%kmSh zs))!H#vlIlBLCb&c@Fy4X{Z8anT$H19F{^zk8dJd2oXJnLppUsrJ z{;zL|!9^jp2x_+xyd*zSJ`-3Q3aU@{6J&pH_v<}G7MZhhE}^;XsQfVd=y2l3R6dXc zE~sb@WY~RuiLDnP5wP4!-EsY0+S)a5rALapEn-=*W@wVq_#|nl_uY`mU|Ml5NLCqo z%N*!zZBLa9dli{>dZ2dNEp+jh`!6EN9iW+7qKMD?Tk|*DfEUWjd_x6JMI-R1WbW?siGGF z#faftJNT9vG!XO!F)EIz_u6P?I5>IHVsAYiY%GnRjhn9i;5%ey8O#ri=SYo;XzVke z_}7=9@OfX=zszT?hxG)cG8T!V6vmSassqz;GHo#TIEbTQcz)OZ2J2h@?p_ml8n8Ao zO<}Q0)HuGJ-6mQ+;QNhS=6A)Zrh2=IR1aF8S}nEC>FFHBs5+U@NZ7`$xNFovhi|j{ zY;(x&#hHqqf5X=eK5AnI0TdTmAM?Z`LlH8Q>0HZ}rjUhEuY_+6Z1G_va769M8hPD-UI z%s^-eqMW6REB!*5mRJ1Q*`04b+T0F&^CjEr;@vpQaDx24U{-j^6%l*?bw^q8GLceQ zrW8y@o&5@hkdF{-lRv=YIwU#ftlAmGzE(qRuS7=H6|2~k2443|{70jKt69%bi6L36 zKtEF#HuE*fJbBo*nU%ma#=8i+&lme~mb@d|lKeSKfnP--ZIf0OYW8<|5Ms{8B~RJJ z$etK8AG>p*q;hNA=T2(3-V)bEId?8A z;^Sl7b&8iInzjUC3YZj)d%2ZDmV+}ybNcdv97o_;L+P-J;g!Toi9o!&B2wClqJk>;mI8MpGGCFib-i@6~DlA(dAr4@|sd4@IO@wJu#|0}kwW=Bh zWU-jR{(2UCnnk63QsGX3U85xQb?hjn@pj4=ImMYzU$i|ZV^3hUZ}rV^2$|TZ=IR_N zmHeTUl}`!4BT6qZ;vdiVQSLpFG%?|z7jVe+>I`8TdOVhlZC*Z57&%T$`}MNx8ybjn zn(RcsM#vZozc|H8SxJ5KI`ZlS7Tt7`-v*^9oJ0MDKaAQ_5G3_rx zuGp^n&|_;&X)Z)bo?6yAh;nmrU~x6Zg1Y$(2DSI>NIsdbG2)~1@82e7`gyt|CFxG5 zl<^89ATy%806gZ_%vNnUx)}yFFFR=DSwVHhPGlVm6*kQI+~;+#=sLKkr8khXiKTmT zjGpQWydXPX8jj*$`_`$J?0w%QywzAoIp>07CQ9 zT3bBr*38kyNu6ys({1HI3}SY4P-z2gKVH!7Ica}LcthEUo-Z%EPk*FeMjfxoW#NMmYtzE*|n$Xao_PG)rfXXB;?}Y9Tcvz4kW1Kas zt8X-v=+4ufKRp>y+_uQr*bY&E?G^LO@~n&{_WD>Dk=KWRceGjnQ~t{bLh1hlc+?Ov zQgpT>XM+UOoK+ti6OcU$Xr(QRYHZwN!g&XNX5KVRuVy$m`+e%9f;Ps`&Lf&{Z#0VW zt(o-97+p-O|4at_PDa{pL9~+HJm`=_kYsbKrOr>E_seqLMGH@cJBBceYubc*OS9YI zVqduG66q8t$Mw;P2AyE43s93{prUzh*>Sw~2P&Dw^|&25e?tXEvbBGpB|zGxQN%-H zdVjt3B3YO z>Q&Oa<@RPD0Sc43jIW~NzTGQ6GPn_WpEgJNlAXurA5FV(>=&$$w^8mN>~vADiRs25uWanR#GH=o$4rz#)r;6|?zQt;B|k z?4sS!GLBfsQrlk!@(a$guT-Z-mNo6NP-spv%$Szg;eW44+2>olDIjepxQvQ9HvRB}a1-k}#1t0w$+ zHl~+i18uNisC;rJ1os>b4hA@{DV%s4JD5@u>LdJE9uAj zy0=RvMR}A|1z~~?NGBd^n(bm~(sa1!zN>Zr{LBHYA*DqIQsS}D;pWL@c(2~YMf9`I z5`B(^lrn@1-Bar^E|T|95VRoG+T09briFfFSloucj_CdvVgbe=8oy)xT;JUAs4~9x zdq#!UKWqNe_{U`ipf-%>Pa!->yz}kV$4we6&Is6WoqhhL1y&J@0||MQd!pUmcMCVP z_;`bAEzs1y*L!ELhl|9*D>cN?g>Ym5y`DfSPWKG|LMJUBD3V{wyn#s|j@dcmho}n( z=$ZFIY&bhFQu?_NHV77p*h;bbNO-Ox0P8vz#Myv2IUAnr{S@Q2tL-=cGhVcW*;l=? z_8*{te+*Gg3G_!Z`PGF_BhLKKOY}?j*M>Oxe-&o+@#MA~4)<9)FvXr~!mmO=2|Q9% z2&<9a#ggvQAWunIQb*u+9FH3Hk#>y&Zc@R>g?_Q~O$y}bs}qe~CFY9!@T5d&g>ECl zI*!x9JY+_p_AfDTTyW`X?9@aEC?M+^m*j-!WdELdWS9$K*vSr2$H__Pk0UR0~ z;UTY12mSsZAfM#%SboH_GP_qoJ9JB&^K)%O+w=*W)A@>Qhh-ZVdfkOU(`XFJukrv3vcaOl zjBFg_RqlL!xN2Q)FTJAdb^pXstny zaWhfKu%L79j7E^6#%H$$lOK?lxtjuZX9W$>hWIWwSAOkfO#Kxm6tVW6>+Oi#+Fo$K zMsJy2KV{m3@C(iPULns5cW_iWUVpVp7yHvM3n@{tOFTDXFJ!!J;URJdWKELB{wGi-Tqciq5}8b`t8 zmC}kjyD|>zf|L5>g;k{oE!&gMrjE|}!?Zw8>`giuGlBllf!)VH@Lh={?yRkQezvL` z{)J4!^1pw~xBo8YF@B5?&v0ITUoyAtLw_lwIeZ?ywyks49PvOC3jF8JuE9=%6l5$5 zY)4c0K6=PE({#{xmE%ZrN}s2T(xz`ct!hTkCx&N?UASpB*F!i@3a6*pX)PP4=V$9i zI=?5FUPjW8E`Ia-b0N}%=X(4&r7VD`yfq182;C15>TEM~nSl2`K(ZQ!{&nO}k%X;nadO9{c)Bchp`m6ymh~b- zK9r(GdtD0-Tn{~yFZckh{~Bt-t$O=3e?-Cp?lPMN!E>C1(QZ6fmxMfw!if@L zWF;;v%d;T&Z)4)(UNi4(5XNZF?!GWOFgYxZUR)IV}+S%&KeU`rKZ^9&C-ITt@_2Kk&?PI-IhLcxmM6PtId0%7lWD*n(+}AN$?!21Knbd*Q(hPAph_x0k$%ek4SG zXg@#k?3rt!b%jn4pi30qa4_@0y<^!ZF1AavYw_XdC8#s%)oU*zO1~<>Vsn z(v{-hi?Z%2x&8xnhTW!k z-0Ay*hR35NQTtn}1I--w&tIxhLL^}$oBJ)^5C+;))3`tVpM$`~sH&pgfE(yV zUvm6FaGC^n2VE<+XD}31h;)KgN$p%a^3PqFcJs`4;`xhfsM0OS9U_|)Z2mYEGMca) zJh>*$TB5G1WC&T@t}Khyk6Tj_byM+pgk4IwJ?B;;Wf4!Wb9x#)d}THj*jEL^Mu>H^ z4>O8nK5V@3U#W$-k(PH**dpiAXz$?gbAGv%_ZDSdzP2a7KSY4kbq1ZAwxfVr!uET$bll zw0u6WA&Wj0dJn#_4}ZUqaaQF?25I8tL}D{^I@ARd8C`yg2=S}OQPFNUvvM{gPrR8k z>t9IQM_WKH@!=N%ww-osq|oz~<)8f)i0M^RtTj%xAHOI3JP%uixKslX{LYbTG~$9D zHNP3_OEniWGF+T=Yu~?qBdei2c3u)y`LdtnJ2UR&@HBz{U z@>Te*;37;!eSe8%WZ1owK%Dq7~t7Fgy;pjr-Jg-N^=Qp)kR*myd#o-MPP>eavs%XVF| zk`DZvaGyqHO}&ot9nz?rI>JuR6&#Mx+9EVnKQPVa1J(uhincMsTIZm*YS%%|PwOR`1GCpyREH$s!l!y$abOqJ-^!vHux zoCJ&8@|BI_g0{w%d4nScb3+-nXGNTsSq1@-+msK(ex1CugdSt`kjB=AYzkpnap;z9 z^qH+iHhbnF1lN-~w|z+HI<5}Z4J~lU-znG5-u6`=30t*FAjdUQSn&_xP8+3O%o*)% zY$1A|b@#7FzA($>X-_7;k$fkl4S5SZVWr2{uXa3alrO}_Z;}&pYL~^4Wxap>HR&^Nt>kMdEMeA$5dne< zIZgBY9iXyoiP#)`h^0dy-oGW>{xXV-7bZy=p>_CvqKqn_ZG2#$c0INe^~yh*PQIfG zUpTC0r}(>9lm24t#y=LO8D~_(Aq7e(uw)&?+Z>G^zuC<|*8&^WeLPYAgY%2xv9^)% zAnP}GPpO+0Bxptec|kOczJ9Rt?jTwtNnlef<5HMrY%cH%f6?*pMFZ9}onSMKQDW3b zp}+;_3Je9A4WUfgssmT%fdo8nNXo6tyyI)iY*XX9i~5=B4rs0*w>b!xaB67UGr?cs zWo^2=;Vf!bbiFz{EBi z1vN`M4)J?JGoq;cg(^jZ5n^otygqLi;ll&p9DiV zHe9Mo_h6_Q!+~yEKc4e@;~2^?Ngz&y+gFIwHVh-&A;F-fApCdF$pYx=$~w$Zy{|%ik9x#j%%OW@%r~oHUN_#)`~WEK*G~Tz6%V5c;i*!^tqvXet>goq=9|R zl+xVvN;m8)`rF|!{$e7_W+tocvW8uUQ)Y1a`d4QcCu4bMHlhiIt-N=0O1GC-5(-J) zQdD7+L2)SI1K-Bss4Lr%FWJ-c5Ycg5zkh2Rc86RE*=#`VY%z{U0}ZsX(vRDw)&YojmY=m0s`KeQ0B$n4j(!g{fjJaP?MV{>EJ+EYm>=HMn7tR*K%D{!8cyKR$j9XDNnOWpQk187(p z&h6ZJE1k(rv4T7jw9Syh`4}wJ0jj0GHEWh>Q_9lOU_*A4$K0b4JY7pbUlM_&=GM;C zJj6Q26Wt6@7f;cN_d4zmQl9O6wJ8&1fDkxox&r7OI(d3pve4auQi2M$4HhVqH7i!>(gpeS^T}P2!aVdMh(_Vi{ zy|U<|a=3bRwHsSb)n7T*sb`*y#V!E{^bxt{m2#)6chYyWS_~%TVU$3=vEhp_JEPoM zp|8j=v>6v(hnkQC$Yh@m2e&L1M6&G)1x4HVu$~{}pT|%0^&tmbRc~=sAhF096xa~3 zIh7xgn??2QKL-YQQHE(#PC;)KF1)wkd#Jwd{b(s5d{wv+Z@gGFSXw~rc1TZ>HK9&> zuOriP(#*BQOZadHYZ%tWY?59v{7JMJ^vkO)3a%YDLl^Q)fF`fbtF?n&;%!qA#enCh z3>&C|f0cdTEB3IE1K6(;YqPVDB9|V}oY()7Islr+X?8Tnk4YFZQd;rv32w`yJd#OY zeV-DbnK3nNJgO*xHJkoz2b)VH*NrJ3&;copwYXw%3`zI1#KN}8v3=GHja?thWnR7+ z85yWtTvpvAm0pI4q4z9y`Bnz#U6W@r^46S=qjN~tw$Y?##ZKcyYH1+9l-C3fn=$G+*xU!Wa4RS3frJ=&Dh);gQ%4YcsS{W zr!BYF)Ub`KHO@z7Pc3U;@2^e8W%Rq>C~PEC;5SeXwcGQqykUj51^GG=YW}*^ak>dy zW6}TZxJ2?gN6*Ax(-G+tB>^qiKq8Bo^i(v>mUNjNVIvF0|EnuVY<`-L6|l@TW-&Kl zPjeF?rSyY7p%|Ty;LoGL_KTm+szWA3k5%94Leh&)fvJE^LbzUaq2PB+S#n!iYVk)S z1#U9^BS?=ap7$1Bp&(~Z&@pWhfj#s>vV77VBXP`7BpzSm52v-c>IPhD3zm5n9t`rs6e`iQB*^9PYI;dzjw%*NR` zY3Y7}c`KNhhEo!?N-iKulGZm@DE%*76{)$TbA?Ex6AO)<3Qp2tZbAB=R<{z!1nM0@ z5*w&z7Gqrz+NgjggWlR$AI2r?f)}15jEiaiV(&~*rEKeQh-1hk=QP{k(vZ@KDDbR^ zek3^D4Y-?G;?QmSe2sGLL5a9{c$M4nZIdBv(;-j{E&jLIjHQORmE4%%&}Db_)#d8& zPC-)hBfy(|vyJEf1 zi5Dmw$egcL)zyhk zE41WFDIjdsNl8fJ(_vad59b-CkPevwld&PRX@pRfRa)i`OU^lA8vV22k^sFRJimWtr;qK4k2wI1vJqC`H})I zLSmP#KFNK{8&$)*&y{)&oPz{o;{*dLt8pT^d0PRYYpL@~buui8EGZ~I^KWp`Um6ME z-P+*X=Sfb)6(={i(f}UE$C5h@sCw7vW^2<^SMn^!b<*O)@0-Wkd5C zQMVf&j$qAa#nRlK?Gc0mc5{j0`$?&p(uEKs=+JMJ@V@D&=a8M@qW!qWAfqm@!mBC) z3sNxl5#?qJDI-fGhwXY8>Zh^);0mtGv5}2N+rp5MNRXEDQVbIk`z+&fz^uGEPV=|q zxh~u)zlt)aT9ZuJ-(YkWX~?-iJ0lpLAFj}|1R ztrJm$>ukjsARGpuf3&mx83J<>|DTVD>d-;?)BTQ;EghZ`_glV_Z^3@3w8r=m)1x)D z+=5`g{5{{t^18+>HT`FkMs@-a{rtHz(s%iO34`PuOG zF|0Q*dE(k+Qa9aCiqoX3_byciUzg+`wk|jTc#RYrAiCp^wuL2c!N>@PE-2xxVdF7TFqCXH$ z=w#LLY_g!0Cs-A9BIC-PP&$VK*(@r-Qbi|!H11HlUoK4K|wp`(3)ysJ@r4h zkJI*li&*#k4WEN({s?H5CnX5Jfx)gVmm~%cw>qkGrxhhUW}v##r5tiXg@bb|nGZm6 z5VZ#dXWZ>{l$~pZ&+uRmeV5kc;!MU*9?zo+cqNKjQv$x!ZwpK`r3DV0kxS z|4NTsHaIMbJ@w_@}+8ILvm-|uTuw7e_*WWhqftI64E=$l@UH8CXY%}M(h=1*L z@sl+&%T8zZ#e)fpFLv}QrGz(K4{Sl$byR>F-iR&H;Vo|mLugJaejiwwmM=hgf4x*x z9w2*-l*Govj&EqP>A>%=*!1neD@Scdxsk?#NPxBAN4}ekKYjSs(a;Q-x0i5z6s_42 zhZn`lhc7t?UHhw(XgwUku@VOIocec|Swd`IjLv$s9A~%6jH{!CacE%?8WyhWoc+&O zHPafZ)03Hc?zXkk?}?AM3H>Tk5>xD(u0L`D$G~t^<#|YCf_ev%Jrc^Os4-e4!VL@= zB@Q)7&I(dKS@*=qSN+^gzljWTG;4)OlH*Xz&jh1}hA>b4`dQF%5pu*`7+ zHo+*L*s4kIC40t$ePCG^FblT?;{W4AMf6IyXr1$pDtJA{H|K0VUlui_cTu*0Ygd*p z&WD$dgj0dmO#RpVs3y>%;wf5T4wl4_b*@=0)XJXvb92R(s`YU*fw_nT>AN7XPyx}S z4)cAU^l?DR2&j{9q$1nqpwIA8z{;$-@@L^E(ee;g1o+WW0a$g**%Rk_>o?N3{0aSO z{8%m{si{m<)J$!w17t%2QIc57`xDt*P6G3^xve>I*2r(VXjTH*^I=Zfz&N9F)~$TV ze{iD7MIX>ZLq}*oXEfb)rg|3j^P%RNRtVC<_RNZm9e4NW3%=fUvHC0*qc%Vl#Jj$n zaQOa=OLI$;4!CKMr!|*+&J>o|LpvT+LhN#(JsWRox3)+C`L zyWHq#+*QP@l6q^=)Vb#(l=runXM;PPqDVU_NlOl=@}=$cUoLi%Cp&S5Xt;NB}EwQ&OKS7D77($n(<=f}5h^{!yJR7V9gy+^9rJ z{jHu#eZL+WWZ{CloB^ZsO)>X`DIp1Zb|+6aop9F;2?me{uKX^kJMyVxc=KGj6<0plMh52yK<4`F! z|786S!8#lbQ?Zv)biZ0(;HJCLavxRrpFz^3yxlFF@wW=g`gO#RhKNtBEy!vD+k)#@ z!qF6`V_nKu(}qvFl}~=-S{@5*Y-iX;UtPVX#)Gg4+mf`kv52X+9@%>;w_Fi)ywvp31PW7k14}|w zc0Y0G$HHP~7(u#=`yu`saVY)@UMpJh1^y{>3ewpWcR|Z`7w5s%>@YKW5QQoZo2QcN zc5Ijc^?^p4MxzwXYI_sDxnG#%;P8eS68y5CZZ$iW-iu91bY}{QpoZt#OF|ji?oA!kixc?SlYiph85L^bneOBjGeqW^g3BE`U(2aj za!G&T|4gWjPLG-=Sk+v2dqR8UW4k=*DV%O3xgxQb|K9a@n9GoU5jO1d@kYW_V&5IC zDsnqdTqKe*MI%oXeEDfkaYFUluYOp3sjyW6v1Dm}1j3ey{<6Ov$-q2vCgdih(b#au zr|ih$n=_p)8)eyUS~UBKL{m_1da+)Hm)5TEg_B-bzyezONaD4Po`IABun|kQn0{7B z{jld2`7DKb_NSh*m=_tW6$aHKZd9x~{5DKBO3dEuF2)D_sv37(00b`p6RIUA=jm5Q1QFG8526I`s>}Sx z-}p`rAMhbb!b{S6-i#U4928A6Y4iBoEk>wekDZQ=>;+Eb6!R<*zGw}(73Abc_o9_0 z5x#C66JxWv-)?%O0yeOU#FH2^boMKafZ-1IwSYK2kq{!g#Ajg_Ux6w6S>;x+jPTmp zmt6T9&{zfoV1F-TWVr}qbIoD5FE>t6L#KZxVHEOI9pL7~bgbHIQh^gLm# z$?${-jSOLHQPxd~QndXS4^@niYCH(!8H{ua%lPD?WpcsB#&)`~?g#1OpF?Uo^Zn}V z6^l)-j_@Xa{jO_tS2U`tn2qKCJtpwKhi6Wu+|vhVEh@$ zLZIrx=?xbp&KGT(G?g(w^>%i54CU!(X+4{5PaLZo%U7)XH!`hR@P`+u*6GW}%Clkx zo35uG5U#RQY?E_(QF(IDzbwXjIUUX}9m=#cEa2{Fvk^)dY{Umtpon|;g)en5RtTSX zO68vW=OmkXrN~o0s`@T1gz_Z*2S+8`j)Ir3EvnnfoPJH&z#esecJaAu{%5zppk$Zf zdE^wlV>$#*p12<&e?U8DOH9FuB_O%QuwYZ!;qY}%UVdCwsM?ZnU7mP)-0-4CBvZ)# zND2a@t-7Im{WH|`r3oWv4pZSMp>j`Zf&6aat_w|<=YfbMD_pY#abLf3Kb4GnR~g7W zSc4skobcRm*9lkl38)w}JHs66=L3|BpL*37?(71D$$(H*a{dD7(xe?80Tu1z>QPhFir zUjuq&4RKCLa#sA^I+7id*u7F}0a=<$8IxyjLw51chH&|r&qRJfsVJf0N*>ENLjhSK zA1ou`F!I}V_Lnx2knP`zr|wv7Vg6zXhlU=XSX z1NGG!N?4*)21@g(6hinmX0V& zk?(t!9$=rUvs8N+Z*9JsNN{i58c~qQ0#9$t zF_dB3U2=iHYYvB(t1ia|m$9$v73(Jz!Id9z#n0N2Rv%KnxsL%6xcStzygs&zUfNks zPl!loR{&8W4(Hr;Z{=T9mIwGd@*$N3zJPh_w!|~gQSx{majh}`*kVp@34ZtF zA%tS_xB=1{2?*PTN&+&IhUr-MhISz9x8Y9~_9l+{wDCG?AUI2PKrnl{Fnk-~=#(tn z6bF_;m2=0^nyPgiuPb+7brL7-0Qar9IwTj}J-=lsNA7sVQS^(ZBGV|*rHEuuy|O>Z zh0RGvorSP|oj9RdWkH*PF39j4ZZCVGV~IUS6AwCy){i}LHtTD>azqJCTK6WI)|_-r z`HKH9uVrFp-B1xMWN8IuN6KS#{g6Mqpfie?C%lyuJO zk_?C~vv>D}aP<4k4jzeq59ah8do4)|L9Inb!09Ztjiz8NLW<=jt3!VkSgM}T<@17< z$rzhrOwJSg;e=BP;MynZN0xQJG|4MKg0*R$+;_zXk_iV$9;w*aY5#w)o&!hfDgKWN~lT{33AhZYa@vk3m-##bvAZ8FK({BU(= z%=MI6W_#UVf$V%?v%r2nx!MScQdzFmrE8T-xSoQ0{FTmT$LJ-V|7t(M5HYa*mi>6R z(Tn&mf4J(E`?_Gb0OgdDY2j!|M7+ktL;>bpv7aL;1csrWr?=l&i0LsAb#-6I6~9mf zC|^q(P(1$GB9+Q!D=iYy>@PmiO`1xkNwpqfz-6IvlRyaR+mCyRn^%1wZEyIfv7`u^ znC%N_+xL7~A=we6I`^!bR!!_Me-(P`@DPvv=ULkboxGphbojX1HFA_lcVn!aJYc2X zRgS!3sT3c60IZe)p{qXHJoro?uRSN_&xbQr&SL z3dZyy8(1Q}&pw?IeJkBtlQIuN{xSCFVu;K>NzA+t-Lo!349zEOdFSz*tj337F#D^L zi#4BtPLZ=Ksa=}N-$~I1^S%pJoD6yI z@!azS8@P{>G{B{L_sWX$MduS0)nS3`08tH}=$C(X7mvWYC+2;nz3I3f?x)Z_ohQ$$ zxfj@r0dzSM-L+ezElQ9ahGxE1qjEftDi@}RJ$~wn|8w#QJ9TZD?Spql9CK_1it8#ezk%c0Qq1qa`w}gitXKSX*Uc`+Cw_O2dx(&=tlH z(OWNgamQ013ObDg(s`tJidDY^U7kU$V?o|@ZP?J?+mj+E)dWD6#Qu?Kv$21=6G3!u z%0XD?2|xLTZ164Jm$GVCpoN)-Kf~3xN4ryT z8dmRer{|K6z?sqUq|tF$_bYJCyI!(5uh`*QshE_#$#i~V`DZ_Oa%7OB*gJP=Cd9w8 zHnw2?yc5T3Gz_;roV$&!Fv6SeyI1fDD~_L%s{UHEbg3IVPNqq3tbvOi1CujF&E|lZ zSdic*`ZreG5+&waPRkk=wu$kH5KP+38VSj-1PgZ(S44M z{Dic21AL2CZ*Tb)^uCQHBp6r4wv}1=iL==44}#R zoo!s>b!C71736ErI-o)9+SX&}q_yYt>ODeRW5-Na@lVV@XTHz0(ws^7OI>%q@)a&~ zjr%aPwuv(LWv7{QT{cK9=ShAsmg;xgI`g>^`!}%O&kno2sKYrrM5kD=mGsNWWUiq4 zkmM9+?($S{lU!7-=@TDB6Pl>168Bb{xHq;bH4-F~(C{2X#d(26aJS%Yu(qa;_QEP@ z-jrV4>PePP9PI1INzs1vR7Hvdb4u3+I7bre{b9=Ux@2nlp7XqtM5d&`b`doE&>55M z+WnIbtWApzeEQh)N98efP2LUQ^O$%ah^Q4@ub2V(UVr2lT^ijoR8vv z-Tn~dY>rwl#nIf-2q&;8;n9eax$d=->xd547J)p`CmGg?TCL@2ao}za+$=XGN2cou z>O66w%{mYBCctt0ahiL+ ztoBazrkitOtHC&^-F9MEcT&o_%GBElOUql6qm$+G)2MC~k1?3y1S~1g*q!epq%v5; zAX4?m=LW~9^}YZd<H$PW z4`)i@rO<-+SB8U)^Gg=%etQbvTv3LSK+MQ~gg@;b%!onC`&aC#zIAgyuPPTypweAMA3(BIm^X zS*flC`SbiXSa$1Bgeaquo_(IFZIt-Pd1KmsZEWpC!^G&>eN9N#CR^t>2a+&UOk$e& zolTIw$=NKSySa7QO-A(KRs@f+KNYTD##6j=8no!D3+H8pern0tNFkL2dKe{H^B;AAdGcGl=p*Qpm zFJB4uwY?e>0!m=ELE1Wj>Z+zZZuMqJ(k=}rEqCw~aWjT-ZE_tgG_H*JFIK|CQupBa zA65ANrRo1W_@yMBpz7_8?@wDVEKm32<29opHnwHv^h7XIldF5_${$aVt1rd-e{gJb zN+od7eH#Z~hTtfk2dx+t91Y?uoDTerWG8u%ZG0_KE_^_L2m@T!qPI*rQ|FUfbWZ*n z`~j73il(*?$*eOOn3rr9?=AXMuG@$#4lPnc+A{>%StI+O*}#MrnE5#_^dy2%KZ4Q2 zdK0xc3YE>Z(Hj6HdVDqQp+Xn^N$|WYaBotJer-V`?ynB+WDQV%8gH~relCl;8CeU5 z?BH7?8y|Oa2iC@2b>XlA`2Cs|DBR{HGCN9)xW_Dn# zV=^TB9O4@pMdnK}?5yfHzEJ1flA~18Y-bvG{8Pb6F`7&0F80lJT2%0e=b&B5{GxE2 zuf`s1PxKRE4ZtmNl-Lz0gL?3EI0t{xQ_LXLQv5U>JM)4H+lbVycQOwIE)heSsPY0KZH zaQHHi@VF&C$ZC|<9Ne+OvS#SIykg`B9gZ%Jz%Boz=a;#<64HXFCzG$2b zH`fFbYcKULYER8vZ~EGnuoJ!|G;SG}+v-$lbF&6>h7VBM(`71u(N69Da^SJwU>Cp8 zVeT;k3h@oSwVj4o<#oY#`8SkH)$h^jxkCjdC*G<06B%9|fs4yOdTf4_Pq;3s*Gn;b znTwPDrNrPe;$#_+<0nj@iTW(j0_}@N52zL#_WIrxxn(B|!deM@h(E!R4|uGja!2n@OR|0?E6lm#mETQ+$R zF~U~~O%x**nx!$qU!n(TFOQZQ9sm30P3SfBpsQ9t?*4_*lZ?CwE=6Q8z$PiI68aQ$ zXZ*upZ0I*)yO(ZjgbctN5Ol90<)#1#_>*j}LYjwKVz9nbdj>tQ>YO=0P*$#0FO5Sp z54hjxkereb4ze2J@*%FUZj0N~YKl2|_>G|f)kFnKD~QSAAp!DpO-=DH3_4bM5{>uk zGCY;^&xwmX=>;+aa?6vqmr1=FkMk|}cj*j3Rx~LO5j&d*_y}*J?kW(9c2s0BI8F4jjM_21& zQCG&n4kQEmf!=gTT17lE{z@1I1pArI^?i@XKcOvd$UPGmjnJ?6W_!89tx8o57wt`o%jroNjWb0in8`U-y~&2_wSt z19+@8jT=VqJ0_78j+J@-ivDr^MeE;Bz8pV@*RpQoF+H^tP15=_N89vxi;7~HuPJx< zvDO`FrUm`d5CxG^r%Yo*vSQ~VnArs!ll?JxNl-JTXq18S)x471u(p0l=AQ90FmjEh zA>F}?)=d`aCOwc z&lK`kMNf2aE7FrXDrvYFO-b(Xwsd-y6J?uh90WXHD|yj3xlAzEV=uz8`Sln-PiJCU2F=Kep>KO-9)B$ zm}-_6JHuFT+rT3UsnjzOupOGeQTe(w6U!nqp9Mxpb++!HG`soZqz~`H zN7X?^)-72Hn`<<=i_BG0V4|qw(z_nU^t+@t*i>`lr#`o<;Ra-8&(=HFM<>*M77L=A{GOq~;Skg7qZgjR z*k#u6Dq`xVOW;esluz_RzKo3ohRc{lU;!(C#zlGN&`>T%@G!(|al(+jS(DGF!jWiA z#1HzWDq?4lkUye3_I%=s~w#R?L-Ew8=7-N zTGs#{jV2UO$6WiiL;I@nWB0{jnt-;JxkaswiAPyGfcd&4ZdzJ%;E|)Y5(T@~_jM|K z`+syb)tT&=nHXKawcvktw3B#YJ^6*}J542NTLcEkiRf@kdXnG1MUlno4WMzi1^+;# z&`$;=A81JK2Ewb(d7@DMBSBRnoA%P>03=VL7kE2gg&|G&#~q%VFR-1Pw)QSKRWCse ztItU@@;SVDT+ct`xa{)@d6lhyqrXOd@>=8(Xf};95~Ent(U^R%kn_EfSvx8ag+j9S;g7GhMB-1ZcSYoZuR{bm30zP33}TR+!O z$^2}bb4U{4ra+;WT*f>JD9{k2C1mw4+cZ%SE?w|)=`yDlGmC`{j$W(RU5|Az&M<15 z`GznwRdIgs=E+W(q1x3f;#e9wV?1&QB30Bdc7LnXoVlZ)D_jtv;fuDSh#(D|%>L@{ zYMWX;yTpc8Yq3m0j}^SP-bpQ0i8c?By!w~ztV-!y;L6M?-izAoa-pHwCNilXK-72^#EB4&z1iWBiGC>geG-X0adOm z^(S|#tgqhA@0&CF=^c>6C#_PO$y-0j8k6+vP_Rb z(dxavgo>S2$G&2;bXZaf9hPKD&y**t1C`l~oc7MK$=X?IRiDx)Dmo_v2RQ5m)zssFw#JC@75*#nuHg99qyyN(}*;N1I!X^ zf5a0k1Lx@GL}pb;7g&I;y0)f{#JoOz75f`kJlnx@7Bcz{rkp6_B>hE-Y@_=69?zSw z`tmm-u<+I_6yfiyLC}R5EX}Od{i$f0KCYW)=)^c01;;-O6Zv@Qnfbr_BOQhuP zb;}j_>n+p8B-_yKI;{71+tFO^Vt%OVZYK;N+sZ3Eas&aY7mnixX~&xgvfR>|QS^!Y zBDNZR?ymeP>9-7Rw*H%SF(<75A6zrTz{tqAoG|pVC5wz<6MLX_8^~!{m!F6zmd1|W zBho6#K_}jYujzPpXVY@6ja1!Kn{4zS1#zB#>s02WBBd_~ zuGU`(wk?(sjqS9}(pHg9=^!t2zs0$wG8mL__4bnX%H)$J`_VJ-O|wY`?_9ghPI4g3 z8!hG!B?<%aT?OIR*z!))E{KhpAkm^VjySmh5E5|Bu4X>P(T7!|0y3ZoTHMR#Z^G^3 zKF(MXw|{n1U+lRF9i;{PVGC3dj-q2x4Db=*>2?1eO8v2~uhz8PtS}Bo2Ihu!0%mbO z3-W;6{4HB-y&bTdinoTai79$qX6iQRge<5yPP2QndbqzKL}y+4eFCYOi{rzu8mmRwz#*?oSZ^PIAjg z7wiHgmf}!K*rrU!HNKw!wp;&u0LDAy$nx`H4;b)bINu7D_-8(b)1nIHnzAD?WDi?> z2&L9dCH?!^8qTmWUy4)knfO0AlA3r|ltrW37L?jh*x%b0D|3IClArcpW*S2)J2Hb>bi^^Kxd~N814%$K-Z5WqoZcbCkZLB&TX9b>F+LeJ_Byl~o)70($-AZYOxol_#1j9k~8 z7y>}r+p~ViaGcWOEaZ8{P*iGZ z6<0)l6BX*keGMMD#em<@{WJNQLdriF>x49>N!HsT6U*f~sYHfaE8vckt5x)L>8!jy zTotTN(39gxNLC;t%D(_sT9A8Ax_P_!8j~j7K=I0aooLfZlGK(KrBk*#L}UYAV<$&?U|`pW7WYfb7+fjU^J zJTk!*JISxvaGNXqHo@Y$itd6+Z~jt8RE$-i0cg9M>39=OtgX5F!++aPCvL@<%RmZR zeLYU`42G`lJM$E5aAEtRy{}MfVGL$R7($O5)apa$_!a4N%WSl!@zYE6wyeK|Uvbn}{%w5yYG?q;JTh2qI%L2YhOp-vXXk{U z%nAfa@(k?MI@DHyH-X2VI`s=Wy6vtaQquBPUp_W};nMi>k4;sl^h;S>*}8G00Hs;w zAYTBeSm}_P1AB69ZvtN_e;&y(m8ybuq}f? z+*ugK|BX6>~`)6THxVxW|`-`>ULnYt}p~A*KYjS$JH`{LoI{8Z-$9=G% z!9VE)W3uS{xnnjlooU1v!678I77lOe#=Ponlfhp+2W8(&8lpaIIq+XvvL8>QyiW_( zM1;^+I9rQBX>9Bga0GP{JEGlJgFA?>CuJV0(ig1dF>`s5wB&q1-qf*4(pHi?$>M_4 z=(%y-#H|hO^Q?!>F9wn{av!&IQ@Dzd4?_O!CV9}yINQ&S5xRRG$x3HD9IgPC)qjZ( zblEU0r!K{?NGx7}svVu1kJ*aYX@3)PBIH3#&AdI=V1V41Iy{wv^GpX87m;KD-%|C| zFFnu)xZ`O-5r6GK-EY0K44oiF=0r9bj*^UXZY4lNVw*MGRgl>hY&4Ek;hJ;Ex;AP? zSIsS4kV0Z$iyv6J>eon~8zs(|kQ(`T*b4Q%xHnQ1kZHz4vDmER8>vZOK1g7HZBp|m zkDDO0W#9DW$+5L0qGw1KUtAwe?2AOoD}QPT-{Li%8WLVmiVS03%Jxp$sok=(*6iQ~ zSWqX0gaw{#MrE9M)bqIeZWVn{r(#Pq_~&Mn9Cb71ggQu85cJK zH4t2trC5?HqiC~y4mVeosYAnMDl#C@{GN@Wvn8=q!B|$UzQK_)tItF;ckxLJc;X(I zgoBayyQaI7hP?~tWgx-Qs#|^!+9VQgg)t#ZW(&4W8Gb+Tw5_t9U!9YA7V1$WT`u?C3T8`_ArpJC*HB@S z!Ce9bcb7(jYva~f@Zc`NgF|q4*G7Xw)3^oc#$CSKcks{d_#f1&QBA7WI(5$8`+c5b zISCK$0N6wh$n7mf61Zv)Bs8KHK6ySjXio3bctDN$I?2x;NS}4M!yH3*LDcQIkJUlm z@zNylp>XFbNr-O?l6cznL2jv!`(Pk>e1L#r92@;FXh4D*8ZKNP2p#XD?9MKQkCqtt zwN>k>U=nfcNFT^ya{3j@oqq&T4@baenx%o*eM>cz&HQu2e+>#grd@99kA3M%41BWO z()sLGNe>?L;b9$T*bgtWe(W~gxHSp;^1Y>{aRPhtQb=W~+T&?X&Pg&Q2S@pFem|XE z_)Ilu!=9K}3le3S2XH|e6;b_5OmmK2R;_T0oBchrA`COJ z4;-pr6RCbZ%h5H7{)fb@l(e4*_-QA4bl8z%hwg--E`E;wCwl)IS$Q0+Bx-n}Ar+(? z!CCWMmlQAciDb~C?!?gB5cJxQ4)&@;^I99<R}XnhQS(bTeT->04i;pl9-L3oZ_z+sqHXDj z*jcip<)Fjp-rN^SMNTXu5%UdJbMPS^+%TfHX-nVPl6LlV=Ssnn!{$0P7kE!jipA-! zGoG~)uMHF}ge-|vh%UFpAKoS9r>z{4zrPb{J7lIjeyN4f&L1>)vs-Rw!WN6y>H3qs zl3w5-^b}~;(7U-&yElwbu=7X$R<@G3hJ?(d1o9rIcu;l4`$i)bwtBvP!Bmm$y%|sD z_EUR?8qF^+g>xs`^>rPyumWZ7F&Fg)+*lyBN9fguhv$k3z6Avf@=>CjWXVi*QCMs4 z@ld)sI;sVqDntnY%GA9zUOH87<>qqv*=SP_3(a#-Ib$nq4)KdLV`(U^GoCCk_0JTy zIZ6+f|D#4)$KCPy_8>0?4m!J#+5(}Sq7>@VRid}cuCRV1*$N03x%Q(=z8T^ zof`KxhH*0I!&k>c^imNrb5*Ng1c*b}U!`Z`)aWfBL!)1a;e(%ft%?;|(@ua6t>5hr z(ZXIhqu4Bx1lNqvZk8&Y%#`@<*utFxNprfal}s8Y8=4-P1*NQB@<0vXC7qp4kiC@u z*xZ07-p0$uZR7U=J=7B_yeJ!^X^O}Gf|$5m`jzZHSQp+xT{=u|aZH82P7)8y&CwUuWYLVYPm7?2Kc* z66K!yX#F=7cPEJ-K4Oyg`!pR*uakJixAn$s1<~yFGP*yuwVr3F!#&iycx( z>}>F56rvR<4*a7=dL!yO!m2y>#=tvf!811+-CUA%9Nvf6J|X&bO;I$muiugd%}b?8 z*Ynkdmo$A-+&;>;4JDThN`Jl_GcRxx#?S9N6l?pFz*v>lwSSl+?M$b9F;Z1f$4#33 zYKR1a@XQ#^L5*cz;;@9p!en?c zSjXD!K}-?_UHmnT-KdgSbYHQ7}34{s2VIh^FIvzc{@4lchWRHOa&au7J4692mT zENA~a83boY(-}+zQE4Z6f6#67MLrppgtSjcW=NPK?WMZdbO)vu+$w_{%)Y2I;&8BRjY zU}f+6fD({NLY?Amw1?-Or)D5Gh87>!%Qejnf@I z?LO@LY(jo6bMWU3J)7iZh}$yz=gIzWipDxrB#|Y(Ab$bp?M;+n3NE9*WvuxoE!Y>T zJ3D?n;aw0#%3R@n9D8%`;6X>H0R-|{d&~@haMlxIPa{QWA>nVo)*KM%!{}t7gzCsC zDf8XVfrf^j;>Mck%wnm3uIRmfugd9vT_LRh9fih)%CJ10bb3s25yQOPtK64;4Z7Jgj~&}`qhsLgiN zr9F2<#-qU{vy+j*PEZ^Ho`zJV7ZMai(E}Q2sU4E?RKIQ4> z&dR-xNM^)g!Y{*udlzFry+kS31n#;;$;^pLBP{G_$g@+h3c%M4kcsfcK1QV!Qwxp$m`Mc3GI2qV?5o&K0Xp6eF?Jw>c1td%Ftz~BS^EF8a&xn56%r~_9MG=f^B+P;) zf>evMwp3*ET_TPr*4F8I>I_-tn4Fa8NUlbn7C#$Zod3R1GYq-fw3NtE%I34_^=fk8 zH$8D3d3RsKfbkKC^?~Q?|M`Odzu${M@5cz}B`PSpSyUGW+JIYlUnM?`O1${m4_N#w zMomQxDUSbHUQ*0?W`eR?lB^b0&2742msGQm>@&78NKr%akr=+6k&?2Rb$9%*W{}4B zCAQM(3w;+q19>BsO5H>B8YvP3eolyj==HE~yCTAhbD2QAFOWJ{M!AoOwVGDI9#N#3 zf70ebhxevM7jS#FBhK;zo13*gPIw#U(-~rA@)Sc8S#Cf#dnFo8feERzxom`=R1Au1 zfxSw;9*9JLgBU__EcE+5SxxST+U<#T?(O|}@?Wuz7yQf02=`{*Bo56j4cVbT;kI2D z{nitZvYC02K8kaGGQTJ3Qo-ACI|}v3yQ7?}Q`>4ngHM9jHoWH^%qD#M)PVvDHwxht zhmdIH=av4WrAA@3ydJSbzKS0YRgT2S8rn8&zBzmDA*?m` zYFiTt@1NNk8yBkCs&0@h6^K^%{AG=Q(b&DcF-q=tbItp}x;Ue;d{v&QQyLW;UxmSf z@?BuTyJn_FW$rcrC;LAnZMV^!9}aGTPZ{a2-`XGQTobA(;9^|ytjvb3y={N@6VyEL z;n*Sjm`LtToKMBOp=(D*-eETq_z)TIBA-$r#DRU)Dj#+MVZ$ZZP}VpELD%HfS4dYB z`m2iMvM9jM2^HFB#N^R&n_n=`Oa=Xa{C#EKyw@6h>>XTJJW*N%k{0wl5nSRD zxbZq(p`zds;8M05#T`E}*&9KewMAV%mUMy&EQh<*Q0ER`%*9_!u@2)%Chs00}u zkOSiy%-dQ1#Z)hu>sI815lXmg^)QnR`m*}#B9`pwa9cK<_-7!#-J?t%nD@k1gY95F zJ((NDD&c}6**$mx$M=RYI%cp(2bgd`h2v9Y8cA5LGc?{UjIovt5YJCpcFx=++1KBT z3k8`ey{XO+JMYO?9P19jC~N_&G6b7gsZ4IMrsPH|JoQ~%<{LskGsKVR7kzCEgr!U8 zwvFtL8tqx+ab1_rkmiguFgRu&%YNP3+j=EAGa@)P$X~p!)Gw{ab0x!z3TgPZ>q;N{ zqoMdiNP8{5@qMFGvqBfo_RR(3UL{K;l}D?Nh+C|B&$WWJeEjR(6*JJy!amylYxdYME+dWY)qui2mFlAN5MTghr-xsFr*FB z?5lHfBjNaZDvL2A_URB!OLgDwwz}QUMQf6p=hB;sKT+5+$5M-d!{dmCX;0yf6PD6; zb$RY>UUo^PBAHnXiCc8hNyQBgofmW9LxbYB9HB@ zn9R3Qye_HfM8KqPoaACYqpGjXsT{`Fc4t|0ek;l7)NS$xec_r|wQ!tM3b00WYi? zi%lsO-WC)aih!uZQMR>9D#6sNc6sqtzK*yQ$K7FT-t*_9veF*oI}tVXXQz9u3zU(L z(XcMeT@_}d3#TLot`jnCJr;)fuI+Y#WUo31`HRN)ccX8+8P~vdNyGwF?nFrk(+^&I zyJG4ex$+k8NB=`Yh2LA07(Dx5phuR?!W_-#OSEUVqQ1o^d!((t*&SaY?nMm|nhIP1 zaJ)_N9k^ipWbGnPt6!lDRXe}R3HYq}rwonNdsBL3o9Z)YiA?8#t+uokVZZx%b0fjf z!_{_QgrExGOW^c;Qt&g|s`!F8BNLc;=WyBW5nsFCJ)U2kl53au>K6DLEVZk$y)wHvc*~LRk_cuIWjB@ zp=~|?F=Wg(!*k5vdWL!>Wx;yu|KaWazZY3_!7*{n^OW20``2DADLX~=lrE;4 z1+UpPr@XRdQ@kDtAHVI*1ZwG~c~5pF{oIlWzSyew$s^@b1W;0F#sk4;=7r^0JJS~G zh^+6MKZUoafl1KcDRoFNzoun23Ia z%ZRjhns0xf zll-TO6tr7{E2?B=SA47?&34hBE45E=r68xn^;;xZr=I~oSy(R|A^a|I-!hgScm#&` z%{RwXFyw1w-F$eGV38TH5ETE;m|%i*WYWJKXa8h6Z?LfecrW|wMRu(2?)Am(0ZUg({mHzJ45tW) zrMetl#rlk|XN*33wYM=__IFQbAx2FhsOyOD_iHhC)%DldrEv~2h&A4zJ00=?p>wW0 z&F)_h(h7E>gV{X&(gjM~9LB^L%uJlgiFiZFg&Nnq>!Kp@xx0U|iC~774;d;1a&9BZ z`CPwjoHLSwKESKw6yuz}E;QA)vN|`5tH&RHEVfrNQy_ic8MK$|CcGPM7dpAP^>cbL znW!bz8UFlK-TnnfitD?X zGD@4=DDmsWxWVQ=7&$!>C-!U0_J#iLj>q%vkrgx_ja%oGA92{4SuHa$MS7imWxBW8 z=_NddP#!c^DwC1xTZB7*HFzf_YZa{T^u7=KH8m7vGBhtbr1&knKdx1+z77z zu3xJk7QcAaI=mU|YZ@;qQ-0q#*h7~$zoUFhvliC&#KzEBfcH=k7|`$9T8jR*K8I~y zg8zb;Zpge`W5kT`_-_Wc@v?RR4juT9kGH~tM7?Ngq5{x5gS%ex4fbp%0Nw~Q-8mFH z%Bo2}DUm@09Xgw2=%X!vY-YQLc4G*7BgXfU>AU@G!p%9bEboa}`VM5=YMoPI+RwC+Z7y)T^hO7HA!7pc?Rp#nmp(Ax8zl z&q03CyZ#P44memxA0>Z)%CakaHw^miJZd?80G7c;f`XcQvEFaHpwCkG-MeF+4qveD z@s<_mzE}b@+yf};X@es<=7k1j4@t()MUYLRw!Vb%=aF8F-!~4C!8T+4Wke$^dwZo> zM+j%~+AT#T;0w6VEF#Yfs_Cuu@bCB2LUC4VXsW6blRIZAo)u)EV%s)cAJ4X0>oye;n}Ui&_RvG{kgW=0jm6k8xw;z#vu-e%pwC{^-%L z8jCn2wPd{JM$}^GLrkgKxz=!!sUjpr!QQOZ=YSFK$eS&IdmB(b?Yhw;`I0NjS1!3j zsd%Oxy{2U>J|g%LAjtiv(!b3`-gYu5!sxB28(P4ct6AB)eieTU4nq`uqJKZ}&P%udA<+ry|F9RGH&9_{#r^qT zRKZiBTKsiB9rhp6TdCj?p*P)rnk^kqiuS_hT}hH6U_4NJRJN@KCiONc7(C3c&&)<2 z36;hO*C%zS8#zT0OhkZI0)IU_FrzVAoVc@f>~1ysi#7#F z==IihJ!vlqq*p&FZz%*O^<#z8v}QEc%Oe}}k^?G)-ipW#DP_;RwsW>5^j-hKL(Y}RVYN%Lt2 z+&3+VG3j>?6})_-d7NF*9`;n&7`Y zAwkfD_$>GCw;kux)!SznJ`VT76l`vj6eRIqMe19Fc=CFUOpd*m zHb^68JuxTv$@;s}(Y`yeZ;|TBxM0|hqS#1@Jyc`Hkum63HNgUJk13VScLEp{osAws zgpe8bTEBno6I~SIhx-a{Pz>r#1Qs>nDF8|mrgAO%#d+^TpX_}?m6xAI{E8ASIu@Bz zt5{K;F)nlYFZYDeMAJ#YBy>Hu^Ve$tN(LFAGu=w{q^`@TGtqD>OVOv_Zqa*AUIuwJk#V;?gq1h>~fgAxc)w@ z?F)I35G;CCq11;$tY1+1Pq*UH)wmz@-gNiN>BIJfY3K&ig>(3__IdbC+O+^jB?s-t zGjV@*qNM@<{+J4|=plu!&1ruH#ONL{oJY9;cj6Uuknc9A{-%dA)e|A*Dk77t{_QKp zM-t94F$XxgAJ>l><5l@7uJ+V5qht)JKLT`)%zLrrPphIgQ~nmaIIC|B0=ax*^zVVY z?5u;gcXcek_%LF{jV|heJGSSb*8?2Mvpmr7pPYXWuZ-IUW*4cAY>gjs<@uqS8!v$; zd5Z{YkuZ8tQ%p>DWoI|QaJ6Sf;ru#^5jI)=Zl&cik)YwZj6O(B>||?7ZP0}8qO5QWTIYlkNM*GUiiBGBBDr;noN$_{DHa^}6XP*88*A;%A!_gV)>r_S2{q*3_54>lf zK;&5;F_)5^P+L7u6p~J&eD?A?@drWXa+t~D1^Qrzb6gaf-5WjM zU(&mb-^T6yAo7u7Zb|PsJpAN$kIMZm zT4u596JoM@$4ij;B?;0&OE{L`J}?OYA)4|)VYg&EcysUGG{?>Nrp4UVz?o06@~cK1 zByWax=|x>bvqH=*E(B8CmJsGtg<{9dFnb89kZGYlD9ERemN8?o+SfaB*Nh=>w*-O*wxFWAPiv zY+OHp%NyCw{2Owf5W%?uVp6}i+Qz9x{{};59r~F@+(>udxb;H=%`QWJYV9|%Kg^5P zw(Muu70zXx$|lgv&?s4XW^WDf7*gn&+I$u8`w~-q=2l%p+Fr6W6KVD4Su$yd{MiCl z=#j?hyycWpxoUU>w;5rlZrGM_F_%?ypd+*Y*5A3VKKnb%Kaa5rUp?~)86bsY-PSMX7U zOaaYQ_#uayX`+bK;=!Q@H@#9@J;NSazaaRZh^u_Vl=F6@Gr=7lHS2g&9vCZ*lf6d) z%cf@jZ>^KCtKpF&V^0*(@w8oP4ne}i*J4ZVJ^xIKq*1N8){q9FV=*V~C3YuRGNza= zI8VcCM@f=fHeSP}d+^=(Fq2yz8p{cV$*P2hvXL7eL zlvJ~nY4@3_j#~SV1Dn=o@c^a|LALV}o)ooQZR zV`zM$gcU1c2A)?quNSsG^`pB8zsM=pwJfW+T>M*Bx61>zM)(y1gzB%DXg6&&Lhug+ckA9XRIp-$Qmgk`JLfgQJNj_{Szd1u zclIuYD|84qIi)_Q=%dFU1Q`>1A5fNUCFtcB14hjtMh(%2A0qSI`7Jf!_heTU%CJ|3 zug+$nji69P_8p=Nf=RZP>2Gyg+ajf1UCw1(Y4bKnFboK4kQ402XkNBc;tr+?|c-|9}21`r%Rc-HZgB!@}x`O2wM-zt!+ps`dM(qx1Xt zIfqra)Qp`YmcpCxv30uS2!0_!=j@cM&YrUTsHr+12bN|600cg2XW>L8Ca&c0ts|Nb zuj+2@4<;yxh81_r3rzli6(FpWD7r_0~s^_}VRKvU1lgZS+U{yC+>Eh(E(i)K=m`);j zl5$tSR?3=dz!*KM+R`z%tZi$w#s`j>^s!>ULQWYd(-gTKrjd8NzOwVZYaAkHI%0g8 zZF0P`4lX${~yGNqmK5*4paoO{XfpXg|+pR=w_$L)9*ZjMye~ zz~IbzV6@?>y0mXsV-H5bokyo!k4tK)>a#}M@M>qGM~s@LDa8}ZY?Tr8$IoAe%v`5m zr}9J=%N^O}B5l$sMP8XQhKgb^rdP~OWC`Maqg+uvoIyHl17|$$)QzCf-W1vp?Fc>d zByPA1IR1B1>pm3SLjLyTL!&eIV1Tm=g2&k`YDm2L+L)8nE|2=dZ@%O+yZmkZlHkMd zWd3{y)yJ@@*M`x%KzHQWzT(`<_4;YQ=&7#Dv$8yZg2&Y@NTw-?<)Hw{D0MYwWV8b5 zYQ)_bL2i&kwrXo^x7}BA2rAb*4WF60vIuTH7<=?A_oNhOwP};zYtFiaz_1!un1~or zkXSBF#U}9Nss&1iu1e!oFJH%(4d$6c07|#G?Z%fWSRisKo?ZJ8pDnH#U)|;ywM$rO z-amb#a29rTVQDZLh6Jo$2-dVqSOeQX(RG7D|IL)l{2?%4diWlm`c@vMj%3tA`U}rX z!0qkl21*G{9+O`*@i=_^6Amt3X`8K<4lnzp<`i$-`%5Mx?MJ^*_Rn3zY?L~?ZSXgD zhQCB96-$!5{dAGrC!t4^ES$2GJfc7!S)DtQFP_i+Ir*m0!mFxwsTXplLv6HiGdC9uE7B6)M>lt-01Y>2;)5uOXyY9JH%YS`g*3bXWTN~ zK4D|SRi88<%%ZJDmvKdQ*j#>5T*0Dk_W=8;DXvZ) zd`PG&LHCIaezeol-rQr2LBAs;Kv_zPWY$^Z=dRDRMquR>D$#s)_6%UPyY*$Pi*usa ziC(=<0`0eH*+IIdv%-_kPpOQ;& zzuUo>3Q+DuA3cC2EoAr360-VFA~Iogqf!Mur5v)^bo<%D+m*6pq_Fa!WCVi_T4@zx z`Lf@CS8Z2gN2xez6^5>}1iW7BytnCSTwsVCYjCt~w}Mupw(YUx=4^Z2FkBgcagELX zLuv$W_0FfBCKbj_EohExat3-u=svhU8>`AVs5ovy8m9JYa~XT#L>qXzR*nf9v3n!v zw36r>P5W6Z`lF&QP{1!5L%^3xLsCgt@*|@QD8*L;%YIWvTL50|a?kpqcXkk)LX<;xvz# z@V3(9jSJxJPyO3HplS};lon3@H!0K6-MI9<8;G?LCyQ{GkA?AW7d&ukM83mMCuJZ! zGUc%coJrUzU4T6KibFL#l0k*)gWqZDHTm~o=p@JI)hgLBW|*}A z%?Ld{cRjMP-Wi9xDen}U=ChXrP=@T-mV>@E-N53l0sm-=tl7xHgYV65wOLe(M*UTn zr0$ABQ-{RFcg z`Vg6buPRQce@R|#TPy@c+P>s)A`*x7-ld}zMv#%#&o(ZM+H-{;5XUzMt=B3v3VBs> z7M{-7Wi9ld@Edl;R|xCVT1@2wKFm%y#uX{9=Suc1GJ1$Gzu=o{8Tz?C5%ti3DmP8> z%3_qN7(gYW4`6Q4l>KQaY04>3<)1_lT%^U#=fvbEQKb3O8N&h}`NT*^9&s3miFIu8 zEn?Mlai0MFY&BYV48=y5Z(g8j?OwD>hPxt)MluxRJ({^E+;2Dq0@m9Z?*8B@K3%x- zK2DdpR5SL+MG>=!-;c^X2twM{&a@r(Abd5=k=H9Wu{2~Y1y?ffq4iN?-+%Qn(|n=1 zXv+&=rNSXRrgmyyXvXZUJo(uZg0AF%76-H(Srk($fVk|h#QVId^OyFSJE~;~D3VW} z-jd;U8K4JgIuW951(k{Ep#{iT9_P`t{M`cD|6A*~t^)6i<{8Zil33=`{1n=CMfbM< zQot_D)yZlYGR z?62)QoTbJ!WuhynSkrl0gk<~sM*7j#y=2|3y)Wm7wHBH;VsI;m^qMRYk+I^SBksxi zk>L$#&JfO({RsZ=E(I>8OAUCB=nG{IPf8+oPBpOyBuY{?kw{@utK;qq6n^H_hO3ct zBeu>>Kv}d;PD}~!buIl_Q*WeK_HYyz%}GdYLNID9H!|q7-{JnHPzoJW-~_PWMQ}yu zd9dbjT{sNS6#j!~8>&|EuG?GU8!9n3viGN_L;H^R{{CsoXP8 zO=H=kVn5wI;D`MYQ?~CvB{qhT=rSZiq*5GYca{4SMDSvpl76T~K!I;Mmpb3m(Fn}f zMXXY1Bw?kS$Rl`g-1n@yUnqi35Vo50OK{nn{qiIzU*C8x*)63c~<}y z0+Yxv*2aHG4oF=EAJC&YXS29S1CQGu)ZEn;#Q)N@ciZvmHw#&P1lxHs zr`d2UG6Nf9>wvwW$YT*5!QrmQXA|8dv5^vyO7^LLD=pdDS2U(=#V9$JDY03n2?GJF z$?_LdYCDTiQ>q$&?0{0cN9$B(`GbyzxW&?6*qio_d2&+3l)@<{7h+J>;^yX9#S730 zg>I?r6$b&hnG#GBo1g9cm34dd&_KfRfuoA|Vm}v@R*)uozJ&&T?#lBpkBc1@6@TGn;yA=-51{N!#9(ESdP&?p3pmYLmNxU^v#oaS z^+f8`iRRa*WKL#41I>&Q?0m9yP{tYWt+ zSGG}TWY?PB<2G5iH~QHYR-yyZ3-0<%i6gzq_m7#NNo-gbZ{R~PaveRLm`*YWd*k=_r)8mA((2~?y6ln#XW(FyU-hJVANhf2KQpS_ z!XZLq^X(~1TAI{V>cmsib}$hycaH`jU@ZTQ7a&u3S$Z}&jb%b_B_Ur-`(zm zUhTovA%`}3fcZ2b5B@nRC?_w`F{y^Np6MP-vCxvua>uyn2rEHsb9s6yDdgZ_DrO&f z>lT)q7(zs?7q_Myai~$RG=Yzlym6

Mr$5*p7n|PUY6sPh@o+MTa8Y*b$u$-up3yg5TKU-aa0I=5gWNsbT8doOB zQj|L?B$4K}`VpQRm97P`o<5O;&A;v ztZUT8f9(4mK38Sc!^Ob8It4GnOj)Irzg(iBu{QP9c*IgCir;(N({UPQ%ns7i1$ThQ zdKv7o54MB*Co}#_FAYipF;h9*Sqtk)#T&5l#hZlK;4Wkj;JR47o-R~?%#L*3NK}LUl2lZY$Wzi2U0(LxLw}D3xX)L>!D*A4FDzf3U%#B6j%^-*9gY z5rR-kS;`Yn;U6#z=dKoMa|1*09fQT%+5)S+h)(NC*uQu^?ousy1`R z?#MjzGKpXwAOA|qJ-`*;cI<0ipMJ@>z?^fe>#Lee*!iGGoWaDH8qa{dg4^zfVdP&# zvo}8jL7R+Nh1!{z9Pvqu(+3WH@IioU1fz;-=Be~gEfYHc9c$@rUx@Y`;pFM+a+%4T z$W!u{;6nprdu+mXBLoL{QET zYWsS${HM3RVH2W&F};p9+R28BiQvWhcpTBZUlq1;GB)lQtsQCan-pBE()kjT=y69R zx^TX`j`97lbhUHfICQYHabrxE7SxjfDdrH0V!_7*cL_sL(;NQPeQNWw)qfiX60Ky& z)Z8V#!lC($9%`7SO+2-eYXXSz<7>*>rmIUdB`scnEs1Uy?t)z&NEvcGnX<5Rr@Wuo zM}D8LuN%sFvN1BX;}N>(yVRrn}rqt$d?ov=P)?#Z2HI8#-vRe6AKv;* znY1*zS`jwycY=~sXbh~>xDL?|MCwCAZn^O;sQ zGkVmQ!}^};q>WIWHDE@1>53BC%-JmQxYtA_MN#=)%1wdD@A_Ftb9YU(a~Z=&1$TzE zsxzw;VqC?aJ_!@3d#&rJ=W+yDZp6f@RO{cuB9-@kou=tG#jm`I2kIF49kly+{4?2* zZEW30YQpvgVRCkGn7$QTec<$&7NpMg$g+nH+F&;iu#Gu&l{2@b7FLRQqM%Q{@1F71 z^vxjjcK5>a`UIDN3=UdtAg06x07a?9mm)a^_XvqMa}W!JD&=*4#H4F zyvBrtTy|~I3--S2efC;rQh?z(RLc)ZbtR4?C8PRB=#kL2dJ2IlJgSfAl)Cx+3xE#p z{CanP-{{di|E3ZI3sF8)bWd@pP)`&=Tr9K^glS9Ha0 zm3|;p^m961ez-NOQ?y|UyuKQIax5IGoDGe~760M{S>K9R5N+>g;+KAA*xL4f^eQz1 zWc$F04saTdr&tW%rQxhX1?~nA`7&|4f1nCj&DkmZ^!EaZ-LQ#lI%^XLW8n1t+3S>{ zvB_eM6B{3j_YZE>@``utY<0r>`Q8_35*}V>S#8Z`_BtUWw#G6=>q>TFeFk$DAuETj zY%ag^ekZ^C$8zlpd~L0kMC%^zUN~W8<1rfEXG!dAc_Y97bvtsDK2+Nh5Mx22I~#LYM8S5#F<$fT$b-nOY7|<#JGkYoBRQtQ1Mfy z;@IElso~+op6>cAr6m?3P6aFwxDNuyp+`g|yp&E>nsJ&~Y&G+lPr>xx3WZR%0Z89z zY23cT?VG#9p}N8BOwqT-JI3=9&3e?JJxcNDw*kl7@_Z{Gx|wU?3bE!gY%kvTY&fhOz->f|WqQt+A_p30`ZEee?Hsw-9IPZaBUiCS^L zDR6zGB6-+$TV3&U-Dr0?H?qH7Hq^~pJ7Lz|(yj_2|gZ{=ajWW1lk zfiIxkDaPKOOxf~vS9SP-%Nr%hsW&D`ekaXLbc%Izb4_VEL;=}hJ7%IpE2}79p>op( zD>uw_H^24xKYknBYhU1COhl8ideHf47N5803AaCO0NIf#F8}#`IOz>}tI9o<_tsAr z)fIz}gK6>VqV&q=P%r;UO~O2#-5#ff!#d-3~PzNy3}tm0OGz19qT< z=~GQB{hoWW%1L#t(KbnyxcMZWwZ<$|+8sTR1< z^p#u4Nqlk=4mZ4(aiF^0%mJd+&-z&R&rqJ2D-l2{1yT(nRvAF5RvORDYZtp4N&Nj* z?zbto`hV$0Svm0{r;(t2k9)pbzE@gJ$=w@d?~H6{9&!c|P1YOn+&>iA-}NGx;sxjQ z$gg_%^+T#eT+^&6EJI^o?7IggDc8GhZx29)41iJlE*6S6(>>AdeS42&OR`DZYMj!H z18sO=425{eXRqLsGwtfR@q=05tR#_55oH#2MU2YHGBxEkrnc)Ox5&3yF%0N}S; z{Ny+%qC~6SuU>}$MB0zCh)Es_Rr=`wXGIr8-l1Y`hf;hJ+{1GP&-ivW?>lqW3>1?L zekh_Gb^1YtCOh}eie)B4aDO?ss8+T6KO|v}jbPFyX)6)q)d{|-*mU>e1gyl?Ns_mH zG`nf^sMOLkzO%?){$=m7p)Z90HhrK1=W~=5Z+`>lsQ;_hg=f$Cx0T?%>!`Kbw z`g81^T|>yS$YP@pXY$gE5`Of1okVB(sUP}&6uGVe(&Y`nqEb-d?V11L8AQke?~{6kys)s*j(-dFBMuq z<~;wy+gk>;^@eSnp?I-EaW77BcPLP-fg&yL-rx{iix!svfuhCTCAho01cFP8OR*yV z&HK*o?0(o!`(ZQlWF}`OGdU-7&htF?ef_Sh-FpnFNyAL|vZDQOc=^CS=(VwG-byK| zMeNzS+}0y_@~bqH>w%C|4r%41LU+$r;9I2x3_D%?Q|5`b*l~&L5KBvPM#-)4ks6(9 zx*k&GM1BEeS%kBiC1gQ0yr;Vj&Nz&K&%4rI-+%jYhT_njZJr}d@p_T;Q>}Ch7TOy{ z*(0|6@=fF7+u~I@p0j zZaL2iuv&yaa422|#XJFvm3AxIvvv9v7M<0me^mP4hEBk?&GBP9gi(btHwd7Iue-JW zs7c&A4W1SHI8l;-Xp%upu{ja}9MxS!?!QV{TQ8~khSH5TsZ4R?V)IUJ+I7@K3V_od z`!(7D$Y0t@(DItCT4LaZixPK6e-(6f1TP%ZH&-DcW!^n-^BI;R(R{^}V?LC|*##eKOM^1ct+P<56&_y4QSM z6dE_C`WXGF5xs8-BBZcXo5)P(-a+}zk3HnVp+Do=43mtli7MOqGgb6Spnx1%x@9ZQ zzCo-xW@l&2!1KS$Qee{0>d}4rpTGV88diq(I=Uu2i-I4ob^i5<7N&@A>sz6fec3## z{TIDl!+Ozi3Vu}ez6Vm*O`{j(7$^*BhqZt8d|#v&LF1LQsOCFpuR~qM*t0#cp%10> z$Y?768vQqHJ@6R``c)?Q|G#s||8K1F|Mz3;*nJRi&xru=|2`|??*QaW9OeH!#K^0+ zn(%?&zW=WVEJxH!v=b-$!iVUli7UTME^={CG~SWB|fai2K3&mPIp*L?f9_Yjl7$r(#lo@yo&wyY*8SXhln z__4z+*=sGDVD@LK@YFMpjDttuk)=KemeII~&>eHUD|f*I#7tXP}qtV!v?4?2yV3 za8YLNck&E1B~oHI71-!id1|O#KPxHZQ(^a|s57-vQKir_9`IXAxj?FKshCX}G+iHPv6wKJ<$+O2$%d6tT~3mhJ5MtEC-` zx%Dm_Xm|$Zb9>^3i2n9XsIu@*(@a*p52&?s{ZialSE5@OI<#!R7dTl#Q2Y;)1 zp`8p0#F$IdUZ{4+8Y~-sD=9pG_P$iZe{dPCmL9;XauTSw;P@id2>n-rbe-5{Z-gyo zP{nlW*%^%mTL1&7_jOeIGV+`67rOONV= zO@EzG`@-h03cEMHIM~!qQxT7wfMA`TQl6U0mFs$1n`s+@9+a4J9g?c~Ga4;vRv%!q zN1?Yq5gt)@0fjl$x6S8g0YRfVWeK^g(%Ifm6>*msosQcGqJw|?%64l3N zPmahlIppb7%Z=IFv^bTyd5n?#=u>C4QRh*A&bsa;g^GQv%s7FO27=+=0j{ zpLoehS*f0E$*>3UoeN7fbE*Xyp|j1m0&5D8*Zc2)y+Dt1WG4um;8` zsE(Hmq}@v*F0+>5mOrC**YeX%d-9mGy2L!G+lgbbmw5hkWfT7`uladxm3&VhZNrRQ zH`clqU(XD`wMH>TY5~qac>$?`E|ri}7BF=h)NSR~3B`r~I4Kg^&mL3qhF8wp^EinB z0U*h`tiM`sXgWiZO|2BT2GUT9=AEioe-_3oJ1yV2@mxG@rM_$F?HP7GzG6KoajjUp z2M%R$HWa$BbPMgNnq#R|UIkU8D&jwn9Xg|(?NaN`Z@%dOBjc&J7l)%tniqu9w+3D< zf0k!#@8Vr~EGQlF7CYkb`3bZsQHFY}&B>>@LXQ}(`# zX^B>&8r+XwI`5`dHOE~X%U$w>N^-eY<{KRg^I~M95&Seai|-Xls#_q8Z<_fXR3F&b zkgYx>KDTBP6Xm?$J%@B{R}PaPq&BohmrJ^<8`901%X&NKOKVHyn!_R1uia~PuVkRr zb^vK4`FGr%Ccl#{&SkOL4_81G&Vc6sT*>5?DtOO6N4){NVy0bxGGx~GnX><#Ex+qL z#6$M2*@SGSgSiZ7UuvvCn_Ka_SwN6~`1Ki|;Ocb7o|!GJNf70~@elXdTT&SC$)MW3 zCEGZ-Rr?Z?P8yhI14R9v$fvIwv&eU_JNxx#i{`d@XYS=uL;Ejv1}@!K!}$q1iNP(t zU)wZdIh&-ZLOO`1YYE*dVs0gu+CrWF0|aIS^~y*)KcVdKpuJ4Nmm@p0{YrZ)j}7{a z|Gdz>%ovuLql}&L)8o;!9i}kF^<%WltfnhnJZ^Qh?npcnP50^Ok`;r52u{In%OLzM zRo8fnmcgklzH!KzUo#_!rJL?UZWd)v&-y27td+F|;O-pZz zT5|@zag`#B4SUfD$@78peT-eN+Y>qp|01%q@tO(SkpPK@GZnVT3DX+{jTc=T`CYjX zV=9Rdhs2>Xzj@c(&IbM-MAZ)8b%=l0ti#U4;0o+^qZ6<4@`*)mEIJmf>bXm0j zun@of`zlP#z6-{3iIG|89jfR^UEu;L8)Y&?p%2M3JQrbPIs~0@WJdJ&lXmfS zsQ9xMtc|&E3QHU#NO_qp*7TFT#gdfd#2=T!=kV0E7aSd|b2hMs(@6T1i?*D1f1quZ z-_q~>TM)SlXxEM3SlaGYh)0~-;!fknth0-)-MPm9(?{sn~S?jNa7e1 z>KCB!uCp!NrY#b{B-_ID3EWDxK$q5KZ`wbvX3di6@-KXmKPZyq4q5T0Kku}OHNC_5$(#kr zjeeQOe;joU-fQn+?csD}8P%(CD4DBESSqFp!50%8M`$S_AKR_h^v%&8wzQzDNW@j4 zCAkCbXTJrQ?;4HCYBuH7(#DP9BwWw>^S=ac}?)Q!MMgNC&4K0)5iNVXHrw? zB`-W`*R3}*({Dx--*``pox_`6`U?<)m`T9l{ z=OiiXuMNk-9o&1^uBWj*p5jceY3w;;ugz5HomDh{pstQsQj`hSpYJXT-{5xkK>-2O z!dJ#EEpJtXM&QPMXZ)_SAs1h|9drbe8kBe{?BPW>sROrVQu~=>j6ea}xhW-tRH7{= z(+x?1$WPZ|$BrDFFWEJ(KYeCqPgu`-8m1<4LB{UtwB$^!eeNdR0M#dUq`kiKv8xm7 z3n6$d-SM~xcCbb}3@>9{|-r=q#$h4KbCr!^m|7 z4=DETlgylYXR|xO25!9D?cUcgLj0}=Eo%S+0#FC(Ib6)IO^)$`-#7S|OYn+Ghv|@( z_;cB|FH#(Ial8+^A|Aaa*=~N`k#3sam@rhwv6YNdaUD=&#``kx`oqDC!}xbj32EO@^o3@1>ww1d!GGT%~RtFJCIZ zw_vi;*nd3>5Ro_mH>Z)3N&A7I!WTel1>(u{?F?RC9iH3e3a?3H(#zrEIBAgOVzdD# zzcM)m-NDF86{L_>}u_qyB>9sUu6w>F0*@$iU#cAa{Iz z2_28-Oh5G7JadO;9WA5Mq+$@hs&%&~4qa=m!LbLM!M|;C2zLni*}D|Lwen}a+MHDy z?@Bg0^{&~1`N00N^^K7Y$FYtz10|(irro=k+_tv~MvLN}A6tu~*({QEe`q%w#=M!! z^Z+4LJ^##9ey|D|F5SJTxHkI8V*&k#^r2^oUV z4LTI2O-6Xg6E77YSr8(X&)W~ui=Q?wojK1w{x~JQBO=$)H^0i*PJ7WWCEvT7va@8i zBt47ypyUW3VyR*HI6GuOieeQU<%S}|pGtmsJ?Yj~A=T(?OVa@{%B*w6g>d+UdpRI8 z+Hga!sbei*H_RD}aGu(Ymp`4=oQ=GVw)i-9`qLgr1*50xqn5` zvK3CMk@t@M@H@Df!LR1B?r^TTx^digA-pGIbr+st$(iDUDB0%HMHdDjO&7C3pTXnfQFx&8RlS7|4 z>C2C-tfSzAd#WC;+gR`GR>{54teQ_(1S``$q=`?0X#+LI z*<9z`*EECu``ojMc@YXP+w|Ms@O~+Lj<~TKVhKbpd#E0o9mWf=Sx)h5Euj z3j+M8GumCH`VPb46u~>?ZpmNNoZr;RnR4Yv51QN&EE_Mqh24*89WzI`bzHG(xH0du z>de#ucQWpGLS0M^F1Jfpyp3;pQf(@?eqd(*=B4_!2VSnW`@5_u?_o7HZ&Jzk0LFGP z&f`dom6hSRWer}ZJP*^74k_{ynDY18;=%GRP70{o za;R7s18L41mRY0@!hX85tf##2qW#z}f6`pvN^YT0=kK{EnaXtZjMZo1(ha5jjkXQ$ zBaiBB6iV+4M+pIYsW&Z3zsH>>v?+d&QYq{DvGE8~t|`mBI2Z$ZTSD3L6ZH*Y z5R&Q5B%sT_1pZ>WrDr^suxL}<2ce_&Y34a(Aw@pXVj3;yIIg7A!=PdkMNQ=7dcA3c z!2b3)h+p*1!$NjLU^92DHe(25dGAp&V{jqq)v+z>**5)UllmrY%M>3x>_h^T*Msmr z?`aOABnWeAGJIDN6%98)hBjYKZSoEL^8dxHYnMezBha|4PAvnc9IaEHHID~r?Htfw zD_RA0lmsbAx9j1r)I@n8CioZ%EQT`%IVDU2H(`nR5sD4*Z%=x zO!H#U1O`h7i!x8~=O%4exgHw$^TXFI0Pgg>04S@FHunt>7@%g*2frS;BPvO?6)=An zXK3%_ysi5<2AHn454q3Vk-7iyLSxqqr7Sai*4}NLZPZU}U{Fa(90?_Vt>W>nQy?RB z`}KYP@D^>FPt}p8J&_!<{yX|{WVv~4WbR5O3Kj2rR;;dI3UyW4amOZp9S%XqMzfTF z{uj%V@oawh0S=^;D}+LrpIU%TGbGT$H8+Jz!oi**=k_D%(rxjVGG&qs<#qEyfGv9K zNMDXOLu2KMbu^Bjy-$-G+ob!vd=Jk4R<3B-(0pT3yg&|Emz2X^-*(}IK0K_xQJ0U( zlBV(6lEM0H-9tXR>t+@s-%C9Hky`F2Lw#dcv!OR@i~}DCb9A6f zY|!@*&m8=tqso(~@fg81M`tsbQ#;gnhqvr13@4OaYLqqSCKa{Ezam_}hUxn#$$rJz z!0|h{5z-lG+m9BU@vV1~*~S{ai4!NgHFL(@HQ)0xn<3vkY~$mD$&df~rz>PdGrnn2 zZ)H_2&(K(LnXD~tjcIn6F%9aavmXyQ?#HzR;4X^lp1{bO2j@RE=WOeUZQ#XFgZU^k zDgrIPv)g^EMj=-|-OB&-;RiS;;BwHyXo%}c#fw_?fWqeI4M}q>&#Gn`_!MtSF96wT zwYhdOFf2W@?11h%C?2tb(CjHsQ6!#sH>L1oncK&!DE6+-Za^!84sq|+vFLoJ)rx#1 z-FK^O`M)fTG|q7ri~9smPQ_4HUmEV-)#rzXX$5L~a-x`zpl00^+leG2j%rOO(I~TT z#ziyO-f2IIv&aF#FuM_@bpY;lPHIIZ=++Gc3=n#rtQxG$3u_+FbRrH98^CZA-=ikN z0MC_e=quperdiW0%o%5<$_iRxhJ4^VpvDzeLRXf_6(W5vpn6bON=Jv?dG67;D_2$qpFdi z3gOR*!pMkKYMPx7%H*OaD`HiPwF|qK8TPt4$goi#`niFlJ_+j)ekEb-4HY`3pX4u& zu(%tXKP&3Y1;$3AIU9S}s4D*fqz;B(6DVLt(3HvHNvU+k8UoAmJeCx*(aJ5jBneNw z(&_tp_v^?l5u?ZJI?UscfFI z4@;Tbgnd1Q3OE&<_n`U=jUiLYRU0!Ov?fK=grIAEiB+SR5txMHW$H)(#C>Wr8qfb*R|J?SJ&eSPZ`EI3ZI)OL)C?1 zK8{&KT=+@f#bV%OBj*QS>%ocZUPqQ9lEu^2YlEYIb2AJNc0N8-X;c9+oH}^N?iS@> z$Ff6V{v*;1>+HCd)_C+wGm_O!PTDrj_C{zcvwkpXQlEbNbyAI zy)0$q8;q7KcnIy1e>IQV1uMIJUL0{OC?h{;z2tBd&lMS1`Y_g?05sd3Xz4|_eitYQ>MO@Vg4Wo-6{7nLw=8t zs*?F_ySt=kD_h^!!X7Gv`_)GB*_YS3y-`1HThUCkX*?k+usE+rcpo0vEyTQM;aD!vNunZoDG={(LQ(d^5Ho?L?cKjx{hJ*g&ZG#KmZ z&vnpkm)5X0#sw3>&b``8nL@Ia=yHn!6t*3u+?_Gytqax7B|llk+jD4GL3Ie4Ubpn< zDDI7#1Z)MpI_-A+@}&VojL9&ef#T}+?1$S3x!F7OL}W4ckI7)kp#RmlOB$t6=fZ2p zQ}bvG%Xkb2hUU4Vl^nfSg}zJPcH&^5`aNrK($=EMCs>C?b{nE|Z!=)-Nkp`U>`8FG z!>q2eDYi|qtA5N>J6uQEsTP$ii~0?9T&ci9)?tyiR9De%LfDIRJp7+XBL!k#pbpj& z)nySW{hKOM3Pp!b#MM;Gz}t6ML(N_}MyI_2hTP&ta?hfUS?i9(7NDjt_LyyC5pEPM zy#-#9eLt(J*_vwt`ka{{ss1)|!H)%_2fWhymWjN)vaD#=24mQr1YT6BT2(4VR1ZPD zzh$?(sX#CTj-w3Mc%0I+IgWJh$cb-yHp1FNOWFi5Cy_*sj?6FZeEk9w^=nZZpgt=V zdag$pYQd>#2jA850K7VQ=R6{#A2Eu)C#Ob=C2DV_!DHZXJo3o_dwpSaEn|r6?&=%3(>SL0IC^RMzUJ6qOl1a zzU_2QioK94E;*e2lT%kTsC3dPKuV0Y-1iN_K=q$ZUdeh{H2jFS4I)pOe#T&?QTglp zYY2wGJYAeWXvY-SJ_y&NQ)Ixv=(zOWPm4gRk%gU9!lHqgcPefyuII$UWebDamd>+6 zYTPh$r17`(9FvC#8HRG-E4hhh0*a9@NjZy2G7%P+3O{az)$s*La?@$NB+nBv;%k{zjHI-NmL1U z9IR-xn(#c*`T4v<3cx$gDMz6u{9|fvaFl3rZ*%@7+Avd!8wUWl9*6(5XvKTu>hgwq zq$0b8rvIy!BSLC+du9+w@G`A=&3w_-Y)n@Y*aedozt}-|r`>jP@BdOi1#ug&rP;15 z>NgKz)A6HAe3+g9)U-M^t~lYf8x{I;#TY)Mjl}|4FeIDI0yX?z(raS6$k##Qwgb~| zj^W{mIRi;EIe59n(eJbMiC^ph2;T{I?=<6DhwkNY{{@~pa7O3OSorj{*CEM?X(Io8?1G45PL_D z%4~o z4q&>3aP%}q37u2fAp=F)3XJT|!5(dR;;*iT9XoqgenCple7Hu)B`rEB?|OuD2<~-3 zrJH>@Hoy7=<3XPUnLcTMXQU#gj_W^n`K;hJO~%ghr=lpp7sGlWXVL)TY^d*$1MkYb zGf^))phOd&$}KIr`_cH=KB>5~HO_*^IpZ0-{HXanIclrW=_Z;({(K;keI$^M+Z<+Z4>ibY|s0(TDx!i^^r6Jr9>PmhuKN1Hof_CDYeszdP_vS0@RVqqUeO+%G`sMSn(v-*OAIZ7N z@Wt@<*1eBykdH^{hS3q3Kvi{-mn)mX`rKY0))tA&mF#OYn;9LUy=w~l16NgOpNyR_Af zbT?|sZ2#yd@tc>n=ab)#HBNuCrLiW^2OOLK_us zI<8v~fOqIEG%}%UP5K2qJs&+bUljdEvOUTo9#7{cd~QFTs9+C{_)1$s^Une@nP_Y@ z{7S_mhh11Wfmo;qa4%ClJoRkhQ6V}$21;KR7))tuF z0I$(`q!AA@Ky;-rh`hpPaIe-lpo$zm;MGX)^Qpno4j}M2<=3p#B>WdIDi%5q?}|HI zm#F(OwMjdJN{iu#{@WFvm0t4DK7D*F$hzZtllihvi^D(^LS zL9|!C4m7X_<#P1^uCL!dv6AG`KYsO1&tUzE8{^?W(!P`US3ydDE%t^Q_n_W@uZE$h zCe_+f(u>))J#IU$+U#c--^6K(g0?6o+Tl0AVUYnWn&b3q<<)?R*rp|CyEa7xcB<^I z)Q{_5{m#rkVHivLR_~*P%2PqsA0J0TscX7GON55;NL+^>p4&3cnl5cyh?x%;b6^e z2q9io-(V|6h*^i_*|xgDOoAFPTjW{nX}=N6l5dDvMUQ)@-P=O>IAbA=2Zj_22@LR-KvIv*q;-l+)g z-DxBmlR#4E{esGqWUB=&X&mgXi%Q1nXTw4&*!*#o!dK&#uFUfkBN96w3>Fdbcl=&d zN@E1ni$9`yGBuQ)_H!iP?pHe^F5~J-CE_>s86Hh>qopsZ44;%c(+XG z={ZJ#tY1TJN;TwF6#4p&)``Ooaa0^pI3y|C{{a?BzFe~-?avG6Yn&=Q9=7JI|Begb z*v!3i-sgx&Naa*iW?U0HS8u3mXqs_kuKP+ElvN3VZU`se0pCIdhQuG|H3S^jYhlTz z$gcgXlXjviYKYtht{Qdt(Hp1EjfBH^-tzVc0}JR$FE8-Or9D94cIMUb52#N27g7& ztV8!prTY(nXjQf)lekK!DBIW3ViYgjfZ<&vqf(IMuYkt)enY~b;FIILdtDD%ArW1N zy4cB!mLRG~5yHCt~LTUT;Qwc{9u-b*bm zC4u-INj>lC%;iEOFod?1Pn2j|s|bYYVAIa7)^9*r@OB^7sWoX!&T?KN`IT3gWr9k@ zBe@pwdR9^Ui66PIDy`x$PRE~n{NkGmH5RIy_<6R&iH>##)JhArhMdy*Y@z|Kc~jlFH9OPH6Z2t$xAmm_DX|~-W=cUgILMfj|ppenxr;k=`A&h zA(D4V#cN_|5)j>CR*p?Znq#Nq&#ldn4UV9Cl}?;VB6BBfR%y>I-?Inh)8&kTt42TX zL*c=FGF;Y2$*Z73PL8WOBiyZ=)#<#7Dpx?nj8svr2rt`XrT3I3%tI5lFVVIjWXAH- z0MB+hy{s{6a&X|=W29CK{Oe!m!1U7`ySeqLHtT*yeZ)HECMDc<+KMXsoC?!Ip;4xNYLu)2W`kzgW$)Rq{`0T#Y@wzCwQ6@~3tngF zne~GY+O5Nqb=DuRVnMzS7se0OS8`;8$^wb~GJJmzC3X4?)|7-!pr+rD${{HE5c0sYFP5!BYz zjx4I=iEUer^}aAnXN&i#5+}&Wp$27G#jV(=Ug7n2O9;Qq>Sp*2`GecKZIk`l`r*kr z?BpL}ji~~??ZE-?d!j!@<|M@4R(ZZDbJ7Vo{EOr2=4x7e+kxsf^ z6IFjthObIwojDK^rLE1u(<$@jArV6^q2;0L!4H}~Z|p}MPXTdOIqHpuZQJ?_PS%X~ zpMAMq>=qmEU{MaxWf4!W#4*+H&5IG#0e3e0DSrWGhpm-+Cq}d(f7<*#4dPPc1~ga_ z&>QR2ZQi6M{Rar1l6FojFYUcyX|#GYu8unR05MAUQEXAG$BI6|C6mcJ+{kaq_D6^hyi!&3ZFvkrbiDX4Thq3FmaP#hGC`Ef9xV=O+J!X1oJ+_Ho8$F^VY_DerP93<)*N zp44ccb6089f)?F=V%k9@ti5{=0SmKw>lRZ8uBEdx`x>cO3SPySg)=5gsnFMp9OSLd zD$cI#!Dp-+I|9uznSr|VU|X-{D*H7WIJKssk|ZZm02i$D!DqyO|1C|_bf>0w6}O~Z zAAIRRH^x^|Z>%F;gbiSZj#_}oQMlQ?E*M`V z*@x9l8Wnxv1D_x3&Wn!7X2i7P5AN}fnasoN2y9N29^wSLgFgMQ4_72noOM4I;*tRL6@15~NtI(ku7s&w*XaUnGdfgc^H ztG^xwuZfkX_-MLhIMi~_D0A<@>cg2L%Y5o7gky!TyaBt(YYb3P!3R$BSHLnjrltdo zbRFHAX+T$!$jglnp6BPr6sfeY#snt10!knIzr8v)$@RkR|J8#=InU+j=*axkFwT_5 zPp-Wa)|y%u9K2Ff(+Q@81c6rc|J>I7;d|hr&euP)73Hm7XHdp8kv97wxfBj9P7uy; zJcu|rx_T?9^49z;kGioE-$moP@kVHhxiV>^YVsK|uI5zkvFR2?Ih++_N%Hr?Q6mwr?0p! ze%HD}-`-`AhgI#HP<2G;yfYql@M8UY8a+O5<}J7_DFUlom3;?QtV7AzzY@p9wdPs z7|G8wI*B=MrK$+$^ZiM5BiZD$Sl0goyt%C$%;1kuVa3}|jmvpA5xwa{;P7@z-B-K4 zV}X+8<0DH37rFYIFJM;c@KHw03zn=zs_7EAybqedz0MFmZV zZx}4nhRCR`vVn|?_Dx~|NK}4`A250huXj}O^X@}@x~svr(YIXr^!7W6IJXq0kf5}} zR1sRKRR~src9Jy(?!Y0g1ofS$Sf!C5PTCo3oE6&v`(eO18Y4wk>7JX5>vS<&QR zQFpZ1KY8iXG-CsW1+Ok6-g~)oCEe9_V$#iUg=r2_SL|U`Q-0wb1iX?PK7SkB{vE^h zkItUb+r}=3Q;HAy#5lpz8`DNFQW9TCs$%c>qF}^HXpx5R$hXQLZ5b1Mb=zKj8;7jw zDjB1va^N1A!;8Hqo82iyeTn5defpdvqP#+NN^4Tst#kynB<4V zMqUgyVqYi{Eb%Gu^{PdOEk~yUq?@F-_o28g&TU>U;JG}Q@>b|cEhkoODK@pYMrbV@ zb4-H3Ts@j4?qDL0q5Vu_0MdFo`sYt?7`D$`p$HIXl~aI$h{ns&LJN6{kEa=wu-nF0L7K zkdE11R~lR3`+-UKux=J)UMzw0McWv=bz^pa_c_g`VP}<}Qolks*&F+HB?(t+0CB0p3 z&WT}^4@WA0s}1EAI%Lbm5ypCJdVi)SMj-u6;P4lc_nQL}StzH*UjQRxzJ$?by@RXi zX08`QnzxPfFko@bLCwsyVVv;!ARQsm2bS8IO8~2^2|L z@nXsv1tytSf;NP^g7XOS>V1-oM!}t{(xoIfHBR7vLO8;_lZJ`Q1M{qbAQ zoAdd!3cgj9u7kzB)T#zTv1qIU5(>1jVMxO@N5R$|VUSc8AclDS|X^pR=JnQ6INMn$FJi`7~V z_wF8~EER4K2=_3j zG#SAuF(bu-7aXtgq;YAqt5b047=f4*9UnQ06mOtLF+v|6n8sN>>bB^Do=t6^bxqsV zeCE%c4qYJ&Rp3J2gcww<6xk#<^ zmyrEhBnx+gIGxvUI%R6ko!u@sx<2dT4&UmRL(MRK-ogt z3%Zv2&HqxWHOTkx|NoAH&i@5YE$$;U>B71B*J#G_-B6fnZ>p(2H0pKuHYlMGLbjD1 zi)y8BWg_3^7I{iDz@TSyb7+Q2v17ofG@ir~kos-#vw$8v@F#U3XH$ygl%lzE6DpDyDw9X_wsi)r`{p3z}`AKMuV%3!a+S&yFIB%HSYz`Aw7d;a3-* z@+?$-^S*!PD~RiN`sg^0RGudN4yYK3t10{Et$56d%|J79M4?_P_>b+dNx3hY?M#&A zyR`Cs_KrOs$8GK$Lq|5N*-^dXEvG8)NJX(&y!p{M=OY_aw)?-Qq!O{N*YT zyTFL!)n~rb*w;_j_xpaXJOkNobN|k!Hgyaq({$|)SrB?ahd21~l>jq-xfhRrnA;UA z9t3EA?p)H-CFQ{%vE()f6#Z;EIlnkX>#RK`^ghW<6-Dhj9E25JTs77lwg0VuT$XB8V`6w$?E37fof_GbP$lf*BC~DepZo(V0Y9v5tCjLPcvPWib6YFS`d!agSr{ zcWX$LKqbbbCH>$k)26}2H8WUe>adbE78aK-DQy)cz)^G$|(Vql{ zxJ6K!j5tmi3mn1m&#tC2-V#F%aBoz#3!d=P>LwbKS)}<#^*dE;3yD-356}mq`;GBPG2R*0qa5o2QYD zF3p=xt*xL#cv6VTjt(j}IC+@bDtXd>{Bl|+cZVSE<{b0hk%@UH!cn%Wy1AnQ%SIth z=4e4!@ry+K;%>4j(9}RAOd2pQx#6&!M)D%e8~nAs~nN%5@s@M2SQ~ zG5aef4em4&2A1J1IXVlgXh2TBGd)YqB|exl1?#(bu>M>gh1wL4{KgJ4U*S0}Y$Pko zR!jPC=Au&mado-OT=%3Y`a7IQ`QJcl#if5Vvenh*!V&DVvAFdXs!nG5-&ck)DQf1_ zsqII9`3ttEiI_U%Aa+=Ce)KTrzntLTv-=*U$cB^7mnr>nXLyW>bCmU`k?3q`&2699z=W$FP=2*~} z#)}-2X}D^6bWl@x9Cms{G|eA6#+TfBU%Vvb!|xMUddrPA;yw=D!Q;jot6#n1Ey;i5 zCgrAHWD&R`uDw)sA)++j_^@kia(fGu5~r{M06C+Qn?9qsQhp*%4o+ScnlQfabN;>| zv`D2L0umfQ{Uiu$YRgd`h#l(!McWuTQU#+#ZJAkg)(k+uJZawxn0se1k>1&RUvYYU z|6E4wgO4$hc-j~1KV0*fgIZf=qde+&03Dv$Q5P~If;)}*Yhh(7%vWMf_pa-Z@M3ci z?i?Is!G+<6$MLnc?UCv^MlDB1cpJ;DocRxom4Y?6y~@^~xNfmSWha;D>0@it!iiwE z+uk^Ba(Um!+c~sVdesXC&i0gee07@Rz7C2D;7-DTDJ=*_NBqR@v3-j2vBnRpJA)m{ zoaWBEuU8ozsKa-P8voh;G#C9_#&ARjM>&Wxr@+2~ID2DajU$Pe`TyYUEE?kIx~>hu z1Hl3Wg1a{EEZ4U!EWEO}{}6s|F>f_E~%F zYx&TakHDm+uoNCD)zUK|m7>_6#(1jwPU?ofrm~5X>jP@((mR)&o=+h%`)@r+PL;}k zYvK&K^)5bWE4En&-T_f@mXqPzQSY#v+terJ&_x3ByBj#)@3#%1cC$U=I@>(%?ts=! z{vCd8#UK%Qa41rdsx#2w9NSpF`ALv#>NZn6Uh$-^wiW6fPv#A<#oNe_-|1LNKx)tF z5pW7gtOEVA2AQNSF7rdLI(a*hl}QC@9!~kO5yhzTYrqOH>w~B%2=Bs$7hCX+CWZ8J z(v+~_4$Y)fET$1K!tglpzkZ#GDVwX!bjNKMAyb%!`)zUChI#bfR(0stVBz+8u&$3d zS2x)A07)J!xmiLGk#a&1&sgo$g_*Z6q$*%CL3U}|oW0TZ+l~tF;(Ms?82A6W>4T-% zy9!9vaE-E+;-zs-rVBA0IHgR)^(m3jMqnZVXKF%O3xt-r32J|%dTf&N+>X?YZY!LJ z)8=|b!NB+R_C@i1xSfGj*uH{W?=RH7Z$w_R-RiFr`yL}BgF#BaG1u*G{60rU;fq8& zbBM-f$F|bmRPQNxj9Y6pvT{0-Z!A3gAiCi!T!$g+2rd&Kr`*N%X%Uk0MKK`5V zvyBxe@YU_7Bz+@gM+rALRPV4dl`2p-&A%@(OsBL9 zI#IzgwAUxh{zwpq{z!MhB7g^W_mA;#R(N73-}XsW!Xy6eUeX3W5Bd**Txl_lsHFuT zwqj^#Uu5rtUIdNT1w7OdpoqHV*e>xUiZxdmOx*2#Hpyl$6h-{(yT@78;TJc&vSpQ9 zAq)n&c79z6Pld_lwD-s2>3k)n$9V{1#lIX)S5H1$r_VubHNq{vv??RVP@hg7U~xEH z_*zQnMQFWWNS;IC9ZxU6r%GcQIy#O&zOPoueqi|y&Mbrh>31kDaU z`@NSp!bXrtaHx;L^PpveUJu028Z;zP0^m^7-+7zf&DB53gUQml|D@9fD*Wa@+7VEuQvTEPTEAJanpwGYFu2Ai2l2GpF|=@g$A*Gg`(xP(jejezAyYph#Fl%TEW#g zOpjs(o4%3v;H4LjYJO~Xl4mChGRsVdMUDxgc@$l5(rYjMxPc-GE6~m%p6Q-Lk@;hG* zPTSJa$YuPRb`b>Pj&|1HvIdMEnpuXpD;zKDSntKY=2v{VR&nF?U{MY{lV#XV(%pP? z%M*^%+20EWg^h|tS+vGe1)8i2LAllP)3_@~!^FRN=mC+|Cp-uzb9ucNX9l6@HCWh^ z&!a0-Nc)V{?6w}au||g*!0m?SG$$U{yhoP)kG?-p*3{<;me;dM?ke%R+BfB(1_Jj# z#{%9d%$X9%K~LGahB7-7e;(4_RCdd@pSl}2cg5*?xaeDbQl*9AP%=|?PthCDI@|Y0ycWr7*9%eL4}SOty_^Ed>kgM6w-(V|je4e&QeAiKpk_ljc(_)$&z# z9aftY8xFITCHV>V3Cs`@P5G`7d+M>nasFnlS(|bpiyirbg!qXHzi+9F|CykCbkKoL zJr)ffr)l+;?PvQw6N#32KDBp>kSwbng&8I(vn zbX%Ya0)Per!}ub#ZIc+{mo6WQ<~jT8vo@lKH)`@sW^DgIy*Ng$@JVq;FHNvRVk*SY zu2GhENwa@Y$R_WAgAI!e%{+lPXjAuu%Ro3Lx|x=A<%9(s(HSy@3tlfo0`W_Y3R3p0 z2weg@h)eF;CQm&^yJ=^37tSxdJbhSQe3Hz=P6hFW@v(u!J%4Jr-9LEHC{fd)C-r`~ z+u~>r#l7E&vDDR(O45huU$kd2oV+T2=V2PcjN+y zFJ_#1xQz+n7ZxkJJ zqzzsyMA>X^$11J5oC}tEGSe8xHyWf-cJfdQZ6Fd;bT{R0glo*{=*=~ASu7EK^DZ;= z07~S#9kQC4OUo$?wV}ndRX&D27&Zp*$2_Plf19C>_Cch%rK2DT;Fp?m)cK+zea)?e zq)f}Q&s$hFEwlWX5%Rib21arcljFJ6Wi88? zbaijbEE_)jnxfSX{av^C#xc*jM{oH9A=Y{igmw8}kL(nvNH4N7XOT8Bvz@w$&MIi7 zOn)2{@TSPUF>o_7p#w)12=LE}N*Zt>Um}U_{d)^yYSiPvs)v1Hh}qa$Q!oQFg>v@N z3VLs>T_D>cThswo3bVQ<3R}Y#ZFO2cA)VLfRII(U;wF#4xG|hF`2hD2l#Y@anBgkI zKjV=Wb5bn+1=a72Vv`PrM;3|NN@GBV*4E5_gL=|9*-ZPAXiIVTA^~4N&t8ZqJw>JY zy1cKLAhxHm;O^B*%(p*XqPW9Yi5PA_cc^fVbGVY_F)SSmtD+<^PvDk*S@qCYj}qvk z8=U@Cnt;t-b(xt|t8YrmW9Fv^hB943~HD@jMSt(BW{x)okvwOxW~q zqzTtJ5b4m?owt2IZfh3JvP&vSGDQ_X)WwZ)p08mn8JlhQc||g4Po#}nu}+8$RfrK@ zmeXX=xrA!htjU{QN_0jfcs-niILaOz$#@_UZmB5=QX(W!fv5$5{C``?W{elX7xWLL z-MZc-5jGBPtov)F3*{}tjbSY=afi_v zYWSwU&l4g$EGNUFa42zABP^Y0vH(peO~z0*8&rzbi+yqI@-x{LoefRS+*^AS*eiqY z=g1U3FI>SD#=m(-4`L9XF6CuZQ?h>$tcIq0(eKZaG_5co_tN>n``Mm`&4N3HJ#;rF z^@)@!IU1VVM|+s!Et7EtCL%;})r=5BwII_q1V*B|?uLr+D!7Vh?+Deo1)5_m5@q>8 zv)0-|ve7T?g>fVWuT*EXzv|J+7hh_5pU^OKh>Q|~#7-C!^wuW)zbc{B$$gZpZ{k)J zts`s`rOXyOV*S$J0D|g5`CA&FLWVM_|3lCn`hYuyg`?q-ReS$dBY(5{)E>7<#U0i1 zu3!&UgR}JrgK+d{l*3)DB8A6sebqaYzNO)BX;XlLm4h^XXVcy2!{#UA%hY&0vyU6ab=Em`*TkX1^>VXnz&s@lOq19>|9y)S2T0P0H zHxndqEDU)m9V_h;t7Fw(C2oTUS(_d3(>^K?4=INI88}?Xg9o2ylUl`>=;z_& zDYNtMM~|k=RKywBl-wA~d%1A)OtjdW{~QDpQL?!qK7@#V5+puj3YTAQMsY%Q$cjsc zRp-<%uTMZmovqqC;%A7dpKB_5>JjS)-79!fvxBg|c%8AAL)NBR5tH)} zPV)^CpT&3dogEp7l3+stEq1i-vq`8sM}0!?H~r*Ia#;pae-&FgBF~EDTuga5*HT57 zB$Ck-kRkX{rA&AVu)e=ifcW{&!UpL6X?HDW0ID7w1lSy1O%pp;ZYvb0H;p%e^i8vV z>O!&!?)15a@dciV@3eSjy{TkST5%x zFo*bhQ|O`UsHwy2#_<=B8f>86e<}=u{Ec6rb<%)6Yd>=bl^{#Q8E{5T}9feqlXekt9_vo>`{f z=Sgm0N%zenqqj#;Ox%Pd6oF!SCm*G`FiXGc1Ds7ca4hy`f5$ubmBTT{qO=dmPYdU& zjGr4}c%=659EPLLZmq!4GYQzfZpcuLJp)PCw2(P(S z3xmn#42?BYXDI~)5~gk8B6&@%t#*EoLwZ9prHHfZoA@@~Z_PEm8R=v}QFppCXMHaA z8Z&M*eos$UQHrxnw1sBaep5%db#|ik0lSSw{4~+D1Wi{%WW&LW}|M{U9i*N4d%`!?$c?V!Ae4yedV3KimF4 zEpxCw{#$a?C4BQsKf3gb<2Nt9aFp2z-~pKhz{hhg&^*@xl271OLGgtfi6M?C*kw%9 zE2xixprbuqMPawaSZ8Lp)v%P&4NPKbNke!b3N`D;j>vxIG|-1Vg0$v5A8GU~I-f-= zZR;j5S<>vF^SecCm3*ER*VS z*fPedjBv7(L&ObW=lMZw25t{4@aC6@)BD4Q8+OmJ0Hk+oU+QXTv*Z$AEw9sZT`|z| z_l?m8E~7jG#UIULTJ9SjqZH_7R8}nSqoI^c3OV@iSOo;v2SKcVvJBq#7A4mdjZSv| zA;1M|h?h1~G4|Zbitmpl{#=MW1=eQFya5)p>!iUWgbZka( zc4Ps0`oZ{ex)&kx$w5Bf2 zflG(>(vzwQKs|UvL8~60zK1Tg4?z-5(2U2p>i*aR^9gs%#RXEERdw{oOdsl3@57?| zor3EK#s0{EVG45sGe-u$WK0A}xjLQO5XFPkyDaQgkL@Vc6t(k{KYc)YNF?C_z1bt%J*XGQVz-d!IQ z@79umKI>Fg*unVbj)?#sd-2jF)L_=6lm4e4nFJMwbl=Yt6h_+v8zOQq5=q>?*<0)A zIUA_FL7A#+7ym;5q+D&Ht#7=@zqYAG1J0?Q+4^N|@7)?!M@h47C=V>W>#_X7f@Fvn z8_bV|+v^NVstwZ@d)-S;E}Q50eV@n3)Wg@PhFN?RrzkndiZHds2_Me+43wOR~R_Kc|dlgIVkKZfzoF#ERSud+8 z-(Q+Ie*S^!~2?i)8W|ctGpZxG;tUXX}+ntRMSr5hz|6Kv8 zN$Zq?5ue*MLpS*VtBR&yfkhqPRmWYBNCXr=k)0zIAI3e9dwf+Znc&NeG8*$JHc&ax zm(09D%V@O@@15FsYU`m$70>-;y8i8-xu}Oc`vLeiV^_l$hAl*V=sG;*Fr%sPml@do zOT;)=7=Cp;s3PY^%a9EzV_Bjlv6ZtR{3EbIh0ttrsL~`n{vU!vYrbMQyFNo-7+wYr zH+4dps{8K6K?kdL+U$w%;st3&)p9SJt^&zR)jpUuu3Sv-?FQeTYMC|0kgHqRStb|) z*T*2hI~|?D)!~L%2qNEZdgO8Ar1ju3ObA5BSrN#I zs&fNPL^H&W7O1cd^#1WLUGGx6ssJrh4y70ikjg+0r}hruZUES~?1gsyL5* ziEFbwIj)2!GHre9_409E$V9esCHYtb@L-r!g1Lt^zg>!4LU^|6YXtm4=~eCglP+r_ z%O(QVn}M7aDW&NdU#CcM+md;MRVPBJ{8y7c2I;|%$Q%hRyu>c(yhTmZG>|!O5o=wN zUoh1DD6%-j|33r?|KC37jZHbSj9DmBR|3NqCTTN<)()}zd`)Y;rsJgezua8ik>hB5P`EN=pIn7E97 zRr99l!i5RIlgD)8#${;u5$oTd2dHp?n1((rfDbu7+=i?zMGXqcvhS-jIY||MdSd2D z?^!l0l3$+Hcs>Eno0%BkeXDECc&l|rOv#ON;%#rKB2W&Qn6z1@Kq(|+U>SRom7J7| z$G&uY0>NI&L%T-=dALN-!cUkd(O)au^9SyVq6izNE~~!@y^S#^rQg*Or4mj~M9^z! zQ_a(dWvE=T?J4v}28AYl#W)2kP6-zhvMUW?CJvumh~uk23n1^o_wd`E{JF?JPQO>E zu_9`z^m7g^h}pOC4x7E7-Rn$2*c5i6LdApDs_Uou(=R0aVzU7zbJz$7ctrQ;NOmCA z2!lI!=QguW4*bpnIXt|0lMG=6))BH#V7X*hosaY9&Z=(@yo7&RJl}&n?jEntJ=O*E zJB=H8&6psr@_d)l$7SMNe~w2(DB6jxsTm|2Au?-CbTvq33kbuL8nITt;j!H(a|fB8 z`G1S9kh;&6zWR1{5x{(nKxeMSjK-DltUz+c>IC6g8R2WmfGMKWhGN81*lG*WyX97> zF_w!rqvku*gVI1O26T&i2R+o@W^y{RlFV(AmW-0)pS@gAb#-q zTVI#A1G9%I?EH~yLk(o7u)^%MmVl2VW<4?X=4oFJ5iHW$&N;aR{sVj`9a}_KE;UD~ z>;De_4!_{LlN~!*>i*cAwK%2L-U$?4P$EsiilKE$jq%c%5}aavS_*q)d7B!6NyB~F zcZ{W3$0vLshEe85#Y9YP)RM@Rfh&w)6-yHpcYQDU2{+!u&-Q?9=*H~Je+V^|i&g=? zO%p7~%>?bU6sTEd$%!IkczeM89Ne)7EL+CwvP&%ff5eRepzMy*>|J8JbK|&5WWcDO zqoSv1e&?q)(Z%!&XTE?{5Qxe7yrs&5zwt)8jx+_B--#0PUh&Ph+mPe2A~oB6YNOE^kvCJ`;oJB$tNyADwrXzOgc-7OcyNN840l z=ZjU1h;@xO(4;TNa7`yeTZBZH<|r_yJ*Th?YvOGo<9tC=Y+pE8_u+vuU>-95(Y7+8ZkJ+_m;4c{Nj6M znK(0KlBxm_bMC4E;yaj1;qBo~>2vtoThKJ(mk}3|$g~~K)=ASeF|CK{GRG>j=EzCd za;J4?Xenif4}Hl78gkrAMKJ<4u&VM$*qF*&mdruRGoBnXuS1?eCeHz?(VlJVV88)1 z%W3^2h=C|x`0HLow7t2L=6HRQaj#hO8PVW|J@wDb5N;cux%ZQTAHY3cVy7A-Y<%c7 zm)nU-MufvW_;vhie$EnI9l1mMRjiS%X`om`zO;a3wmj`|U3#ZB$IG1fWo6INFcIzO zv%U9@7oKAvLm;iL@5+V{>c>p9huzDjxBx9Ch6`^+wPLnYA_J4kN+W|!pm;G^MY8EJ ze!7wp#O+~61};K|)!HjF9rI*3M1gTF|0j`LyncK6g7)exg}2>tHk2-DC^_}#TfIdu zbs0LH^>_B*@r0Eg&epI(=T_aMOKK6ulw5y+N@DgO!o{IjZ;j>PH~Opf7>C52Oy2wE z!7(R}uWg%L?D_5rlRFqw8Qkv>Lx7_5lbqoB>&DMoESe4#I?YvgFT!iRR}!&jftK5X z%@~E0tLl=XJ1KCo7&s&X96}M~3#BYJ_ z7uaa#W*PDr2g{>Z}%Oi5_vzi$1=8;I7uK+XX9%1W7y`mwqQS21Eq@d zJp1a=tsH@k-ahQ!HLSpr~u6&sZVfZ_ojGI0;!qwTya-_T2uw{==1e$W3+74*Rs~Z zZk$5tWm+qQaER;;x8HZYR|m)MceHJ5j<^vrE4rxwZvg&)6rk5>utf5r;b}L*bSE=k z=VBOa@$Y;|VhMU@UpNfyr`kBqTSgw(6~$L~Kup=Uat9?p%=1^mUx4s6(S$WtJqAoP zYBg?OD+GgDFXh;n0(uqPZ-5g{q{8j@qH}+vB(|qSc{wisSZKOyb%BT_ub93q5#kk_ zPq^`z*#B4iwag3m*ojxU!9l@?HZ4-*e(R+$!|d}>x$sSTqvw;Z=U?(xML)2qjvExj z3VLhb>MmUiF3f!6E}RqP@hd#}M=@7JTn6Mo4wE%e)yF_WLq?jvJg%zF5weFBEI|#Iy)zipfH?}7-!H#|53@S{vQJBh62X&A;TNw z+xAbq%s_j;@YIig6T!OymCc`8%=^DOaLRQ$X6znH4P~evkOO+Kb)cra2wY)30I>^nzPHz*a!o6uwCpu`_l zM~c}cA)D_s?{R_`)ju;VP?Ffg_3?#8lC~>Qn=-MR_EAYCmpzbYCjbwkdapC#hE>y` z)X9;;lk-%0gHUkTvUu?Jf;{xS)g7ywk12ZBruT8*Xcuf^3||Edk~3?(omWViM^FUJ zJ#x&jEMxBM=MNhi&Pp#vFlJ}P55Ta2Nty8vWhC=_+OhjQYTlJaBp()px6Kr1FZ?*j6@Tb^`~xYOD}=Y(Yu)(Q?nXcWC;1 z2#!P0(n`&(7N!r|M}rBvV8>Q3IUb6tAyNdByo^d=nm)|qG#n&DNu?@{;b&71tl`TS z_R_W~6L|vGF60%Wd}p?5=iAd*{xDz*(9Ny^A(0y^j1GxynJn$dp$N&-3BcauEz$19 zqrcviJeWAilb9KD(r+uqr8&iSk&EU1_xpfb#TU+-;a~hh&h*+s$cXctBIQ{T`Q92z zxxxX*dthrrM`J&o2sx3GOoXQ>%t0KIb5+H0x3&4ONxT4iKS2CguQ_LczE!>@&qwG* zt;&B0CM^5S@wY^3qRE&A&KVVcEY^9PuOEqzPu6nCJ_C5)+?UPOX)5doe$*ZColl<> zLrHB&$KwURzG~%cEjGf0WylY3@av^W2 zM3ITAy7O#r|NXa*&nj)fUB5BM$uh}f`k*B2gY;~#7p4$(Q_8n5i!c3AYNM7Kf;P^r zFAlq?!y1jO_Pu<9RynJ~gT9vI_i1^W1}OWPGG1%$SlIW--|3REnf$o0_Nc(7V5=;)_N3D4`L&?q#5>3lyo=S4~?WXv(!GYL;*r$;HtoT*dAM#cH%W*7&>s31WG z9h}=nI~}r+H0E&rqlH#bcuZ$CTUhdE{;c2G_9CvLo}U$~m-lQy1dKoSDj}gnrTv&qxz5Cp|qD#`epRJ&wG<7i>a;aK!{Jli$<0O*3Hvb3* z)vER83g&3$c8yfBtQ#;E8;*oLHp8pW4u-0%nC6D9{D0bX^xY9V9O;-$MJlrY< z6{ouSm{Iz$V-!f~Txw13ez8$Sn?dJo1kioDIO;*^@Z`YG zVWUg*fCkqD#4Xg*II{O+O)&=nE9@6^t!WJ3N7t_Xz@vpctweiRSL^>$$aJ|XHv3~NF`Jd-z+S90p}kWcIg9hxT?75n!`x$DoPWk}e$FA}3=Xuu@AB;x zB4H?Kg8HGRmW0yjT5HL>Hu8qlQ*lupw+)jZMp{mFfheVfXfnY1O=3HLBpOMw-X=Cb(}l#b!oO*Vd{4Qp zn1PXg;9mUFq_m$v@F@?7FLFqg@pG4~Zp$O4%dJrE-{(0`Yi|9tbWffN%3P^UT3{aW zbsU0l0*hI!c(VrtD)OH(2G6K(3{= zXnK2S7^ac^HJf6r)Av7uyB}8bimH#79zL49&5Z2?$tm@c*T-VM7xz)ZHQI|XL9!)z zsnm0pq6)L-Z1VAT^1`C9RBB2Z{&tzRt}2r7TXCs*&a$~J;+|;{GXQMjyXVv(P3+e6 zKytpc(a>2LOI))DqsV90Ijq}9wHrlgRdpoHvfwU}Zg`V>@S88I;8EYuVZ3!(d z4$HebDHaZs@th(Hs4kNK4?&&O=_|sYI?ac~`T@|fu*?Wst(O;amM9kqeZ^xa%}FBb6HZgHUhUgNn-1Jzo-|>V$uzC>nxAl#VP3IZH>!+RJ%suoY3S zuLQLCz6BCea}sml5=9wG2gWXrH6(O24kGShxr4Yx>}lr1r&eln^by_2hV{;{f)^_u z=w5z_zp8la;tA_78)3=>(W*oT){#*9FuIA&2jdW*#|#Yadl*{84{Jikz6C~h2E-Y& z@ep{aY|tl3P6718h>RXcqARTT3pOAbQ9p2VfmIPu*3|&-SIM5?U{ajHnG+2Yl-gnp=7jv*# zEQIJhwX)|%9U}bAY9!Asy0C4{(ksri;;(?5!iN{+8tf2U(*)twmxa}++gVImFEnLUowIrH9>+xgzYg3z~vYbOwta? zVJIqnD;V7h&;ZmQ^x5-LpLXSB1`Kp{-e31aPb-uJma`a*tRPCK$Uu4)$Sg!fr8E@p!z<2Bs|gOCfVsf#h}*P!En zG{lx&MCHsm^qr&zejMlS97y~#R3;lg+@{0?A?wmHgvS|d|s_~yk6#F);y#0}EA|JxPwi%^R z4{CW&`p>WF3I*tm`*&Uv7VC8=YFK*;wpg@T4k9sME`o*L9cOa5Un}ru>n%C7N_ZBY z053ekFS9m+%=AtC_MKt_BYiyb-ro)RI}JrZ-a%he z)IknSvFyO|1Pl-2l=0!u&*n7qI5X;b;t7vA&Wgqo;H|d)37xNFT~HH)2eno|bOfX| znDP^Z(VNruNOE$#H2E+h;6NBE){k`WN9@^JEYx|o3h6lI&`7<(@1MzDJ+#4-0kIzx zVF5qd8wDusqMdh_(f`p|h~I)<08bHBd$-fDT`!_0E3izEk9a92Z-Zj-Xn1NQR(YPQ zFm`553{Q|xnaPCfHIU19KTdpFA6-3s3*i#Fgp|ihsiH>*oOJb~9N*UN$UyU6SiRJXBWp0MYCYKn?(0&QW9PxpKTmmI1S2zUF;$(O- z9{LgYGu6K0$UqZIZS>ZkW;1<;t(r2oqAHwkNIsEhJA#YLs1p1S%Ed4g@?c9Eeol)p z5OMX};#kVfk0rkIxGE6Pxw%%cUTl(YX7&Qcdnnuy}nrj zN-LLwhTM(R*L8i&;E#y&fB!DRRPfp|wUdM!qDc|l{h1F_{?Qb9qz-tbaIWV1%iH|S zU`LL7VtX6;Bir25!${8#(Zk3T*HloLhSC^D(-ugnGX-#(xXB>ZKHb z>AIR>OIpr{PWiXtuSV1R>hL8mW01PA^|-2)BVY%0RnV*RBFwOg`o(9DPOjzH(o(dF z+J0B%N}_>{cW{ky2~kAm`7-94*lYL4jivNb&8+K-!l>- z_8N5cPjudzbwrU(K_2e=793eXvK4%HTooDqxFLP|{1w-v@8PM2Zh|i> z@UgKp&}wO}e}kj(S~tvKk)aWMs2sDgdyd@w9|F@KNxX2_`&LFOTtA_E@!P$s!9nx| zA2Yl*DA~uwd|5)8_e>?oc*&CJHMJcer0?Go26HFnPh|-Z)c+rc?#~x1ebTKi_^J}y zr#MNVBLBm@#hN12yc$B z86C=JxhDv3ge2_{_<+?-8XQ<}#AMW>3#ZR%EUB%drEW+)u!TQv)M%=E_gCg@A!d2m zGJ3Dv3HmGMGWB`_gL+MPb}GAA=I$e>P5X7d`CB-MR*5f)zmhMQ$h!_LzZJT|KD9Pg z0FS>7GMM464Z(mW(pG)JMin*viijua>8#=lS+P{??%2}5+0_QO9~m;VgS|aFqJtu3Q)79w08!9oN5=Bj>vq9+Vb&z?E~dOSlkYu($FJQoW0xr z3TXe0S*>qU`tTVx!qApW6-P7TM(sz8xR3!?>(W%;@46Ez*XZ46kU_@IY+}j|3Ed3PWiB#lUcdD!FZ#4+p zIXGC+IQno#%Poh#nMA-ki2kiWcUn8&ujJVOd*tsqM;9YYklMR8Vj*HWx9`KZeAO&7 zN@12TWT@awp+DYj-eQ^)o`}?~catEjTW+wd zuNU1tVC!UmD3Qq(LG?@SxUGKvdj3Wy3MG^ZUzp6Z^!-|@P+`IK8dvNDw{F-ts9eiQ zfN3a|7074(4d(DS2PZU;`8D?HAKd~~oWoKS*p$VUmNuD~Hitc!JIKw*yY^}l4luuH zazoveIH&4s5i;=xbVYBWAjFxaED6=R7Bv;eS1PIum5(G|jnNER|KucO?lxeVv4<&5 zzOF7DcRlAx6hDge!_s3pI7H1WH&x8i>Sb*0Qnpx80kpUnSU`*jT0vz0r4mpUQSJ^U zis@spM*OBqXGkA6t&>PlqQi1gV|7$2(9}f+Hr%R)lxhx<`;?vgR4OpR%os!(M0l1q zV&|SmcBLCB%G5f2d)xGmK3dX3x+2b1_?;`aJR{jbyI*0<4orbDMrhlM<$Aa|hR-e^X(NK%RGlWSM zee|#fqZcjfbRS1^56G`}n31(vbw0auef0Na zmP_Tc8_;JTK_O6A_+R=Z!vD`hXsVgO=YQj^#k7J`;y)2n%i@>36)^Wp{!ySKSS1Dd zyXh0v&|Sy(J4Qta#Sm$HyPw{SkUG9Jrq-u8BGS8O_nTDX3&nSOj1ANv(%aKp`)!lN zth2i!?eXYcb3!P#M9DG#WHg25e^nWDNZG!5;CZVq>zc1cFijd)FGwu@@AgC*^?aEG zsYd7*mt6@O3pyIwyhZx;05xUa=4Vf(E}q@W&b|d)4_R-_(J5%9H#^+}#EGrb?4b#=ECCGtx z-qhO12%PX>e2zK2*=ny3&Id4zk_06gWOWe{zvSrUj|UK)`1)01GTo!bGCO0vhA?zG ze)Jc4#o>A04<9wZeEQ3t5;!9Q#As`lhn+uUSXq5sO8~L412hv^b;Tz6uXZ8=Vha;X zHCJ|+Ubvf=CcIvPa56h(ufxU$bp0iMX!bzc2Q~_A0ed(eRws3$Ul8jkbLzzgH$-lX zmR^`CqlH@vU3g3qF{J{_8A@Ms%Q93NgNL?hz3l~R$in^T*+hP13oOffCc56`c;P#;;SQK}$=ue8e||CG00#(BXHxc0F4+Q$oDk8EO@6+MU#+yUe15 z_R|`VKTW`QU4Mgn>f!$(yy?xMCV1(6dF1nf#)ShuJEW*e*LF+TDnG|N`%gPS2-xp) z{+BH=5yWWk(9-U27z^@EC$ZZy`qDkxohw+0!y33{u0@%q(&y4D{&VHWkBTqS!>C7t zt`N#U%jXl;I!z~H-r_frt%e*UM=W{{_NG48J}2Xq6C7&u)kVhA8%tlaVEfi#epJ9X zd@S|d4rh}( zBM}-I@YybR@Aea+{LoJZJhxXuORu%pF|e9UF5%9(5iLX*6N=PnRO$-7!s#{Uo)R4+M=)!hIjKFATCb##_XtVola8G zYfy1Ld89a&ioZ80PxB4&@Gm2TP2$SGseG8w9WPnq_O^0x3;-6#1$`Jw)6AH+ z3%bcSecl*nN(WTHmXf5jt&Z^5F`BFJte zr)wPkwYUsp3m=4ooqUwHpi5){+92Eb+sJNBkZ3Zn&d)6^SwWPUav(;H#wlG1MCa@W z<}O2GsUM?ol?zC4)8uIj4ICl*2XQwN-gqsUALbH69lY5=~RzW1}hsfhNC56bIZAk%&3==j%4nfN~bbw zm7Re*M51dCK6~0NPOyQAIIHOD18?HjV}r3B;_6|Bii}F6NAAk*7a^nJYHWICLL%Lo zDT#-sS;CR$fM@9!&~*f4J2-*@>tA0Zbe=i@6AJABX3&*%LO(LWlPM9{%q|B(j9;%d z&lk$x?10y{%1W&+6bFaO&}Z2aIR4fUI_Z0qN$#2KKI$bkQH3lC((ip$-vc;_=g)A_1 z%pVl~F}xL$Pg7g9u-KjS@7-K5U&H&btBZ=3#i{$}byYF+m9aM05GP%(PIaPR=L zrM;26%FV_eXUjB8UbpULi)P){HkB?5nZBfP!Cj=;-#p^DzMpnDV%|)QE}tDtMCVL0A%&LrL#DC_H! zJfQg}2(0hngQRT?1|zX?vq7Z#`7#k6{Qls8Tq?o+@VI2QmRM( zu-A;EZJ5F2g>p^U7mvBQRf;raCLzQ-NWQLU#)*Fl!&d9E7L}VFQnPfJ5`QPS;EtSl=`;V%-2k6TS3 zCQ|P~g9KO876}*Q#hYB1g37V+({~o4ROD;<(A~uQ(y8$B1Mrf%Glp zB2H}J8$mxlc8JLf_4GmrE<9z1N5KbQ=DviJ)X-M1x~#y8{c>L(kU5%0MzK*~O}uWnkDA?@c6^?L<3i5%AMv$?*QW zmjeHXvXX`Kh0iMDT0F+wV}P3TVtdhH!`B9Ed2?-sWa`XRTd*w^YRmF=0o|oWL7YT4 zh?~?s3qG8`az%o$QL|ybp(@&>ElAydD2P0-DCZ9tedAqYc)74JRj(Ld6Dc=RJ;hY{ z_P{m=Hp-2}sz-%;373`u#qtT7o`#lQq6t31m>dvg3XsOLzg}yEVU*O*DsF-?DenAM z0x~lzii{zHYVU_UJFunwYayKya&%Flp*{W7xTctt*ei?Tfnn;o$~fj5kb*s%OjW}c znkH&3dDPc_*k!%(s}clJ@(K1}Z-OhUbSODfgCFRA0H3xZo(MxphQ(N3$}Q5=>5e@Z z3bvgNNf@YE@U6@O21Y|K^O{i>=8PsASPElo?Va_zts>Og!A_!t$mK(hZZV+NpJ4fM z6QdKVqfG9RkO*HXz<(KK^%;y%CZ#H<9`zg^6xB_R5N#aO7RxpAI&b&5Iu zWm+$By{a&91n;jEg6y|Axt0ft&$&o2y1Fs4uTMhBc3&p)?(L#XY?p}&pad!>w?gffVaCav-!J)WAaR}}n z+=_gQeZJTEI>c~TjQi9Fzv1iT%IM^r9s11St$QSw}U>0@m!QK zalN&dXxMKtbV-u?gV|woY5~YRjL<3NV^S)a04eQ;BEgbcG~;^<(m;0;DpP65Z@PR4 zVEh<6^~Oi}Zim62EVhN07b4U%9`LBIe?78;2`a1Gxsh&ZP}nVIrr`GN$m|l}$U8)R zDj5V%1n1<_1sp-LpH@bud_L=Oygbg??>2W6v|tayMfhDX@{XLm4ewJ6dztzyaRN>C z{MVZoIwWw6k3e>`Vj|jeq(N}}es{N}k6D8rJON1lHrvMa9pSvTMr=eoE>XIY>V{|> z7#-2?Es`YJVF^-6CGEAxyuqI4o;cWla9jE9Eqy)V_w5Ar+pEmq19M`FA!tSJJrK3kt-`*hDASgXnhip z)tD5Ye_s;nnyhF2KE!@C3Ot3`DbcFFuAft+UL3yKxNNR)%5$}Y2U2^icrHj@^HaQn z`I)Lk-ZgvYX3VR2^-$oc&zvy0LmHmIj^PhYtl4_6{^7x0#n$|bV6`|2P!qj|U`BQq&c-*fVn}K%o5S=|j0qzK$1v6HLnATI&1i39YI?~+q$|`0% z{{p=CUS{oz{`(Fbi8BWgrQVci^)kfgmiWk>YSB)*2=mtJT3t;&?W*v|5! zRv}HYg`rG~UuwR-IG?)u^#mjlCy=kpWsj~ux~33cWdBWx#n1ZNBGQPv;@|itjH`n> zNIFwC;yPd-B=%=7F&o54Zs2hT%Nnf@qic;MbFhe@UWTGPC?9PeHi> z!w?7A@^M=xA58RJ1Q3UX&~bEbWQAkzF6C{LK~H1Sf!2NtIdddQ2no({PH?&z8vDNb zi*5_CPwqMv?U1N@02Oj)=`$1DQw*jjrjjTW>9+R6W9_pvup4919SiMP^WR~_iwSA< zsH5FXkc!A<#@hBz%xsHi9K%VHNqg=yWtJpIr(lJAD^#PTufkpIr$#sdb4KXRZFeZ$ zfFqt3fo$yKFz!`(Lfhz7e(XxAD%@`z1fMb*oPscINhN{hJgH@)R~mkn6iih@0KIa^ zsco~TLp#z7_tN0FzdN^lJe(Jm7rE5iR0yMQgoE}cq;b1zCFG<0o5e1z-v8j5dcr$3 zTwO~fiXQX&{&m>U9>2?#k-=cUw0PHXG(x7IEeNj%xA^;;n1R-{D32FE=iUQR5;C*5 z(O}&byK~dF<`yr*SG5RQzqezHSgE;w#!J@(q`IT`NwC?^OtFJ<)$)7m3cqRGI$+QY zArgSIR@aa9b@+;X8lzcRLVvyuR$S)3+OqwWmvMQ|8{v$75bMtC%Qwnx?|EZrE3pLg z6Q^0ofG8?VA1Xq4nc#x!dq#vkf&{EYW5qGM0=f4z@7eUTu185dKP%LyLOmxe)>;ik zeu@pr)C6iS3JGo}wRN>N)XqS3-(u#^nGI9^*ZHdG z?HMY<^eC~D7acH|Z_DGPzx-pCgmNlw;Luv;pUfDCvVUiifx*Fzg%cCyvvrgP$0)j2 z#wB~i-|Vu7tX#$#?jpV$$#pXC0Q=CPx%*_x;?C%coyddk+?lhQGTZ1N3t$oYca>-k6R-HMprH6pS^ZD9w5^P+xR165S4~j-?zR#= zudw`Q#q~m)uNkTw)Hhlb0_DVG=Z6r+%DLMoZpMtT+*3WY@obbWRjYUhIOJkuU9To5Na zFGoDiXl{mzw2|nOw01jay9N&HjtJk8ZqHqQ5{2Sc2~D_;byWO8dXzaNn^alQaAYxw z7&kF-=7kZ^rhP(wF6Y};ez`pn%ydmDa*Gbjnm@b~ZR)B4+j}xWtC4$)v3btxI<`CK zPOu)Fe)`P*2M3&H58DZWUP@izrF4$We!B@pRfiFu<_$rczU-+pnjR&f-N1O5}q911;89lzO1~PWZSCKJgJl$L&ZoTlo zcCx%kl$R8(^8vxk+-Q{4w%#V%>)7Z>!HMDs>`p5pDUCZ=6py>Rgptj)7%x0sJ(sZ& z?Ur?^%ksptChV2%(^U1UvCRzuH|DNJ7LTL`u`z(vHiiaQ`d|mju%hlxM?P0#)F9H)I5I1@T@h? zDEayyT*gy4V^F;YC&~`}4!;SnM;iFq?xNOpu#@I;TH#W;uS?g}$xnXA`m2R(sN=mQ zODu!aP-L%vfEt=Vy6p$dASR+Zc3uIyz&- z?$u|-+YS8riHG~TlO$axfA5$ zEcq-#Hnb{UL7|b{?+6MsCpmCWKBP+;(!imj6>=l&%R8oupB2Aj^NX{)4U9IXXU0be z<-8W(m;dhG1@R*|A3=iG3f{eZLOK29cUys^B8)x3%vSY(n`4o_KZak^K$6qK3@|$O z1{Bb-wYrtrcDj5cWzMAgtGZl<&JnyJ)C1THlypxv#fFRvZ5se179J42xQL z^t=pb-)R*BUUA#G87Cm8x(<*#nWSrz|A_^^A5WF-_RbL;Spae7izM)# zbc?HWkX@lqMao-_D@iI#hnXm>n7KfT7a3@77p zjQUa=(J6YLg@&OLnz*c|gTL1C;RZik^K$}Q=*z~!-iF|ey*uk_z+pdx0!nWs{3k)T z4!7noo`YvQ=%h<@WtgbCp0k2TI?1odQyYuqthe88VId}=zh*B$Xw{g!yQEZ;o1lgnvAHf_*} zHf2sSzU6wC^DrHN{ST4dFTI_Db9y;O`MkC{P_p#0JsbfPMgs4HCu z;}{tZ<9m{MYP+qm+TsQ`2^>b`NM;SX0>3af>NUOtF|~hVJyOQNG1DcZMxlWmW@1;lm9V2 z#Eo87_Qj$oAj249H5h zoUOH9DBWgRr2N>OQV2xt^*stB&ELG69@@yD~ozjQ$$_JJ6pm(oyHnF!!TF6B%at z(Hbj-U+ei$p*Uz7gVWO=l)Q+i#b%&_5D zKj_VvL001NtcEDmnRhc$e;fxiuWzY;n`}tE2C^bFR5z|k1DyYquO?cG4!FiU2xuN# zOQa+wd6Fiqj3qVg(6v)^HcAgRFbrh3nlRA+Z-}T<->ux?)_^Lo+g3Ld(erAuW@TQ z?Eb?=4A)+;gF1G5&W{H&Bz>N$`UXu2>k1Wi80DY!+Z;E{v{ zljSzwF4GOKvu2SW&N^$-sL>uPIb&`6u4}i#H(Cl0jyvfViEaaJ^9w042n8VRG?;g8 zRbrU1cX?5y``2Q(3yl&r7sUXSB63X=hOqFd`UN`J(EX=ToQwB z!lfoGjvBtTx6&tUuIG2YYpE<6$%^Xs?gVBrx?q^)Q(E_Kg0i@tOEnlh+SND`C7sLe z{9sJ>T|sIRKZbHA&cFxlVAILN%>(NB*%yJoQ zTM{3=s&C;cQ`M}l{kZn7!kB0gb@=R%f|RN~e3Lq@kIf$AMrKnb>wGVm71KO`<@*eY z+I?kFcxm&yL?iz|P3cBe1^sl!p$+whI&vz=r|-w^+h+73YlP2H520urCe^uaMB209 zE>g2(lgn2HRRR*KQ;Yrk6X)d@)Ew!jl^7;GL1a=BCz(ol4s~m?M4W%9W3WXO*hZ;a zmaeO+Y*Hawj)9I9$Gr0J<4g@}jv(uFzasAuX`~>|1U>|HW(Alyc{Tw_gdNi^yVOd2 z5?buqXX5Ff{_L4$<>QV7C1lw?i7j)XS(cgHh^As2s}`rDPpEI&Ri3=HCfsLf^u|fh zYC_H`IUTcDX`(}ZGAAV6>CXAsq4p)87(>&^=MH%p@ZWIb8a_^$yVjRF+Sl10f8ljB1=?rpsphuYN=eS4 z?mS0SnYwgtUz1V#j1d1ZTAuGroiJtI!JJ=ESIiqD@gg&CtYPll{-C`D0?Az8FluSa z+Q)6!uM>dt52|LWbpg%GkBi$D+PDrdTRd|WQ)-J$Pz5q#QMZjII$y_jz1r?mgzBnK z?o!|Z?`QO=b=T~}96!ha^tXzwLrEc?E=qqfU5&m!{vM!!ijZA>(S9v7bGF|{!Dhp0 zuMv9o{}X1s){YZoI~;(zK3<|@`vp?(ZsKdp6|yq1Ypybly_KOJJMoJ$dHdIGwTai27c(T!hnpA5o4e}aNZ47X zAcnxd?>aP!svBJ1*#l2s^@vrqV*WYLc8So=(ftMQ^+ef5Qg{4}0kLt&t%ZvDoKtXG zg&n_l74(l)1Qadrd2YPV1thL6a4VDKYS1BU0-w?6h>p?y;iqS$dr9-L2;ede;2X z?`g;N_T;%ZG!#=81BJ&aIqCDhG{*WX5#8e_A=Js50C+L{C=-)QIw)u@Odc|lN$X*7 zLYZz&Txnfo%5YZ{eWzWt7lVeBmuM%c?ePhX%Rq*|>4^YA77AB;5)yFSzqM*!+*_3kLX){iGc}N4LrIbqq*`Nc0;V>B8Y- zPienzptDuJfvhvr-_E$%!l5xlon_K(&KW7JX5SB&(_yN&uPx%UfVm5CYf5))|CBlO z2py-b#5H3V*TuHzX@p0qgM;f$<;%SArq#syl7<+;A#5Jg)?Q;zg4b2_y<9I+ExLs( zdG9x*PeN7P(T=MD%x~7$H&@@?Q#YSQ``Ljrif(iIgN|-h>={LUV~>9_T(rJ6@Ez;W z4ZqQUql+6`eYQNSP80co<$CX-($tOeRU`h=4gb8}OIbqCd!U?rVuu zwJi0N5)Ia@x1Q~^oHw5@fpLBs{$<**`C3#N2WC&nedK{aPJBu@Okd5e_&(p&X&n6% zA6Qx0s=POcEK}oWS9+}BsbLykf3MmAUqvP8sa}Ze?Y1MphKYRRIL2dc7acIn*b|#h z=h+N^qz8YYja^?+-0!rnFZtjyq$-YzRqCq4)Fo-CW_SD>9g^2nz3Sg>Sjzib=sjB2 zE}c>;)~^^NlQj8`!;)o-Q`KFMCyC;FqJc9vyKo10c}mXtN#>uBlgxwZ;(ANpFGxQH zhdTp~&WG?S_OLnQr<(O8Xx1z2*$kjV2A0gJ*6{vw`*$=xaRK>@HmgSQXu2CK`ZVtk zgjg1x2Z5k9;&2yjO!i~LFl0s@@>kcE5j7BsU%mP2&h{P0MeR! zR@}(4rOOkKz^-=Vy40eNW%#~b2UGvB_5a>~?rPM1>^3O}ps+UA?3Hm5Q60`XJXrnv zYtpmN706xkn%{6k*NS>G$>wXTf%HM0haWz8iEjUNQqdkrQn8=xv}lh~(Ca7W&KG^p;lFXw$^NdJN+8W5qzu)|1a@if23x17rkUNZ8PakbP*^KIh7gc;R!r%^m+|en*MzBM6`V?fUK@{419!s+D=kgkNwr1#oZ zD$~5oH~{zBaoH{S-(v+qn5ehRtIag?uKgvloH~(3O)3)aF4tys?j9Z{<__oiY!*ZtO6=B$3ogI!RqY(k3{3pi))c$>kqVGfEYH-> zAF3d;&6~e93N!y{ME$U8k@+5ReTGL#+-K}m2J@X~CDr74ut&FNoVF)x|It9;4H5~# zR>H%4?Wz2{WF8`F+w$$V|2{{drut*n z#!S9Vo&8eZqB%{>B+9Tpdn@m3=5Bc@Pcu1SLmfx#VoH7BBtBM!i-_sz{C9zlkWh)4 zsmbQ8`<5jp zyD(MlnP(hnWpWR-<2V_Vg}^~nPv3cDSK^BJC#5}$)=tUs5-1_FbnS^h9%xN>WTwY{ zcaNM!ax<>mLo=%nXNaTvkX)t+SF zhxDyqH=Y!!^kcjTgN^lG?mz^Eoy!PQ-^if&DRo2QbW&_2>WcHs6^ITuF%~pbi~Tc` zp(m7w9W}s1l{2WUw$@J5X3#B@c|evlO*7S_&%}}Krz{<;Lg-gsR`6_7=wg-e4fIEO z!)kH5L>|LI}8!C+VVADZ0 z>9>^HxPg2-Dz8Wh*U0$!_a`-2?k=fiVaOu0oUOlOavUAcg+HE{BT~W@`hGe&>Q42F z9!lmhLOoMtJ4vFsjK?9hm50#WSlF{;v_?!j<(6QYlag5g;ZzoG>jb8CvlPcp-;Rt85_q5 zCh0B$bR``FLSQi1qUm6oNo*DjMkoB?NSe|OU+MZ_ilE!V_S;v29Vm%)oEdxV!`0M( za24?Hvb)Circ|N}x5wMp?|tr37@|JaKN5;Zip|;jG4-+^ijmYzBi)}@y;Y&tXW^Y4 ztpm|1b`1?dY*_*{+O5a)=0|amp!8*}EejP&}*^Qzu|aOC%u4bxWd;+vfPk(t{C$0p{c z%X&-GEqr9oYuG59+uOM<#!nr9r_oVd3xTb(Z@{9bEyGjoUTCV+RG+$Q@DiNHDgW)t zT^sc*SB{i<*xMYVWS>yB&6ZC&3$rm7o~a*Afyg9t2r;+YjlYhg zj+rcetJcMHOzoUcr&)#$e-wB%h+A@Ku^P0t;OB5h%*ufpb^0^_9udOXj4IwjRi>DV-KhI^P zu8DB5Mr1IOa&JdXv=UYapvg0gFINVYuN72C502zBF*pxtbZAR-nHkn&N<&D?p#&Z? z)rwXJ$`P~JaB+N74>|D;zL?IsKTBE{0M^F2f-AJ^%7Mr98M1kDg1w5xU2`6YkLbd(WA4_e~SwzCG3;)=VVlI(SFlejC zRPpHuT2y+uAs5YTHxp$(0~)Sv!@8?;OyDFPkP5JD1$pmU$$v^2!iO?~OZ`sA`X@9zJ#9;3;2I zNObp*l2k{upq?ycP*%7vM8t;?Kfv{X0G7KTfLlub<+f}2P7pe2PE}L9n6SdwiN91-=Wd?ffkXt7y2`poAF#e3t zXpa7uxReST_EASCb8NVz*GyN0OB5-X_%@nvlHT`CrTV6zk;NrK?D9>#ypEQz(TxVH zDvmfTyZf4tC@kcC?hspf+n|HM+YXnn$>n`ap?5#M5FYNpzTcXM!UYw@p!(xXmOt!& z^Sgo?-d9qOVna4~FakkF3?t>Z*8`vuP@OVXj{t<4btF$vw5aI+Uq{+caU!*r{`#Q1c&LS6y~0brsGCJ|1YD zX{vAc{Il}c7DzY^Ej*p3DpKVG|LAd)CvKy_!`0+EqyU{=R~Kr?J#>_ec%y^EnKUhu zejK-8gCVzNGv-jx9VwS)Fjd`c7ISEGE3rvUzR*7e>TWF4*9WHELo+x51TCzsu#2x2 zNaSma$yQ2OOh0ua3jO5H90pv>S^hrP=X7*njTP!Pv}wfk83byw{V|l0>^wP&m;JOt2%^=<7z4LHn%D`Xx*sg*_&_R{T`g6)lAQYk}M-mg{UzF?Mmbh7v#Ng-i+D^K%bs_Zl;C z<*?kS%{x*(8&g>4;fy5WB!cphr!G30%*eZJZodT?tl_mrvAfNrV_S?Je$`N}*vow? znatnCn~DEMAPbP)qO}cT-){sZ5^1dy(DNKQ>&e_+DESVt+w#Yd5o5hw!Fdu;E&0+zOd+$P5 z4aXFeC*s6EqI9PI!t|r->%=r`D=l3e&zi>x4C$S1hU3((l@_Yln0&(8hnJQ0kH0mq zb(qnY;!rZ6R%?F!H=oRRS&*cN@C^eSzu&AfDk3DZEVkl)ASrlPP~ACTNyObzXH=h= zb~eit_jF52Ce$cUx=DnvA9ucKFsET2YLwaXs98_q)$7O$)ev|&0+?XMd;GnE&VOC_ zD}749ovDom(ww@ZfFA?1A%!%o&EYdM@us#Py}xW+Pi<`2iz>$HkQ=dKfL)wHWP&x` za5v`$cx<-t0|JVZmG8RWs#H6au)f_;zspt%w&B?ZhievHd|c%Hh9*7tL}n8cQqFq) z5t;YLBS{bC{cV-Q*XHg_SwNa%2)AZS)P^cgKC#h5yr~i<{c+JCd4>C@l6`RJ;@)R; z;}JF`T_H144{9>sg}mGG(kL>%VYt{_`6Oo|Ts%_0HHsA9r0n}ad!nOnlU!~PD2Q=@ zg~eRGZ8?!Ul7`yylsaaIJ^RN4uXs}h^K-J;+II);$vJ6&fB@K!6i!Dk0ary z)Jieai}Z;07B?iKJnejUIg&U31q#?0oivOrF_r^Wa=@7A(bRi2XbG;rMh%A=lQn84 z$>PeC&`q_^#T5B)slNqTks%MUpMo%b+{^P+8-A&^H-(lAt|^uMpaQDY0Y<4!-`-JQ|2M=@Hpn!~?Rdory6 zVmq#Sg{x=?)<*@}YV6D6mPhfHek3t@DFh*HOv9J@xbt0Tz*rn+8I8`W+&W+XRnN)N znrlalx*P3`jF84T_wH%Br?y_8qu!@s5Givt=4JhgO&8YoIcQq@kp`M(kK3W8|AHQB zJtV8KyLOfB4{Tjo{t8ThH%RbT@UL-kok)}4syy|FfgDY#QCFc>%Q%G9C%@k7KV zCR;VuckjwDT`~^d)*A`{-lsYJV~4RNsKepL!Ld3Q*?q2a9Q$H&(Vk@zH*KoBuL;FU zV#aW0qihIa_nJHZp!Ux{jr{!gLT+aa;J&(62zGO)%Tq_))=NK<6OpiTtuTZBL_=XC zR#wg$9P;oOlA$;Md*aX@l?i7$petTZ&_&X!i6+Z_O=SZ=Ybp%Fkl^CPo~t7r@ZM&M zR2T3rtJ->9bL)FJ?D-F_GL2rc$0im%h(d52T|X36S!vyOrvTzXtIUBPmMJwfv_=ZQ zbgHRL8K3UYpj$VrqA1v2GdFU2caYZl9~`O}Gd>ApMv)0MRgEVtB1!yols6@&A{;Z` zUt~*~l?Im&!=!EnXz9I)8hWjoBQKZVJ`4+&zt^1T;r^8Tf5duMla~1Nfk1zHazr)j z;9VTQgYQWH7KJ~57z^?i<=sAW-}Axm0#Bb4?(lD~;7>OF9AZJ@Od98(JlS5^m&B&3a5S`X*hYB8flY|L1?}kN)5IpF$UojWgTzRFZOPCgH;{ zyre+ljM8dDDeMB4E_46SRt1TQ>=812nLeBn2V*VfZPv9A z6O=cXT=+0>GG~xNE}r#}G!)0!_z)D3LgSKqx!%Lc_B>#gboU?J7sT@-zUlg%gbL28 z3nw_rG9vzAx^5{^HKplVJh-MPSuq&~nIoSl{hOE@1>nbgQ;KZ#Potwd(I3SDwp2lb zLzq%aj4$o+HXb5&LBhv20G-eb&<`hRN?QJDqQlv^tXTWDucAC`vj5by`4eTF2p_{a z6u$vjWY=7m)xEwIfBV5djrP!`Bn-^|(cM;BfkCbg!t^dr^GrwFLsmnrSPZDrJHYD3QdPI3=3&*+^{Vqk$@jFTPXUL!Hc)=w8+ z>);suo;{oCZ0Pr?t4&76y^A6ig?Fb`*Rhp3l#l^lzEY*`r_CjVwe0HzVT0@ z><-SFZ}@(kkBU}E_ZPpLQH1Q>@o!t$Y5^*>pLODOTd73k#3{7dL0A54Sn5@0zZ>U~ep?yS zsJoDvsir2-uaA9>8`)XYmdaPk`A`+I>DEdUA;26 z{lb-i{|<_<7&XkoJG6D)j4^vsD~>HhX>gAex74rGVDLGF&n;|lXJs~+_M{ti;)u3!SL<7nPR2-9pf~@Kg-N7UNKVmEk9|l|NJx%gNJ|DKr{<*Qf;k% zGycG0fcY26$8y>!-IRX4S9?Fd;)Kv{X!1@1VIEije#2`M?0cYDp(ti((R zQE)M#^0geNel4~IC-Ei$j&ALi{~~HOOHup({i5hHiHxSvPzey}_dgU7?;qM(g?$Rz2-c7D@neVCHsY%>(s!c2@na&`U{t{(DVgnu~qdp;u@( zMJt|VwSI01zace~4Ar+uOV5(9f+<0g>!j^-AiQgg?>vU(|F&u71-cm>h1l>9z1;KIf^aFfak(^h% zg!hy_zdq(k;}Ec6Fxn#f{b?c}*#K!mo7_uS+IhBz^+nCKCSWG81(LC?T>xpiGzdE# z4#e-S1!yjPL?pMEOOXFWw@2_q60f!vkmyw>X|kn^eKK-R0&Y4dSY)d5+|Mc1{E+^w zFK0d61;da3nFM(1ekHwg-%&A4HdG)|WxsF4WL&+P-bk;MwVRABGvtDyP=uPh2N7ks z;-t`Y?X{RmDKhj(?I;0v2QKBUlapWG|JtJX0PH5aylXtpbkE+#lSE1ZtmfpHAiz1b z+0l?#h?%_(LVOgTDnXY!;QIT)qenA-?m&n7(f-#K@~r6#j)qi;?bnFUO1rN>tok*bbMHuN145fRDf!cQXq(a5L+@=g{c|6RShGO?t2 zbpjRg3{Wp|G7rr9oZT4WT&)h?=b`qPRkby(6X?;Wa^ey4Mjzk@|Ki#(BehRV zW<%xhnzB{0l{VX}_m&jGwAJEEZrW>3OId%COCF=gLk{qfHSr)~U)?k@+S0j#IA0zqS&w4ZyJmHT_j^JA1WN*0HWlsbK}z%S z2#L@AeMv!OU4ALg?`hw;{vLRD3>PQ{#k0I2O7-fhq|KFl*=nb+DeDTPqA&D=Tz0cR zW9f_Jqu;-}*))U8*M(b2YU~vw+GD``<-z3-uOR#N9=UZ{VLPAKXZ{L3G$u`!k{l^$ zM}vH!^pF0Z9Z`I1BZl;*Er}M{?=Z0|0{ArXek;njj4BMoq%yJ8y6;09vrjLr%p{R( zJlA8cOZ;oU=WiISgpfMQF?fOH-yY@quy-D!`gk)!OVMsz_%0 z&?G|KX*$v(muy@(hjm+8355F_WSI=K&uARKt);~15`&yLW8A*|(d zK-3}!fqiNo-K+lbp1DJ+6<@`F?>Hm8aXw1yB1P4>c{9;mibilnm?;(I z^@to3V`imX#EkBJa+hJYL*2}8Glt}sqw`IoNSnH+MYYPLL?fjL&ilz}W#xk44P zMGiupFuKgg#+{m+E4}_r3?cffzyWfOmD<(yB5_}YSy^|QH7!ysdOU_7SA}7!Y)|}1 zd=+4Nwdgdn8`!riNBC4T0zxbbTkb2pv-6&ffZ}v!m=z?Hpe1fkmh3#^w;3aP0zB`8 z3|x>B&~EuS(@q|b;Gu<}dI!y(hg^r(JSa3K2ziR=^K#Td0G?4i-V4gR>MQc@9XZme z+05$IE|qm}5tg2TqlsvVz;YSqi7T^(dPLXLRzG{k*y~!fVknDTA1Ag7Hp|oxOO%C6 z9g^FH-#_H$wC99f>!0LW1eHaFN7>wSR@a=Dc6MasING1bg!twN(0Uc*{9f~OiH%QV zVjq+sU1BZor)iV}cYlR&V8KRvt%Hg9PNX*o?h(#M7TF8-)ip ztm>U``X^RXkJwf)H&g+ZF=!7E;xBNPZcC?jr-NDSs$p5O$yMBY06E%}?&E03b?M}Cyn;zEP0HYXeDR91t3O<5@tGX1K{7d;bMQkzbKAYJ?HlfK`U#r7X<{|5 zo-ky{?YY;}-K8v-&Hwb*V+($B%h~Gg6M4T1u(sN~xjs%&mUT?wpK5>W`tHJKq)uFOV87_8){!)w{8oZ1g zPcW4JIsj}<lFuy zWR;fmAzmscDVS|`ooMr0E&9K>k{!vqPcI#L4gI8|R;Zmr#K9wUIV;>zNe3z_ZO2yR zlz)4dDx~;qlAJvr%$_LT4{a9S(3S3I1cHYz8Z9e(*9TODxF#)0QwJ7XALfL1IwkHS z7FHErLGF)~5l@7(!;U~xn8tx!NLCQsHu7@o5SmunF$HR%tr3yY@r|L^++d=(gXcR&)JL#~GyMwb%yTE_qu?pl??4xfYu=j>@SkP} zPsc8Xpj_OJHhA%1bHG!r2_^ffAWl1>cv~G#8i_9RmNhgFg<^X+(rl?&l-Mh4z-J4Y zo1`jMe6P*|ZbxRzu~o@wX2hFPD^Crz*6Ypj-}6*9qPQBNfdHRex~K2Pan+l@0QbLa ztzV+R9BS>*;|-36U%ljv^7tXJgN?w(;|oT9Ao-63ScnAi>M-0Pv}?k~<6lio=6c4> znf?#RXKbNxgLL4JS~ z(U_gZQ;@oAS;f$U4guXs&pl}JYC=uNOLlNT4%!j2r5u(;I=boR|`R*hBoas^SoK?Z(Y+^;OOa^J%HGspQT)s zD<&m)GRu@&8-rnH-X2dOe44Vv@_xOjcd@^8R735>ndL2Duu9Zp>2Im|!FxqSIJmtxU@m0(<{evWjyTzGF3o$cF1G&BrUKwD}gVq?)+Hv)JK-lF*?MkSda{dA^Pp;R(!?1X;3yM(jLj5o# zhIV1lomN2xFhEKG{eqKUv&FXW^13uC;R~X;mOOll?3U zkCQ%%lmNF&X4`ow`p1aE_I_^7@ECO5ZUrl9orh@@Q)dqpVoTsk^BplBI0@ZkRw$h} zdu*i6*#~Y>glMKR3e@sly9yqqtooF$KXc~H=&83qMi!pv^0W5#6F!FN)95&T z&)XfwRqbMJYwK~^aeTwBF!kDRDlT%@=LfgaN7?KWWc}J-?$~n=dHdRrJvLuNC$n zMr7K$cXgesB#ocqVt2M~5?q~vtCcF4qM)E$Al^G%J}kG^o{6StXfWFaZf~$WP`?iF z+%Fs*Va^3d4fn_tb*D2ex*9N*ng?$&UCITYFcb$M*1P{vOAq`3B;LkpS>q$nV|n^}j z&EPwlUXt4qMyd2SLJaag^*SaoB_yJ0KDtcUg*^<=tmo?+%@`JEMv2|%-GFYAsvSh+ z`jG5Ko+7hy<{hwZUoLyVn?@o@Nr)R`@tcgK?!HQetx5{tY+Qvl&oy)Ag>L&5OKEQJ zePNLQXkX}6+-9ryBSbIX2uA^i!XX15gOBa1Dr*Usx9!L}rA8<8Y(XS0Y5jRUN$Fsj z@-E99(Vr_!o!4JkrCRo$#17ef5H~^a8}DhO&Zq0LAgORTEA*EPU4#fmb;@X({|o@q zFvbp$=dQb|ZZfbJ1r^BlSRr(A(VyY~p@C6fGZ$YK?x!ShzZY^|Ukh#dftN9dI>+@d zDZ*bYc09V4Iw`i9_0&VQ3)(vtnjVX9R>C#*lB_-54Dn#o72L;*rt78_9WALAZE5ED zQULi9cm~v4xLkRND5~OxKUl)n*Hic)$KrE$o&`;Nz6N#5ZU&nVJO6O4?%3#wyIc${ zm@BVh=s2;zKre?{CS+LBYdb->$>}WN6ZMCbfbWx2czbaJnhNc-iSD~#R-Mk-t<_RJ zg}S6tGn1s$wf+=g$hGrE$LjgFwUa#ScBy&l&_RIdnzu>^B4uz3&Ddeu@wv{@r<{Fl zccdnEB(p;iWMdbDqQd}@&c$vklD@wx`}>+_uBv(xWQ7$`D1~#>Ao&Ow;tv&ao&Cgc zt$j+?K>Y=h{XhX^BjwDYRh33m=2?uXk+p>0?)xn-wG&$pLB7MT)`nccF12wJXKyn` z(hiC{SL}dC(RE=q5#2nCLnt>wTby2pLU``-erH9(8%!f1d+YYk5YM8Tr%%cV_>wmF!=-U zZJbolG~z={1^+0S_lb{b8;V113{JGIAc`G$_j(%Y>Ah*~*;m9WNp!Np4JI$(y1%z| zXDM((w=oYfYsyziFd~x@<1{vU_VmeER&meiJ= zytDFy8v*i=dWOwdktaIbuRXjn1Y-kvFC>W0zrYs&0CEbrA2&56yGss;K(&WX5^9?z zS#B_7oPE+qB{%gv;8VM0Eg0B_sM;ON%yg?eri~?y;kZ>Tii6d zd>1i8B3(xyXSbUt?Qx;oxT>Gt6djH;ky+MOAMrM{XS0v(?|C9!m5i;lGXDV25J@DU zUJoC8@~NKM@gUXUhUw;+6wPWCN_q1!%84Cu@{A4#pvg27EsY^@J*}0L_KMR)&n&V; zO0?33JDB8>Tjt=Y`-7pZ?L$$L=U273y0S@OolC}#3bDZBrf~V|jOP_X(#Fy$ovmYQ zTfrBXbt*TRG=2P&*f#F!IURG>vSGQpxUl}wXfv|t#w{&k+|UGVt#KSg@c7`aNIih2 zn=qE=Lw_l4J{cHTO?@Oq)#JCytb4GyW#~_A=Nl$Py^i1x<@gFru` z1k>+qgl(wJD&8V0N`uRiGanI3>OSsy1ORc=nv1?-+DTl;y;&sC?p|r0d)sDMEMaJh zt1)fOf-#0219}0R(_@B9>nI^>d?d`}*5YEUho}y7l0fJIBi^)chuSV}3}mIqiR4*s z1je{JZ^&HlTT$`9$jFH838&sCB#S6zIQacn-&yY7CmO@VekV=mAy>=OOJIe$S z&m^cGV6cYRq~+0v7$?vi{VOJT*J0D*x{eD*V6sgr{mCS4!AB&3$EnB2DyEWJAVo=1 z?it?wAq^~3Z;lxh5h2-)$_VB>`Veat_+8%HUA?r^TSX+WGR=0sGK6p5Azb5X4vc#H z*4ta|)oz8<_sMB)!wnqaXNAWs%^QCQa7G3@cc_e$T+exNd24?Z4=Na}Ud$JFQH5Xu zBrZARfmp`nqRp+|+l3c!Sj!ZW0GFsv*ke5%LBMaPTDx=QCXaJ*Y^!^2jkXyG2=g{R zQb->#9YYLNFCy}2G|N=kc;Z(xfhyuA9UBdtk?21vj`m4W+RD=I3uoOKhFh4Amm_oX z#sSXZgOQwcteUY5O+xnmYvd5yrTc6au9nf^BN^aESb>#pT%7x2vzG4a3)cHqBX^Oc zxPmDS#76@OC#!JXotBE?0 zIyd)CU%5oTv(@h9u(Y*#p(<|t+)E}n69PFH9Ax(GRaW-?%T70!H#WBi$|5)-3nXz4 zzqmj${POuH2Ckp8!J@*J(pYM@(M`SO^TyYha^=-?jyfR7s+Q%oZHyfbIc}o0va-`G ztuH6IX)Ynu5ANG(+Kd+&jJWF9!1SsOcPzJ(%si+TM)G8aSr$u?H<{8fK2{taarbfc zt>tTIEF*<(7s3Ay7C*Z0&14Yrs~pZ@!Gw-%`MABc6Dh{lkX6CImuyOW$>QP z8GJLQYF76WOA~4e&_M;R`*o2=%rM+8c*_i9XwGZXJbyH>d^yzY=ku<*ntVwVmb8 z?LJw=TAk&x?oTibf``67?;Yz(8(5xiwBK0V-3VFbh6lpL19W15;gx#ynoIKFSOE0}I>E;Sp*EY?9*Ye+$2 ze5UA7;~zeA?^oluyja>@Qrk&}-YC(PZKTX`TruW3Ndx6kjj#MiwPdBKYAKDfOQqBj z<59WP#IeR_f(cvf=$IJaEUALve+rS7sAP?8#1|TUrNf^*+$p)XK6L1M%Mk~iz2hRU z%YO>$_lL;1be)zc?b*4vVg9kCX3o!Iay{FH;^iRnrkT#^ra|)wRk8P#cMZKx4>ii) zc<;g%zBtn@ZuMO?FCzxx=u0P@vnfy``J>1ra!L|7^gP$jULg35t?GKc)H8UQw7VH( zSuX6fSen%VUzKA7XFD=|bCdXXz8CmxE<7u9uD*{wgm!mIkXxZ=nca@v#c*7%(pZdO z4!G-Fbuq4OC`G&ckCe*|kOhvHX+Zf-5&j_U7Hj_3Y8OjfTH zS8@(;B9r}2TZPFW{{VWsyL-9fT|I5}9X8?#qA*P)f#x%?Y_f&~0km++Kn!t)7{z>_ zcGnH@%E!XmJww$~aJ1r~^30YwL7ZvlmB8vUR-ke{~F*5wv*7 zWBu%ocJa?q+O@*Ub5iF?Td|f)nc}MAT^gxdmz%pQ&SQPC zENL$IQaCN!ZY7P1H_R0GU(Sda-03z=FWOnRJhI$doQbzT3ZRmtc0A)XvyHbtx7sl$ zx13#DMqD4@$uCAB%i7;T>9CSHzOrX!cWYhfII6w4ZB? z1!s*>KJivytmp3g=DI2E^#`@pzRfK6?Qw0jtfIokyU#5VKgOe;)$u3BRMaoOY8&4P zTMa{0lTMUa+1q)IDQO!7fSnZbsMzXLIisJG-Z?QCj!5%2{{Re+w<5WQ^H+-N?YeWr zb2L6(vmZ9q9Y$bqO8wK>yLCA{*G4q^%bhYPRtR8tBzu;TE<}-A$ftQOzs94e#twT| zg8Tru)@Jw(6k4^eqhX|3TwIT~Tpglx1x_N}_nBNWZ0W(|9tY3~5T5qPO{rMjsLaao zpCqnND69VfEhHUD|nwY8i&edMx0(wjuSnFKd*70Yh< zi9#`ry?C!lzqjztx1w3;SNc|is9H;N_LR5OEd|2d$gIk*&nF7l1B3G)rF@yJt)GE^ zYrAU=B{WDZ?KLb#4w^SWuOg@owEW7OiCw2P$y&WwIN5u**U<8KgD}NmX!}YpZjE+L z{x-4oNa;*Mtwt1p5Y6Kq__r0LI&3) z9-B{8T<5kZjV$zNuV6`S{@E;&19u^3lIB&$1YjPaw`8_LjCHF~*w1#!r`^cn?kGjf zq~JR#ZN@|-kCYw>7$&!pdmi07s&G>7MPX^Cd89g9{{Y9rvg+|%vNhw7a-|M-rVq-a zzpZN9!8OdSF@oCK2X~TaV~{7F3BhJkK@IrUmYo5L@(XzFZ2r>2WI{$hUDTM|ssIG; z#{-d$`L0`2@n(~!=zrRJlN~l2SV_2!`JpLjrcI)GCFEqc$`>a+YQ-w4YS|vW@n6AS z9r5mm;mvzn(e3q}LK7oE>%Dkrc~+TJ7bXth3D0Ggu#< zB8`P`{{S+g@$+Y%)$ne!0oK3Zqpx{n)_S~YeFRa#BF8F{VaX+cJL5*qWIW_-_piNS zxRMK3T}~r+J>JMJZdu9la6Uv(+<8M7B%VtO$yMfUE{BnW%%@iwDl1sVDc{Yvr`)b* zTZ3h$Ngd>Ow)&x8BMFewjA!KshQR*->*lW7%Fx;@_b`j4!ZEvs=zW*Y&OD;TWS%fc zz{wnTs~0dL*}}GQ!F18g5-T>l-ss!Ei1p=q5rJ7-Ewveh7qdloaUH>l)*szPZzH%O zHXn4llBAq<71I}FdwlDuX42X#n`tj3)9*al=a5fo;gMjK9}lpcHvDx^aC-q)uB4Dl zrd}=7pK4p;jEbA_Y|-OvVQ|O!)#ZxIb+(r!_50pkd8RRPSpA^JerZW#@)8bIjGhj2 zRW#_sOC7v|1-U^RMe?wg5;zPc&)zHPz&)xRub|}mn(%1?XsnprnW3{Tmg{jKWOj48 zgD5|JN2Y5|KP7B*%|=^saX!Woh9D$)7!e|lhy9_7#}>btII zxUmkQqJ^zNU8Lh@A9FoVJ!z6!{g=amY*$LuBC)!W7TQaOD9p{d)Va6{QH3wbpO6&3A5LS*$m(+JVL&cK$Z{ z5raVQVwHu}#iS1`Q?zRg&m_~NIdYEw04vAN5c>7}D^6cFUlv^41%?Ukg3oOBkNfEM z4qaD{N$NX}wH=kUpWE%Nt+d;V%~S0Th+^C=@r~-(Ck#OT6IxTlGHK9X#}&WZE+xg< zoHTGUuPDTj>R5ciK{dRi?vw2`Beb{v(zW|B^DS*<-y>blJhK#^#5ONX{{RLtntDMq z=(krg+*-`|3v7`CBxO{EQV`*}83Z1!`BhstND_Nxl&sMb&onQzN~f$?IV|3UV-&A( zIJRr6lCj=|^WGMO$0TSo^C>wXf^tD8oK{I(4FhsoNo<66PiX1{b2=3$UzSOKzN$Sk zJ*!C|{?@m9X*GzWh+73n(h;?ZZ@HZ1*Z?!n85N#fTwgB_C|8G8&I03s#^O7QB-3Myw&tW$sMPfc z4a_mI^1RUCg^Vc4WBt+gZ7|lpCu?zO`6HaWrlhZr_!+FLl8fO5)*5>27bO zQ0CPqF)WI~mw}C>bs>F7&%Il=wR?SH8CEN&vX_O0GR&7?Zc@vPp=S9=B=pTbf_t5; znr*Up!DQ2~VYo|jH^*u`=@$b9ZX2M(a1KZm877RZ5nB1p4(SM#?v@jhNMBaxhUU3_ zKJ8)Cbtxf0(KBLnvkepkDdr%@BWCVN<%hj?q+8#AW!+p|MQe1oJS51_(dC+764-gy(t`|=l`*MPmFpTI z`@r`HAXaJ9Qqak76e8B%Lo6=?7LdN*-!m}(0G4aJp&6?-dXz5@nJT(KEWnYifiE8K zy68v*d*=k!zhp-G%?7Qgg=p7K`$Uqc0^bqJm_NHEeGW2x%~px^QKMx}N6jM+EmP zX0gcjQM)uEGETvRoVE`mpRPv~<7-`znlGjMEH4eJzM$_np9l}IDb5Lg0V;omd(>{% z66ot_VZQq~keS{GDqcqFn@`?U{d-naL7>y@n61m~W9K8w=F0mI%;yAfy>aQ&6|#|| zuAL-PT;E(uhwU3CCgMpq;R43l3WR*b=aE#E_bxA~J&P>bDm|QY22i*GLhS+e ze85z!%O$nFz0J}}mdvpmnW8LYn|@ayVX_yi43A+?noGNT2ZL9Z8^-e$TkNP6i)RYU z&=8}8nzqX!oy2bUBHctUdvHu;LFyFaJN}%~lyuM;XHok^8n}#&MtIDPx;3>{RCXCy zYW}DDzT>C8C`!ay*m;;t97~t*x_j<7$AZWJtD`9!4OBs$g@>nw{Ck2^7=Z~A|Qx$M( z=C_-34zoRw@ZZ?%;s?9kGbAq!nyr9mA1T?WVMN=Z-0EAr}gbc9AjIg?K`z zu1911ReEgwsGHlU($t?STd2rBZ~);S1LoxQ>+e+b@qKe^1FFLX^|T9;k>Dcd4he1? zdH?|(jZ$_YF2vS`<4?7NP)U)-9U~U^BsAdkVsbWy>5Sxc=}c=waxAVS7O-HMrGoH; z0axa2z4v3Lc_yNGY|f};TQs)|nbcoLAXvU%FYX=!HbxlaeJW4i%MG@ama)NkaRGF< zyosf09xt0RN-?yN!U2r;%?;eR==B|WBeXL~VJ|K-2uOg>rf-hrpnI?y_8YL(U_x51}-tQpX*y>lW7&E z*k!N)TWppQ5)i!SjPs8Ew2PCmb{lqGPDN%|=7#D;n&7W7lDpgyo&X$snxlW@&v~U= zmX(#ynfrz!QNV5G@Jjr-;i}V5=IZ0@(Lp4FbyFioPwtg+;m&rFr;am|Qfco!oYoJg zUfWZX( z@b<{XbhEVY_7P~UaXe8LmOVOS8pNN(26#O|BOPj%m-er=ygQcIM|$wB`_JYS!sIbS z(6>%8&w85L?Im|Lcz6mcPvBv^<^ zcMm!}t%9m^oRgFEC+kzf@Xv4d*h{RhAcxIh446)#Imsi}IjEF1&>WSE(_6_L5lWpF+~GMad4`aa75BWAN=$iLEJu2#2!X^`c^xavyvI0g|#Cr?)I|8OJFd@ zdVHjJsFu2fUD(TOXsxZIv{|mN)>YiD(~`{lI5{L8!=d)6T5D6RM{6AM#}QB_w_9c+ zcHj_u1Dx?oYcz0Zki`Y8bI!7>JglM7JCX@M#nV2ua%H+}i;pYGONC)5`#YA{06QLC zz-^I<`-3^fE57Bl32v9V)rfiB+TKYvk_e2b<(H3`mHle`?H}3YbhEp;o=bBd?u!2a zrpM3)ApZakdXO7~OtzIKw?I@uc?lEJvmfCY1gnHeqIoX{1=&G#e5Nb%7$a4COFz2IlOz_2<58T3K3Kizppk zRmmaYAftL<_2clUnWK`?)rw1P6sOINoa1OYPW%DIXU1MT+3lk9Uiu{ykbsYs^T1Qb z*93kP`9{qfa%Q`^XIYS)!brB@4#0&u-Sw+5GDwjZe<@W<`8z-_9xw@B!@oS|)1^_g zg&@@+jZM;#8>T18EX3#Ue}!I8HcO|%2!o7B$T1>;z{$=xcluOK2z{)}IhjNkDH;-? zjqdyS=~96(RfG`5%Q;j2PnGKiSZ4+XzJ4up9urPELD_4{EY< zyP1waN`@=LFqsR6jE&-X6|#0bvXQ}0cfNutjbD)ROLw> z4l(^rEdU~@R0=Xc^(3FxmWn6X$8N;oHllifPPo6S5V{eL(i>_*Vz;vJ_8; zV&!Cpf3&v$05T}ThXX1JIXO5SpI=Uuv>&-6#0FOJ(_}cOTO7$7Zjr$1_)(5_lSF9qE2eooLE;<9v2&-1%j-&-+Hj9N zU)u`$&8@ z)isH%p6=?v#^|4Dx$@Q*X8sjB_hnDYa-*J^rR-(U!vW(L3SwlTEKjnN=~6O->-@^y zA79Y-+AGeqkBdJKb*lupwDCTj8nn_v7Ulex+>BJ^TL&2&9^(Xcu8?@Q!pzVC;!O)P zF6f8bqsxqEBc7EmoYv_394{1P_?Rit#nY1VoL}m6G*$}utHUfU%J_>zVLKIr7txk@%BCd#g~U<`I1!__r?Q+%u7p$n_OU4~QNJy0>X`jDU1$DVh$92NTywUUGRmS!^J=Lz?EDejVv9Vv)m};sLv-D z9r0K7dYz9xe0{@^z45g4{_;ISit~7WC+M@@d2#7pCGz~uf@5KXJZC?9IQ%O%%i{Kv zsgQKf4tT!h1;>)+T|eyXoMb-PSxHZI2CM3|f0T)Mfy1%4`&?c7UH(Y*sw>Ld;%&o0 zZq}Xw@x9wzMr5{8WU1!>+gklTxttPJE$B+^KQ1~M?e#h#r;J^E1a(zWis^Qt^w zg_NxdRbQn!f05kLTx4g*(mZlM{3AB#$lIYQA!K3G<_tm4UYt_HZ{xL*8huB@vnfA1 zEv$*OdmYCor6ouE%kMT^M=4s^O27CDU!0TtF1n+#qPX*>c&2&Gmm0;iJ6L&Q)G~rQ z?#LkiUyWIZMAXD_iTpvRN_R1kt`x8&;0$#AYQ2OO^IwTn^Q>h@?%<}En}YuU+rOlA z^j9o&4Mnb5&xtjNl!XehI$}I^`^wvi=t=xJsn*{V+YMT{>&+ z{sytkvGV@_m`1Gtp_3NVOsH`ZoGZ1zD+1DLU-4At=oq8N|_~xa38Ydq$_Nabc zxcf=R<EVqS7 z#u{SZ&oub7YZ#cYMtKkMvFG&SpDi!u`~g?Y8(+GL{{XkY`(1wnL8pZqYt0h2GlJl8 z>rtD_L7d%N53Hm7Ydw5FqovWEY+?IB>nX`&_|&IF(hC+kZJRO9S)v4-`ktnXQSQn1 znWOso!ouNfRjmj-#(yZ}w)NzdvHO z#sJ%}ZR4jMGw)IhD=-)fOKdUA4=i$M{nweI{?Kn;PsjcN8|r#|dv{&Kl5hZQ{{Sx3 zkE&S4z#D~QoMCy#za6S|w6#O>TU)35v4KxmAxGSh#Et5x0iyJ~G4kdQ?L~Z>{Z;<} z0;l$+hCusD9OndN=N)OMSFpzuGn{7vHqJjPz9Wn=A~Xby6SkaHNWlP)LMdLCXZQaA zz$@9~n)u`Y0D!;#NY8Cf1z-$UIV0u$(fPQ~6vWl7_AP+Lyk2(alf!e-LzWm;NfZ_#WS_+vNcZVhiYsSw zt7Ks0bsm&#KmZD$0e~^mo#EJ(3|0O(+tL33nOFNl&ubq&4%31FIUV|Xd(*|`qXI?D z2OWQSDdyhXl1vbiPEJsBLt9(CitPj}$}ps$;-BvP$x9jDKXd;8F^2NcE=|?27|wjr zN84=t&4%vVelxet8UA#Aj@JMScvKFXPz-)m7}KnP1MKk-Ipsm;*XvDtFES+Y-4uTk z!p{SOQfQbCxNvb&238qX3_U@rU)i=IS9P~kch2TgMLBF>T!r%$Pw>%1r~d$G+T-SSPBVgsr>!2!eTDs{g}YwSY35#{plhpTMrWQRRT*OJ1_!ClIcI_X z?9n&T!Kvkaj)h*6cIIDsEfj%)0D=fUhL)t&JB1WcKm`<0Km`<0Km`<0Km`<0Km`<0 zKm`<16M@j4dr$(=N9#>eaG}N=u1FamemI~9QAHF0RB|AZ0+K)st;ewk`c#yJ;AH2n zDXqfx05A?cb6$O-1OEUEH^d5Ud91YKg&M}Pjr+nG! zF`rJ=%6$N|&FUlwPtA<*Kh7z@WApB4=s2JQoO;p_3#sZ<_B}YIz#!yx9ExiYice1b z4!*P@p^oKMWN9OYFiCymx7R#SA2Kf2kIN_KInGa@=ADIT@>3x5w2$-6I4Z7os9c=7rs`ZpQ3$j+vpbZsSOO>O*{>9E^4RY4lM@S3HN~e~0{0;vax| zoxg-`#9E|9Ws=?X7P3pY0R~vS;0cL}gSJe3r<(Yq_Du1{r{c{U#GeTMB5GHf?u~J0 zTG^?3cGt-L3-HH+d^O^rzRGImzDa{c1A2bRm_ZL{xIA<~Gne z5>KUgHizTe4I|@Dr||E_63+&^6zX)#>1W=$oNe=_6-E+M&Qx*o_UT^us3U|f<|?DB zwol?uCcZ)Nw};{Qhx=cAYP;6$HA!^qd&?V3NS!6NYet1|@>|>jH!O>S$~)v|itNIC zGQP*5gte!Azu=!&PiYOr3MUMhkVz3oD9M44Ngs}Dgk5P9NQ(A-OllB$sLg9{VkVt; zy2g(huPYYfS(xtQINAktO?7YKy%FWqTGr1&u!sbZyU17P+MhEVlaIVlayjc+I#-4) zExb>4t*@4oU&zj(alH}SKPlvZc*=u;T2iu3?@or4T35ct?c2B8?>wnwdx+sUbpY-E z0AwHG?UUPz<@|5rxcnXPuT$|PS}v!l&u9afAh&mUN$M1*BPWdX_N}Id>-#GD+F5NZ z?`D!oV|y6M0EWUyLv_f;bIH%)S4oQE)nbMfFiSHm z+whU5(n%#d6)!!w59Ey zoA!7wgO~G-mLhpr{N&>so7X?BZ^#QXGs=r{RH`eEa5><5`_^=699k1L*%nC-{{Y+; zJKLiiXN=ILc-Y=DPBuB;8Cu?I9tzei;%!EId&to|%S*8fjirvm$0*-*fWazA6ipBtCeO zJA*2i-BmzhJF154c|73yes%m?({(R{fACS?_*^mR`qkHmrjpj+e`Z>F=+=fGvr7x* zvfJc!VYFp@vCwt2qMh15G4Uq>C`SvJ#eV{6zwqqeU60U@E9`a&1IHvx&E-$Ld4Tr; zh~V-^0E6#UWoWEz@1}-%)s_6qgk%O~z~rhBdC3PSJannNGpt+qlfim!v!>o!YL-{b z(@ia_A1xa>*gIz@8;Iv`Y>KU_w09QG5t>{0U6Gk$OiDMl6?b|O!D4s=@vZ60n?v+` z4l^MpS{G550UN`($cYa@crV!vncqVM!pkS&5ho?UE)ZaWJ#TxB`A-UwLYP<&oHlWN@7{oEEu~NJV9OZCM20>ccMl;m; zUlAdQsgPnLg;$$ND|x#=!sNa**IL)Y-XHj7;fsrS?FNddk=e*M+*<`qpEU}}4$QK& zSi=kqcCP{W+wel;MesB~6EsP6okPVsW$?P!Cev-&JGryMUBq^UA!1SrjkzFq>-J~E zZ-mommp0xd*0rrW#TS<@O}x5Y*tmijfp0L02nxV4=x|%wyU!A6&*Ci^^dqN>%RN;Z zIc=kDjUp%|zW2(-v5mZ76P(gXMQG21$v6U8=33ri7fmH-F4}LQ<9`FbD36Oj1T>98 z_VP=;QX;WkMRREIT<$C8Tatr2m5>Hg$jLoA4;THZ{C#|%4D`W)7e&+rDQei#1J<4DzSVurwLBTMq`u8pzLt`-(``IjO0Aqo|a0X$=+ za2_u$#gEI+9SuD@{{|w5qPWNTX=s$@Lsp$9SrG~BHHM|daD(}%_7Kr$UqA; zi}M9yK2Uqt=*NZiJu>g%Zj-IprMor8pkR^m10&hZOH&g$gDzwM;w#Vy#wJF#y<%7N5UQ$@E?dS zbkx?b?-t*~zuFhEK|O?WDSg)p8v!4cS4{3Ew~S}G;CNreINZB5UfyltYAZ#%*>?N; zpH}M{lpY$>E_^|(*}cjQ=+;*Ve$NVR!|s%0YG=MSp4IXEV_L1>ViD3A};tz&8Io0koo8xb8@Fl>J zwOIU)#2YRbcp-K~M&Mg5$N=W5{8`g} zD11ivz2U!ycA7q+r1%}Dhf}oGe#au|?pboPUd#qQR#Ol`(6X}vd8I~-?yT&1oH;r0 z{d~g@3N575id|cY^XG*$op0g??R%?fI%VaQx((KpZc%-$2O$2TvB&%l_mB>9#c&es(2@HX8YaLltvaBT;GNz~GGzQpt zH?xE$J9eLvn4XG>^q62f`6EcT>Z1W&qSU{@JJ{#F?EcKWqd0y1LxU(;bJduz*-M=rH>Uqyf_cpW^vf1g; zPc^g3(#c~Rk{WncF!DCy1~>DO+P-W3ri>B(&yZLhv1vYZOK@%`kzL`D!DIn&6;!Tw zdmmcb$LgF%QO7K=%lxnMIp5i1PX5jPlB{iK7nfGW?ggANZeo`5O6=1*=Pl36yFQq& zq32R`h?2t2ep)BMofl4WNsOxSL17X6Q638vG(;Mx*V>ts7pSgv&AGDjlq}9k}2+X zqP_@?_ye)!agSkN7k<^6P2Q#O{{X_5_7-WS>9!X^q;t zz|<^-uZL1ufs*IX5*D|0V;d8Jz0W5ez*m_3U+_rRJ`c&KwARww~xE=Rb6cO4q%Qo#Je@Wc&7LXKm%u6T z_WHq&yq91@cCmRE6QND*6hmFr_Wu9?`~&cJgw2%NmZ|>$2}g=9 zC%2kCL0RBP@CXp4zei9q8KfbJ=L4m3$x2Sio@Q^G=lIIMRLki5HGO9-lG{bqpEUR* z;kU$(j1Jy4@s7DXejMDQ#wm=fFFtdfsr(}+JI}9PmG)dZMXrr!VWN0*!;#x*uv?hz ztl|S|zT)i5C?tZcSm&W6t##U+gwX0~XqE}6SVpVk3NjT(TCW|w zs*7uRo*g$&LeMt%^0woUj7MwEc7mdN4jQk)!PJ?k03!xtKoqbR~w zZD`NT&$52dzqID9XQOLc4vV1pZSFkzn)=4--qvuc@zck@3vd^dCANuh^c(6qg8RF6QsSCuTZrVEbadkM@3s+e`Ri z;%G(v%w8b3)b^O{?mkaCmg98yH1I}~JeIYts+v@YdVR>VwlVhHofu3rY?EBz2d|~4|OYLsj zSo|vu^CMf~nXl%<777q-cNKp9g*&7(cX(xhX;;KQg|wr#%U8FXYvuATJXWzoCC%hg$ER7Ux0;%V@32M_ z862NbK*mQklX}r#HM>cq>2b7jZ^SBEOo713?gu<$9rH@D{jTO28~ZK`hJoQjJC_ru z@tHy3w@mdsaf)KZ_cm6~1hGjnP0h;8SuPj;dPkgOB8(VvM?c}+{(?qAvAP<@>9E>aUllaHyS+YniqO`VH-rD(YTkTQB z7n-t2epNon->%$)#aXes`%T0Bnp=B2hb}jg>?Tr@W~G1{1X2jYd?(rLKc-8IoeCWNGGpH!O{uka!B*1Ja?`6J=Rvn$N?B zWVUcL(MTLZ?1l};CHM8g^cA0ZYjb#FS?$&+zjj3B0*H`usg>tA?sHvKa)~X;{oTC# zxGqtx$X>0<2Lrh8+OYo6si|S()Ff-I<(l6dY&=A%#|Nlxc&bt{Z&JMaOWQ&`t4TDy zK_*s}-cZYMZhqR){a%S3RRYD*_2Uu}+%aMz*&ab=uv-DyWs!!zmlG#B+smF~J8I z6*9XLX905aSldMeR@c@yJNDb%0$yfTJHg33Zai(k!2If+^fJpXoE^hnMJhWi5pF2U zl03o=R5>{R0AzK|b-Im$YyK`((%>GT8@}v)h4zP z{fY>hIP9ibNRflT5=e87JqSManQ7{0PZAFiK=X=Z7y zH7mD!t63yyomv99jUops5r#SRAZOm3Yz58L?3Z?`@m(N=pk1y)BW(0{Gm5JQmnF$tTM7J+w#*{9 zjLLs_SNEPv1IHtw0QEiVp|jJ6_JzKot3_b19n#9S?%TYU+rSOM9PmvBcd^gB+KsN2 z_In$6F2>N?;@vE%0B@a;6OzTq$vNVvIf^|-GO|rEF3D)nozQRFkYBj;DtQOFtM@5s zYY~oenw`-zf2KurU}gokG%BNz<-GB9%p7g=wrpfo=O_m`^{TeXr&?+gJAILK@fpO5 z+g3x2?1+#-BcW_mIiP~N*yiK33E|OsB)1c3pJ{ZOAfii%#y(I1#_oB}NXO?|O=mUL zgt~3}%W8*gS3=rPDq@6ZB%JMaUI6}du}d`GB6(!8gY5xgjxo3&vw+#=GI6_a%Y&a< zNSPda&epY(~cc~C}oZRk&a)nb&cib(|DWHH4$%I=ERVNiKdBOGwU?-Be% zwR1isyzv}bwu@om*feQYT~Er^7XC+yQ)r`=jZlrUNO6Wa#yJMNNFkERBL+Cy#bgeq z#scq*aP5A>#iI3Vxz-q>!yRag=`3kKF_w}vQgE%9)`BTFGyz<`sGjGa|b91XN? zA-KB*hrumCa3{DX5Zv8$aCdiig1gJ$?jD@MT?Y*o2>+Q=_x0YY``Qov&{EaC_gdeF zDf&83upqL$Bumg$VGw4Wvzt@fF(ONG+9el(j#^(Ce{(X~_57ZrByPuW|%8sBF z7^95~s#kS&$pNNVcYGDVEOc>d_|g&bhc&r1Gm{g=^ghqHQkc73R6kB$ zwzFd()6VOe=w-s0=EQeGE0j5Xh%w)5KX05^F-v#wwb}&t8+n(v!*eGdG>mx*XUz9= zk*7=b#)MO*iiu-(iXL$>Y|jSL1SRE|EKFXUNA0ga%+I(VlpG_3K#?uW36)FoMTxfJ z45;u8^V+=2cnH^LSC~MeuAZ}|WoF_P^F25{9q~&E8N^C}uA50r_q+fA^1h*t)U-?E zx3dAvD9CS_nIvYq9Fg7HDjTlicYn?kD(miYb_9gSzRvutk#UuWBc2!dLsM+0&ci~s zET}78p)2A4Y0`FPF~U@H`|jCeyg=bF$ytC*gHAglze0c3*1q6FCP66HV2Hd-sal(Z z%0Ye2iJ#oAX?ZWoXtS}yOG6=D2fJ!;zx`AwmkPJyMVu$ScF>)CD-j>;-;r`Sa}P0R zozqLESlv$p(JmCY@>lU{Py+KDn(aUmCQGfLPLR5dD~gRnFeTIGBE8w58p@G*P6Jz- z=4V!ET_MXEE6tAf$mz7E^JB)hY9GSE!^JK)kX@`@u23P3UN$`?7!5U)yC*C^_piCJ zRYGV8b7?#7hK+(a2od>N3w;v8)TIRP2su03g!tiW~Of|!=;nn1_ zlXKTUsnT|vQLNZ~53c`}oHh^N3`Ra!{|`oVz!^Ppy28y{2A4I(Q{%e9J;h)+K<_}E7qY-*)#dk={c05XFP}H zGx<_jISP$SuTfvAvoDHxVGVF9s9{Kd8|c%cCcB2aDL^W7-^HSS;|pu8>CR?jM=k2& z66~5K3x5DiX{W%st-Erni?(>!f zvqS1lZhbTF3eO)+Z`S{6=TRhl&R4Iw$8Za~#Ys|G zaJo8rW+fMuBi&xwp0Tj2ubS;}wXIyLxfeA>A{JW!Tnkl-RqFozNZJWlZv7|DzsZVA zE7+Rbyx5%N8u^PnQURK?_{|^iuV4tww4Dex{W(Mscl?t>qCk7kjiJo%@OJkgGrDa) z_6K-}KHIEBf0q8GuJtt4u0sf_6IA{M(JJ=rnEhy|7a)?si( zpHhhI)Q&7~t#^>RW%<$C!B8=Jn^+7XNPXDFAD2bu8Ay{TV1P)oF|eNiS6DUc#%=w1e1tLv>XwP6TjH_^0UiwH zAelB!&?+-?8)E;bc@?jN9zS|^ru!SV+Qb>>&MECOI!gCJzg_O%?AMoblSX<}FP!_G zzgCa#xHr!KraeR0QhKMoaVA+~bV@<)#8WWaNK0f|E6tnjvj_lG^Zvgq6S*ww9ueFpXD9${QFilzPtt%6K=UhyaY% z{{FT^wdK=p6N)tR`XHImGtaEbq5`l233p~cv5{JPH%qVx2F%O$f>4W%cK_XdRd z{p!sLq{>`ExpvAllLy|&DRL3G@Tn(Bl>o@rE+e!ZI$}pFahR}4slEM9pZ43)<_IpM z!^GGh`1dl^*~jSvn*mm?ag`Be6!VS6+XJUU2y&JH5r zpy^!?7E*0jAwf={XZ@`pur;N^dq@l?FmC$_H~RcUf$^`!$-Tp(J!W1V=c1jvZ4KNv z+riZ=dW-V9(%AWmh{Rt{rskI^8#xlNs{OfOlK1NA;iDe|tIh47FsNQloe{}m@_V0HE-(VIMs5pE{j)yZzV#01=uX9#$m!7>P6w z425#IcDfyLjS)l-$pB;FiEBy{b*f2uL`ky>+r6(GU|QYC1IJwGoQ@&XzHAY*F_p{a z>R#S~ShAchE{{8}iq)g)54lWBg929iESVSj0|qn7;McmgE^mgvlp5dsZOFHKCUB?Z zsabhPJIx%bfF>yW32V8{ov&EFh-C?T4^-7!03U9D+-q=i{ql0LW{ zTHxQ&Q0t~FsjNQS<^QiNKlR%&Vv_E*V{~!)+{^Dt)-rkUmOrN<%bTK(_2upE{#+f> zlb;NRp`XkZjSE`2l&?5^T!a28d6j9E;<}=d*mBp)6!8{ATlqD}h<4%Kzrhy!W2{g3 zZcAO3?Ot1FbJ*9uK>f8v*hOxFs7NVuV(dQ{+k<{9a--4D^TQAwXuOw$qR!H_)6n2k z?s&$r0ph3EgaA4DBeUZRfmzoNhE+#*j`fB?!LKKZc6QTi-7P74>7=+0@ z8pL0Sp7a7Eblc;ar!>dT_=yG(-BVeUJm<#rgLkPkUB-Y~aq8!RJui8=LVjtC8XmTq z4o~t8qw8ny{)cvAkrY@&C-bU3eI5C%wR_(0{cR=K&E5$9D8~`V1P`t+Vk7;yJ!}UC z>Z7_nJ|5{7eJ6^cl{{^Abv;OEj*VRhra^~PN5GVklhV7e_&dC(Nl}8|ZOS~*8l*?# zkXzmf)A*uY7mzb^c-|NO>mGN4%l}|Vw_8<%yR<^xCZK`8H|$GS6Hz|_IMuC9U*<$j zy-6mYtLykg?WTSw9z2T(ul6deKuGRocpV-;ApK&4^&i}~E3LC=2FpAfH??khjMUil z6)r^6Usb##;o!Xsw$b1WG`rsvY-<>vjDr1yTq<>BD5(AGikz78gEa45`3QuAjzaI> zOY&ZygWvHgU*^YJ&UO7SN1AL7KCTprofB z>T~=+w+>jtg_J#7b+)dyhP2CWu{wr~JVYxydWr(4Ox@NAJftBEGfGyeV?ZMXKhayv zlD!6)d|HiF4q=-r!>=id-l0xtm8O2JxPGs+Vm+cET_DTmu7tlAI)`t5(e@6kn-FYi zn)cs4WR3Q&s!CA3YvG&SC%d=W-<Ap1EG>DElcZ_UJn^lZXTmkDpaPgR7YflW@9C=^8^ zqb1xz(@|-O-EByuNIOVXPL3?~UzbESmK9wVdfGu)Py6J>QpB9%#g^>zr>8i0Hl{&rC5)mg@^E{t>o3ZRe}42!~3-91c8u%Qt30gIZC)b%r1) z0nC1N*ZM@!vl3mm-`JFXoTPfZolS70y45m)>`Wwp^FEHTV7ziqR(ApXYh5rrl%v0< z>0tTHdmQm7poXc)dmRu`M`~9^mq6Fp-V4ffMO=FRS}l2F@H++OadMKO-?pu4*b}kN zKDAkY$oyxHr;`A!kgE znQf$9?W>x;;ZO}33!Z}pd}7}(s2E7o+7O=Kc39OW-Qp_dX3155{BZnRmMreUjiFWtT_p^lL&e`#7fs6ohHEKJjLL))iZK{CvQ7e_fQb>lOnH zOBa}U^}+;pco0OF>wa@`H3xMs{y7iL)rM3AZg-6Deuq^Nyi0&KC_%2-_m@OhrEcc| zxfHV%^y1lIN^*~al03{IkjmL)_7EG_?x;Gh!@gx2O@kCrLLY-GiGt-Y|T^te%6^FLr4}5dVz$3Xj4w9a&q*D zArZI^~O!wxT`~W&0>m-xT{B*lM+DnQ&-9n-GwTdU17DXGu)rhUmGyGA1S)eK9~%gzx>g-_PUd*Xc){SPM75w$Pi(&`rkobxnmWvQn5v6#lL zDfe3yoc3?A=cpvmSKztoimD@19!6JDurOYrwqt0oJKK zZA==f5{gaN{2p*O`8M)A#ti6O{?(uOovo7eEhAYtD#D`?8sn2LdM+SZx@a)$#0s>j z!cX1Vve4g_Di>~`wfR6#$ew(v0^>PO`kM)jthNvU=>|j{cORRkI`(C&+g0mqiD+5JLuEjD{!h*1yA#ZO5N z`)oM`Hz-JRn=C#H#C^jPW7J~+K4Wq(m?ikvC=hE7-CN3muZ8^QzurxF@{HdK#zDsT zsX~)gaysg5M?HO#MhUBV2vYxSVJO*tiP zJBjS}Ntb<26T3Xk6)&gG#->49e@EAw1PUJZ@kSR(jB)UJ^0?oc7}UIvcf7J|{y`9LH;Dw^*#EBV> z;qme`HqdYE{ob5*=UJI7Y-~_|P@i4brRH%Mi`RVGRkEpNkI^>VIz9|>hyR9ov!7I$ z?Xmzj-)pDewo*Iki%Lu#p%Jn>qu#u6^r{q~eI{|X>rqUkbOvmSYc$ZeNtR&lNDwMl zWj>I)KTdR+`sC&M#S>b*TQ`nTR}jpW2JD6O>TLU2~W-?M`X6^T0`R!MvQ$zbz8HR zI!Sea`)z{;_YgS=3;a_J4Nn7gS>#!Q&bizB`uArgFeyGY=!d<= zD>1RStHgyrdKx8;w{;+iQ#uj)T-Ta#A#bvhB^0Hry)l_fCY_iW@Kv1HGsd8efn@n( zdHqu)_=0qU{g7d`w&gn7mO{0R1={ozpKOo%_n8+m;o`2G6b}O@^Wr)czVm~-8wUmnRU;%W# z_RMY!{#ZbFW-8+Iu>a;Y?O^U;*}^+3%1-kge{66LM)SC^=brdZdQPAUiP zBY@B=2$f1dcYd)UbpJ`zwUg`mbsD0)WUomC%1M>PA!&5j@ZJh@^>m{RVIF9-i#u1B z^?j18bDiJ-HKGO>hGEbCc9r`9E^nv7khDH&>69zY;K6A*5lDL$8T>O@#colsJKDat zxj8mV{0}@H3KE%M009fjaN=WJ?c1;l8KS`#a`ej%X^r_*iN~3=C&Z4(Y7+1i$~F?8 zvJ6=~`fwT_0QuVXW4xJ`j(IK#+f@u9j73Xvv+g$N62;LJ#@Gop9cI5MpjL_LzdQqR zN4Ae${I?8#JT_wDX~fCb-lpWA-z@5cqm>g=|CRYP&*;i2uwc=7)8=81xQWeW0})O) z%9+_)r}^@>B%FZG5!SzrNQ7jzYemn=ZD+7IH(S{_z^liU)7jsc=q0;VWS#p)esYz_ z``e+)Wz^2p(29pnua{(_<~<4rFJP`X#}7_dHIbQ`M&NtU2Xa!SH^!7)?{UBa=T}P` z?Mi#HEpb|nzNSu08GOO~MkIpeP>L7R?NnhTQflZw+q*r{fj#+TexFQBmV)T&b=aV5 z(Z9i7&Na?geM+YoRoaaKwun#fIyfw4;aJd?P(&h7=3} z0aaU-MZwzpqmR9lDN-pIdlLLq5Qg}P3vHJ?UoGY?3xIBOvo#osP>idkkkGoE20XaT z&)jTBlQl?|*Bi`w9_!7_lS&qqM#(6J)!a2szAFV>6qL6((!2@8@Yi3x-v~2H#tp_5 zx-~lh2xuG5V^$)#ZLIb2TO+=!`E!}VvGxzWknB-N#$o%e{`QpM^AMqK%^b4rlkz0O z?vP?cJ&_bZnbR5AYiRK4K9zMj;4HK0)68@no{p0s${Nx)Z<^np_nF>C2m85&`!f%?pe_wHj7WpEil4_I!-cw*B0F}o`WY6<$I=SiDz6x)`zlo_b zb{LaN^hc?o$zv=ytxUprAd|1 zSH|z_qPCoa9n17X5UPSa$U2GaG+_$UyZ+K3!RsJmabeUBzVX$itrNK!F6Bb2`T26r z4nKFPvpT0K)iV&Y#0=1+G|B*9Hjz06F8#8F>1Eb>x0*Bna*>MRLG#GK&+ye==fdem zmoSt}UdxGuU=Nx(k&iZK#dgVlZDfj;P#b^{pP`Hg))_3e@rw?duR8a*!m-HXJ6{=P zmRNQC2V?d1)MdP*{Vg(@-M%h7*5FD9qwMrLcaj0+K1c$#7ZdoZCE-+I^Mohw@Agny zTGO-ig|+9sXzkbOb)Hp|KrI`CA+)qFmcFTP`RgQ)W;S(DJM?obJzRo}?6|Qs!PY^d zo_^V~8#BYZ6WXF1+lVVQr}^!&`$hKlsWN`ENol*ax4G}ORm&q;l`(l*mRTGw)6`Qi zVs7;)k547t&?85LP^>Mo6T`J}OJDNS3_b-(CKA#b+1?6-ohC=4YmDwqWSF}p9F?ft z)BF^0inP?w%VJk`{WZH3B!AdtJ!lH0Kxqm)FZ3vS)MK@(Q`VG7@W zB@-X({5(w;V?q+`W!ARv^(XLq~UGbOKm8KYwHnfqr0DA~t zj}nwjg05i5%*dVuYVIm^G{?SCB?owItcAmsn5~KStSF3fzJ1JAsJcAm9vgq_v<9Z; z88hu!l_N6Sxks_4jG1fGCTBIvcLNKEQ+FvnZ%Y%b`+e!=bMX~+tmQfHgG3+9%2la+ zmiF&0Kspc$e-Me6nMoUBz%vZosbkEgLZ;nb=u%q~A0}!t2T%!4+t*oD;#Fge%OQD0?SxP0r`gG2 zJ^y^Yh^@6Dn|3oRX!w!)b+c>q8juWGtKlvjRe?oy}74;B?l1&IwOfie$5S02|Y6UQh0ciFx;yotMm|h z{{0VwiPw=8(q@~uc`78ic<6*4-B2kAJLC)J@+rf8nHfh`W&CIISD|40hCn3>|2y@k zvPNVHW^p>z%2LvvvAOO3;e^)y(WSdmT2B(%Bro9wYS|sfo`=Ud}MgRH$j2S{`hg#!{~76p&>#E($I#||D%PG zf#Qxk+h0to6)gxxo;k+}xdn#~44q%gX{tBam@b{K*p&|;h_E2!vQG{YU`mpJNx($r7qN@${_V%+ z9Vl7`+&}K>{9eT~3Mn{Wf;*v3VeSU?!izr`|?v@ zR~p0LzWC20Xy$o3apPuykB~QGV+8_nxFsD9xXRj#u35R}d+bT86pF_5*O4p*}x zO-#cNso4~EMTQt|*x*FXx?mPnhi5-?P5LYu!^ScCg+uS}W9_j*tJY}IpKL^(f!8+T zgG!6mEsGVq_C&XKp8#F5?=J|q=U3Mb9QJMGs;XHg4(!*{vM}WE+OQ?#4y9&1%>h_m zxCTlFhUbA`))bjrwn@!<1$0JD7+&sqR##P?jp2ZpvygXoSW*sb7Ez&VV#=aAYk&>) z);xYTAR_kqP#Ci!N$C0MT)&N3GvVrOrazQlMOSSA>R=9-e*F75eI~Q-$MC}fngMM* z_j`H&P64yo>P>OSRDk()d1McdHTN%+gG=Mk_Pcysi+EltUnzTz3feMvsv|erf01_*duFmH%KmDet+)B8zJ!h~ySmU=T3-SF~KFjbX=JftPwee^yPp3-veO8a^rz6msoJPw z;t`iPw^vyLI(&i2>)G@D%B2_M%wh>?{GYl1Z_o4p=6?Qv9;4PU{>Di4I8jy{%;O4c zXU`c$4TFwOMWAWGJZ9QwP8B`}!+)v!RinB^k2|Lx2}@15r99`4jIB+wRIqWu$+o9O z2+o5quB-w^+=2agpfi4GhrpKX(ytHqGHESPA&}#0hD)AtgMGGPGP{^unH?^+!$Nt) z+dhlbWpLtD;GL1%mQm%>y8I}x24Kdp+pyYNSpwd53pN%AKus|c`tW4T?NoEuYUyAe zCrxr3U)$U%HqeA~GqH9&G+Fc0{?vM2hMl6o#85?Bhx+{zJ0D$Zz2>>>uXdcib5Zn9YywjJl#1wfB|XR5|873MJc__&V+ zqT0s#Ywakt@Jp95DjHpbUg_g)W zJDb)hEdO+N5O;$c+>R|F5G`5a@-E$y#NVLB0F%0)m3X%FFZJoyoqJJ7y!3Li5*2p* zeeDq82Ka{9&X-M`s`;;c?2JIMw?@`(C*2t@D99E`aacR0!A&4)iznlKD^I9h6I@bUr*ZPL%9 zJ4I=E*q?0}iYkk4v31{m_O~q6Iuvtl=^H3DjpJh0&WywO=Ir$Z-gypCqMJ9WlG@## zCHnpcLs8)7&~BFJpgD$e;gT1G(m=4(02Or-MQIfWJyyjq4mDiN(PZf^gTyUi@~g3C zn+63~&VXy*P)}>2JfaH{!NT+@8IRbGR^c#0f6Z0$nQrD7@eP=IFP>EAjwgKt7V@Zw z=2n0LYp|K@88YCqMskJW*L2r?U^OO&Xa}ax^gRSD@`y;O3iA;X?nt*!WE+?;4qRCp zWx99>h{!rMyi1FP2H<(o9O@;ih6rtT7J=ev!GN9){sd7J647p7)Rz*~+rTJ4tD1{l z{C69h11wx^XbF2Ap7JUWdB$ocmz<~c#B1H*I`72BUf!R2F#bN9acy_YT|bVC&I)tD z^rfqI^hJ@%dsEDIx81{kFp;8fFP=3Q;OD_YOgq6XMZ}6g6Y}LdxR2TiKKL_1xCHOR zyvKTQAO0=Y`0nSIT$xpNw?foW%5`_b)}sC2vT&)Icu#V0ELS$y%u`J2y);k)M zgBvVh`u*py#%SHkk6mncM@ehHh4><=C&vTA5dpsiRS5sAS@gh9kUYsYuRq!*T6!#imYr+>!o+hyjjO1yLTZ!DqhX z4lx+i`KyB-H}366h9FwjQG=tcNyBYl^Y0rik>7=mhSA_4X-L6l3yV( zNf!UMgLtK4?$~VMP(^se{AG$?iJoMw>g#su>a>5u(%*}I>2&zy@l*Kp-x ztZxY-c6(Tf?V9a{?We;_-qddx<58@q?QUtApbi{0Nre6|CpF&~NC4Tp>0L!w zk6!`8OG|}p#W+1i+tr#A>r=DB(J1-y90B>!Yx}DXnHe$Fic^9nn7!mp+fR7gs#@>D z*CLsRaRex-DJ-B|>xpQOz!ID!!zJy$|K*{`$Utk)&nSvaBY5sbvn1B-LdLnryp9n{ ziTk*(8BM&2PTACdov`cx@umtM7umq2Jpo+u+{a{m3)*a3S~GQo`Anx~Mt{i&rPZLv z-D6R`eQt9h)8Yl{P0b!RuD<~oheeu^sU8ej57NM59)myK86{P#jWRPLg{m(3ZeLQ+ z&`9~MBJ?!V9nF)%xLCsP#}?#;p^x1q)Kx`z@pzNEt%0r?w_g9&%}(p9HmhBPXXpK5 z_?_MPTwk!H*xX2^JIWkNoXE!A2Lt#I21htWo}r3=&h{)_4?!TV(u8Vk5lh9+Mngfk zQI{gN#`=Dg1e}p;Q6-DeyKHY3ADb=%=X!{s*ZFPBbD$c<+U*jJxY*8rb)ngW7Vzo^ zLFQg|c^q}%>9O-zvyd%l^0rj#H0|~EJq7W^yIrr<2xif0&!M&KIf}U@Dy{r*IQPeB zeD*PtB#5!G%JJ;bDb12{v7=uolLf9cd!O-F8&WS9D&Hd3G^kpxm5=S%WFQ#jG5@>H zmw;m+i&W%YRl~8vFM@hn zDPm{A;jO)@@>dpkKu-EJ-hF2k@6fu7?#HsqBVd;MkM~3l@B>xYe)ZlZC7OM)T1DWZ zxNp!vZ$4!T#c*f`vNY2iV#(N|K#P9Ybad=}`iDnL=C&fzPl({EkK*<^xC}o12US~> z+_ovqr+V4lQ&#RJeu9c)fNpG9#E$$)+&GK{4dcS0=j<|G@T-<;$CGSwip53*`Lb7! zY+E0gar1o|jcw-aEtRv=!Z$J#rV+qZG$*bm!2j1WS}76eC}HO=hk~2}OAPqq@i;Fo z@Knuahr6Zhg4T+obPU)o+@?v)LN9<7&8xS)`b~P%(!7agCs&R;!EQFdNEAU)!GE-0 zZ5a2LoFIzEn!QcF$oh~ES!)K~?Z>-v0w+Wt6yHNs{4VnX^ewjg#1d=#Ti>Q-oLld! z`Z%MzP!QdBE_Rn>n$#rUKWk6wTZ*s|zEUkjl6D89CI7(na&a7*bNu!(%N>Y%q?!|?U?%$r=J4m1QE%yjdyEW!wNX{|H zJvGc+&;YY?Y3ZVm?h@?Qc?@{x)n)`&^DAs`WnEL($31Nm7A8T~ZkkATFkU=|e7h~4 zLn5lAf8xL7Tl^JexqW^wGWDXb1$uKuv|5~}GUdQGnf`*DXXuHFvr%&vj( zPloXvgLzg_qJrn=hiq^%3xE2Fyh7eah)hL3Un(qptW-#Y;AS)>Q6c)glqBIJP5$9ds!HmeZzL0}@)s=UiOBElx4R+cU6~TM zbFpP~TT^Se;-9A78A%CsNUJ-KV6xzZPr9;omsEpidt6!PAjFx|pUlyoV^a&2%;WC) ztAAc!l>s-0k6zvbaNW2+$J~FYJ_wLg&fa1@#N(MCXlkn-~1!Bc^l`Y$!yl6&RyjA zIRbH7YQ1{o36UmUULTK4cl?ZMogD$3(kLa53>g2VWim{UR0HN5xxX{ru!>0G;m8gI z=JQN<4TD$+ev%)v%REBU+tAgRLTB2h{>C>lB(*k9dp+N_R2EL8WX8b>vd8)G%iR{4 z7VieO!VsQ#A%$DNERD}~o6&U*9S$Lk5}IMge7of1B6ipA5j%PUb(Xl}B{Ok2M99$T z3+FS^FM>3S=GbA-oc&LD%DcVNsLi*j(3dQ8vN%n4&MUt;_W^HqJ2ef?uXw3#N1(U4 zZ~JS*5V8IKVKfo?-|iR+la7u~Cw$F_X3o1D*UMy5L4=>E_|<$0?1(<_wT6Tm$R!SZ zogyi)yYFD)^d{-%(n&it^lPo_R=)q4g!R?(cJjy7&!)t9mHTs0X?KoB`pS_myw<6$D?uG2kH!cHDn(F1yn=(o{7yLz zY~_eJ7q0S%^$K})9>0gcS<{u7Jh#M*b@${P*c5xl@TWdolm&eeKO`1e_Q$mL*!okV zz^uQjb*<@btaw9xfU93NsdmMS?Ajf9)PoB&47|e{dNve!vGx-x4K!9h$QtZiDq68f zL30tnd7T!W$IL0bq2WY^+p1NFJ24#C9wE}$QNCbIW z{3TEGAdXz&4EqVf?2@u_$=Bab6l&V0eNwLwLi)jBmDF3H>UCPPC7uNK53NTDqHe>K8^jzN^H0%`NLkQxF`bvqcbJi8c z7bFh_^jm93A|9yczXid9kwqTl)mtF%}~D%GoB%Lp49^nB6+h%Wa)iV z%AH}Px0y|`&7w#_TaDE1w6Fs$XS;>bc1loCg@B2X_+a&H*+t{LyNj3d5HiBDR1Ln> z7-?l(3k^Ce$}wjB1p82$vUC#-R9Dv+&*gM?7DYhHuwieC2t7-9gxw}I)s?%G zswK`0i2W-$xjS$9`ET9$CLr?1%%BBcV99|@H1=_Hl>d{;6=%*w3n&5%|LQN`ylN=>CU zck(A5?;EH-M-kuXLs|=@ps~I-DN+%aF5F`T^;@`#jv}yT$>%%Oo!&fWZ7f1jX}AZA z0+9BBH*Xg}C|xr!LCE(vN!DCSO3V5kWmJDlLu8M^o#ms2LiwB?SZ7pVApuyMuCFL_?&u!LLKs9OMZ7>_7y4B zHvy;MG!EeGu(`Idh^Jwm149W-N6a1Mw_B&^eDyaPNIsdu#(yvcF{cPw&q%c3I-Lz8 z{V9eNz3ymwi{zA_I1w4&-r6-j5FII2`Nznk4v$KiTf6^UvT3mB+sF8^r_RlOZ; zPd>oHSFOr5kbl&RlPHIxJ8?BL>;k6<%6R;VKNF>0OvsWt^Sl|?zLVe~nIt84$pm=3 zZ8zyHtm`mDxii^A4jWhUigM(KB0JzScTWO88~?F~W&-k*C;YbdoHwbJOQHOu^DvQS2TZw!iwOJy zP@XqeV?AXQJ&M#VSR+`8{mU18Ucu07Wd=6X_?dqSHzP#481?!7mFKs%RYGj%EwSdF zCXExh+7?)v08KPgA>WM!6^J!&4G9Q2KVe1MY#PgFt&iKl?#bgGLze4-2QrLcoFyg< zm1)O3;vOmUO}2@x)(%iu3^pQu__TkcZtOtd4*F@1>vK}9?(y}9jJ;rf?&T+O_TN(W z=by%KBqXBY2dt?00$iEfme=_H*6n2aV(hf0Of)NFR7Z`}zEj6XYK+7Bgf4&H%$V3V z(4opy=;RKCDL|&+L}zxbhVBom1ZJ%_Y{34RQ8eCa+U&8!4g|+jdg#WXt?#uyHIIOV zeCBkSnN#BXUaUEz5HLl_A?0SE)@|!|Td>_(PX2bgr^3&mrT@n0^oewU~Z-kz*O_U{~Lm}gbTI)W`L-%I! zpRX3|e6mMMYw~s{Ut+doGD#Eg#|9oX_9JayW1p(;>~mCy9E6lpJ`Uv)NBAa9Z@A&O zjJ@l)8{QvK>tWwU4v8Bo5{ka&h~)hZiw7{+#l~8Xzx#2ZZvyZ0fGr(IM=nMMl%Iv4x6S?#pmecd9$P{ z%fd=Fa<$`*`f{X?&MOnft@F~$rLmK_k2wfztaJ?)(M|M zo`9&3f8acerb%!~y&dWxn_IV?0nH4ld2?F=v1N`tY76B4Kw96?r6p;bb0_8EoR#iP zo_B6R=7ehTnn`p^mZeclbP)@tAkVaF!@5=aHUVLeD+d3xH#ML^T@&!>es%Neb~`p3 zZnz>z>esK=L6RBA@do~<+Oq=7<+{CyZ8&)rS#EvK`w`pj_Hyn5XsavBMB8qhA;sb^ zr)Ktw>K%i$P4a@3e7Uy=xsmvy+;IKl$biRFK5!wFA0~Sly51aisyfr9QJBhX*%0>3 zN_Kg29zM3zcVMk1kRTD6WSU}Nw;1AJ=-Jm_NLU>&N^cc){Hr$+?NH zGj2`KI&U0-2(S5;f=A#ZNItMwq*@~Id@ zRwpp9&!hwgeV_lO2#c8=Y*G^Y$#hciWz6w5pBm_P|`oF|_$(o}0Nk z?JSaNh+mR}(%FYU-~Q|*W<~sh$eCh$-oCvPS(R$W`4YvPmE)Ir{x2Xf7%3O~_I_*B zx_$Q?HCYeiu7%6P&y{<e&Q+PTbslv?+R6tJ^UL*{DtAf8}Es) zb-|Z>!a3G5Vs(NrM93vN`=K*iT$q!rl8Ve{)t*y( zuvF<*5WhFvNICxw(A)t?8KDTrgymt&&H(gxr5u`rxF;!7po_T)+6Q`*jx31@>c6}y z+)Mbjx;>fLrOv}5V+FYU<}q}}&0j-LVx)zG>gKb2my^KY9xg?mIL``-pK1>O)(4L8 zuZ2!mYvdi=%SWq}?Hqgvk7V&vloTf^XCLyz-nX9TIOVd1Xsjs?d`U0i@wRP=xTEQF z9-KpVRG_%m&d~^WQiAO*y;`U{d`;C>LZw~?}RSAkTf-Tc}D z`=(G}@KcLSLWFR1pRf(U7hPtb>YUiZk|v79e~-6;u!D{&gpX3Ys&!{s*8;7&BQPY4 z%w0wU>P~`G46=O?M3CX{&Q(ecp1IRzW zj7701&@&^;1TpoHowDb8Ix-Y7k5@F+ovq3}#*5?cn%GWVEGmaOB*Y|e-Y0DTi?`~{ z{nvGHO)m2SMr6IyZFFMsymK6%FK|T^e5##_tDo~gY|Wj>fE0mNijuy0x_r5pid~zF zj&QE^re(OTL1l9iodue*(`zK5b$871ja9f<$V`mi?uE{({G2S_+8p$y%;@hVO!*ex zZZ@BBO0o??FR4P}uV(q0scY_{XyFe3y|_q~ei|_K48FyxHk13}zK5sUY&Ui=G*+w(I18 z6}L0Aa0r~sQBuN%#)2jD|s7FpJ9=ZcR$xOD*`J=CT>c?lBDUkvSjpns5FrEvzyXPrh0JIx=d*zxk1HSWqZV)L zM}q@?Af*IetK*v-mvj(~GLLItk&SK6<8f~-h50RuzC2HEQl`LOt2y+kTqZ*Yjw?)q zs4b+^ct+N^gtatd-b&g{J5l?>*IpuFRv4ILeO7U3xF+FM2%euxuD+K)(@9(+_@s4A18TR5IRTSG=pXQC zLOW{o_8gcYao3w;2dV_ZT6{V7E?bJ$rc1hFbf)1=z~j<9!Q`Q%$HU|w(f|*^xGKW8 zPT`CKd|yA(U#jSit8+fipA)NG6 z+`#Eie6TG^iWDjfB7O1=Y;0Iy%K~A^8W*@thHF~#PvLLl{Q|Ytvn@lbu3$s7N&3;n z3pT0*gV_${Zh-+ZXk0FHw)P}JP*=|8aLDo3)$W!Si*7v&1WVQ|#?gD3!%0&lXw4Gf zOT6NAh(HVd#8Dnq3bEb|!TP`{Tou)te6UDfB@5NQF5b zGqFscj+6}#(mb&-O%MwCq_pWxW$sK`ewe@Aq|WD>%6-kYsMl0A*21%etpM`4SEBNk z(+32F4j|>1w9%F2Y2Lv1nGHQNr&9GL1q&kVU0+Y_dM*dJ8~@9b^{?37B5IWB}nm%1|LL6sn!!;kj188loph)4fuj9_I8_PaB-~aaXd3(X)3S zVE9_BawQ*EaKO^NQT&iyZz2#>*UdGOy~#W`PEFDu7Dus_z{2LRPZaRe!;=G@%RCcd za~cVubCNFcwrajtCu3ZNOCOraZEY*Ly6-8=d-!>-I>6H6gQlYCf_XMqkv`GE2DjBD zL57RB@-2qAaGTp*e=p&+w)3Wu&ol&js*tct_I&GmtQNN6l%_)lb}S7?IRU_Fua#8B z(~@NS_qnwsg;}(T0~h`P)HGwx4)nhvvOF~eb$@gf!(&cX1)}0LuW{~28lDL-Jqd+V z*S0j%uW)Q~YPNOYa1G?!zhifEb3sVuDc$lMo%Tnyfn?vbcgHIgzv9i>nKqna>u6F!;5#)PHj}B5U7JAlzF4bWt3=my9Xa5?tBN=5;J?1= zU0(;OvX18@7*OTsD@Uz(GRoM}c-uWVfT(!r>RVeWzbh#@a^#NSpe?GHHuPC#Kj?s` z4RM*u{eG%|ue=P`fSKF@0!p@Ma7T}Diz@q8ptz0&eW zvkF50)b__=r{9K`YCg;<-M36MMIC|QTdfxbjOEu+SSYnbkQ;tBhab0wXQ27^N>FbK zu-C?F1u+BoH)uIzG3gSRMT+-q289XglVDjrCAJ2 z2VygXFgclaI(@xlfrBoPf9sTtnZ=V3(OJSDvKD?pIyZnEaR$-#H`#S;&;s3s5ZPM& zO7r%N{j$dVf!diML4wuJ3Ozl!wPf!TCe1VNSU}beb*3kC;3f=oe4Jfoc22DUGRx@i zQlsnb>Ul#SSIxHifsHdHX|JPwcswsD>L|i;&>tF?LwEDEy}hWX2kt4f#=yKklaQ>& zy2BOx#{#LT@ha!=t{LR%T^SArI+9J|1ITmb)I9DU9viZHe%!{6r@l)?Ob@!Af6j<^ z5q<%j1rrY^y6Ea$$jI~j-Y2gj$j|5i zx*7+gIJL#A1zz>aKz0=Mia#VB675~RjgyEu;N8dd*DCzXZ|i1n26G+M&L0`tT6?@t znMi1Xa@CbT<7X%Z;0uIKI&R2c^nTnL7CAInuL_p!B)iQxUbA5ff~QH)PH{^@yk33C zca0y;bh29^921zj39BHw-5EP+Ex~vsF*x_aU z4{K-D6h|AaQ3wPHPH>k&g1c)HJh;0vxCXbN!8N!CcO3?o;2sN9D^?|2m*!@eB1pGC)WCR7hLM%-Kg9a$6&k1Ya>s zOx;COoSPi=EoHJV+xvgJqpaa%j zGeg%gM-BULyR%YVjX(ZwRQiN+P}JmQ2w37{0B`|>B|E>pFvbC@k&{gQeXLt}p3ftl zEgF`hpRC>WoA^KoD`tS@&v3bm6*XwbZhyWC9HJ}ZnlmuUiD!Om)(I3QQ( z)^W(3=#$SD8F#mJtJ7i(r_Ehn0Vsj(hZ2TZUp-WNokCR7uGBE~mNH|3#v$z%H& zO?46$1eRcfqjRe(PZu5t^uQM0;LmWRO`AYAZ)qppmVWL#OjJDPq|XA;Z8~(f6aRhW z8uS*!I}`0HKO@N3x|IMaPAJG+?CLAoZ=qX9kg=xALDz#$@s$d8g!x(=+uZwYYveGK zm3By-_VvGR+IS`JL=872`O2gU9sX|E@*?c_neX!h4oZGlwR@wTm&qN2PeN-qx?&ib zg-9hF-nkCG(*iPfBj{(l8550oPRnx5>$Ud6WWriPruh1Q|QT>U$X@?Fz8_z85?6L z-G(a7>5E^Jp#x${{(zY~$HC-J^b)!iG?p$x;@opBY?3?XR?PhkZ{A=;iCQ(M%2lcfi(M z>#~T+aKd$I$6bVkmd%79Q8>Rbp-W~P2l*dShX9EFcwY7?El%SblC?U0VshJ$zLvbG zdX0zJ3zmuDr<)*Fuw4M>jt$Z5v7kMs7Z^7Q_h)=8HILAu9Lf8}HZstbOGJ7Q!X-mw zrAw8GgWq7>N=N6sMP#4^i8QJFmDb~rwDqp7>+FcnRX>|L+|HLadgP|GC%Cnkgw(ym zmevf6&rj;N7p`$)3{=XC9+K5G{4M9F@?fG70(Z=l%WytA=rTAA`o0bKq-mXfIE#PRC4mqp z{VP2k*F?V=uZctP3)3Z5U4ehaM1>u3cFB-MGZ=G{CMkvZfd0P1qn~8hw~p+=FL_wD zl)wC6ujTd3!1}L6ASX`g`Ms{jhN+E+E*pIUqB!2>6t7B0GX&PZZx}D1mIKIl z&Oh1*v59y^*G+MO8s}@v8A?6b8nY<4RirTqF@O)3riyaq2Y+OGWq-nK=@NF{Ax)3- zjCzb&iy5z<{E#fllmO9zwoqW)(+^Flg->I`9edpQNSYNhK z!<@V1UdvtXrl^#LEWHKN2gebSnd9)k@Z{p}IkEVf+`^+UF$yg1Dy+q(dro5Tr<-=+ zv2P6SS?YfF13!5_5yuAzR-NDro-35bdEL-ZRD-if%y-PJ3BYSC%KNNkq+0tYrD^2shF()>Nk*Cu=Dy=4jp$}8$L{F4{4rT%3=X}%S5tvarOg6)xA``nr1Uc;vmDR&yHB_r$T?7)HV#j_(eSt> z1#{XTg{*1lTB9N43zhI1LJFnSOOrF##zltv0%}xkDybmk6Fvyw{L=}}UlwVt8+^XQ ze?&QWHb2`hcCnT}*g&68)flR`*>{25C9`1>*Qgh~Uej)y{0gC^8yllM{dZZ{q>d%+ zYt5q^9tl1(<%b5Ozv$;m-=?}lVqyj3oXy>h8Ppy*+nba8EGe+tYmH^uCB#`KERLo_ zRM?jSDkTRknJP^VdmXhP&S`c;^-iyi9*kx-k?i7tu^&`c(A{%Us&{dTe&dT!j8{2W zBV>Jmp)35$M?)55Ye#P9@vg+qf?CV*Q>Q9F0*Z}T@nlly`WU%_c&>h^923TKlOSdH z!-+vdG_`tnq-Zc#gD&m>(-{8Q#OP{2AR&_`VQ+a<0`QQ!OZnw)_OF=m7Q3QPZLMc% zLyihDilJeabrkwwWfHNC;3o>J{BpuOdbXzHQ;9KdYX!<|-u6w~0b$B}Z`i;0K+<8O z^^Vn*YcBn6Hf6iH7%)dq2k0qq@E&E|G!v^njW22YeM{BfZ}l^o#Uw{ZG4s!Q8A{R4 zmQlpHNoQ-;+KC4ma2??bJrbnx^v>vrn?*GT{padd)?Zou{@XWPoN-q!@#Fnm?o6H8 z+JGbWx`0)-zZv+K5ooHya0fW6d?)Xc^^}QL(rD8JvW6<1oSO%g)BUKhwg$GJ>ld;r zfV`)}><8aVeMNj9vIVC$Ulb~SnqA8K6j^`m0RY{+Hn<1v18f6p&>vjs$i-B)PjP*1 zQPdUzWB=N?CgbErh8ilQ7j;I@^r2r)HQ=UJ_-~CALu;Ft-C;u`7^JbJ*vrh;woW>X z2_MrnIhdfA>sUHDI~BX8&#|BS7lo865Bh~Apbc{?f?t(MmmTwMXlFJp+wwuB6kXycgsb?TuoKRRBFXXIcYdP{ z1k2)b;|b~AakBjL2cpj9_c;1#cS5sh+M81+qgHVBOV;jpk*yOXE-YLXD(HRqo+*{h zTeCkgc11%8$i0)7(DnwC*rw@OdLFoLT z{gKsL=WIeR+dd3OMB(TJiL-SCKWb^U;l>d^hS1^LI_J9B>U0T>vA9o6Rfi4L4Y~2G zwv)k*K>2ie)eH(ALzff^+z)5Zb=%DkZgU`51Ze-p)sS42!D4uEKQ0$`LQtGo@LCiC zGnz_FuO-k_@^|p}rd7Bf*I{0PrQ?Y@{Q8)tAY^7( zzr(Ta*{>?YbsLpYg9E55D>&zI-Xj4<0;RNBOw8|lL2v2uccDb>x1e=I@UoCsfrn)y75 zH+B67s|PB_a31XRi&2M&qb?*|)3BK2Zz6LX&{87kv#2gNoAf)8k-^5xQvP-hR~;|dek*Cs|LJbXxJBu?)?$P2q@u>^{k-+0 ztd;h#?3M4t9jZ{_FNs;Uvn5gAxCT;ZY(UtdO&p`buB3o}tHW>a1RU(r{mJDr;T>v# zuuYrxmb^z^3=V@b@WBScniES9Vcq1*ATXyAWr;)QeEsf_L_M*`hu>-G&Tz~M6jAT= zrEz2(k5O2Tvj3zr1g6qAyw=dup}^GC>X4Z(ztTY@Yi**myYO8CWIBdkZ0CaY%ZnR~ zyEaPlI2zmuE_%`uBywZFhS<4}1S87|mFRPfj}WPRrlIEj(XDq-*3sMzex_6MV2}8v zDc=#0$Vf)}V%Xq2;%Jeo!(UE&1u-hi6W`O_fj&;8lAHgQj~*MLC#A5gvjg8R*`cK0 z%|S8RCq}S322XG@!`QC=H(6qJWv^!*e@feyMx;-dH04SuK#XkZJP?QdxCaDDOm42P zOh=rB8VSt1PZLQaThgYfQgeQGOFhvCc{xlf5O9Dyp{!nA$vT>tKN%&s6ghk(jXVi$ zhs|5LXPhWJ&a}YUJ9|VChUcQ#KPej!Z>OZ4_=k(kIL@Y8cuLGIJzGc3$Uj`|g=$F0 zcU>lU7~J`}4+VCcfq&IAFMlwcv=O_R`M~02!#5OPy1+LQ1D%`*w&qr4Az=LM*W5sz zq`5F(;7FKuOgK>@JTbhX^kARFC+PvG8KMT3khP30Yf2(b2h_Vs- zby(r7L~&5}3Ajk)kjM#h|CF*jgZjNo- z;20*9(tD4JG3_q0n;etUKbbP&d&kNj?xgM8&n;haNta(!=*g73)S73_A6aD1wsiOT z(^=`v>J=brE8pWUk&xK)_nkuUJRsfIDUMdGl5{s*@oPl?1YX-q@oRo&8Q@goZD~IJ zO)o<&pEUa)SA0xbCtCZrkN3i`7)VS0!Z4>b7=Huhx-e#CM^vAD-!XT;L4?umwrac3 z5Rr17cl?OHD})%o`qQJaQJlvnU~cv3U`;WBQiJ3$eM)J7jYKQW>hZ_gLK?-#lW$E! zlUMptU+7f!-nc6f;$D3{LEx; z9`b})Yc^^+3f=ARm~Hc<0sL*oza917?V3viK2%Uc zHPS)WDR68Jou<@TWD2GCU}M03q(8f&=_fsveqrramVg?o1Bl5%}4}B>n#C zsjB*1>%K16ffrBuy;`CU@y_OF+>(DEMsxOJK64dvAAh(%wTDQQbcC-l&VsZ%zzI7F z$w6-9A3MZ1rllwR5cQiO9fpP^yX`6DKWz=ig}6elN%2%vpqm0Jk|KXYr@jfyW+;&0 zJN>>!mLHG|$bFp?W<7QwCj1LwPnIj^F@ef_TwiO~G556RA%K_3!taa+t*G3f^b(K1ffa)?ur#iW01j_4C73gyF4MnFe1t_J2ez4q)s1ojWGq)J0C6 z@6N-ntr~xS>zpd>CwKdM$A+Scgp_Z;P6V;iX;_uR0zWBD{*eoR54OWToS-l(P(#=< z)0(1e5#Z`*xq2+%3D_HdRv`^&4vPy|MJ>ggcF_!$YMxI=uRX2hTL90OT;GB&x`bma_X&!&rt`p4RN;a~IRTd|>LT!p$yG0}H_pB+rkCnmZ_CyeOIbO9MC zr0j;))t>4h5%(k`QF!6$MGpND1})$I*L&+c?mA zr8RYql~PH=VBfG_LC0Y^Qc+!)ic+U;%qIr_(ag+%VZ;U$SMnY?;S+7ZT=$eEeRR%e z5H->J#XfM%82jfxJ1Y{@6kO9%H(N*vxAW2^dPWYon={XA^0Tyt9`9N-6>?F(EL{2D zJXtNPnCW(KE7GPgxLywGB72H9=lgE?`7iocdY`x0mZT8r*ySP+(4LT7hteic$@EezEbqp{gDV|v;wkECQwcYj_g zXkHzEX$v|Fd1Q;LlqMRLMcf|R1Q6lArc+!*iP$UQ>46p6J(;pGt&ln?1S#?zY20aP zV!;>qCgHh0fsh4wlm`&%O3x}`|NMJPd9CA8yVcnSRxmlzH*)szID$MoM*MRz7h^g)ND*R z`1+Ol7)DF-)l3-b*GSm`oNK8gp2nhRV4HpK!X-@Gx`zjLnLp{P5pK9_&zvFPo-V0k z1dI}^?pkVctN8H- zw`<&$Q~!j#M%}ND(P(x`qnXpHSg@JkAdmr)6Gi1a!Sg*$@O`^`p=Gc*mVi?DdPMkK z)i{yOb1BJI-Tuiaeg2|AC*_2|>D;<#MjArWj~cGPeu_B%7{^P+`4P@@eA_R4HjJam z!5w|KOo@Y@rIAb`1zD_0pJZr_LSqoc1@6T>Z>sCTw0c(?;=vyxPy4$StuX~^lFxXP z(h>tRk8JA^;c#-bJNNgT`MRF4p#Cu7~w5X#Gqq+!tZn=1` zb_*T__MZ?k;qtw)W7|WwJ*S%yKT`u{L{ZO~ZvOB{EtXN-k6ncDop@NjB)vMISuFFJ zcQ{m5heu>DWcCO09(4eAI=@a1+Hlki}OuG9&%9EcM+S zJOM27La!eP*CgGl*tD^i#Ex^4VcI1Z8I$E7l=&GuDZp=Fur+SgE}f!Yb1CYKxiT!{Q9h_{O9_D45qr~O3z_)4 z%kl4;2)|Z~Azd5}W>8Udv|JL$b;(&W|1@a4cwuD|@%T}iF_To{EbVFBj%>B}4y~$} zI@lIztM~oT_6*9go%e3M3co_n-w4S@r%}-|_Y!JBF&5y#6LvtsUBGLK#bsbkki^4g z>2b5&+>9Il&u|beft!7z=y~85b+EQ%H+unx_#VsERtllOumy{(Sj$p<{Y~P)5-VxU zl#XHQ^ldtbf!z}MxnyGv0`=O|2L9==NxnR}Tf8Jr_!(EnZ;Cwt;2kP8(ucLpzWYM_ z#QJl5a9TUJ!(EdG&*bnDXRznvL*T{u$$%-=_duj)7tO}>9SEh645n8e&Kg{Ygq3@S zRPEF!E`RUx6MhKxkiW28fX-qsuKPQfBKRi8ApUKRMI#0Do zv~fog|6elnL37{^qg)!ZG-&cHjuejo@c==onRtr`f;jA8L}(}rb9#DXq6+MTC)dLF zes61%$5)OYyMrf!qpP8_>YaX`&dUlJy})|3lPBO0=NHu-xl5Gtnv)#To<-twb_+T8 zI0Dzsd*2*Xvu5YABbu!KdMj=kV53gYvadj6S7Dv zefCasgFoInlU^L>EBuHgig36(d(^4B4>W=G&W-Ldfnp53qtXZSWD$i%%;zs_p3%;4 zUUd#Vx2>{@<#mLzXuw~oz3rF)q3*Jh-*h#-%LG^Vow(sX2~Ujl#P8N}7cgYYV@ZR@ zoV(b|!`LqBEhn5mZ-n6xpXR}Pm>saPZnd~IS{{JA=aljllVIzIM+z5usR_O=koaSV zFBOq*g#R$#;#qyYlHKBF6X*uAKSLh0O#LB%TC5|ez@zfv+~8}{Yr*GuGKTMgrBvS5 z(d5D;>#C?RcQ}#M_&268o0z+ovJrL_D-gairqCOv9P%INn)}V1ZnNu*lrQdJ(#3h_+!`}-CwbAG))netn|(O? z%kn;E8Nb0Y0a3IAJC7w1M!qX<_($@6ZQ(2&FOPq(*GZ&MVPGVOHPlY;YGp^5CQWZ{ zQEnR$ibJn0GhR+7;f+45RrKdq^Q1x3_hJnNZ##jEsa2{Mnt61 zyE=2H_3SX^sg0J5#5A&D+!9~N(5s(XpHFpc#)jr$Dw}6_Z_UQ zoT!GylSs^iboUXlH9r)Z%bz*~2$;g~-M!>SE(PNkKfyK3R%-F`vN{Jj!Cl^JN|<) zaG0#(k~4~f$>Ai+*%HG6NXs_(r-r8x<#|%cd$;f~pNgw1XTCh^Zg!V#hHFrcv+u8Z zJ;~6LyLUV>Ly)nAurHGnzt_Uw=7*VWg`0`$ZaLLU)5xMQ@<>oI94C&WK?s*g3XOF8 z#izmYi%a_h&Edfzpa^QD4*)x%#0pmqS$DdJWR5e4EH)^|`G#k)XS{;axQxtG7Mk zpIvnzhYnMD^!>qn8A3#-DJ@J7+ zoV$IdEQbXK98w6yYX;l@Nou+ z68u1l(j=c}b0^FjF^`G)UaZeR3FyV0Y(DkI+O^jnVbVm`QJn91UA$>Y4aTu47{3>P z>Z;$Nc%zvI88hk5A9ltn{lF77?0F|_P2FYUUHwUDH?-@PE+4SFq z@fSXi;yR3?t>pe!>1xn^FSZM2M?o}OZB`v$1qZ>}x)Y*NZY0JG5^KKHiAkx9E%Q_f z@Q?5OlzWw4Sj=HD?0|DTsskOh}qng3iqB2$PABg*L( zaOnqj?D7xMYy;*(B#;!;x6P4F7OpnA52t!=9w{QBoGDdR`xy;H6QFO-Me6rRkiV^x zx?`-zR(KnDRx`5ewIbHsSm$3eQjna%C&5LUUlcesi6O|nHrbM+dD5Nf0et)qVZh8b z$I+1pu*P>E?a4Am7d2kP5uxa6=(SHTDkVPTwf{7(H2N6Cu5_G~`pg^qqFNX-ikcrN z!%j=e;vbeg#r5fR75bn)x_j_+X~eX!l9K2rB@Oq#i=&m6(EN@ORYM&y1(}8iQ14XF zyql9U4v8}hI~f)IpaNiF#ZHFUnH~_+ml61 z=eQjl)w%#&bE5V#!!U?hvw|$PsPug(g^xjjx>^rum-K^zO-GQt*1Y$#4ZZUDzs}Z#~Ys9#Qzd|8PB&%tW zbA?=_kGeElmwol_Ao=1ZnFwtyObWjQk^7^iw)*IN>Wsnv5KwNNs04d4m~~TF>5!Wv zM8nN)5gLqk^V&!F57{)+^lDQif7@Ps=gQLdmAlW3?uR|ycZwor6kT~O6t=FSFf(QJ^Ury_NN_|Dfvp6|W&N6JR61!maVQsU4=ep10!dQ? ziCT%XQ~5hEC^0d^;AZ|`F!qaRjmhyOR8zU)NY|AO0DJs}7L^(aFoS=~11vho2CL58 z=C33KIY(S`eVii=eL&^Tc~}om3M)0y#+p53GuEY^0lZN6{kogI7)=8j+|-P4+}5w=kzq6P zd+qIS0ikn%sI|*>Z+OO2+G@80O>%Tsdq8_Yr7Y~n7ce=PqT-f+HY%)IDIKS-eE7nP zryK{U?WW%?lKxAh1oEqZ{oIKtVI6GB+UiFP6aD?*XNquSa8PYoYNFuu9dE0r)7G+6 zL-*d4nQ3y@otuOl4S-UQ25Rb5g>e2++t8~k4SfHcr(UNC(- z+y}o8pu03akJ}tH{ph(0qSQCHh0(QkCCU99^V!FGYhgwctk8B0gf2?AOpHo8Olhhq zF`sz?B7V=8TXCSnzLI};Ze!MQUl$7)(%bDT7WFo?0?czC?k-z40FkZ~3unpH=?p1mVT%&2@3t9B22-*SVb5 z?!|AwC?cr7ZMQbioRc`C0z6E0&IQe)(ONiM4X?M;C4aB@Q58^?>o#&uc416i#Mt>mJi` zOKIO4JHI^lwlwjgd=(}1NJ5>LSmmEVW9T{jM*>9eS9S;tG9FCXQ77uA)RAw$hr8W?3+n7!;*%yMu4FB6Uu)mWEL_zm2k6M_iRK6)I*d7eKkX^Ni`O&0jyN9<~6 zazj)UZx9e?<=UoM^~Ub}t3%vql(g6Oxy|&OghtTE=jxQAp?V1-WcwRi ztHTV`=Ri&F&`TwE?Z!Yk?lm3n#E(rV2eP<|ten&On{wkKkG~YYBbW626)L53>Qkq4 zh8#9%=YbVA$ROwNGweVql8s0Hjo1h$^Y-Yb7qdqdB6n5@jwdYS4A)CQ^P-`W0+t_j=q_qV#WE}d8&*rl$^H}cAV44^UWF`dN9 zwJv?5XnfK>`NV!kli)#l%1U@W8cW8p-R%{>@;s0lxAZH0IYQdbEE%G{w>J8djW?w{ zU#|TS+BC0_=H^`{DmA<%e;L+9q{XzCD$M3h?efd-+Bm-2=u}lIMc;)Z$uc;1(y}Sb zD_Y=nuIKQfd7eJTIzHS^v@@{LBA>|iTYPd?>s;I`JeH4uL+McT3^<-OlDBL}8;XmO z(z5A;pdV7A^-&Z=#0ljd+BO9W;9Apz>R0#ory{I4@m^ zq0=yaCI8Sa#Ly4GOUziS7_!&`%MZUA@0K(}|I z#U3@ZjUztq%YQib*>aoGz%@Gmp1(nLAdn2O%drUMGM+_o569)=z9~}XZ_myN{Ps}X z-rCXrcysAS*eCze-b6@|f|-THo|;%|HAb9QIaOi=fTdyidwj@S#`}rff6@|iZAm(1 zw7}_f=82m93Axs}hLJU{j;nD~j%I-kgD{`nz1EUMLUA^Xy9M?ZF_LY*pG3$XM6Vnma#Pt5hYkft zrT*2r+8l8q?Br{l5KC^hI}EbaMLGjE_sUojeMT}dIHY8?UC{I~vC*$caf3m}W zFCV=Q>&1m?@!N}=IM$6sjalkf6+#62DV%i>w5+O`M`h1*;o_E#>e0E=$UFa4u$X@b z5B4_|#DUx^974ZkE%d#>)`Mw>oNz|T(}%>|9Epc?xBibVgOtCRTm!&bgAI27{-I{;MzY9%iV#LVq^xF1j}hxy7A(%# zW{R$7h4V(9s6hS|UujbuI!j{kSjb09q>4%%k;j}XxZ4gdhVRAxR zHsy4&hlki1Be&|^i1BQ>jC|4BeTZ~!uE%o1r?Wb-p8`eM=CmHnf)GB z>=S11wMH^WYQj@+B=ek2_dwAD4GROzjG8A&B_qA-7dJ@a* z02wf6r47l&G3z_M3v2L18zEEtpr!jQ$%(d=|5{FA zt7a)^&NT58l|?0h+#~$ysi0fAQLmmhhD1kxH^t1w*#*E!aE2lnA;vh{Px-vWqp~|U z?Aa`0uVDw~+-v@X%i89`jxgbgfGf^D<*2vGX5f^bDh}%M3YFwx2>B6%tT~e6^XL9h z>=LGTf7ggsQ;(bXRW2*3clyB+q=(Iea7aB}t4xue>JllCfBUO^wW|@JO0>Rpc!s~p zb$_?h=-dwwITJqU`ZZwArlVdgU#2hdO%NI_Jf^wqX-VsEoAb@kR|kGtv?#SI*IxVn zpty2Hq+0Cq6qiu2h&lM;jilJfK|h9FT!z9`a$8w8Z`QU<9|_g!%t5>dL7TT5k4Q1K|ml=;Q2X%TZ5k&S<`yk|3w! zw9vK4)lGWN1ldWItS86v_hv|r?a9$zTk5Bq06zOBQ3=vgRNc<_HJg_Yu@QNUQ8pQ! zb8qAT*GLh)hDqE~iVxUNhLk9DI-F7!?y5iSDQMHDY-5Jfg&`A)zhzP_W>s%O$9w#pcnc3g> zd@X=*mrm`aAGIEn0M?uwbHL6?h@FWY?+&v&nX}1TW0*z4_MUCy7Ra4|q1NCi) z{~@`ZdL7deT~qGS)Awq+{tqxZ6dj|KNi>8+6;+V3y-n{G=^QgK9hiW=Bo;wAtXnYB z8?f;94QPOtyg_1xFIMe_P3F4E@@QEoeCYGoxYo^l#`vh7h@2fhfi=LRw2uT zkIeiZ0;kx|)ip{PUZn(woUGNlhy{z?`_jMg{?(*pIF%47g|0MF_}`i!qoHi1!?9*Y zCaGRPn3t-G{7H8D)00*E{2XJXrt54b6Hy^8rEBr?$}!H7qSk)*a3gvrJ;BDxku4Am zYPD;iYqKO$43*HfLP}9BNU_WC{Ujuaq>QSa2pc=)u!xkBh;wf0!vb?kXv7)XkJtbDFXuGolTw-kO_?#8wO zOjH*K^n!mh6DXOO6%?ob!451R!tNp-0j5YRJ_Y(q#ABl35^7@ zl*ByH^MwAhQ`MhZx4;g9=dbC<^ih&f3 zfRjbM8fB{_pf7bi(#qRkm-M;V2v3zlfcbRN!j%_eFvuDscUw-gAZIDFRo=ECV&Jwqup6&dVj!Gd0xyNasi!e{pQQw%c@0_mQ| zT~E_55ya=&GWgge}*48AtrknlD8% z{^n`oQg%Xop;&ZLOupB_~2%09)8{wSd|1gQY<%J7nE^U3m0;yI;<# zJ=MNTdEOT}r7z&eeN7bKvpgN+@@Ku;_v2HdO+j}|9*thK^rC?Y;?-Wq5a=R%9h;`A zwT_yzDOxk|fMw!!>A3tsbzh6)R^DkZ-y!pFY_xjJr)z6wQ2-E8`fM;;`Tc5!wG*44 zmAl@_r$7Slcl4jsnn{&#X=5a|EYpSm**iqJh+kpSEwphMut)mWufOFby-Fmnz0t3l)2`?nLz0>645 zdz><3@eTzbFRg=vQYC77xThx5R~I<@oYg7$oQ<(P@ZMdyc}hXvPIefo*6NG#7xU&w zZ4Lm3FUbWWfWHoO2O&F=fm#?iC>?yoTwB>5# zHbyztFW#uP4EY{y&Bkp+JD;tYRTQ9rVESn5_Cv0rHp5sTkZW{qopn0qkB{Co!nCD( z_zUc9#`&=tPi$$~3+(a5o1*zFn&@DGE<&~A_(zh$dGe!%ZH3~9B!8ukbHPkoYvZ$# zI~yX8WfCGNt~{0Aa&p}pS3*5xNH=9#^gjf$HRzC7)!c#5mfSl&><6~38y)dZo%CWS zbB^-z>3iJ+hsxG5-i|RxE3J*Igy__(0l*v2#^>VA64>d(&?~XSh%*v z$z$f_)%SZ&^f~SPvUV0OmPudR>An2nX zcUGf(CyV#BHtx|(CA zY?tyXu^L`~Z?+DT=Vi&I&P~W4Zm>UX16gv+*^OjS4y}{9?kQ%~SqZNc+p;n+x+ zZp-{wubX*3cbbn)t2FVoI|;h$+p6RFHm+zAtK!$XfA#ta?wgK@?hOJBFz?6pct95QSH`lgDNh7h~2mmEC$%tuJQNP_@KTv69XUnr$x`Ti8 zfkPJXs;e|wFR*{6{6t>E;3FR!+)JO#K6&r0fu1B4(4M9F+~1>C4ssW{AB5XYAIi(@ zh`}r~p2!8ApOu7lrb*f%5{@^hA!n@h?V;$CZkyr@ch5bOR^F@R4f|T}(1+nA0qD=) zjLlfn#dhW%@8b$rr+kSaWW@h0;{*Y@I5|Q>J58yMnQN7ndfYPGyDU(JL*FBo7E@9A z?myLLhaezy-AHLiS%UJj-dQc_WQrk*IwN<+HF=@qOEEHnzs}-%;}~NmM|o?n0zeWt zO;{+^&M~rZ_XbJ^wC?Zfr!(QMJ0~z;>_swpu;OBG=ih$PQ~GKqA5U?gp-U_v0QO#1 zLcgNrP{aPFyiAG=6h5D;-I!vS5&+p$jR*Lv%S&@b0y4Z} z1Clq5)A5E2jnLil8h;+61|0riWrR+>|J4-u`_t^cWLrxs^VjfO9w1KGTx89Mz$ubJ zC5D1rKq!$cD{%i&7t!!Az*1b*?Qf80G(&tbgc>GXy70BBrFFL7>v$-70Ac(K%lCg$ zyQSZ~TbEjiVlZ03cjYiHWuyaD?qLScF@)kL;JfxCi}qM)P{NWS=|OAOOM9s$c{3OE zU7aw=nX7mumNIgIT}Sp9Lx?puAXOP3!NmN9!5`C;1(otzkM+amYM7lH!&%PzzWklz zu@zaX5h&Z{37213!JiIpbF9TMz42u37&neJhxEkLsRV%KVx&LPOu*bsxpNbHxsm>= z9P+Wt8K8|7?X&wS;+ADEs(7QmXe+S{+F8#;JsLy1FE3em0#L#hXD0Ux&}@d>qreZs z4j`M_yD}17Jzdp-nU4w52C46TVp^c=vbvqJg0=Z)0db+5+__B?u2JpaX(`Ve@y-R} zxgnbNcHQ0rm5!f*nOawS?zPXO-J{~uSTtXPTkC>B&fjyKF21;4f5ueA^g8V`L!8ZJ z?i-<6jAg8>EGu#_|BmeS459Y~)Rf7_oty2x`R?}eS8+JE7mMy}Hz7xg6k%C=ZLxT_p|RCPoxQevOTkl&)2(7WJ%zP0es1aTSGK!532ZkX z?!7+Aj@6EL@@x$DWT^esW8~GqE35x2eFA;u(CoC1J6VT)E5+CVs@tAin~iXQtQPeg zvaUvfE7fl{=v0MHnG4p*ZfkAx_X)2S%wpw9!Y1iRf6OfCC@*!_?(m~FR%97+D-G|= z_!g;D3nm^)b-gNO>%!j(JWW6aF~oV@yQ4P5j33NQ^3q*Io^1!|h5H^`Qp$}Z9%IR; zt1KtCrK-VE#~{nL(PXQ&v{l-XiMQ3!yNX+%@^;mhF&9^txH`TQop9Rd=!s@0p>@&x zpKbhF8&SC;Eo_{ut5Ac^74{bl(jWcwBn%VVKOhLts}p#C@5+y!R8lSL?8zcC?25(e zX*KSSKFB#MFkFXRCn<<_ybO@kb6nOB&!D_WF7`IjC2FK<gm%j*E!>dTvVP8xZv@_<*e;_jiIN7m@Jr9?pTIttA`A-HR;h% zSU@Lf57VVg;t%@G9V~kntjQ=-Rl{&!&aX(w#dOp>I)JKBLuYahS8h|TRiCwfDD~wa z6acU14*Z93^Q!o7%4_*vKMl#5Bep9&K^7>y7QxzoTX#NUihLXBy*r#$dqkGX6uFTz zEl4(?^NTU+reS(%oy|TE8hC-zJ$){P%AD`tPrB zh_GR7j;&Kjg4&@&75p_{iyu6sxIgGNRF1p~lD^S)dp`H6ZdV4rEqW z0>xx_?FBv`>-$l@)Y0%ZJFil9Sej%}tuxTB<*hs0Q{Af!h06HH+wn_$7dy zoXEbg5%D}`2)d81s67a4j;^4f-4b4%{|pj*QHE!lEI3ggI0rg(3V;kdEy>6!c8>IM zI|^i<`-siZ&O{KG=}$5_oZg1`YX=RSvux+(o25TIy01%|6_($x716VZE@Cl#y#PnR z_iM8^tXSO6MuBY*gQ`!M-o8TW_iBe8-;oPS9XRaxZT$2qv3{IeGOFTo zijNbAjonboJ=lZ2*thU&<507gJNL~5f<4xg!9%G3SACu7E1r}r;t6${=c-ZOlwK&M zL+ib4gF7f^p_+g1`UFqe!Ol5($aOo#Wn%ykZuLK`omEpDZMd$703if-2o8e;3xmtx z!9s9%cX#*TFu>p*g1Zjx?gS6+?(TexUA5OgSO?w5UDaLP&-?a$-50@ojiZHE@bRP4 zqCA3ILyFR>;V-BJ^C*$O7kk_(tUW z6hDjia=a%L(OJ(Gu_2FN6zaokT=bBm+~}L472hmm1bgRfg)Js@8(zvkAxeSoDm912 zkIc2|jY+Exe2E2aH?yitgV01bRr0CSS8>df)AXYQ9Haz5ihPYr;0RZZa$4aT5gs;j z2GyMsqMnbWxCZLIm~Yemc=g8zX0tc#RNKxwtr+Q}%bXfzze8d>hvc8WTd zG|g8H#xs2QmH&z6aW(J#8yQbmgQanQdLd1EP*iG=Vf9D_4{>#>u$F zSM;V4l(A7E=3jgC&W}&jyErjXz8PN1k=`PtvH<9uM zq2@;(c;0~@3B#N%Q>3_M%EeVgc#7X(JhJV*^1g<5u?&t(3?@mjswN}Fa4lHT=t;%X zVs6)M=`oENcY(GveF`71-2MZ6?hw+~DzK-lW%JE4m?PT<)sGW$9Z64Mg5V$`N8&~n zZ(lD4VE%WuIDP4YHLi%G-OSNnLYn=XTg2)yW#|gotV~zZn_5%~EQh}-m)Ezk>MX-< z{`zKyS+al=h((9Id0XLXIFnYNAZL0>0PUZYgHo&&@lvX|xamsA)0@2elobC;OLc_s(?i ztex~bllZr{TwrwVF@Bj?#gXBi=g8=|=E49P7YX$90wblcQA#otRUH<77(Wt`>;ldg zN+ztK!K$#%R+ugN-Lz*W3NCD=R)_izGC4}NpL_-qIX!||17*jrM|T2utnq>mTAFGi z*vmkVeWZk01Ao3nkSOe{ezNrPSZlHN%4@v*ou#JL;ZH!*VNoSN-g`rXrQaJou5(<85 zcBK+*UUU4*GEtpjU*`VwGuLx_`6S0bKFeSir2Vq;JGLcS5#h-{)7i2yOne7hhL?j~+kQz-m~q~m=vx_UpSe&cU_1$-q&t>Nt!l7n3g zo~#{n4=}1V;XAF$+d3npU{#Bd5$qW+7&3rDCfH{e*2V1dOgV47LK2viLc)77Eum_} z?mjCZwc~+lKJ|ELKLfk(&ScQWVNrO$r8P$<#)Ff0mf(D^oFnm%u{yNcq1I{aQ79y@ z8hkk{AYHtbq7XR7m(+8_&f)#5`r9b&N9Sh8;6?~Y+22gJyHMBnj|hoe;LA|Kzgp>N ze8xG+-=tPD@(s%()X1lmdD00dEDur0l)X$@!3p;tdGU_;x%?uCmlf}>>wHU*(&2dF zCmSQ#zs8f8fDl5k$$s4q7HGGG7|f`t&Bo-5pwiD|wwa=<;&}|+-kxjW-#PE8hZ1Y* zlKUutfVqQX)5a7@qySP&+PVhNk~m|1ghjXMhdPjZO5XW##6cVU)|B6)P8Ws*z>F`N7i^q9II>CuF>0JJn3wo5dJqQB28wT%oe>ti+6@V?NCEQsnb=H zPJ|4Z3S`L13YI_3#18{{FK(G~jeXoP8Gsw=Ug0N$*@l!SFuy1c7a!H(Tl{G7b7D0$ zC1ifUQkjcp(Ql~NZb#=$=YU?|#WU?S4pXpVo9Cpf4V*c^o%BW?u(<4nZp*bahQw>I z%b>6#=7P^D-j$5hoJ#W+Gurj(57IWaxx|IZ3WD=Ut0K|+|1y(GvY#|ij2v9{mCKqU`<_bQsaqh2s1{|NUc34xa6#{&-|E6izj8$&xr z@nB`+lvnxTGS5-GqUTD;&wc1zPt%J!(q;xwDV-xI2naB_iXiMpI^%BYx+`MV`(w9L zNaVAy27QMyH6INy3O3)KNr%LT*nTMZIF(4@7ss6dK|7L z6SADqKmdOkyFMX%2kA2&$FC=(hi(C*G-N!1O--R34oC5R{{eV6CGXqWK;LJ*K>ZD7 zr0HmV}pYLRP;BRGPjH9fbedt%>j6%ZJKTuq*i1`DQP3hQiCc8Z)RYYVm~Ub`;sZ_{ zxj8NlI{gtr=w(gTZ@S!wE2=>Vgfe1%iSKvx_S;ie+^N0>Ctp*p#%4D2qP%Vfc)pZ+ zcf(t$-6>UEdPtetQ;*Y%%}Jkml4LW4#(1MAEXc|6ad3dWYEoZ+kb?fT2 zDYeZ$atAh<+Ms?sZ-P3Uj0_EelC>>Ulx6a9mb1i5tmcrCqr6pvwzgWu7Hd=z#l6vJ6l$IIRcm+VnX3q|* zu*rg$8F%jvd!wzC0T)IIttCCBRBr7+E%L_WLZ^((!EE)@pQPe#4S3=<_8lf1d|Rfg zAsltyB92ZA7FU?YeYthRssnSkxBaZcmd?fqj%~H=v;9$BDyjK{%F&pMC(^i&|E8OL zv*)Luh>QY_8}>{@zNMa2a>ZfP`6Y#bB3DlCqqKBCOa=H7ruP6_Rc639ocomh8%JZ^FuUE5U!0OxSo>r3Eq`@?ScbdR-bM}sBvsP-*P$Ry) zq?C%dsR~~^hh+<2p2kSnPaLu1(f&5z?!Z}BEoz@OqjY5qk{rw7xI~B0Ah-7W3d3i5 zdV%4IXaWC9-rciUH_2CIeGKv)v8{OIlvjd>5pp|qFdwux&cZT}Y&tU+c~t4s|IW*I zp@s^5+l&;+lks)L-zI917&1%caRal}yb(;o$*HfwZpK-K|2}eyy6e0a><|lz%?7_{ zJU5qT{0%E{+M1FGh;p_013m7 zR#VKx#6Vi8!7JE8=_SjuH~u0+a$SZvLO9Q%W9o67X-xWzrHQHCPjg#dThP8OR)V3<(eaSX+0D19!n)9BMy@HMY)rR( zLc$3Q9oJ*|_}yd|47MYY+%jz}VA=pK)3{#f>pw%#2h zkKU(Pua0NE7UGbgqOD@TlwkUi!AADYvV~Ww(A|YTz=5ji=%5;KURjP7ZExM{@sXHfJ{SJ4g?oiwghlOp+uY`!brN zKuR`mr1FF7C5K0#^?KoWEp7MPvI+I%=qbz3n0jNLCHBCXI8gR2j}C|znBA7?r&}^d zK%__PPicz6aYaPKhQnyLoU=(5{8tsSmY8|HmYiUK>x!!=^}hu4he%=2N=^kc09R2Q zfUD#ry%9}55!}icZ4BO@4#1BTBAGU@N1G5H)T4*9`2P^fwNSV<{80y*^cT~#Ti@!C zSg+=*e{sFP2@&>-83(m)U;wJXzvzr3U|;a1kJ^JZ9<1V|a9a&Z92IUtrrYNC9s1$G z!)TmP1R`wY#5fl(+6N#cOPW#DN)$97*~Q))znrWKdj6Ah^p0v%Qw0BA0NqON2?c_` zc|VK2t?=DP_$V1SPS?xI?#{U!ms#w%MUV_yo01R1Ha<|DQ~NBZB>=K|Zx&URIKL|t z=Y9Td0H>eLSCJAc^d3@(ewqxwS!H;;@8)hqH<<;7RGyrkF0Ls+ZCzcA&er)e?RbH~ zlm2w4GF8@sC_(m!4-BOC`tb-ArdHGIo{nLFGmQWPUFXIIU&l$8;t5O51Ah*ODq@or zYHfnB36u(}SBUc{uh`jMdZb z8D)JCC1Gu&acZt%^ttMDAJpAEz4xK*KL9rK3z5C|#bXtatAD4XeugUW7UegnmeG;t zDi}1xv;z?OiQ|wEX?{jnnrh?r0m4^+ET}C9f)(b-ek)3Up49zQcauDu)60cXK4^61vZwnn9`eYA&@BDX<#Z{w5DeTnb02#m}2mc!T@8g0cL}mco9@H|LA0d?Ac&XFa?`hm}dF^ax|=*@8+txi^{d#kKeYG~vkW zzBfvSztuVym8ObiX&PCG^0TMdmXz8lGc4xL3{u}A!*CP<%Yg%| ztCK%YPJh4VwrLCI+Izo-ZH~&<_t{pSi9qQ8vYLUqi7aXP{rAfT;GI4qx*AoVWk;F# z*>CuHCYwB}&>NH(IpVGO9$azCvDuwUyd9}O%RRZ)**rNBhqF+dH)a#f>Escvu%hx% zY&YGMlqFyIhuDHiH~s^hWN4Q~ZQZl2Oge)d^G1P{x)E5VRX#2gfMEgal1hAk?Tu2k z5>cEAbm{uaDsRCBEq+8pk93sLst-pBmZx7<+cYFx(2=O=kfOJFCVkXSIg|9bBvoAu zLzUP*-4qd+rCxfthUfChTheyi8jp6MS}I!T*A<1iScoFj26X-O_}8zo6YWk1^>vni zh`-1aeaK$=V!f0TUT(|rm{!m*V-Nn-9uu&NTV!cl1fR&T>UneSa!M{cjc+>hUUT9U zr^Vs+kCm0Hgh%n@w_27?X{Y5lDFzDjW}5&QnyelXnMsL<-@-}SN!9r8U4mIF9=6Eb z(L;UJ-+pXIu{7)2{M_gGO8@LjbNh0B)vIPS%+m<>j0AX4R*1?zO$wCeyvx{(%d4&g%@;aIeGFx)M|-U z+Y?7t^ZE`FZc`(u7kD6T-elw8=pOM!S!v~`${quw0|68`ZOP_4yAk_K?R;(PJuTyJ zb(ckhhv3@RU>WGz$P!|f7X7kyYbHR@4UL#&CqTulm5i&tq-kC3`h`36MId>fqh>y{ zlviePKsn(Tv7C}a)HEO6lg8048nqPu!ot36t;|43eP!ubucF-SkO zZ}9U{#Wpyn^^L~K;qlh4V=%IL+t$Fc13h^Sj-w@ODY3rs7d)`fX{4FLBsw|)V(l(o z{Wf-yonxSz+51Upj8*#lX`UfZCB0L5+2aS^L%frS-%-Y%CG*}~((@ws!9x7-197i= z3*2n~a$bZ9oQ{M_2MWn8*m-dFwo3R<?>dwl_Ok3>GWl*; zaTBDj4`m!?p}cCe@o+QWBiwh&3~=~&7{{Kz4gPkKB6@LFhIYGqx*uV;v1BumYj0O# z)eF5WSEMD11wuXH39D58l&BZyj{2h8=zlgPEcXH3R$nGroYHkZ^1HOS9XLK+dlc&9 z9^UcE4B8gRlb@eKSHSUn4N^=xh)PZHp9g_ATeTcQVbzOP(#6MG1!t{(x&>)=G@g`} z#1xw*OrmfxC7CRYQwM)I_X(HyP)K_g{rCw;kslfTKTxOHUIlYT_>oQ!al zRaR>a`+l)7Njx^Cr~iGk4cd$-b;9ii>d8)gNdz&s10XLf76ayRbcqNw@#ant<0ad#(cUQzqfGLU zYzIFo2Ou_9jgg>ctr%rG$s>_m$IHm=>WhSH^r1##b%uW&B9Ear@SH@7&-tO_)Auwh zszUIA_L0UX2?-o{ejM#6w?HMYq#!*xB7xy|yV;3jFw68t|A3l1kok^RF>QwFx9V*TV%1ErvS*sLd2f@(F8L5yf1S6vNt6c>%G;T;;lo>s{3{`; z83JT3s3E`IdS)ZxDLappaZc&~2Y|E8ZibJr$%Aq+MgPuYoshJzkk{nn7mJ-r5P;E>>u{pU$BBwe+rvi4pgZ}|gVb7*GE!GMgpz`r}`sP5zk#_(A98gR| zleiBEKG3h%%czjNSdg7R<)pSY&L7({8gAq9xTsxmA^T|q&*fLxmat6_MXdW82j(w5 zTyQwlqiD$H0j3PGuW9@+4YxzU4)*%mE9JJExDWHz@DIX~SIvDn-eT)D+)XuPT*AsU zRQqPOtmGoYd_YC*cX7xes5}>6f&kVU$^KP!HjXQ6$G{e5mw|=QOQyjXC5MT!n%*N1Ku9>bMXPaWa zITaikK;Ttr3{ilOHV3#45|#A@u*o5^zRzy`T@&kCVM?}|buHQOXvi(`g$drRjIY~6 z+oXbt(_J!+*4PBR%Y!o^CkkjM`iUbq zcf_)WiQtKy$d6C;5I;tgYWvOO9N}1e$^YX0HHcYGrkAt5r+S6vFnm{S1a4K17rfBM zE+;q>PP&coX^tH6I!IffC0n3mdJyB&CK35(YC93?_`sRSqdd)-&b0BE(dvh$0nWU! z1X-^ihSrOhX1=U zepy?qR3hQgPwn-$F|h;a-eZ{5dTN?Wq1>l2lZ9w#=UMp+4R`-6y_s;Wpr6gxk=P=- z*oyDg!vdt8RY$%32CPkqNmf?U?$SwI{pN+@r1cmKB3F{Qj?q}q5AYDcc6O#p=tu1| zbLVEPB zEVz81<6xGTSztnDMx6U~2)2Qv2r=Oi7(}X&CJEVEIj3K9>Q@PkeXkncE^1dXx@U>b z;~Xb&G1r#4`wPtzg%dP8++l$N*1vw1CnCkr@=A(T#MW(*q#3mhpkG>U-jx>}oX(;W zzViG)1CdN@ggT~q`CU4`P=nDKMd^RKfl5AidomJ^4Dn-P$oI6EbEK54^5(ZoQ8k7l zLFsJ_!b87a#WG?3W7_!-pm!suqD{_XvEB5qD*|0;c+C5%wo`?|e(!3O`{iU8yEb!g8Ppk1sw_D79f= z;#XKC1#FglR&i&nX6n!YNazy>MDG{Vk?efAIA8jS#swA z9+m<~9CWTCus#k^pk}IBUX3hp_nWy?&(i5B)f-i=LwVQ3^~u1b7x%qNo-&?Qx*f$W zI`>)vP%Bwu_E4;G4##Sv;?0l3{4(e~Rk3G6Rzguv3lYo}FMR1_ImPRbTDFCGg<3M6 zOmZYhP0i8`Wiic^!i3wL;~wTcg4ma_gX3Hin$q*PF_+6nYTO5=FcD&Kd_YMf+XrFe z>>{#t-v{^&^WIogSk`PhX>wipIF^sz=pGTK1a&$Wf~`}2bl79vdgMvE)s;8-Sd$&| zRtMKO4M}Bbo&lD|WIAo#2`m>d>m z44nsa1r6e_d#n+ffZghMTY@`=p(2^uvQRNw8|P2KFSw=h+0u+1Z$?8bTBLk?=J6N# zL`KWk)kgxuZ`iDYuwIYWK|lNpp+NgK>8&iQUg^f#6c)RD{(J_9WmQjeoq*BvQ{C)5 z8d%cxD2FBDFHEBR>vaS1Xj4@Ja-S=Cn4h*s=zGgUPW}36Nts0pXW#grfBG?emn>#6 z2I;d~lF3{mFsW`;8+@l12%4&(rK~tP@4$-sYeevVGYlyN9?(ZU#LXL@Bs9JhS8Be$Vrh)~)w-Oy`~ad!@9b z+C+i7Gi4otyJ6M_V&Yh>v4ic1808S)^VRzDg5LX|6r>lN4XN~}HBvE!XAzYQYowTD zd$ymLYg)wyp!?M5y>{=-6)*B0@_-Kbi}%@89{s?XHW6#jdKMrz-mFN}u$#X+JPFL4 zS16%zef3uZzo@y=UuJ&xzoWtoK*ch6`ifsR#_Q$uNagImfWQ=?Vq z)d<KM;IR?gDzU3?rrXIO=q#JyxVh`GSoJ>Hn71CBE81#pYz>pG>hx5HnaSdYGVUnYoO$W@sa>T1aruN^@dx-E;Aky~mfy0UlCZl zCj>9?240jNnrz+>58q=ekUX@(J6KPKb=0VDKp*=2RnU#FpUyq_W~)Ty=XH&aE3_x` zh~d(XG41&8lf-dftm78H2XfA{(iXAXEdCrGCWQ^Zt%Jju6si=3adFjf=Mq7G=S7;| zzs7X&QgE^s&G;#-G8Qkogn2*dTGsh}LzKr(jZ0)mY4uXy%7^J8U@5jsms0Ijq1U3r z&xwx3i5*|!uP2iO(uY4~YP&+@mqHL$%@mYr4QX8?U{Zrm>G`$Pv+ zxXKGVT5?vw;XK#X5+N3<<>$T##Li^y)R*cHrRO^UelJJ$j~!^Y)ok?(P^9I3dgEsQ zs7x&K4krOwi#!&U6tP=D_&Z)Z$*|rDcSlGkySeRLz4O|t=A?5`J?PIr=84x5C&tHy zR2n&lsjTtj=f177;d0IX3URlXa!V~4hH;MMh5_xs0LerGY9TJZ?MNS}VC%Cv#_DT- zS^;E_${>d0SM+)GFtR7^>5`I2P6pZnDZf!&e~B&I8h>AQue|ZTG!wAiWcwUG8&1GE zTYyneR_|P~8fWR?UdRZmo_T*@3fB4_CR@G6KT*d+D_CqnPyS+i^skq75$~v8kvRIj z-W5>Q20xZ2*vWDJw| z61tn<#7{a%h)|>hX?31%j>5pRCg755Y;pT-7;1^??tTF!@tupo&Bl!LEU7%N+?zM7 zkCk1>KGGmP4-B(@6!*LEx$rix6yh6knXAXG8^J%mXLnKqiOzTEsN+X5N=z~^DIpz| z@{qXS4(=;zgB`7UM3~!@U}fO=i8t+-JTgoF7HV=A5_3|KW1Sn24lJvjTaB-vqO5UA za@mO8+@j}XC$7)I-TY8%{+^)Uyh)ekXk$d}qHVr=I~ueY)4a3@es(XwUr^54$6bCP zUm5TIs%s$5KS-A2Qb@=2$2Ajg&1uI_HH=hv*t!NuE-p0`9d%*VG38NIib?N?d#cZ4a;+7JG_QBixFbcNh$ zjz|!NiMFfLRT15nI5m-+Pf+W0+HAI}-b&>pMzO__66mv<5-v({6Mr7UfD0SX z9;nCKO^{0F(K|yE-BJr6jjUx7uQt(p)N2B7MD8H84CEAuF}XosYgkk_qWffiocI~3 zV6~bnd1t2C zu+V-O+Ha=Q75F}vOGxxj{?=ovr-fgaXF1MnQ z4q|tK=D5rz#TQ9CFLO?^;fe|S+vHd+Cw*EA+2VRXmPl1tDgg=!>zEo4eFWJQK8QFo zcUv$?ypmXTj>@oPg*%CU5x@Ig;YdTPV+Ud5bHA@N)0I(%Sw|h*?6+f&jDrifwFd%{ z#SvbH7wo*A=f1Y7yQCLPlv!^cZyFrgR**>%v#k3Yw`5K9{yvmhOnR%`+^zz4Uf{dP zBF^V-p^W}&OxDbA^UgVW$Q_fJSZxw=Cl#HCYOZJ(w>5{7u;nCw>WU{Mu@zTN7A)ea z{O)nBA5Sggi=!EO*2)g|PX;V?CXjAZZoc&x!q#&ju`-_TO^t7^j;!S8#z4Yp0p z&kU(aBxhgA=>#?HC9oDu71*4Gaee9L^Z?+N+|@??VORE z_x`SiD$;RSqy@W`geJH(bt77mxlw>deoNrqwcqd*ukRt{W71N}+lNVE$kV?gGLFe32hG4OcYCnWng4e}tp7xz~;e!<;3 zu~Pmnd}Smph8-L;@=*-allN4Qq>})~=*uv{IEnC3OP?+sKflzS-*}BdC_2b9I3|T8 zz{up|Fz<5slYktxa-;dDG=2d>Wu+o9&HTS;!0V?;`0GDPd*(FySWZ@Ma<=}&SmJ$_l>6G4Lw(8SX|($>=9nuQef{ zw^N_<{{U!ch^>VFn_p(P0x(TA7pz(2RBPo|1-b@&Eooj0IAqpw#R`x8Fc*9TY-wtm zxcMSQYx+M;ET;C!JZ50;`PSdUr+iXva(}NWEGhmQ%|R9z}Y^0A+sfXbiH*;=v|Ln)FJSh(PX#_!j#+f%%9lvI7PvNzv zY`<}|j4Lw9wgO4SLY=|}Mq_6sC% z$dwA@G_ChK^&gOm5-;Vrc%D4e6;+jvI`m{rZabcDYoG3jjH7y|`n~>2)Uma3Lqc*P zrUwNCNJNj^Ue_~`Bk5;L3kuw^t_{c)G_FSf=w%EWf_S!*;fqUHAmgAaYW^K4Yd*ss zr^^|Vp7&+H3jUU?=)|5T49*!W!^Ap{eHsyE81~E@+a8VT0$<@ZoKwkT>7?xm%n)ye z4oQ+GV&lc+B~r$@8XO0WXgKA&k~02zRj{xUI}u^u$$xVIygiO1O8pow~BwwQD|c=r{$rN!1PVRK=QiaIqqyajQsOu zb`IyTT04qSgCl3{BR7Je!OtsdJDy1$h-8K7q;t#U@uxg%#))5wMjg8tR<10W6?0^>&eyP+v8GOw0rq+Vry6*>k2rbl~1Zpl!#QBq%1_pn{gNkd^7lCW;UHWaUAh1 z*JcJOdZ-51CV4qU@m|L5?cPRBwKDFmZqU}%)z-8;S>v}P|I%f^^JrkqvRCl{BR9vr zSkTY30@o=!H*k*&e?|Nl@#$ls+^ew(5F1L2T}xd zc{zdwLf88mzP(QN z4A{bw$(IWbIBr#_WHOc1AW^eyOo$~!ZKynlvCHwNb>1x$CxX*D} z+7`cvbQU!5cZe7Z=!=Uf{3&OBk`re9mQcEM$Sjyou}H-zAx(=O4Nnp@oS7UMcXjfo&HI2;18i@;Vd%7O1 zFxHoGMSY0+39AkslBePy`Yv1uiW?npccXZ3zHvpk>}BF!V3SO}%Ud2Rz$McKPj1o` zqRV;D+n)UVJHB57;f|oy0Maon4kv|O#twO_HPoQ1vu{c5Ts-lQdLvj;rcpp?pspr_ z7708I`tvoMmiRI=XiY9N*qg?}@C<8GgKh*QyV{fi@PW&me}7BPebFQ;G7U+~Yx+5K z(mugQ^1dl8qg+IkR)oDGzL#(9&5S}cZ(EmJVts$vDdUSUF66)1Pij}^EK zh_R@o4BBK;e}Pi_%fc)@SL@MRtG%+(G4SY8jF@-CQ=UavlEft_`b1Hq>)@}de0wiT zlan_rrAx8!2L9BZCu^8sHHkhO(^B56q6uN-y&rq#DT@7F`z)4NqNq-1PE0AQ}|sc;H+JWU%{9Iv`b zcP#wA$LSN+fGe&&*{ZA&Z5v4A z-X2R^vIBhWxHc{!n=Nqdq9(ArYG& zMLNln{XFJGk5yiN0B%xmhKKe>-te2HC`=h;39g!5i&mhP*_Gz1vK{4|)Eo`+-dCuY zjyGTNXgZs75b3n$6jtCU@?HKXvwNsUN5SM8fFko)l`X1)mrv#STF{MG_<{6;I?Ul3;1P z_DG^{w>()DFRj&UGJ`|vYDP{WBKFIac|j@k`R03%|JAb2N_Y5`tI4+v-(HD{;I=59(Z9=Gj@!r|UrO1{cs!(T!!t-V-{6PgN@XiN6 zMXg}%DVC@~?r<31$D+dc@};PJr{al z*1}#R-8n}pzw?<8dCiwCZ&`E<*m%JR!X#qV`7|SJ#mQK8f*7J5)AU@}hNF1#g5$TK z#Zujg`9jt}`?!%KpVU9M(W(Ja`D0?UDdgFP2iymu4lw*G!c88}%MnVMcR0f}t1_>f zpZ8C@A!(?SEYf*RAK*vfocR;EiW>SA?}Hsy@~9o-a)7V1lIA2w&GMsTxZi|mMRz#x zKLF3L4*lZ-sdK+pE#yeL0!9mKN*`xQ=P!|>TvHV~#&ZmY9DxS+mEPNr36y^)Vr>f;DICiVX#0cHoQUoT3`{>_&b}fQ zpdwQqH71I%+0~7daZ;7M9KxV%{qlG}sQ(346-r)Tt~OjKv}h3T*3wVe)Dn}6AdOl? zEXJiW___<+|DD33t5M^;6IyzB#~&N;Mse8z+bEp#qp)bKa(4Bki+6Rk3~LP!45k3r zV8o&0;*oeQl~0Y3QER)J(yKJo%G%#S+D-fto9mpr?}5N*4(~)h&f{eZ_u3X6%j&jn=G!#gh)iBP+^~OLuhcv z*3cHQXc%XVK>nQDP{i}EuMXfO;UMc?vN;+X{U3n*i}&dQK4Sz7MG9ApB7$m}^0OEm zH7mfFMi;>_f4*4T8tFd`WQA&+4m{OQ|^w35R9t6y7uX!BWpAE zmmtYZ<=MUUm;Ro$^?qwCh>YfkxNzFdYB2TV|h4bu*NrvvZg;XaJnr?l{jn z>%aBcx>?I3d$YWozZR5Rd5Pbr-2FKyT*8RkppaaqqjQG)i>mH@In%|sC6BIY zt>u@7;P-XvmIN4OLrZ}9Giy(--mQsQ zqm#cU)u~}q?lyUUlR3}+q>s=x{xq0$OCI4tYn7AKUc-XLFb!eAV+^isozZZZmX;bp zrKPhs%e;I2^9}KEfl2G^+3L6Q)x;><(-w+-az@tEg|)(DA)H$&Ca~SRcuKcw;U$)V zsDX+jA8MVh?pAK+q)-!qc&^z-7$j5X`Dwtg_oQm zFut|jQ6Eo`@L1?`WjW_5K6(9tJGWvFr!w%XGg;v_5ET3R0~>vjWHSKlURk!;-%*4y zNDAOAhgalg=17ij*f;ohWeS`fnNv*krw9&SR+zsMI^yHr+Pulbw%M-HH7!xTV2rzC#!rp^Lvi!dNt|Qv4?c(Q2CGUIZv+RK`BdX2e6|50Jqsq zkKbc_Mp$2m0a83FZUwARqT2r|KRkapKl@>(_~Y}r2d?32VEQm!>nwG1 zGK*sK*6(eqIx1Y^OHSjY?zitSyl=R*JU=aQrGp!&H>Us@9Asqb7oT#tvv!QOiAaBb zoIwan$I8I;RyDoi--soCrm*U${FESFaeSv(qL_2GEvKVsZ{EngoZCpEWASRhPS@}( zOD-d3GM8(%=E(iMVGy@!m@R>25jWyLfR5z)%~2bOY5Gg-rDHqz+=+g5OVDnZjP3bO z#O#LLT}}C8(P~yD4Tzls@J}%+Oy}ur@Pp`Y%jveiH~(I&X``17aDcp3Mc0Qlewpk* zt-g82@UCZwVHTXRT(g_XE9}LGL0-;PkTlWq37Ik@-tR71g?`@J! z#0(9X0Y*9XlxJAQ%uXY6YjQJAtc5LMEZp4iF;{B5gsf9DtSS$v3e<_t|L8Nuvp3=V zr1|zLu?Y(J-5SOsw*1Gz zx;WwIQNvf(&k0lP({=fZQMX$(zgx#YTv9)e^+*Wo zb|MRw$2-}6A$@ejllL}rVqvS!{>_<2%v?&|`|?jTQQ3t1{cLyJ6J2Em6%k{+WToZl ziHn%=+RD+H)-k-AoR?jN5r2AM9~@b6)>=ciFjE9y=_f#An%tYFFmFmK#>0It0w;(Z$m>3zJ9FNl|>f;qCB&KsO@$ zxkyVXaa(>8R}E7NSOC`2Ue8EQ3>L`^ln%v)(IG0wR$nRYEPwet9%I0R^eXx^ zAYgEgT~(8?9D(cmrg{{P`j_>c7NbXWOlE3YzWQ3l6)|xx)kedylw3MIO0G7{hjoM` zlQbu|JX>bDF;W}nL*3bm^GJP`c@IPS4GGz&#vdsLnso6vlO^_V$v5x#B(df4Wd!Z@ zu~r>jb1)s;V2aBxCUey{%s$({-#tO4psvvx{{a})`jVISrW{>?^j z(;TZjF@YDUhPC1)J}_=d#LffKGqPVuC$g3t4#czK2Eu>jt_mEg9_X(I4ef<)#-ma3 zjp8F!`UZ|Rr)GsNlT_6Gar$X6E((8x{KatYG>+b>^!nJ4|HO7(%}H``7|NO0U45OO z_D@$_V|J1MX>Man49MM7f1Pt2pynMBNyVnIMEB+}dS~*@sP&ZQ^pSGDWr}PRKWySH zx|zu$1`dqUIi^L-za4&Mj!O94I>4UT1Prz}^yujVUrRk>TN zUL6Nfrr(&cP35I+Bx1bvdOB}rdiO&WCSs>?c)IJFzP_S6EjsaYFB~JYm%R*at|OSK zhzFL?ndi_{)l1D&MfvCFWz6BWWwIY)s)4Cvmk(7h>=Jzhn-6&IqCfam&o$&LVv~`6 zyGEUZVm#|5Yu3R#rC0ayfCtXRJgG!Ol-M@RJc7qwTK)IS+`mEdTt@h*2s^`6SW3AQ z4S8XLYNVzO$^ycl<&0RqrS{N>ko^b1qBQuI=-u3wddwwvS3hQ92YxVnu-uhZ-9Rke z%g|Wtv{Iy-gF`H?^xE564J!uuV?KrB%DFy)$u$M`s)a3D<&;AbPf6ZT&N3D5-$7|j zi{t(1;yI7Vbry(O@Di&X}qnz-+r{9Yj*?{eD z3qi|$?#_6IV@{@b5#pHRB4WFOLyen0|6UhU5DcFmY`z?MnNSq3g^xRWUvzXPdz$3OS))tEU* zuFh{B%KVY8%7*{p*J#_|K*o`KeSa;g+GPE~Q|@p2$`%L%@=-C0%?%mB3grxQrK6%~ z25)@Y$_i)H)?cW6NG(?&QIPCX^*l(gaK2E!ahw4RX$9FA>p7VxSjKKT$k&gcz(I@+ zmsg{h$bny2Pfk3>?F_%0FbC4ZP6g2&Sb##~YysU?YTWpi#Xd;a*Oki-cI)$EQ{)N9 z5DfNTJc^e*F_0(?u`8#iL-$a_1ZT?IKTpO_u+I^+Af?Rh$mHh~Zgddp!OLMOD|!*D zqbJv4%G#(iZG}7W@4^%w*W5Ta)?>RjKi@g&0=6Qye%h&_zh(JDUZU?F zBI|r@ks=D4g+;f+;mBH1MSnF*so6FT*Nl^a;lH0goI=%I+pfye1 z!SVOvCnPfviPwxoKJzf$%Ct21I8(pEnHLFD_>6rw1+?Ls*^YjiHG+_c(`aP-p`wWb z|4;%YO7M0i_F(tju0Mf)Q`?i^6|k>&>dk6>a6AZ-=pJGyGEB6iZHUFWbr?<4SI>jQ z%j0nbaGf!HVWf4>dYYnssB~ik8NxbZW^t{rWS$&cY|?jC*O~m#AH6DW4YVsCY43>m zl}lE~@JS7u==JDUKp!Xv5`BlN`fRO>zJnK-UG1WF^jX^n?LgvZ{aW7FPII*t_G~#2 zb(veg2(Aa)fEapIVopwxy0f;L4uy`0;)(Bvy^o?|)5|7$Cv2x0-=bdSLEq$l?tC2< zalhgu4XMuUt7FZLs^Uioh@onY(DNjWe zhp}u~(=157{>#>9D}8VCjSs%?K89UNMlytqpG}$BLf0bLDk;gAL;aS!6W+FGIRCW! zEXe-sFC1pPu?5}V&srDQ45wilk;RkYH0%zFc2s<1HDPAuGPDA@Ons-G!Ii`b&*AG2 zPWXM5lg5`zJ-&e!=UZ8AO!rgfj0AoeB|<2gsLCsY_Jz&)Sc^q^z4>9A0i%f&{T5$)*N{=dzz6 zpkREeaK^_Bk~I z1t$UXy_n35F1E5#o3|!Nx5<}ve#9klIArbU(9`W2_9rP{h`6<8dgZ*h7$Bp zStT^_p&ItV*^>~&IL~_(N~$e{B{c~Vy_$#Mv*uebCd1p_i-0lpUIM?U*0>e8d34)o z!#S3=&DSe@}?Vi*^XN1K!3 z1OR_e(Q>KYolDNnCcNcQ;0G2eF31>ZN^N|u8>TNo`&J&4%pWp_%=5bg&A^-0o^y7HlmQ0fMJM_hynv1nqk{@J+ZI+h~e?!B50fxUMv>}3^; z23Bq?btp>5qNrzQ3TOnt5flbu$89zDhSTkv0mSA*Nf$1k8?m3b0NU$9HK{tb@tlw? zwCn!>NB=t;gf=$<;9s)Z!Bt|BAfJ+d z2-5i8lYRiDOYR(1{AgdA_g^OkNrqm39x?**Q~z$g8Q5BehPKt-9_#6va16mlfS{xv zr6h_A0WP{ISKhdnXm=Z4*+ShAtWvlUY;@-r2#36lS$^ST$vC54(k8$xYoTEw-lxUP z6c)Xa7fTY#xz@+MOpTl4_~ai)E8TzNtuT~*XntMvg%{e5p@T=%{x)1ld zPK4d?OS5PI*+o)|MKBjk@B^Se?CXh4bX@3U?P9wZ4T{S1HE_H*=d!hq&i$3Ku4^`c z#M7a;lHE(rN}raI)PCaMq5uQ&wq?dXV{vx&q(Kv-c6h|x%v1rp^i09@GqLg$MwI#F zgo4EEe6G-acuxs$Hy}0jM)doRGNZ}fu!}dIEpg>CQTi@t@s6~N(d;s$BiM7T`q$H2 zun)eD?18y7z8Z2+UWL7Zl8abbnVx+GPndx6TyHP&u@M)+F)Ait^u>s*fqBKWNRB+B7_J6w&tsPr&=x^ z#0h0NCOMZJKNpjNE>Cwe!7Hq5ukT|S^Zz~p@?&efeeFvQ8cfz!443qK+lq2FCCFTp zbS%3m4Uk|8$5~llM6&#J$6iS<^e-l%HE)e+Z(D1ixY~3I?5`te5>+f~ODWLB;q zuk}l0%hRT8xQK++qoGa5&?zbCd@{mQk-m0TM7>72=7>W&N*G_N{lz25iM8r1Z z?2=1H#v$xtt)G>ldzIWjrs}k*L#w{3Gu2FO@{0ws$|eE6E#2?X5Wnl1tS;Me;eLZj z=-aBc&z|~R(*wrb)=L?~EUkmD6#5`>EXA$Vg-Sg8PndF?MMY|h^T2UJ*weS-OV zt%wC$n~oG$8> z_U7e^Gt8OS%vyI>66!ZQgcefjwY`-UCRL@kYV`k_Py4_3Swcbm!?fS`eVF>FrcWu% zjrhI}3v68#4Nj=2(v*BRxgK=cjb%KWPmWlx-Ah^KLEqjZ_bJK`!OO})7IuG|)lL>6 z{uStX)oR|t2WS#VjFNG#q@2LAC;Wm0i)9G3!`OP7w}Ed#Xs6DA@X`rrZ?PSpe=9KBA74AycvBVa*6vyT8_Iu0JSop62m*wv%tXKL=Uzgi!r%&xC-+NIY zyJpoeJYFdx>N_RXMC0u=%xOPUK9H--KY86m%BYasZPAdsuH^`pr9q&Tc_HR0Epjx6 zSkx`0?W&eSjIf#xezsxl@WdzIVT$`ln-cH^68|R)mHA&TBYGA6Bd8jfs7FKB)cJbf zJ1jgZ-&UAK%WL}ED(!U)7NV;?R%Bqzqw-o#QQGi$i6OWEoC{fE{aQqKS2eD4?R?L4 zHbA)Hq}4cWNdEZ`Llir>{tuo**6)0T&I9y6y``cK*OAW(VIM|dja;I=GI6d6xZ>OeA zV>J{ibGpP9M2Kl3y8BGuRjjC%m9H#E)LK{%-Lr5W)D7Z0vT(1SCzx#Wm%Sm0i1G7WGklH=zoJ0ZYwiS){E?HkD2U%UIMvqO7h{A9 zoNmKP-B9{~4^TXzJ)uQUEN;R2VM@wNi5!3>v{b98Y+;3?H&7;Ho^D?+Xhj;9M{T$RDD>gs2ZMrB20lJH6kz)TmKgZc7TB)BAia&AGZ6TIMw##&|>Sb-Ae z*_L68v#j!iZ}<}fy>fR*fj4bN&G~Y7C(C`yhN$VF7%K>^t?h^q+@!b^QRdpnw_lP_ z@LBx_k~svEJLgFjY4c?-@0{|2%l`)Q_Z1g2eU#|eFZ^8DmfG!etj9=v|46=xx!5Ci zet1wQ1BA!txW_&}-D7PDbbhSq$H0=W?|f5Ean=qV{fBE?5bOXvpk6S@T|j!3#Rq_&>@MKYvD?cP+D?5P>*WrWc?Od1 zo9c&8q(3zDa!7v^BJ@>QalGPk&gyO_MFnrr%>~GAyp8kN{)&ihD1Vywe;P=9*pfRj zLfkE=!BvRwrkA~|R}NIp`#$q5aL-?%@+ugN4Ns7;s*9RYW9e7e_{k9vNtV1U1Gg$Q z3D>tCuC{9e)tE~ZXX-URM}so z@5Q3z6YD~_zuJH#u!$ikUqts4<=QUjoD{ZZ+^Js{&P?rHE{tZCx%g^9Z;U9?bWJZx z5(D(jfq|Rkx~AuQk&a60MNz39M?jZS4r-8^x7-q?Qc9}oVRHCXhHa3@D5{D}znS%W zo(IzDqqY;^e}H1Y=;OJqGqeD~d(Cp6;DNjO9I`osV=0FMg#uJWC%2JuNtx#Ne|kO^ z#wUinke^>|-9^5BUhRmA+~}f!85YGUT2`1G=*3zkgbczIxtwTr`;z7Es!=vnyPYw8 zqBq9D6Jirj1jhXs6a~=`xl&kK68o0P8is@4- zUca8CnYgp++$hG+7$7rN@IS47HCrqfZ~2>5!oPUFZI}K|8Tj6r`=sa*sb=f!O<*zI z3Bg^&<)E_zD||+N#{hbziqpqkiuBy=DHaav;uJ%&pR9VDh)D)WZ65t)ui5~EX4Jd> zyqjSAMDIeq=av^bSI;?;@j@}j6Bl`|`$Ghhsnd}$9`BXU5uz}91)Mx@2!U_MQ#hCQGToq1w4NO{2`2Y=Uie!lvQNXBAy;zC4LEuT*(8q%F?MyP$e>F8&o*Ca4vBnv$i4lQq%bFj ze6MNPp?D&}TD@(k>yIOlVk<$43I%-aUjMRwG2QtmkVg4RWa)&EFUplgeYtudr577J zv}X&Vv{~vC-3z1q5kOLDe`T+Md*=5+RN6 zp6hF4vziWSqfE|0p5uRAd_|dStm0Zz3WMEC{?q^ZChxeR+nBPPlK@2Su4@+jMO9X= zuN!M~E^lSt=`m!+3h@mtsfuJwxJ-ILxz&O3@u=1T&}gtmswxAhxS zN52z!IHq>u>a3?HA=-{-cQ5S2jO48`LS|UL-KH7|HYYAtMg&wY$v84|Tc%_oEK)d> zS8Bu_263+kW7<3@2Y8|@`2uNE!HFxnH_Ky=8Nc~^i7VOjL59E~8&fXkbOu&psGk=@ zVgUi(;T<{~;iO`h);D5Y{m@1an43#C<>sqr84!sRRy5G)jq1u`BZok2jdd4;bV72y zFZ|IR-+@s(V5eCJhF$~4AA-7O5!_bdCESYVy`(ufuy;Qc+=gAq6y&{*``uPy^grT4 zHBkI3eCa?QX?h$=cnRw`&FcU`=J|I1Tc-14Kh<7kXXEqN+?@kA5lJ{*yE9L{baLMC zg!~oi5S003^3y)rTQ3l0uo`syn=}vk z^yD1U;Pu)luDF{t!0L;23cNnjiioLZbJoLMme4T|Zw}**56zil0e4c*);JpAM@`UY zDa@bI&&O}2GY`=w{YGE+9^UQLpMP7p3y$(*2+wZ_ zKakQl{lZKA_xMb&g=hg7+?ktqZhC@P2|wy;yv|72na}jLbUM~pA6ba=z*R2(XZ=(5 z6Vk(yoMSCPS>XC4Wq{&KmWckAZquBnVI~4WKaAjyEjP)^z_L|xNXLhrQ&qewdzOvN5UlY zLf8S=z@g6;T_+R`FOv8N4kWujD@E7srgwka)RWE@s-71t~5;D|kflTML){>?7bd)TgO^eg50e9Oj(-@_^U zF%8(G72F@IV}>j?!?qjnMbyPjM%tgD*E#eR?LK(jm|3r@{=Dce4mocZwFyIvyMo9EzBbUvlZZcBLz;=Ahg$9ac^TJ`rRDf$`h`8uWq$zH~; z$mjE`J_?e1ug&STK5)rN!>~8qa$I`GJH`H2#p=cEW;n66jB1lv*>IP?CVV0&X{nkU zx9H~Xt*P=m9Y3>v@erdt=kLuWd{#c!h8BC+fagSVxfP-ep`pAyW}`GiA717qPY_(& z%7~9fC38d;UMb-|gr*;S(rKIKaex$WD)S!#t-ng>)6tN_1TYJLl+TJgOw*P3W)kq< z05-mNSfb2F%E9uj7g%o+Anv`HaRRlmQwH$of~sIu?>ya@so*-Xlv z`VP+DJf;r74WdOw1KH)34W(cYvNQ8!tOD^07p5;X%e!CGT_%RS;DR9|L=Hf4KJLaG z&P2bg1$CDr!VhEHdAEC;m4u0Ux9;E6kfLznNC`7qojIvcDVT^;cx*Yxkt1pN?ohS4pZH zFmk7Y(9@Uruk4VZo3EK`kErm1&9FTU)yT43F*m;1uG!K9gk2(Kh-C14|Ex9V5$3sb zOVj%)Z_bo(oY&e4GbDym!P@~=WttCc(PCvEo*Y@pXVw_6K&)d1yc1ttRA$W=Q^$3{ zi7cVxtY`;7!y$O9t zVjH3rrKyT40Z)~$y)D^4dsTO!D-CL)VtBnE0DY3)*L>n#8RA=t=M+s#m)=+z>u6tt z&qKt=j@xTBKeO%K2Krg^#`Be)R!Ezn^$&Rd(s1*h%SSEB8(&0*ti9R;jm982 z{PW51LpsF$qdIG!9cH=$%R66`;;Ti(*uGg_60??uFx1oOX}hH&e>$vMgtigAi?A^t zsL=HQ-|YnHk`tS@wt4o<_~jYJx9nLnMeIF+Lm6ZYohZdcUMW{!p3fF`|2|kU?}iDA zEs8`F3m!Z0Q}mb8+A509U00Rs!=$*O-OEM|Y?lfFJuN$3?Lz3E8ZU-@3slJ=OXf05 zG^1XF-&>3Vni+P;}l)6RrTdfS?hKL1Qr7o$XpYe$x=0H{@Lee_m1%{@e2FWkF?4pS6Yp7HIs%Rj^N6U z`P>fB!9jhc-}bcRFs2lQD>3QXBIk@+aTP9uE_x>XEEC)3TJ&@qqmVrS8Pb{3ADFyMB$tU}D;@YUQi6wRTa}fi@ z+1R;}Z|WZh=3v6D?Srpw}HksR;79~f=0Xm`AQ-v5uVb><{dQJQBlR2w6U^a1fSQ1VMm{cjNM<`_jkcK zNay(5p5wq_>%90S8Gk!nHUCVz8${Z*78zoP(qgDl=@5W_fnqj&Sg?gq=7X(Qq;f7y zE0sf}g+Vkp0yE^U%Kt|-o6hQ^DV4>}ydtAnw+7M2h&RkM+@i*G45nP@?T&*Es(!M= z@h)~zgs$6~qpHwk7@dbu$Z4*%1!?0FW+#5<&)L%P|FR8E2~`4QT9{RZ zkz8Gww?55zKtTTiv{QhmP8%&v`dt4g+1*Yj(=8|FCZ&TmTfe-|s^tBK%Ab5{9#f^{ zsEBJdVtcyBBE0RnTPnA?rGmHmVLfcu^3%#7$t5M{77IS;>mdRZ!{+#!B0JFqCPNQe z)l+N)ei{UCKUd14wWnUD!nbvdE_)%4lJLsD)r5@}x5&2c8|N}HgBOX>F4=$gN+))|3lfN&_3}=i)@N1?nCe)U z>QqB{Zgd(EJK~sN*65w1nXTN)(W9*odzV)&AK!wOJf1Q!|Il(Gm2Y2a#l-gbMw%V$|0b>e$p4L&bR2`wmVUAny_!C8)v~`izn2zne16 z(3M6tZSsLOfx0=vqkl9!g@~ByHD|6CXbuT=W?|Wx^JJVQU9?CBBl6=#3BZ?w4zI#h zo_N+^L~f>sVKf2ANKWKhw~q1It1E%!=Hr1%3@Vvjt({v`qyl+~-ia$pxWrWUEIlwq zvI~$VYna@C1bsI7z|L7JW3Fc85>Q=D-X(#7g*4@|cH7@`zzbKxGtk{-f!(%K5Tu(! z9t%PYiNQ@OR)A35RVtS5wl*iXrwA*wWv_#otPpC6<)W(v?#SH@pUjOW8mLgl;ZivAnhEOO0=&%X13?X$-754be+xJ39jO=Vs?c( zNajf-q7@x2b^cX^9F^x%1kdiu*k)a9L7H9V@d1OB3jK|J?VjELJUE}%(HgA=PRZjVbedtggbxzRr6z;EkUcn}qIiFwP}9@_wF>5_ zhosl%Q9i$?;4KSazV~CFw>}>S4f>LB7o{~zVPX<(ONA9Qcs?$0i}%z-U4383NIMI! zV}(URTKE&|kdRQ;upfxLxH^kFqnc-`ExKxj;<4SP%ZutBfCbR)ltLBB+*53CFY1PP zohq*#^wgDyAfxn)793kauKL7tc0k7&>mpv6}5hDo@4r3J}XYSFt z`xI+j|I=TxoZ5_Y4>!nyvyYR$^-ooCOViUg#$8Uqu#q8wMAmYy9aS0i+0-k%8N}Gd z+G(f4rmO1e-OebxUejLVXi)j08i`++sJl+#%xRunTqoc~m49^p$9B565G);#LmEn|Ah0mUkZnCzAh+rO0fGufAGdpXNo z@&C@E{PX)3rKI`5m;jpTP)A=I8UcbX>-YvVW}`l=bOS&rjy462%A#y6LBn4#9OZo! zEcg??a-K5JbaLkg%t>E~Vkr+xll}CINuP%qGFIZERoJ9YY|`6ANn{ZS_Mr9%yDwap zyJu$pIU&f8k_QjhA6_HbV>2LxZPDCo`)yVGE!e(Wf(YX#~z(<$})@#O~}%8>Wb7rjBcvP91}fGC-}}8k~7@Lz$l4IEeDXl7X(`tUgK1hj0e>FKGaC;g6=`TuZTa0SlKbCYSFbKfN3PtY78O-R z*wrtainPH5iv&}++?%}ym2OK$=ro=!6Hn^&o$^MY99`{z+}PRII8-jvZM#g`(?0+SSK2GV zMNSREFJUt8#{M{%Oq($7UyzQ&jZSy?!Y?O0^%m`986Y$n<+4o z874y`y?d+Ck;TV1TNr^{RhNv_K_mefzmZwE8`}c95#WfkTJ(hA3+ctyHPK3?1zaelMTpq`svAL4r$g~9aQRDtE`&LhW)IR?k{EZ@>kv#u$9ypfw~YFMm2;?&w35^$;O zzJ@&Hv##2l25ly8)ijr@J8;2{s;mQn-yxc^x4#XT0}yE938Ya3ogen)sOxVGL#$Vw zJnpSQ>%;C|?i?DvO!5c0ZQ;2^Y~gjYeXcx@{gelM5X^yZI7@7XEbTm&f>ci_i8t{H z=sHQBWu#wzWR6A;W$kXH)%9kjp0-Q~&s$BeN|&#SrEo%W4mk;$UQ( z#K|ZM|DL30g(B;hJMv~C9QIa}aZ7b*%*+=?SA7|3I(V}C$|_to(Wds6CG}R`xKkMC zl8Hi&uVkKk|7N)}^-HiN&HpG>IlGIvleteIpfHdx^QN(mrOy~kHViWNh0#RQUM@0; z%IyIj=jXB>9Ww&@r3gAlgPG*b;@e%gDKnAKIcdP|XFAIr$-H^%T?Fd7U#CSzJGdw6 zGED1N^(afM-f^@%JUMaqcY_|F2LuQGMXu-Fw_5HYt_9w$~ zztO>8#a%Gtd{YiXXGw%O{^ocdb&a{;jv6;@F>HuW-79mLXQ?=Lpr_+UH*3 zn;34>Z%ZoY&e84aw$4;fY8}&-s|YkMGDafdh~mLjo=h~#TC6`6J#^NaiKHCu@m}sP z#U3cTWw>>AE~TdnKgIk|q#+pdS0uB%bGY-lt=ye~KiUr{dIY?by^gM7u@Qd-KZbq( zrAb0@q|}DpV^JOy+jVZq4wGitr+VOL_adTm-3e|4k_97vP?0vOhijjuFED zi5F&6dBSx~0y|uU5+f#VHqf0@CasR#GEYW!vL<4h|8Y8zBDLoZo#5)D>=&q+V&wTz zG;5wXsSYC1k--kwq16fC+^Ykak+~|(SVrv{mKC(lGboE$(1Tl2(&fn$gIqY1g%M&e zi;~T=s;iTbAs_#x$MMi3{gNP zy_{3-UA;j(AWcK<$(dLEq!ah;OO@Bf;}iD2q}DtyGSz$scjf8ilBL8A+_m z4~HUH7#h8^X>wX1prInGIB7taPC$(F`O{W*$1?_2oJY1FVZYa1{o&;@>c{vmc6E)G z#W&mWRuoM|t{anyw~s3w(5lTd%vF~3X^8;vf}7!hqw31XHeb;o$B&PHmt@&vNGE4D zb8H&m`!%%cmETVK0oL9OIs)jbl1u^~g>QWM0?8VdV*YgXHY@wy*NadV_q!Mrf*BT` z0&kK=yL)G}m6bCG_SWTqsyj;F1k$ZWzAAL^Jfd_0j@hph2c9M82RlJHe=rsa`C&&+ z<^@>U??Y1{UJns9Ds2m-nQDkUzFjn66SlhFP~o z?X_)9v+C$vlR}|8alU`xk_D&GK@u+!CxPy=L`v0|SITW`)yN&y^%^>e?yK!M?)}{+ zu&CfrrwdC&k+m#Y-YwZKkpYlU8nTBCT7x1uYd8#5i+#G!r~Cn0^YQNaloN_E7Io1W zXK3qO$CdcaHC;IQ((9Ba3myIA3sw{8=8P(kRZWj?GnJ<;gBW~jHk$Hmd_V~E$gnSl zfcab_eP}gC4q9pzAd;dLWGW^Vz0;{C*{@qHvKX86Ehe9vs!lUouR9uF8^tKYp~3i# zKPo?`e!V!ZV~IVw?f9g#8ZU$@%7uk^>VH#>{M46=6U6YH-E*_(Vm|Y)Qf00USmttG z0RB6Fk&7IswpRmlD|Nn0VSBpfl!xT=v@@`}Fny^2;>$)xVCHQ>hyL!=#2XXYMWXz2 zS+r1HiuPh@jRZ*?MtG6cU%BNd93$e{8wypnmSQOfb?6-1Vv=MN{|9K8cMZIQ6oXCO z#pI{YLf2=|L`dQ#}`52?jkS3W+fPRtuPQ)$xM#-BEC|4;)$j zVZ9;e?iX^ZA+-=FP{&{RNc$c!%so5HQMe&BYo6?t<(&LjuHji=%ITewZAWw4%wJrV ztc?QK5TUG#Tvt=6&ZOOa{xyeM$Sif*Mh5Zex;#FUXDU`G$t?=+8-6y1ugL#<0JAwY z?}o$gYGAkg2czt`iIbI!0V8`}%0T#h7nUu-wNGi6UaqL!r^!AnWFFl8AmmJiw_U6? z$3}>0BPGw}tEHeVO0j#qS9OKX#eaY>_Nuks$5~zP(@2K0Yd(c0eXg6B_IuT~5J&fMB1}E@Q;D@~WBJCdzq`3fC8)yjw`|>( zHr6#lqbV_-UNO_$scbGxd2Iu}CBDIVZr0Vs0=|Vo^O)qhV7>3>X6^pQ?A!!q0mf8> z=h{pO?}Gx%_==o8eOqPiPHiY{BMD@tL&z8rAxiU&tHe{w<2hG-d&!(Nn=w1V|_UkLSM~ZDTP0BR#kgM$Wp#rqs)|~j0_<~^9P^8EC2r=jrPQT2d1|{dXO`xvj*Ed$Xs<7<4M+AIh)5Z!t)BIc8mGub9ewb-|^>4uyYf z^{JbpH3@GMXySc)Ip;$50Exj-9T4T_^UiScO`o7O`Dvbg3@{7Dfkoo!Hwo~@Hlo`p zV2h-OLA0Fq{LOFox8cb;B#Z$!uwFKIoHPFQBt?bm7>-O9y4Il!Ij4+X9S>S6>hpB_ zAu^9ip;!Mvib}@rTx335=PDPuV`uykGWZc;@C@+$;;xjt@f!ZVa7J(0$e?3O#%be8A`w|qW-rc# znwN>obwbr-cBLj?RA7=X`nfIqp}}PJbo!aM3R+U^@=3g*Y*d-vEs7Vh{EomfyON(%SaX3FdXOYG>jwny| zDa?s687k329!7&+DjGwRSGJkMOvE+Fgbkc$@Xn+`@D4ip8PF$!El5$^f`7i#bgf!y zyn2*8j8>MN?shuTPP~ZIQh*{5aK{@MKpd_zP52)`eU^=N-nu!KSt7cAZ^vekR7QfP zd7P;p{AO!59_!lceVPC%?ibA|i93Dqr5OL$Dwx1IjQ-+{8ItUKl<_muHsuuP==r5T zQR8$|%PM>JKLB8Fmtg@CuprDIQLSiDNx{;^HSDGz(4zhNZ+uR1oh)?-rK?JnK4!D@ z`m?=lm672x4mI7tM*sh@c2;d|wcQ$}#fudwQXB#lclS~xXrZ_icY?c1f#M`c(9jll zC%C)2ySux+o9{pDgPg6L`u_+llgn^EUAhb$%VHd8I#4xKGT)}V5R9K<*g%r!(_5`|zoTm))_IkE4Z!hC z^T|(J>jsNf=a``7dgz#)d|~qZuJU)R#V$&Puy$x5pzt6$UWxmwNhR0F?eD>lxzG<^ z!`hcJ?&xbFq1W6xnE|!HS5!UXsnA41ye_BE6&g|zcv8LV&xfTkK(u=)+SxHnc2j+8 z1KflC%910?hMi@x%d;`&IB1^J zS_=!27)P8=CRToUnHpWvYY!SHnpQQxz+T1JPwy+W3Nl;;vU` znkKP_K1q#0R=W=>bR#AHn!dwjs|ex(@^0v>di*j` z#S0Xg;RVi*S~(Rk5ei{G}okc$gDa|KE5y<~-x=a6(kstq6(OMI%eFBjq zwzuUm0b`wPF4vR$xL`n!FjurAinVAkR zh6unI4$WqyCJ0<-fcSv$f>AEHLJ-*DMj@58WN{WLe1tp9mQu~Z?>ro6#aCWv$~eX;s4%p-VmP`D|qrKzSt2Tv|DFhL|o zwQ|6{Zxt!tW}8a_MAL*W+L$f(0r_LGz(FvOIqRpi@Sp*I*QI?pu0d}pfI}r|lnbW7 zuXxQ+Cd$kJh+$ubtdgb!n~%`st&dMCc$c`%%%hrP5^5kC2 z6BGQazGbHl21@S!j{Uy z)_;|=Ljsaei=}jmXIc-IRnBWDX55^*e(p^OqU%y13#tLfz3Ko^@2f1Ce9S(egA z`Zh->;iW7~S?;9bw+iILNqk7xl+|W^PUcnvM2_|Nl$HL0jYdt1&@_bRbbbA%{lH+` zz3J?P6{_~6@AQt0NDYCmU4Pp$p8Mp@h_shnw4(#L6jYl9mX=W&+0$EvW7TYE#Hq>J z*XEMvs2vjC;mVjyZlPk*ph&!6nz@O!#4-cIqV$*Rs`Qp*vY&(|mN_BL3vN`-1=(%h zE%bk#K(=lUrnm+&mlmA!oLx$^WDcfTiO5JFIhEQAR8$|M7Gpl!M%fns8)*?~@6JYg zS}!Dx4|<#B@|cA?pr7rCJ{L*4EI8K9>i06(2UXsb1qxWU zy1>=}W4@f>pzPndqr?GYKvKtth%HelIa9REDQV`^vfkkwKfteOYslJM?p;3u0#WR+ zIN7*Bsq&NtkUcxXjw7K5&jHlnCO80E-j2QD3-WV>LY)>DI`4kkKY7%D50cn&SHBvw zarq7MWsfQ-W!+3*yp7V){+6dw|0h<8WBc@Avf&7Wm(>EZV&(lQq*u8=(0p`L276ty zf5ZgC)R_`PmZHT2tF|_`_VzD#?a6eHuJt^4m(r37fwBx$xA{>-6RL%5w^ffo$tGxy zG=Pq{yKtB-?318s_%^=YHxMpv>cq^eC!0$qUX#Ykp*HjY)C_WZ%1vT@&_c3#B1Ps% zs4LnxVpU8K$dRqdBW9{=C)^%*vD8k{J_9xB-@>TD-1N(!Yt%O|i@MOAsk2MjsT_!tS3(-r80(Bt|Q?4`J@HG=)xir4e> z-6%~gFl*3SoeZ~K1V7>R6B{~*hqRuK`{5l9%f#5NTqg@F)fxrPpcx_wZ2>AOIk0eN zn(Xb+&#X}n&$yn{H|FwWdG965!Cu*xVssL%tn44WEqL+PeT_!6?5+VS@Lp=!G@8P1 zA3n8hi1${;|CWHqsUvr_Am-cZjKB~Q?bIhvlQbynU@9`O(F@aNJ6VwcL;a8clJrw% zk=v9ur~MLoSx7Z&(9s(XUIlVYP}Gx0g5&;<+T6q}tK_mIJn&iXctu9<84nED`&j-t z`CgW7`)ODSguHS+$#mMNjzrMADainy51KkJft`I#lPNJVldW$^=5_Y?WZYo--6i_m zS@uZXP_xeGTYXSYL#&sMgv4+M6w!*Z)AP~iN+&IQbp;4=K3Dma!-euPfPJ{oS*beE z{^s=9ojcxC@NyHc)EiY-C}1$;sd&IfTP%eMV?Pu`6CO8R%l-frV8looS*3C;O-lI7 zA~L@***qy`Ol-sO`ID;D^53Z{_%3W^1m?rE3O5_FZS6~$LlX_W`uK$!|#fIr`wkdcj zveE&*B1S@RhX{~+k{|T$`E@2*cy@uAu`#vR-{-^p0+LLRZ^m;Aoy_UgJ6ro0{vcs` zj5){?JUD*BcUWK;y@Um3Y+VWz{N*g^6!`F4ZgiZ3`*p0~Pzgw=n2;UuZmq)^`y!~H zB4g|PQO)|D(fS3fH7pQ;41s%${E)R0@cWboZ_9*l99!sw5~^a8E;uGCG>vJkVUnAq zT{s94qDZAo%~wNwcoT0T6#R|ut$M$6Ma$2G!sQa_zbvQ60FJhd^w?5Ftb6;`Fcbll ztlcmvoofE7_y<>U|`5(qA^H)W;7&{fD3 zYAF@D42sKYJXv&XW?U(|H-f2v4z8SCr9dY{9Dm%O=aK78h;k(75)u*;%k>3u(7|`9 zZBb}> z7(H!g3Yvy^e{iDKNd2ur22nHmsObM@Z-Tg95lPfVc;PFjd298eQl_uhe@5M5|qb;T5GAEqfsZTRu6ek}%I)1`eS zmP9HWl-~{oFa`gKZuw?2k@RI+ZAJf?ALBYAKeSv81`6Gto!Iv9x6!Iwxn1o$=sC^J zx2}We+wk9Nexy0|vbWTpku7AAcwcxxK|S6q`B$pQ>T_>;xiw_aH1gMa_P%v+RCSw zaIPcY^0sz;Sid_PJw410f8N^9wj?hewI!XDIh=d|-%q`M@Ht=VgaAGV9|&ba2LN7A zj2VDs&UL)H({8tY8RqLk1YAs0RG5&9A)=>0-NoKB!6itklrli$V=)@h@yy{;kG_l+V8RBU>Qu zO@p}3tgz3DTiwvg9H?%|?4(f2vLMG|${0REQ|dC3w5ZGAOOPSTy{zigD~bQaD=V~n zQ8}j=xevYl=W9Mkf<8Ryf8#7M$e5RT34QJ3pZmMS8!2-k9NO-C4%MJdG9>Rvnvc4}wnUE@`5WM< z<|5SYRrQ@Y2MY~LX`gEna@PHmokDPNbt%y`>-k7$w>P z3GNh+&0T|QDB)g?`}VUOIKNKowsra3gII6Ys`}h3mzW+ZvftC{#6I_*78xkoXnZH{ zcFM9ZDq4k#z7lnsPy1J#SM4UG@43&VS6?4YU3>^W+{F;(+q~SB{8WR>18G1y(I8=n zGyX9#SI!H*k?j#bUu{DyV>4Hx_SM)#+Z0Sz5}G9Z5E@zRJ6W!8Y2EeZsh#3Yu40!J z=B)VFwGFQeH=~!XF_zeO6dTiK(!p6pf{6DRab3297xFT-LD}WG__(W(z5*kwHLOvf zB?PabUvYD?01vwp21fJ^L$lCoR4|5!o~bC_Pr0TT(I_p7Hp=`K+)i5enIK&=Jh~A7 zGE&tlnq)nOm7*FdTvv{j)Y$ZPbe4L_R=9a{(RQNq=UK9CoHxZ+G^eJ})||PI{P>G; z+@2@=lZm0z_g|0_!Tuh<)D6ntuUHplS(fx6W!fViBJ?W9d#ReIR02j9md@a{$hT&n zOy~wkc5AmBHL~V~UuDv@9?AP>f`{Mkk`%?QhPlNUtmm6qvN)qCcmHE{*U5QSR~w#5 z#raHZP>yGmZfLeD&Sj%3WlZq25dP|_}u?CV~{o1w>H|UEueASq;tSL+s z{b%EMF&$t@gDl%BAKBb|g2Df3-#eE;RUh@nN^2yb2G&%}-#K7 z9?_ZL6jfNR)T%2@Pyacg_Y}~*-OTW_jB+deyOMna+;()XvRC)sL!m+eOZZ15EBz%Y z4J*%+uv?585^{v*-pAfGk_P-K$Me~qtNlHH+K8fp*(hkb>0U%@BmA{S)96vd|H_W|8b ziWdU`Y-y|d6^X{xsQ17XIKadrNT7Oq*{Nas4da-BdFGsMfNV`ni#QQYC-Q?4b%SCplYHZ8IEp) zK5r$yN1W6P)%jJYeq1=U3XzgfN|ddd61-@3@D}*I(pXVO|Fi+`dXd#KkU8preHQwc zQTnXw>tw(<>Y0k*bQZS9AZlAz&U+uamAzpg#7xS}JXETC;t#~5-O=sK;2B*J`|biS zEV2IjBk7;t9KNY@GvRyBj2`K!@GHP8Q26jx%OkmTE%{zxNyJ zs&Mb1YeZ#Ls&@yRn3b5pq2_-9cqz}r0B<~TdY;hrNBH)dcQBC4-IOEVzdcmOTz!Djiei1m@+-_!qlzrB#3+~NBU9r=0+7k0r7;WYDc<$TN~?EI zIj$m%HUEQxIkFEhH+RS9QIypO`G0@WQ|dPu$h-gN4qa1n1UZ+_)*3CDYq8V55Q{V6XJy#rPD=mmp?31q zGI+I?OUp(0i|Y7w`(3^p<~yob?gOn823!3dPZn|RtZFSkyXfmFyZ1Q(3ysb__+h_T zn130M2gRb1qvZ!!928Z3nL5@mOC0`KTXp%ZIPs7U{=IxQZ(&dgH*ZKQtQ z-03fGe$>go>6*+R-6s2TmEC0eFQG03a<3LRgM;gDCbdK6eU(@WF>!1$*h*vgoa&ze+ytdZIsIiggo#<=9JIrBC~@s?5-) z6>Zy8WX`pqK_g23fHLEp;iKxnJ@uqoc%5oOWL)#hQO$Pp=$U~VJat|7x|M7Ex>&f4 zY%Rw5NENcF2V`hStizL-=uD4Q<251v=$xg@Y^ZP%+jh})8+Fe9%dOfpw})AYq^dS1 zFR`75>ypkw=7TBL?gKEim!xY5lquH&Uq*nSmekDf#s^yfo zwl^)LNtM;j@W;jjF#bcZ=zpbr9e-Sl29?{L)!4>~F*Dna>+TBdXt0%h4J_WpNs|56 zF38Jkqpmiy?=Rc+lXUN)SI}gA_xy%F@u3F9Q1(=Mk~&fTs{K7Ttvuc;Q( z0#q>IP}@DvldOC16*N}{?|>jz%2lvIswx(9el9uUPailBg z^DJE$ANcEzqKzbpxKkXHSW^I|#&kJ3nZiZ@CdY!kFy+sdyh^OcoF(@FuZO3+XWILS zvf9#ISSV%q35}%i;;J53y9HaPTy*+?RnYe*`73bfr{cFdZ!6uj7|+tGXPu7&j`hS^ zAM3Ud;PST{I>)62y+{Gmdx3W1QNfP#rj-On!g=L$;6vR-v>D~pMZVq{u9q_s6T;=a zaNSl+`!x?t=$|fy7|#An=e(VK_vJ{Pqei-6QRJ(P8|bhevy&mbwkU2oP%$ zzw@~%pHfKKgJ@&A@F3G^niF^ZIn1Ye+%`pxZL!UoZKnL=nP4#Grer8RS?)$Il3dZ2 zHt~6LzJfH3L6AAawTFd|8T>RR;}=eHj)E%I`88dhjS>fPYO~<+NyP*xxpT&`s|+2`*`-dwhh%YY+4p2+tkwUQ!~-W?j?vR zzF7|FuDQDpp^|)Tu>y@MQuXt1V0=xUzF9*%Nyk|)b9=MTlaMd{eRw%v?xq3ZEN>VN>ML!CfT_D}iZq{W6K69K<2*8I?HdG75U&E!R9{hI)cqea5n z^(F(`uEoU9z2R;nePxo4z&}W|0kWF?BTijJoLEi%h zp1n4vD+Pct%JY|{4@h(pCJGd`(>3DQ2d$sZ^D_Tf%@U@$r{?PcKHKqCAVmTYt^JAv zu?6}Mbk$OKBNs_+H|IE)rMb%#?M%qOgF7Dm-Sn5Mouk$o&RAM=?L;&zEps1Swf;k( zHK9+m?za@Tq~Z8LgcY*3+eiNgV!ev8hKYCi7S5&&x_+Ey_aJEin`$qg4E%<#ippI- zTNh0b$1hh4^<$b)kNy~+6UqnaifT_*HA(GQ(|W$nIDG`i7jfvrB*#d$KispcpL_I( zha1*n$FE^FvlkBKA8~oX7}E}cWi?At>dd4y?6_-WJ%-MOKQpksUxqJJPco3d1&Xc2 z{*rgk8uxfq=MPQn{Wfg3fU=Jp6r<(7>l=+HxgLEf^v)o~OF&r9rF+cN5+|(}QndJ{ za4r383tyF|kDMGG#2BF1U2=ZO+(qD|qA+xzj6YKC5*glI8@2uQD>=T%ce2=#i!)ew z+Z3!$c#+qpjXLINMgx!w_!S*S`>InYvOSxj;(@XBt$UdKYfWVRRSs1`GGgd8l}X|s zXyG-}2WH!(#omGICd(#mc0~^wx#)BBNb#?g?}ej-W%bj%f$#Wfwv}uV^{b>tXSQOp z$=D>QGB90WyE!rR{3?5A3SA5u(Md6~ZoQ7S^yqBaKIH;>(sVt2De8=0errRKfxZF(5$3hOf1iKgBd%O|rhQs> zJ5hF1Xfno4%}zGnWsd&_P7>5y$cX#Po5|YKeU6d-`*-t7%7n}?yE3-tnEz&^V-qs& zonpBuO?b)*OL?H|09-`)DX71L?D|vBeMsjk?uC7-14V9*r$aYXE}C^@rbLr|@}~;WCK(BTzNyE^;qqYL2J3q9v5py#f7;WulTZ3jJEJ zrsBKyJ#rzpvcv|E1=GC{??I!RNiI>NH_Y;%FUGyj#|DBVR%+E=)~YpXa-z{dP3j#p-;m5#Tw4o_J$;V2U&OYxFyKOI5Pw5oHiFX zt#J`&$L#5_F-Y#RI3sV_TrZuByB9$YD;L(5UrO{02KO6koJ~1<-%&@5tso{NLgaRn zZ>5uFwe#V%8jNIubV&QCD}90h#7Hw?P&wf&BaPQ!h0mX$S<8U*nD#{C2TyW|(vA6B zJRnv@+GVFgYHskFa$WMK6i%v8<4M#(rBCEIk($)>rzv=Pdmf#cW zr)qDQLTEhff8627Y*DE)>R_+vBo)23WE{ZoTui^=uQmUUq{J#j<%G`2k?P@>D^9;G;bS9#?3% zaX+~u!fvHW@PGpwr7yU2nx(RaI_a;*(?r#^<_#6r4F3|+8|A^MwXOvotz36up!@{8 z)l}r{qE1ElBf6^0YwxPCp~k4x_@a-ur=^}> zlkhR6$(nUL(ZolQeJv@@&h@8^s7=j(2*z+Ldkw6fW;Ky=4y8$b1Uaj1k*ko)TZ%+d zLDrfj9rLDejpUUypc_NL%JR-tB`WH#2SnHP?ayJefT^h5o%xz6hGw7S2s!n|p*XgU zKsrHM(g3nabmrq8J#^$@cfKlV!gOb`Nyu=k=`Yi+K^c^BAtRIg*j|#6_WHUf-tDPx z<_*|VXc`qRV=@R^ZM9rJnnJRRf3#0S2E|6W<-T2F?np$a3}tLt^>VoA@^c={U6EEn z9d%#+unsW?22D8Qh_$@C;W@Ts6r}z99=e$O*i3{1Xi8+_kr#I-b?!$KDR&h0t1lr; zbvRo^Nn%UVNv32AxQXtgmZaUKZM*Y3k{#g!dh*n8F0Fz|6>x!K6Cw3pHgZfHjxSCj zaW92IP0nlr}plGToL) zLYcLD2(lOC-S5=`U;g?-PC=fsLox21pF>Ugm7;A z=MiPkEf|oekoBiH)10C(gGnabnbbq`Segr+V)pLoE3?`VL5~^y4R2acf@g0UFL%&u zE5FMef)3AQ0j0?*tpg#yyFzvuJGXsXoP}pFzyu|^CwZ+vHh$efQfpG7ezd10Z==`R z6gnq>8{=p{=zoGulFmu!YFlD_1<{)F&FD zJ-cazRNTA}txt;!9z&&t3y1|LNQ4F0NP_T2Kp5KdJe>VB+Fy$wTCj!U6yGbKGS#+B zr@a4?2XAGjPU8t5wwehao}@gZXhOj$vxz1QGvuU$H!WdJBEfZh2mUA;ajIsq6uZQ} z$coHPb5-jq1(<@cqH_ouGL*mlw26*D#8aUSiTBE@jli?YbpVkyI!*qa*4@~)8rI_a zT1fg$&xIL$my+>?)_(az^1(@Vi=Orbm3Eihs&{6CVe|Vq<>!;l>X@rHO{m=X*E+o| z6Ph$c0_h=Vp*xXiQEB4Vc{T)DE>>L(2{f2GKtZFneCEoXHoy)N!TuF2D8v#_wHNt)l7B8yqr z_c#1*)BQ(;`Sa?C8}e}BZB()LpuqPQ{IboJ{=Pb9AuoqN7j!GlT2*?Z=iM|4UUC4+ zbmv>-@Pf_IdYbGgVPdwLbU7oqs%tuJ(4yuF=MdkdGyfxF=k5C%x+a*gZG`>L3kQwQ zt2niIc)UNV;S3D<;xR&kmi1u@VQ?$ZM!hzrGmAY$7KVDkXwUWT(Ik1%^cLfHPNNUl zO(?36HJgcEWBXfZ^{+9~QNc4^SCk?C%V&_PpR&_K7!( zsrwFPqFh0=IZ`E2B@1sW(WJ|f_(2BeeMOSA&wDex0ZjVaozU&Wi7b}R_2F03lSLPp z3UNERSgnXP*CEYP6matwkTdSiOzU#2`T~rrpH5pZ}x#TTbx^ zRue;D(tmmis9!L5^Qwr@l;Y|aGmfri=AcD#bjJCFUC5iGYo9hDZR#UBAMf>}TLt<# znqG(y$x)K_JXg4kx}jNXN*P-K@LS(4B9Ov|cmpEH zEn>fn!%ZUW)ax{vpuEdv>s*$PUpp@yhM_Ybp|bd~8`4KLgyYgbAo6HZw8)bN{hcjG zXdu>+cexR}((UQ!?@WLnm_yMp0u;-(b#fw$5^b-Q(MCN(#I1A+Bo&sui(shZ)F}H` z(U8G{mgbf0ATU4%`@zY4$;3hKl9g!oG}9*q)7+OwlG)syRq!;6WEpvnPX3XKu3g;6 z`TAKU|C93U>#h0c(A?aZw`bK;8mZmxk_XklO49nBa79N1k=Y`_hH9zL$ITH+jp>@* zMjuI$D7@oz_nzB?X2O(Epfzj{VvC)W&CKSi5{lC@K-ChlGL`ON3*rQ(XM9U%Yo6|?%)WYm zi!E~D9Mw)f%(fDbv!PcgxCWZp3aekT-PTT5J|s^vJ|r^|Qvk`B*`@9(Cn1W`%o<>i zLtVF#ow9tE;4j@y+etEuMoHd9xX)gXCRG+~KUg2USXFZq|JA6GP$M{M_xs^Uj;YR; zE-&-Ykfxe(9=k5jJ8mI{BH^qu!NRXbByBox7-E^VLG0|~%fMDlz~E5VFEVNd$}hc~ zBZ~1qhiw*@^;d~fSHDmD&sU2se1AjE`gGRY>!sRdTW0EvhF9s z{X>$C_*fEkJPG3tF<8>C#8MyRtzoTIslDdbAlLp8;z(*FxDuC=;aYTC zZtGLB1|$GkdnOFrhU$oPrMy~zr7VM{PsYTS)pJfNcD^kC^>A>HFK7wYritC4c{13z zyrYeVBH(=j02qn;MSIkyPd0so37!-(H5VDFm-mi$m0h~Nh;w1T+n4pfVV&mE-xq3~ z7Ann2#Q=C9C;zB#;>J8jI4mAr=aASeWM3LuBK{sDL}vvdGSN`gqH4~BR#3FK=+U{E z3LiOv*Y?yZt&J3Xh^T<%m-bJR%1sizt6nQVibnXCeyCLQbIR>kM3`SL(|ehyNUoux ze)_q%Ny0lKdB*edhP$bvOaAz(&L;R9=XCGB=m36s>sK^)Y%-~VE0^H#WT6fLzH*?T zihH!$lF-MfgTw9rL)ia%J9{}Yx$4fv^5rvQ1hK{d;JIb-U-Qe9flQT6oa?0nS10$* zK)j9w;_g}Sn?jc3=jh_;<(%@=eBA-SYGeM0db=8XJ5CYDrjWTWcb{V@9n4bytv*%0 zL^?>|$I;lELg~B3QbTOrWk+6ZcSMe~?~@5c8jg+>SsK5OB8Tui%-wOjSwk!5zeM0N z4}db`bL-cH;|Y+VC6b|Y_X!f8s4jKJS+fp9(GFN%E%=<0NX_CfCaRZ>DAs4{!p2^4 z;ik7T)3h=99y-w=qo>P~BC%Vd!ZFdn1L@2%veP@J65WzBvH)`hJ!9fzg&aFD{>!u? z#E@K$SZp)5vWhUqeS$|!5dyO2^C~%rF0clywlrm&k^V!rBBZvjRJ5FH_ z)!z=}A8;(Lc!mi~k|N6)bUWi-%75^k{OEr{xk6GjxdG>_(8Y6 z(Ir);v9ffJm#Dfe#K0|ATNm<`)<2)6K*UQTDg(~g=te@8Ew;cMW1T7_C?^L*&xd5^ zJ!P$aPX)W6+Puig3H)M2_`O0@U#(t~UVe1yS^z|EXn!Es!?M1}sb}{vioAxO$bAm4 z2FTm-vcNcR3BLKxlzXhj-PvXqwo9^Q0r;f>W$x8tc@Ob(>C45tucJ9C^j(s#&`siG zPWO0-2VF)8g9$PHW<`=w%XJ5vgKb+(ZYeoN+;dHUtUD;H99_Fge_n2m;w5fN|FS3&WauYRIIqCwnYcN^GCU|66EB-D8=Y|7Gd?>0j1(Dp{QMDyfp( z4;{VKoTU}=Wqk^ltl@kR#R@`*3kKf-;kzcT0%D7Oem2j7o)RK3F}$=ouoQu@KQZ8a|(wN;+g)z}4dt-S6mc$R4}5ny+Nx*({zP=7kNL$f65v z0{}9}Lj(pMWW3Hs6hw#TIKEZsrI;=bIF2~_&O87)`?G1-`m6w3(R*n~?$@fU`z7x`jw1oE^Ik2HE;`j=PSrVJO=)n*S2pL$v6DCfVsb$yEq?)F>```NEL zFO0WDKNfp9Y`NWR^g(i)-|M>E7ibcmwz0KH_U3ZcEeUS$l}a(^S~5+2QfeOXedBC- zr^@JI9A2g$_ZuF9jv|vPW-sRzeDb9ou+mmJ^+S{SHaXUv0~QX>^oVZbOHXQUp}0dX zG$rm@==A)+(fRY`_;#a==aowBF#_F~+A4h#|3$bB)Si|Gm-FfDR1{x;yi$wVm1P*x zIm4sP0^9U)G{ub*vg2PEI`slL^)IePkUz~H^?5iOyRal5AO-%3W29I%^4}BZlNGM) zQERP*$7xQTfhHge41i^M-|=m1YO~YqvH+oS2c!g26X+y-jIPrw6%R-u?yZmkf1<)f z5VlO)1=i6|?5usgtl!T%v}5zoi#Xq$l;qJ8F)eB~EWf*akYWe(UpXhoZ32`1W>@o?`FP|5b< z{B0+;8Y26Ys^AT^GZQfBI%bY5h|Zj?0t@Aeq9ckV@zETsm{!BZ^dWDCde!Qe-~URV zRY0WH?iYD%{OnknuTOO971-VLbnfgV=}L? z3i(5Mr#WlxxG;juoy#UW^Mj=Hdg>h5}5?eM)87&OmbzX_)3v} zLaVmv7C5_fjb3qfMIL4aWRx3Jes7!3sp+sAKI)XE(&@b2FQyQ}j-U|vOUj#K3_K~z zMm*F!W(q*`ko)aL2guTvD?Ne+5uKK8GpF)p-tbm{S7UL?KkM_NH8YKUPkcP&vhj37 zme_cv8hoJN7u)Rc_uh8nXvOw!R?R@TNXpur;-Kt({UWZR%|*NieoTv>?N856eurA1=OTvn6blqv+DzY&&U77cMI}u{K0IcbGT=?f4|teP&xTpCmj} zw6;%HW(jY1pULAeh`LjBxvbYzRN7pQ3d$`L zII0ys>)XiiSA=>r4+>lnS9X3YoUuHXQ)MlD11#&UXL$|x@ z!z^_l0Sy4PvgEldTCG^|ZmM zanv0X&2N?oSSX;Q!^E4;Bm*^k7z#sUCnO~x*5kjxoJITG%Z)`!mcf;;oQJ3zkuU|H`&y)G zMIcG^&QQ#~ag%dws?1ZfdAN6!^RmA7($9JQF1p_RPpcBtnk$#mG?z3C4Q~ue!(i)D z3kXg{iTi{!y$MzGZLTs`W=i2c_f)O}R`im77gn0Y9ABqxwFhUcq#Fk}m?~j!ab-yq zRneo^-K4kE>XdcT^LVe-(lv~V!s4m_FE$^eNW7=m3|;daZfR{sueK2&ru^9~e^`QS zLv~n;iekQK{BSnz9}5bI|9h}Y-K86H^Ee7Ea|RdmP;lMp><6;x-$PkT58*TFXD)I2;my19uyfyuJ6mfE7>WUCHEnh z*yzeYw-j(tGqq%)-QJ}TTU}BO%?k@r?jw%;g=K1@xK$YZ?dve*8ts=mxd<80&3pnb6I-blhO>tp(;%hR#2{ zv5Q1x_{zw0tpHOut^Xl7ne*U-EX9tfy&QIV&U+_F$Z-WBz(j~fb-RWjZHs<&O=GK% z*V$QVIm-%d(x#?Ws=3w!dEAPGt+Ozqxe-JT{%_MwqZ-VQPP6D-farHAmc3e zp#sW#6TaoA<1E4f{V3}w6Yw4TZr8Fo`~?@E zG9c>N#~V4WXJBnIzSf1@U$3rX5%{3lMJ9tbu(S+OayR5*_Hrp4*iLL#H>OZLH=rm0 zyD}^ZJkFY3)cojiL2}NW9IELNz#yyJf|w&jzZW}25ZkRz)EK;t?L|$X_)~XVS4X2) z9LJkS-McI^f4LHb#Qzq*(acSb`!w=P>*G+NB!Ek%ea{qv&4(Y-Y)bnkVg}ij8N>Fa z@|Jo;rvUEMeNe8lGZ=&7MhH7;HF&jANrY%}Lr-uOEzkw+SK#2FOZ{o?@#X|q<}hiL zk3jO_0BdJKqI~bo`>Me%IvH=H>msl;R@D&d0x!mqfIiR#d!&Tyxud>g3ARwU)ewBU zsI9X2&&xo~5;s+MWqx~r&FgEMvaN>-oVD=q&O4F^?s5{$SPEb(+2_1s^D=ab9CVzf zqqmeKgV@9aW@m-zp(BYX%jA;Fm4&?o?nkrmoU}~^{2~L9AA0$tvjtL(Z`ltL&J67N z7n@00t4UcWf^prq$_I^JN~(GCr!B{??&W6!eLr8AT58jmY*hPLPoac4teRHqb*Z`= z#_YiqTq?t*qdo<*sRq;zDXExol`Cv=K{g;>ow}bOkU(;$5+4n zZ)uBPo084Ne1DZ~mIjgrV&m9zMlSjI*p|v~o}Y!TJg1b>*juR1IbU}i%P{#I3Dbfc zd>oJqVVqS&Z_5zT8A{>wSiuo&wyo&XIJ%09zF#+MF+y3vu5ZEk(y{0g7H+>>7A%Yo zbieN6iY4ce`$$s<@1rx~-dT62gJiW;<|xk__8Ot24~~PCILR7)gMGE`9%)J`ldkC} z;!5K^+gx&>GrV_HaF!;gUB8z|FZ*GEUavCy!%wz4JWmfb_h+=pUpl+&5%YkSxIsZR z8F(`2r&x;FyRJV9z`7eq{JPP)rTLF$Y6W56LWa;OpO}PBZivNhScmjv-^#NdOPd(% zsbpU6)(U3Wz~y|ZFycZ7*WM2UF09L&j31W$pHm~V+M1q<{Hy}~z`q{d()9FJq&~^|Y~SoR)_^gULGTa?4~~Xkho-E(3+%gzWB2 ztTLq=m47?RCFLd{4kw6UzKiAHupRR?y-?^_!)g88`ghB~|4w>}I+YsSn+mAbuX~BT zV!{jq#QZ@FN{Bpl71dLiZsz`b=zfO067%TyZ@z~~A619=*Od?ActNkDEWrv-thI^p z@V}j6ej`fD38P>}S6^tbt5}4S zznKjtX><^iW$Z-`>Fp0$yYulZ<UHWfZ+=Nezf$>fojF7VYWmFhg7$ zLPlo?2MTT9wpw|j<73p*0k?zy5Z;f99+u!O^cC!n4^{1=JO1hgCXte`z4lceooUcy zJt+%j$8JuF8eQ&yJ`7#L2O5Moy!jkeR>_OaR%*=zXa)~%D~HH4J0o_HcU!cQvULE6 z2=)vg+K#V_lXXGC1H>>uMRUEx9HkYFf`y|?qQeI9*3pATDYZyBdO9?yjE#DQG3*FM z+GL((`BK)ATeXJ;5h$1YyH_MkXHm|Xk8|Z0IqFt|isXXs$S0yFAy!3|{C)j?G}rH^F1843A3{1GY`Qa3@5X9DwJpUqM{cCh z8WWKrPjkTWQoM8aj&lI^eDS%YwY%$z8i?yrz#{Hc8e1E`9dYfxy5p|UUq%H>@=VFE ze>3--EheBK<%U$Cy%~(8e{w}GquQ}&zuLaH#!E(lQjsOwj4r&`#rqcK4~p#C!!#2l z_r~`2(JInAsN4H)4woRI=juauO3g72fdj5j;%331>ld!}d8X!9law;n>9B8Z`-q5v zBU7-K!|A={&B8<@8{tNUQ;|)>cPr@GdhB?f$-T#N{!=bUDR56a_xNm!TQfwMHA z2x{Sq^(Kk0s+Th!j}~D`WYxdS-`UYjg%5#;va75=Q$=&!3-f}-CKGm8sV*-#jkvk- z?-T;Cv2>FKVT*vNwwe=Tm*l^isA`exO zq>2Hkr|~NEU$N17560}v3wV-m>pbjH)_CKGQc>4_a=63_(87eSbTx~nNdDj{`Gawm zmt?}dzYz(lp>@V7xBeO5b0OXq@NDXJHoUzOnPe^}@3SnBq)*)#YWi&tGw3Dx%!zVR zlDNVthTv6sZ*UIoeetNMEH~xiN89j!gq>ATTWz?uu|g?O3Pp=U zaCi6O#a)ZLyVF9^LU0S#;_gXshu~1$-66Q!xB1WhgFUkk*7=&rWUY5S&wXDPeg$Fd z+}=1kdn4Rrd=ef*wgv;B2|mW$9v^3HPgng(Ta(M=a+=)_VeBID#@;d)yYlxu zHoDmZvawZ}g6nD_k;4Juk_cuvr+O4E9XFqo+?A=+N4SZeiHct|Y~B?G%ANOjHMcbd z{0#ex}?<0p$4}$#j+^H?r>00I*VzBbya`)j&Se(cr-q=JIC7J7H-TM)BoAh z5_8)P-p+#T1wNix?F$s#%a&u&^^l^GYz^J!Z^#<(^e@#mSH+v><_Wl}tTD>?nq@L29+tDK!^!xL!)i>kR&S{9Bj^fqH%UU6;`d?fD)AlJ|n5fA!1S zj&GLYBsc?Zj?22Wh>n>Q)<1AVNopBOL!%#u0-9r+aKQ#1n z;8WH!%ciDiUJRZYU0d@-t<3o6`WuUTi>0;+>HGN2p+LDe#`(e0#BJ8_d8Lc#R})v_ z6f<9^f-?BRTy_WFIsCR^4@-q{$FS?4vJZR0XvrBjg3=q<#$)`SOMlM-P8NM{>ZWxjl|6f5!=l#T(~gIAR;v^Tei7x5X|C+POKM!;IA;)M>S&Bekn}t@Pt-uM{(wHW;6%P<$x{7|N zb<(I*4Am94_D+o<1~^iE@NQbd#zZsO7s1hA3Mw#JTfup&Vln`-Un*HT^nwj@@qqXA zG{wv+%u2pIWD4QEDmI$C`pbJFm=|;k<9e?GXL=7g$a|CIyVRWDAkYL@(xsKw$1ORL z7d+Fax$GsG9TPg>>$Li+g^T6eXgVrodEnA3Gg<`o6+xVImeHw(?TwxV|J7;FGMed^ zL3iTTdEig_rGUx^U!EqXiv1g|{^&P%B$YXUrxkswz=r2daR%#n1QzQ+!*9E>B%)L+ zuaprw-7|W6duYYS+?%OGJ`cGP<)YzRor|xFm$Ohmw^nDFAsE(z7jkp8EKeG%;*#1K zv+REehs@{;YnmSsHTd8r)qUhbdzI2G<5#Nh`YR`+vqux5**@5t9xtay{_iNa;#|yl z7AM~*M~hpQ5hNMs!}AC94~cj?ROTL`!eOm3&P9dHuwBVONBY!4CF|_-*7;qcuIZ1CbHfpQ zP#vbf6fd^Yx!iLNl_!k{(F6&V#cMh`BRHg-33?H%x#)t(bGdW3w-=HD9v@&t=FyCR zKIxY^=5AtmzoG8bF3%EgQ5_We{@DGNgAfD1htVRbsr!a_JKICEwjsby@AdXpkgJEG z!zLvg^}WIna;b<89s!qvLx_E+6Ex0J_;sG@!^*D0K*;YTn22|U>>|}C5f`cm84TjM z0qL+IG{Ge~^=uuTE8;3Y7Yjj1Vu{(?huXdz(Vm2Ol*J!1*tW7VyF$Yh++@uhG8vKN zA=>S2MVYkk9qhE=qSB^KClqp<8jZAe(QT>jypTviG+eeRD|(^AS64Nvqx;>ay;l3` zr|(a-mA{lgbQAZc0|$Nz&Z{q6#o1Q^Nz!G+1(=DltsrfYecz{bAD|p^r@+Yh^?+JbXTS%*mwG2-7u*X(edClBSy%6i zP_5fLm_Y^RJlA3h37snKb5^GAogZv?5lswM1SsBOua$zA^kt=w%dh6Ivti>T-$D5; zmXg~~cr7Fd18!4IlgFci5A~yTWd~GgA~r5GX_#9B>tK8cYrRzSqRnslsV_jreNa#w zj_mi0NKx*2qT|LFCiZ$6{G4)wiCw(x&kWx=AbJEw*$G59k8>^!eBW9r6BLPwND)&^ zIS55A1^+|1(b8|?8sv}C&clf?f(S$Z+zvkO^K9=Yc(0oq z9yb%?iXp9kz?0Tm7sFRI8bBR$e8x^KdE?*?>uv?tp!XGZ&{S{ffZa~gz2y)B8SFHE zpm3jts9z!@mY)rgW<`TJ!kWm6Y2hJ)`&6`)9v7&EB>shv*y>$0T9RB1PYZVGB7m9v ztGm3C(}x1Inht?8jl0{@cWvfJ3SDB3QTUgAp=c1dm8+N(tZKI;Y(UyL!=$+^k;KoH z!EOl_S^j{nZ25PRl(?>fM{Y_olti$E43ET-k28OmO0`MkB+w*Z@sI{&-^r`TlHU9^ zq(`d}jpM*c;FMB|t4ah%O*jY1i88*K+YarT&;-d;1<&LWeN0c6voGQmjZ80oh;k~) z`&jH!k^(z&4u8b*%Z{WO#aj8tcq5Ri%TRt%H4S$3w@y{UfB2!9+$FdzqA?@WQ}`2E zaga-0#W2@xj6)>3hg-qp;%or=c`)7ASA!(Wdz7KTS5NOQ1u+ddKEq?FJ+v)sbGMZu zI^+|3&-?sz^*0vu79h?{tu%~ikSbcNxIJKRO~|QxqB>;U!C<*C@a^v#nlitXz5e=b zg6jUJa_Gx)fU~PMaaLkjtWOQyOLk)pT32UX&RGmt zsa;%o`gJxap!9fNt*CR!iN;S#m5u{n3KO{Oj|jTO1`3g`QNN@H+7vHKvW|`DJ=FGp zIkmA}G{W>JYof0O%qP8$_}}Jj#V=+b806;tk@h!`o%PJHeo}7rJGsOyAMNVf1fr?5 zA#iFdK3BsA-LTTXn5Mc!Xzl$C*>4F6YSmw^k={~WyxNTXCB|ZZ>~nt0`eD6SxAm<0 zCUpi7y0^8un{3($>At*8B~JV~VgIPK9dhz-d-<+*Iv9P~S8POL#wOO`ll{E=fKw(y z|Db8*sF)h2QtZuy!O%;(=STp>^6|EITq-27(Ds$$>y%?l781Wtg;s)r5j~B#qPh%j>O}bv7Ym)Htd{G)Mx*Siy{C8Xx%B7!zXEOW>+kb=AFXR| zAD(!o`$QHzdQlS0QpkTHhpqF@{?qW+KEJM*_B`rWWcQq%Uzrd*-|rER$i=c#>)F^GiYy|MYt&FW=TiCk zm*NY1^vBJ#8B}=~qS9krI)*D3N5ivHp2cY;CH4`!~FjXx@bv7kOI=B)qe5RFiT=BIPC}gVA-&Rf^*t5Ck)wf2`RY zlM0fW8&L;4_!ZZ-IQae3vtXpYtU6^@^w_l-x~TauxkXxD{Gqb2I;YukyDF!8Ug8`d< zX1!vLO%_r3OpWVDg0aR&I}@9y zn1*wj;pf8}!xHCt4=51Z*e|eqO)%#=H%*OIX=isAK=0{izg)@$Hm6C+V-R`MINB7d4UT6BkHl+Oxbh7`~A*!0}z0fifG`HeK#w=?nr>04LHP z()=<}?y-PWJdGMAyUQD~ZQj9BYkWJ!j=C_HblEI0`1%t99s&aLAG}6&z1#(L89apl z{o>8k;PbKis-9*ofZz{8@WT5MAu%k?NQ^>`#fpHZF7tn0e6oxfO>zn4$zXqI?OkOY zjj{tVSgF~j2^1uI2Im4425;ZlhSI{$e}r8C?)n}7sXYF_Tlw+-yV4~%^Qzd5$ZhxA z-)?gm*r+b?j(BhkFVb5V1u@rMCJwr`?cxS(EJc#>Yx?v*N767M5$@V-` z#==q2c3P-)Y9Ee;!vtZP6D7RVr%U`?$?M1zb4dyWJZmTT?uhg&8^Mi_K9j~$nYG-^ z0dNSs8h)^~py<0`oo9se;DYV{5SD=0aN#PMYPM?Bk}Zr8y`Mf7pTpNFH^t0RIR}tp zaX>G$FZm)=mG`g>D(EEZ($Oi#L1Bti67O)IvG&rZPT!v+^cM^QRG~B98}51>CL$;> zU0A_Ct-Z3~vWBhEti~6V9+ycZsZ_3fJ3k}^hpO+TKn0`g&w}?gQ6lsi7av1H|1xxz zPq!65@)yT{Ki1@ze@X2iJiMDUSzBIrn6Hy>K=(okW91^PtlAwY${_E93lO7rgekKP z+7_tT(xgq;=~JiiTBWMESH9oTJ~w1}e>e@yPqBo$iXMZsOK7bprZ01ehcBBhHx6XU ze_sXE#{tue?b1FO*g*&kyecuGOu^yiK+ag#as*PhscH_3%OCFrM?Mc;_cLQ14R*nq zL#0ipBUSbq+yfexW7Kt|wQ#yw8Uh4F+@yOmn@#<&CIwYs$5|pm0 zlHW*10*CQXx3jZD6zxt8{5cmaE>E}TMP^VGQnY}AR7?ZknvZ|}Kovxz@5Eb^t&7Kzd7-T)ID2OrOA{kG zA=dwSUgv~4Zim|OMFSMRa|$>WVz+EhKE?#*YrVH{M-aH25FWar&ko76|1AjBO9(vv znE*p3Q#Lq_qgln|qWSBGv!TjUfoUW1TzI!*k-IjF0?pNkWPJi3xAW~J_W=E$9yN36 zbkg5W>H5@Rj20swGtr=B*QG{vjnIWMz_L@WB>Z-4cQ>fHJhBsyw**53$C@n9a$*XtFK6 zdFG+<6o>VEqxo$cp@uZXqA9sA?G^cqWK4q=LN96bO^#?8{HHUFhY4NT&xPLCTcw08 zEltq4EBw)4yXXse&bwC&@RtDXpU8BOdj2felm8G{=-)X_&jhK`3*MF}Ip9H=aa|zPcP4yhBxxfXT!DLc5dpXqhq7r_noN!KDAihCSQr)cs7&raC5^Tw`9C$aOn10S{ z2?E-06tLyZ-%K`Lj#kl+h?|%pi zu4T{>nFIWf?p-^NG5Sj~O_0Xe0bW#9t|k2xW{Ixd#Hgn}@|0!fV=K^P=4JyIm2ut;(QDZ(2^l*#b&S{~@1#i`V(zHs;uge7V7wZXPL!5^ANFU_lGN z$|1(YC-0`j$YC+bgbgnuMvpVfXWi+4~T_iG@J@M8X=M55I8>=xqB}E%aLgdk`AACr2W>LhG zWt|QwGHf0C+@CZ?RNn$k!c-z_Z;N{x5a$;5MENKQ`)(k|RaV!8JK+@MXke{3KMn

G2>8BIx?e<6H%1l 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%0Do~yMQI20EXWKd>!!G=JNAMw6oRqf)*y! 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

`|ck;&;@rZcXrNY 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

%9?t#Z;KZFyy3Qj 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�?e2pnS&> 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

)Xdw`}j^b#_OK7`_ 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�@5*k;b=nX?G`) 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%0AV_aPzf<;zI_JbBbh2uZO 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%0Dgsta%JT~^U-EbQmf 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%0D7xuwyK+>%(Sc3YG{ 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%0A)>U(#AbRjB#X0)PD_2o$1B*%7t!iaBmTRpdW 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 z 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

67a3EUC(j$5{Q|CIZpeBk#?gilk!GC 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%0D1`RV0Cz#Va+9nU?jV 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 Date: Tue, 24 Oct 2017 15:41:27 +0200 Subject: [PATCH 0602/2114] Increase wait time in NIO TLS test CI fails sometimes. --- .../rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java index abf6376c46..029fbbd5df 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java @@ -121,7 +121,7 @@ public void configure(SSLEngine sslEngine) throws IOException { private void sendAndVerifyMessage(int size) throws Exception { CountDownLatch latch = new CountDownLatch(1); connection = basicGetBasicConsume(connection, QUEUE, latch, size); - boolean messagesReceived = latch.await(10, TimeUnit.SECONDS); + boolean messagesReceived = latch.await(20, TimeUnit.SECONDS); assertTrue("Message has not been received", messagesReceived); } From b3f3aa5001b5a3f38ddc68b829955a1736f5a011 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 27 Oct 2017 11:28:36 +0200 Subject: [PATCH 0603/2114] Increase TTL and waiting time in test The test would fail frequently on CI: TTL and wait times were below 200 ms. TTL is now 400 ms and waiting times >= 200 ms, which should give the broker more time to expire the messages. --- .../com/rabbitmq/client/test/functional/TTLHandling.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/TTLHandling.java b/src/test/java/com/rabbitmq/client/test/functional/TTLHandling.java index f6081c99c0..40719510fa 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/TTLHandling.java +++ b/src/test/java/com/rabbitmq/client/test/functional/TTLHandling.java @@ -143,10 +143,10 @@ protected void releaseResources() throws IOException { } @Test public void expiryWithRequeue() throws Exception { - declareAndBindQueue(200); + declareAndBindQueue(400); publish(MSG[0]); - Thread.sleep(100); + Thread.sleep(200); publish(MSG[1]); publish(MSG[2]); @@ -156,7 +156,7 @@ protected void releaseResources() throws IOException { closeChannel(); openChannel(); - Thread.sleep(110); + Thread.sleep(300); expectBodyAndRemainingMessages(MSG[1], 1); expectBodyAndRemainingMessages(MSG[2], 0); } From e9b642f7e34499b67928d00c4b868d5e9228e34f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 7 Nov 2017 11:44:47 +0100 Subject: [PATCH 0604/2114] Add property file-based initialization Fixes #324 --- .../rabbitmq/client/ConnectionFactory.java | 76 ++++++ .../client/ConnectionFactoryConfigurer.java | 252 ++++++++++++++++++ .../com/rabbitmq/client/test/ClientTests.java | 3 +- .../test/PropertyFileInitialisationTest.java | 170 ++++++++++++ .../configuration.properties | 25 ++ 5 files changed, 525 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurer.java create mode 100644 src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java create mode 100644 src/test/resources/property-file-initialisation/configuration.properties diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 4074f9d448..ccf7482226 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -1059,6 +1059,74 @@ protected AddressResolver createAddressResolver(List

addresses) { } } + /** + * Load settings from a property file. + * The default prefix for keys is rabbitmq. + * @param propertyFileLocation location of the property file to use + * @throws IOException when something goes wrong reading the file + * @since 4.4.0 + * @see ConnectionFactoryConfigurer + */ + public void load(String propertyFileLocation) throws IOException { + ConnectionFactoryConfigurer.load(this, propertyFileLocation); + } + + /** + * Load settings from a property file. + * @param propertyFileLocation location of the property file to use + * @param prefix prefix used in the property file keys + * @throws IOException when something goes wrong reading the file + * @since 4.4.0 + * @see ConnectionFactoryConfigurer + */ + public void load(String propertyFileLocation, String prefix) throws IOException { + ConnectionFactoryConfigurer.load(this, propertyFileLocation, prefix); + } + + /** + * Load settings from a {@link Properties} instance. + * The default prefix for keys is rabbitmq. + * @param properties source for settings + * @since 4.4.0 + * @see ConnectionFactoryConfigurer + */ + public void load(Properties properties) { + ConnectionFactoryConfigurer.load(this, properties); + } + + /** + * Load settings from a {@link Properties} instance. + * @param properties source for settings + * @param prefix prefix used in keys + * @since 4.4.0 + * @see ConnectionFactoryConfigurer + */ + public void load(Properties properties, String prefix) { + ConnectionFactoryConfigurer.load(this, (Map) properties, prefix); + } + + /** + * Load settings from a {@link Map} instance. + * The default prefix for keys is rabbitmq. + * @param properties source for settings + * @since 4.4.0 + * @see ConnectionFactoryConfigurer + */ + public void load(Map properties) { + ConnectionFactoryConfigurer.load(this, properties); + } + + /** + * Load settings from a {@link Map} instance. + * @param properties source for settings + * @param prefix prefix used in keys + * @since 4.4.0 + * @see ConnectionFactoryConfigurer + */ + public void load(Map properties, String prefix) { + ConnectionFactoryConfigurer.load(this, properties, prefix); + } + /** * Returns automatic connection recovery interval in milliseconds. * @return how long will automatic recovery wait before attempting to reconnect, in ms; default is 5000 @@ -1118,6 +1186,14 @@ public void setNioParams(NioParams nioParams) { this.nioParams = nioParams; } + /** + * Retrieve the parameters for NIO mode. + * @return + */ + public NioParams getNioParams() { + return nioParams; + } + /** * Use non-blocking IO (NIO) for communication with the server. * With NIO, several connections created from the same {@link ConnectionFactory} diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurer.java b/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurer.java new file mode 100644 index 0000000000..315b608671 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurer.java @@ -0,0 +1,252 @@ +// Copyright (c) 2017-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client; + +import com.rabbitmq.client.impl.AMQConnection; +import com.rabbitmq.client.impl.nio.NioParams; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.net.URISyntaxException; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +/** + * Helper class to load {@link ConnectionFactory} settings from a property file. + * + * The authorised keys are the constants values in this class (e.g. USERNAME). + * The property file/properties instance/map instance keys can have + * a prefix, the default being rabbitmq.. + * + * Property files can be loaded from the file system (the default), + * but also from the classpath, by using the classpath: prefix + * in the location. + * + * If default client properties should be set, set the use.default.client.properties + * key to true. Custom client properties can be set by using + * the client.properties., e.g. client.properties.app.name. + * + * @since 4.4.0 + * @see ConnectionFactory#load(String, String) + */ +public class ConnectionFactoryConfigurer { + + public static final String DEFAULT_PREFIX = "rabbitmq."; + + public static final String USERNAME = "username"; + public static final String PASSWORD = "password"; + public static final String VIRTUAL_HOST = "virtual.host"; + public static final String HOST = "host"; + public static final String PORT = "port"; + public static final String REQUESTED_CHANNEL_MAX = "requested.channel.max"; + public static final String REQUESTED_FRAME_MAX = "requested.frame.max"; + public static final String REQUESTED_HEARTBEAT = "requested.heartbeat"; + public static final String CONNECTION_TIMEOUT = "connection.timeout"; + public static final String HANDSHAKE_TIMEOUT = "handshake.timeout"; + public static final String SHUTDOWN_TIMEOUT = "shutdown.timeout"; + public static final String USE_DEFAULT_CLIENT_PROPERTIES = "use.default.client.properties"; + public static final String CLIENT_PROPERTIES_PREFIX = "client.properties."; + public static final String AUTOMATIC_RECOVERY_ENABLED = "automatic.recovery.enabled"; + public static final String TOPOLOGY_RECOVERY_ENABLED = "topology.recovery.enabled"; + public static final String NETWORK_RECOVERY_INTERVAL = "network.recovery.interval"; + public static final String CHANNEL_RPC_TIMEOUT = "channel.rpc.timeout"; + public static final String CHANNEL_SHOULD_CHECK_RPC_RESPONSE_TYPE = "channel.should.check.rpc.response.type"; + public static final String USE_NIO = "use.nio"; + public static final String NIO_READ_BYTE_BUFFER_SIZE = "nio.read.byte.buffer.size"; + public static final String NIO_WRITE_BYTE_BUFFER_SIZE = "nio.write.byte.buffer.size"; + public static final String NIO_NB_IO_THREADS = "nio.nb.io.threads"; + public static final String NIO_WRITE_ENQUEUING_TIMEOUT_IN_MS = "nio.write.enqueuing.timeout.in.ms"; + public static final String NIO_WRITE_QUEUE_CAPACITY = "nio.write.queue.capacity"; + + public static void load(ConnectionFactory cf, String propertyFileLocation, String prefix) throws IOException { + if (propertyFileLocation == null || propertyFileLocation.isEmpty()) { + throw new IllegalArgumentException("Property file argument cannot be null or empty"); + } + Properties properties = new Properties(); + if (propertyFileLocation.startsWith("classpath:")) { + InputStream in = null; + try { + in = ConnectionFactoryConfigurer.class.getResourceAsStream( + propertyFileLocation.substring("classpath:".length()) + ); + properties.load(in); + } finally { + if (in != null) { + in.close(); + } + } + } else { + Reader reader = null; + try { + reader = new BufferedReader(new FileReader(propertyFileLocation)); + properties.load(reader); + } finally { + if (reader != null) { + reader.close(); + } + } + } + load(cf, (Map) properties, prefix); + } + + public static void load(ConnectionFactory cf, Map properties, String prefix) { + prefix = prefix == null ? "" : prefix; + String uri = properties.get(prefix + "uri"); + if (uri != null) { + try { + cf.setUri(uri); + } catch (URISyntaxException e) { + throw new IllegalArgumentException("Error while setting AMQP URI: "+uri, e); + } catch (NoSuchAlgorithmException e) { + throw new IllegalArgumentException("Error while setting AMQP URI: "+uri, e); + } catch (KeyManagementException e) { + throw new IllegalArgumentException("Error while setting AMQP URI: "+uri, e); + } + } + String username = properties.get(prefix + USERNAME); + if (username != null) { + cf.setUsername(username); + } + String password = properties.get(prefix + PASSWORD); + if (password != null) { + cf.setPassword(password); + } + String vhost = properties.get(prefix + VIRTUAL_HOST); + if (vhost != null) { + cf.setVirtualHost(vhost); + } + String host = properties.get(prefix + HOST); + if (host != null) { + cf.setHost(host); + } + String port = properties.get(prefix + PORT); + if (port != null) { + cf.setPort(Integer.valueOf(port)); + } + String requestedChannelMax = properties.get(prefix + REQUESTED_CHANNEL_MAX); + if (requestedChannelMax != null) { + cf.setRequestedChannelMax(Integer.valueOf(requestedChannelMax)); + } + String requestedFrameMax = properties.get(prefix + REQUESTED_FRAME_MAX); + if (requestedFrameMax != null) { + cf.setRequestedFrameMax(Integer.valueOf(requestedFrameMax)); + } + String requestedHeartbeat = properties.get(prefix + REQUESTED_HEARTBEAT); + if (requestedHeartbeat != null) { + cf.setRequestedHeartbeat(Integer.valueOf(requestedHeartbeat)); + } + String connectionTimeout = properties.get(prefix + CONNECTION_TIMEOUT); + if (connectionTimeout != null) { + cf.setConnectionTimeout(Integer.valueOf(connectionTimeout)); + } + String handshakeTimeout = properties.get(prefix + HANDSHAKE_TIMEOUT); + if (handshakeTimeout != null) { + cf.setHandshakeTimeout(Integer.valueOf(handshakeTimeout)); + } + String shutdownTimeout = properties.get(prefix + SHUTDOWN_TIMEOUT); + if (shutdownTimeout != null) { + cf.setShutdownTimeout(Integer.valueOf(shutdownTimeout)); + } + + Map clientProperties = new HashMap(); + String useDefaultClientProperties = properties.get(prefix + USE_DEFAULT_CLIENT_PROPERTIES); + if (useDefaultClientProperties != null && Boolean.valueOf(useDefaultClientProperties)) { + clientProperties.putAll(AMQConnection.defaultClientProperties()); + } + + for (Map.Entry entry : properties.entrySet()) { + if (entry.getKey().startsWith(prefix + CLIENT_PROPERTIES_PREFIX)) { + clientProperties.put( + entry.getKey().substring((prefix + CLIENT_PROPERTIES_PREFIX).length()), + entry.getValue() + ); + } + } + cf.setClientProperties(clientProperties); + + String automaticRecovery = properties.get(prefix + AUTOMATIC_RECOVERY_ENABLED); + if (automaticRecovery != null) { + cf.setAutomaticRecoveryEnabled(Boolean.valueOf(automaticRecovery)); + } + String topologyRecovery = properties.get(prefix + TOPOLOGY_RECOVERY_ENABLED); + if (topologyRecovery != null) { + cf.setTopologyRecoveryEnabled(Boolean.getBoolean(topologyRecovery)); + } + String networkRecoveryInterval = properties.get(prefix + NETWORK_RECOVERY_INTERVAL); + if (networkRecoveryInterval != null) { + cf.setNetworkRecoveryInterval(Long.valueOf(networkRecoveryInterval)); + } + String channelRpcTimeout = properties.get(prefix + CHANNEL_RPC_TIMEOUT); + if (channelRpcTimeout != null) { + cf.setChannelRpcTimeout(Integer.valueOf(channelRpcTimeout)); + } + String channelShouldCheckRpcResponseType = properties.get(prefix + CHANNEL_SHOULD_CHECK_RPC_RESPONSE_TYPE); + if (channelShouldCheckRpcResponseType != null) { + cf.setChannelShouldCheckRpcResponseType(Boolean.valueOf(channelShouldCheckRpcResponseType)); + } + + String useNio = properties.get(prefix + USE_NIO); + if (useNio != null && Boolean.valueOf(useNio)) { + cf.useNio(); + + NioParams nioParams = new NioParams(); + + String readByteBufferSize = properties.get(prefix + NIO_READ_BYTE_BUFFER_SIZE); + if (readByteBufferSize != null) { + nioParams.setReadByteBufferSize(Integer.valueOf(readByteBufferSize)); + } + String writeByteBufferSize = properties.get(prefix + NIO_WRITE_BYTE_BUFFER_SIZE); + if (writeByteBufferSize != null) { + nioParams.setWriteByteBufferSize(Integer.valueOf(writeByteBufferSize)); + } + String nbIoThreads = properties.get(prefix + NIO_NB_IO_THREADS); + if (nbIoThreads != null) { + nioParams.setNbIoThreads(Integer.valueOf(nbIoThreads)); + } + String writeEnqueuingTime = properties.get(prefix + NIO_WRITE_ENQUEUING_TIMEOUT_IN_MS); + if (writeEnqueuingTime != null) { + nioParams.setWriteEnqueuingTimeoutInMs(Integer.valueOf(writeEnqueuingTime)); + } + String writeQueueCapacity = properties.get(prefix + NIO_WRITE_QUEUE_CAPACITY); + if (writeQueueCapacity != null) { + nioParams.setWriteQueueCapacity(Integer.valueOf(writeQueueCapacity)); + } + cf.setNioParams(nioParams); + } + } + + public static void load(ConnectionFactory connectionFactory, String propertyFileLocation) throws IOException { + load(connectionFactory, propertyFileLocation, DEFAULT_PREFIX); + } + + public static void load(ConnectionFactory connectionFactory, Properties properties) { + load(connectionFactory, (Map) properties, DEFAULT_PREFIX); + } + + public static void load(ConnectionFactory connectionFactory, Properties properties, String prefix) { + load(connectionFactory, (Map) properties, prefix); + } + + public static void load(ConnectionFactory connectionFactory, Map properties) { + load(connectionFactory, properties, DEFAULT_PREFIX); + } +} diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index 1162bfa357..2391735d56 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -49,7 +49,8 @@ ConnectionFactoryTest.class, RecoveryAwareAMQConnectionFactoryTest.class, RpcTest.class, - RecoveryDelayHandlerTest.class + RecoveryDelayHandlerTest.class, + PropertyFileInitialisationTest.class }) public class ClientTests { diff --git a/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java b/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java new file mode 100644 index 0000000000..899e4ca966 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java @@ -0,0 +1,170 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.test; + +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.ConnectionFactoryConfigurer; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.io.FileReader; +import java.io.IOException; +import java.io.Reader; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import static com.rabbitmq.client.impl.AMQConnection.defaultClientProperties; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.notNullValue; +import static org.junit.Assert.assertThat; + +/** + * + */ +@RunWith(Parameterized.class) +public class PropertyFileInitialisationTest { + + @Parameterized.Parameters + public static Object[] data() { + return new Object[] { + "./src/test/resources/property-file-initialisation/configuration.properties", + "classpath:/property-file-initialisation/configuration.properties" + }; + } + + @Parameterized.Parameter + public String propertyFileLocation; + + ConnectionFactory cf = new ConnectionFactory(); + + @Test public void propertyInitialisationFromFile() throws IOException { + cf.load(propertyFileLocation); + checkConnectionFactory(); + } + + @Test public void propertyInitialisationCustomPrefix() throws Exception { + Properties propertiesCustomPrefix = getPropertiesWitPrefix("prefix."); + + cf.load(propertiesCustomPrefix, "prefix."); + checkConnectionFactory(); + } + + @Test public void propertyInitialisationNoPrefix() throws Exception { + Properties propertiesCustomPrefix = getPropertiesWitPrefix(""); + + cf.load(propertiesCustomPrefix, ""); + checkConnectionFactory(); + } + + @Test public void propertyInitialisationNullPrefix() throws Exception { + Properties propertiesCustomPrefix = getPropertiesWitPrefix(""); + + cf.load(propertiesCustomPrefix, null); + checkConnectionFactory(); + } + + @Test public void propertyInitialisationUri() { + cf.load(Collections.singletonMap("rabbitmq.uri", "amqp://foo:bar@127.0.0.1:5673/dummy")); + + assertThat(cf.getUsername(), is("foo")); + assertThat(cf.getPassword(), is("bar")); + assertThat(cf.getVirtualHost(), is("dummy")); + assertThat(cf.getHost(), is("127.0.0.1")); + assertThat(cf.getPort(), is(5673)); + } + + @Test public void propertyInitialisationIncludeDefaultClientProperties() { + cf.load(new HashMap() {{ + put("rabbitmq.use.default.client.properties", "true"); + put("rabbitmq.client.properties.foo", "bar"); + }}); + assertThat(cf.getClientProperties().entrySet(), hasSize(defaultClientProperties().size() + 1)); + assertThat(cf.getClientProperties().get("foo").toString(), is("bar")); + } + + @Test public void propertyInitialisationDoNotIncludeDefaultClientProperties() { + cf.load(new HashMap() {{ + put("rabbitmq.use.default.client.properties", "false"); + put("rabbitmq.client.properties.foo", "bar"); + }}); + assertThat(cf.getClientProperties().entrySet(), hasSize(1)); + assertThat(cf.getClientProperties().get("foo").toString(), is("bar")); + } + + @Test public void propertyInitialisationDoNotUseNio() throws Exception { + cf.load(new HashMap() {{ + put("rabbitmq.use.nio", "false"); + put("rabbitmq.nio.nb.io.threads", "2"); + }}); + assertThat(cf.getNioParams().getNbIoThreads(), not(2)); + } + + private void checkConnectionFactory() { + assertThat(cf.getUsername(), is("foo")); + assertThat(cf.getPassword(), is("bar")); + assertThat(cf.getVirtualHost(), is("dummy")); + assertThat(cf.getHost(), is("127.0.0.1")); + assertThat(cf.getPort(), is(5673)); + + assertThat(cf.getRequestedChannelMax(), is(1)); + assertThat(cf.getRequestedFrameMax(), is(2)); + assertThat(cf.getRequestedHeartbeat(), is(10)); + assertThat(cf.getConnectionTimeout(), is(10000)); + assertThat(cf.getHandshakeTimeout(), is(5000)); + + assertThat(cf.getClientProperties().entrySet(), hasSize(defaultClientProperties().size() + 1)); + assertThat(cf.getClientProperties().get("foo").toString(), is("bar")); + + assertThat(cf.isAutomaticRecoveryEnabled(), is(false)); + assertThat(cf.isTopologyRecoveryEnabled(), is(false)); + assertThat(cf.getNetworkRecoveryInterval(), is(10000l)); + assertThat(cf.getChannelRpcTimeout(), is(10000)); + assertThat(cf.isChannelShouldCheckRpcResponseType(), is(true)); + + assertThat(cf.getNioParams(), notNullValue()); + assertThat(cf.getNioParams().getReadByteBufferSize(), is(32000)); + assertThat(cf.getNioParams().getWriteByteBufferSize(), is(32000)); + assertThat(cf.getNioParams().getNbIoThreads(), is(2)); + assertThat(cf.getNioParams().getWriteEnqueuingTimeoutInMs(), is(5000)); + assertThat(cf.getNioParams().getWriteQueueCapacity(), is(1000)); + } + + private Properties getPropertiesWitPrefix(String prefix) throws IOException { + Properties properties = new Properties(); + Reader reader = null; + try { + reader = new FileReader("./src/test/resources/property-file-initialisation/configuration.properties"); + properties.load(reader); + } finally { + reader.close(); + } + + Properties propertiesCustomPrefix = new Properties(); + for (Map.Entry entry : properties.entrySet()) { + propertiesCustomPrefix.put( + prefix + entry.getKey().toString().substring(ConnectionFactoryConfigurer.DEFAULT_PREFIX.length()), + entry.getValue() + ); + } + return propertiesCustomPrefix; + } + +} diff --git a/src/test/resources/property-file-initialisation/configuration.properties b/src/test/resources/property-file-initialisation/configuration.properties new file mode 100644 index 0000000000..b703e68d8c --- /dev/null +++ b/src/test/resources/property-file-initialisation/configuration.properties @@ -0,0 +1,25 @@ +rabbitmq.uri=amqp://bar:foo@somewhere:5674/foobar +rabbitmq.username=foo +rabbitmq.password=bar +rabbitmq.virtual.host=dummy +rabbitmq.host=127.0.0.1 +rabbitmq.port=5673 +rabbitmq.requested.channel.max=1 +rabbitmq.requested.frame.max=2 +rabbitmq.requested.heartbeat=10 +rabbitmq.connection.timeout=10000 +rabbitmq.handshake.timeout=5000 +rabbitmq.shutdown.timeout=20000 +rabbitmq.use.default.client.properties=true +rabbitmq.client.properties.foo=bar +rabbitmq.automatic.recovery.enabled=false +rabbitmq.topology.recovery.enabled=false +rabbitmq.network.recovery.interval=10000 +rabbitmq.channel.rpc.timeout=10000 +rabbitmq.channel.should.check.rpc.response.type=true +rabbitmq.use.nio=true +rabbitmq.nio.read.byte.buffer.size=32000 +rabbitmq.nio.write.byte.buffer.size=32000 +rabbitmq.nio.nb.io.threads=2 +rabbitmq.nio.write.enqueuing.timeout.in.ms=5000 +rabbitmq.nio.write.queue.capacity=1000 From 6a9c1ab6abfe8fb7b02223e886bb67babd44b716 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 7 Nov 2017 15:57:15 +0100 Subject: [PATCH 0605/2114] Rename ConnectionFactoryConfigurer to ConnectionFactoryConfigurator References #324 --- .../rabbitmq/client/ConnectionFactory.java | 30 +++++++++---------- ...ava => ConnectionFactoryConfigurator.java} | 4 +-- .../test/PropertyFileInitialisationTest.java | 4 +-- 3 files changed, 19 insertions(+), 19 deletions(-) rename src/main/java/com/rabbitmq/client/{ConnectionFactoryConfigurer.java => ConnectionFactoryConfigurator.java} (98%) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index ccf7482226..5ed3783a1f 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -1065,22 +1065,22 @@ protected AddressResolver createAddressResolver(List
addresses) { * @param propertyFileLocation location of the property file to use * @throws IOException when something goes wrong reading the file * @since 4.4.0 - * @see ConnectionFactoryConfigurer + * @see ConnectionFactoryConfigurator */ public void load(String propertyFileLocation) throws IOException { - ConnectionFactoryConfigurer.load(this, propertyFileLocation); + ConnectionFactoryConfigurator.load(this, propertyFileLocation); } /** * Load settings from a property file. * @param propertyFileLocation location of the property file to use - * @param prefix prefix used in the property file keys + * @param prefix key prefix for the entries in the file * @throws IOException when something goes wrong reading the file * @since 4.4.0 - * @see ConnectionFactoryConfigurer + * @see ConnectionFactoryConfigurator */ public void load(String propertyFileLocation, String prefix) throws IOException { - ConnectionFactoryConfigurer.load(this, propertyFileLocation, prefix); + ConnectionFactoryConfigurator.load(this, propertyFileLocation, prefix); } /** @@ -1088,21 +1088,21 @@ public void load(String propertyFileLocation, String prefix) throws IOException * The default prefix for keys is rabbitmq. * @param properties source for settings * @since 4.4.0 - * @see ConnectionFactoryConfigurer + * @see ConnectionFactoryConfigurator */ public void load(Properties properties) { - ConnectionFactoryConfigurer.load(this, properties); + ConnectionFactoryConfigurator.load(this, properties); } /** * Load settings from a {@link Properties} instance. * @param properties source for settings - * @param prefix prefix used in keys + * @param prefix key prefix for properties entries * @since 4.4.0 - * @see ConnectionFactoryConfigurer + * @see ConnectionFactoryConfigurator */ public void load(Properties properties, String prefix) { - ConnectionFactoryConfigurer.load(this, (Map) properties, prefix); + ConnectionFactoryConfigurator.load(this, (Map) properties, prefix); } /** @@ -1110,21 +1110,21 @@ public void load(Properties properties, String prefix) { * The default prefix for keys is rabbitmq. * @param properties source for settings * @since 4.4.0 - * @see ConnectionFactoryConfigurer + * @see ConnectionFactoryConfigurator */ public void load(Map properties) { - ConnectionFactoryConfigurer.load(this, properties); + ConnectionFactoryConfigurator.load(this, properties); } /** * Load settings from a {@link Map} instance. * @param properties source for settings - * @param prefix prefix used in keys + * @param prefix key prefix for map entries * @since 4.4.0 - * @see ConnectionFactoryConfigurer + * @see ConnectionFactoryConfigurator */ public void load(Map properties, String prefix) { - ConnectionFactoryConfigurer.load(this, properties, prefix); + ConnectionFactoryConfigurator.load(this, properties, prefix); } /** diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurer.java b/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java similarity index 98% rename from src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurer.java rename to src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java index 315b608671..ce9f29648f 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurer.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java @@ -48,7 +48,7 @@ * @since 4.4.0 * @see ConnectionFactory#load(String, String) */ -public class ConnectionFactoryConfigurer { +public class ConnectionFactoryConfigurator { public static final String DEFAULT_PREFIX = "rabbitmq."; @@ -85,7 +85,7 @@ public static void load(ConnectionFactory cf, String propertyFileLocation, Strin if (propertyFileLocation.startsWith("classpath:")) { InputStream in = null; try { - in = ConnectionFactoryConfigurer.class.getResourceAsStream( + in = ConnectionFactoryConfigurator.class.getResourceAsStream( propertyFileLocation.substring("classpath:".length()) ); properties.load(in); diff --git a/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java b/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java index 899e4ca966..5bbd2e3de1 100644 --- a/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java +++ b/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java @@ -16,7 +16,7 @@ package com.rabbitmq.client.test; import com.rabbitmq.client.ConnectionFactory; -import com.rabbitmq.client.ConnectionFactoryConfigurer; +import com.rabbitmq.client.ConnectionFactoryConfigurator; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -160,7 +160,7 @@ private Properties getPropertiesWitPrefix(String prefix) throws IOException { Properties propertiesCustomPrefix = new Properties(); for (Map.Entry entry : properties.entrySet()) { propertiesCustomPrefix.put( - prefix + entry.getKey().toString().substring(ConnectionFactoryConfigurer.DEFAULT_PREFIX.length()), + prefix + entry.getKey().toString().substring(ConnectionFactoryConfigurator.DEFAULT_PREFIX.length()), entry.getValue() ); } From 46263cd9503707521d8f77b87dcdb883dfec4bc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 8 Nov 2017 11:19:16 +0100 Subject: [PATCH 0606/2114] Add Automatic-Module-Name manigest entry For JDK 9 module system interoperability. Automatic-Module-Name: com.rabbitmq.client Fixes #320 --- pom.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pom.xml b/pom.xml index 8e218f2839..302c1638c9 100644 --- a/pom.xml +++ b/pom.xml @@ -861,6 +861,9 @@ ${project.build.outputDirectory}/META-INF/MANIFEST.MF + + com.rabbitmq.client + From 638c5c1b16a2ce8ad1393e5b62ef650bac00a4c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 8 Nov 2017 16:40:12 +0100 Subject: [PATCH 0607/2114] Make NIO tests more reliable --- .../com/rabbitmq/client/test/JavaNioTest.java | 55 +++++++++++++++++++ .../test/ssl/NioTlsUnverifiedConnection.java | 20 ++++--- 2 files changed, 66 insertions(+), 9 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/JavaNioTest.java b/src/test/java/com/rabbitmq/client/test/JavaNioTest.java index 33630aef80..0051765da6 100644 --- a/src/test/java/com/rabbitmq/client/test/JavaNioTest.java +++ b/src/test/java/com/rabbitmq/client/test/JavaNioTest.java @@ -2,6 +2,8 @@ import com.rabbitmq.client.*; import com.rabbitmq.client.impl.nio.NioParams; +import org.junit.After; +import org.junit.Before; import org.junit.Test; import java.io.IOException; @@ -14,6 +16,25 @@ */ public class JavaNioTest { + public static final String QUEUE = "nio.queue"; + + private Connection testConnection; + + @Before + public void init() throws Exception { + ConnectionFactory connectionFactory = new ConnectionFactory(); + connectionFactory.useNio(); + testConnection = connectionFactory.newConnection(); + } + + @After + public void tearDown() throws Exception { + if (testConnection != null) { + testConnection.createChannel().queueDelete(QUEUE); + testConnection.close(); + } + } + @Test public void connection() throws Exception { CountDownLatch latch = new CountDownLatch(1); @@ -101,6 +122,18 @@ public void nioLoopCleaning() throws Exception { } } + @Test public void messageSize() throws Exception { + for (int i = 0; i < 50; i++) { + sendAndVerifyMessage(testConnection, 76390); + } + } + + private void sendAndVerifyMessage(Connection connection, int size) throws Exception { + CountDownLatch latch = new CountDownLatch(1); + boolean messageReceived = basicGetBasicConsume(connection, QUEUE, latch, size); + assertTrue("Message has not been received", messageReceived); + } + private Connection basicGetBasicConsume(ConnectionFactory connectionFactory, String queue, final CountDownLatch latch) throws IOException, TimeoutException { Connection connection = connectionFactory.newConnection(); @@ -121,6 +154,28 @@ public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProp return connection; } + private boolean basicGetBasicConsume(Connection connection, String queue, final CountDownLatch latch, int msgSize) + throws Exception { + Channel channel = connection.createChannel(); + channel.queueDeclare(queue, false, false, false, null); + channel.queuePurge(queue); + + channel.basicPublish("", queue, null, new byte[msgSize]); + + final String tag = channel.basicConsume(queue, false, new DefaultConsumer(channel) { + + @Override + public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { + getChannel().basicAck(envelope.getDeliveryTag(), false); + latch.countDown(); + } + }); + + boolean done = latch.await(20, TimeUnit.SECONDS); + channel.basicCancel(tag); + return done; + } + private void safeClose(Connection connection) { if (connection != null) { try { diff --git a/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java index 029fbbd5df..7312658894 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java @@ -71,7 +71,7 @@ protected void releaseResources() throws IOException { @Test public void connectionGetConsume() throws Exception { CountDownLatch latch = new CountDownLatch(1); - connection = basicGetBasicConsume(connection, QUEUE, latch, 100 * 1000); + basicGetBasicConsume(connection, QUEUE, latch, 100 * 1000); boolean messagesReceived = latch.await(5, TimeUnit.SECONDS); assertTrue("Message has not been received", messagesReceived); } @@ -120,30 +120,32 @@ public void configure(SSLEngine sslEngine) throws IOException { private void sendAndVerifyMessage(int size) throws Exception { CountDownLatch latch = new CountDownLatch(1); - connection = basicGetBasicConsume(connection, QUEUE, latch, size); - boolean messagesReceived = latch.await(20, TimeUnit.SECONDS); - assertTrue("Message has not been received", messagesReceived); + boolean messageReceived = basicGetBasicConsume(connection, QUEUE, latch, size); + assertTrue("Message has not been received", messageReceived); } - private Connection basicGetBasicConsume(Connection connection, String queue, final CountDownLatch latch, int msgSize) - throws IOException, TimeoutException { + private boolean basicGetBasicConsume(Connection connection, String queue, final CountDownLatch latch, int msgSize) + throws Exception { Channel channel = connection.createChannel(); channel.queueDeclare(queue, false, false, false, null); channel.queuePurge(queue); channel.basicPublish("", queue, null, new byte[msgSize]); - channel.basicConsume(queue, false, new DefaultConsumer(channel) { + String tag = channel.basicConsume(queue, false, new DefaultConsumer(channel) { @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { getChannel().basicAck(envelope.getDeliveryTag(), false); latch.countDown(); - getChannel().basicCancel(consumerTag); } }); - return connection; + boolean messageReceived = latch.await(20, TimeUnit.SECONDS); + + channel.basicCancel(tag); + + return messageReceived; } } From a5b271d494364b0fb0931e49202febc4afc0b64f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 9 Nov 2017 15:14:21 +0100 Subject: [PATCH 0608/2114] Prefer connection prefix over requested Fixes #324 --- .../client/ConnectionFactoryConfigurator.java | 12 ++++++------ .../configuration.properties | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java b/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java index ce9f29648f..6b831cc2ee 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java @@ -57,9 +57,9 @@ public class ConnectionFactoryConfigurator { public static final String VIRTUAL_HOST = "virtual.host"; public static final String HOST = "host"; public static final String PORT = "port"; - public static final String REQUESTED_CHANNEL_MAX = "requested.channel.max"; - public static final String REQUESTED_FRAME_MAX = "requested.frame.max"; - public static final String REQUESTED_HEARTBEAT = "requested.heartbeat"; + public static final String CONNECTION_CHANNEL_MAX = "connection.channel.max"; + public static final String CONNECTION_FRAME_MAX = "connection.frame.max"; + public static final String CONNECTION_HEARTBEAT = "connection.heartbeat"; public static final String CONNECTION_TIMEOUT = "connection.timeout"; public static final String HANDSHAKE_TIMEOUT = "handshake.timeout"; public static final String SHUTDOWN_TIMEOUT = "shutdown.timeout"; @@ -142,15 +142,15 @@ public static void load(ConnectionFactory cf, Map properties, St if (port != null) { cf.setPort(Integer.valueOf(port)); } - String requestedChannelMax = properties.get(prefix + REQUESTED_CHANNEL_MAX); + String requestedChannelMax = properties.get(prefix + CONNECTION_CHANNEL_MAX); if (requestedChannelMax != null) { cf.setRequestedChannelMax(Integer.valueOf(requestedChannelMax)); } - String requestedFrameMax = properties.get(prefix + REQUESTED_FRAME_MAX); + String requestedFrameMax = properties.get(prefix + CONNECTION_FRAME_MAX); if (requestedFrameMax != null) { cf.setRequestedFrameMax(Integer.valueOf(requestedFrameMax)); } - String requestedHeartbeat = properties.get(prefix + REQUESTED_HEARTBEAT); + String requestedHeartbeat = properties.get(prefix + CONNECTION_HEARTBEAT); if (requestedHeartbeat != null) { cf.setRequestedHeartbeat(Integer.valueOf(requestedHeartbeat)); } diff --git a/src/test/resources/property-file-initialisation/configuration.properties b/src/test/resources/property-file-initialisation/configuration.properties index b703e68d8c..2d088470a9 100644 --- a/src/test/resources/property-file-initialisation/configuration.properties +++ b/src/test/resources/property-file-initialisation/configuration.properties @@ -4,9 +4,9 @@ rabbitmq.password=bar rabbitmq.virtual.host=dummy rabbitmq.host=127.0.0.1 rabbitmq.port=5673 -rabbitmq.requested.channel.max=1 -rabbitmq.requested.frame.max=2 -rabbitmq.requested.heartbeat=10 +rabbitmq.connection.channel.max=1 +rabbitmq.connection.frame.max=2 +rabbitmq.connection.heartbeat=10 rabbitmq.connection.timeout=10000 rabbitmq.handshake.timeout=5000 rabbitmq.shutdown.timeout=20000 From cb03deefea17364ed5d5631666734dc00142aae5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 9 Nov 2017 15:49:55 +0100 Subject: [PATCH 0609/2114] Return connection factory in load methods For fluent API. References #324 --- .../com/rabbitmq/client/ConnectionFactory.java | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 5ed3783a1f..2cfed492b0 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -1067,8 +1067,9 @@ protected AddressResolver createAddressResolver(List
addresses) { * @since 4.4.0 * @see ConnectionFactoryConfigurator */ - public void load(String propertyFileLocation) throws IOException { + public ConnectionFactory load(String propertyFileLocation) throws IOException { ConnectionFactoryConfigurator.load(this, propertyFileLocation); + return this; } /** @@ -1079,8 +1080,9 @@ public void load(String propertyFileLocation) throws IOException { * @since 4.4.0 * @see ConnectionFactoryConfigurator */ - public void load(String propertyFileLocation, String prefix) throws IOException { + public ConnectionFactory load(String propertyFileLocation, String prefix) throws IOException { ConnectionFactoryConfigurator.load(this, propertyFileLocation, prefix); + return this; } /** @@ -1090,8 +1092,9 @@ public void load(String propertyFileLocation, String prefix) throws IOException * @since 4.4.0 * @see ConnectionFactoryConfigurator */ - public void load(Properties properties) { + public ConnectionFactory load(Properties properties) { ConnectionFactoryConfigurator.load(this, properties); + return this; } /** @@ -1101,8 +1104,9 @@ public void load(Properties properties) { * @since 4.4.0 * @see ConnectionFactoryConfigurator */ - public void load(Properties properties, String prefix) { + public ConnectionFactory load(Properties properties, String prefix) { ConnectionFactoryConfigurator.load(this, (Map) properties, prefix); + return this; } /** @@ -1112,8 +1116,9 @@ public void load(Properties properties, String prefix) { * @since 4.4.0 * @see ConnectionFactoryConfigurator */ - public void load(Map properties) { + public ConnectionFactory load(Map properties) { ConnectionFactoryConfigurator.load(this, properties); + return this; } /** @@ -1123,8 +1128,9 @@ public void load(Map properties) { * @since 4.4.0 * @see ConnectionFactoryConfigurator */ - public void load(Map properties, String prefix) { + public ConnectionFactory load(Map properties, String prefix) { ConnectionFactoryConfigurator.load(this, properties, prefix); + return this; } /** From 580677c8b36677f4af74dd8d5d30c7080d5d9fe1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 10 Nov 2017 10:15:26 +0100 Subject: [PATCH 0610/2114] Polish Javadoc of ConnectionFactory#load References #324 --- .../java/com/rabbitmq/client/ConnectionFactory.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 2cfed492b0..f9b5ec7d89 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -1061,7 +1061,9 @@ protected AddressResolver createAddressResolver(List
addresses) { /** * Load settings from a property file. - * The default prefix for keys is rabbitmq. + * Keys must be prefixed with rabbitmq., + * use {@link ConnectionFactory#load(String, String)} to + * specify your own prefix. * @param propertyFileLocation location of the property file to use * @throws IOException when something goes wrong reading the file * @since 4.4.0 @@ -1087,7 +1089,9 @@ public ConnectionFactory load(String propertyFileLocation, String prefix) throws /** * Load settings from a {@link Properties} instance. - * The default prefix for keys is rabbitmq. + * Keys must be prefixed with rabbitmq., + * use {@link ConnectionFactory#load(Properties, String)} to + * specify your own prefix. * @param properties source for settings * @since 4.4.0 * @see ConnectionFactoryConfigurator @@ -1111,7 +1115,9 @@ public ConnectionFactory load(Properties properties, String prefix) { /** * Load settings from a {@link Map} instance. - * The default prefix for keys is rabbitmq. + * Keys must be prefixed with rabbitmq., + * use {@link ConnectionFactory#load(Map, String)} to + * specify your own prefix. * @param properties source for settings * @since 4.4.0 * @see ConnectionFactoryConfigurator From c5c0f640e34d44bb3b2867bd6d8b69cde498fc1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 10 Nov 2017 11:03:28 +0100 Subject: [PATCH 0611/2114] Use connection prefix for auto-recovery keys References #324 --- .../rabbitmq/client/ConnectionFactoryConfigurator.java | 8 ++++---- .../property-file-initialisation/configuration.properties | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java b/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java index 6b831cc2ee..518fa7e6d4 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java @@ -65,9 +65,9 @@ public class ConnectionFactoryConfigurator { public static final String SHUTDOWN_TIMEOUT = "shutdown.timeout"; public static final String USE_DEFAULT_CLIENT_PROPERTIES = "use.default.client.properties"; public static final String CLIENT_PROPERTIES_PREFIX = "client.properties."; - public static final String AUTOMATIC_RECOVERY_ENABLED = "automatic.recovery.enabled"; + public static final String CONNECTION_RECOVERY_ENABLED = "connection.recovery.enabled"; public static final String TOPOLOGY_RECOVERY_ENABLED = "topology.recovery.enabled"; - public static final String NETWORK_RECOVERY_INTERVAL = "network.recovery.interval"; + public static final String CONNECTION_RECOVERY_INTERVAL = "connection.recovery.interval"; public static final String CHANNEL_RPC_TIMEOUT = "channel.rpc.timeout"; public static final String CHANNEL_SHOULD_CHECK_RPC_RESPONSE_TYPE = "channel.should.check.rpc.response.type"; public static final String USE_NIO = "use.nio"; @@ -183,7 +183,7 @@ public static void load(ConnectionFactory cf, Map properties, St } cf.setClientProperties(clientProperties); - String automaticRecovery = properties.get(prefix + AUTOMATIC_RECOVERY_ENABLED); + String automaticRecovery = properties.get(prefix + CONNECTION_RECOVERY_ENABLED); if (automaticRecovery != null) { cf.setAutomaticRecoveryEnabled(Boolean.valueOf(automaticRecovery)); } @@ -191,7 +191,7 @@ public static void load(ConnectionFactory cf, Map properties, St if (topologyRecovery != null) { cf.setTopologyRecoveryEnabled(Boolean.getBoolean(topologyRecovery)); } - String networkRecoveryInterval = properties.get(prefix + NETWORK_RECOVERY_INTERVAL); + String networkRecoveryInterval = properties.get(prefix + CONNECTION_RECOVERY_INTERVAL); if (networkRecoveryInterval != null) { cf.setNetworkRecoveryInterval(Long.valueOf(networkRecoveryInterval)); } diff --git a/src/test/resources/property-file-initialisation/configuration.properties b/src/test/resources/property-file-initialisation/configuration.properties index 2d088470a9..7ec04b03fa 100644 --- a/src/test/resources/property-file-initialisation/configuration.properties +++ b/src/test/resources/property-file-initialisation/configuration.properties @@ -12,9 +12,9 @@ rabbitmq.handshake.timeout=5000 rabbitmq.shutdown.timeout=20000 rabbitmq.use.default.client.properties=true rabbitmq.client.properties.foo=bar -rabbitmq.automatic.recovery.enabled=false +rabbitmq.connection.recovery.enabled=false rabbitmq.topology.recovery.enabled=false -rabbitmq.network.recovery.interval=10000 +rabbitmq.connection.recovery.interval=10000 rabbitmq.channel.rpc.timeout=10000 rabbitmq.channel.should.check.rpc.response.type=true rabbitmq.use.nio=true From ee4e19676d600a3395fbe2680fbca53d65837be3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 10 Nov 2017 15:55:42 +0100 Subject: [PATCH 0612/2114] Get rid of read retry in NIO for plain connection A FrameBuilder class has been introduced to be able to read a frame in several network reads. The frame builder keeps track of the partial frame state. This avoids pulling from the network when the channel doesn't come back with any value from a network read, which is against the NIO philosophy. References #319 --- .../client/impl/nio/FrameBuilder.java | 114 ++++++++++++++++++ .../com/rabbitmq/client/impl/nio/NioLoop.java | 31 +++-- .../nio/SocketChannelFrameHandlerState.java | 6 + .../com/rabbitmq/client/test/ClientTests.java | 4 +- .../client/test/FrameBuilderTest.java | 109 +++++++++++++++++ 5 files changed, 251 insertions(+), 13 deletions(-) create mode 100644 src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java create mode 100644 src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java diff --git a/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java b/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java new file mode 100644 index 0000000000..a4cc776a0f --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java @@ -0,0 +1,114 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl.nio; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.MalformedFrameException; +import com.rabbitmq.client.impl.Frame; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.ReadableByteChannel; + +/** + * + */ +public class FrameBuilder { + + private static final int PAYLOAD_OFFSET = 1 /* type */ + 2 /* channel */ + 4 /* payload size */; + + private final ReadableByteChannel channel; + + private final ByteBuffer buffer; + + private int frameType; + private int frameChannel; + private byte [] framePayload; + + private int bytesRead = 0; + + private final int [] frameBuffer = new int[3]; + + public FrameBuilder(ReadableByteChannel channel, ByteBuffer buffer) { + this.channel = channel; + this.buffer = buffer; + } + + public Frame readFrame() throws IOException { + while(readFromNetworkIfNecessary()) { + if (bytesRead == 0) { + // type + // FIXME check first byte isn't 'A' and thus a header indicating protocol version mismatch + frameType = readFromBuffer(); + } else if (bytesRead == 1) { + // channel 1/2 + frameBuffer[0] = readFromBuffer(); + } else if (bytesRead == 2) { + // channel 2/2 + frameChannel = (frameBuffer[0] << 8) + (readFromBuffer() << 0); + } else if (bytesRead == 3) { + // payload size 1/4 + frameBuffer[0] = readFromBuffer(); + } else if (bytesRead == 4) { + // payload size 2/4 + frameBuffer[1] = readFromBuffer(); + } else if (bytesRead == 5) { + // payload size 3/4 + frameBuffer[2] = readFromBuffer(); + } else if (bytesRead == 6) { + // payload size 4/4 + int framePayloadSize = ((frameBuffer[0] << 24) + (frameBuffer[1] << 16) + (frameBuffer[2] << 8) + (readFromBuffer() << 0)); + framePayload = new byte[framePayloadSize]; + } else if (bytesRead >= PAYLOAD_OFFSET && bytesRead < framePayload.length + PAYLOAD_OFFSET) { + framePayload[bytesRead - PAYLOAD_OFFSET] = (byte) readFromBuffer(); + } else if (bytesRead == framePayload.length + PAYLOAD_OFFSET) { + int frameEndMarker = readFromBuffer(); + if (frameEndMarker != AMQP.FRAME_END) { + throw new MalformedFrameException("Bad frame end marker: " + frameEndMarker); + } + bytesRead = 0; + return new Frame(frameType, frameChannel, framePayload); + } else { + throw new IllegalStateException("Number of read bytes incorrect: " + bytesRead); + } + bytesRead++; + } + return null; + } + + private int read() throws IOException { + return NioHelper.read(channel, buffer); + } + + private int readFromBuffer() { + return buffer.get() & 0xff; + } + + private boolean readFromNetworkIfNecessary() throws IOException { + if(!buffer.hasRemaining()) { + buffer.clear(); + int read = read(); + buffer.flip(); + if (read > 0) { + return true; + } else { + return false; + } + } else { + return true; + } + } +} diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java b/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java index 900b72b3fb..c58a1737df 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java @@ -149,22 +149,29 @@ public void run() { state.prepareForReadSequence(); while (state.continueReading()) { - Frame frame = Frame.readFrom(inputStream); + final Frame frame; + if (state.frameBuilder == null) { + frame = Frame.readFrom(inputStream); + } else { + frame = state.frameBuilder.readFrame(); + } - try { - boolean noProblem = state.getConnection().handleReadFrame(frame); - if (noProblem && (!state.getConnection().isRunning() || state.getConnection().hasBrokerInitiatedShutdown())) { - // looks like the frame was Close-Ok or Close - dispatchShutdownToConnection(state); + if (frame != null) { + try { + boolean noProblem = state.getConnection().handleReadFrame(frame); + if (noProblem && (!state.getConnection().isRunning() || state.getConnection().hasBrokerInitiatedShutdown())) { + // looks like the frame was Close-Ok or Close + dispatchShutdownToConnection(state); + key.cancel(); + break; + } + } catch (Throwable ex) { + // problem during frame processing, tell connection, and + // we can stop for this channel + handleIoError(state, ex); key.cancel(); break; } - } catch (Throwable ex) { - // problem during frame processing, tell connection, and - // we can stop for this channel - handleIoError(state, ex); - key.cancel(); - break; } } diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java index 08d20e7125..5e14b7fa90 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java @@ -77,6 +77,8 @@ public class SocketChannelFrameHandlerState { final DataInputStream inputStream; + final FrameBuilder frameBuilder; + public SocketChannelFrameHandlerState(SocketChannel channel, NioLoopContext nioLoopsState, NioParams nioParams, SSLEngine sslEngine) { this.channel = channel; this.readSelectorState = nioLoopsState.readSelectorState; @@ -98,6 +100,8 @@ public SocketChannelFrameHandlerState(SocketChannel channel, NioLoopContext nioL new ByteBufferInputStream(channel, plainIn) ); + this.frameBuilder = new FrameBuilder(channel, plainIn); + } else { this.ssl = true; this.plainOut = ByteBuffer.allocate(sslEngine.getSession().getApplicationBufferSize()); @@ -111,6 +115,8 @@ public SocketChannelFrameHandlerState(SocketChannel channel, NioLoopContext nioL this.inputStream = new DataInputStream( new SslEngineByteBufferInputStream(sslEngine, plainIn, cipherIn, channel) ); + + this.frameBuilder = null; } } diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index 1162bfa357..59962ddfc3 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -16,6 +16,7 @@ package com.rabbitmq.client.test; +import com.rabbitmq.client.impl.nio.FrameBuilder; import com.rabbitmq.utility.IntAllocatorTests; import org.junit.runner.RunWith; import org.junit.runners.Suite; @@ -49,7 +50,8 @@ ConnectionFactoryTest.class, RecoveryAwareAMQConnectionFactoryTest.class, RpcTest.class, - RecoveryDelayHandlerTest.class + RecoveryDelayHandlerTest.class, + FrameBuilder.class }) public class ClientTests { diff --git a/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java b/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java new file mode 100644 index 0000000000..d6c3d9c81b --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java @@ -0,0 +1,109 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.test; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.impl.Frame; +import com.rabbitmq.client.impl.nio.FrameBuilder; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.ReadableByteChannel; + +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.Assert.assertThat; + +/** + * + */ +@RunWith(MockitoJUnitRunner.class) +public class FrameBuilderTest { + + @Mock + ReadableByteChannel channel; + + ByteBuffer buffer; + + FrameBuilder builder; + + @Test + public void buildFrameInOneGo() throws IOException { + buffer = ByteBuffer.wrap(new byte[]{1, 0, 0, 0, 0, 0, 3, 1, 2, 3, end()}); + builder = new FrameBuilder(channel, buffer); + Frame frame = builder.readFrame(); + assertThat(frame, notNullValue()); + assertThat(frame.type, is(1)); + assertThat(frame.channel, is(0)); + assertThat(frame.getPayload().length, is(3)); + } + + @Test + public void buildFramesInOneGo() throws IOException { + byte[] frameContent = new byte[]{1, 0, 0, 0, 0, 0, 3, 1, 2, 3, end()}; + int nbFrames = 13; + byte[] frames = new byte[frameContent.length * nbFrames]; + for(int i = 0; i < nbFrames; i++) { + for (int j = 0; j < frameContent.length; j++) { + frames[i * frameContent.length + j] = frameContent[j]; + } + } + buffer = ByteBuffer.wrap(frames); + builder = new FrameBuilder(channel, buffer); + int frameCount = 0; + Frame frame; + while ((frame = builder.readFrame()) != null) { + assertThat(frame, notNullValue()); + assertThat(frame.type, is(1)); + assertThat(frame.channel, is(0)); + assertThat(frame.getPayload().length, is(3)); + frameCount++; + } + assertThat(frameCount, is(nbFrames)); + } + + @Test + public void buildFrameInSeveralCalls() throws IOException { + buffer = ByteBuffer.wrap(new byte[]{1, 0, 0, 0, 0, 0, 3, 1, 2}); + builder = new FrameBuilder(channel, buffer); + Frame frame = builder.readFrame(); + assertThat(frame, nullValue()); + + buffer.clear(); + buffer.put(b(3)).put(end()); + buffer.flip(); + + frame = builder.readFrame(); + assertThat(frame, notNullValue()); + assertThat(frame.type, is(1)); + assertThat(frame.channel, is(0)); + assertThat(frame.getPayload().length, is(3)); + } + + byte b(int b) { + return (byte) b; + } + + byte end() { + return (byte) AMQP.FRAME_END; + } + +} From 72e792ac0b50991832ce73e3ee20d3832bc723a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 10 Nov 2017 17:38:15 +0100 Subject: [PATCH 0613/2114] Use correct test name in client test suite References #319 --- src/test/java/com/rabbitmq/client/test/ClientTests.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index 59962ddfc3..c749a47e5d 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -16,7 +16,6 @@ package com.rabbitmq.client.test; -import com.rabbitmq.client.impl.nio.FrameBuilder; import com.rabbitmq.utility.IntAllocatorTests; import org.junit.runner.RunWith; import org.junit.runners.Suite; @@ -51,7 +50,7 @@ RecoveryAwareAMQConnectionFactoryTest.class, RpcTest.class, RecoveryDelayHandlerTest.class, - FrameBuilder.class + FrameBuilderTest.class }) public class ClientTests { From 099cb3d86cf6cd25b48c400d5fb5ed29b0039ee0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 20 Nov 2017 11:51:22 +0100 Subject: [PATCH 0614/2114] Add frame builder that supports TLS in NIO mode References #319 --- .../impl/nio/ByteBufferInputStream.java | 57 ------------ .../client/impl/nio/FrameBuilder.java | 47 +++++++--- .../rabbitmq/client/impl/nio/NioHelper.java | 25 ------ .../com/rabbitmq/client/impl/nio/NioLoop.java | 10 +-- .../rabbitmq/client/impl/nio/NioParams.java | 2 +- .../nio/SocketChannelFrameHandlerState.java | 16 ++-- .../nio/SslEngineByteBufferInputStream.java | 86 ------------------- .../impl/nio/SslEngineFrameBuilder.java | 77 +++++++++++++++++ .../client/impl/nio/SslEngineHelper.java | 20 ++++- 9 files changed, 139 insertions(+), 201 deletions(-) delete mode 100644 src/main/java/com/rabbitmq/client/impl/nio/ByteBufferInputStream.java delete mode 100644 src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferInputStream.java create mode 100644 src/main/java/com/rabbitmq/client/impl/nio/SslEngineFrameBuilder.java diff --git a/src/main/java/com/rabbitmq/client/impl/nio/ByteBufferInputStream.java b/src/main/java/com/rabbitmq/client/impl/nio/ByteBufferInputStream.java deleted file mode 100644 index f0121f00ba..0000000000 --- a/src/main/java/com/rabbitmq/client/impl/nio/ByteBufferInputStream.java +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - -package com.rabbitmq.client.impl.nio; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.ByteBuffer; -import java.nio.channels.ReadableByteChannel; - -/** - * Bridge between the byte buffer and stream worlds. - */ -public class ByteBufferInputStream extends InputStream { - - private final ReadableByteChannel channel; - - private final ByteBuffer buffer; - - public ByteBufferInputStream(ReadableByteChannel channel, ByteBuffer buffer) { - this.channel = channel; - this.buffer = buffer; - } - - @Override - public int read() throws IOException { - readFromNetworkIfNecessary(channel, buffer); - return readFromBuffer(buffer); - } - - private int readFromBuffer(ByteBuffer buffer) { - return buffer.get() & 0xff; - } - - private static void readFromNetworkIfNecessary(ReadableByteChannel channel, ByteBuffer buffer) throws IOException { - if(!buffer.hasRemaining()) { - buffer.clear(); - int read = NioHelper.read(channel, buffer); - if(read <= 0) { - NioHelper.retryRead(channel, buffer); - } - buffer.flip(); - } - } -} diff --git a/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java b/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java index a4cc776a0f..cbb4647ab1 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java @@ -24,15 +24,23 @@ import java.nio.channels.ReadableByteChannel; /** - * + * Class to create AMQP frames from a {@link ReadableByteChannel}. + * Supports partial frames: a frame can be read in several attempts + * from the {@link NioLoop}. This can happen when the channel won't + * read any more bytes in the middle of a frame building. The state + * of the outstanding frame is saved up, and the builder will + * start where it left off when the {@link NioLoop} comes back to + * this connection. + * This class is not thread safe. + * @since 4.4.0 */ public class FrameBuilder { private static final int PAYLOAD_OFFSET = 1 /* type */ + 2 /* channel */ + 4 /* payload size */; - private final ReadableByteChannel channel; + protected final ReadableByteChannel channel; - private final ByteBuffer buffer; + protected final ByteBuffer applicationBuffer; private int frameType; private int frameChannel; @@ -40,15 +48,26 @@ public class FrameBuilder { private int bytesRead = 0; + // to store the bytes of the outstanding data + // 3 byte-long because the longest we read is an unsigned int + // (not need to store the latest byte) private final int [] frameBuffer = new int[3]; public FrameBuilder(ReadableByteChannel channel, ByteBuffer buffer) { this.channel = channel; - this.buffer = buffer; + this.applicationBuffer = buffer; } + /** + * Read a frame from the network. + * This method returns null f a frame could not have been fully built from + * the network. The client must then retry later (typically + * when the channel notifies it has something to read). + * @return a complete frame or null if a frame couldn't have been fully built + * @throws IOException + */ public Frame readFrame() throws IOException { - while(readFromNetworkIfNecessary()) { + while(somethingToRead()) { if (bytesRead == 0) { // type // FIXME check first byte isn't 'A' and thus a header indicating protocol version mismatch @@ -90,18 +109,24 @@ public Frame readFrame() throws IOException { } private int read() throws IOException { - return NioHelper.read(channel, buffer); + return NioHelper.read(channel, applicationBuffer); } private int readFromBuffer() { - return buffer.get() & 0xff; + return applicationBuffer.get() & 0xff; } - private boolean readFromNetworkIfNecessary() throws IOException { - if(!buffer.hasRemaining()) { - buffer.clear(); + /** + * Tells whether there's something to read in the application buffer or not. + * Tries to read from the network if necessary. + * @return true if there's something to read in the application buffer + * @throws IOException + */ + protected boolean somethingToRead() throws IOException { + if(!applicationBuffer.hasRemaining()) { + applicationBuffer.clear(); int read = read(); - buffer.flip(); + applicationBuffer.flip(); if (read > 0) { return true; } else { diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioHelper.java b/src/main/java/com/rabbitmq/client/impl/nio/NioHelper.java index ef073a5e6c..277025222f 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioHelper.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioHelper.java @@ -29,29 +29,4 @@ static int read(ReadableByteChannel channel, ByteBuffer buffer) throws IOExcepti return read; } - static int retryRead(ReadableByteChannel channel, ByteBuffer buffer) throws IOException { - int attempt = 0; - int read = 0; - while(attempt < 3) { - try { - Thread.sleep(100L); - } catch (InterruptedException e) { - // ignore - } - read = read(channel, buffer); - if(read > 0) { - break; - } - attempt++; - } - return read; - } - - static int readWithRetry(ReadableByteChannel channel, ByteBuffer buffer) throws IOException { - int bytesRead = NioHelper.read(channel, buffer); - if (bytesRead <= 0) { - bytesRead = NioHelper.retryRead(channel, buffer); - } - return bytesRead; - } } diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java b/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java index c58a1737df..a8d6a49a0f 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java @@ -20,7 +20,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.nio.ByteBuffer; @@ -144,17 +143,10 @@ public void run() { continue; } - DataInputStream inputStream = state.inputStream; - state.prepareForReadSequence(); while (state.continueReading()) { - final Frame frame; - if (state.frameBuilder == null) { - frame = Frame.readFrom(inputStream); - } else { - frame = state.frameBuilder.readFrame(); - } + final Frame frame = state.frameBuilder.readFrame(); if (frame != null) { try { diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java b/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java index 1d14bc3e88..0dbe627808 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java @@ -26,7 +26,7 @@ /** * Parameters used to configure the NIO mode of a {@link com.rabbitmq.client.ConnectionFactory}. - * + * @since 4.0.0 */ public class NioParams { diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java index 5e14b7fa90..ead31cfa6d 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java @@ -21,7 +21,6 @@ import org.slf4j.LoggerFactory; import javax.net.ssl.SSLEngine; -import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.nio.ByteBuffer; @@ -75,8 +74,6 @@ public class SocketChannelFrameHandlerState { final DataOutputStream outputStream; - final DataInputStream inputStream; - final FrameBuilder frameBuilder; public SocketChannelFrameHandlerState(SocketChannel channel, NioLoopContext nioLoopsState, NioParams nioParams, SSLEngine sslEngine) { @@ -96,9 +93,6 @@ public SocketChannelFrameHandlerState(SocketChannel channel, NioLoopContext nioL this.outputStream = new DataOutputStream( new ByteBufferOutputStream(channel, plainOut) ); - this.inputStream = new DataInputStream( - new ByteBufferInputStream(channel, plainIn) - ); this.frameBuilder = new FrameBuilder(channel, plainIn); @@ -112,11 +106,7 @@ public SocketChannelFrameHandlerState(SocketChannel channel, NioLoopContext nioL this.outputStream = new DataOutputStream( new SslEngineByteBufferOutputStream(sslEngine, plainOut, cipherOut, channel) ); - this.inputStream = new DataInputStream( - new SslEngineByteBufferInputStream(sslEngine, plainIn, cipherIn, channel) - ); - - this.frameBuilder = null; + this.frameBuilder = new SslEngineFrameBuilder(sslEngine, plainIn, cipherIn, channel); } } @@ -202,6 +192,10 @@ boolean continueReading() throws IOException { if (!plainIn.hasRemaining() && !cipherIn.hasRemaining()) { // need to try to read something cipherIn.clear(); + + // FIXME this logic may be simplified: + // flipping cipherIn and return cipherIn.hasRemaining should be enough + int bytesRead = NioHelper.read(channel, cipherIn); if (bytesRead <= 0) { return false; diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferInputStream.java b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferInputStream.java deleted file mode 100644 index debefa6d63..0000000000 --- a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferInputStream.java +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - -package com.rabbitmq.client.impl.nio; - -import javax.net.ssl.SSLEngine; -import javax.net.ssl.SSLEngineResult; -import javax.net.ssl.SSLException; -import java.io.IOException; -import java.io.InputStream; -import java.nio.ByteBuffer; -import java.nio.channels.ReadableByteChannel; - -/** - * Bridge between the byte buffer and stream worlds. - */ -public class SslEngineByteBufferInputStream extends InputStream { - - private final SSLEngine sslEngine; - - private final ByteBuffer plainIn, cipherIn; - - private final ReadableByteChannel channel; - - public SslEngineByteBufferInputStream(SSLEngine sslEngine, ByteBuffer plainIn, ByteBuffer cipherIn, ReadableByteChannel channel) { - this.sslEngine = sslEngine; - this.plainIn = plainIn; - this.cipherIn = cipherIn; - this.channel = channel; - } - - @Override - public int read() throws IOException { - - if (plainIn.hasRemaining()) { - return readFromBuffer(plainIn); - } - - plainIn.clear(); - - while (true) { - - SSLEngineResult result = sslEngine.unwrap(cipherIn, plainIn); - - switch (result.getStatus()) { - case OK: - plainIn.flip(); - if (plainIn.hasRemaining()) { - return readFromBuffer(plainIn); - } - plainIn.clear(); - break; - case BUFFER_OVERFLOW: - throw new SSLException("buffer overflow in read"); - case BUFFER_UNDERFLOW: - cipherIn.compact(); - int bytesRead = NioHelper.readWithRetry(channel, cipherIn); - if (bytesRead <= 0) { - throw new IllegalStateException("Should be reading something from the network"); - } - cipherIn.flip(); - break; - case CLOSED: - throw new SSLException("closed in read"); - default: - throw new IllegalStateException("Invalid SSL status: " + result.getStatus()); - } - } - } - - private int readFromBuffer(ByteBuffer buffer) { - return buffer.get() & 0xff; - } -} diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineFrameBuilder.java b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineFrameBuilder.java new file mode 100644 index 0000000000..056470aae4 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineFrameBuilder.java @@ -0,0 +1,77 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl.nio; + +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLEngineResult; +import javax.net.ssl.SSLException; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.ReadableByteChannel; + +/** + * Sub-class of {@link FrameBuilder} that unwraps crypted data from the network. + * @since 4.4.0 + */ +public class SslEngineFrameBuilder extends FrameBuilder { + + private final SSLEngine sslEngine; + + private final ByteBuffer cipherBuffer; + + public SslEngineFrameBuilder(SSLEngine sslEngine, ByteBuffer plainIn, ByteBuffer cipherIn, ReadableByteChannel channel) { + super(channel, plainIn); + this.sslEngine = sslEngine; + this.cipherBuffer = cipherIn; + } + + @Override + protected boolean somethingToRead() throws IOException { + if (applicationBuffer.hasRemaining()) { + return true; + } else { + applicationBuffer.clear(); + + while (true) { + SSLEngineResult result = sslEngine.unwrap(cipherBuffer, applicationBuffer); + switch (result.getStatus()) { + case OK: + applicationBuffer.flip(); + if (applicationBuffer.hasRemaining()) { + return true; + } + applicationBuffer.clear(); + break; + case BUFFER_OVERFLOW: + throw new SSLException("buffer overflow in read"); + case BUFFER_UNDERFLOW: + cipherBuffer.compact(); + int read = NioHelper.read(channel, cipherBuffer); + if (read == 0) { + return false; + } + cipherBuffer.flip(); + break; + case CLOSED: + throw new SSLException("closed in read"); + default: + throw new IllegalStateException("Invalid SSL status: " + result.getStatus()); + } + } + } + } + +} diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java index a5cc25c330..7bfaa26d1e 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java @@ -89,7 +89,7 @@ private static SSLEngineResult.HandshakeStatus unwrap(ByteBuffer cipherIn, ByteB cipherIn.compact(); int read = NioHelper.read(channel, cipherIn); if(read <= 0) { - NioHelper.retryRead(channel, cipherIn); + retryRead(channel, cipherIn); } cipherIn.flip(); break; @@ -106,6 +106,24 @@ private static SSLEngineResult.HandshakeStatus unwrap(ByteBuffer cipherIn, ByteB return handshakeStatus; } + private static int retryRead(ReadableByteChannel channel, ByteBuffer buffer) throws IOException { + int attempt = 0; + int read = 0; + while(attempt < 3) { + try { + Thread.sleep(100L); + } catch (InterruptedException e) { + // ignore + } + read = NioHelper.read(channel, buffer); + if(read > 0) { + break; + } + attempt++; + } + return read; + } + private static SSLEngineResult.HandshakeStatus wrap(ByteBuffer plainOut, ByteBuffer cipherOut, WritableByteChannel channel, SSLEngine sslEngine) throws IOException { SSLEngineResult.HandshakeStatus handshakeStatus = sslEngine.getHandshakeStatus(); From 4e282fe02ff0b33cf1cf8094c41804cbfc576a0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 20 Nov 2017 13:33:27 +0100 Subject: [PATCH 0615/2114] Remove ByteBufferInputStream tests Class does not longer exist. References #319 --- .../com/rabbitmq/client/test/FrameTest.java | 76 ++----------------- 1 file changed, 7 insertions(+), 69 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/FrameTest.java b/src/test/java/com/rabbitmq/client/test/FrameTest.java index 933917fef3..a154a6cfe3 100644 --- a/src/test/java/com/rabbitmq/client/test/FrameTest.java +++ b/src/test/java/com/rabbitmq/client/test/FrameTest.java @@ -2,91 +2,29 @@ import com.rabbitmq.client.AMQP; import com.rabbitmq.client.impl.Frame; -import com.rabbitmq.client.impl.nio.ByteBufferInputStream; import com.rabbitmq.client.impl.nio.ByteBufferOutputStream; import org.junit.Test; import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.ReadableByteChannel; import java.nio.channels.WritableByteChannel; -import java.util.*; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Random; -import static org.hamcrest.Matchers.*; -import static org.junit.Assert.*; +import static org.hamcrest.Matchers.equalTo; +import static org.junit.Assert.assertThat; /** * */ public class FrameTest { - @Test public void readFrames() throws IOException { - Random random = new Random(); - int nbOfFrames = 100; - AccumulatorReadableByteChannel channel = new AccumulatorReadableByteChannel(); - - for(int i = 0; i < nbOfFrames; i++) { - byte[] payload = new byte[random.nextInt(2000) + 1]; - Frame frame = new Frame(AMQP.FRAME_METHOD, 1, payload); - channel.add(frame); - } - - ByteBuffer buffer = ByteBuffer.allocate(8192); - - DataInputStream inputStream = new DataInputStream( - new ByteBufferInputStream(channel, buffer) - ); - - int nbReadFrames = 0; - channel.read(buffer); - buffer.flip(); - while(buffer.hasRemaining()) { - Frame.readFrom(inputStream); - nbReadFrames++; - if(!buffer.hasRemaining()) { - buffer.clear(); - channel.read(buffer); - buffer.flip(); - } - - } - assertThat(nbReadFrames, equalTo(nbOfFrames)); - } - - @Test public void readLargeFrame() throws IOException { - AccumulatorReadableByteChannel channel = new AccumulatorReadableByteChannel(); - - int [] framesSize = new int [] {100, 75, 20000, 150}; - for (int frameSize : framesSize) { - Frame frame = new Frame(AMQP.FRAME_METHOD, 1, new byte[frameSize]); - channel.add(frame); - } - - ByteBuffer buffer = ByteBuffer.allocate(8192); - - DataInputStream inputStream = new DataInputStream( - new ByteBufferInputStream(channel, buffer) - ); - - int nbReadFrames = 0; - channel.read(buffer); - buffer.flip(); - while(buffer.hasRemaining()) { - Frame.readFrom(inputStream); - nbReadFrames++; - if(!buffer.hasRemaining()) { - buffer.clear(); - channel.read(buffer); - buffer.flip(); - } - - } - assertThat(nbReadFrames, equalTo(framesSize.length)); - } - @Test public void writeFrames() throws IOException { List frames = new ArrayList(); From 9a236277bdff9e5054bf053fa74be06e5949b1e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 20 Nov 2017 14:58:33 +0100 Subject: [PATCH 0616/2114] Handle protocol version mismatch in frame builder References #319 --- .../client/impl/nio/FrameBuilder.java | 104 ++++++++++++++---- .../client/impl/nio/HeaderWriteRequest.java | 4 + .../nio/SocketChannelFrameHandlerState.java | 8 +- .../client/test/FrameBuilderTest.java | 43 +++++++- 4 files changed, 128 insertions(+), 31 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java b/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java index cbb4647ab1..56bbf28669 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java @@ -19,6 +19,7 @@ import com.rabbitmq.client.MalformedFrameException; import com.rabbitmq.client.impl.Frame; +import java.io.DataInputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.ReadableByteChannel; @@ -32,6 +33,7 @@ * start where it left off when the {@link NioLoop} comes back to * this connection. * This class is not thread safe. + * * @since 4.4.0 */ public class FrameBuilder { @@ -41,17 +43,14 @@ public class FrameBuilder { protected final ReadableByteChannel channel; protected final ByteBuffer applicationBuffer; - - private int frameType; - private int frameChannel; - private byte [] framePayload; - - private int bytesRead = 0; - // to store the bytes of the outstanding data // 3 byte-long because the longest we read is an unsigned int // (not need to store the latest byte) - private final int [] frameBuffer = new int[3]; + private final int[] frameBuffer = new int[3]; + private int frameType; + private int frameChannel; + private byte[] framePayload; + private int bytesRead = 0; public FrameBuilder(ReadableByteChannel channel, ByteBuffer buffer) { this.channel = channel; @@ -63,15 +62,19 @@ public FrameBuilder(ReadableByteChannel channel, ByteBuffer buffer) { * This method returns null f a frame could not have been fully built from * the network. The client must then retry later (typically * when the channel notifies it has something to read). + * * @return a complete frame or null if a frame couldn't have been fully built * @throws IOException + * @see Frame#readFrom(DataInputStream) */ public Frame readFrame() throws IOException { - while(somethingToRead()) { + while (somethingToRead()) { if (bytesRead == 0) { // type - // FIXME check first byte isn't 'A' and thus a header indicating protocol version mismatch frameType = readFromBuffer(); + if (frameType == 'A') { + handleProtocolVersionMismatch(); + } } else if (bytesRead == 1) { // channel 1/2 frameBuffer[0] = readFromBuffer(); @@ -108,24 +111,17 @@ public Frame readFrame() throws IOException { return null; } - private int read() throws IOException { - return NioHelper.read(channel, applicationBuffer); - } - - private int readFromBuffer() { - return applicationBuffer.get() & 0xff; - } - /** * Tells whether there's something to read in the application buffer or not. * Tries to read from the network if necessary. + * * @return true if there's something to read in the application buffer * @throws IOException */ protected boolean somethingToRead() throws IOException { - if(!applicationBuffer.hasRemaining()) { + if (!applicationBuffer.hasRemaining()) { applicationBuffer.clear(); - int read = read(); + int read = NioHelper.read(channel, applicationBuffer); applicationBuffer.flip(); if (read > 0) { return true; @@ -136,4 +132,72 @@ protected boolean somethingToRead() throws IOException { return true; } } + + private int readFromBuffer() { + return applicationBuffer.get() & 0xff; + } + + /** + * Handle a protocol version mismatch. + * @return + * @throws IOException + * @see Frame#protocolVersionMismatch(DataInputStream) + */ + private void handleProtocolVersionMismatch() throws IOException { + // Probably an AMQP.... header indicating a version mismatch + // Otherwise meaningless, so try to read the version, + // and throw an exception, whether we read the version + // okay or not. + // Try to read everything from the network, this header + // is small and should never require several network reads. + byte[] expectedBytes = new byte[] { 'M', 'Q', 'P' }; + int expectedBytesCount = 0; + while (somethingToRead() && expectedBytesCount < 3) { + // We expect the letters M, Q, P in that order: generate an informative error if they're not found + int nextByte = readFromBuffer(); + if (nextByte != expectedBytes[expectedBytesCount]) { + throw new MalformedFrameException("Invalid AMQP protocol header from server: expected character " + + expectedBytes[expectedBytesCount] + ", got " + nextByte); + } + expectedBytesCount++; + } + + if (expectedBytesCount != 3) { + throw new MalformedFrameException("Invalid AMQP protocol header from server: read only " + + (expectedBytesCount + 1) + " byte(s) instead of 4"); + } + + int[] signature = new int[4]; + + for (int i = 0; i < 4; i++) { + if (somethingToRead()) { + signature[i] = readFromBuffer(); + } else { + throw new MalformedFrameException("Invalid AMQP protocol header from server"); + } + } + + MalformedFrameException x; + + if (signature[0] == 1 && + signature[1] == 1 && + signature[2] == 8 && + signature[3] == 0) { + x = new MalformedFrameException("AMQP protocol version mismatch; we are version " + + AMQP.PROTOCOL.MAJOR + "-" + AMQP.PROTOCOL.MINOR + "-" + AMQP.PROTOCOL.REVISION + + ", server is 0-8"); + } else { + String sig = ""; + for (int i = 0; i < 4; i++) { + if (i != 0) + sig += ","; + sig += signature[i]; + } + + x = new MalformedFrameException("AMQP protocol version mismatch; we are version " + + AMQP.PROTOCOL.MAJOR + "-" + AMQP.PROTOCOL.MINOR + "-" + AMQP.PROTOCOL.REVISION + + ", server sent signature " + sig); + } + throw x; + } } diff --git a/src/main/java/com/rabbitmq/client/impl/nio/HeaderWriteRequest.java b/src/main/java/com/rabbitmq/client/impl/nio/HeaderWriteRequest.java index 66ebc299eb..96e35849e4 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/HeaderWriteRequest.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/HeaderWriteRequest.java @@ -25,6 +25,10 @@ */ public class HeaderWriteRequest implements WriteRequest { + public static final WriteRequest SINGLETON = new HeaderWriteRequest(); + + private HeaderWriteRequest() { } + @Override public void handle(DataOutputStream outputStream) throws IOException { outputStream.write("AMQP".getBytes("US-ASCII")); diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java index ead31cfa6d..2fa7f8187b 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java @@ -120,7 +120,7 @@ public Queue getWriteQueue() { } public void sendHeader() throws IOException { - sendWriteRequest(new HeaderWriteRequest()); + sendWriteRequest(HeaderWriteRequest.SINGLETON); } public void write(Frame frame) throws IOException { @@ -192,12 +192,8 @@ boolean continueReading() throws IOException { if (!plainIn.hasRemaining() && !cipherIn.hasRemaining()) { // need to try to read something cipherIn.clear(); - - // FIXME this logic may be simplified: - // flipping cipherIn and return cipherIn.hasRemaining should be enough - int bytesRead = NioHelper.read(channel, cipherIn); - if (bytesRead <= 0) { + if (bytesRead == 0) { return false; } else { cipherIn.flip(); diff --git a/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java b/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java index d6c3d9c81b..ce71a779a7 100644 --- a/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java +++ b/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java @@ -16,6 +16,7 @@ package com.rabbitmq.client.test; import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.MalformedFrameException; import com.rabbitmq.client.impl.Frame; import com.rabbitmq.client.impl.nio.FrameBuilder; import org.junit.Test; @@ -31,6 +32,7 @@ import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.nullValue; import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; /** * @@ -47,7 +49,7 @@ public class FrameBuilderTest { @Test public void buildFrameInOneGo() throws IOException { - buffer = ByteBuffer.wrap(new byte[]{1, 0, 0, 0, 0, 0, 3, 1, 2, 3, end()}); + buffer = ByteBuffer.wrap(new byte[] { 1, 0, 0, 0, 0, 0, 3, 1, 2, 3, end() }); builder = new FrameBuilder(channel, buffer); Frame frame = builder.readFrame(); assertThat(frame, notNullValue()); @@ -58,10 +60,10 @@ public void buildFrameInOneGo() throws IOException { @Test public void buildFramesInOneGo() throws IOException { - byte[] frameContent = new byte[]{1, 0, 0, 0, 0, 0, 3, 1, 2, 3, end()}; + byte[] frameContent = new byte[] { 1, 0, 0, 0, 0, 0, 3, 1, 2, 3, end() }; int nbFrames = 13; byte[] frames = new byte[frameContent.length * nbFrames]; - for(int i = 0; i < nbFrames; i++) { + for (int i = 0; i < nbFrames; i++) { for (int j = 0; j < frameContent.length; j++) { frames[i * frameContent.length + j] = frameContent[j]; } @@ -82,7 +84,7 @@ public void buildFramesInOneGo() throws IOException { @Test public void buildFrameInSeveralCalls() throws IOException { - buffer = ByteBuffer.wrap(new byte[]{1, 0, 0, 0, 0, 0, 3, 1, 2}); + buffer = ByteBuffer.wrap(new byte[] { 1, 0, 0, 0, 0, 0, 3, 1, 2 }); builder = new FrameBuilder(channel, buffer); Frame frame = builder.readFrame(); assertThat(frame, nullValue()); @@ -98,6 +100,38 @@ public void buildFrameInSeveralCalls() throws IOException { assertThat(frame.getPayload().length, is(3)); } + @Test + public void protocolMismatchHeader() throws IOException { + ByteBuffer[] buffers = new ByteBuffer[] { + ByteBuffer.wrap(new byte[] { 'A' }), + ByteBuffer.wrap(new byte[] { 'A', 'M', 'Q' }), + ByteBuffer.wrap(new byte[] { 'A', 'N', 'Q', 'P' }), + ByteBuffer.wrap(new byte[] { 'A', 'M', 'Q', 'P' }), + ByteBuffer.wrap(new byte[] { 'A', 'M', 'Q', 'P', 1, 1, 8 }), + ByteBuffer.wrap(new byte[] { 'A', 'M', 'Q', 'P', 1, 1, 8, 0 }), + ByteBuffer.wrap(new byte[] { 'A', 'M', 'Q', 'P', 1, 1, 9, 1 }) + }; + String[] messages = new String[] { + "Invalid AMQP protocol header from server: read only 1 byte(s) instead of 4", + "Invalid AMQP protocol header from server: read only 3 byte(s) instead of 4", + "Invalid AMQP protocol header from server: expected character 77, got 78", + "Invalid AMQP protocol header from server", + "Invalid AMQP protocol header from server", + "AMQP protocol version mismatch; we are version 0-9-1, server is 0-8", + "AMQP protocol version mismatch; we are version 0-9-1, server sent signature 1,1,9,1" + }; + + for (int i = 0; i < buffers.length; i++) { + builder = new FrameBuilder(channel, buffers[i]); + try { + builder.readFrame(); + fail("protocol header not correct, exception should have been thrown"); + } catch (MalformedFrameException e) { + assertThat(e.getMessage(), is(messages[i])); + } + } + } + byte b(int b) { return (byte) b; } @@ -105,5 +139,4 @@ byte b(int b) { byte end() { return (byte) AMQP.FRAME_END; } - } From 5ff6ad478e6363fc45c4c8eefc08e9cc5f242d9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 24 Nov 2017 15:41:17 +0100 Subject: [PATCH 0617/2114] Check active RPC property against null References #290 --- src/main/java/com/rabbitmq/client/impl/AMQChannel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java index af06638630..5216771efb 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java @@ -165,7 +165,7 @@ public void handleCompleteInboundCommand(AMQCommand command) throws IOException if (_checkRpcResponseType) { synchronized (_channelMutex) { // check if this reply command is intended for the current waiting request before calling nextOutstandingRpc() - if (!_activeRpc.canHandleReply(command)) { + if (_activeRpc != null && !_activeRpc.canHandleReply(command)) { // this reply command is not intended for the current waiting request // most likely a previous request timed out and this command is the reply for that. // Throw this reply command away so we don't stop the current request from waiting for its reply From d0e9e242eb48f72a4736afe60f4cfb03b4a426fd Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Fri, 24 Nov 2017 16:25:42 +0000 Subject: [PATCH 0618/2114] [maven-release-plugin] prepare release v4.4.0.RC1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 302c1638c9..d0dfe7ddf3 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.4.0-SNAPSHOT + 4.4.0.RC1 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v4.4.0.RC1 From e307444ac6fc1aaa002413db1b7bd37804e7c6f9 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Fri, 24 Nov 2017 16:25:49 +0000 Subject: [PATCH 0619/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index d0dfe7ddf3..302c1638c9 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.4.0.RC1 + 4.4.0-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v4.4.0.RC1 + HEAD From ded8e386d4a591fc634bf3b76e3598d37b07a697 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 28 Nov 2017 11:19:20 +0100 Subject: [PATCH 0620/2114] Set release version to 4.4.0.RC2 --- release-versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-versions.txt b/release-versions.txt index 303387c85d..9f79f639d0 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="4.4.0.RC1" +RELEASE_VERSION="4.4.0.RC2" DEVELOPMENT_VERSION="4.4.0-SNAPSHOT" From ee1e897f73ba146892966090ab2b4b9372bded1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 29 Nov 2017 15:27:24 +0100 Subject: [PATCH 0621/2114] Use Package#getImplementationVersion to get version The previous method (property file in the JAR) can cause problem in classpath-sensitive environments like OSGi. Fixes #334 --- .../rabbitmq/client/impl/ClientVersion.java | 27 ++----------------- 1 file changed, 2 insertions(+), 25 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/ClientVersion.java b/src/main/java/com/rabbitmq/client/impl/ClientVersion.java index 18aece8eaf..a71022fc7f 100644 --- a/src/main/java/com/rabbitmq/client/impl/ClientVersion.java +++ b/src/main/java/com/rabbitmq/client/impl/ClientVersion.java @@ -15,35 +15,12 @@ package com.rabbitmq.client.impl; -import java.io.IOException; -import java.io.InputStream; -import java.util.Properties; - /** * Publicly available Client Version information */ public class ClientVersion { /** Full version string */ - private static final Properties version; - public static final String VERSION; - - static { - version = new Properties(); - InputStream inputStream = ClientVersion.class.getClassLoader() - .getResourceAsStream("version.properties"); - try { - version.load(inputStream); - } catch (IOException e) { - } finally { - try { - if(inputStream != null) { - inputStream.close(); - } - } catch (IOException e) { - } - } + public static final String VERSION = ClientVersion.class.getPackage().getImplementationVersion() == null ? + "0.0.0" : ClientVersion.class.getPackage().getImplementationVersion(); - VERSION = version.getProperty("com.rabbitmq.client.version", - ClientVersion.class.getPackage().getImplementationVersion()); - } } From 455987dc60b69f8e231c3e0e21eaa1f9994f5435 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 29 Nov 2017 15:37:08 +0100 Subject: [PATCH 0622/2114] Get rid of a few unchecked warnings References #324 --- src/main/java/com/rabbitmq/client/ConnectionFactory.java | 1 + .../com/rabbitmq/client/ConnectionFactoryConfigurator.java | 3 +++ 2 files changed, 4 insertions(+) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index f9b5ec7d89..d07b2a4a4a 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -1108,6 +1108,7 @@ public ConnectionFactory load(Properties properties) { * @since 4.4.0 * @see ConnectionFactoryConfigurator */ + @SuppressWarnings("unchecked") public ConnectionFactory load(Properties properties, String prefix) { ConnectionFactoryConfigurator.load(this, (Map) properties, prefix); return this; diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java b/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java index 518fa7e6d4..73ef9da038 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java @@ -77,6 +77,7 @@ public class ConnectionFactoryConfigurator { public static final String NIO_WRITE_ENQUEUING_TIMEOUT_IN_MS = "nio.write.enqueuing.timeout.in.ms"; public static final String NIO_WRITE_QUEUE_CAPACITY = "nio.write.queue.capacity"; + @SuppressWarnings("unchecked") public static void load(ConnectionFactory cf, String propertyFileLocation, String prefix) throws IOException { if (propertyFileLocation == null || propertyFileLocation.isEmpty()) { throw new IllegalArgumentException("Property file argument cannot be null or empty"); @@ -238,10 +239,12 @@ public static void load(ConnectionFactory connectionFactory, String propertyFile load(connectionFactory, propertyFileLocation, DEFAULT_PREFIX); } + @SuppressWarnings("unchecked") public static void load(ConnectionFactory connectionFactory, Properties properties) { load(connectionFactory, (Map) properties, DEFAULT_PREFIX); } + @SuppressWarnings("unchecked") public static void load(ConnectionFactory connectionFactory, Properties properties, String prefix) { load(connectionFactory, (Map) properties, prefix); } From bd1d73fc2e60ef78532504a17a05085ee421def0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 11 Dec 2017 11:24:53 +0100 Subject: [PATCH 0623/2114] Load client version in a more reliable way The code tries to read the version from a property file (with a unique name) and falls back to Package#getImplementationVersion in case of error. If Package#getImplementationVersion fails too, a default hardcoded value is returned. Warns are logged for every failure. This should make the retrieval more reliable in different contexts (e.g. uber-JARs, OSGi). References #334 --- .../rabbitmq/client/impl/ClientVersion.java | 55 ++++++++++++++++++- .../resources/rabbitmq-ampq-client.properties | 1 + src/main/resources/version.properties | 2 + 3 files changed, 55 insertions(+), 3 deletions(-) create mode 100644 src/main/resources/rabbitmq-ampq-client.properties diff --git a/src/main/java/com/rabbitmq/client/impl/ClientVersion.java b/src/main/java/com/rabbitmq/client/impl/ClientVersion.java index a71022fc7f..15c6dc6e0a 100644 --- a/src/main/java/com/rabbitmq/client/impl/ClientVersion.java +++ b/src/main/java/com/rabbitmq/client/impl/ClientVersion.java @@ -15,12 +15,61 @@ package com.rabbitmq.client.impl; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.InputStream; +import java.util.Properties; + /** * Publicly available Client Version information */ public class ClientVersion { - /** Full version string */ - public static final String VERSION = ClientVersion.class.getPackage().getImplementationVersion() == null ? - "0.0.0" : ClientVersion.class.getPackage().getImplementationVersion(); + private static final Logger LOGGER = LoggerFactory.getLogger(ClientVersion.class); + + public static final String VERSION; + + static { + String version; + try { + version = getVersionFromPropertyFile(); + } catch (Exception e1) { + LOGGER.warn("Couldn't get version from property file", e1); + try { + version = getVersionFromPackage(); + } catch (Exception e2) { + LOGGER.warn("Couldn't get version with Package#getImplementationVersion", e1); + version = getDefaultVersion(); + } + } + VERSION = version; + } + + private static final String getVersionFromPropertyFile() throws Exception { + InputStream inputStream = ClientVersion.class.getClassLoader().getResourceAsStream("rabbitmq-amqp-client.properties"); + Properties version = new Properties(); + try { + version.load(inputStream); + } finally { + if (inputStream != null) { + inputStream.close(); + } + } + if (version.getProperty("com.rabbitmq.client.version") == null) { + throw new IllegalStateException("Coulnd't find version property in property file"); + } + return version.getProperty("com.rabbitmq.client.version"); + } + + private static final String getVersionFromPackage() { + if (ClientVersion.class.getPackage().getImplementationVersion() == null) { + throw new IllegalStateException("Couldn't get version with Package#getImplementationVersion"); + } + return ClientVersion.class.getPackage().getImplementationVersion(); + } + + private static final String getDefaultVersion() { + return "0.0.0"; + } } diff --git a/src/main/resources/rabbitmq-ampq-client.properties b/src/main/resources/rabbitmq-ampq-client.properties new file mode 100644 index 0000000000..3562d483ec --- /dev/null +++ b/src/main/resources/rabbitmq-ampq-client.properties @@ -0,0 +1 @@ +com.rabbitmq.client.version = ${project.version} diff --git a/src/main/resources/version.properties b/src/main/resources/version.properties index 3562d483ec..a13aa0c291 100644 --- a/src/main/resources/version.properties +++ b/src/main/resources/version.properties @@ -1 +1,3 @@ +# here for backward compatibility +# use rabbitmq-amqp-client.properties to add or read properties com.rabbitmq.client.version = ${project.version} From 67e2207b332b04d1abe560f987f10e7ac190129c Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Mon, 11 Dec 2017 12:47:59 +0000 Subject: [PATCH 0624/2114] [maven-release-plugin] prepare release v4.4.0.RC2 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 302c1638c9..91e891acde 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.4.0-SNAPSHOT + 4.4.0.RC2 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v4.4.0.RC2 From cbbefac8cc1b657daf6c4c503a755dbd67e36248 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Mon, 11 Dec 2017 12:48:06 +0000 Subject: [PATCH 0625/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 91e891acde..302c1638c9 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.4.0.RC2 + 4.4.0-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v4.4.0.RC2 + HEAD From 47b787b765990244544285562d6115fd710ee8eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 11 Dec 2017 14:00:20 +0100 Subject: [PATCH 0626/2114] Set release version to 4.4.0.RC3 --- release-versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-versions.txt b/release-versions.txt index 9f79f639d0..d05bb3ad05 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="4.4.0.RC2" +RELEASE_VERSION="4.4.0.RC3" DEVELOPMENT_VERSION="4.4.0-SNAPSHOT" From c3ba84950470945887d57a9d73be0bc398d0f64a Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Mon, 11 Dec 2017 13:04:42 +0000 Subject: [PATCH 0627/2114] [maven-release-plugin] prepare release v5.1.0.RC1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 070cd51d78..232817cf27 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.0.1-SNAPSHOT + 5.1.0.RC1 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v5.1.0.RC1 From 57ac78abe3876bc7de79d6f87316e0dd4b3583d0 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Mon, 11 Dec 2017 13:04:46 +0000 Subject: [PATCH 0628/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 232817cf27..d3cd36297a 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.1.0.RC1 + 5.1.0-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v5.1.0.RC1 + HEAD From b297656de4b4ddd3878a2e704a04d46e5d8590c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 11 Dec 2017 14:08:22 +0100 Subject: [PATCH 0629/2114] Set release version to 5.1.0.RC2 --- release-versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-versions.txt b/release-versions.txt index 0f1562a3b3..7ac8b39fcd 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="5.1.0.RC1" +RELEASE_VERSION="5.1.0.RC2" DEVELOPMENT_VERSION="5.1.0-SNAPSHOT" From b492090b6f4ff603370033043956ee41908a9380 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 18 Dec 2017 10:15:19 +0100 Subject: [PATCH 0630/2114] Set release version to 4.4.0 --- release-versions.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release-versions.txt b/release-versions.txt index d05bb3ad05..a05be5e556 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="4.4.0.RC3" -DEVELOPMENT_VERSION="4.4.0-SNAPSHOT" +RELEASE_VERSION="4.4.0" +DEVELOPMENT_VERSION="4.4.1-SNAPSHOT" From fd5c95e2b386f11727c94419c94f66e92607a1d3 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Mon, 18 Dec 2017 09:18:35 +0000 Subject: [PATCH 0631/2114] [maven-release-plugin] prepare release v4.4.0 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 302c1638c9..642e8b05df 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.4.0-SNAPSHOT + 4.4.0 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v4.4.0 From e1a3bf1a7132354d1245bca5cefaca7e8b804a9a Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Mon, 18 Dec 2017 09:18:39 +0000 Subject: [PATCH 0632/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 642e8b05df..e70f8ceabf 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.4.0 + 4.4.1-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v4.4.0 + HEAD From e45f01e2f965ce7e9c6d89732a9b1d4e950875ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 18 Dec 2017 10:29:51 +0100 Subject: [PATCH 0633/2114] Set release version to 4.4.1.RC1 --- release-versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-versions.txt b/release-versions.txt index a05be5e556..a120872f56 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="4.4.0" +RELEASE_VERSION="4.4.1.RC1" DEVELOPMENT_VERSION="4.4.1-SNAPSHOT" From 51cea74ff1392af2ef370e63b02c49f5e0b30f33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 18 Dec 2017 10:32:26 +0100 Subject: [PATCH 0634/2114] Set POM version to 4.5.0-SNAPSHOT --- pom.xml | 2 +- release-versions.txt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index e70f8ceabf..55136c5c76 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.4.1-SNAPSHOT + 4.5.0-SNAPSHOT jar RabbitMQ Java Client diff --git a/release-versions.txt b/release-versions.txt index a120872f56..bcd262b846 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="4.4.1.RC1" -DEVELOPMENT_VERSION="4.4.1-SNAPSHOT" +RELEASE_VERSION="4.5.0.RC1" +DEVELOPMENT_VERSION="4.5.0-SNAPSHOT" From 78151ec37254f1782f08491a0ac46278bc827667 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 18 Dec 2017 10:34:42 +0100 Subject: [PATCH 0635/2114] Set release version to 5.1.0 --- release-versions.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release-versions.txt b/release-versions.txt index 7ac8b39fcd..8c67d9b529 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="5.1.0.RC2" -DEVELOPMENT_VERSION="5.1.0-SNAPSHOT" +RELEASE_VERSION="5.1.0" +DEVELOPMENT_VERSION="5.1.1-SNAPSHOT" From 512b142be4af0b712676f6239ca157dceeea0955 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Mon, 18 Dec 2017 09:36:49 +0000 Subject: [PATCH 0636/2114] [maven-release-plugin] prepare release v5.1.0 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index d3cd36297a..bd4faf5738 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.1.0-SNAPSHOT + 5.1.0 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v5.1.0 From 2de284c5b85de4be6152606c0c06177138d1b41c Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Mon, 18 Dec 2017 09:36:53 +0000 Subject: [PATCH 0637/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index bd4faf5738..b4ee40ade8 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.1.0 + 5.1.1-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v5.1.0 + HEAD From 7537a339285220b1b773d132cd37d62da82782ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 18 Dec 2017 10:46:12 +0100 Subject: [PATCH 0638/2114] Set release version to 5.1.1.RC1 --- release-versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-versions.txt b/release-versions.txt index 8c67d9b529..cd694a0d71 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="5.1.0" +RELEASE_VERSION="5.1.1.RC1" DEVELOPMENT_VERSION="5.1.1-SNAPSHOT" From 8f77c7a05385405bd77103953fa1c6da33ffe214 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 18 Dec 2017 10:48:02 +0100 Subject: [PATCH 0639/2114] Set POM version to 5.2.0-SNAPSHOT --- pom.xml | 2 +- release-versions.txt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index b4ee40ade8..06dd6f6607 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.1.1-SNAPSHOT + 5.2.0-SNAPSHOT jar RabbitMQ Java Client diff --git a/release-versions.txt b/release-versions.txt index cd694a0d71..ddb1fe40cf 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="5.1.1.RC1" -DEVELOPMENT_VERSION="5.1.1-SNAPSHOT" +RELEASE_VERSION="5.2.0.RC1" +DEVELOPMENT_VERSION="5.2.0-SNAPSHOT" From 3e45465608a3d8924aeb3a35cc6e50952d64b231 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 18 Dec 2017 14:27:44 +0100 Subject: [PATCH 0640/2114] Set version to 5.1.0 in readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 59acd15be9..09d128559d 100644 --- a/README.md +++ b/README.md @@ -23,14 +23,14 @@ These versions can still be used with RabbitMQ server `3.x`. com.rabbitmq amqp-client - 5.0.0 + 5.1.0 ``` ### Gradle ``` groovy -compile 'com.rabbitmq:amqp-client:5.0.0' +compile 'com.rabbitmq:amqp-client:5.1.0' ``` #### 3.6.x Series From 434fc4c21b56481794a304e8509f02637dc2cb83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 19 Dec 2017 09:45:57 +0100 Subject: [PATCH 0641/2114] Fix client version property file name Fixes #335 --- ...erties => rabbitmq-amqp-client.properties} | 0 .../com/rabbitmq/client/test/ClientTests.java | 3 +- .../client/test/ClientVersionTest.java | 32 +++++++++++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) rename src/main/resources/{rabbitmq-ampq-client.properties => rabbitmq-amqp-client.properties} (100%) create mode 100644 src/test/java/com/rabbitmq/client/test/ClientVersionTest.java diff --git a/src/main/resources/rabbitmq-ampq-client.properties b/src/main/resources/rabbitmq-amqp-client.properties similarity index 100% rename from src/main/resources/rabbitmq-ampq-client.properties rename to src/main/resources/rabbitmq-amqp-client.properties diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index 8d409a066e..e2f60c4470 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -51,7 +51,8 @@ RpcTest.class, RecoveryDelayHandlerTest.class, FrameBuilderTest.class, - PropertyFileInitialisationTest.class + PropertyFileInitialisationTest.class, + ClientVersionTest.class }) public class ClientTests { diff --git a/src/test/java/com/rabbitmq/client/test/ClientVersionTest.java b/src/test/java/com/rabbitmq/client/test/ClientVersionTest.java new file mode 100644 index 0000000000..33b15a956b --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/ClientVersionTest.java @@ -0,0 +1,32 @@ +// Copyright (c) 2017-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.test; + +import com.rabbitmq.client.impl.ClientVersion; +import org.junit.Test; + +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.notNullValue; +import static org.junit.Assert.assertThat; + +public class ClientVersionTest { + + @Test + public void clientVersion() { + assertThat(ClientVersion.VERSION, notNullValue()); + assertThat(ClientVersion.VERSION, not("0.0.0")); + } +} From 7bd0b73e3c9a7d9839f3d2246d4f6fbf04cfa0b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 19 Dec 2017 09:49:05 +0100 Subject: [PATCH 0642/2114] Set release version to 4.4.1 --- release-versions.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release-versions.txt b/release-versions.txt index a120872f56..c438f5ce45 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="4.4.1.RC1" -DEVELOPMENT_VERSION="4.4.1-SNAPSHOT" +RELEASE_VERSION="4.4.1" +DEVELOPMENT_VERSION="4.4.2-SNAPSHOT" From 1961244f20351856c84939df226d61454a08f4a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 19 Dec 2017 10:08:25 +0100 Subject: [PATCH 0643/2114] Fix server version parsing in test --- .../com/rabbitmq/client/test/ClientTests.java | 3 +- .../com/rabbitmq/client/test/TestUtils.java | 4 ++ .../rabbitmq/client/test/TestUtilsTest.java | 46 +++++++++++++++++++ 3 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 src/test/java/com/rabbitmq/client/test/TestUtilsTest.java diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index dabe16a918..c66a337aae 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -55,7 +55,8 @@ RecoveryDelayHandlerTest.class, FrameBuilderTest.class, PropertyFileInitialisationTest.class, - ClientVersionTest.class + ClientVersionTest.class, + TestUtilsTest.class }) public class ClientTests { diff --git a/src/test/java/com/rabbitmq/client/test/TestUtils.java b/src/test/java/com/rabbitmq/client/test/TestUtils.java index bdabb3f941..62db841bf5 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtils.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtils.java @@ -54,6 +54,10 @@ public static boolean isVersion37orLater(Connection connection) { if (currentVersion.contains("~")) { currentVersion = currentVersion.substring(0, currentVersion.indexOf("~")); } + // alpha (snapshot) versions: 3.7.1-alpha.40 + if (currentVersion.contains("-")) { + currentVersion = currentVersion.substring(0, currentVersion.indexOf("-")); + } return "0.0.0".equals(currentVersion) || versionCompare(currentVersion, "3.7.0") >= 0; } diff --git a/src/test/java/com/rabbitmq/client/test/TestUtilsTest.java b/src/test/java/com/rabbitmq/client/test/TestUtilsTest.java new file mode 100644 index 0000000000..379196a6d0 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/TestUtilsTest.java @@ -0,0 +1,46 @@ +// Copyright (c) 2017-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.test; + +import com.rabbitmq.client.Connection; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class TestUtilsTest { + + @Test + public void isVersion37orLater() { + Map serverProperties = new HashMap<>(); + Connection connection = mock(Connection.class); + when(connection.getServerProperties()).thenReturn(serverProperties); + + serverProperties.put("version", "3.7.0+rc.1.4.gedc5d96"); + assertThat(TestUtils.isVersion37orLater(connection), is(true)); + + serverProperties.put("version", "3.7.0~alpha.449-1"); + assertThat(TestUtils.isVersion37orLater(connection), is(true)); + + serverProperties.put("version", "3.7.1-alpha.40"); + assertThat(TestUtils.isVersion37orLater(connection), is(true)); + } +} From 4c2ba23699138fa981406206c8e17f3d23d22efa Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Tue, 19 Dec 2017 09:11:12 +0000 Subject: [PATCH 0644/2114] [maven-release-plugin] prepare release v4.4.1.RC1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index e70f8ceabf..ce8165f075 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.4.1-SNAPSHOT + 4.4.1.RC1 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v4.4.1.RC1 From b2b1570071d6f6294deb570e80d4a10f3c1e4456 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Tue, 19 Dec 2017 09:11:16 +0000 Subject: [PATCH 0645/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index ce8165f075..e70f8ceabf 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.4.1.RC1 + 4.4.1-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v4.4.1.RC1 + HEAD From 5425d0e836fcc113891fd516a38b684df2321e46 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Tue, 19 Dec 2017 09:15:03 +0000 Subject: [PATCH 0646/2114] [maven-release-plugin] prepare release v4.4.1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index e70f8ceabf..f8e8462df8 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.4.1-SNAPSHOT + 4.4.1 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v4.4.1 From 7ed511d5518d4ed8946ea0fd3918377e329e337c Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Tue, 19 Dec 2017 09:15:10 +0000 Subject: [PATCH 0647/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index f8e8462df8..18fa6d391f 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.4.1 + 4.4.2-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v4.4.1 + HEAD From d645b843a28cc590687978273f4861b042c22481 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 19 Dec 2017 10:38:03 +0100 Subject: [PATCH 0648/2114] Set release version to 4.4.2.RC1 --- release-versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-versions.txt b/release-versions.txt index c438f5ce45..0537e09316 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="4.4.1" +RELEASE_VERSION="4.4.2.RC1" DEVELOPMENT_VERSION="4.4.2-SNAPSHOT" From c2b64a23a0dd9fabfce37e808ce2b98be7d47ce5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 19 Dec 2017 10:40:17 +0100 Subject: [PATCH 0649/2114] Set release version to 5.1.1 --- release-versions.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release-versions.txt b/release-versions.txt index cd694a0d71..f4bb9ef46a 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="5.1.1.RC1" -DEVELOPMENT_VERSION="5.1.1-SNAPSHOT" +RELEASE_VERSION="5.1.1" +DEVELOPMENT_VERSION="5.1.2-SNAPSHOT" From b3561f5722c49bd86879e6d702c79aa8867cde28 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Tue, 19 Dec 2017 10:12:22 +0000 Subject: [PATCH 0650/2114] [maven-release-plugin] prepare release v5.1.1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index b4ee40ade8..30f91bfa36 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.1.1-SNAPSHOT + 5.1.1 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v5.1.1 From 57b9cf2cc6594868f9d8b1466a4d20ba7c9b2d7c Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Tue, 19 Dec 2017 10:12:27 +0000 Subject: [PATCH 0651/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 30f91bfa36..23d276bf01 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.1.1 + 5.1.2-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v5.1.1 + HEAD From ac5f967f52b14483cba6012913c4537e7763c322 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 19 Dec 2017 13:43:20 +0100 Subject: [PATCH 0652/2114] Set release version to 5.1.2.RC1 --- release-versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-versions.txt b/release-versions.txt index f4bb9ef46a..525bf8df02 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="5.1.1" +RELEASE_VERSION="5.1.2.RC1" DEVELOPMENT_VERSION="5.1.2-SNAPSHOT" From d1004aa6310a30e0a2deeaa079e2226f2b15696f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 19 Dec 2017 13:52:46 +0100 Subject: [PATCH 0653/2114] Set version to 5.1.1 in readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 09d128559d..d8db9131c1 100644 --- a/README.md +++ b/README.md @@ -23,14 +23,14 @@ These versions can still be used with RabbitMQ server `3.x`. com.rabbitmq amqp-client - 5.1.0 + 5.1.1 ``` ### Gradle ``` groovy -compile 'com.rabbitmq:amqp-client:5.1.0' +compile 'com.rabbitmq:amqp-client:5.1.1' ``` #### 3.6.x Series From 80d38c5685a06fac2ad19938dbea6a2cee231f66 Mon Sep 17 00:00:00 2001 From: Andreas Presthammer Date: Thu, 4 Jan 2018 08:47:38 +0100 Subject: [PATCH 0654/2114] Add RpcClient doCall/responseCall/primitiveCall overloads which include timeout There will be use cases where a single shared timeout specified in the constructor of the RpcClient will not match up with the expected timeout for different rpc calls made using the rpc client. It's then convenient to be able to specifiy the timeout value on a per method call basis. Otherwise the user of RpcClient would have to create multiple instances of RpcClient, incurring the startup cost and having redundant consumers of the response queue. --- .../java/com/rabbitmq/client/RpcClient.java | 33 +++++++++++++++++-- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/RpcClient.java b/src/main/java/com/rabbitmq/client/RpcClient.java index 61d881f60f..928d819585 100644 --- a/src/main/java/com/rabbitmq/client/RpcClient.java +++ b/src/main/java/com/rabbitmq/client/RpcClient.java @@ -209,6 +209,11 @@ public void publish(AMQP.BasicProperties props, byte[] message) } public Response doCall(AMQP.BasicProperties props, byte[] message) + throws IOException, TimeoutException { + return doCall(props, message, _timeout); + } + + public Response doCall(AMQP.BasicProperties props, byte[] message, int timeout) throws IOException, ShutdownSignalException, TimeoutException { checkConsumer(); BlockingCell k = new BlockingCell(); @@ -220,7 +225,7 @@ public Response doCall(AMQP.BasicProperties props, byte[] message) _continuationMap.put(replyId, k); } publish(props, message); - Object reply = k.uninterruptibleGet(_timeout); + Object reply = k.uninterruptibleGet(timeout); if (reply instanceof ShutdownSignalException) { ShutdownSignalException sig = (ShutdownSignalException) reply; ShutdownSignalException wrapper = @@ -238,7 +243,13 @@ public Response doCall(AMQP.BasicProperties props, byte[] message) public byte[] primitiveCall(AMQP.BasicProperties props, byte[] message) throws IOException, ShutdownSignalException, TimeoutException { - return doCall(props, message).getBody(); + return primitiveCall(props, message, _timeout); + } + + public byte[] primitiveCall(AMQP.BasicProperties props, byte[] message, int timeout) + throws IOException, ShutdownSignalException, TimeoutException + { + return doCall(props, message, timeout).getBody(); } /** @@ -266,7 +277,23 @@ public byte[] primitiveCall(byte[] message) * @throws TimeoutException if a response is not received within the configured timeout */ public Response responseCall(byte[] message) throws IOException, ShutdownSignalException, TimeoutException { - return doCall(null, message); + return responseCall(message, _timeout); + } + + /** + * Perform a simple byte-array-based RPC roundtrip + * + * Useful if you need to get at more than just the body of the message + * + * @param message the byte array request message to send + * @param timeout milliseconds before timing out on wait for response + * @return The response object is an envelope that contains all of the data provided to the `handleDelivery` consumer + * @throws ShutdownSignalException if the connection dies during our wait + * @throws IOException if an error is encountered + * @throws TimeoutException if a response is not received within the configured timeout + */ + public Response responseCall(byte[] message, int timeout) throws IOException, ShutdownSignalException, TimeoutException { + return doCall(null, message, timeout); } /** From aa736b4b60f3fe74bc5d15cd677811af77aad30e Mon Sep 17 00:00:00 2001 From: Taras Sotnikov Date: Fri, 5 Jan 2018 11:00:10 +0100 Subject: [PATCH 0655/2114] Fix recovery channel metrics that are sent with realTag without offset --- src/main/java/com/rabbitmq/client/impl/ChannelN.java | 2 +- .../client/impl/recovery/RecoveryAwareChannelN.java | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java index cd73ce5f0c..82f0f51b25 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelN.java @@ -90,7 +90,7 @@ public class ChannelN extends AMQChannel implements com.rabbitmq.client.Channel /** Whether any nacks have been received since the last waitForConfirms(). */ private volatile boolean onlyAcksReceived = true; - private final MetricsCollector metricsCollector; + protected final MetricsCollector metricsCollector; /** * Construct a new channel on the given connection with the given diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java index 353578da6a..4f29f04690 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java @@ -22,6 +22,7 @@ import com.rabbitmq.client.impl.AMQImpl; import com.rabbitmq.client.impl.ChannelN; import com.rabbitmq.client.impl.ConsumerWorkService; +import com.rabbitmq.client.impl.AMQImpl.Basic; import java.io.IOException; @@ -86,7 +87,8 @@ public void basicAck(long deliveryTag, boolean multiple) throws IOException { long realTag = deliveryTag - activeDeliveryTagOffset; // 0 tag means ack all if (realTag >= 0) { - super.basicAck(realTag, multiple); + transmit(new Basic.Ack(deliveryTag, multiple)); + metricsCollector.basicAck(this, deliveryTag, multiple); } } @@ -96,7 +98,8 @@ public void basicNack(long deliveryTag, boolean multiple, boolean requeue) throw long realTag = deliveryTag - activeDeliveryTagOffset; // 0 tag means nack all if (realTag >= 0) { - super.basicNack(realTag, multiple, requeue); + transmit(new Basic.Nack(realTag, multiple, requeue)); + metricsCollector.basicNack(this, deliveryTag); } } @@ -104,7 +107,8 @@ public void basicNack(long deliveryTag, boolean multiple, boolean requeue) throw public void basicReject(long deliveryTag, boolean requeue) throws IOException { long realTag = deliveryTag - activeDeliveryTagOffset; if (realTag > 0) { - super.basicReject(realTag, requeue); + transmit(new Basic.Reject(realTag, requeue)); + metricsCollector.basicReject(this, deliveryTag); } } From 2f826242411a22981bef39d0ecb2908eb5d43471 Mon Sep 17 00:00:00 2001 From: Taras Sotnikov Date: Fri, 5 Jan 2018 12:07:15 +0100 Subject: [PATCH 0656/2114] Fix wrong tag --- .../rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java index 4f29f04690..933877dc4d 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java @@ -87,7 +87,7 @@ public void basicAck(long deliveryTag, boolean multiple) throws IOException { long realTag = deliveryTag - activeDeliveryTagOffset; // 0 tag means ack all if (realTag >= 0) { - transmit(new Basic.Ack(deliveryTag, multiple)); + transmit(new Basic.Ack(realTag, multiple)); metricsCollector.basicAck(this, deliveryTag, multiple); } } From 7495e1082026c166485c2e47cc737899663ad406 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 9 Jan 2018 11:13:20 +0100 Subject: [PATCH 0657/2114] Add test for ack/nack/reject metrics with offset References #339 --- .../client/impl/AbstractMetricsCollector.java | 35 ++++---------- .../client/test/functional/Metrics.java | 47 ++++++++++++++++++- 2 files changed, 54 insertions(+), 28 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java index 2b2bb1e35c..71983fb457 100644 --- a/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java @@ -38,21 +38,11 @@ public abstract class AbstractMetricsCollector implements MetricsCollector { private static final Logger LOGGER = LoggerFactory.getLogger(AbstractMetricsCollector.class); - private final ConcurrentMap connectionState = new ConcurrentHashMap(); + private final ConcurrentMap connectionState = new ConcurrentHashMap<>(); - private final Runnable markAcknowledgedMessageAction = new Runnable() { - @Override - public void run() { - markAcknowledgedMessage(); - } - }; + private final Runnable markAcknowledgedMessageAction = () -> markAcknowledgedMessage(); - private final Runnable markRejectedMessageAction = new Runnable() { - @Override - public void run() { - markRejectedMessage(); - } - }; + private final Runnable markRejectedMessageAction = () -> markRejectedMessage(); @Override public void newConnection(final Connection connection) { @@ -62,12 +52,7 @@ public void newConnection(final Connection connection) { } incrementConnectionCount(connection); connectionState.put(connection.getId(), new ConnectionState(connection)); - connection.addShutdownListener(new ShutdownListener() { - @Override - public void shutdownCompleted(ShutdownSignalException cause) { - closeConnection(connection); - } - }); + connection.addShutdownListener(cause -> closeConnection(connection)); } catch(Exception e) { LOGGER.info("Error while computing metrics in newConnection: " + e.getMessage()); } @@ -89,12 +74,7 @@ public void closeConnection(Connection connection) { public void newChannel(final Channel channel) { try { incrementChannelCount(channel); - channel.addShutdownListener(new ShutdownListener() { - @Override - public void shutdownCompleted(ShutdownSignalException cause) { - closeChannel(channel); - } - }); + channel.addShutdownListener(cause -> closeChannel(channel)); connectionState(channel.getConnection()).channelState.put(channel.getChannelNumber(), new ChannelState(channel)); } catch(Exception e) { LOGGER.info("Error while computing metrics in newChannel: " + e.getMessage()); @@ -231,8 +211,9 @@ private void updateChannelStateAfterAckReject(Channel channel, long deliveryTag, } } } else { - channelState.unackedMessageDeliveryTags.remove(deliveryTag); - action.run(); + if (channelState.unackedMessageDeliveryTags.remove(deliveryTag)) { + action.run(); + } } } finally { channelState.lock.unlock(); diff --git a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java index 0a1304ae0f..70400627f8 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java @@ -46,6 +46,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicInteger; import static org.awaitility.Awaitility.waitAtMost; import static org.hamcrest.Matchers.equalTo; @@ -70,7 +71,7 @@ public static Object[] data() { static final String QUEUE = "metrics.queue"; @Override - protected void createResources() throws IOException, TimeoutException { + protected void createResources() throws IOException { channel.queueDeclare(QUEUE, true, false, false, null); } @@ -397,7 +398,51 @@ protected void releaseResources() throws IOException { } finally { safeClose(connection); } + } + + @Test public void checkAcksWithAutomaticRecovery() throws Exception { + ConnectionFactory connectionFactory = createConnectionFactory(); + connectionFactory.setNetworkRecoveryInterval(2000); + connectionFactory.setAutomaticRecoveryEnabled(true); + StandardMetricsCollector metrics = new StandardMetricsCollector(); + connectionFactory.setMetricsCollector(metrics); + + Connection connection = null; + try { + connection = connectionFactory.newConnection(); + + Channel channel1 = connection.createChannel(); + AtomicInteger ackedMessages = new AtomicInteger(0); + + channel1.basicConsume(QUEUE, false, (consumerTag, message) -> { + try { + channel1.basicAck(message.getEnvelope().getDeliveryTag(), false); + ackedMessages.incrementAndGet(); + } catch (Exception e) { } + }, tag -> {}); + Channel channel2 = connection.createChannel(); + channel2.confirmSelect(); + int nbMessages = 10; + for (int i = 0; i < nbMessages; i++) { + sendMessage(channel2); + } + channel2.waitForConfirms(1000); + + closeAndWaitForRecovery((AutorecoveringConnection) connection); + + for (int i = 0; i < nbMessages; i++) { + sendMessage(channel2); + } + + waitAtMost(timeout()).until(() -> ackedMessages.get(), equalTo(nbMessages * 2)); + + assertThat(metrics.getConsumedMessages().getCount(), is((long) (nbMessages * 2))); + assertThat(metrics.getAcknowledgedMessages().getCount(), is((long) (nbMessages * 2))); + + } finally { + safeClose(connection); + } } private static ConnectionFactory createConnectionFactory() { From 54d98cc9236762a2151c9f8480c5a431c5772253 Mon Sep 17 00:00:00 2001 From: Taras Sotnikov Date: Fri, 5 Jan 2018 11:00:10 +0100 Subject: [PATCH 0658/2114] Fix recovery channel metrics that are sent with realTag without offset --- src/main/java/com/rabbitmq/client/impl/ChannelN.java | 2 +- .../client/impl/recovery/RecoveryAwareChannelN.java | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java index 6cf5a25897..e690464d16 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelN.java @@ -93,7 +93,7 @@ public class ChannelN extends AMQChannel implements com.rabbitmq.client.Channel /** Whether any nacks have been received since the last waitForConfirms(). */ private volatile boolean onlyAcksReceived = true; - private final MetricsCollector metricsCollector; + protected final MetricsCollector metricsCollector; /** * Construct a new channel on the given connection with the given diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java index 353578da6a..4f29f04690 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java @@ -22,6 +22,7 @@ import com.rabbitmq.client.impl.AMQImpl; import com.rabbitmq.client.impl.ChannelN; import com.rabbitmq.client.impl.ConsumerWorkService; +import com.rabbitmq.client.impl.AMQImpl.Basic; import java.io.IOException; @@ -86,7 +87,8 @@ public void basicAck(long deliveryTag, boolean multiple) throws IOException { long realTag = deliveryTag - activeDeliveryTagOffset; // 0 tag means ack all if (realTag >= 0) { - super.basicAck(realTag, multiple); + transmit(new Basic.Ack(deliveryTag, multiple)); + metricsCollector.basicAck(this, deliveryTag, multiple); } } @@ -96,7 +98,8 @@ public void basicNack(long deliveryTag, boolean multiple, boolean requeue) throw long realTag = deliveryTag - activeDeliveryTagOffset; // 0 tag means nack all if (realTag >= 0) { - super.basicNack(realTag, multiple, requeue); + transmit(new Basic.Nack(realTag, multiple, requeue)); + metricsCollector.basicNack(this, deliveryTag); } } @@ -104,7 +107,8 @@ public void basicNack(long deliveryTag, boolean multiple, boolean requeue) throw public void basicReject(long deliveryTag, boolean requeue) throws IOException { long realTag = deliveryTag - activeDeliveryTagOffset; if (realTag > 0) { - super.basicReject(realTag, requeue); + transmit(new Basic.Reject(realTag, requeue)); + metricsCollector.basicReject(this, deliveryTag); } } From d4b4e95d91b5e1be45dbce10ca0a449208e00c07 Mon Sep 17 00:00:00 2001 From: Taras Sotnikov Date: Fri, 5 Jan 2018 12:07:15 +0100 Subject: [PATCH 0659/2114] Fix wrong tag --- .../rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java index 4f29f04690..933877dc4d 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java @@ -87,7 +87,7 @@ public void basicAck(long deliveryTag, boolean multiple) throws IOException { long realTag = deliveryTag - activeDeliveryTagOffset; // 0 tag means ack all if (realTag >= 0) { - transmit(new Basic.Ack(deliveryTag, multiple)); + transmit(new Basic.Ack(realTag, multiple)); metricsCollector.basicAck(this, deliveryTag, multiple); } } From 54cd4f074d1d657063f0e1e8dff167e3b646a289 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 9 Jan 2018 15:03:37 +0100 Subject: [PATCH 0660/2114] Add test for ack/nack/reject metrics with offset References #339 --- .../client/impl/AbstractMetricsCollector.java | 5 +- .../client/test/functional/Metrics.java | 52 +++++++++++++++++++ 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java index 2b2bb1e35c..4c84d95c7b 100644 --- a/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java @@ -231,8 +231,9 @@ private void updateChannelStateAfterAckReject(Channel channel, long deliveryTag, } } } else { - channelState.unackedMessageDeliveryTags.remove(deliveryTag); - action.run(); + if (channelState.unackedMessageDeliveryTags.remove(deliveryTag)) { + action.run(); + } } } finally { channelState.lock.unlock(); diff --git a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java index 25889bdb47..9b36b5e885 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java @@ -31,6 +31,7 @@ import java.util.List; import java.util.Random; import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; import static org.awaitility.Awaitility.*; import static org.hamcrest.Matchers.*; @@ -426,6 +427,57 @@ private void errorInChannel(ConnectionFactory connectionFactory) throws IOExcept } + @Test public void checkAcksWithAutomaticRecovery() throws Exception { + ConnectionFactory connectionFactory = createConnectionFactory(); + connectionFactory.setNetworkRecoveryInterval(2000); + connectionFactory.setAutomaticRecoveryEnabled(true); + StandardMetricsCollector metrics = new StandardMetricsCollector(); + connectionFactory.setMetricsCollector(metrics); + + Connection connection = null; + try { + connection = connectionFactory.newConnection(); + + final Channel channel1 = connection.createChannel(); + final AtomicInteger ackedMessages = new AtomicInteger(0); + + channel1.basicConsume(QUEUE, false, new DefaultConsumer(channel1) { + @Override + public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { + channel1.basicAck(envelope.getDeliveryTag(), false); + ackedMessages.incrementAndGet(); + } + }); + + Channel channel2 = connection.createChannel(); + channel2.confirmSelect(); + int nbMessages = 10; + for (int i = 0; i < nbMessages; i++) { + sendMessage(channel2); + } + channel2.waitForConfirms(1000); + + closeAndWaitForRecovery((AutorecoveringConnection) connection); + + for (int i = 0; i < nbMessages; i++) { + sendMessage(channel2); + } + + waitAtMost(timeout()).until(new Callable() { + @Override + public Integer call() { + return ackedMessages.get(); + } + }, equalTo(nbMessages * 2)); + + assertThat(metrics.getConsumedMessages().getCount(), is((long) (nbMessages * 2))); + assertThat(metrics.getAcknowledgedMessages().getCount(), is((long) (nbMessages * 2))); + + } finally { + safeClose(connection); + } + } + private ConnectionFactory createConnectionFactory() { ConnectionFactory connectionFactory = TestUtils.connectionFactory(); return connectionFactory; From c7a44f337c8d2ea3a039c73e35d9fef8dfc2f8bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 9 Jan 2018 15:07:25 +0100 Subject: [PATCH 0661/2114] Add Maven wrapper [#153555660] --- .mvn/wrapper/maven-wrapper.jar | Bin 0 -> 48336 bytes .mvn/wrapper/maven-wrapper.properties | 1 + mvnw | 227 ++++++++++++++++++++++++++ mvnw.cmd | 145 ++++++++++++++++ 4 files changed, 373 insertions(+) create mode 100755 .mvn/wrapper/maven-wrapper.jar create mode 100755 .mvn/wrapper/maven-wrapper.properties create mode 100755 mvnw create mode 100755 mvnw.cmd diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar new file mode 100755 index 0000000000000000000000000000000000000000..f775b1c04cf89b25c7814d3a8a7c810301092e57 GIT binary patch literal 48336 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 \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" + # TODO classpath? +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/mvnw.cmd b/mvnw.cmd new file mode 100755 index 0000000000..4f0b068a03 --- /dev/null +++ b/mvnw.cmd @@ -0,0 +1,145 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven2 Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" + +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% From 62ac6a321089c900a96739479da70409214d9450 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 9 Jan 2018 15:20:24 +0100 Subject: [PATCH 0662/2114] Remove duplicate test method added after merging --- .../client/test/functional/Metrics.java | 45 ------------------- 1 file changed, 45 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java index 63edd2b2f6..70400627f8 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java @@ -445,51 +445,6 @@ protected void releaseResources() throws IOException { } } - @Test public void checkAcksWithAutomaticRecovery() throws Exception { - ConnectionFactory connectionFactory = createConnectionFactory(); - connectionFactory.setNetworkRecoveryInterval(2000); - connectionFactory.setAutomaticRecoveryEnabled(true); - StandardMetricsCollector metrics = new StandardMetricsCollector(); - connectionFactory.setMetricsCollector(metrics); - - Connection connection = null; - try { - connection = connectionFactory.newConnection(); - - final Channel channel1 = connection.createChannel(); - final AtomicInteger ackedMessages = new AtomicInteger(0); - - channel1.basicConsume(QUEUE, false, (consumerTag, message) -> { - try { - channel1.basicAck(message.getEnvelope().getDeliveryTag(), false); - ackedMessages.incrementAndGet(); - } catch (Exception e) { } - }, tag -> {}); - - Channel channel2 = connection.createChannel(); - channel2.confirmSelect(); - int nbMessages = 10; - for (int i = 0; i < nbMessages; i++) { - sendMessage(channel2); - } - channel2.waitForConfirms(1000); - - closeAndWaitForRecovery((AutorecoveringConnection) connection); - - for (int i = 0; i < nbMessages; i++) { - sendMessage(channel2); - } - - waitAtMost(timeout()).until(() -> ackedMessages.get(), equalTo(nbMessages * 2)); - - assertThat(metrics.getConsumedMessages().getCount(), is((long) (nbMessages * 2))); - assertThat(metrics.getAcknowledgedMessages().getCount(), is((long) (nbMessages * 2))); - - } finally { - safeClose(connection); - } - } - private static ConnectionFactory createConnectionFactory() { ConnectionFactory connectionFactory = TestUtils.connectionFactory(); connectionFactory.setAutomaticRecoveryEnabled(false); From 250190a7b1c33f1f773cd13bf03aa8149981373b Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Tue, 9 Jan 2018 15:27:33 +0000 Subject: [PATCH 0663/2114] [maven-release-plugin] prepare release v4.4.2.RC1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 18fa6d391f..cb58231324 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.4.2-SNAPSHOT + 4.4.2.RC1 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v4.4.2.RC1 From 41fbb521a8e9869205d5ef4f99bd84fcef4e8ca9 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Tue, 9 Jan 2018 15:27:37 +0000 Subject: [PATCH 0664/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index cb58231324..18fa6d391f 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.4.2.RC1 + 4.4.2-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v4.4.2.RC1 + HEAD From 03b695f94a4f8936f74e2ef231956382c5cafa6f Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Tue, 9 Jan 2018 15:37:08 +0000 Subject: [PATCH 0665/2114] [maven-release-plugin] prepare release v5.1.2.RC1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 23d276bf01..263f87a649 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.1.2-SNAPSHOT + 5.1.2.RC1 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v5.1.2.RC1 From 32d33926ee0541bc627766d7c8c743b344f86d96 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Tue, 9 Jan 2018 15:37:12 +0000 Subject: [PATCH 0666/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 263f87a649..23d276bf01 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.1.2.RC1 + 5.1.2-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v5.1.2.RC1 + HEAD From a2f7f7ce21ed03f2985b5bcae0208aa6a4e61c6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 11 Jan 2018 10:11:34 +0100 Subject: [PATCH 0667/2114] Set release version to 4.4.2.RC2 --- release-versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-versions.txt b/release-versions.txt index 0537e09316..c0540717c5 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="4.4.2.RC1" +RELEASE_VERSION="4.4.2.RC2" DEVELOPMENT_VERSION="4.4.2-SNAPSHOT" From 84d8c034755f59a53d3cca7fbc61f30c4e51e19f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 11 Jan 2018 10:51:48 +0100 Subject: [PATCH 0668/2114] Upgrade Micrometer to 1.0.0.rc6 Fixes #340 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 18fa6d391f..8cfd8d52ef 100644 --- a/pom.xml +++ b/pom.xml @@ -56,7 +56,7 @@ 1.7.21 3.1.2 - 1.0.0-rc.2 + 1.0.0-rc.6 1.1.7 1.1 4.12 From 95c33e7590e8cce216a830e13540c567307bd80f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 11 Jan 2018 14:37:25 +0100 Subject: [PATCH 0669/2114] Support tags in Micrometer metrics collector Fixes #342 --- .../impl/MicrometerMetricsCollector.java | 50 +++++++++---- .../com/rabbitmq/client/test/ClientTests.java | 1 + .../test/MicrometerMetricsCollectorTest.java | 71 +++++++++++++++++++ 3 files changed, 108 insertions(+), 14 deletions(-) create mode 100644 src/test/java/com/rabbitmq/client/test/MicrometerMetricsCollectorTest.java diff --git a/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java index a134cb725e..180d3f8be8 100644 --- a/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java @@ -20,7 +20,11 @@ import com.rabbitmq.client.MetricsCollector; import io.micrometer.core.instrument.Counter; import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Tag; +import io.micrometer.core.instrument.Tags; +import java.util.Collection; +import java.util.Collections; import java.util.concurrent.atomic.AtomicLong; import static com.rabbitmq.client.impl.MicrometerMetricsCollector.Metrics.ACKNOWLEDGED_MESSAGES; @@ -61,10 +65,14 @@ public MicrometerMetricsCollector(MeterRegistry registry) { } public MicrometerMetricsCollector(final MeterRegistry registry, final String prefix) { + this(registry, prefix, new String[] {}); + } + + public MicrometerMetricsCollector(final MeterRegistry registry, final String prefix, final String ... tags) { this(new MetricsCreator() { @Override public Object create(Metrics metric) { - return metric.create(registry, prefix); + return metric.create(registry, prefix, tags); } }); } @@ -145,42 +153,56 @@ public Counter getRejectedMessages() { public enum Metrics { CONNECTIONS { @Override - Object create(MeterRegistry registry, String prefix) { - return registry.gauge(prefix + ".connections", new AtomicLong(0)); + Object create(MeterRegistry registry, String prefix, String... tags) { + return registry.gauge(prefix + ".connections", tags(tags), new AtomicLong(0)); } }, CHANNELS { @Override - Object create(MeterRegistry registry, String prefix) { - return registry.gauge(prefix + ".channels", new AtomicLong(0)); + Object create(MeterRegistry registry, String prefix, String... tags) { + return registry.gauge(prefix + ".channels", tags(tags), new AtomicLong(0)); } }, PUBLISHED_MESSAGES { @Override - Object create(MeterRegistry registry, String prefix) { - return registry.counter(prefix + ".published"); + Object create(MeterRegistry registry, String prefix, String... tags) { + return registry.counter(prefix + ".published", tags); } }, CONSUMED_MESSAGES { @Override - Object create(MeterRegistry registry, String prefix) { - return registry.counter(prefix + ".consumed"); + Object create(MeterRegistry registry, String prefix, String... tags) { + return registry.counter(prefix + ".consumed", tags); } }, ACKNOWLEDGED_MESSAGES { @Override - Object create(MeterRegistry registry, String prefix) { - return registry.counter(prefix + ".acknowledged"); + Object create(MeterRegistry registry, String prefix, String... tags) { + return registry.counter(prefix + ".acknowledged", tags); } }, REJECTED_MESSAGES { @Override - Object create(MeterRegistry registry, String prefix) { - return registry.counter(prefix + ".rejected"); + Object create(MeterRegistry registry, String prefix, String... tags) { + return registry.counter(prefix + ".rejected", tags); } }; - abstract Object create(MeterRegistry registry, String prefix); + Object create(MeterRegistry registry, String prefix) { + return this.create(registry, prefix, new String[] {}); + } + + abstract Object create(MeterRegistry registry, String prefix, String... tags); + + private static Iterable tags(String... tagStrings) { + Collection tags; + if (tagStrings != null && tagStrings.length > 0) { + tags = Tags.zip(tagStrings); + } else { + tags = Collections.emptyList(); + } + return tags; + } } public interface MetricsCreator { diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index e2f60c4470..08a8d02259 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -44,6 +44,7 @@ SharedThreadPoolTest.class, DnsRecordIpAddressResolverTests.class, MetricsCollectorTest.class, + MicrometerMetricsCollectorTest.class, DnsSrvRecordAddressResolverTest.class, JavaNioTest.class, ConnectionFactoryTest.class, diff --git a/src/test/java/com/rabbitmq/client/test/MicrometerMetricsCollectorTest.java b/src/test/java/com/rabbitmq/client/test/MicrometerMetricsCollectorTest.java new file mode 100644 index 0000000000..b84c956852 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/MicrometerMetricsCollectorTest.java @@ -0,0 +1,71 @@ +// Copyright (c) 2018-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.test; + +import com.rabbitmq.client.impl.MicrometerMetricsCollector; +import io.micrometer.core.instrument.Meter; +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; +import org.junit.Before; +import org.junit.Test; + +import java.util.Iterator; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; + +/** + * + */ +public class MicrometerMetricsCollectorTest { + + SimpleMeterRegistry registry; + + MicrometerMetricsCollector collector; + + @Before + public void init() { + registry = new SimpleMeterRegistry(); + } + + @Test + public void noTag() { + collector = new MicrometerMetricsCollector(registry, "rabbitmq"); + for (Meter meter : registry.getMeters()) { + assertThat(size(meter.getId().getTags()), is(0)); + } + } + + @Test + public void tags() { + collector = new MicrometerMetricsCollector(registry, "rabbitmq", "uri", "/api/users"); + for (Meter meter : registry.getMeters()) { + assertThat(size(meter.getId().getTags()), is(1)); + } + } + + @Test(expected = IllegalArgumentException.class) + public void tagsMustBeKeyValuePairs() { + collector = new MicrometerMetricsCollector(registry, "rabbitmq", "uri"); + } + + static int size(Iterable iterable) { + Iterator iterator = iterable.iterator(); + int i = 0; + for ( ; iterator.hasNext() ; ++i ) iterator.next(); + return i; + } + +} From db8cb7b6122fbfcd2b49daff78c6e1f745ed7cea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 11 Jan 2018 15:00:13 +0100 Subject: [PATCH 0670/2114] Add constructor with Iterable arg to MicrometerMetricsCollector References #342 --- .../impl/MicrometerMetricsCollector.java | 42 ++++++++++--------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java index 180d3f8be8..ab766807b7 100644 --- a/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java @@ -23,7 +23,6 @@ import io.micrometer.core.instrument.Tag; import io.micrometer.core.instrument.Tags; -import java.util.Collection; import java.util.Collections; import java.util.concurrent.atomic.AtomicLong; @@ -69,6 +68,10 @@ public MicrometerMetricsCollector(final MeterRegistry registry, final String pre } public MicrometerMetricsCollector(final MeterRegistry registry, final String prefix, final String ... tags) { + this(registry, prefix, Tags.zip(tags)); + } + + public MicrometerMetricsCollector(final MeterRegistry registry, final String prefix, final Iterable tags) { this(new MetricsCreator() { @Override public Object create(Metrics metric) { @@ -153,56 +156,55 @@ public Counter getRejectedMessages() { public enum Metrics { CONNECTIONS { @Override - Object create(MeterRegistry registry, String prefix, String... tags) { - return registry.gauge(prefix + ".connections", tags(tags), new AtomicLong(0)); + Object create(MeterRegistry registry, String prefix, Iterable tags) { + return registry.gauge(prefix + ".connections", tags, new AtomicLong(0)); } }, CHANNELS { @Override - Object create(MeterRegistry registry, String prefix, String... tags) { - return registry.gauge(prefix + ".channels", tags(tags), new AtomicLong(0)); + Object create(MeterRegistry registry, String prefix, Iterable tags) { + return registry.gauge(prefix + ".channels", tags, new AtomicLong(0)); } }, PUBLISHED_MESSAGES { @Override - Object create(MeterRegistry registry, String prefix, String... tags) { + Object create(MeterRegistry registry, String prefix, Iterable tags) { return registry.counter(prefix + ".published", tags); } }, CONSUMED_MESSAGES { @Override - Object create(MeterRegistry registry, String prefix, String... tags) { + Object create(MeterRegistry registry, String prefix, Iterable tags) { return registry.counter(prefix + ".consumed", tags); } }, ACKNOWLEDGED_MESSAGES { @Override - Object create(MeterRegistry registry, String prefix, String... tags) { + Object create(MeterRegistry registry, String prefix, Iterable tags) { return registry.counter(prefix + ".acknowledged", tags); } }, REJECTED_MESSAGES { @Override - Object create(MeterRegistry registry, String prefix, String... tags) { + Object create(MeterRegistry registry, String prefix, Iterable tags) { return registry.counter(prefix + ".rejected", tags); } }; + /** + * + * @param registry + * @param prefix + * @deprecated will be removed in 6.0.0 + * @return + */ + @Deprecated Object create(MeterRegistry registry, String prefix) { - return this.create(registry, prefix, new String[] {}); + return this.create(registry, prefix, Collections.EMPTY_LIST); } - abstract Object create(MeterRegistry registry, String prefix, String... tags); + abstract Object create(MeterRegistry registry, String prefix, Iterable tags); - private static Iterable tags(String... tagStrings) { - Collection tags; - if (tagStrings != null && tagStrings.length > 0) { - tags = Tags.zip(tagStrings); - } else { - tags = Collections.emptyList(); - } - return tags; - } } public interface MetricsCreator { From fe02a1f23facdbdb2f307cb759cbce24a062aefc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 11 Jan 2018 15:11:21 +0100 Subject: [PATCH 0671/2114] Fix unchecked warning --- .../com/rabbitmq/client/impl/MicrometerMetricsCollector.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java index ab766807b7..e418378a5b 100644 --- a/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java @@ -200,7 +200,7 @@ Object create(MeterRegistry registry, String prefix, Iterable tags) { */ @Deprecated Object create(MeterRegistry registry, String prefix) { - return this.create(registry, prefix, Collections.EMPTY_LIST); + return this.create(registry, prefix, Collections.emptyList()); } abstract Object create(MeterRegistry registry, String prefix, Iterable tags); From ab9ff600a20559d829db6bf97c8e7d69d4b08e59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 11 Jan 2018 15:29:22 +0100 Subject: [PATCH 0672/2114] Remove explicit type --- .../com/rabbitmq/client/impl/MicrometerMetricsCollector.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java index c66cebc92c..38a940e674 100644 --- a/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java @@ -196,7 +196,7 @@ Object create(MeterRegistry registry, String prefix, Iterable tags) { */ @Deprecated Object create(MeterRegistry registry, String prefix) { - return this.create(registry, prefix, Collections.emptyList()); + return this.create(registry, prefix, Collections.emptyList()); } abstract Object create(MeterRegistry registry, String prefix, Iterable tags); From cf73772ba0a883a804fc4d4bbb28b7998dd46ef1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 11 Jan 2018 15:30:25 +0100 Subject: [PATCH 0673/2114] Set release version to 5.1.2.RC2 --- release-versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-versions.txt b/release-versions.txt index 525bf8df02..196e09dc34 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="5.1.2.RC1" +RELEASE_VERSION="5.1.2.RC2" DEVELOPMENT_VERSION="5.1.2-SNAPSHOT" From 9f5b654ac4f43abbc50ac44420c726a8192bae06 Mon Sep 17 00:00:00 2001 From: Michael Dent Date: Fri, 12 Jan 2018 00:12:10 -0600 Subject: [PATCH 0674/2114] fix PRECONDITION_FAILED error after channel recovery --- .../impl/recovery/AutorecoveringChannel.java | 2 +- .../impl/recovery/RecoveryAwareChannelN.java | 14 ++++++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java index 2ce488f00d..5eea54bd2a 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java @@ -600,8 +600,8 @@ public void automaticallyRecover(AutorecoveringConnection connection, Connection final RecoveryAwareChannelN newChannel = (RecoveryAwareChannelN) connDelegate.createChannel(this.getChannelNumber()); if (newChannel == null) throw new IOException("Failed to create new channel for channel number=" + this.getChannelNumber() + " during recovery"); + newChannel.inheritOffsetFrom(defunctChannel); this.delegate = newChannel; - this.delegate.inheritOffsetFrom(defunctChannel); this.notifyRecoveryListenersStarted(); this.recoverShutdownListeners(); diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java index 933877dc4d..d910da496c 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java @@ -34,8 +34,8 @@ * @since 3.3.0 */ public class RecoveryAwareChannelN extends ChannelN { - private long maxSeenDeliveryTag = 0; - private long activeDeliveryTagOffset = 0; + private volatile long maxSeenDeliveryTag = 0; + private volatile long activeDeliveryTagOffset = 0; /** * Construct a new channel on the given connection with the given @@ -83,10 +83,9 @@ private AMQImpl.Basic.Deliver offsetDeliveryTag(AMQImpl.Basic.Deliver method) { @Override public void basicAck(long deliveryTag, boolean multiple) throws IOException { - // FIXME no check if deliveryTag = 0 (ack all) long realTag = deliveryTag - activeDeliveryTagOffset; - // 0 tag means ack all - if (realTag >= 0) { + // 0 tag means ack all when multiple is set + if (realTag > 0 || (multiple && realTag == 0)) { transmit(new Basic.Ack(realTag, multiple)); metricsCollector.basicAck(this, deliveryTag, multiple); } @@ -94,10 +93,9 @@ public void basicAck(long deliveryTag, boolean multiple) throws IOException { @Override public void basicNack(long deliveryTag, boolean multiple, boolean requeue) throws IOException { - // FIXME no check if deliveryTag = 0 (nack all) long realTag = deliveryTag - activeDeliveryTagOffset; - // 0 tag means nack all - if (realTag >= 0) { + // 0 tag means nack all when multiple is set + if (realTag > 0 || (multiple && realTag == 0)) { transmit(new Basic.Nack(realTag, multiple, requeue)); metricsCollector.basicNack(this, deliveryTag); } From cd89d2cf67a4abb9f06ce4a371f999af9ada3d64 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Fri, 12 Jan 2018 08:47:11 +0000 Subject: [PATCH 0675/2114] [maven-release-plugin] prepare release v4.4.2.RC2 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 8cfd8d52ef..3d82f977c9 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.4.2-SNAPSHOT + 4.4.2.RC2 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v4.4.2.RC2 From 225d1241ffa35ba7566c7390f8e673103331b8cd Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Fri, 12 Jan 2018 08:47:15 +0000 Subject: [PATCH 0676/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 3d82f977c9..8cfd8d52ef 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.4.2.RC2 + 4.4.2-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v4.4.2.RC2 + HEAD From c7ec9cc92edf071d5cf59b40e787851e48d2cb3a Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Fri, 12 Jan 2018 08:56:35 +0000 Subject: [PATCH 0677/2114] [maven-release-plugin] prepare release v5.1.2.RC2 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 0f37984871..acd88468ee 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.1.2-SNAPSHOT + 5.1.2.RC2 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v5.1.2.RC2 From c6ae89e448548832e0853863e7f4641282a86e7b Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Fri, 12 Jan 2018 08:56:39 +0000 Subject: [PATCH 0678/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index acd88468ee..0f37984871 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.1.2.RC2 + 5.1.2-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v5.1.2.RC2 + HEAD From d65ac2fc7b95c7b78f56eb81649802543f690ecd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 17 Jan 2018 10:00:44 +0100 Subject: [PATCH 0679/2114] Set release version to 4.4.2 --- release-versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-versions.txt b/release-versions.txt index c0540717c5..5169495ceb 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="4.4.2.RC2" +RELEASE_VERSION="4.4.2" DEVELOPMENT_VERSION="4.4.2-SNAPSHOT" From efe0d14ba95d0809b2e8b9ee0676885e2044da72 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Wed, 17 Jan 2018 09:02:12 +0000 Subject: [PATCH 0680/2114] [maven-release-plugin] prepare release v4.4.2 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 8cfd8d52ef..e4881fbcc8 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.4.2-SNAPSHOT + 4.4.2 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v4.4.2 From 9ff3ee0c129044af49fcb2f47421ad64cbe249b8 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Wed, 17 Jan 2018 09:02:16 +0000 Subject: [PATCH 0681/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index e4881fbcc8..8cfd8d52ef 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.4.2 + 4.4.2-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v4.4.2 + HEAD From 1264d7239f050fac1de9516d82e2f508446cd263 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 17 Jan 2018 10:05:55 +0100 Subject: [PATCH 0682/2114] Set release version to 4.4.3.RC1 --- release-versions.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release-versions.txt b/release-versions.txt index 5169495ceb..0a6d3cb46e 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="4.4.2" -DEVELOPMENT_VERSION="4.4.2-SNAPSHOT" +RELEASE_VERSION="4.4.3.RC1" +DEVELOPMENT_VERSION="4.4.3-SNAPSHOT" From ed615f72cb0ba269dbbc22c3348fc1ecedbd2e2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 17 Jan 2018 10:07:42 +0100 Subject: [PATCH 0683/2114] Set release version to 5.1.2 --- release-versions.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release-versions.txt b/release-versions.txt index 196e09dc34..a5b18a4d83 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="5.1.2.RC2" -DEVELOPMENT_VERSION="5.1.2-SNAPSHOT" +RELEASE_VERSION="5.1.2" +DEVELOPMENT_VERSION="5.1.3-SNAPSHOT" From 19290f67622491d30d28825f98a194d93cf2068e Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Wed, 17 Jan 2018 09:09:29 +0000 Subject: [PATCH 0684/2114] [maven-release-plugin] prepare release v5.1.2 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 0f37984871..38b3cc5cdd 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.1.2-SNAPSHOT + 5.1.2 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v5.1.2 From bece3b35f8b5a3758f1a8aa8c5a99aad317c83a8 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Wed, 17 Jan 2018 09:09:33 +0000 Subject: [PATCH 0685/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 38b3cc5cdd..52a9c79947 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.1.2 + 5.1.3-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v5.1.2 + HEAD From 365ddb66dbf2fb3938e43736759fe09e4cf16b26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 17 Jan 2018 10:22:10 +0100 Subject: [PATCH 0686/2114] Set POM version to 4.4.3-SNAPSHOT --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8cfd8d52ef..7195d79e27 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.4.2-SNAPSHOT + 4.4.3-SNAPSHOT jar RabbitMQ Java Client From bd5823617deb0700170359876ab5da8cf1bfb1cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 17 Jan 2018 16:01:30 +0100 Subject: [PATCH 0687/2114] Set version to 5.1.2 in readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d8db9131c1..a42047ddb6 100644 --- a/README.md +++ b/README.md @@ -23,14 +23,14 @@ These versions can still be used with RabbitMQ server `3.x`. com.rabbitmq amqp-client - 5.1.1 + 5.1.2 ``` ### Gradle ``` groovy -compile 'com.rabbitmq:amqp-client:5.1.1' +compile 'com.rabbitmq:amqp-client:5.1.2' ``` #### 3.6.x Series From ecdbd20c4808c1f7c94b248fd45fe3e951e530aa Mon Sep 17 00:00:00 2001 From: Michael Dent Date: Wed, 17 Jan 2018 11:57:12 -0600 Subject: [PATCH 0688/2114] add excludeQueueFromRecovery method --- .../recovery/AutorecoveringConnection.java | 26 +++++++++++++++++-- .../test/functional/ConnectionRecovery.java | 25 ++++++++++++++++++ 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index cccac5e5f6..ffee9bfb4a 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -761,6 +761,28 @@ void deleteRecordedQueue(String queue) { this.maybeDeleteRecordedAutoDeleteExchange(b.getSource()); } } + + /** + * Exclude the queue from the list of queues to recover after connection failure. + * Intended to be used in usecases where you want to remove the queue from this connection's recovery list but don't want to delete the queue from the server. + * + * @param queue queue name to exclude from recorded recovery queues + * @param ifUnused if true, the RecordedQueue will only be excluded if no local consumers are using it. + */ + public void excludeQueueFromRecovery(final String queue, final boolean ifUnused) { + if (ifUnused) { + // Note: This is basically the same as maybeDeleteRecordedAutoDeleteQueue except it works for non auto-delete queues as well. + synchronized (this.consumers) { + synchronized (this.recordedQueues) { + if (!hasMoreConsumersOnQueue(this.consumers.values(), queue)) { + deleteRecordedQueue(queue); + } + } + } + } else { + deleteRecordedQueue(queue); + } + } void recordExchange(String exchange, RecordedExchange x) { this.recordedExchanges.put(exchange, x); @@ -789,7 +811,7 @@ void maybeDeleteRecordedAutoDeleteQueue(String queue) { RecordedQueue q = this.recordedQueues.get(queue); // last consumer on this connection is gone, remove recorded queue // if it is auto-deleted. See bug 26364. - if((q != null) && q.isAutoDelete()) { + if(q != null && q.isAutoDelete()) { deleteRecordedQueue(queue); } } @@ -804,7 +826,7 @@ void maybeDeleteRecordedAutoDeleteExchange(String exchange) { RecordedExchange x = this.recordedExchanges.get(exchange); // last binding where this exchange is the source is gone, remove recorded exchange // if it is auto-deleted. See bug 26364. - if((x != null) && x.isAutoDelete()) { + if(x != null && x.isAutoDelete()) { deleteRecordedExchange(exchange); } } diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java index 1ad6feb960..1c53da1fcc 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -559,6 +559,31 @@ public void queueRecovered(String oldName, String newName) { // expected } } + + @Test public void thatExcludedQueueDoesNotReappearOnRecover() throws IOException, InterruptedException { + final String q = "java-client.test.recovery.excludedQueue1"; + channel.queueDeclare(q, true, false, false, null); + boolean deleted = false; + try { + // now delete it using the delegate so AutorecoveringConnection and AutorecoveringChannel are not aware of it + ((AutorecoveringChannel)channel).getDelegate().queueDelete(q); + // exclude the queue from recovery + ((AutorecoveringConnection)connection).excludeQueueFromRecovery(q, true); + // reconnect + closeAndWaitForRecovery(); + expectChannelRecovery(channel); + // verify queue was not recreated + try { + channel.queueDeclarePassive(q); + fail("Expected passive declare to fail"); + } catch (IOException ioe) { + // expected + } + } finally { + if (!deleted) + channel.queueDelete(q); + } + } @Test public void thatCancelledConsumerDoesNotReappearOnRecover() throws IOException, InterruptedException { String q = UUID.randomUUID().toString(); From 928693f3cda3b74d0da215a35a7d03bf06165d5e Mon Sep 17 00:00:00 2001 From: Michael Dent Date: Wed, 17 Jan 2018 12:02:32 -0600 Subject: [PATCH 0689/2114] add asserts to test --- .../rabbitmq/client/test/functional/ConnectionRecovery.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java index 1c53da1fcc..f882b0a73b 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -567,8 +567,11 @@ public void queueRecovered(String oldName, String newName) { try { // now delete it using the delegate so AutorecoveringConnection and AutorecoveringChannel are not aware of it ((AutorecoveringChannel)channel).getDelegate().queueDelete(q); + assertNotNull(((AutorecoveringConnection)connection).getRecordedQueues().get(q)); // exclude the queue from recovery ((AutorecoveringConnection)connection).excludeQueueFromRecovery(q, true); + // verify its not there + assertNull(((AutorecoveringConnection)connection).getRecordedQueues().get(q)); // reconnect closeAndWaitForRecovery(); expectChannelRecovery(channel); From 19d7d53ece6051b7c3882a4a6a01823a908df39d Mon Sep 17 00:00:00 2001 From: Michael Dent Date: Wed, 17 Jan 2018 12:09:55 -0600 Subject: [PATCH 0690/2114] test fix --- .../test/functional/ConnectionRecovery.java | 36 ++++++++----------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java index f882b0a73b..f0c0cb401d 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -563,28 +563,22 @@ public void queueRecovered(String oldName, String newName) { @Test public void thatExcludedQueueDoesNotReappearOnRecover() throws IOException, InterruptedException { final String q = "java-client.test.recovery.excludedQueue1"; channel.queueDeclare(q, true, false, false, null); - boolean deleted = false; + // now delete it using the delegate so AutorecoveringConnection and AutorecoveringChannel are not aware of it + ((AutorecoveringChannel)channel).getDelegate().queueDelete(q); + assertNotNull(((AutorecoveringConnection)connection).getRecordedQueues().get(q)); + // exclude the queue from recovery + ((AutorecoveringConnection)connection).excludeQueueFromRecovery(q, true); + // verify its not there + assertNull(((AutorecoveringConnection)connection).getRecordedQueues().get(q)); + // reconnect + closeAndWaitForRecovery(); + expectChannelRecovery(channel); + // verify queue was not recreated try { - // now delete it using the delegate so AutorecoveringConnection and AutorecoveringChannel are not aware of it - ((AutorecoveringChannel)channel).getDelegate().queueDelete(q); - assertNotNull(((AutorecoveringConnection)connection).getRecordedQueues().get(q)); - // exclude the queue from recovery - ((AutorecoveringConnection)connection).excludeQueueFromRecovery(q, true); - // verify its not there - assertNull(((AutorecoveringConnection)connection).getRecordedQueues().get(q)); - // reconnect - closeAndWaitForRecovery(); - expectChannelRecovery(channel); - // verify queue was not recreated - try { - channel.queueDeclarePassive(q); - fail("Expected passive declare to fail"); - } catch (IOException ioe) { - // expected - } - } finally { - if (!deleted) - channel.queueDelete(q); + channel.queueDeclarePassive(q); + fail("Expected passive declare to fail"); + } catch (IOException ioe) { + // expected } } From 46a7d8629479ef26379bc83196f8c606a6338619 Mon Sep 17 00:00:00 2001 From: Andreas Presthammer Date: Thu, 4 Jan 2018 08:47:38 +0100 Subject: [PATCH 0691/2114] Add RpcClient doCall/responseCall/primitiveCall overloads which include timeout There will be use cases where a single shared timeout specified in the constructor of the RpcClient will not match up with the expected timeout for different rpc calls made using the rpc client. It's then convenient to be able to specifiy the timeout value on a per method call basis. Otherwise the user of RpcClient would have to create multiple instances of RpcClient, incurring the startup cost and having redundant consumers of the response queue. --- .../java/com/rabbitmq/client/RpcClient.java | 33 +++++++++++++++++-- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/RpcClient.java b/src/main/java/com/rabbitmq/client/RpcClient.java index 61d881f60f..928d819585 100644 --- a/src/main/java/com/rabbitmq/client/RpcClient.java +++ b/src/main/java/com/rabbitmq/client/RpcClient.java @@ -209,6 +209,11 @@ public void publish(AMQP.BasicProperties props, byte[] message) } public Response doCall(AMQP.BasicProperties props, byte[] message) + throws IOException, TimeoutException { + return doCall(props, message, _timeout); + } + + public Response doCall(AMQP.BasicProperties props, byte[] message, int timeout) throws IOException, ShutdownSignalException, TimeoutException { checkConsumer(); BlockingCell k = new BlockingCell(); @@ -220,7 +225,7 @@ public Response doCall(AMQP.BasicProperties props, byte[] message) _continuationMap.put(replyId, k); } publish(props, message); - Object reply = k.uninterruptibleGet(_timeout); + Object reply = k.uninterruptibleGet(timeout); if (reply instanceof ShutdownSignalException) { ShutdownSignalException sig = (ShutdownSignalException) reply; ShutdownSignalException wrapper = @@ -238,7 +243,13 @@ public Response doCall(AMQP.BasicProperties props, byte[] message) public byte[] primitiveCall(AMQP.BasicProperties props, byte[] message) throws IOException, ShutdownSignalException, TimeoutException { - return doCall(props, message).getBody(); + return primitiveCall(props, message, _timeout); + } + + public byte[] primitiveCall(AMQP.BasicProperties props, byte[] message, int timeout) + throws IOException, ShutdownSignalException, TimeoutException + { + return doCall(props, message, timeout).getBody(); } /** @@ -266,7 +277,23 @@ public byte[] primitiveCall(byte[] message) * @throws TimeoutException if a response is not received within the configured timeout */ public Response responseCall(byte[] message) throws IOException, ShutdownSignalException, TimeoutException { - return doCall(null, message); + return responseCall(message, _timeout); + } + + /** + * Perform a simple byte-array-based RPC roundtrip + * + * Useful if you need to get at more than just the body of the message + * + * @param message the byte array request message to send + * @param timeout milliseconds before timing out on wait for response + * @return The response object is an envelope that contains all of the data provided to the `handleDelivery` consumer + * @throws ShutdownSignalException if the connection dies during our wait + * @throws IOException if an error is encountered + * @throws TimeoutException if a response is not received within the configured timeout + */ + public Response responseCall(byte[] message, int timeout) throws IOException, ShutdownSignalException, TimeoutException { + return doCall(null, message, timeout); } /** From 5b3b5e80512087c65720a7f72acd62dd236307e5 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Wed, 24 Jan 2018 13:16:27 +0000 Subject: [PATCH 0692/2114] [maven-release-plugin] prepare release v4.5.0.RC1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index b6b91d0a03..6ae0488c5b 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.5.0-SNAPSHOT + 4.5.0.RC1 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v4.5.0.RC1 From 9b0f3fa5c2734e6a24b471e682fdb47ca103d9c6 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Wed, 24 Jan 2018 13:16:31 +0000 Subject: [PATCH 0693/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 6ae0488c5b..b6b91d0a03 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.5.0.RC1 + 4.5.0-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v4.5.0.RC1 + HEAD From 44c9e8db886e37a6c77829e1693d008c5dae05f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 26 Jan 2018 12:06:28 +0100 Subject: [PATCH 0694/2114] Generate Javadoc with Maven wrapper --- deploy-javadoc.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy-javadoc.sh b/deploy-javadoc.sh index 9c3444592f..d4a65cce6e 100755 --- a/deploy-javadoc.sh +++ b/deploy-javadoc.sh @@ -32,7 +32,7 @@ done set -e -x -mvn -q clean javadoc:javadoc -Dmaven.javadoc.failOnError=false +./mvnw -q clean javadoc:javadoc -Dmaven.javadoc.failOnError=false ssh $DEPLOY_USERHOST \ "rm -rf $DEPLOY_PATH; \ From 5b38953bc7cbe0b5c4dfbf955294a29c2e76119e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 29 Jan 2018 10:42:33 +0100 Subject: [PATCH 0695/2114] Avoid too long closing message in StrictExceptionHandler Fixes #344 --- .../client/impl/StrictExceptionHandler.java | 25 ++++-- .../com/rabbitmq/client/test/ClientTests.java | 3 +- .../test/StrictExceptionHandlerTest.java | 83 +++++++++++++++++++ 3 files changed, 103 insertions(+), 8 deletions(-) create mode 100644 src/test/java/com/rabbitmq/client/test/StrictExceptionHandlerTest.java diff --git a/src/main/java/com/rabbitmq/client/impl/StrictExceptionHandler.java b/src/main/java/com/rabbitmq/client/impl/StrictExceptionHandler.java index 2c722d5d76..ab373e15fb 100644 --- a/src/main/java/com/rabbitmq/client/impl/StrictExceptionHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/StrictExceptionHandler.java @@ -55,25 +55,36 @@ public void handleConsumerException(Channel channel, Throwable exception, Consumer consumer, String consumerTag, String methodName) { - handleChannelKiller(channel, exception, "Consumer " + consumer - + " (" + consumerTag + ")" - + " method " + methodName - + " for channel " + channel); + String logMessage = "Consumer " + consumer + + " (" + consumerTag + ")" + + " method " + methodName + + " for channel " + channel; + String closeMessage = "Consumer" + + " (" + consumerTag + ")" + + " method " + methodName + + " for channel " + channel; + handleChannelKiller(channel, exception, logMessage, closeMessage); } @Override protected void handleChannelKiller(Channel channel, Throwable exception, String what) { - log(what + " threw an exception for channel " + channel, exception); + handleChannelKiller(channel, exception, what, what); + } + + protected void handleChannelKiller(Channel channel, Throwable exception, String logMessage, String closeMessage) { + log(logMessage + " threw an exception for channel " + channel, exception); try { - channel.close(AMQP.REPLY_SUCCESS, "Closed due to exception from " + what); + channel.close(AMQP.REPLY_SUCCESS, "Closed due to exception from " + closeMessage); } catch (AlreadyClosedException ace) { // noop } catch (TimeoutException ace) { // noop } catch (IOException ioe) { log("Failure during close of channel " + channel + " after " + exception, ioe); - channel.getConnection().abort(AMQP.INTERNAL_ERROR, "Internal error closing channel for " + what); + channel.getConnection().abort(AMQP.INTERNAL_ERROR, "Internal error closing channel for " + closeMessage); } } + + } diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index 08a8d02259..16545e9003 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -53,7 +53,8 @@ RecoveryDelayHandlerTest.class, FrameBuilderTest.class, PropertyFileInitialisationTest.class, - ClientVersionTest.class + ClientVersionTest.class, + StrictExceptionHandlerTest.class }) public class ClientTests { diff --git a/src/test/java/com/rabbitmq/client/test/StrictExceptionHandlerTest.java b/src/test/java/com/rabbitmq/client/test/StrictExceptionHandlerTest.java new file mode 100644 index 0000000000..5cc68d1eb3 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/StrictExceptionHandlerTest.java @@ -0,0 +1,83 @@ +// Copyright (c) 2018-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.test; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.Consumer; +import com.rabbitmq.client.DefaultConsumer; +import com.rabbitmq.client.Envelope; +import com.rabbitmq.client.impl.StrictExceptionHandler; +import org.junit.Test; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; + +public class StrictExceptionHandlerTest { + + @Test + public void tooLongClosingMessage() throws Exception { + ConnectionFactory cf = TestUtils.connectionFactory(); + final CountDownLatch latch = new CountDownLatch(1); + cf.setExceptionHandler(new StrictExceptionHandler() { + @Override + public void handleConsumerException(Channel channel, Throwable exception, Consumer consumer, String consumerTag, String methodName) { + try { + super.handleConsumerException(channel, exception, consumer, consumerTag, methodName); + } catch (IllegalArgumentException e) { + fail("No exception should caught"); + } + latch.countDown(); + } + }); + Connection c = null; + try { + c = cf.newConnection(); + Channel channel = c.createChannel(); + String queue = channel.queueDeclare().getQueue(); + channel.basicConsume(queue, + new VeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongClassName( + channel + )); + channel.basicPublish("", queue, null, new byte[0]); + assertThat(latch.await(5, TimeUnit.SECONDS), is(true)); + } finally { + if (c != null) { + c.close(); + } + } + } + + static class VeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongClassName + extends DefaultConsumer { + + public VeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongClassName( + Channel channel) { + super(channel); + } + + @Override + public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) { + throw new RuntimeException(); + } + } +} From e324bf92a045ff86ea350e40217d1b8984c81ccf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 5 Feb 2018 11:31:23 +0100 Subject: [PATCH 0696/2114] Trigger recovery if a socket write fails Detecting connection failure on reading can take a lot of time (even forever if the reading thread is stuck), so connection recovery can now be triggered when a write operation fails. This can make the client more reactive to detect failing connections. References #341 --- .../rabbitmq/client/impl/AMQConnection.java | 16 +- .../client/impl/ConnectionParams.java | 9 + .../client/impl/ErrorOnWriteListener.java | 33 +++ .../recovery/AutorecoveringConnection.java | 9 + ...NoAutoRecoveryWhenTcpWindowIsFullTest.java | 200 ++++++++++++++++++ 5 files changed, 265 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/rabbitmq/client/impl/ErrorOnWriteListener.java create mode 100644 src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index 0d89880046..a72a286a1c 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -61,6 +61,8 @@ public class AMQConnection extends ShutdownNotifierComponent implements Connecti private final List recoveryCanBeginListeners = Collections.synchronizedList(new ArrayList()); + private final ErrorOnWriteListener errorOnWriteListener; + /** * Retrieve a copy of the default table of client properties that * will be sent to the server during connection startup. This @@ -245,6 +247,13 @@ public AMQConnection(ConnectionParams params, FrameHandler frameHandler, Metrics this._inConnectionNegotiation = true; // we start out waiting for the first protocol response this.metricsCollector = metricsCollector; + + this.errorOnWriteListener = params.getErrorOnWriteListener() != null ? params.getErrorOnWriteListener() : + new ErrorOnWriteListener() { + @Override + public void handle(Connection connection, Throwable exception) { } + }; + } private void initializeConsumerWorkService() { @@ -556,7 +565,11 @@ public void writeFrame(Frame f) throws IOException { * Public API - flush the output buffers */ public void flush() throws IOException { - _frameHandler.flush(); + try { + _frameHandler.flush(); + } catch (Throwable throwable) { + this.errorOnWriteListener.handle(this, throwable); + } } private static int negotiatedMaxValue(int clientValue, int serverValue) { @@ -879,7 +892,6 @@ private ShutdownSignalException startShutdown(Method reason, _heartbeatSender.shutdown(); _channel0.processShutdownSignal(sse, !initiatedByApplication, notifyRpc); - return sse; } diff --git a/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java b/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java index 40a82f2ffc..08232437f3 100644 --- a/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java +++ b/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java @@ -44,6 +44,7 @@ public class ConnectionParams { private boolean topologyRecovery; private int channelRpcTimeout; private boolean channelShouldCheckRpcResponseType; + private ErrorOnWriteListener errorOnWriteListener; private ExceptionHandler exceptionHandler; private ThreadFactory threadFactory; @@ -213,4 +214,12 @@ public void setChannelRpcTimeout(int channelRpcTimeout) { public void setChannelShouldCheckRpcResponseType(boolean channelShouldCheckRpcResponseType) { this.channelShouldCheckRpcResponseType = channelShouldCheckRpcResponseType; } + + public void setErrorOnWriteListener(ErrorOnWriteListener errorOnWriteListener) { + this.errorOnWriteListener = errorOnWriteListener; + } + + public ErrorOnWriteListener getErrorOnWriteListener() { + return errorOnWriteListener; + } } diff --git a/src/main/java/com/rabbitmq/client/impl/ErrorOnWriteListener.java b/src/main/java/com/rabbitmq/client/impl/ErrorOnWriteListener.java new file mode 100644 index 0000000000..555f478744 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/ErrorOnWriteListener.java @@ -0,0 +1,33 @@ +// Copyright (c) 2018-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl; + +import com.rabbitmq.client.Connection; + +/** + * Listener called when a connection gets an error trying to write on the socket. + * This can be used to trigger connection recovery. + */ +public interface ErrorOnWriteListener { + + /** + * Called when writing to the socket failed + * @param connection the owning connection instance + * @param exception the thrown exception + */ + void handle(Connection connection, Throwable exception); + +} diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index ffee9bfb4a..4f388076ad 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -18,6 +18,7 @@ import com.rabbitmq.client.*; import com.rabbitmq.client.impl.AMQConnection; import com.rabbitmq.client.impl.ConnectionParams; +import com.rabbitmq.client.impl.ErrorOnWriteListener; import com.rabbitmq.client.impl.FrameHandlerFactory; import com.rabbitmq.client.impl.NetworkConnection; import com.rabbitmq.utility.Utility; @@ -87,6 +88,14 @@ public AutorecoveringConnection(ConnectionParams params, FrameHandlerFactory f, this.cf = new RecoveryAwareAMQConnectionFactory(params, f, addressResolver, metricsCollector); this.params = params; + this.params.setErrorOnWriteListener(new ErrorOnWriteListener() { + @Override + public void handle(Connection connection, Throwable exception) { + AMQConnection c = (AMQConnection) connection; + c.handleIoError(exception); + } + }); + this.channels = new ConcurrentHashMap(); } diff --git a/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java b/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java new file mode 100644 index 0000000000..76abbb8d80 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java @@ -0,0 +1,200 @@ +// Copyright (c) 2018-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.test; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.DefaultConsumer; +import com.rabbitmq.client.Envelope; +import com.rabbitmq.client.Recoverable; +import com.rabbitmq.client.RecoveryListener; +import com.rabbitmq.client.impl.recovery.AutorecoveringChannel; +import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; + +/** + * Test to trigger and check the fix of https://github.com/rabbitmq/rabbitmq-java-client/issues/341. + * Conditions: + * - client registers consumer and a call QoS after + * - client get many messages and the consumer is slow + * - the work pool queue is full, the reading thread is stuck + * - more messages come from the network and saturates the TCP buffer + * - the connection dies but the client doesn't detect it + * - acks of messages fail + * - connection recovery is never triggered + * + * The fix consists in triggering connection recovery when writing + * to the socket fails. As the socket is dead, the closing + * sequence can take some time, hence the setup of the shutdown + * listener, which avoids waiting for the socket termination by + * the OS (can take 15 minutes on linux). + */ +public class NoAutoRecoveryWhenTcpWindowIsFullTest { + + private static final int QOS_PREFETCH = 64; + private static final int NUM_MESSAGES_TO_PRODUCE = 100000; + private static final int MESSAGE_PROCESSING_TIME_MS = 3000; + + private ExecutorService dispatchingService; + private ExecutorService producerService; + private ExecutorService shutdownService; + private AutorecoveringConnection producingConnection; + private AutorecoveringChannel producingChannel; + private AutorecoveringConnection consumingConnection; + private AutorecoveringChannel consumingChannel; + + private CountDownLatch consumerRecoverOkLatch; + + @Before + public void setUp() throws Exception { + dispatchingService = Executors.newSingleThreadExecutor(); + shutdownService = Executors.newSingleThreadExecutor(); + producerService = Executors.newSingleThreadExecutor(); + final ConnectionFactory factory = TestUtils.connectionFactory(); + factory.setAutomaticRecoveryEnabled(true); + factory.setTopologyRecoveryEnabled(true); + // we try to set the lower values for closing timeouts, etc. + // this makes the test execute faster. + factory.setShutdownExecutor(shutdownService); + factory.setShutdownTimeout(10000); + factory.setRequestedHeartbeat(5); + factory.setShutdownExecutor(dispatchingService); + factory.setNetworkRecoveryInterval(1000); + + producingConnection = (AutorecoveringConnection) factory.newConnection("Producer Connection"); + producingChannel = (AutorecoveringChannel) producingConnection.createChannel(); + consumingConnection = (AutorecoveringConnection) factory.newConnection("Consuming Connection"); + consumingChannel = (AutorecoveringChannel) consumingConnection.createChannel(); + + consumerRecoverOkLatch = new CountDownLatch(1); + } + + @After + public void tearDown() throws IOException { + dispatchingService.shutdownNow(); + producerService.shutdownNow(); + shutdownService.shutdownNow(); + closeConnectionIfOpen(consumingConnection); + closeConnectionIfOpen(producingConnection); + } + + @Test + public void failureAndRecovery() throws IOException, InterruptedException { + final String queue = UUID.randomUUID().toString(); + + final CountDownLatch latch = new CountDownLatch(1); + + consumingConnection.addRecoveryListener(new RecoveryListener() { + + @Override + public void handleRecovery(Recoverable recoverable) { + } + + @Override + public void handleRecoveryStarted(Recoverable recoverable) { + latch.countDown(); + } + }); + + declareQueue(producingChannel, queue); + produceMessagesInBackground(producingChannel, queue); + startConsumer(queue); + + assertThat( + "Connection should have been closed and should have recovered by now", + latch.await(60, TimeUnit.SECONDS), is(true) + ); + + assertThat( + "Consumer should have recovered by now", + latch.await(5, TimeUnit.SECONDS), is(true) + ); + } + + private void closeConnectionIfOpen(Connection connection) throws IOException { + if (connection.isOpen()) { + connection.close(); + } + } + + private void declareQueue(final Channel channel, final String queue) throws IOException { + final Map queueArguments = new HashMap(); + channel.queueDeclare(queue, false, false, false, queueArguments); + } + + private void produceMessagesInBackground(final Channel channel, final String queue) { + final AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder().deliveryMode(1).build(); + producerService.submit(new Callable() { + + @Override + public Void call() throws Exception { + for (int i = 0; i < NUM_MESSAGES_TO_PRODUCE; i++) { + channel.basicPublish("", queue, false, properties, ("MSG NUM" + i).getBytes()); + } + closeConnectionIfOpen(producingConnection); + return null; + } + }); + } + + private void startConsumer(final String queue) throws IOException { + consumingChannel.basicConsume(queue, false, "", false, false, null, new DefaultConsumer(consumingChannel) { + + @Override + public void handleRecoverOk(String consumerTag) { + consumerRecoverOkLatch.countDown(); + } + + @Override + public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { + consumerWork(); + consumingChannel.basicAck(envelope.getDeliveryTag(), false); + } + }); + try { + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + consumingChannel.basicQos(QOS_PREFETCH); + } + + private void consumerWork() { + try { + Thread.sleep(MESSAGE_PROCESSING_TIME_MS); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } +} + From bfc5884ef463127a784e6ed323474f6c3de941e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 5 Feb 2018 17:32:41 +0100 Subject: [PATCH 0697/2114] Test connection recovery triggering on read Test disabled for NIO: the IO thread (reading and writing) can be stuck in reading mode (work pool full), which also blocks the writing (no heartbeat), and no detection connection failure detection. References #341 --- .../rabbitmq/client/impl/AMQConnection.java | 5 +-- .../com/rabbitmq/client/test/ClientTests.java | 3 +- ...NoAutoRecoveryWhenTcpWindowIsFullTest.java | 34 ++++++++++++------- 3 files changed, 26 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index a72a286a1c..e0391bf82e 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -567,8 +567,9 @@ public void writeFrame(Frame f) throws IOException { public void flush() throws IOException { try { _frameHandler.flush(); - } catch (Throwable throwable) { - this.errorOnWriteListener.handle(this, throwable); + } catch (IOException ioe) { + this.errorOnWriteListener.handle(this, ioe); + throw ioe; } } diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index 16545e9003..73258f1e59 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -54,7 +54,8 @@ FrameBuilderTest.class, PropertyFileInitialisationTest.class, ClientVersionTest.class, - StrictExceptionHandlerTest.class + StrictExceptionHandlerTest.class, + NoAutoRecoveryWhenTcpWindowIsFullTest.class }) public class ClientTests { diff --git a/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java b/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java index 76abbb8d80..f3635ca7f0 100644 --- a/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java +++ b/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java @@ -45,14 +45,14 @@ /** * Test to trigger and check the fix of https://github.com/rabbitmq/rabbitmq-java-client/issues/341. * Conditions: - * - client registers consumer and a call QoS after - * - client get many messages and the consumer is slow - * - the work pool queue is full, the reading thread is stuck - * - more messages come from the network and saturates the TCP buffer - * - the connection dies but the client doesn't detect it - * - acks of messages fail - * - connection recovery is never triggered - * + * - client registers consumer and a call QoS after + * - client get many messages and the consumer is slow + * - the work pool queue is full, the reading thread is stuck + * - more messages come from the network and saturates the TCP buffer + * - the connection dies but the client doesn't detect it + * - acks of messages fail + * - connection recovery is never triggered + *

* The fix consists in triggering connection recovery when writing * to the socket fails. As the socket is dead, the closing * sequence can take some time, hence the setup of the shutdown @@ -88,7 +88,7 @@ public void setUp() throws Exception { factory.setShutdownExecutor(shutdownService); factory.setShutdownTimeout(10000); factory.setRequestedHeartbeat(5); - factory.setShutdownExecutor(dispatchingService); + factory.setSharedExecutor(dispatchingService); factory.setNetworkRecoveryInterval(1000); producingConnection = (AutorecoveringConnection) factory.newConnection("Producer Connection"); @@ -101,15 +101,19 @@ public void setUp() throws Exception { @After public void tearDown() throws IOException { + closeConnectionIfOpen(consumingConnection); + closeConnectionIfOpen(producingConnection); + dispatchingService.shutdownNow(); producerService.shutdownNow(); shutdownService.shutdownNow(); - closeConnectionIfOpen(consumingConnection); - closeConnectionIfOpen(producingConnection); } @Test public void failureAndRecovery() throws IOException, InterruptedException { + if (TestUtils.USE_NIO) { + return; + } final String queue = UUID.randomUUID().toString(); final CountDownLatch latch = new CountDownLatch(1); @@ -152,7 +156,7 @@ private void declareQueue(final Channel channel, final String queue) throws IOEx channel.queueDeclare(queue, false, false, false, queueArguments); } - private void produceMessagesInBackground(final Channel channel, final String queue) { + private void produceMessagesInBackground(final Channel channel, final String queue) throws IOException { final AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder().deliveryMode(1).build(); producerService.submit(new Callable() { @@ -178,7 +182,11 @@ public void handleRecoverOk(String consumerTag) { @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { consumerWork(); - consumingChannel.basicAck(envelope.getDeliveryTag(), false); + try { + consumingChannel.basicAck(envelope.getDeliveryTag(), false); + } catch (Exception e) { + // application should handle writing exceptions + } } }); try { From 98d32d43fb3c7db2d6fc9f33249b803e9435e8a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 6 Feb 2018 14:10:42 +0100 Subject: [PATCH 0698/2114] Adding log in tests --- src/test/resources/logback-test.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml index ee88f442c2..4bd2e37606 100644 --- a/src/test/resources/logback-test.xml +++ b/src/test/resources/logback-test.xml @@ -5,7 +5,7 @@ - + \ No newline at end of file From f312fa50b01262340daa9f1971ddbd88bf4fde49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 6 Feb 2018 14:50:41 +0100 Subject: [PATCH 0699/2114] Make AMQConnection#doFinalShutdown idempotent Now recovery can be triggered from write operations, late connection failure discoveries can re-trigger the shutdown and emit spurious exception. References #341 --- .../rabbitmq/client/impl/AMQConnection.java | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index e0391bf82e..7c03ea0562 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -32,6 +32,7 @@ import java.net.SocketTimeoutException; import java.util.*; import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicBoolean; final class Copyright { final static String COPYRIGHT="Copyright (c) 2007-2017 Pivotal Software, Inc."; @@ -63,6 +64,8 @@ public class AMQConnection extends ShutdownNotifierComponent implements Connecti private final ErrorOnWriteListener errorOnWriteListener; + private final AtomicBoolean finalShutdownStarted = new AtomicBoolean(false); + /** * Retrieve a copy of the default table of client properties that * will be sent to the server during connection startup. This @@ -700,14 +703,16 @@ private void handleFailure(Throwable ex) { /** private API */ public void doFinalShutdown() { - _frameHandler.close(); - _appContinuation.set(null); - notifyListeners(); - // assuming that shutdown listeners do not do anything - // asynchronously, e.g. start new threads, this effectively - // guarantees that we only begin recovery when all shutdown - // listeners have executed - notifyRecoveryCanBeginListeners(); + if (finalShutdownStarted.compareAndSet(false, true)) { + _frameHandler.close(); + _appContinuation.set(null); + notifyListeners(); + // assuming that shutdown listeners do not do anything + // asynchronously, e.g. start new threads, this effectively + // guarantees that we only begin recovery when all shutdown + // listeners have executed + notifyRecoveryCanBeginListeners(); + } } private void notifyRecoveryCanBeginListeners() { From cea5e9714ae5bc22854545d10005ae8e31a008bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 6 Feb 2018 17:02:48 +0100 Subject: [PATCH 0700/2114] Close ExecutorServices in test --- .../client/impl/WorkPoolFullException.java | 8 ++++ .../client/test/SharedThreadPoolTest.java | 39 ++++++++++++------- 2 files changed, 34 insertions(+), 13 deletions(-) create mode 100644 src/main/java/com/rabbitmq/client/impl/WorkPoolFullException.java diff --git a/src/main/java/com/rabbitmq/client/impl/WorkPoolFullException.java b/src/main/java/com/rabbitmq/client/impl/WorkPoolFullException.java new file mode 100644 index 0000000000..bbedc782bb --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/WorkPoolFullException.java @@ -0,0 +1,8 @@ +package com.rabbitmq.client.impl; + +/** + * + */ +public class WorkPoolFullException { + +} diff --git a/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java b/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java index ceb26b264a..c8970205c4 100644 --- a/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java +++ b/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java @@ -30,23 +30,36 @@ public class SharedThreadPoolTest extends BrokerTestCase { @Test public void willShutDownExecutor() throws IOException, TimeoutException { - ConnectionFactory cf = TestUtils.connectionFactory(); - cf.setAutomaticRecoveryEnabled(false); - ExecutorService executor = Executors.newFixedThreadPool(8); - cf.setSharedExecutor(executor); + ExecutorService executor1 = null; + ExecutorService executor2 = null; + try { + ConnectionFactory cf = TestUtils.connectionFactory(); + cf.setAutomaticRecoveryEnabled(false); + executor1 = Executors.newFixedThreadPool(8); + cf.setSharedExecutor(executor1); - AMQConnection conn1 = (AMQConnection)cf.newConnection(); - assertFalse(conn1.willShutDownConsumerExecutor()); + AMQConnection conn1 = (AMQConnection)cf.newConnection(); + assertFalse(conn1.willShutDownConsumerExecutor()); - AMQConnection conn2 = (AMQConnection)cf.newConnection(Executors.newSingleThreadExecutor()); - assertFalse(conn2.willShutDownConsumerExecutor()); + executor2 = Executors.newSingleThreadExecutor(); + AMQConnection conn2 = (AMQConnection)cf.newConnection(executor2); + assertFalse(conn2.willShutDownConsumerExecutor()); - AMQConnection conn3 = (AMQConnection)cf.newConnection((ExecutorService)null); - assertTrue(conn3.willShutDownConsumerExecutor()); + AMQConnection conn3 = (AMQConnection)cf.newConnection((ExecutorService)null); + assertTrue(conn3.willShutDownConsumerExecutor()); - cf.setSharedExecutor(null); + cf.setSharedExecutor(null); - AMQConnection conn4 = (AMQConnection)cf.newConnection(); - assertTrue(conn4.willShutDownConsumerExecutor()); + AMQConnection conn4 = (AMQConnection)cf.newConnection(); + assertTrue(conn4.willShutDownConsumerExecutor()); + } finally { + if (executor1 != null) { + executor1.shutdownNow(); + } + if (executor2 != null) { + executor2.shutdownNow(); + } + } + } } From c8926f8ddc7823ffb56664de872047f7fc0e0ab9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 12 Feb 2018 10:15:38 +0100 Subject: [PATCH 0701/2114] Trigger connection recovery on socket write error Automatic connection recovery triggers now by default when a write operation fails because of an IO exception. The recovery process takes place in a dedicated thread so the write operation doesn't wait (it receives the same IO exception immediatly). The test to trigger the error has changed: it doesn't use manual ack anymore, as this could sometimes block the broker and make recovery fail (broker was busy re-enqueuing messages). The test now sends a message in the consumer, which is enough to reproduce the error. Note the test against NIO is skipped right now, as it needs additional care. [#154263515] References #341 --- .../rabbitmq/client/impl/AMQConnection.java | 33 +++++++- .../client/impl/ErrorOnWriteListener.java | 4 +- .../recovery/AutorecoveringConnection.java | 47 +++++++++-- ...NoAutoRecoveryWhenTcpWindowIsFullTest.java | 80 +++++++++---------- src/test/resources/logback-test.xml | 2 +- 5 files changed, 113 insertions(+), 53 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index 7c03ea0562..cee548d567 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -254,7 +254,7 @@ public AMQConnection(ConnectionParams params, FrameHandler frameHandler, Metrics this.errorOnWriteListener = params.getErrorOnWriteListener() != null ? params.getErrorOnWriteListener() : new ErrorOnWriteListener() { @Override - public void handle(Connection connection, Throwable exception) { } + public void handle(Connection connection, IOException exception) { } }; } @@ -572,7 +572,6 @@ public void flush() throws IOException { _frameHandler.flush(); } catch (IOException ioe) { this.errorOnWriteListener.handle(this, ioe); - throw ioe; } } @@ -592,15 +591,24 @@ private class MainLoop implements Runnable { */ @Override public void run() { + boolean shouldDoFinalShutdown = true; try { while (_running) { Frame frame = _frameHandler.readFrame(); readFrame(frame); } } catch (Throwable ex) { - handleFailure(ex); + if (ex instanceof InterruptedException) { + // loop has been interrupted during shutdown, + // no need to do it again + shouldDoFinalShutdown = false; + } else { + handleFailure(ex); + } } finally { - doFinalShutdown(); + if (shouldDoFinalShutdown) { + doFinalShutdown(); + } } } } @@ -706,6 +714,7 @@ public void doFinalShutdown() { if (finalShutdownStarted.compareAndSet(false, true)) { _frameHandler.close(); _appContinuation.set(null); + closeMainLoopThreadIfNecessary(); notifyListeners(); // assuming that shutdown listeners do not do anything // asynchronously, e.g. start new threads, this effectively @@ -715,6 +724,22 @@ public void doFinalShutdown() { } } + private void closeMainLoopThreadIfNecessary() { + if (mainLoopReadThreadNotNull() && notInMainLoopThread()) { + if (this.mainLoopThread.isAlive()) { + this.mainLoopThread.interrupt(); + } + } + } + + private boolean notInMainLoopThread() { + return Thread.currentThread() != this.mainLoopThread; + } + + private boolean mainLoopReadThreadNotNull() { + return this.mainLoopThread != null; + } + private void notifyRecoveryCanBeginListeners() { ShutdownSignalException sse = this.getCloseReason(); for(RecoveryCanBeginListener fn : Utility.copy(this.recoveryCanBeginListeners)) { diff --git a/src/main/java/com/rabbitmq/client/impl/ErrorOnWriteListener.java b/src/main/java/com/rabbitmq/client/impl/ErrorOnWriteListener.java index 555f478744..b912dd07a0 100644 --- a/src/main/java/com/rabbitmq/client/impl/ErrorOnWriteListener.java +++ b/src/main/java/com/rabbitmq/client/impl/ErrorOnWriteListener.java @@ -17,6 +17,8 @@ import com.rabbitmq.client.Connection; +import java.io.IOException; + /** * Listener called when a connection gets an error trying to write on the socket. * This can be used to trigger connection recovery. @@ -28,6 +30,6 @@ public interface ErrorOnWriteListener { * @param connection the owning connection instance * @param exception the thrown exception */ - void handle(Connection connection, Throwable exception); + void handle(Connection connection, IOException exception) throws IOException; } diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index 4f388076ad..0f976b5ca3 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -22,13 +22,18 @@ import com.rabbitmq.client.impl.FrameHandlerFactory; import com.rabbitmq.client.impl.NetworkConnection; import com.rabbitmq.utility.Utility; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; import java.net.InetAddress; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; +import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeoutException; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; /** * Connection implementation that performs automatic recovery when @@ -52,6 +57,9 @@ * @since 3.3.0 */ public class AutorecoveringConnection implements RecoverableConnection, NetworkConnection { + + private static final Logger LOGGER = LoggerFactory.getLogger(AutorecoveringConnection.class); + private final RecoveryAwareAMQConnectionFactory cf; private final Map channels; private final ConnectionParams params; @@ -88,15 +96,37 @@ public AutorecoveringConnection(ConnectionParams params, FrameHandlerFactory f, this.cf = new RecoveryAwareAMQConnectionFactory(params, f, addressResolver, metricsCollector); this.params = params; + setupErrorOnWriteListenerForPotentialRecovery(); + + this.channels = new ConcurrentHashMap(); + } + + private void setupErrorOnWriteListenerForPotentialRecovery() { + final ThreadFactory threadFactory = this.params.getThreadFactory(); + final Lock errorOnWriteLock = new ReentrantLock(); this.params.setErrorOnWriteListener(new ErrorOnWriteListener() { @Override - public void handle(Connection connection, Throwable exception) { - AMQConnection c = (AMQConnection) connection; - c.handleIoError(exception); + public void handle(final Connection connection, final IOException exception) throws IOException { + // this is called for any write error + // we should trigger the error handling and the recovery only once + if (errorOnWriteLock.tryLock()) { + try { + Thread recoveryThread = threadFactory.newThread(new Runnable() { + @Override + public void run() { + AMQConnection c = (AMQConnection) connection; + c.handleIoError(exception); + } + }); + recoveryThread.setName("RabbitMQ Error On Write Thread"); + recoveryThread.start(); + } finally { + errorOnWriteLock.unlock(); + } + } + throw exception; } }); - - this.channels = new ConcurrentHashMap(); } /** @@ -661,7 +691,9 @@ private void recoverConsumers() { for (Map.Entry entry : Utility.copy(this.consumers).entrySet()) { String tag = entry.getKey(); RecordedConsumer consumer = entry.getValue(); - + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Recovering consumer {}", consumer); + } try { String newTag = consumer.recover(); // make sure server-generated tags are re-added. MK. @@ -676,6 +708,9 @@ private void recoverConsumers() { for(ConsumerRecoveryListener crl : Utility.copy(this.consumerRecoveryListeners)) { crl.consumerRecovered(tag, newTag); } + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Consumer {} has recovered", consumer); + } } catch (Exception cause) { final String message = "Caught an exception while recovering consumer " + tag + ": " + cause.getMessage(); diff --git a/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java b/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java index f3635ca7f0..6fe1fe5fe0 100644 --- a/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java +++ b/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java @@ -20,6 +20,7 @@ import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.DefaultConsumer; +import com.rabbitmq.client.DefaultSocketConfigurator; import com.rabbitmq.client.Envelope; import com.rabbitmq.client.Recoverable; import com.rabbitmq.client.RecoveryListener; @@ -30,6 +31,7 @@ import org.junit.Test; import java.io.IOException; +import java.net.Socket; import java.util.HashMap; import java.util.Map; import java.util.UUID; @@ -45,58 +47,63 @@ /** * Test to trigger and check the fix of https://github.com/rabbitmq/rabbitmq-java-client/issues/341. * Conditions: - * - client registers consumer and a call QoS after - * - client get many messages and the consumer is slow + * - client registers consumer + * - client get many messages as the consumer is slow * - the work pool queue is full, the reading thread is stuck * - more messages come from the network and saturates the TCP buffer * - the connection dies but the client doesn't detect it - * - acks of messages fail + * - sending in the consumer fails * - connection recovery is never triggered *

* The fix consists in triggering connection recovery when writing - * to the socket fails. As the socket is dead, the closing - * sequence can take some time, hence the setup of the shutdown - * listener, which avoids waiting for the socket termination by - * the OS (can take 15 minutes on linux). + * to the socket fails. */ public class NoAutoRecoveryWhenTcpWindowIsFullTest { - private static final int QOS_PREFETCH = 64; - private static final int NUM_MESSAGES_TO_PRODUCE = 100000; + private static final int NUM_MESSAGES_TO_PRODUCE = 50000; private static final int MESSAGE_PROCESSING_TIME_MS = 3000; + private static final byte[] MESSAGE_CONTENT = ("MESSAGE CONTENT " + NUM_MESSAGES_TO_PRODUCE).getBytes(); - private ExecutorService dispatchingService; - private ExecutorService producerService; - private ExecutorService shutdownService; + private ExecutorService executorService; private AutorecoveringConnection producingConnection; private AutorecoveringChannel producingChannel; private AutorecoveringConnection consumingConnection; private AutorecoveringChannel consumingChannel; - private CountDownLatch consumerRecoverOkLatch; + private CountDownLatch consumerOkLatch; @Before public void setUp() throws Exception { - dispatchingService = Executors.newSingleThreadExecutor(); - shutdownService = Executors.newSingleThreadExecutor(); - producerService = Executors.newSingleThreadExecutor(); + // we need several threads to publish, dispatch deliveries, handle RPC responses, etc. + executorService = Executors.newFixedThreadPool(10); final ConnectionFactory factory = TestUtils.connectionFactory(); + factory.setSocketConfigurator(new DefaultSocketConfigurator() { + + int DEFAULT_RECEIVE_BUFFER_SIZE = 43690; + + @Override + public void configure(Socket socket) throws IOException { + super.configure(socket); + socket.setReceiveBufferSize(DEFAULT_RECEIVE_BUFFER_SIZE); + } + }); factory.setAutomaticRecoveryEnabled(true); factory.setTopologyRecoveryEnabled(true); // we try to set the lower values for closing timeouts, etc. // this makes the test execute faster. - factory.setShutdownExecutor(shutdownService); - factory.setShutdownTimeout(10000); factory.setRequestedHeartbeat(5); - factory.setSharedExecutor(dispatchingService); - factory.setNetworkRecoveryInterval(1000); + factory.setSharedExecutor(executorService); + // we need the shutdown executor: channel shutting down depends on the work pool, + // which is full. Channel shutting down will time out with the shutdown executor + factory.setShutdownExecutor(executorService); + factory.setNetworkRecoveryInterval(2000); producingConnection = (AutorecoveringConnection) factory.newConnection("Producer Connection"); producingChannel = (AutorecoveringChannel) producingConnection.createChannel(); consumingConnection = (AutorecoveringConnection) factory.newConnection("Consuming Connection"); consumingChannel = (AutorecoveringChannel) consumingConnection.createChannel(); - consumerRecoverOkLatch = new CountDownLatch(1); + consumerOkLatch = new CountDownLatch(2); } @After @@ -104,9 +111,7 @@ public void tearDown() throws IOException { closeConnectionIfOpen(consumingConnection); closeConnectionIfOpen(producingConnection); - dispatchingService.shutdownNow(); - producerService.shutdownNow(); - shutdownService.shutdownNow(); + executorService.shutdownNow(); } @Test @@ -116,17 +121,17 @@ public void failureAndRecovery() throws IOException, InterruptedException { } final String queue = UUID.randomUUID().toString(); - final CountDownLatch latch = new CountDownLatch(1); + final CountDownLatch recoveryLatch = new CountDownLatch(1); consumingConnection.addRecoveryListener(new RecoveryListener() { @Override public void handleRecovery(Recoverable recoverable) { + recoveryLatch.countDown(); } @Override public void handleRecoveryStarted(Recoverable recoverable) { - latch.countDown(); } }); @@ -136,12 +141,12 @@ public void handleRecoveryStarted(Recoverable recoverable) { assertThat( "Connection should have been closed and should have recovered by now", - latch.await(60, TimeUnit.SECONDS), is(true) + recoveryLatch.await(60, TimeUnit.SECONDS), is(true) ); assertThat( "Consumer should have recovered by now", - latch.await(5, TimeUnit.SECONDS), is(true) + consumerOkLatch.await(5, TimeUnit.SECONDS), is(true) ); } @@ -158,12 +163,12 @@ private void declareQueue(final Channel channel, final String queue) throws IOEx private void produceMessagesInBackground(final Channel channel, final String queue) throws IOException { final AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder().deliveryMode(1).build(); - producerService.submit(new Callable() { + executorService.submit(new Callable() { @Override public Void call() throws Exception { for (int i = 0; i < NUM_MESSAGES_TO_PRODUCE; i++) { - channel.basicPublish("", queue, false, properties, ("MSG NUM" + i).getBytes()); + channel.basicPublish("", queue, false, properties, MESSAGE_CONTENT); } closeConnectionIfOpen(producingConnection); return null; @@ -172,36 +177,29 @@ public Void call() throws Exception { } private void startConsumer(final String queue) throws IOException { - consumingChannel.basicConsume(queue, false, "", false, false, null, new DefaultConsumer(consumingChannel) { + consumingChannel.basicConsume(queue, true, new DefaultConsumer(consumingChannel) { @Override - public void handleRecoverOk(String consumerTag) { - consumerRecoverOkLatch.countDown(); + public void handleConsumeOk(String consumerTag) { + consumerOkLatch.countDown(); } @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { consumerWork(); try { - consumingChannel.basicAck(envelope.getDeliveryTag(), false); + consumingChannel.basicPublish("", "", null, "".getBytes()); } catch (Exception e) { // application should handle writing exceptions } } }); - try { - Thread.sleep(500); - } catch (InterruptedException e) { - e.printStackTrace(); - } - consumingChannel.basicQos(QOS_PREFETCH); } private void consumerWork() { try { Thread.sleep(MESSAGE_PROCESSING_TIME_MS); } catch (InterruptedException e) { - e.printStackTrace(); } } } diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml index 4bd2e37606..ee88f442c2 100644 --- a/src/test/resources/logback-test.xml +++ b/src/test/resources/logback-test.xml @@ -5,7 +5,7 @@ - + \ No newline at end of file From 4e223b205cf2d347ae00ec69d79fed3d5e405862 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 12 Feb 2018 11:51:17 +0100 Subject: [PATCH 0702/2114] Add timeout to work pool enqueuing Making the work pool fail after it didn't manage to enqueue work for a given time makes the client more reactive to broker overload. Note this usually happens to clients that do not set QoS properly. Neverlethess, making the client as early as possible can avoid hard-to-debug connection failure. This complements the triggering of connection recovery on failed write operations. Work pool enqueueing timeout is usefull for NIO, where the same thread is used for both reading and writing (if the thread is stuck waiting on work pool enqueueing, no write operation can occur, and the TCP connection failure is never detected). [#154263515] Fixes #341 --- .../rabbitmq/client/ConnectionFactory.java | 31 +++++++++++++ .../rabbitmq/client/impl/AMQConnection.java | 11 +++-- .../com/rabbitmq/client/impl/ChannelN.java | 14 ++++-- .../client/impl/ConnectionParams.java | 9 ++++ .../client/impl/ConsumerWorkService.java | 10 ++-- .../com/rabbitmq/client/impl/WorkPool.java | 46 +++++++++++++++++-- .../client/impl/WorkPoolFullException.java | 22 ++++++++- .../rabbitmq/client/impl/WorkPoolTests.java | 2 +- ...NoAutoRecoveryWhenTcpWindowIsFullTest.java | 12 +++-- 9 files changed, 135 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index d07b2a4a4a..e12969b9de 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -81,6 +81,9 @@ public class ConnectionFactory implements Cloneable { /** The default network recovery interval: 5000 millis */ public static final long DEFAULT_NETWORK_RECOVERY_INTERVAL = 5000; + /** The default timeout for work pool enqueueing: no timeout */ + public static final int DEFAULT_WORK_POOL_TIMEOUT = -1; + private static final String PREFERRED_TLS_PROTOCOL = "TLSv1.2"; private static final String FALLBACK_TLS_PROTOCOL = "TLSv1"; @@ -138,6 +141,12 @@ public class ConnectionFactory implements Cloneable { */ private boolean channelShouldCheckRpcResponseType = false; + /** + * Timeout in ms for work pool enqueuing. + * @since 4.5.0 + */ + private int workPoolTimeout = DEFAULT_WORK_POOL_TIMEOUT; + /** @return the default host to use for connections */ public String getHost() { return host; @@ -974,6 +983,7 @@ public ConnectionParams params(ExecutorService consumerWorkServiceExecutor) { result.setHeartbeatExecutor(heartbeatExecutor); result.setChannelRpcTimeout(channelRpcTimeout); result.setChannelShouldCheckRpcResponseType(channelShouldCheckRpcResponseType); + result.setWorkPoolTimeout(workPoolTimeout); return result; } @@ -1270,4 +1280,25 @@ public void setChannelShouldCheckRpcResponseType(boolean channelShouldCheckRpcRe public boolean isChannelShouldCheckRpcResponseType() { return channelShouldCheckRpcResponseType; } + + /** + * Timeout (in ms) for work pool enqueueing. + * The {@link WorkPool} dispatches several types of responses + * from the broker (e.g. deliveries). A high-traffic + * client with slow consumers can exhaust the work pool and + * compromise the whole connection (by e.g. letting the broker + * saturate the receive TCP buffers). Setting a timeout + * would make the connection fail early and avoid hard-to-diagnose + * TCP connection failure. Note this shouldn't happen + * with clients that set appropriate QoS values. + * Default is no timeout. + * @param workPoolTimeout timeout in ms + */ + public void setWorkPoolTimeout(int workPoolTimeout) { + this.workPoolTimeout = workPoolTimeout; + } + + public int getWorkPoolTimeout() { + return workPoolTimeout; + } } diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index cee548d567..94fabe973f 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -64,6 +64,8 @@ public class AMQConnection extends ShutdownNotifierComponent implements Connecti private final ErrorOnWriteListener errorOnWriteListener; + private final int workPoolTimeout; + private final AtomicBoolean finalShutdownStarted = new AtomicBoolean(false); /** @@ -255,12 +257,12 @@ public AMQConnection(ConnectionParams params, FrameHandler frameHandler, Metrics new ErrorOnWriteListener() { @Override public void handle(Connection connection, IOException exception) { } - }; - + }; + this.workPoolTimeout = params.getWorkPoolTimeout(); } private void initializeConsumerWorkService() { - this._workService = new ConsumerWorkService(consumerWorkServiceExecutor, threadFactory, shutdownTimeout); + this._workService = new ConsumerWorkService(consumerWorkServiceExecutor, threadFactory, workPoolTimeout, shutdownTimeout); } private void initializeHeartbeatSender() { @@ -619,6 +621,9 @@ public boolean handleReadFrame(Frame frame) { try { readFrame(frame); return true; + } catch (WorkPoolFullException e) { + // work pool is full, we propagate this one. + throw e; } catch (Throwable ex) { try { handleFailure(ex); diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java index e690464d16..269a8df2fa 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelN.java @@ -387,6 +387,9 @@ private void releaseChannel() { if (callback != null) { try { this.dispatcher.handleCancel(callback, consumerTag); + } catch (WorkPoolFullException e) { + // couldn't enqueue in work pool, propagating + throw e; } catch (Throwable ex) { getConnection().getExceptionHandler().handleConsumerException(this, ex, @@ -445,10 +448,13 @@ protected void processDelivery(Command command, Basic.Deliver method) { // in case a manual ack in the callback, the stats will be able to record the ack metricsCollector.consumedMessage(this, m.getDeliveryTag(), m.getConsumerTag()); this.dispatcher.handleDelivery(callback, - m.getConsumerTag(), - envelope, - (BasicProperties) command.getContentHeader(), - command.getContentBody()); + m.getConsumerTag(), + envelope, + (BasicProperties) command.getContentHeader(), + command.getContentBody()); + } catch (WorkPoolFullException e) { + // couldn't enqueue in work pool, propagating + throw e; } catch (Throwable ex) { getConnection().getExceptionHandler().handleConsumerException(this, ex, diff --git a/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java b/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java index 08232437f3..efc57abe8a 100644 --- a/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java +++ b/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java @@ -45,6 +45,7 @@ public class ConnectionParams { private int channelRpcTimeout; private boolean channelShouldCheckRpcResponseType; private ErrorOnWriteListener errorOnWriteListener; + private int workPoolTimeout = -1; private ExceptionHandler exceptionHandler; private ThreadFactory threadFactory; @@ -222,4 +223,12 @@ public void setErrorOnWriteListener(ErrorOnWriteListener errorOnWriteListener) { public ErrorOnWriteListener getErrorOnWriteListener() { return errorOnWriteListener; } + + public void setWorkPoolTimeout(int workPoolTimeout) { + this.workPoolTimeout = workPoolTimeout; + } + + public int getWorkPoolTimeout() { + return workPoolTimeout; + } } diff --git a/src/main/java/com/rabbitmq/client/impl/ConsumerWorkService.java b/src/main/java/com/rabbitmq/client/impl/ConsumerWorkService.java index 744aa59416..6e8683137f 100644 --- a/src/main/java/com/rabbitmq/client/impl/ConsumerWorkService.java +++ b/src/main/java/com/rabbitmq/client/impl/ConsumerWorkService.java @@ -31,14 +31,18 @@ final public class ConsumerWorkService { private final WorkPool workPool; private final int shutdownTimeout; - public ConsumerWorkService(ExecutorService executor, ThreadFactory threadFactory, int shutdownTimeout) { + public ConsumerWorkService(ExecutorService executor, ThreadFactory threadFactory, int queueingTimeout, int shutdownTimeout) { this.privateExecutor = (executor == null); this.executor = (executor == null) ? Executors.newFixedThreadPool(DEFAULT_NUM_THREADS, threadFactory) - : executor; - this.workPool = new WorkPool(); + : executor; + this.workPool = new WorkPool(queueingTimeout); this.shutdownTimeout = shutdownTimeout; } + public ConsumerWorkService(ExecutorService executor, ThreadFactory threadFactory, int shutdownTimeout) { + this(executor, threadFactory, -1, shutdownTimeout); + } + public int getShutdownTimeout() { return shutdownTimeout; } diff --git a/src/main/java/com/rabbitmq/client/impl/WorkPool.java b/src/main/java/com/rabbitmq/client/impl/WorkPool.java index 106d885411..1117132db5 100644 --- a/src/main/java/com/rabbitmq/client/impl/WorkPool.java +++ b/src/main/java/com/rabbitmq/client/impl/WorkPool.java @@ -21,6 +21,9 @@ import java.util.Iterator; import java.util.Map; import java.util.Set; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Callable; +import java.util.concurrent.TimeUnit; /** *

This is a generic implementation of the channels specification @@ -61,6 +64,37 @@ public class WorkPool { private final Map> pool = new HashMap>(); /** Those keys which want limits to be removed. We do not limit queue size if this is non-empty. */ private final Set unlimited = new HashSet(); + private final EnqueueingCallback enqueueingCallback; + + public WorkPool(final int queueingTimeout) { + if (queueingTimeout > 0) { + this.enqueueingCallback = new EnqueueingCallback() { + @Override + public void enqueue(BlockingQueue queue, W item) { + try { + boolean offered = queue.offer(item, queueingTimeout, TimeUnit.MILLISECONDS); + if (!offered) { + throw new WorkPoolFullException("Could not enqueue in work pool after " + queueingTimeout + " ms."); + } + } catch (InterruptedException e) { + Thread.currentThread(); + } + } + }; + } else { + this.enqueueingCallback = new EnqueueingCallback() { + + @Override + public void enqueue(BlockingQueue queue, W item) { + try { + queue.put(item); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + }; + } + } /** * Add client key to pool of item queues, with an empty queue. @@ -178,11 +212,7 @@ public boolean addWorkItem(K key, W item) { } // The put operation may block. We need to make sure we are not holding the lock while that happens. if (queue != null) { - try { - queue.put(item); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } + enqueueingCallback.enqueue(queue, item); synchronized (this) { if (isDormant(key)) { @@ -243,4 +273,10 @@ private K readyToInProgress() { } return key; } + + private interface EnqueueingCallback { + + void enqueue(BlockingQueue queue, W item); + + } } diff --git a/src/main/java/com/rabbitmq/client/impl/WorkPoolFullException.java b/src/main/java/com/rabbitmq/client/impl/WorkPoolFullException.java index bbedc782bb..146d05f414 100644 --- a/src/main/java/com/rabbitmq/client/impl/WorkPoolFullException.java +++ b/src/main/java/com/rabbitmq/client/impl/WorkPoolFullException.java @@ -1,8 +1,26 @@ +// Copyright (c) 2018-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.impl; /** - * + * Exception thrown when {@link WorkPool} enqueueing times out. */ -public class WorkPoolFullException { +public class WorkPoolFullException extends RuntimeException { + public WorkPoolFullException(String msg) { + super(msg); + } } diff --git a/src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java b/src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java index 90739f4206..fec748d205 100644 --- a/src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java +++ b/src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java @@ -30,7 +30,7 @@ */ public class WorkPoolTests { - private final WorkPool pool = new WorkPool(); + private final WorkPool pool = new WorkPool(-1); /** * Test unknown key tolerated silently diff --git a/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java b/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java index 6fe1fe5fe0..9f6c381a75 100644 --- a/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java +++ b/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java @@ -24,6 +24,7 @@ import com.rabbitmq.client.Envelope; import com.rabbitmq.client.Recoverable; import com.rabbitmq.client.RecoveryListener; +import com.rabbitmq.client.impl.nio.NioParams; import com.rabbitmq.client.impl.recovery.AutorecoveringChannel; import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; import org.junit.After; @@ -79,6 +80,7 @@ public void setUp() throws Exception { final ConnectionFactory factory = TestUtils.connectionFactory(); factory.setSocketConfigurator(new DefaultSocketConfigurator() { + /* default value on a Linux platform */ int DEFAULT_RECEIVE_BUFFER_SIZE = 43690; @Override @@ -94,10 +96,15 @@ public void configure(Socket socket) throws IOException { factory.setRequestedHeartbeat(5); factory.setSharedExecutor(executorService); // we need the shutdown executor: channel shutting down depends on the work pool, - // which is full. Channel shutting down will time out with the shutdown executor + // which is full. Channel shutting down will time out with the shutdown executor. factory.setShutdownExecutor(executorService); factory.setNetworkRecoveryInterval(2000); + if (TestUtils.USE_NIO) { + factory.setWorkPoolTimeout(10 * 1000); + factory.setNioParams(new NioParams().setWriteQueueCapacity(10 * 1000 * 1000).setNbIoThreads(4)); + } + producingConnection = (AutorecoveringConnection) factory.newConnection("Producer Connection"); producingChannel = (AutorecoveringChannel) producingConnection.createChannel(); consumingConnection = (AutorecoveringConnection) factory.newConnection("Consuming Connection"); @@ -116,9 +123,6 @@ public void tearDown() throws IOException { @Test public void failureAndRecovery() throws IOException, InterruptedException { - if (TestUtils.USE_NIO) { - return; - } final String queue = UUID.randomUUID().toString(); final CountDownLatch recoveryLatch = new CountDownLatch(1); From 9387b9fd7b24764cb07c81402974e1f7e48f61b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 12 Feb 2018 15:32:29 +0100 Subject: [PATCH 0703/2114] Use try-with-resources in test --- .../rabbitmq/client/test/StrictExceptionHandlerTest.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/StrictExceptionHandlerTest.java b/src/test/java/com/rabbitmq/client/test/StrictExceptionHandlerTest.java index 5cc68d1eb3..3b09ede84b 100644 --- a/src/test/java/com/rabbitmq/client/test/StrictExceptionHandlerTest.java +++ b/src/test/java/com/rabbitmq/client/test/StrictExceptionHandlerTest.java @@ -39,6 +39,7 @@ public void tooLongClosingMessage() throws Exception { ConnectionFactory cf = TestUtils.connectionFactory(); final CountDownLatch latch = new CountDownLatch(1); cf.setExceptionHandler(new StrictExceptionHandler() { + @Override public void handleConsumerException(Channel channel, Throwable exception, Consumer consumer, String consumerTag, String methodName) { try { @@ -49,9 +50,7 @@ public void handleConsumerException(Channel channel, Throwable exception, Consum latch.countDown(); } }); - Connection c = null; - try { - c = cf.newConnection(); + try (Connection c = cf.newConnection()) { Channel channel = c.createChannel(); String queue = channel.queueDeclare().getQueue(); channel.basicConsume(queue, @@ -60,10 +59,6 @@ public void handleConsumerException(Channel channel, Throwable exception, Consum )); channel.basicPublish("", queue, null, new byte[0]); assertThat(latch.await(5, TimeUnit.SECONDS), is(true)); - } finally { - if (c != null) { - c.close(); - } } } From 2db37dbedd986526cdeb246e7ed7707ec0ca1a85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 13 Feb 2018 14:24:33 +0100 Subject: [PATCH 0704/2114] Deploy Javadoc to GitHub pages [#154631313] --- deploy-javadoc.sh | 45 ++++++++------------------------------------- 1 file changed, 8 insertions(+), 37 deletions(-) diff --git a/deploy-javadoc.sh b/deploy-javadoc.sh index 9c3444592f..41cfd1d055 100755 --- a/deploy-javadoc.sh +++ b/deploy-javadoc.sh @@ -1,43 +1,14 @@ #!/usr/bin/env bash -DEPLOY_PATH=/home/rabbitmq/extras/releases/rabbitmq-java-client/current-javadoc - -# RSync user/host to deploy to. Mandatory. -DEPLOY_USERHOST= - - -# Imitate make-style variable settings as arguments -while [[ $# -gt 0 ]] ; do - declare "$1" - shift -done - -mandatory_vars="DEPLOY_USERHOST" -optional_vars="DEPLOY_PATH" - -function die () { - echo "$@" 2>&1 - exit 1 -} - -# Check mandatory settings -for v in $mandatory_vars ; do - [[ -n "${!v}" ]] || die "$v not set" -done - -echo "Settings:" -for v in $mandatory_vars $optional_vars ; do - echo "${v}=${!v}" -done - -set -e -x +DEPLOY_DIRECTORY=api/4.x.x +TAG=$(git describe --exact-match --tags $(git log -n1 --pretty='%h')) mvn -q clean javadoc:javadoc -Dmaven.javadoc.failOnError=false - -ssh $DEPLOY_USERHOST \ - "rm -rf $DEPLOY_PATH; \ - mkdir -p $DEPLOY_PATH" - -rsync -rpl --exclude '*.sh' target/site/apidocs/ $DEPLOY_USERHOST:$DEPLOY_PATH +git co gh-pages +rm -rf $DEPLOY_DIRECTORY/* +cp -r target/site/apidocs/* $DEPLOY_DIRECTORY +git add $DEPLOY_DIRECTORY +git commit -m "Add Javadoc for $TAG" +git push origin gh-pages From e37f15f39be362d48d7360091a10d637b8cb6fa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 13 Feb 2018 14:37:56 +0100 Subject: [PATCH 0705/2114] Javadoc for 5.x is api/current [#154631313] --- deploy-javadoc.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy-javadoc.sh b/deploy-javadoc.sh index 41cfd1d055..46cfa7bd7c 100755 --- a/deploy-javadoc.sh +++ b/deploy-javadoc.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -DEPLOY_DIRECTORY=api/4.x.x +DEPLOY_DIRECTORY=api/current TAG=$(git describe --exact-match --tags $(git log -n1 --pretty='%h')) mvn -q clean javadoc:javadoc -Dmaven.javadoc.failOnError=false From fbd707c0539611044afcf79344cf6562448e68fd Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 14 Feb 2018 14:54:36 +0300 Subject: [PATCH 0706/2114] Wording, cosmetics --- ...NoAutoRecoveryWhenTcpWindowIsFullTest.java | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java b/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java index 9f6c381a75..1047dc4287 100644 --- a/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java +++ b/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java @@ -46,18 +46,24 @@ import static org.junit.Assert.assertThat; /** - * Test to trigger and check the fix of https://github.com/rabbitmq/rabbitmq-java-client/issues/341. - * Conditions: - * - client registers consumer - * - client get many messages as the consumer is slow - * - the work pool queue is full, the reading thread is stuck - * - more messages come from the network and saturates the TCP buffer - * - the connection dies but the client doesn't detect it - * - sending in the consumer fails - * - connection recovery is never triggered + * Test to trigger and check the fix of rabbitmq/rabbitmq-java-client#341, + * which can be summarized as + * + *

    + *
  • client registers a slow consumer in automatic acknowledgement mode
  • + *
  • there's a fast enough publisher
  • + *
  • the consumer gets flooded with deliveries
  • + *
  • the work pool queue is full, the reading thread is stuck
  • + *
  • more messages come from the network and it fills up the TCP buffer
  • + *
  • the connection is closed by the server due to missed heartbeats but the client doesn't detect it
  • + *
  • a write operation fails because the socket is closed
  • + *
  • connection recovery is never triggered
  • + *
+ * *

* The fix consists in triggering connection recovery when writing * to the socket fails. + *

*/ public class NoAutoRecoveryWhenTcpWindowIsFullTest { @@ -80,7 +86,7 @@ public void setUp() throws Exception { final ConnectionFactory factory = TestUtils.connectionFactory(); factory.setSocketConfigurator(new DefaultSocketConfigurator() { - /* default value on a Linux platform */ + /* default value on Linux */ int DEFAULT_RECEIVE_BUFFER_SIZE = 43690; @Override From fdda435e99bc73de64582ae6735771d46c3870e0 Mon Sep 17 00:00:00 2001 From: Nick Johnson Date: Wed, 14 Feb 2018 10:00:26 -0800 Subject: [PATCH 0707/2114] Get credentials from a CredentialsProvider, with a default implementation that simply tracks a static username and password. Useful for reconnect scenarios where the username or password might have changed between the connect & reconnect. --- .../rabbitmq/client/ConnectionFactory.java | 63 +++++++++++++------ .../rabbitmq/client/impl/AMQConnection.java | 14 ++--- .../impl/AbstractCredentialsProvider.java | 39 ++++++++++++ .../client/impl/ConnectionParams.java | 19 ++---- .../client/impl/CredentialsProvider.java | 18 ++++++ .../impl/DefaultCredentialsProvider.java | 32 ++++++++++ 6 files changed, 146 insertions(+), 39 deletions(-) create mode 100644 src/main/java/com/rabbitmq/client/impl/AbstractCredentialsProvider.java create mode 100644 src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java create mode 100644 src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index d07b2a4a4a..37b80bb31f 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -15,25 +15,40 @@ package com.rabbitmq.client; -import com.rabbitmq.client.impl.*; +import static java.util.concurrent.TimeUnit.*; + +import com.rabbitmq.client.impl.AMQConnection; +import com.rabbitmq.client.impl.ConnectionParams; +import com.rabbitmq.client.impl.CredentialsProvider; +import com.rabbitmq.client.impl.DefaultCredentialsProvider; +import com.rabbitmq.client.impl.DefaultExceptionHandler; +import com.rabbitmq.client.impl.FrameHandler; +import com.rabbitmq.client.impl.FrameHandlerFactory; +import com.rabbitmq.client.impl.SocketFrameHandlerFactory; import com.rabbitmq.client.impl.nio.NioParams; import com.rabbitmq.client.impl.nio.SocketChannelFrameHandlerFactory; import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; - -import javax.net.SocketFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.TrustManager; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.net.URLDecoder; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; -import java.util.*; -import java.util.concurrent.*; - -import static java.util.concurrent.TimeUnit.*; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeoutException; +import javax.net.SocketFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; /** * Convenience "factory" class to facilitate opening a {@link Connection} to an AMQP broker. @@ -85,8 +100,6 @@ public class ConnectionFactory implements Cloneable { private static final String FALLBACK_TLS_PROTOCOL = "TLSv1"; - private String username = DEFAULT_USER; - private String password = DEFAULT_PASS; private String virtualHost = DEFAULT_VHOST; private String host = DEFAULT_HOST; private int port = USE_DEFAULT_PORT; @@ -107,6 +120,11 @@ public class ConnectionFactory implements Cloneable { private ScheduledExecutorService heartbeatExecutor; private SocketConfigurator socketConf = new DefaultSocketConfigurator(); private ExceptionHandler exceptionHandler = new DefaultExceptionHandler(); + private CredentialsProvider credentialsProv = new DefaultCredentialsProvider(); + { + credentialsProv.setUsername(DEFAULT_USER); + credentialsProv.setPassword(DEFAULT_PASS); + } private boolean automaticRecovery = true; private boolean topologyRecovery = true; @@ -172,7 +190,7 @@ public void setPort(int port) { * @return the AMQP user name to use when connecting to the broker */ public String getUsername() { - return this.username; + return credentialsProv.getUsername(); } /** @@ -180,7 +198,7 @@ public String getUsername() { * @param username the AMQP user name to use when connecting to the broker */ public void setUsername(String username) { - this.username = username; + credentialsProv.setUsername(username); } /** @@ -188,7 +206,7 @@ public void setUsername(String username) { * @return the password to use when connecting to the broker */ public String getPassword() { - return this.password; + return credentialsProv.getPassword(); } /** @@ -196,9 +214,19 @@ public String getPassword() { * @param password the password to use when connecting to the broker */ public void setPassword(String password) { - this.password = password; + credentialsProv.setPassword(password); } + /** + * Set a custom credentials provider. + * @param credentialsProvider The custom implementation of CredentialsProvider to use when connecting to the broker. + * @see com.rabbitmq.client.impl.DefaultCredentialsProvider + * @see com.rabbitmq.client.impl.AbstractCredentialsProvider + */ + public void setCredentialsProvider(CredentialsProvider credentialsProvider) { + this.credentialsProv = credentialsProvider; + } + /** * Retrieve the virtual host. * @return the virtual host to use when connecting to the broker @@ -954,8 +982,7 @@ public Connection newConnection(ExecutorService executor, AddressResolver addres public ConnectionParams params(ExecutorService consumerWorkServiceExecutor) { ConnectionParams result = new ConnectionParams(); - result.setUsername(username); - result.setPassword(password); + result.setCredentialsProvider(credentialsProv); result.setConsumerWorkServiceExecutor(consumerWorkServiceExecutor); result.setVirtualHost(virtualHost); result.setClientProperties(getClientProperties()); diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index 0d89880046..b19cc2d12e 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -129,8 +129,7 @@ public static Map defaultClientProperties() { private final int requestedFrameMax; private final int handshakeTimeout; private final int shutdownTimeout; - private final String username; - private final String password; + private final CredentialsProvider credentialsProvider; private final Collection blockedListeners = new CopyOnWriteArrayList(); protected final MetricsCollector metricsCollector; private final int channelRpcTimeout; @@ -209,8 +208,7 @@ public AMQConnection(ConnectionParams params, FrameHandler frameHandler) { public AMQConnection(ConnectionParams params, FrameHandler frameHandler, MetricsCollector metricsCollector) { checkPreconditions(); - this.username = params.getUsername(); - this.password = params.getPassword(); + this.credentialsProvider = params.getCredentialsProvider(); this._frameHandler = frameHandler; this._virtualHost = params.getVirtualHost(); this._exceptionHandler = params.getExceptionHandler(); @@ -323,8 +321,10 @@ public void start() "server offered [" + connStart.getMechanisms() + "]"); } + String username = credentialsProvider.getUsername(); + String password = credentialsProvider.getPassword(); LongString challenge = null; - LongString response = sm.handleChallenge(null, this.username, this.password); + LongString response = sm.handleChallenge(null, username, password); do { Method method = (challenge == null) @@ -341,7 +341,7 @@ public void start() connTune = (AMQP.Connection.Tune) serverResponse; } else { challenge = ((AMQP.Connection.Secure) serverResponse).getChallenge(); - response = sm.handleChallenge(challenge, this.username, this.password); + response = sm.handleChallenge(challenge, username, password); } } catch (ShutdownSignalException e) { Method shutdownMethod = e.getReason(); @@ -1021,7 +1021,7 @@ public AMQCommand transformReply(AMQCommand command) { @Override public String toString() { final String virtualHost = "/".equals(_virtualHost) ? _virtualHost : "/" + _virtualHost; - return "amqp://" + this.username + "@" + getHostAddress() + ":" + getPort() + virtualHost; + return "amqp://" + credentialsProvider.getUsername() + "@" + getHostAddress() + ":" + getPort() + virtualHost; } private String getHostAddress() { diff --git a/src/main/java/com/rabbitmq/client/impl/AbstractCredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/AbstractCredentialsProvider.java new file mode 100644 index 0000000000..609c5a31e1 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/AbstractCredentialsProvider.java @@ -0,0 +1,39 @@ +package com.rabbitmq.client.impl; + +/** + * Base class for extending to implement a concrete CredentialsProvider, used + * when creating connections to the broker or reconnecting during recovery. + */ +public abstract class AbstractCredentialsProvider implements CredentialsProvider { + + /* (non-Javadoc) + * @see com.rabbitmq.client.impl.CredentialsProvider#getUsername() + */ + @Override + public abstract String getUsername(); + + /* (non-Javadoc) + * @see com.rabbitmq.client.impl.CredentialsProvider#getPassword() + */ + @Override + public abstract String getPassword(); + + /** + * Default implementation throws UnsupportedOperationException() but can be overridden for + * classes which support setting a static username. + */ + @Override + public void setUsername(String username) { + throw new UnsupportedOperationException(); + } + + /** + * Default implementation throws UnsupportedOperationException() but can be overridden for + * classes which support setting a static password. + */ + @Override + public void setPassword(String password) { + throw new UnsupportedOperationException(); + } + +} diff --git a/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java b/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java index 40a82f2ffc..93dcafc679 100644 --- a/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java +++ b/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java @@ -26,8 +26,7 @@ import java.util.concurrent.ThreadFactory; public class ConnectionParams { - private String username; - private String password; + private CredentialsProvider credentialsProvider; private ExecutorService consumerWorkServiceExecutor; private ScheduledExecutorService heartbeatExecutor; private ExecutorService shutdownExecutor; @@ -50,12 +49,8 @@ public class ConnectionParams { public ConnectionParams() {} - public String getUsername() { - return username; - } - - public String getPassword() { - return password; + public CredentialsProvider getCredentialsProvider() { + return credentialsProvider; } public ExecutorService getConsumerWorkServiceExecutor() { @@ -130,12 +125,8 @@ public boolean channelShouldCheckRpcResponseType() { return channelShouldCheckRpcResponseType; } - public void setUsername(String username) { - this.username = username; - } - - public void setPassword(String password) { - this.password = password; + public void setCredentialsProvider(CredentialsProvider credentialsProvider) { + this.credentialsProvider = credentialsProvider; } public void setConsumerWorkServiceExecutor(ExecutorService consumerWorkServiceExecutor) { diff --git a/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java new file mode 100644 index 0000000000..7b6361aa9d --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java @@ -0,0 +1,18 @@ +package com.rabbitmq.client.impl; + +/** + * Provider interface for establishing credentials for connecting to the broker. Especially useful + * for situations where credentials might change before a recovery takes place or where it is + * convenient to plug in an outside custom implementation. + */ +public interface CredentialsProvider { + + String getUsername(); + + String getPassword(); + + void setUsername(String username); + + void setPassword(String password); + +} \ No newline at end of file diff --git a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java new file mode 100644 index 0000000000..fd43c678f6 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java @@ -0,0 +1,32 @@ +package com.rabbitmq.client.impl; + +/** + * Default implementation of a CredentialsProvider which simply holds a static + * username and password. + */ +public class DefaultCredentialsProvider extends AbstractCredentialsProvider { + + protected String username; + protected String password; + + @Override + public String getUsername() { + return username; + } + + @Override + public String getPassword() { + return password; + } + + @Override + public void setUsername(String username) { + this.username = username; + } + + @Override + public void setPassword(String password) { + this.password = password; + } + +} From bd069581177365379b0078445218da23598fc753 Mon Sep 17 00:00:00 2001 From: Nick Johnson Date: Wed, 14 Feb 2018 12:10:38 -0800 Subject: [PATCH 0708/2114] Fixes two broken tests; now that the username and password aren't simple (and immutable) strings, a .clone() operation needs to specifically return a clone of the CredentialsProvider that can be modified with setUsername/setPassword without affecting the original instance. --- src/main/java/com/rabbitmq/client/ConnectionFactory.java | 4 +++- .../client/impl/AbstractCredentialsProvider.java | 9 +++++++++ .../com/rabbitmq/client/impl/CredentialsProvider.java | 6 +++++- .../rabbitmq/client/impl/DefaultCredentialsProvider.java | 2 +- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 37b80bb31f..945ee99dd6 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -1080,7 +1080,9 @@ protected AddressResolver createAddressResolver(List
addresses) { @Override public ConnectionFactory clone(){ try { - return (ConnectionFactory)super.clone(); + ConnectionFactory clone = (ConnectionFactory)super.clone(); + clone.credentialsProv = (CredentialsProvider)clone.credentialsProv.clone(); + return clone; } catch (CloneNotSupportedException e) { throw new Error(e); } diff --git a/src/main/java/com/rabbitmq/client/impl/AbstractCredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/AbstractCredentialsProvider.java index 609c5a31e1..a6e314906c 100644 --- a/src/main/java/com/rabbitmq/client/impl/AbstractCredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/AbstractCredentialsProvider.java @@ -35,5 +35,14 @@ public void setUsername(String username) { public void setPassword(String password) { throw new UnsupportedOperationException(); } + + /** + * Default clone() behavior is to call Object's clone() method. If you need more custom + * behavior, override clone(). + */ + @Override + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } } diff --git a/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java index 7b6361aa9d..97de85ced0 100644 --- a/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java @@ -4,8 +4,10 @@ * Provider interface for establishing credentials for connecting to the broker. Especially useful * for situations where credentials might change before a recovery takes place or where it is * convenient to plug in an outside custom implementation. + * + * @see com.rabbitmq.client.impl.AbstractCredentialsProvider */ -public interface CredentialsProvider { +public interface CredentialsProvider extends Cloneable { String getUsername(); @@ -15,4 +17,6 @@ public interface CredentialsProvider { void setPassword(String password); + Object clone() throws CloneNotSupportedException; + } \ No newline at end of file diff --git a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java index fd43c678f6..e8639114fa 100644 --- a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java @@ -28,5 +28,5 @@ public void setUsername(String username) { public void setPassword(String password) { this.password = password; } - + } From ea66f12abca2bd1fbf42ae50d608691bfd04cfbe Mon Sep 17 00:00:00 2001 From: Nick Johnson Date: Wed, 14 Feb 2018 14:25:13 -0800 Subject: [PATCH 0709/2114] Adds tests. --- .../client/test/ConnectionFactoryTest.java | 29 +++++++++++++- .../test/functional/ConnectionRecovery.java | 39 ++++++++++++++++++- 2 files changed, 66 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java b/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java index 21a201f253..cc81cc13a2 100644 --- a/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java +++ b/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java @@ -21,6 +21,7 @@ import com.rabbitmq.client.MetricsCollector; import com.rabbitmq.client.impl.AMQConnection; import com.rabbitmq.client.impl.ConnectionParams; +import com.rabbitmq.client.impl.CredentialsProvider; import com.rabbitmq.client.impl.FrameHandler; import com.rabbitmq.client.impl.FrameHandlerFactory; import org.junit.Test; @@ -29,8 +30,9 @@ import java.util.Queue; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicBoolean; -import static org.junit.Assert.assertSame; +import static org.junit.Assert.*; import static org.mockito.Mockito.*; public class ConnectionFactoryTest { @@ -62,5 +64,30 @@ protected synchronized FrameHandlerFactory createFrameHandlerFactory() throws IO ); assertSame(connectionThatSucceeds, returnedConnection); } + + // see https://github.com/rabbitmq/rabbitmq-java-client/pull/350 + @Test public void customizeCredentialsProvider() throws Exception { + final CredentialsProvider provider = mock(CredentialsProvider.class); + final AMQConnection connection = mock(AMQConnection.class); + final AtomicBoolean createCalled = new AtomicBoolean(false); + + ConnectionFactory connectionFactory = new ConnectionFactory() { + @Override + protected AMQConnection createConnection(ConnectionParams params, FrameHandler frameHandler, + MetricsCollector metricsCollector) { + assertSame(provider, params.getCredentialsProvider()); + createCalled.set(true); + return connection; + } + }; + connectionFactory.setCredentialsProvider(provider); + connectionFactory.setAutomaticRecoveryEnabled(false); + + doNothing().when(connection).start(); + + Connection returnedConnection = connectionFactory.newConnection(); + assertSame(returnedConnection, connection); + assertTrue(createCalled.get()); + } } diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java index 1ad6feb960..25d36ed805 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -16,7 +16,7 @@ package com.rabbitmq.client.test.functional; import com.rabbitmq.client.*; - +import com.rabbitmq.client.impl.AbstractCredentialsProvider; import com.rabbitmq.client.impl.NetworkConnection; import com.rabbitmq.client.impl.recovery.*; import com.rabbitmq.client.test.BrokerTestCase; @@ -34,6 +34,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; import static org.junit.Assert.*; @@ -121,6 +122,42 @@ public class ConnectionRecovery extends BrokerTestCase { c.abort(); } } + + // See https://github.com/rabbitmq/rabbitmq-java-client/pull/350 . We want to request fresh creds when recovering. + @Test public void connectionRecoveryRequestsCredentialsAgain() throws Exception { + ConnectionFactory cf = buildConnectionFactoryWithRecoveryEnabled(false); + final String username = cf.getUsername(); + final String password = cf.getPassword(); + final AtomicLong usernameRequested = new AtomicLong(0); + final AtomicLong passwordRequested = new AtomicLong(0); + cf.setCredentialsProvider(new AbstractCredentialsProvider() { + + @Override + public String getUsername() { + usernameRequested.incrementAndGet(); + return username; + } + + @Override + public String getPassword() { + passwordRequested.incrementAndGet(); + return password; + } + }); + RecoverableConnection c = (RecoverableConnection) cf.newConnection(); + try { + assertTrue(c.isOpen()); + assertEquals(1, usernameRequested.get()); + assertEquals(1, passwordRequested.get()); + + closeAndWaitForRecovery(c); + assertTrue(c.isOpen()); + assertEquals(2, usernameRequested.get()); + assertEquals(2, passwordRequested.get()); + } finally { + c.abort(); + } + } // see https://github.com/rabbitmq/rabbitmq-java-client/issues/135 @Test public void thatShutdownHooksOnConnectionFireBeforeRecoveryStarts() throws IOException, InterruptedException { From c2551b0eadd3d21a987e8f0192523f6898fbbe04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 15 Feb 2018 09:41:00 +0100 Subject: [PATCH 0710/2114] Add ErrorOnWriteListener property to ConnectionFactory This way connection recovery triggering on write can be disabled or customised. [#154263515] References #341 --- .../rabbitmq/client/ConnectionFactory.java | 24 +++++++++++++++++++ .../client/impl/ErrorOnWriteListener.java | 4 +++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index e12969b9de..8a0e6b5327 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -141,6 +141,14 @@ public class ConnectionFactory implements Cloneable { */ private boolean channelShouldCheckRpcResponseType = false; + /** + * Listener called when a connection gets an IO error trying to write on the socket. + * Default listener triggers connection recovery asynchronously and propagates + * the exception. + * @since 4.5.0 + */ + private ErrorOnWriteListener errorOnWriteListener; + /** * Timeout in ms for work pool enqueuing. * @since 4.5.0 @@ -984,6 +992,7 @@ public ConnectionParams params(ExecutorService consumerWorkServiceExecutor) { result.setChannelRpcTimeout(channelRpcTimeout); result.setChannelShouldCheckRpcResponseType(channelShouldCheckRpcResponseType); result.setWorkPoolTimeout(workPoolTimeout); + result.setErrorOnWriteListener(errorOnWriteListener); return result; } @@ -1292,7 +1301,9 @@ public boolean isChannelShouldCheckRpcResponseType() { * TCP connection failure. Note this shouldn't happen * with clients that set appropriate QoS values. * Default is no timeout. + * * @param workPoolTimeout timeout in ms + * @since 4.5.0 */ public void setWorkPoolTimeout(int workPoolTimeout) { this.workPoolTimeout = workPoolTimeout; @@ -1301,4 +1312,17 @@ public void setWorkPoolTimeout(int workPoolTimeout) { public int getWorkPoolTimeout() { return workPoolTimeout; } + + /** + * Set a listener to be called when connection gets an IO error trying to write on the socket. + * Default listener triggers connection recovery asynchronously and propagates + * the exception. Override the default listener to disable or + * customise automatic connection triggering on write operations. + * + * @param errorOnWriteListener the listener + * @since 4.5.0 + */ + public void setErrorOnWriteListener(ErrorOnWriteListener errorOnWriteListener) { + this.errorOnWriteListener = errorOnWriteListener; + } } diff --git a/src/main/java/com/rabbitmq/client/impl/ErrorOnWriteListener.java b/src/main/java/com/rabbitmq/client/impl/ErrorOnWriteListener.java index b912dd07a0..84d493984a 100644 --- a/src/main/java/com/rabbitmq/client/impl/ErrorOnWriteListener.java +++ b/src/main/java/com/rabbitmq/client/impl/ErrorOnWriteListener.java @@ -20,8 +20,10 @@ import java.io.IOException; /** - * Listener called when a connection gets an error trying to write on the socket. + * Listener called when a connection gets an IO error trying to write on the socket. * This can be used to trigger connection recovery. + * + * @since 4.5.0 */ public interface ErrorOnWriteListener { From 4644e17ed6ae124eba50d7662a342a6b98c9b730 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 15 Feb 2018 11:29:09 +0100 Subject: [PATCH 0711/2114] Polish introduction of CredentialsProvider CredentialsProvider interface is reduced to the bare minimum of methods (getting username and password). Test in connection recovery test suite is fixed, as NIO mode can retrieve username several times for logging. References #350 --- .../rabbitmq/client/ConnectionFactory.java | 63 ++++++++++--------- .../rabbitmq/client/impl/AMQConnection.java | 2 +- .../impl/AbstractCredentialsProvider.java | 48 -------------- .../client/impl/CredentialsProvider.java | 12 +--- .../impl/DefaultCredentialsProvider.java | 25 ++++---- .../test/functional/ConnectionRecovery.java | 24 ++++--- .../test/functional/SaslMechanisms.java | 2 +- 7 files changed, 62 insertions(+), 114 deletions(-) delete mode 100644 src/main/java/com/rabbitmq/client/impl/AbstractCredentialsProvider.java diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 945ee99dd6..e219b01ffc 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -53,7 +53,6 @@ /** * Convenience "factory" class to facilitate opening a {@link Connection} to an AMQP broker. */ - public class ConnectionFactory implements Cloneable { /** Default user name */ @@ -100,34 +99,30 @@ public class ConnectionFactory implements Cloneable { private static final String FALLBACK_TLS_PROTOCOL = "TLSv1"; - private String virtualHost = DEFAULT_VHOST; - private String host = DEFAULT_HOST; - private int port = USE_DEFAULT_PORT; - private int requestedChannelMax = DEFAULT_CHANNEL_MAX; - private int requestedFrameMax = DEFAULT_FRAME_MAX; - private int requestedHeartbeat = DEFAULT_HEARTBEAT; - private int connectionTimeout = DEFAULT_CONNECTION_TIMEOUT; - private int handshakeTimeout = DEFAULT_HANDSHAKE_TIMEOUT; - private int shutdownTimeout = DEFAULT_SHUTDOWN_TIMEOUT; - private Map _clientProperties = AMQConnection.defaultClientProperties(); - private SocketFactory factory = SocketFactory.getDefault(); - private SaslConfig saslConfig = DefaultSaslConfig.PLAIN; + private String virtualHost = DEFAULT_VHOST; + private String host = DEFAULT_HOST; + private int port = USE_DEFAULT_PORT; + private int requestedChannelMax = DEFAULT_CHANNEL_MAX; + private int requestedFrameMax = DEFAULT_FRAME_MAX; + private int requestedHeartbeat = DEFAULT_HEARTBEAT; + private int connectionTimeout = DEFAULT_CONNECTION_TIMEOUT; + private int handshakeTimeout = DEFAULT_HANDSHAKE_TIMEOUT; + private int shutdownTimeout = DEFAULT_SHUTDOWN_TIMEOUT; + private Map _clientProperties = AMQConnection.defaultClientProperties(); + private SocketFactory factory = SocketFactory.getDefault(); + private SaslConfig saslConfig = DefaultSaslConfig.PLAIN; private ExecutorService sharedExecutor; - private ThreadFactory threadFactory = Executors.defaultThreadFactory(); + private ThreadFactory threadFactory = Executors.defaultThreadFactory(); // minimises the number of threads rapid closure of many // connections uses, see rabbitmq/rabbitmq-java-client#86 private ExecutorService shutdownExecutor; private ScheduledExecutorService heartbeatExecutor; - private SocketConfigurator socketConf = new DefaultSocketConfigurator(); - private ExceptionHandler exceptionHandler = new DefaultExceptionHandler(); - private CredentialsProvider credentialsProv = new DefaultCredentialsProvider(); - { - credentialsProv.setUsername(DEFAULT_USER); - credentialsProv.setPassword(DEFAULT_PASS); - } + private SocketConfigurator socketConf = new DefaultSocketConfigurator(); + private ExceptionHandler exceptionHandler = new DefaultExceptionHandler(); + private CredentialsProvider credentialsProvider = new DefaultCredentialsProvider(DEFAULT_USER, DEFAULT_PASS); - private boolean automaticRecovery = true; - private boolean topologyRecovery = true; + private boolean automaticRecovery = true; + private boolean topologyRecovery = true; // long is used to make sure the users can use both ints // and longs safely. It is unlikely that anybody'd need @@ -190,7 +185,7 @@ public void setPort(int port) { * @return the AMQP user name to use when connecting to the broker */ public String getUsername() { - return credentialsProv.getUsername(); + return credentialsProvider.getUsername(); } /** @@ -198,7 +193,10 @@ public String getUsername() { * @param username the AMQP user name to use when connecting to the broker */ public void setUsername(String username) { - credentialsProv.setUsername(username); + this.credentialsProvider = new DefaultCredentialsProvider( + username, + this.credentialsProvider.getPassword() + ); } /** @@ -206,7 +204,7 @@ public void setUsername(String username) { * @return the password to use when connecting to the broker */ public String getPassword() { - return credentialsProv.getPassword(); + return credentialsProvider.getPassword(); } /** @@ -214,17 +212,21 @@ public String getPassword() { * @param password the password to use when connecting to the broker */ public void setPassword(String password) { - credentialsProv.setPassword(password); + this.credentialsProvider = new DefaultCredentialsProvider( + this.credentialsProvider.getUsername(), + password + ); } /** * Set a custom credentials provider. + * Default implementation uses static username and password. * @param credentialsProvider The custom implementation of CredentialsProvider to use when connecting to the broker. * @see com.rabbitmq.client.impl.DefaultCredentialsProvider - * @see com.rabbitmq.client.impl.AbstractCredentialsProvider + * @since 4.5.0 */ public void setCredentialsProvider(CredentialsProvider credentialsProvider) { - this.credentialsProv = credentialsProvider; + this.credentialsProvider = credentialsProvider; } /** @@ -982,7 +984,7 @@ public Connection newConnection(ExecutorService executor, AddressResolver addres public ConnectionParams params(ExecutorService consumerWorkServiceExecutor) { ConnectionParams result = new ConnectionParams(); - result.setCredentialsProvider(credentialsProv); + result.setCredentialsProvider(credentialsProvider); result.setConsumerWorkServiceExecutor(consumerWorkServiceExecutor); result.setVirtualHost(virtualHost); result.setClientProperties(getClientProperties()); @@ -1081,7 +1083,6 @@ protected AddressResolver createAddressResolver(List
addresses) { @Override public ConnectionFactory clone(){ try { ConnectionFactory clone = (ConnectionFactory)super.clone(); - clone.credentialsProv = (CredentialsProvider)clone.credentialsProv.clone(); return clone; } catch (CloneNotSupportedException e) { throw new Error(e); diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index b19cc2d12e..d415ef74f6 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -1021,7 +1021,7 @@ public AMQCommand transformReply(AMQCommand command) { @Override public String toString() { final String virtualHost = "/".equals(_virtualHost) ? _virtualHost : "/" + _virtualHost; - return "amqp://" + credentialsProvider.getUsername() + "@" + getHostAddress() + ":" + getPort() + virtualHost; + return "amqp://" + this.credentialsProvider.getUsername() + "@" + getHostAddress() + ":" + getPort() + virtualHost; } private String getHostAddress() { diff --git a/src/main/java/com/rabbitmq/client/impl/AbstractCredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/AbstractCredentialsProvider.java deleted file mode 100644 index a6e314906c..0000000000 --- a/src/main/java/com/rabbitmq/client/impl/AbstractCredentialsProvider.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.rabbitmq.client.impl; - -/** - * Base class for extending to implement a concrete CredentialsProvider, used - * when creating connections to the broker or reconnecting during recovery. - */ -public abstract class AbstractCredentialsProvider implements CredentialsProvider { - - /* (non-Javadoc) - * @see com.rabbitmq.client.impl.CredentialsProvider#getUsername() - */ - @Override - public abstract String getUsername(); - - /* (non-Javadoc) - * @see com.rabbitmq.client.impl.CredentialsProvider#getPassword() - */ - @Override - public abstract String getPassword(); - - /** - * Default implementation throws UnsupportedOperationException() but can be overridden for - * classes which support setting a static username. - */ - @Override - public void setUsername(String username) { - throw new UnsupportedOperationException(); - } - - /** - * Default implementation throws UnsupportedOperationException() but can be overridden for - * classes which support setting a static password. - */ - @Override - public void setPassword(String password) { - throw new UnsupportedOperationException(); - } - - /** - * Default clone() behavior is to call Object's clone() method. If you need more custom - * behavior, override clone(). - */ - @Override - public Object clone() throws CloneNotSupportedException { - return super.clone(); - } - -} diff --git a/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java index 97de85ced0..1b1c308cd6 100644 --- a/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java @@ -4,19 +4,13 @@ * Provider interface for establishing credentials for connecting to the broker. Especially useful * for situations where credentials might change before a recovery takes place or where it is * convenient to plug in an outside custom implementation. - * - * @see com.rabbitmq.client.impl.AbstractCredentialsProvider + * + * @since 4.5.0 */ -public interface CredentialsProvider extends Cloneable { +public interface CredentialsProvider { String getUsername(); String getPassword(); - void setUsername(String username); - - void setPassword(String password); - - Object clone() throws CloneNotSupportedException; - } \ No newline at end of file diff --git a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java index e8639114fa..f743a14618 100644 --- a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java @@ -3,12 +3,19 @@ /** * Default implementation of a CredentialsProvider which simply holds a static * username and password. + * + * @since 4.5.0 */ -public class DefaultCredentialsProvider extends AbstractCredentialsProvider { +public class DefaultCredentialsProvider implements CredentialsProvider { + + private final String username; + private final String password; + + public DefaultCredentialsProvider(String username, String password) { + this.username = username; + this.password = password; + } - protected String username; - protected String password; - @Override public String getUsername() { return username; @@ -19,14 +26,4 @@ public String getPassword() { return password; } - @Override - public void setUsername(String username) { - this.username = username; - } - - @Override - public void setPassword(String password) { - this.password = password; - } - } diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java index 25d36ed805..8aa9d20c4f 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -16,7 +16,7 @@ package com.rabbitmq.client.test.functional; import com.rabbitmq.client.*; -import com.rabbitmq.client.impl.AbstractCredentialsProvider; +import com.rabbitmq.client.impl.CredentialsProvider; import com.rabbitmq.client.impl.NetworkConnection; import com.rabbitmq.client.impl.recovery.*; import com.rabbitmq.client.test.BrokerTestCase; @@ -37,6 +37,8 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; +import static org.hamcrest.Matchers.is; import static org.junit.Assert.*; @SuppressWarnings("ThrowFromFinallyBlock") @@ -123,14 +125,15 @@ public class ConnectionRecovery extends BrokerTestCase { } } - // See https://github.com/rabbitmq/rabbitmq-java-client/pull/350 . We want to request fresh creds when recovering. + // See https://github.com/rabbitmq/rabbitmq-java-client/pull/350 . + // We want to request fresh creds when recovering. @Test public void connectionRecoveryRequestsCredentialsAgain() throws Exception { ConnectionFactory cf = buildConnectionFactoryWithRecoveryEnabled(false); final String username = cf.getUsername(); final String password = cf.getPassword(); - final AtomicLong usernameRequested = new AtomicLong(0); - final AtomicLong passwordRequested = new AtomicLong(0); - cf.setCredentialsProvider(new AbstractCredentialsProvider() { + final AtomicInteger usernameRequested = new AtomicInteger(0); + final AtomicInteger passwordRequested = new AtomicInteger(0); + cf.setCredentialsProvider(new CredentialsProvider() { @Override public String getUsername() { @@ -147,13 +150,14 @@ public String getPassword() { RecoverableConnection c = (RecoverableConnection) cf.newConnection(); try { assertTrue(c.isOpen()); - assertEquals(1, usernameRequested.get()); - assertEquals(1, passwordRequested.get()); - + assertThat(usernameRequested.get(), is(1)); + assertThat(passwordRequested.get(), is(1)); + closeAndWaitForRecovery(c); assertTrue(c.isOpen()); - assertEquals(2, usernameRequested.get()); - assertEquals(2, passwordRequested.get()); + // username is requested in AMQConnection#toString, so it can be accessed at any time + assertThat(usernameRequested.get(), greaterThanOrEqualTo(2)); + assertThat(passwordRequested.get(), is(2)); } finally { c.abort(); } diff --git a/src/test/java/com/rabbitmq/client/test/functional/SaslMechanisms.java b/src/test/java/com/rabbitmq/client/test/functional/SaslMechanisms.java index 046f7e925d..d4dcf9130d 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/SaslMechanisms.java +++ b/src/test/java/com/rabbitmq/client/test/functional/SaslMechanisms.java @@ -122,7 +122,7 @@ public void connectionCloseAuthFailure(String username, String password) throws // to be reported by the broker by closing the connection private Connection connectionWithoutCapabilities(String username, String password) throws IOException, TimeoutException { - ConnectionFactory customFactory = connectionFactory.clone(); + ConnectionFactory customFactory = TestUtils.connectionFactory(); customFactory.setUsername(username); customFactory.setPassword(password); Map customProperties = AMQConnection.defaultClientProperties(); From eb3a963340dff278c5d7700e2d847630e35354f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 15 Feb 2018 12:01:11 +0100 Subject: [PATCH 0712/2114] Polish previous code with Java 8 features [#154263515] References #341 --- .../rabbitmq/client/impl/AMQConnection.java | 7 +-- .../com/rabbitmq/client/impl/ChannelN.java | 8 ++-- .../client/impl/ConsumerWorkService.java | 4 +- .../com/rabbitmq/client/impl/WorkPool.java | 43 +++++++------------ .../recovery/AutorecoveringConnection.java | 38 ++++++++-------- .../client/test/SharedThreadPoolTest.java | 37 +++++++++++----- 6 files changed, 67 insertions(+), 70 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index 5f7d6cdbe9..5287b806ea 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -220,7 +220,7 @@ public AMQConnection(ConnectionParams params, FrameHandler frameHandler, Metrics this._virtualHost = params.getVirtualHost(); this._exceptionHandler = params.getExceptionHandler(); - this._clientProperties = new HashMap(params.getClientProperties()); + this._clientProperties = new HashMap<>(params.getClientProperties()); this.requestedFrameMax = params.getRequestedFrameMax(); this.requestedChannelMax = params.getRequestedChannelMax(); this.requestedHeartbeat = params.getRequestedHeartbeat(); @@ -252,10 +252,7 @@ public AMQConnection(ConnectionParams params, FrameHandler frameHandler, Metrics this.metricsCollector = metricsCollector; this.errorOnWriteListener = params.getErrorOnWriteListener() != null ? params.getErrorOnWriteListener() : - new ErrorOnWriteListener() { - @Override - public void handle(Connection connection, IOException exception) { } - }; + (connection, exception) -> { }; this.workPoolTimeout = params.getWorkPoolTimeout(); } diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java index aa425dce13..11d812c407 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelN.java @@ -453,10 +453,10 @@ protected void processDelivery(Command command, Basic.Deliver method) { // in case a manual ack in the callback, the stats will be able to record the ack metricsCollector.consumedMessage(this, m.getDeliveryTag(), m.getConsumerTag()); this.dispatcher.handleDelivery(callback, - m.getConsumerTag(), - envelope, - (BasicProperties) command.getContentHeader(), - command.getContentBody()); + m.getConsumerTag(), + envelope, + (BasicProperties) command.getContentHeader(), + command.getContentBody()); } catch (WorkPoolFullException e) { // couldn't enqueue in work pool, propagating throw e; diff --git a/src/main/java/com/rabbitmq/client/impl/ConsumerWorkService.java b/src/main/java/com/rabbitmq/client/impl/ConsumerWorkService.java index 6e8683137f..128e9f07e9 100644 --- a/src/main/java/com/rabbitmq/client/impl/ConsumerWorkService.java +++ b/src/main/java/com/rabbitmq/client/impl/ConsumerWorkService.java @@ -34,8 +34,8 @@ final public class ConsumerWorkService { public ConsumerWorkService(ExecutorService executor, ThreadFactory threadFactory, int queueingTimeout, int shutdownTimeout) { this.privateExecutor = (executor == null); this.executor = (executor == null) ? Executors.newFixedThreadPool(DEFAULT_NUM_THREADS, threadFactory) - : executor; - this.workPool = new WorkPool(queueingTimeout); + : executor; + this.workPool = new WorkPool<>(queueingTimeout); this.shutdownTimeout = shutdownTimeout; } diff --git a/src/main/java/com/rabbitmq/client/impl/WorkPool.java b/src/main/java/com/rabbitmq/client/impl/WorkPool.java index 1117132db5..ea2111b320 100644 --- a/src/main/java/com/rabbitmq/client/impl/WorkPool.java +++ b/src/main/java/com/rabbitmq/client/impl/WorkPool.java @@ -21,9 +21,8 @@ import java.util.Iterator; import java.util.Map; import java.util.Set; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; +import java.util.function.BiConsumer; /** *

This is a generic implementation of the channels specification @@ -64,33 +63,26 @@ public class WorkPool { private final Map> pool = new HashMap>(); /** Those keys which want limits to be removed. We do not limit queue size if this is non-empty. */ private final Set unlimited = new HashSet(); - private final EnqueueingCallback enqueueingCallback; + private final BiConsumer, W> enqueueingCallback; public WorkPool(final int queueingTimeout) { if (queueingTimeout > 0) { - this.enqueueingCallback = new EnqueueingCallback() { - @Override - public void enqueue(BlockingQueue queue, W item) { - try { - boolean offered = queue.offer(item, queueingTimeout, TimeUnit.MILLISECONDS); - if (!offered) { - throw new WorkPoolFullException("Could not enqueue in work pool after " + queueingTimeout + " ms."); - } - } catch (InterruptedException e) { - Thread.currentThread(); + this.enqueueingCallback = (queue, item) -> { + try { + boolean offered = queue.offer(item, queueingTimeout, TimeUnit.MILLISECONDS); + if (!offered) { + throw new WorkPoolFullException("Could not enqueue in work pool after " + queueingTimeout + " ms."); } + } catch (InterruptedException e) { + Thread.currentThread(); } }; } else { - this.enqueueingCallback = new EnqueueingCallback() { - - @Override - public void enqueue(BlockingQueue queue, W item) { - try { - queue.put(item); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } + this.enqueueingCallback = (queue, item) -> { + try { + queue.put(item); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); } }; } @@ -212,7 +204,7 @@ public boolean addWorkItem(K key, W item) { } // The put operation may block. We need to make sure we are not holding the lock while that happens. if (queue != null) { - enqueueingCallback.enqueue(queue, item); + enqueueingCallback.accept(queue, item); synchronized (this) { if (isDormant(key)) { @@ -274,9 +266,4 @@ private K readyToInProgress() { return key; } - private interface EnqueueingCallback { - - void enqueue(BlockingQueue queue, W item); - - } } diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index f7b3b19e35..dcfd7a705b 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -18,7 +18,6 @@ import com.rabbitmq.client.*; import com.rabbitmq.client.impl.AMQConnection; import com.rabbitmq.client.impl.ConnectionParams; -import com.rabbitmq.client.impl.ErrorOnWriteListener; import com.rabbitmq.client.impl.FrameHandlerFactory; import com.rabbitmq.client.impl.NetworkConnection; import com.rabbitmq.utility.Utility; @@ -104,28 +103,25 @@ public AutorecoveringConnection(ConnectionParams params, FrameHandlerFactory f, private void setupErrorOnWriteListenerForPotentialRecovery() { final ThreadFactory threadFactory = this.params.getThreadFactory(); final Lock errorOnWriteLock = new ReentrantLock(); - this.params.setErrorOnWriteListener(new ErrorOnWriteListener() { - @Override - public void handle(final Connection connection, final IOException exception) throws IOException { - // this is called for any write error - // we should trigger the error handling and the recovery only once - if (errorOnWriteLock.tryLock()) { - try { - Thread recoveryThread = threadFactory.newThread(new Runnable() { - @Override - public void run() { - AMQConnection c = (AMQConnection) connection; - c.handleIoError(exception); - } - }); - recoveryThread.setName("RabbitMQ Error On Write Thread"); - recoveryThread.start(); - } finally { - errorOnWriteLock.unlock(); - } + this.params.setErrorOnWriteListener((connection, exception) -> { + // this is called for any write error + // we should trigger the error handling and the recovery only once + if (errorOnWriteLock.tryLock()) { + try { + Thread recoveryThread = threadFactory.newThread(new Runnable() { + @Override + public void run() { + AMQConnection c = (AMQConnection) connection; + c.handleIoError(exception); + } + }); + recoveryThread.setName("RabbitMQ Error On Write Thread"); + recoveryThread.start(); + } finally { + errorOnWriteLock.unlock(); } - throw exception; } + throw exception; }); } diff --git a/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java b/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java index c8970205c4..15d7749a37 100644 --- a/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java +++ b/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java @@ -23,6 +23,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.TimeoutException; +import com.rabbitmq.client.Connection; import org.junit.Test; import com.rabbitmq.client.ConnectionFactory; @@ -32,34 +33,50 @@ public class SharedThreadPoolTest extends BrokerTestCase { @Test public void willShutDownExecutor() throws IOException, TimeoutException { ExecutorService executor1 = null; ExecutorService executor2 = null; + AMQConnection conn1 = null; + AMQConnection conn2 = null; + AMQConnection conn3 = null; + AMQConnection conn4 = null; try { ConnectionFactory cf = TestUtils.connectionFactory(); cf.setAutomaticRecoveryEnabled(false); executor1 = Executors.newFixedThreadPool(8); cf.setSharedExecutor(executor1); - AMQConnection conn1 = (AMQConnection)cf.newConnection(); + conn1 = (AMQConnection)cf.newConnection(); assertFalse(conn1.willShutDownConsumerExecutor()); executor2 = Executors.newSingleThreadExecutor(); - AMQConnection conn2 = (AMQConnection)cf.newConnection(executor2); + conn2 = (AMQConnection)cf.newConnection(executor2); assertFalse(conn2.willShutDownConsumerExecutor()); - AMQConnection conn3 = (AMQConnection)cf.newConnection((ExecutorService)null); + conn3 = (AMQConnection)cf.newConnection((ExecutorService)null); assertTrue(conn3.willShutDownConsumerExecutor()); cf.setSharedExecutor(null); - AMQConnection conn4 = (AMQConnection)cf.newConnection(); + conn4 = (AMQConnection)cf.newConnection(); assertTrue(conn4.willShutDownConsumerExecutor()); } finally { - if (executor1 != null) { - executor1.shutdownNow(); - } - if (executor2 != null) { - executor2.shutdownNow(); - } + close(conn1); + close(conn2); + close(conn3); + close(conn4); + close(executor1); + close(executor2); } } + + void close(ExecutorService executor) { + if (executor != null) { + executor.shutdownNow(); + } + } + + void close(Connection connection) throws IOException { + if (connection != null) { + connection.close(); + } + } } From 6cfbf9e43a489551093319c383ff681737623ddd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 15 Feb 2018 14:58:13 +0100 Subject: [PATCH 0713/2114] Set release version to 4.5.0.RC2 --- release-versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-versions.txt b/release-versions.txt index bcd262b846..0301654382 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="4.5.0.RC1" +RELEASE_VERSION="4.5.0.RC2" DEVELOPMENT_VERSION="4.5.0-SNAPSHOT" From 70ea8795306b587d14964bbcdbf156d54cfecf34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 19 Feb 2018 16:42:38 +0100 Subject: [PATCH 0714/2114] Fix missing import [#154263515] References #341 --- src/main/java/com/rabbitmq/client/ConnectionFactory.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 7d1f0f8ed4..9546be9f07 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -22,6 +22,7 @@ import com.rabbitmq.client.impl.CredentialsProvider; import com.rabbitmq.client.impl.DefaultCredentialsProvider; import com.rabbitmq.client.impl.DefaultExceptionHandler; +import com.rabbitmq.client.impl.ErrorOnWriteListener; import com.rabbitmq.client.impl.FrameHandler; import com.rabbitmq.client.impl.FrameHandlerFactory; import com.rabbitmq.client.impl.SocketFrameHandlerFactory; @@ -1322,7 +1323,7 @@ public boolean isChannelShouldCheckRpcResponseType() { /** * Timeout (in ms) for work pool enqueueing. - * The {@link WorkPool} dispatches several types of responses + * The {@link com.rabbitmq.client.impl.WorkPool} dispatches several types of responses * from the broker (e.g. deliveries). A high-traffic * client with slow consumers can exhaust the work pool and * compromise the whole connection (by e.g. letting the broker From 284a16a3e686c41e1ebb3e8780a9fbe662713ff1 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Mon, 19 Feb 2018 15:44:17 +0000 Subject: [PATCH 0715/2114] [maven-release-plugin] prepare release v4.5.0.RC2 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index b6b91d0a03..67c961fa7a 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.5.0-SNAPSHOT + 4.5.0.RC2 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v4.5.0.RC2 From fcc3dd221e8137b92183deb2e9d06ef3449f8abb Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Mon, 19 Feb 2018 15:44:21 +0000 Subject: [PATCH 0716/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 67c961fa7a..b6b91d0a03 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.5.0.RC2 + 4.5.0-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v4.5.0.RC2 + HEAD From f83946ca6a43ce3c6d4ae27844cdf995334eb973 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 19 Feb 2018 16:50:37 +0100 Subject: [PATCH 0717/2114] Set release version to 4.5.0.RC3 --- release-versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-versions.txt b/release-versions.txt index 0301654382..69de3834ad 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="4.5.0.RC2" +RELEASE_VERSION="4.5.0.RC3" DEVELOPMENT_VERSION="4.5.0-SNAPSHOT" From 2dcb249fd4a9ea0cabb907b4ef70b7fe0bef75f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 20 Feb 2018 09:54:07 +0100 Subject: [PATCH 0718/2114] Propagate exception in no-op in ErrorOnWriteListener [#154263515] References #341 --- src/main/java/com/rabbitmq/client/impl/AMQConnection.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index 632a9545aa..0beffbbcbe 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -254,7 +254,10 @@ public AMQConnection(ConnectionParams params, FrameHandler frameHandler, Metrics this.errorOnWriteListener = params.getErrorOnWriteListener() != null ? params.getErrorOnWriteListener() : new ErrorOnWriteListener() { @Override - public void handle(Connection connection, IOException exception) { } + public void handle(Connection connection, IOException exception) throws IOException { + // we just propagate the exception for non-recoverable connections + throw exception; + } }; this.workPoolTimeout = params.getWorkPoolTimeout(); } From 7607dbc69892c9938cfcb401bb5dd1fc99305d9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 20 Feb 2018 09:59:28 +0100 Subject: [PATCH 0719/2114] Set copyright period to 2007-2018 --- src/main/java/com/rabbitmq/client/impl/AMQConnection.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index 0beffbbcbe..f8dcd34301 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -35,7 +35,7 @@ import java.util.concurrent.atomic.AtomicBoolean; final class Copyright { - final static String COPYRIGHT="Copyright (c) 2007-2017 Pivotal Software, Inc."; + final static String COPYRIGHT="Copyright (c) 2007-2018 Pivotal Software, Inc."; final static String LICENSE="Licensed under the MPL. See http://www.rabbitmq.com/"; } From d0a439243296efc94ea755004c42d606c2c6e537 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Tue, 20 Feb 2018 13:19:07 +0000 Subject: [PATCH 0720/2114] [maven-release-plugin] prepare release v4.5.0.RC3 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index b6b91d0a03..0c1d401521 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.5.0-SNAPSHOT + 4.5.0.RC3 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v4.5.0.RC3 From 5e6b4e6984ec89b64ef4ead5f5b14c0b056524dd Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Tue, 20 Feb 2018 13:19:11 +0000 Subject: [PATCH 0721/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 0c1d401521..b6b91d0a03 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.5.0.RC3 + 4.5.0-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v4.5.0.RC3 + HEAD From 717b4bb610dc3d881c2622ed60abef3b48ff5abd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 20 Feb 2018 14:35:53 +0100 Subject: [PATCH 0722/2114] Set release version to 4.5.0.RC4 --- release-versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-versions.txt b/release-versions.txt index 69de3834ad..3888dade6c 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="4.5.0.RC3" +RELEASE_VERSION="4.5.0.RC4" DEVELOPMENT_VERSION="4.5.0-SNAPSHOT" From 6b6304c28d6ff181e4b7416a0fc41c6b44a797dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 23 Feb 2018 15:05:16 +0100 Subject: [PATCH 0723/2114] Use Maven Javadoc plugin 3.0.0 --- deploy-javadoc.sh | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/deploy-javadoc.sh b/deploy-javadoc.sh index 41cfd1d055..7289b49e04 100755 --- a/deploy-javadoc.sh +++ b/deploy-javadoc.sh @@ -3,7 +3,7 @@ DEPLOY_DIRECTORY=api/4.x.x TAG=$(git describe --exact-match --tags $(git log -n1 --pretty='%h')) -mvn -q clean javadoc:javadoc -Dmaven.javadoc.failOnError=false +./mvnw -q clean javadoc:javadoc -Dmaven.javadoc.failOnError=false git co gh-pages rm -rf $DEPLOY_DIRECTORY/* cp -r target/site/apidocs/* $DEPLOY_DIRECTORY diff --git a/pom.xml b/pom.xml index b6b91d0a03..0de36f6f9a 100644 --- a/pom.xml +++ b/pom.xml @@ -63,7 +63,7 @@ 2.0.0 2.7.9 - 3.0.0-M1 + 3.0.0 2.5.3 2.3 3.0.1 From 26367287ed00e1deba06b3eca611c610e0a309cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 26 Feb 2018 10:42:29 +0100 Subject: [PATCH 0724/2114] Set release version to 4.5.0 --- release-versions.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release-versions.txt b/release-versions.txt index 3888dade6c..3b0532a356 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="4.5.0.RC4" -DEVELOPMENT_VERSION="4.5.0-SNAPSHOT" +RELEASE_VERSION="4.5.0" +DEVELOPMENT_VERSION="4.5.1-SNAPSHOT" From a7c636d08973af04be0092ac4f4817f5fdc59f46 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Mon, 26 Feb 2018 09:44:32 +0000 Subject: [PATCH 0725/2114] [maven-release-plugin] prepare release v4.5.0 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 0de36f6f9a..b13e5d6dec 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.5.0-SNAPSHOT + 4.5.0 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v4.5.0 From 40688b5bf52d858b06aa5a9323ad90de698d2c76 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Mon, 26 Feb 2018 09:44:42 +0000 Subject: [PATCH 0726/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index b13e5d6dec..ac3dc5481e 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.5.0 + 4.5.1-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v4.5.0 + HEAD From 6a5abe1111f69208ae87879524f839ee875ff2df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 26 Feb 2018 10:58:18 +0100 Subject: [PATCH 0727/2114] Set release version to 4.5.1.RC1 --- release-versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-versions.txt b/release-versions.txt index 3b0532a356..6950477bec 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="4.5.0" +RELEASE_VERSION="4.5.1.RC1" DEVELOPMENT_VERSION="4.5.1-SNAPSHOT" From 90bebad8673bb5e1f1e7d9d931a4e74677847e82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 26 Feb 2018 11:00:25 +0100 Subject: [PATCH 0728/2114] Set release version to 4.6.0.RC1 --- pom.xml | 2 +- release-versions.txt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index ac3dc5481e..64bb051951 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.5.1-SNAPSHOT + 4.6.0-SNAPSHOT jar RabbitMQ Java Client diff --git a/release-versions.txt b/release-versions.txt index 6950477bec..0c0a3b5bd0 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="4.5.1.RC1" -DEVELOPMENT_VERSION="4.5.1-SNAPSHOT" +RELEASE_VERSION="4.6.0.RC1" +DEVELOPMENT_VERSION="4.6.0-SNAPSHOT" From a150df57f188e9a24889997c707fec9c548b927e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 26 Feb 2018 14:12:50 +0100 Subject: [PATCH 0729/2114] Add sanity check script Just aims to check the JAR file is not corrupted. --- src/main/scripts/sanity-check.groovy | 35 ++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 src/main/scripts/sanity-check.groovy diff --git a/src/main/scripts/sanity-check.groovy b/src/main/scripts/sanity-check.groovy new file mode 100644 index 0000000000..e1c9d48686 --- /dev/null +++ b/src/main/scripts/sanity-check.groovy @@ -0,0 +1,35 @@ +@GrabResolver(name = 'rabbitmq-bintray', root = 'http://dl.bintray.com/rabbitmq/maven') +@GrabResolver(name = 'rabbitmq-bintray-milestones', root = 'http://dl.bintray.com/rabbitmq/maven-milestones') +@Grab(group = 'com.rabbitmq', module = 'amqp-client', version = "${version}") +@Grab(group = 'org.slf4j', module = 'slf4j-simple', version = '1.7.25') +import com.rabbitmq.client.AMQP +import com.rabbitmq.client.Channel +import com.rabbitmq.client.ConnectionFactory +import com.rabbitmq.client.DefaultConsumer +import com.rabbitmq.client.Envelope +import org.slf4j.LoggerFactory + +import java.util.concurrent.CountDownLatch +import java.util.concurrent.TimeUnit + +def connection = new ConnectionFactory().newConnection() +try { + Channel ch = connection.createChannel() + def queue = ch.queueDeclare().getQueue() + CountDownLatch latch = new CountDownLatch(1); + ch.basicConsume(queue, true, new DefaultConsumer(ch) { + @Override + void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { + latch.countDown() + } + }) + ch.basicPublish("", queue, null, "test".getBytes()) + def received = latch.await(5, TimeUnit.SECONDS) + if (!received) + throw new IllegalStateException("Didn't receive message in 5 seconds") + LoggerFactory.getLogger("rabbitmq").info("Test succeeded") + System.exit 0 +} catch (Exception e) { + LoggerFactory.getLogger("rabbitmq").info("Test failed", e) + System.exit 1 +} From 4989d7e10328c49f9a0e27c58915fd1f6e9b781e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 27 Feb 2018 14:06:55 +0100 Subject: [PATCH 0730/2114] Upgrade to Micrometer 1.0.0 Fixes #351 --- pom.xml | 2 +- .../com/rabbitmq/client/impl/MicrometerMetricsCollector.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 64bb051951..65e08b38f0 100644 --- a/pom.xml +++ b/pom.xml @@ -56,7 +56,7 @@ 1.7.21 3.1.2 - 1.0.0-rc.6 + 1.0.0 1.1.7 1.1 4.12 diff --git a/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java index e418378a5b..2294b1a004 100644 --- a/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java @@ -68,7 +68,7 @@ public MicrometerMetricsCollector(final MeterRegistry registry, final String pre } public MicrometerMetricsCollector(final MeterRegistry registry, final String prefix, final String ... tags) { - this(registry, prefix, Tags.zip(tags)); + this(registry, prefix, Tags.of(tags)); } public MicrometerMetricsCollector(final MeterRegistry registry, final String prefix, final Iterable tags) { From d5baa3f25cf566752c3da704916f57e9645ea769 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 27 Feb 2018 14:18:10 +0100 Subject: [PATCH 0731/2114] Use additionalOptions in Javadoc plugin Instead of additionalparam, which appears to not exist anymore in Maven Javadoc plugin 3.0.0. --- pom.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index ac3dc5481e..bef6f40c1f 100644 --- a/pom.xml +++ b/pom.xml @@ -475,7 +475,7 @@ maven-javadoc-plugin ${maven.javadoc.plugin.version} - ${javadoc.opts} + ${javadoc.opts} true @@ -527,7 +527,7 @@ maven-javadoc-plugin ${maven.javadoc.plugin.version} - ${javadoc.opts} + ${javadoc.opts} true @@ -580,7 +580,7 @@ maven-javadoc-plugin ${maven.javadoc.plugin.version} - ${javadoc.opts} + ${javadoc.opts} true @@ -929,7 +929,7 @@ maven-javadoc-plugin ${maven.javadoc.plugin.version} - ${javadoc.opts} + ${javadoc.opts} true From 3f288d2c944ce19ff2307f5c076d325392b399b6 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Tue, 27 Feb 2018 15:25:50 +0000 Subject: [PATCH 0732/2114] [maven-release-plugin] prepare release v5.2.0.RC1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 744bc20466..a54c9dad1b 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.2.0-SNAPSHOT + 5.2.0.RC1 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v5.2.0.RC1 From 856ef76eedf5d461068023e6aea19a854cac55e3 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Tue, 27 Feb 2018 15:25:54 +0000 Subject: [PATCH 0733/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index a54c9dad1b..744bc20466 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.2.0.RC1 + 5.2.0-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v5.2.0.RC1 + HEAD From f130ef23661564a8b1feae03028c4d250d104cae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 12 Mar 2018 15:56:23 +0100 Subject: [PATCH 0734/2114] Set release version to 5.2.0 --- release-versions.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release-versions.txt b/release-versions.txt index ddb1fe40cf..0ae49f6e6f 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="5.2.0.RC1" -DEVELOPMENT_VERSION="5.2.0-SNAPSHOT" +RELEASE_VERSION="5.2.0" +DEVELOPMENT_VERSION="5.2.1-SNAPSHOT" From 00d055b5637b374820fa297ee3f52910d09883ef Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Mon, 12 Mar 2018 15:00:08 +0000 Subject: [PATCH 0735/2114] [maven-release-plugin] prepare release v5.2.0 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 744bc20466..132abef5b8 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.2.0-SNAPSHOT + 5.2.0 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v5.2.0 From 3c91aaacb0c48e0feab63a4615a7737106ecab45 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Mon, 12 Mar 2018 15:00:17 +0000 Subject: [PATCH 0736/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 132abef5b8..ffa2f784c7 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.2.0 + 5.2.1-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v5.2.0 + HEAD From 5af4f359369d6375e60bc0342880fe3ff393c50b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 12 Mar 2018 17:04:22 +0100 Subject: [PATCH 0737/2114] Set release version to 5.2.1.RC1 --- release-versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-versions.txt b/release-versions.txt index 0ae49f6e6f..d91f0a9eb3 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="5.2.0" +RELEASE_VERSION="5.2.1.RC1" DEVELOPMENT_VERSION="5.2.1-SNAPSHOT" From d6c40a76ef8cf9b81d7ffef53397a62f6a71bc02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 13 Mar 2018 10:51:15 +0100 Subject: [PATCH 0738/2114] Set version to 5.3.0-SNAPSHOT --- pom.xml | 2 +- release-versions.txt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index ffa2f784c7..96c46ff315 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.2.1-SNAPSHOT + 5.3.0-SNAPSHOT jar RabbitMQ Java Client diff --git a/release-versions.txt b/release-versions.txt index d91f0a9eb3..86b93080e4 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="5.2.1.RC1" -DEVELOPMENT_VERSION="5.2.1-SNAPSHOT" +RELEASE_VERSION="5.3.0.RC1" +DEVELOPMENT_VERSION="5.3.0-SNAPSHOT" From 139aed8e06c9dfa86a577c05d5380e6d65cf375e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 19 Mar 2018 15:50:12 +0100 Subject: [PATCH 0739/2114] Upgrade to Micrometer 1.0.2 Fixes #353 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 42ec4dee95..1555d4fc99 100644 --- a/pom.xml +++ b/pom.xml @@ -56,7 +56,7 @@ 1.7.21 3.1.2 - 1.0.0 + 1.0.2 1.1.7 1.1 4.12 From eed963c1e26dcf93a69c7c17bdf3a742fbc42aaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 19 Mar 2018 15:57:22 +0100 Subject: [PATCH 0740/2114] Update dependencies --- pom.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index 1555d4fc99..10cc51991c 100644 --- a/pom.xml +++ b/pom.xml @@ -54,14 +54,14 @@ UTF-8 UTF-8 - 1.7.21 - 3.1.2 + 1.7.25 + 3.2.6 1.0.2 - 1.1.7 + 1.2.3 1.1 4.12 - 2.0.0 - 2.7.9 + 3.1.0 + 2.16.0 3.0.0 2.5.3 From e02becabb8f4caa64fc9d0b1bd03ab745d4da21d Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Mon, 19 Mar 2018 15:54:04 +0000 Subject: [PATCH 0741/2114] [maven-release-plugin] prepare release v4.6.0.RC1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 10cc51991c..5cc378de1f 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.6.0-SNAPSHOT + 4.6.0.RC1 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v4.6.0.RC1 From 5b498c82b707a7b11d4c7f8b9ed4a1ae4585b1f0 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Mon, 19 Mar 2018 15:54:11 +0000 Subject: [PATCH 0742/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 5cc378de1f..10cc51991c 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.6.0.RC1 + 4.6.0-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v4.6.0.RC1 + HEAD From 3314164654fea2cc860288b4ea1eda35369635c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 19 Mar 2018 17:00:42 +0100 Subject: [PATCH 0743/2114] Set release version to 4.6.0.RC2 --- release-versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-versions.txt b/release-versions.txt index 0c0a3b5bd0..d20bc63be7 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="4.6.0.RC1" +RELEASE_VERSION="4.6.0.RC2" DEVELOPMENT_VERSION="4.6.0-SNAPSHOT" From a345ff54f23d442ac805a9ceb79e2fd8b0d04763 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 26 Mar 2018 13:46:45 +0200 Subject: [PATCH 0744/2114] Set release version to 4.6.0 --- release-versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-versions.txt b/release-versions.txt index d20bc63be7..094db3196e 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="4.6.0.RC2" +RELEASE_VERSION="4.6.0" DEVELOPMENT_VERSION="4.6.0-SNAPSHOT" From c16f297527b08ede9b3ebf9b1008849413f71ade Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Mon, 26 Mar 2018 11:57:03 +0000 Subject: [PATCH 0745/2114] [maven-release-plugin] prepare release v4.6.0 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 10cc51991c..15bc4ae1ef 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.6.0-SNAPSHOT + 4.6.0 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v4.6.0 From 50b3fd572815ac39492b88481fdd4fd4178a3834 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Mon, 26 Mar 2018 11:57:10 +0000 Subject: [PATCH 0746/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 15bc4ae1ef..10cc51991c 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.6.0 + 4.6.0-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v4.6.0 + HEAD From ef3784e93aecb9fb5426be56cc171f3e069c521f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 26 Mar 2018 14:06:56 +0200 Subject: [PATCH 0747/2114] Set release version to 4.7.0.RC1 --- release-versions.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release-versions.txt b/release-versions.txt index 094db3196e..5dc8075f18 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="4.6.0" -DEVELOPMENT_VERSION="4.6.0-SNAPSHOT" +RELEASE_VERSION="4.7.0.RC1" +DEVELOPMENT_VERSION="4.7.0-SNAPSHOT" From dc3ebe153fee66e656c2a7be3e78301a8aa7293b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 26 Mar 2018 14:12:49 +0200 Subject: [PATCH 0748/2114] Set release version to 4.6.1.RC1 --- pom.xml | 2 +- release-versions.txt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 10cc51991c..22140b9980 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.6.0-SNAPSHOT + 4.6.1-SNAPSHOT jar RabbitMQ Java Client diff --git a/release-versions.txt b/release-versions.txt index 5dc8075f18..4efbb3fd24 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="4.7.0.RC1" -DEVELOPMENT_VERSION="4.7.0-SNAPSHOT" +RELEASE_VERSION="4.6.1.RC1" +DEVELOPMENT_VERSION="4.6.1-SNAPSHOT" From 874eada52e083331ac586f719bc2682fdbaa22b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 26 Mar 2018 14:13:42 +0200 Subject: [PATCH 0749/2114] Set release version to 4.7.0.RC1 --- pom.xml | 2 +- release-versions.txt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 22140b9980..487314e695 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.6.1-SNAPSHOT + 4.7.0-SNAPSHOT jar RabbitMQ Java Client diff --git a/release-versions.txt b/release-versions.txt index 4efbb3fd24..5dc8075f18 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="4.6.1.RC1" -DEVELOPMENT_VERSION="4.6.1-SNAPSHOT" +RELEASE_VERSION="4.7.0.RC1" +DEVELOPMENT_VERSION="4.7.0-SNAPSHOT" From 0eacae101eae1fc18b60e2482aece831e3939045 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Turek?= Date: Tue, 10 Apr 2018 12:44:02 +0200 Subject: [PATCH 0750/2114] #354 | track publishing failures --- .../com/rabbitmq/client/MetricsCollector.java | 3 +++ .../com/rabbitmq/client/impl/ChannelN.java | 25 +++++++++++-------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/MetricsCollector.java b/src/main/java/com/rabbitmq/client/MetricsCollector.java index 34bb61f577..c4e8ca72c0 100644 --- a/src/main/java/com/rabbitmq/client/MetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/MetricsCollector.java @@ -36,6 +36,8 @@ public interface MetricsCollector { void basicPublish(Channel channel); + void basicPublishFailure(Channel channel); + void consumedMessage(Channel channel, long deliveryTag, boolean autoAck); void consumedMessage(Channel channel, long deliveryTag, String consumerTag); @@ -49,4 +51,5 @@ public interface MetricsCollector { void basicConsume(Channel channel, String consumerTag, boolean autoAck); void basicCancel(Channel channel, String consumerTag); + } diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java index 11d812c407..da0a9c9492 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelN.java @@ -684,22 +684,25 @@ public void basicPublish(String exchange, String routingKey, unconfirmedSet.add(getNextPublishSeqNo()); nextPublishSeqNo++; } - BasicProperties useProps = props; if (props == null) { - useProps = MessageProperties.MINIMAL_BASIC; + props = MessageProperties.MINIMAL_BASIC; + } + AMQCommand command = new AMQCommand( + new Basic.Publish.Builder() + .exchange(exchange) + .routingKey(routingKey) + .mandatory(mandatory) + .immediate(immediate) + .build(), props, body); + try { + transmit(command); + } catch (IOException e) { + metricsCollector.basicPublishFailure(this); + throw e; } - transmit(new AMQCommand(new Basic.Publish.Builder() - .exchange(exchange) - .routingKey(routingKey) - .mandatory(mandatory) - .immediate(immediate) - .build(), - useProps, body)); metricsCollector.basicPublish(this); } - - /** Public API - {@inheritDoc} */ @Override public Exchange.DeclareOk exchangeDeclare(String exchange, String type, From 6e8395c3d910b2a6fdc336087c85aa3d3f73c379 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Turek?= Date: Tue, 10 Apr 2018 12:49:41 +0200 Subject: [PATCH 0751/2114] #354 | no-op implementation --- src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java b/src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java index 3895f34013..3f25492ba6 100644 --- a/src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java @@ -70,6 +70,11 @@ public void basicPublish(Channel channel) { } + @Override + public void basicPublishFailure(Channel channel) { + + } + @Override public void consumedMessage(Channel channel, long deliveryTag, boolean autoAck) { From ce842ff83eb34701a183bd87a5a68e96aa932572 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Turek?= Date: Tue, 10 Apr 2018 14:59:00 +0200 Subject: [PATCH 0752/2114] #354 | abstract metrics implementation --- .../client/impl/AbstractMetricsCollector.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java index 71983fb457..be128aa161 100644 --- a/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java @@ -102,6 +102,15 @@ public void basicPublish(Channel channel) { } } + @Override + public void basicPublishFailure(Channel channel) { + try { + markMessagePublishFailed(); + } catch(Exception e) { + LOGGER.info("Error while computing metrics in basicPublishFailure: " + e.getMessage()); + } + } + @Override public void basicConsume(Channel channel, String consumerTag, boolean autoAck) { try { @@ -331,6 +340,11 @@ private ChannelState(Channel channel) { */ protected abstract void markPublishedMessage(); + /** + * Marks the event of a message publishing failure. + */ + protected abstract void markMessagePublishFailed(); + /** * Marks the event of a consumed message. */ From 40567a02043dd35c9c93517ae311bcf5ecb1e5f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Turek?= Date: Tue, 10 Apr 2018 14:59:11 +0200 Subject: [PATCH 0753/2114] #354 | micrometer metrics implementation --- .../impl/MicrometerMetricsCollector.java | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java index 1e2b8303f2..a7f65e9018 100644 --- a/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java @@ -27,12 +27,7 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.function.Function; -import static com.rabbitmq.client.impl.MicrometerMetricsCollector.Metrics.ACKNOWLEDGED_MESSAGES; -import static com.rabbitmq.client.impl.MicrometerMetricsCollector.Metrics.CHANNELS; -import static com.rabbitmq.client.impl.MicrometerMetricsCollector.Metrics.CONNECTIONS; -import static com.rabbitmq.client.impl.MicrometerMetricsCollector.Metrics.CONSUMED_MESSAGES; -import static com.rabbitmq.client.impl.MicrometerMetricsCollector.Metrics.PUBLISHED_MESSAGES; -import static com.rabbitmq.client.impl.MicrometerMetricsCollector.Metrics.REJECTED_MESSAGES; +import static com.rabbitmq.client.impl.MicrometerMetricsCollector.Metrics.*; /** * Micrometer implementation of {@link MetricsCollector}. @@ -54,6 +49,8 @@ public class MicrometerMetricsCollector extends AbstractMetricsCollector { private final Counter publishedMessages; + private final Counter failedToPublishMessages; + private final Counter consumedMessages; private final Counter acknowledgedMessages; @@ -83,6 +80,7 @@ public MicrometerMetricsCollector(Function metricsCreator) { this.consumedMessages = (Counter) metricsCreator.apply(CONSUMED_MESSAGES); this.acknowledgedMessages = (Counter) metricsCreator.apply(ACKNOWLEDGED_MESSAGES); this.rejectedMessages = (Counter) metricsCreator.apply(REJECTED_MESSAGES); + this.failedToPublishMessages = (Counter) metricsCreator.apply(FAILED_TO_PUBLISH_MESSAGES); } @Override @@ -110,6 +108,11 @@ protected void markPublishedMessage() { publishedMessages.increment(); } + @Override + protected void markMessagePublishFailed() { + failedToPublishMessages.increment(); + } + @Override protected void markConsumedMessage() { consumedMessages.increment(); @@ -137,6 +140,10 @@ public Counter getPublishedMessages() { return publishedMessages; } + public Counter getFailedToPublishMessages() { + return failedToPublishMessages; + } + public Counter getConsumedMessages() { return consumedMessages; } @@ -185,6 +192,12 @@ Object create(MeterRegistry registry, String prefix, Iterable tags) { Object create(MeterRegistry registry, String prefix, Iterable tags) { return registry.counter(prefix + ".rejected", tags); } + }, + FAILED_TO_PUBLISH_MESSAGES { + @Override + Object create(MeterRegistry registry, String prefix, Iterable tags) { + return registry.counter(prefix + ".failed_to_publish", tags); + } }; /** @@ -192,7 +205,6 @@ Object create(MeterRegistry registry, String prefix, Iterable tags) { * @param registry * @param prefix * @deprecated will be removed in 6.0.0 - * @return */ @Deprecated Object create(MeterRegistry registry, String prefix) { From 403d50a09d683a699da6cbc69af6b662f846f915 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Turek?= Date: Tue, 10 Apr 2018 15:00:26 +0200 Subject: [PATCH 0754/2114] #354 | standard metrics implementation --- .../client/impl/StandardMetricsCollector.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java index 08a3939f24..91f9342b6d 100644 --- a/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java @@ -41,6 +41,7 @@ public class StandardMetricsCollector extends AbstractMetricsCollector { private final Meter consumedMessages; private final Meter acknowledgedMessages; private final Meter rejectedMessages; + private final Meter failedToPublishMessages; public StandardMetricsCollector(MetricRegistry registry, String metricsPrefix) { @@ -48,6 +49,7 @@ public StandardMetricsCollector(MetricRegistry registry, String metricsPrefix) { this.connections = registry.counter(metricsPrefix+".connections"); this.channels = registry.counter(metricsPrefix+".channels"); this.publishedMessages = registry.meter(metricsPrefix+".published"); + this.failedToPublishMessages = registry.meter(metricsPrefix+".failed_to_publish"); this.consumedMessages = registry.meter(metricsPrefix+".consumed"); this.acknowledgedMessages = registry.meter(metricsPrefix+".acknowledged"); this.rejectedMessages = registry.meter(metricsPrefix+".rejected"); @@ -86,6 +88,11 @@ protected void markPublishedMessage() { publishedMessages.mark(); } + @Override + protected void markMessagePublishFailed() { + failedToPublishMessages.mark(); + } + @Override protected void markConsumedMessage() { consumedMessages.mark(); @@ -130,4 +137,8 @@ public Meter getAcknowledgedMessages() { public Meter getRejectedMessages() { return rejectedMessages; } + + public Meter getFailedToPublishMessages() { + return failedToPublishMessages; + } } From 2e2dc249072ad3f19f5ba9d5e8eeb765111d697b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 23 Apr 2018 11:08:14 +0200 Subject: [PATCH 0755/2114] Log on broker version parsing error in tests --- .../com/rabbitmq/client/test/TestUtils.java | 34 ++++++++++++------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/TestUtils.java b/src/test/java/com/rabbitmq/client/test/TestUtils.java index 62db841bf5..644f3a1707 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtils.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtils.java @@ -17,6 +17,7 @@ import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; +import org.slf4j.LoggerFactory; import java.io.IOException; @@ -45,20 +46,27 @@ public static void close(Connection connection) { } public static boolean isVersion37orLater(Connection connection) { - String currentVersion = connection.getServerProperties().get("version").toString(); - // versions built from source: 3.7.0+rc.1.4.gedc5d96 - if (currentVersion.contains("+")) { - currentVersion = currentVersion.substring(0, currentVersion.indexOf("+")); - } - // alpha (snapshot) versions: 3.7.0~alpha.449-1 - if (currentVersion.contains("~")) { - currentVersion = currentVersion.substring(0, currentVersion.indexOf("~")); - } - // alpha (snapshot) versions: 3.7.1-alpha.40 - if (currentVersion.contains("-")) { - currentVersion = currentVersion.substring(0, currentVersion.indexOf("-")); + String currentVersion = null; + try { + currentVersion = connection.getServerProperties().get("version").toString(); + // versions built from source: 3.7.0+rc.1.4.gedc5d96 + if (currentVersion.contains("+")) { + currentVersion = currentVersion.substring(0, currentVersion.indexOf("+")); + } + // alpha (snapshot) versions: 3.7.0~alpha.449-1 + if (currentVersion.contains("~")) { + currentVersion = currentVersion.substring(0, currentVersion.indexOf("~")); + } + // alpha (snapshot) versions: 3.7.1-alpha.40 + if (currentVersion.contains("-")) { + currentVersion = currentVersion.substring(0, currentVersion.indexOf("-")); + } + return "0.0.0".equals(currentVersion) || versionCompare(currentVersion, "3.7.0") >= 0; + } catch (RuntimeException e) { + LoggerFactory.getLogger(TestUtils.class).warn("Unable to parse broker version {}", currentVersion, e); + throw e; } - return "0.0.0".equals(currentVersion) || versionCompare(currentVersion, "3.7.0") >= 0; + } /** From c215793f146cda779442606c82ebb8db7db6ce2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Turek?= Date: Mon, 23 Apr 2018 14:05:35 +0200 Subject: [PATCH 0756/2114] #354 | cause is passed to the metrics collector --- src/main/java/com/rabbitmq/client/MetricsCollector.java | 2 +- src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java | 2 +- .../java/com/rabbitmq/client/impl/AbstractMetricsCollector.java | 2 +- src/main/java/com/rabbitmq/client/impl/ChannelN.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/MetricsCollector.java b/src/main/java/com/rabbitmq/client/MetricsCollector.java index c4e8ca72c0..40e5af3b6a 100644 --- a/src/main/java/com/rabbitmq/client/MetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/MetricsCollector.java @@ -36,7 +36,7 @@ public interface MetricsCollector { void basicPublish(Channel channel); - void basicPublishFailure(Channel channel); + void basicPublishFailure(Channel channel, Throwable cause); void consumedMessage(Channel channel, long deliveryTag, boolean autoAck); diff --git a/src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java b/src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java index 3f25492ba6..6563ab14ce 100644 --- a/src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java @@ -71,7 +71,7 @@ public void basicPublish(Channel channel) { } @Override - public void basicPublishFailure(Channel channel) { + public void basicPublishFailure(Channel channel, Throwable cause) { } diff --git a/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java index be128aa161..03eb64f468 100644 --- a/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java @@ -103,7 +103,7 @@ public void basicPublish(Channel channel) { } @Override - public void basicPublishFailure(Channel channel) { + public void basicPublishFailure(Channel channel, Throwable cause) { try { markMessagePublishFailed(); } catch(Exception e) { diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java index da0a9c9492..1685c249a0 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelN.java @@ -697,7 +697,7 @@ public void basicPublish(String exchange, String routingKey, try { transmit(command); } catch (IOException e) { - metricsCollector.basicPublishFailure(this); + metricsCollector.basicPublishFailure(this, e); throw e; } metricsCollector.basicPublish(this); From 843db2ba4180a3ae0c7be59505a47a6d0a8520ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Turek?= Date: Mon, 23 Apr 2018 14:39:10 +0200 Subject: [PATCH 0757/2114] #354 | test for metrics for publishes and failures to publish --- .../client/test/MetricsCollectorTest.java | 52 +++++++++++++++++-- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java b/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java index 5aa6a24cdc..d6b5095ed0 100644 --- a/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java +++ b/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java @@ -26,9 +26,12 @@ import org.junit.runner.RunWith; import org.junit.runners.Parameterized; -import static org.hamcrest.Matchers.*; -import static org.junit.Assert.*; -import static org.mockito.Mockito.*; +import java.io.IOException; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; /** * @@ -116,7 +119,34 @@ public void basicGetAndAck() { metrics.basicAck(channel, 10, true); assertThat(acknowledgedMessages(metrics), is(1L+2L+1L)); + } + + @Test public void publishingAndPublishingFailures() { + AbstractMetricsCollector metrics = factory.create(); + Channel channel = mock(Channel.class); + + assertThat(failedToPublishMessages(metrics), is(0L)); + assertThat(publishedMessages(metrics), is(0L)); + metrics.basicPublishFailure(channel, new IOException()); + assertThat(failedToPublishMessages(metrics), is(1L)); + assertThat(publishedMessages(metrics), is(0L)); + + metrics.basicPublish(channel); + assertThat(failedToPublishMessages(metrics), is(1L)); + assertThat(publishedMessages(metrics), is(1L)); + + metrics.basicPublishFailure(channel, new IOException()); + assertThat(failedToPublishMessages(metrics), is(2L)); + assertThat(publishedMessages(metrics), is(1L)); + + metrics.basicPublish(channel); + assertThat(failedToPublishMessages(metrics), is(2L)); + assertThat(publishedMessages(metrics), is(2L)); + + metrics.cleanStaleState(); + assertThat(failedToPublishMessages(metrics), is(2L)); + assertThat(publishedMessages(metrics), is(2L)); } @Test public void cleanStaleState() { @@ -159,6 +189,22 @@ public void basicGetAndAck() { assertThat(channels(metrics), is(1L)); } + long publishedMessages(MetricsCollector metrics) { + if (metrics instanceof StandardMetricsCollector) { + return ((StandardMetricsCollector) metrics).getPublishedMessages().getCount(); + } else { + return (long) ((MicrometerMetricsCollector) metrics).getPublishedMessages().count(); + } + } + + long failedToPublishMessages(MetricsCollector metrics) { + if (metrics instanceof StandardMetricsCollector) { + return ((StandardMetricsCollector) metrics).getFailedToPublishMessages().getCount(); + } else { + return (long) ((MicrometerMetricsCollector) metrics).getFailedToPublishMessages().count(); + } + } + long consumedMessages(MetricsCollector metrics) { if (metrics instanceof StandardMetricsCollector) { return ((StandardMetricsCollector) metrics).getConsumedMessages().getCount(); From deb987a729f8384c1a3166a8429fcf128b78d606 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Turek?= Date: Mon, 23 Apr 2018 21:00:43 +0200 Subject: [PATCH 0758/2114] #354 | add implementation for ack, nack and unrouted publishes --- .../com/rabbitmq/client/MetricsCollector.java | 6 +++ .../rabbitmq/client/NoOpMetricsCollector.java | 15 ++++++ .../client/impl/AbstractMetricsCollector.java | 40 +++++++++++++- .../impl/MicrometerMetricsCollector.java | 54 +++++++++++++++++++ .../client/impl/StandardMetricsCollector.java | 34 +++++++++++- 5 files changed, 147 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/MetricsCollector.java b/src/main/java/com/rabbitmq/client/MetricsCollector.java index 40e5af3b6a..a67918a4b2 100644 --- a/src/main/java/com/rabbitmq/client/MetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/MetricsCollector.java @@ -38,6 +38,12 @@ public interface MetricsCollector { void basicPublishFailure(Channel channel, Throwable cause); + void basicPublishAck(Channel channel); + + void basicPublishNack(Channel channel); + + void basicPublishUnrouted(Channel channel); + void consumedMessage(Channel channel, long deliveryTag, boolean autoAck); void consumedMessage(Channel channel, long deliveryTag, String consumerTag); diff --git a/src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java b/src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java index 6563ab14ce..6dc4688dd2 100644 --- a/src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java @@ -75,6 +75,21 @@ public void basicPublishFailure(Channel channel, Throwable cause) { } + @Override + public void basicPublishAck(Channel channel) { + + } + + @Override + public void basicPublishNack(Channel channel) { + + } + + @Override + public void basicPublishUnrouted(Channel channel) { + + } + @Override public void consumedMessage(Channel channel, long deliveryTag, boolean autoAck) { diff --git a/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java index 03eb64f468..6894d09ca4 100644 --- a/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java @@ -111,6 +111,33 @@ public void basicPublishFailure(Channel channel, Throwable cause) { } } + @Override + public void basicPublishAck(Channel channel) { + try { + markMessagePublishAcknowledged(); + } catch(Exception e) { + LOGGER.info("Error while computing metrics in basicPublishAck: " + e.getMessage()); + } + } + + @Override + public void basicPublishNack(Channel channel) { + try { + markMessagePublishNotAcknowledged(); + } catch(Exception e) { + LOGGER.info("Error while computing metrics in basicPublishNack: " + e.getMessage()); + } + } + + @Override + public void basicPublishUnrouted(Channel channel) { + try { + markPublishedMessageNotRouted(); + } catch(Exception e) { + LOGGER.info("Error while computing metrics in markPublishedMessageNotRouted: " + e.getMessage()); + } + } + @Override public void basicConsume(Channel channel, String consumerTag, boolean autoAck) { try { @@ -360,6 +387,17 @@ private ChannelState(Channel channel) { */ protected abstract void markRejectedMessage(); + /** + * Marks the event of a message publishing acknowledgement. + */ + protected abstract void markMessagePublishAcknowledged(); - + /** + * Marks the event of a message publishing not being acknowledged. + */ + protected abstract void markMessagePublishNotAcknowledged(); + /** + * Marks the event of a published message not being routed. + */ + protected abstract void markPublishedMessageNotRouted(); } diff --git a/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java index a7f65e9018..ee17194538 100644 --- a/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java @@ -51,6 +51,12 @@ public class MicrometerMetricsCollector extends AbstractMetricsCollector { private final Counter failedToPublishMessages; + private final Counter ackedPublishedMessages; + + private final Counter nackedPublishedMessages; + + private final Counter unroutedPublishedMessages; + private final Counter consumedMessages; private final Counter acknowledgedMessages; @@ -81,6 +87,9 @@ public MicrometerMetricsCollector(Function metricsCreator) { this.acknowledgedMessages = (Counter) metricsCreator.apply(ACKNOWLEDGED_MESSAGES); this.rejectedMessages = (Counter) metricsCreator.apply(REJECTED_MESSAGES); this.failedToPublishMessages = (Counter) metricsCreator.apply(FAILED_TO_PUBLISH_MESSAGES); + this.ackedPublishedMessages = (Counter) metricsCreator.apply(ACKED_PUBLISHED_MESSAGES); + this.nackedPublishedMessages = (Counter) metricsCreator.apply(NACKED_PUBLISHED_MESSAGES); + this.unroutedPublishedMessages = (Counter) metricsCreator.apply(UNROUTED_PUBLISHED_MESSAGES); } @Override @@ -128,6 +137,21 @@ protected void markRejectedMessage() { rejectedMessages.increment(); } + @Override + protected void markMessagePublishAcknowledged() { + ackedPublishedMessages.increment(); + } + + @Override + protected void markMessagePublishNotAcknowledged() { + nackedPublishedMessages.increment(); + } + + @Override + protected void markPublishedMessageNotRouted() { + unroutedPublishedMessages.increment(); + } + public AtomicLong getConnections() { return connections; } @@ -144,6 +168,18 @@ public Counter getFailedToPublishMessages() { return failedToPublishMessages; } + public Counter getAckedPublishedMessages() { + return ackedPublishedMessages; + } + + public Counter getNackedPublishedMessages() { + return nackedPublishedMessages; + } + + public Counter getUnroutedPublishedMessages() { + return unroutedPublishedMessages; + } + public Counter getConsumedMessages() { return consumedMessages; } @@ -198,6 +234,24 @@ Object create(MeterRegistry registry, String prefix, Iterable tags) { Object create(MeterRegistry registry, String prefix, Iterable tags) { return registry.counter(prefix + ".failed_to_publish", tags); } + }, + ACKED_PUBLISHED_MESSAGES { + @Override + Object create(MeterRegistry registry, String prefix, Iterable tags) { + return registry.counter(prefix + ".acknowledged_published", tags); + } + }, + NACKED_PUBLISHED_MESSAGES { + @Override + Object create(MeterRegistry registry, String prefix, Iterable tags) { + return registry.counter(prefix + ".not_acknowledged_published", tags); + } + }, + UNROUTED_PUBLISHED_MESSAGES { + @Override + Object create(MeterRegistry registry, String prefix, Iterable tags) { + return registry.counter(prefix + ".unrouted_published", tags); + } }; /** diff --git a/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java index 91f9342b6d..a4062eb3b7 100644 --- a/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java @@ -42,6 +42,9 @@ public class StandardMetricsCollector extends AbstractMetricsCollector { private final Meter acknowledgedMessages; private final Meter rejectedMessages; private final Meter failedToPublishMessages; + private final Meter publishAcknowledgedMessages; + private final Meter publishNacknowledgedMessages; + private final Meter publishUnroutedMessages; public StandardMetricsCollector(MetricRegistry registry, String metricsPrefix) { @@ -50,6 +53,9 @@ public StandardMetricsCollector(MetricRegistry registry, String metricsPrefix) { this.channels = registry.counter(metricsPrefix+".channels"); this.publishedMessages = registry.meter(metricsPrefix+".published"); this.failedToPublishMessages = registry.meter(metricsPrefix+".failed_to_publish"); + this.publishAcknowledgedMessages = registry.meter(metricsPrefix+".publish_ack"); + this.publishNacknowledgedMessages = registry.meter(metricsPrefix+".publish_nack"); + this.publishUnroutedMessages = registry.meter(metricsPrefix+".publish_unrouted"); this.consumedMessages = registry.meter(metricsPrefix+".consumed"); this.acknowledgedMessages = registry.meter(metricsPrefix+".acknowledged"); this.rejectedMessages = registry.meter(metricsPrefix+".rejected"); @@ -108,8 +114,21 @@ protected void markRejectedMessage() { rejectedMessages.mark(); } + @Override + protected void markMessagePublishAcknowledged() { + acknowledgedMessages.mark(); + } + + @Override + protected void markMessagePublishNotAcknowledged() { + publishNacknowledgedMessages.mark(); + } + + @Override + protected void markPublishedMessageNotRouted() { + publishUnroutedMessages.mark(); + } - public MetricRegistry getMetricRegistry() { return registry; } @@ -141,4 +160,17 @@ public Meter getRejectedMessages() { public Meter getFailedToPublishMessages() { return failedToPublishMessages; } + + public Meter getPublishAcknowledgedMessages() { + return publishAcknowledgedMessages; + } + + public Meter getPublishNotAcknowledgedMessages() { + return publishNacknowledgedMessages; + } + + public Meter getPublishUnroutedMessages() { + return publishUnroutedMessages; + } + } From 704fa1e284865673e84ff0e48a882c7c1d2c348c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Turek?= Date: Mon, 23 Apr 2018 21:58:43 +0200 Subject: [PATCH 0759/2114] #354 | call metrics (acks and nacks have to be corrected for multiples) --- src/main/java/com/rabbitmq/client/MetricsCollector.java | 4 ++-- src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java | 4 ++-- .../com/rabbitmq/client/impl/AbstractMetricsCollector.java | 4 ++-- src/main/java/com/rabbitmq/client/impl/ChannelN.java | 6 ++++++ 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/MetricsCollector.java b/src/main/java/com/rabbitmq/client/MetricsCollector.java index a67918a4b2..101948e6b9 100644 --- a/src/main/java/com/rabbitmq/client/MetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/MetricsCollector.java @@ -38,9 +38,9 @@ public interface MetricsCollector { void basicPublishFailure(Channel channel, Throwable cause); - void basicPublishAck(Channel channel); + void basicPublishAck(Channel channel, long deliveryTag, boolean multiple); - void basicPublishNack(Channel channel); + void basicPublishNack(Channel channel, long deliveryTag, boolean multiple); void basicPublishUnrouted(Channel channel); diff --git a/src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java b/src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java index 6dc4688dd2..30e0d83402 100644 --- a/src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java @@ -76,12 +76,12 @@ public void basicPublishFailure(Channel channel, Throwable cause) { } @Override - public void basicPublishAck(Channel channel) { + public void basicPublishAck(Channel channel, long deliveryTag, boolean multiple) { } @Override - public void basicPublishNack(Channel channel) { + public void basicPublishNack(Channel channel, long deliveryTag, boolean multiple) { } diff --git a/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java index 6894d09ca4..fd1553acaf 100644 --- a/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java @@ -112,7 +112,7 @@ public void basicPublishFailure(Channel channel, Throwable cause) { } @Override - public void basicPublishAck(Channel channel) { + public void basicPublishAck(Channel channel, long deliveryTag, boolean multiple) { try { markMessagePublishAcknowledged(); } catch(Exception e) { @@ -121,7 +121,7 @@ public void basicPublishAck(Channel channel) { } @Override - public void basicPublishNack(Channel channel) { + public void basicPublishNack(Channel channel, long deliveryTag, boolean multiple) { try { markMessagePublishNotAcknowledged(); } catch(Exception e) { diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java index 1685c249a0..17bee9ffe7 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelN.java @@ -481,6 +481,8 @@ private void callReturnListeners(Command command, Basic.Return basicReturn) { } } catch (Throwable ex) { getConnection().getExceptionHandler().handleReturnListenerException(this, ex); + } finally { + metricsCollector.basicPublishUnrouted(this); } } @@ -491,6 +493,8 @@ private void callConfirmListeners(@SuppressWarnings("unused") Command command, B } } catch (Throwable ex) { getConnection().getExceptionHandler().handleConfirmListenerException(this, ex); + } finally { + metricsCollector.basicPublishAck(this, ack.getDeliveryTag(), ack.getMultiple()); } } @@ -501,6 +505,8 @@ private void callConfirmListeners(@SuppressWarnings("unused") Command command, B } } catch (Throwable ex) { getConnection().getExceptionHandler().handleConfirmListenerException(this, ex); + } finally { + metricsCollector.basicPublishNack(this, nack.getDeliveryTag(), nack.getMultiple()); } } From 5bff5dd0bab1e333c59889c77ab9a1d86ddf3999 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Turek?= Date: Tue, 24 Apr 2018 12:37:16 +0200 Subject: [PATCH 0760/2114] #354 | ignore acks and nacks for multiple messages Metrics for multiple acks and nacks are unsupported in this naive approach. --- .../rabbitmq/client/impl/AbstractMetricsCollector.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java index fd1553acaf..99a5b7a138 100644 --- a/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java @@ -113,6 +113,10 @@ public void basicPublishFailure(Channel channel, Throwable cause) { @Override public void basicPublishAck(Channel channel, long deliveryTag, boolean multiple) { + if (multiple) { + // this is a naive approach, as it does not handle multiple nacks + return; + } try { markMessagePublishAcknowledged(); } catch(Exception e) { @@ -122,6 +126,10 @@ public void basicPublishAck(Channel channel, long deliveryTag, boolean multiple) @Override public void basicPublishNack(Channel channel, long deliveryTag, boolean multiple) { + if (multiple) { + // this is a naive approach, as it does not handle multiple nacks + return; + } try { markMessagePublishNotAcknowledged(); } catch(Exception e) { From cbf70455018e5b6f467b4d997922640d2e07b101 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Turek?= Date: Tue, 24 Apr 2018 14:11:46 +0200 Subject: [PATCH 0761/2114] #354 | fix acks --- .../java/com/rabbitmq/client/impl/StandardMetricsCollector.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java index a4062eb3b7..29240bcc48 100644 --- a/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java @@ -116,7 +116,7 @@ protected void markRejectedMessage() { @Override protected void markMessagePublishAcknowledged() { - acknowledgedMessages.mark(); + publishAcknowledgedMessages.mark(); } @Override From bb88600df886565fc67357c2e3d423ee50c7aa22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 25 Apr 2018 11:38:26 +0200 Subject: [PATCH 0762/2114] Update documentation to run tests [#157080754] Fixes #359 --- Makefile | 6 +++- RUNNING_TESTS.md | 81 ++++++++++++++++++++++++++++-------------------- 2 files changed, 52 insertions(+), 35 deletions(-) diff --git a/Makefile b/Makefile index 8bb2365baf..010b2342a0 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ MVN_FLAGS += -Ddeps.dir="$(abspath $(DEPS_DIR))" all: deps $(MVN) $(MVN_FLAGS) compile -deps: $(DEPS_DIR)/rabbit +deps: $(DEPS_DIR)/rabbit $(DEPS_DIR)/rabbitmq-ct-helpers @: dist: clean @@ -26,6 +26,10 @@ $(DEPS_DIR)/rabbit: git clone https://github.com/rabbitmq/rabbitmq-server.git $@ $(MAKE) -C $@ fetch-deps DEPS_DIR="$(abspath $(DEPS_DIR))" +$(DEPS_DIR)/rabbitmq-ct-helpers: + rm -rf $(DEPS_DIR)/rabbitmq_ct_helpers + git clone https://github.com/rabbitmq/rabbitmq-ct-helpers.git $(DEPS_DIR)/rabbitmq_ct_helpers + tests: deps $(MVN) $(MVN_FLAGS) verify diff --git a/RUNNING_TESTS.md b/RUNNING_TESTS.md index 157b2e1ff9..2619d9699f 100644 --- a/RUNNING_TESTS.md +++ b/RUNNING_TESTS.md @@ -19,21 +19,21 @@ SSL port. HA tests expect a second node listening on localhost:5673. Connection recovery tests need `rabbitmqctl` to control the running nodes. can control the running node. -`mvn verify` will start those nodes with the appropriate configuration. +`./mvnw verify` will start those nodes with the appropriate configuration. -To easily fullfil all those requirements, you can use `make deps` to -fetch the dependencies. You can also fetch them yourself and use the -same layout: +To easily fullfil all those requirements, you should use `make deps` to +fetch the dependencies in the `deps` directory. +You then run Maven with the `deps.dir` property set like this: ``` -deps -|-- rabbitmq_codegen -`-- rabbit +./mvnw -Ddeps.dir=$(pwd)/deps verify ``` -You then run Maven with the `deps.dir` property set like this: +The previous command launches tests against the blocking IO connector. If you want +to run the tests against the NIO connector, add `-P use-nio` to the command line: + ``` -mvn -Ddeps.dir=/path/to/deps verify +./mvnw -Ddeps.dir=$(pwd)/deps verify -P use-nio ``` For details on running specific tests, see below. @@ -47,47 +47,45 @@ top-level directory of the source tree: * To run the client unit tests: ``` -mvn -Ddeps.dir=/path/to/deps verify -Dit.test=ClientTests +./mvnw -Ddeps.dir=$(pwd)/deps verify -Dit.test=ClientTests ``` * To run the functional tests: ``` -mvn -Ddeps.dir=/path/to/deps verify -Dit.test=FunctionalTests +./mvnw -Ddeps.dir=$(pwd)/deps verify -Dit.test=FunctionalTests ``` * To run a single test: - ``` -mvn -Ddeps.dir=/path/to/deps verify -Dit.test=DeadLetterExchange +``` +./mvnw -Ddeps.dir=$(pwd)/deps/deps verify -Dit.test=DeadLetterExchange ``` For example, to run the client tests: ``` -rabbitmq-java-client$ mvn -Ddeps.dir=/path/to/deps verify -Dit.test=ClientTests +rabbitmq-java-client$ ./mvnw -Ddeps.dir=$(pwd)/deps verify -Dit.test=ClientTests [INFO] Scanning for projects... -[INFO] Inspecting build with total of 1 modules... -[INFO] Installing Nexus Staging features: -[INFO] ... total of 1 executions of maven-deploy-plugin replaced with nexus-staging-maven-plugin [INFO] [INFO] ------------------------------------------------------------------------ -[INFO] Building RabbitMQ Java Client 3.7.0-SNAPSHOT +[INFO] Building RabbitMQ Java Client 5.3.0-SNAPSHOT [INFO] ------------------------------------------------------------------------ [INFO] [INFO] --- groovy-maven-plugin:2.0:execute (generate-amqp-sources) @ amqp-client --- [INFO] [INFO] --- build-helper-maven-plugin:1.12:add-source (add-generated-sources-dir) @ amqp-client --- -[INFO] Source directory: .../rabbitmq_java_client/target/generated-sources/src/main/java added. +[INFO] Source directory: .../rabbitmq-java-client/target/generated-sources/src/main/java added. [INFO] -[INFO] --- maven-resources-plugin:2.5:resources (default-resources) @ amqp-client --- -[debug] execute contextualize +[INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ amqp-client --- [INFO] Using 'UTF-8' encoding to copy filtered resources. -[INFO] Copying 1 resource +[INFO] Copying 2 resources [INFO] -[INFO] --- maven-compiler-plugin:3.5.1:compile (default-compile) @ amqp-client --- +[INFO] --- maven-compiler-plugin:3.6.1:compile (default-compile) @ amqp-client --- [INFO] Nothing to compile - all classes are up to date [INFO] +[INFO] --- maven-bundle-plugin:3.2.0:manifest (bundle-manifest) @ amqp-client --- +[INFO] [INFO] --- groovy-maven-plugin:2.0:execute (remove-old-test-keystores) @ amqp-client --- [INFO] [INFO] --- groovy-maven-plugin:2.0:execute (query-test-tls-certs-dir) @ amqp-client --- @@ -100,19 +98,31 @@ rabbitmq-java-client$ mvn -Ddeps.dir=/path/to/deps verify -Dit.test=ClientTests [INFO] [INFO] --- keytool-maven-plugin:1.5:deleteAlias (generate-test-empty-keystore) @ amqp-client --- [INFO] -[INFO] --- maven-resources-plugin:2.5:testResources (default-testResources) @ amqp-client --- -[debug] execute contextualize +[INFO] --- maven-resources-plugin:3.0.2:testResources (default-testResources) @ amqp-client --- [INFO] Using 'UTF-8' encoding to copy filtered resources. -[INFO] Copying 3 resources +[INFO] Copying 5 resources [INFO] -[INFO] --- maven-compiler-plugin:3.5.1:testCompile (default-testCompile) @ amqp-client --- +[INFO] --- maven-compiler-plugin:3.6.1:testCompile (default-testCompile) @ amqp-client --- [INFO] Nothing to compile - all classes are up to date [INFO] [INFO] --- maven-surefire-plugin:2.19.1:test (default-test) @ amqp-client --- [INFO] Tests are skipped. [INFO] [INFO] --- maven-jar-plugin:3.0.2:jar (default-jar) @ amqp-client --- -[INFO] Building jar: .../rabbitmq_java_client/target/amqp-client-3.7.0-SNAPSHOT.jar +[INFO] Building jar: .../rabbitmq-java-client/target/amqp-client-5.3.0-SNAPSHOT.jar +[INFO] +[INFO] >>> maven-source-plugin:3.0.1:jar (default) > generate-sources @ amqp-client >>> +[INFO] +[INFO] --- groovy-maven-plugin:2.0:execute (generate-amqp-sources) @ amqp-client --- +[INFO] +[INFO] --- build-helper-maven-plugin:1.12:add-source (add-generated-sources-dir) @ amqp-client --- +[INFO] Source directory: .../rabbitmq-java-client/target/generated-sources/src/main/java added. +[INFO] +[INFO] <<< maven-source-plugin:3.0.1:jar (default) < generate-sources @ amqp-client <<< +[INFO] +[INFO] +[INFO] --- maven-source-plugin:3.0.1:jar (default) @ amqp-client --- +[INFO] Building jar: .../rabbitmq-java-client/target/amqp-client-5.3.0-SNAPSHOT-sources.jar [INFO] [INFO] --- groovy-maven-plugin:2.0:execute (start-test-broker-A) @ amqp-client --- [INFO] @@ -123,14 +133,14 @@ rabbitmq-java-client$ mvn -Ddeps.dir=/path/to/deps verify -Dit.test=ClientTests [INFO] --- maven-failsafe-plugin:2.19.1:integration-test (integration-test) @ amqp-client --- ------------------------------------------------------- - T E S T S +T E S T S ------------------------------------------------------- Running com.rabbitmq.client.test.ClientTests -Tests run: 50, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.732 sec - in com.rabbitmq.client.test.ClientTests +Tests run: 121, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 58.869 sec - in com.rabbitmq.client.test.ClientTests Results : -Tests run: 50, Failures: 0, Errors: 0, Skipped: 0 +Tests run: 121, Failures: 0, Errors: 0, Skipped: 0 [INFO] [INFO] --- groovy-maven-plugin:2.0:execute (stop-test-broker-B) @ amqp-client --- @@ -141,9 +151,9 @@ Tests run: 50, Failures: 0, Errors: 0, Skipped: 0 [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ -[INFO] Total time: 33.707s -[INFO] Finished at: Mon Aug 08 16:22:26 CEST 2016 -[INFO] Final Memory: 21M/256M +[INFO] Total time: 01:31 min +[INFO] Finished at: 2018-04-25T11:33:54+02:00 +[INFO] Final Memory: 26M/336M [INFO] ------------------------------------------------------------------------ ``` @@ -163,3 +173,6 @@ profile: ``` mvn verify -P '!setup-test-cluster' ``` + +Note that by doing so some tests will fail as they require `rabbitmqctl` to +control the running nodes. \ No newline at end of file From 8c5a1af8699eab82cea1c5c140dcc41990482d31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 25 Apr 2018 15:14:35 +0200 Subject: [PATCH 0763/2114] Set version to 5.2.0 in readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a42047ddb6..43fe167209 100644 --- a/README.md +++ b/README.md @@ -23,14 +23,14 @@ These versions can still be used with RabbitMQ server `3.x`. com.rabbitmq amqp-client - 5.1.2 + 5.2.0 ``` ### Gradle ``` groovy -compile 'com.rabbitmq:amqp-client:5.1.2' +compile 'com.rabbitmq:amqp-client:5.2.0' ``` #### 3.6.x Series From 6d7253af8ff72841153ba1ea610294dc614ce84b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 25 Apr 2018 16:00:37 +0200 Subject: [PATCH 0764/2114] Don't repeat rabbitmq-ct-helpers task in Makefile [#157080754] Fixes #359 --- Makefile | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 010b2342a0..f38700bf84 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ MVN_FLAGS += -Ddeps.dir="$(abspath $(DEPS_DIR))" all: deps $(MVN) $(MVN_FLAGS) compile -deps: $(DEPS_DIR)/rabbit $(DEPS_DIR)/rabbitmq-ct-helpers +deps: $(DEPS_DIR)/rabbit $(DEPS_DIR)/rabbitmq_ct_helpers @: dist: clean @@ -26,8 +26,7 @@ $(DEPS_DIR)/rabbit: git clone https://github.com/rabbitmq/rabbitmq-server.git $@ $(MAKE) -C $@ fetch-deps DEPS_DIR="$(abspath $(DEPS_DIR))" -$(DEPS_DIR)/rabbitmq-ct-helpers: - rm -rf $(DEPS_DIR)/rabbitmq_ct_helpers +$(DEPS_DIR)/rabbitmq_ct_helpers: git clone https://github.com/rabbitmq/rabbitmq-ct-helpers.git $(DEPS_DIR)/rabbitmq_ct_helpers tests: deps From 516f7a34ba26f3c0d3b7836b8678d367c54cd205 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 25 Apr 2018 11:38:26 +0200 Subject: [PATCH 0765/2114] Update documentation to run tests [#157080754] Fixes #359 (cherry picked from commit bb88600df886565fc67357c2e3d423ee50c7aa22) --- Makefile | 6 +++- RUNNING_TESTS.md | 81 ++++++++++++++++++++++++++++-------------------- 2 files changed, 52 insertions(+), 35 deletions(-) diff --git a/Makefile b/Makefile index 8bb2365baf..010b2342a0 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ MVN_FLAGS += -Ddeps.dir="$(abspath $(DEPS_DIR))" all: deps $(MVN) $(MVN_FLAGS) compile -deps: $(DEPS_DIR)/rabbit +deps: $(DEPS_DIR)/rabbit $(DEPS_DIR)/rabbitmq-ct-helpers @: dist: clean @@ -26,6 +26,10 @@ $(DEPS_DIR)/rabbit: git clone https://github.com/rabbitmq/rabbitmq-server.git $@ $(MAKE) -C $@ fetch-deps DEPS_DIR="$(abspath $(DEPS_DIR))" +$(DEPS_DIR)/rabbitmq-ct-helpers: + rm -rf $(DEPS_DIR)/rabbitmq_ct_helpers + git clone https://github.com/rabbitmq/rabbitmq-ct-helpers.git $(DEPS_DIR)/rabbitmq_ct_helpers + tests: deps $(MVN) $(MVN_FLAGS) verify diff --git a/RUNNING_TESTS.md b/RUNNING_TESTS.md index 157b2e1ff9..2619d9699f 100644 --- a/RUNNING_TESTS.md +++ b/RUNNING_TESTS.md @@ -19,21 +19,21 @@ SSL port. HA tests expect a second node listening on localhost:5673. Connection recovery tests need `rabbitmqctl` to control the running nodes. can control the running node. -`mvn verify` will start those nodes with the appropriate configuration. +`./mvnw verify` will start those nodes with the appropriate configuration. -To easily fullfil all those requirements, you can use `make deps` to -fetch the dependencies. You can also fetch them yourself and use the -same layout: +To easily fullfil all those requirements, you should use `make deps` to +fetch the dependencies in the `deps` directory. +You then run Maven with the `deps.dir` property set like this: ``` -deps -|-- rabbitmq_codegen -`-- rabbit +./mvnw -Ddeps.dir=$(pwd)/deps verify ``` -You then run Maven with the `deps.dir` property set like this: +The previous command launches tests against the blocking IO connector. If you want +to run the tests against the NIO connector, add `-P use-nio` to the command line: + ``` -mvn -Ddeps.dir=/path/to/deps verify +./mvnw -Ddeps.dir=$(pwd)/deps verify -P use-nio ``` For details on running specific tests, see below. @@ -47,47 +47,45 @@ top-level directory of the source tree: * To run the client unit tests: ``` -mvn -Ddeps.dir=/path/to/deps verify -Dit.test=ClientTests +./mvnw -Ddeps.dir=$(pwd)/deps verify -Dit.test=ClientTests ``` * To run the functional tests: ``` -mvn -Ddeps.dir=/path/to/deps verify -Dit.test=FunctionalTests +./mvnw -Ddeps.dir=$(pwd)/deps verify -Dit.test=FunctionalTests ``` * To run a single test: - ``` -mvn -Ddeps.dir=/path/to/deps verify -Dit.test=DeadLetterExchange +``` +./mvnw -Ddeps.dir=$(pwd)/deps/deps verify -Dit.test=DeadLetterExchange ``` For example, to run the client tests: ``` -rabbitmq-java-client$ mvn -Ddeps.dir=/path/to/deps verify -Dit.test=ClientTests +rabbitmq-java-client$ ./mvnw -Ddeps.dir=$(pwd)/deps verify -Dit.test=ClientTests [INFO] Scanning for projects... -[INFO] Inspecting build with total of 1 modules... -[INFO] Installing Nexus Staging features: -[INFO] ... total of 1 executions of maven-deploy-plugin replaced with nexus-staging-maven-plugin [INFO] [INFO] ------------------------------------------------------------------------ -[INFO] Building RabbitMQ Java Client 3.7.0-SNAPSHOT +[INFO] Building RabbitMQ Java Client 5.3.0-SNAPSHOT [INFO] ------------------------------------------------------------------------ [INFO] [INFO] --- groovy-maven-plugin:2.0:execute (generate-amqp-sources) @ amqp-client --- [INFO] [INFO] --- build-helper-maven-plugin:1.12:add-source (add-generated-sources-dir) @ amqp-client --- -[INFO] Source directory: .../rabbitmq_java_client/target/generated-sources/src/main/java added. +[INFO] Source directory: .../rabbitmq-java-client/target/generated-sources/src/main/java added. [INFO] -[INFO] --- maven-resources-plugin:2.5:resources (default-resources) @ amqp-client --- -[debug] execute contextualize +[INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ amqp-client --- [INFO] Using 'UTF-8' encoding to copy filtered resources. -[INFO] Copying 1 resource +[INFO] Copying 2 resources [INFO] -[INFO] --- maven-compiler-plugin:3.5.1:compile (default-compile) @ amqp-client --- +[INFO] --- maven-compiler-plugin:3.6.1:compile (default-compile) @ amqp-client --- [INFO] Nothing to compile - all classes are up to date [INFO] +[INFO] --- maven-bundle-plugin:3.2.0:manifest (bundle-manifest) @ amqp-client --- +[INFO] [INFO] --- groovy-maven-plugin:2.0:execute (remove-old-test-keystores) @ amqp-client --- [INFO] [INFO] --- groovy-maven-plugin:2.0:execute (query-test-tls-certs-dir) @ amqp-client --- @@ -100,19 +98,31 @@ rabbitmq-java-client$ mvn -Ddeps.dir=/path/to/deps verify -Dit.test=ClientTests [INFO] [INFO] --- keytool-maven-plugin:1.5:deleteAlias (generate-test-empty-keystore) @ amqp-client --- [INFO] -[INFO] --- maven-resources-plugin:2.5:testResources (default-testResources) @ amqp-client --- -[debug] execute contextualize +[INFO] --- maven-resources-plugin:3.0.2:testResources (default-testResources) @ amqp-client --- [INFO] Using 'UTF-8' encoding to copy filtered resources. -[INFO] Copying 3 resources +[INFO] Copying 5 resources [INFO] -[INFO] --- maven-compiler-plugin:3.5.1:testCompile (default-testCompile) @ amqp-client --- +[INFO] --- maven-compiler-plugin:3.6.1:testCompile (default-testCompile) @ amqp-client --- [INFO] Nothing to compile - all classes are up to date [INFO] [INFO] --- maven-surefire-plugin:2.19.1:test (default-test) @ amqp-client --- [INFO] Tests are skipped. [INFO] [INFO] --- maven-jar-plugin:3.0.2:jar (default-jar) @ amqp-client --- -[INFO] Building jar: .../rabbitmq_java_client/target/amqp-client-3.7.0-SNAPSHOT.jar +[INFO] Building jar: .../rabbitmq-java-client/target/amqp-client-5.3.0-SNAPSHOT.jar +[INFO] +[INFO] >>> maven-source-plugin:3.0.1:jar (default) > generate-sources @ amqp-client >>> +[INFO] +[INFO] --- groovy-maven-plugin:2.0:execute (generate-amqp-sources) @ amqp-client --- +[INFO] +[INFO] --- build-helper-maven-plugin:1.12:add-source (add-generated-sources-dir) @ amqp-client --- +[INFO] Source directory: .../rabbitmq-java-client/target/generated-sources/src/main/java added. +[INFO] +[INFO] <<< maven-source-plugin:3.0.1:jar (default) < generate-sources @ amqp-client <<< +[INFO] +[INFO] +[INFO] --- maven-source-plugin:3.0.1:jar (default) @ amqp-client --- +[INFO] Building jar: .../rabbitmq-java-client/target/amqp-client-5.3.0-SNAPSHOT-sources.jar [INFO] [INFO] --- groovy-maven-plugin:2.0:execute (start-test-broker-A) @ amqp-client --- [INFO] @@ -123,14 +133,14 @@ rabbitmq-java-client$ mvn -Ddeps.dir=/path/to/deps verify -Dit.test=ClientTests [INFO] --- maven-failsafe-plugin:2.19.1:integration-test (integration-test) @ amqp-client --- ------------------------------------------------------- - T E S T S +T E S T S ------------------------------------------------------- Running com.rabbitmq.client.test.ClientTests -Tests run: 50, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.732 sec - in com.rabbitmq.client.test.ClientTests +Tests run: 121, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 58.869 sec - in com.rabbitmq.client.test.ClientTests Results : -Tests run: 50, Failures: 0, Errors: 0, Skipped: 0 +Tests run: 121, Failures: 0, Errors: 0, Skipped: 0 [INFO] [INFO] --- groovy-maven-plugin:2.0:execute (stop-test-broker-B) @ amqp-client --- @@ -141,9 +151,9 @@ Tests run: 50, Failures: 0, Errors: 0, Skipped: 0 [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ -[INFO] Total time: 33.707s -[INFO] Finished at: Mon Aug 08 16:22:26 CEST 2016 -[INFO] Final Memory: 21M/256M +[INFO] Total time: 01:31 min +[INFO] Finished at: 2018-04-25T11:33:54+02:00 +[INFO] Final Memory: 26M/336M [INFO] ------------------------------------------------------------------------ ``` @@ -163,3 +173,6 @@ profile: ``` mvn verify -P '!setup-test-cluster' ``` + +Note that by doing so some tests will fail as they require `rabbitmqctl` to +control the running nodes. \ No newline at end of file From 9e29ced609736e9be701a85e53f363a6beefd27a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 25 Apr 2018 16:00:37 +0200 Subject: [PATCH 0766/2114] Don't repeat rabbitmq-ct-helpers task in Makefile [#157080754] Fixes #359 (cherry picked from commit 6d7253af8ff72841153ba1ea610294dc614ce84b) --- Makefile | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 010b2342a0..f38700bf84 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ MVN_FLAGS += -Ddeps.dir="$(abspath $(DEPS_DIR))" all: deps $(MVN) $(MVN_FLAGS) compile -deps: $(DEPS_DIR)/rabbit $(DEPS_DIR)/rabbitmq-ct-helpers +deps: $(DEPS_DIR)/rabbit $(DEPS_DIR)/rabbitmq_ct_helpers @: dist: clean @@ -26,8 +26,7 @@ $(DEPS_DIR)/rabbit: git clone https://github.com/rabbitmq/rabbitmq-server.git $@ $(MAKE) -C $@ fetch-deps DEPS_DIR="$(abspath $(DEPS_DIR))" -$(DEPS_DIR)/rabbitmq-ct-helpers: - rm -rf $(DEPS_DIR)/rabbitmq_ct_helpers +$(DEPS_DIR)/rabbitmq_ct_helpers: git clone https://github.com/rabbitmq/rabbitmq-ct-helpers.git $(DEPS_DIR)/rabbitmq_ct_helpers tests: deps From 56634ae76b2a9f0ce390fec068672478062488ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 26 Apr 2018 11:20:40 +0200 Subject: [PATCH 0767/2114] Use $@ Make variable to reduce repetition Per @dumbbell recommendation. [#157080754] References #359 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f38700bf84..13f9fa779c 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,7 @@ $(DEPS_DIR)/rabbit: $(MAKE) -C $@ fetch-deps DEPS_DIR="$(abspath $(DEPS_DIR))" $(DEPS_DIR)/rabbitmq_ct_helpers: - git clone https://github.com/rabbitmq/rabbitmq-ct-helpers.git $(DEPS_DIR)/rabbitmq_ct_helpers + git clone https://github.com/rabbitmq/rabbitmq-ct-helpers.git "$@" tests: deps $(MVN) $(MVN_FLAGS) verify From 4b8ab88117da46b35a60fc4d37751ae31537e21a Mon Sep 17 00:00:00 2001 From: igor_bolotin Date: Fri, 27 Apr 2018 21:57:05 -0700 Subject: [PATCH 0768/2114] Throw an exception instead of trying to transmit a header frame that exceeds max frame size --- .../com/rabbitmq/client/impl/AMQCommand.java | 13 +++-- .../client/test/functional/FrameMax.java | 47 +++++++++++++++++++ 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/AMQCommand.java b/src/main/java/com/rabbitmq/client/impl/AMQCommand.java index 5543ee7c1f..e4457076c9 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQCommand.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQCommand.java @@ -101,17 +101,22 @@ public void transmit(AMQChannel channel) throws IOException { synchronized (assembler) { Method m = this.assembler.getMethod(); - connection.writeFrame(m.toFrame(channelNumber)); if (m.hasContent()) { byte[] body = this.assembler.getContentBody(); - connection.writeFrame(this.assembler.getContentHeader() - .toFrame(channelNumber, body.length)); + Frame headerFrame = this.assembler.getContentHeader().toFrame(channelNumber, body.length); int frameMax = connection.getFrameMax(); int bodyPayloadMax = (frameMax == 0) ? body.length : frameMax - EMPTY_FRAME_SIZE; + if (headerFrame.size() > frameMax) { + throw new IllegalArgumentException("Content headers exceeded max frame size: " + + headerFrame.size() + " > " + frameMax); + } + connection.writeFrame(m.toFrame(channelNumber)); + connection.writeFrame(headerFrame); + for (int offset = 0; offset < body.length; offset += bodyPayloadMax) { int remaining = body.length - offset; @@ -121,6 +126,8 @@ public void transmit(AMQChannel channel) throws IOException { offset, fragmentLength); connection.writeFrame(frame); } + } else { + connection.writeFrame(m.toFrame(channelNumber)); } } diff --git a/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java b/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java index 7e1019c4cb..07d7eb9d9f 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java +++ b/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java @@ -17,11 +17,16 @@ package com.rabbitmq.client.test.functional; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; import java.io.IOException; import java.net.Socket; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeoutException; @@ -35,6 +40,7 @@ import com.rabbitmq.client.GetResponse; import com.rabbitmq.client.impl.AMQCommand; import com.rabbitmq.client.impl.AMQConnection; +import com.rabbitmq.client.impl.ContentHeaderPropertyWriter; import com.rabbitmq.client.impl.Frame; import com.rabbitmq.client.impl.FrameHandler; import com.rabbitmq.client.impl.LongStringHelper; @@ -104,6 +110,47 @@ public FrameMax() { expectError(AMQP.FRAME_ERROR); } + /* client should throw exception if headers exceed negotiated + * frame size */ + @Test public void rejectHeadersExceedingFrameMax() + throws IOException, TimeoutException { + declareTransientTopicExchange("x"); + String queueName = channel.queueDeclare().getQueue(); + channel.queueBind(queueName, "x", "foobar"); + + Map headers = new HashMap(); + String headerName = "x-huge-header"; + + // create headers with zero-length value to calculate maximum header value size before exceeding frame_max + headers.put(headerName, LongStringHelper.asLongString(new byte[0])); + AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder().headers(headers).build(); + Frame minimalHeaderFrame = properties.toFrame(0, 0); + int maxHeaderValueSize = FRAME_MAX - minimalHeaderFrame.size(); + + // create headers with maximum header value size (frame size equals frame_max) + headers.put(headerName, LongStringHelper.asLongString(new byte[maxHeaderValueSize])); + properties = new AMQP.BasicProperties.Builder().headers(headers).build(); + + basicPublishVolatile(new byte[100], "x", "foobar", properties); + assertDelivered(queueName, 1); + + // create headers with frame size exceeding frame_max by 1 + headers.put(headerName, LongStringHelper.asLongString(new byte[maxHeaderValueSize + 1])); + properties = new AMQP.BasicProperties.Builder().headers(headers).build(); + try { + basicPublishVolatile(new byte[100], "x", "foobar", properties); + fail("expected rejectHeadersExceedingFrameMax to throw"); + } catch (IllegalArgumentException iae) { + assertTrue(iae.getMessage().startsWith("Content headers exceeded max frame size")); + // check that the channel is still operational + assertDelivered(queueName, 0); + } + + // cleanup + deleteExchange("x"); + } + + /* ConnectionFactory that uses MyFrameHandler rather than * SocketFrameHandler. */ private static class MyConnectionFactory extends ConnectionFactory { From eafb9dfa301173df8aa0c92387c8fdab48ff6d48 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 11 May 2018 22:58:59 -0500 Subject: [PATCH 0769/2114] Tests for priority validation Part of rabbitmq/rabbitmq-server#1590. [#157380396] --- .../client/test/server/PriorityQueues.java | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/test/java/com/rabbitmq/client/test/server/PriorityQueues.java b/src/test/java/com/rabbitmq/client/test/server/PriorityQueues.java index af16b2135c..a8687a5108 100644 --- a/src/test/java/com/rabbitmq/client/test/server/PriorityQueues.java +++ b/src/test/java/com/rabbitmq/client/test/server/PriorityQueues.java @@ -48,6 +48,40 @@ public class PriorityQueues extends BrokerTestCase { channel.queueDelete(q); } + @Test public void negativeMaxPriority() throws IOException, TimeoutException, InterruptedException { + String q = "with-minus-10-priorities"; + int n = -10; + try { + channel.queueDeclare(q, true, false, false, argsWithPriorities(n)); + } catch (IOException ioe) { + checkShutdownSignal(AMQP.PRECONDITION_FAILED, ioe); + } + } + + @Test public void excessiveMaxPriority() throws IOException, TimeoutException, InterruptedException { + String q = "with-260-priorities"; + int n = 260; + try { + channel.queueDeclare(q, true, false, false, argsWithPriorities(n)); + } catch (IOException ioe) { + checkShutdownSignal(AMQP.PRECONDITION_FAILED, ioe); + } + } + + @Test public void maxAllowedPriority() throws IOException, TimeoutException, InterruptedException { + String q = "with-255-priorities"; + int n = 255; + channel.queueDeclare(q, true, false, false, argsWithPriorities(n)); + publishWithPriorities(q, n); + + List xs = prioritiesOfEnqueuedMessages(q, n); + assertEquals(Integer.valueOf(255), xs.get(0)); + assertEquals(Integer.valueOf(254), xs.get(1)); + assertEquals(Integer.valueOf(253), xs.get(2)); + + channel.queueDelete(q); + } + private List prioritiesOfEnqueuedMessages(String q, int n) throws InterruptedException, IOException { final List xs = new ArrayList(); final CountDownLatch latch = new CountDownLatch(n); From c454b63c713386c3caf1c0086a931b3804fd1a35 Mon Sep 17 00:00:00 2001 From: Michael Dent Date: Tue, 15 May 2018 00:37:53 -0500 Subject: [PATCH 0770/2114] parallel recovery --- .../rabbitmq/client/ConnectionFactory.java | 17 +- .../client/impl/ConnectionParams.java | 13 +- .../recovery/AutorecoveringConnection.java | 231 +++++++++++------- .../impl/recovery/RecordedConsumer.java | 5 + .../impl/recovery/RecordedExchange.java | 5 + .../recovery/RecordedExchangeBinding.java | 5 + .../client/impl/recovery/RecordedQueue.java | 5 + .../impl/recovery/RecordedQueueBinding.java | 5 + 8 files changed, 190 insertions(+), 96 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 9546be9f07..5a7e8c0582 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -127,7 +127,8 @@ public class ConnectionFactory implements Cloneable { private boolean automaticRecovery = true; private boolean topologyRecovery = true; - + private int topologyRecoveryThreads = 1; + // long is used to make sure the users can use both ints // and longs safely. It is unlikely that anybody'd need // to use recovery intervals > Integer.MAX_VALUE in practice. @@ -339,7 +340,7 @@ public void setUri(String uriString) setUri(new URI(uriString)); } - private String uriDecode(String s) { + private static String uriDecode(String s) { try { // URLDecode decodes '+' to a space, as for // form encoding. So protect plus signs. @@ -523,7 +524,6 @@ public void setSocketFactory(SocketFactory factory) { * * @see #setSocketConfigurator(SocketConfigurator) */ - @SuppressWarnings("unused") public SocketConfigurator getSocketConfigurator() { return socketConf; } @@ -701,7 +701,6 @@ public void setAutomaticRecoveryEnabled(boolean automaticRecovery) { * @return true if topology recovery is enabled, false otherwise * @see Automatic Recovery */ - @SuppressWarnings("unused") public boolean isTopologyRecoveryEnabled() { return topologyRecovery; } @@ -714,6 +713,15 @@ public boolean isTopologyRecoveryEnabled() { public void setTopologyRecoveryEnabled(boolean topologyRecovery) { this.topologyRecovery = topologyRecovery; } + + public int getTopologyRecoveryThreadCount() { + return topologyRecoveryThreads; + } + + // TODO Document that your exception handler method should be thread safe + public void setTopologyRecoveryThreadCount(final int topologyRecoveryThreads) { + this.topologyRecoveryThreads = topologyRecoveryThreads; + } public void setMetricsCollector(MetricsCollector metricsCollector) { this.metricsCollector = metricsCollector; @@ -1013,6 +1021,7 @@ public ConnectionParams params(ExecutorService consumerWorkServiceExecutor) { result.setNetworkRecoveryInterval(networkRecoveryInterval); result.setRecoveryDelayHandler(recoveryDelayHandler); result.setTopologyRecovery(topologyRecovery); + result.setTopologyRecoveryThreadCount(topologyRecoveryThreads); result.setExceptionHandler(exceptionHandler); result.setThreadFactory(threadFactory); result.setHandshakeTimeout(handshakeTimeout); diff --git a/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java b/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java index 05a3d096b7..0fe4e7c2cd 100644 --- a/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java +++ b/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java @@ -41,6 +41,7 @@ public class ConnectionParams { private long networkRecoveryInterval; private RecoveryDelayHandler recoveryDelayHandler; private boolean topologyRecovery; + private int topologyRecoveryThreads = 1; private int channelRpcTimeout; private boolean channelShouldCheckRpcResponseType; private ErrorOnWriteListener errorOnWriteListener; @@ -114,10 +115,14 @@ public RecoveryDelayHandler getRecoveryDelayHandler() { public boolean isTopologyRecoveryEnabled() { return topologyRecovery; } + + public int getTopologyRecoveryThreadCount() { + return topologyRecoveryThreads; + } public ThreadFactory getThreadFactory() { - return threadFactory; - } + return threadFactory; + } public int getChannelRpcTimeout() { return channelRpcTimeout; @@ -174,6 +179,10 @@ public void setRecoveryDelayHandler(final RecoveryDelayHandler recoveryDelayHand public void setTopologyRecovery(boolean topologyRecovery) { this.topologyRecovery = topologyRecovery; } + + public void setTopologyRecoveryThreadCount(final int topologyRecoveryThreads) { + this.topologyRecoveryThreads = topologyRecoveryThreads; + } public void setExceptionHandler(ExceptionHandler exceptionHandler) { this.exceptionHandler = exceptionHandler; diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index 0f976b5ca3..e225800c5c 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -28,8 +28,10 @@ import java.io.IOException; import java.net.InetAddress; import java.util.*; +import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeoutException; import java.util.concurrent.locks.Lock; @@ -525,7 +527,7 @@ public void removeConsumerRecoveryListener(ConsumerRecoveryListener listener) { this.consumerRecoveryListeners.remove(listener); } - synchronized private void beginAutomaticRecovery() throws InterruptedException { + private synchronized void beginAutomaticRecovery() throws InterruptedException { Thread.sleep(this.params.getRecoveryDelayHandler().getDelay(0)); this.notifyRecoveryListenersStarted(); @@ -541,11 +543,9 @@ synchronized private void beginAutomaticRecovery() throws InterruptedException { this.recoverChannels(newConn); // don't assign new delegate connection until channel recovery is complete this.delegate = newConn; - if(this.params.isTopologyRecoveryEnabled()) { - this.recoverEntities(); - this.recoverConsumers(); + if (this.params.isTopologyRecoveryEnabled()) { + recoverTopology(params.getTopologyRecoveryThreadCount()); } - this.notifyRecoveryListenersComplete(); } @@ -591,8 +591,10 @@ private RecoveryAwareAMQConnection recoverConnection() throws InterruptedExcepti private void recoverChannels(final RecoveryAwareAMQConnection newConn) { for (AutorecoveringChannel ch : this.channels.values()) { + LOGGER.debug("Recovering channel {}", ch); try { ch.automaticallyRecover(this, newConn); + LOGGER.debug("Channel {} has recovered", ch); } catch (Throwable t) { newConn.getExceptionHandler().handleChannelRecoveryException(ch, t); } @@ -610,113 +612,126 @@ private void notifyRecoveryListenersStarted() { f.handleRecoveryStarted(this); } } - - private void recoverEntities() { + + private void recoverTopology(final int recoveryThreads) throws InterruptedException { // The recovery sequence is the following: - // // 1. Recover exchanges // 2. Recover queues // 3. Recover bindings // 4. Recover consumers - recoverExchanges(); - recoverQueues(); - recoverBindings(); - } - - private void recoverExchanges() { - // recorded exchanges are guaranteed to be - // non-predefined (we filter out predefined ones - // in exchangeDeclare). MK. - for (RecordedExchange x : Utility.copy(this.recordedExchanges).values()) { + if (recoveryThreads > 1) { + // Support recovering entities in parallel for connections that have a lot of queues, bindings, & consumers + // A channel is single threaded, so group things by channel and recover 1 entity at a time per channel + // We still need to recover 1 type of entity at a time in case channel1 has a binding to a queue that is currently owned and being recovered by channel2 for example + final ExecutorService executor = Executors.newFixedThreadPool(recoveryThreads, delegate.getThreadFactory()); try { - x.recover(); - } catch (Exception cause) { - final String message = "Caught an exception while recovering exchange " + x.getName() + - ": " + cause.getMessage(); - TopologyRecoveryException e = new TopologyRecoveryException(message, cause); - this.getExceptionHandler().handleTopologyRecoveryException(delegate, x.getDelegateChannel(), e); + // invokeAll will block until all callables are completed + executor.invokeAll(groupEntitiesByChannel(Utility.copy(recordedExchanges).values())); + executor.invokeAll(groupEntitiesByChannel(Utility.copy(recordedQueues).values())); + executor.invokeAll(groupEntitiesByChannel(Utility.copy(recordedBindings))); + executor.invokeAll(groupEntitiesByChannel(Utility.copy(consumers).values())); + } finally { + executor.shutdownNow(); + } + } else { + // recover entities in serial on the main connection thread + for (final RecordedExchange exchange : Utility.copy(recordedExchanges).values()) { + recoverExchange(exchange); + } + for (final Map.Entry entry : Utility.copy(recordedQueues).entrySet()) { + recoverQueue(entry.getKey(), entry.getValue()); + } + for (final RecordedBinding b : Utility.copy(recordedBindings)) { + recoverBinding(b); + } + for (final Map.Entry entry : Utility.copy(consumers).entrySet()) { + recoverConsumer(entry.getKey(), entry.getValue()); } } } - private void recoverQueues() { - for (Map.Entry entry : Utility.copy(this.recordedQueues).entrySet()) { - String oldName = entry.getKey(); - RecordedQueue q = entry.getValue(); - try { - q.recover(); - String newName = q.getName(); - if (!oldName.equals(newName)) { - // make sure server-named queues are re-added with - // their new names. MK. - synchronized (this.recordedQueues) { - this.propagateQueueNameChangeToBindings(oldName, newName); - this.propagateQueueNameChangeToConsumers(oldName, newName); - // bug26552: - // remove old name after we've updated the bindings and consumers, - // plus only for server-named queues, both to make sure we don't lose - // anything to recover. MK. - if(q.isServerNamed()) { - deleteRecordedQueue(oldName); - } - this.recordedQueues.put(newName, q); + private void recoverExchange(final RecordedExchange x) { + // recorded exchanges are guaranteed to be non-predefined (we filter out predefined ones in exchangeDeclare). MK. + LOGGER.debug("Recovering exchange {}", x); + try { + x.recover(); + LOGGER.debug("Exchange {} has recovered", x); + } catch (Exception cause) { + final String message = "Caught an exception while recovering exchange " + x.getName() + + ": " + cause.getMessage(); + TopologyRecoveryException e = new TopologyRecoveryException(message, cause); + this.getExceptionHandler().handleTopologyRecoveryException(delegate, x.getDelegateChannel(), e); + } + } + + private void recoverQueue(final String oldName, final RecordedQueue q) { + LOGGER.debug("Recovering queue {}", q); + try { + q.recover(); + String newName = q.getName(); + if (!oldName.equals(newName)) { + // make sure server-named queues are re-added with + // their new names. MK. + synchronized (this.recordedQueues) { + this.propagateQueueNameChangeToBindings(oldName, newName); + this.propagateQueueNameChangeToConsumers(oldName, newName); + // bug26552: + // remove old name after we've updated the bindings and consumers, + // plus only for server-named queues, both to make sure we don't lose + // anything to recover. MK. + if(q.isServerNamed()) { + deleteRecordedQueue(oldName); } + this.recordedQueues.put(newName, q); } - for(QueueRecoveryListener qrl : Utility.copy(this.queueRecoveryListeners)) { - qrl.queueRecovered(oldName, newName); - } - } catch (Exception cause) { - final String message = "Caught an exception while recovering queue " + oldName + - ": " + cause.getMessage(); - TopologyRecoveryException e = new TopologyRecoveryException(message, cause); - this.getExceptionHandler().handleTopologyRecoveryException(delegate, q.getDelegateChannel(), e); } + for (QueueRecoveryListener qrl : Utility.copy(this.queueRecoveryListeners)) { + qrl.queueRecovered(oldName, newName); + } + LOGGER.debug("Queue {} has recovered", q); + } catch (Exception cause) { + final String message = "Caught an exception while recovering queue " + oldName + + ": " + cause.getMessage(); + TopologyRecoveryException e = new TopologyRecoveryException(message, cause); + this.getExceptionHandler().handleTopologyRecoveryException(delegate, q.getDelegateChannel(), e); } } - private void recoverBindings() { - for (RecordedBinding b : Utility.copy(this.recordedBindings)) { - try { - b.recover(); - } catch (Exception cause) { - String message = "Caught an exception while recovering binding between " + b.getSource() + - " and " + b.getDestination() + ": " + cause.getMessage(); - TopologyRecoveryException e = new TopologyRecoveryException(message, cause); - this.getExceptionHandler().handleTopologyRecoveryException(delegate, b.getDelegateChannel(), e); - } + private void recoverBinding(final RecordedBinding b) { + LOGGER.debug("Recovering binding {}", b); + try { + b.recover(); + LOGGER.debug("Binding {} has recovered", b); + } catch (Exception cause) { + String message = "Caught an exception while recovering binding between " + b.getSource() + + " and " + b.getDestination() + ": " + cause.getMessage(); + TopologyRecoveryException e = new TopologyRecoveryException(message, cause); + this.getExceptionHandler().handleTopologyRecoveryException(delegate, b.getDelegateChannel(), e); } } - private void recoverConsumers() { - for (Map.Entry entry : Utility.copy(this.consumers).entrySet()) { - String tag = entry.getKey(); - RecordedConsumer consumer = entry.getValue(); - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Recovering consumer {}", consumer); - } - try { - String newTag = consumer.recover(); - // make sure server-generated tags are re-added. MK. - if(tag != null && !tag.equals(newTag)) { - synchronized (this.consumers) { - this.consumers.remove(tag); - this.consumers.put(newTag, consumer); - } - consumer.getChannel().updateConsumerTag(tag, newTag); + private void recoverConsumer(final String tag, final RecordedConsumer consumer) { + LOGGER.debug("Recovering consumer {}", consumer); + try { + String newTag = consumer.recover(); + // make sure server-generated tags are re-added. MK. + if(tag != null && !tag.equals(newTag)) { + synchronized (this.consumers) { + this.consumers.remove(tag); + this.consumers.put(newTag, consumer); } + consumer.getChannel().updateConsumerTag(tag, newTag); + } - for(ConsumerRecoveryListener crl : Utility.copy(this.consumerRecoveryListeners)) { - crl.consumerRecovered(tag, newTag); - } - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Consumer {} has recovered", consumer); - } - } catch (Exception cause) { - final String message = "Caught an exception while recovering consumer " + tag + - ": " + cause.getMessage(); - TopologyRecoveryException e = new TopologyRecoveryException(message, cause); - this.getExceptionHandler().handleTopologyRecoveryException(delegate, consumer.getDelegateChannel(), e); + for (ConsumerRecoveryListener crl : Utility.copy(this.consumerRecoveryListeners)) { + crl.consumerRecovered(tag, newTag); } + LOGGER.debug("Consumer {} has recovered", consumer); + } catch (Exception cause) { + final String message = "Caught an exception while recovering consumer " + tag + + ": " + cause.getMessage(); + TopologyRecoveryException e = new TopologyRecoveryException(message, cause); + this.getExceptionHandler().handleTopologyRecoveryException(delegate, consumer.getDelegateChannel(), e); } } @@ -735,6 +750,42 @@ private void propagateQueueNameChangeToConsumers(String oldName, String newName) } } } + + private List> groupEntitiesByChannel(final Collection entities) { + // map entities by channel + final Map> map = new LinkedHashMap>(); + for (final E entity : entities) { + final AutorecoveringChannel channel = entity.getChannel(); + List list = map.get(channel); + if (list == null) { + map.put(channel, list = new ArrayList()); + } + list.add(entity); + } + // now create a runnable per channel + final List> callables = new ArrayList>(); + for (final List entityList : map.values()) { + callables.add(Executors.callable(new Runnable() { + @Override + public void run() { + for (final E entity : entityList) { + if (entity instanceof RecordedExchange) { + recoverExchange((RecordedExchange)entity); + } else if (entity instanceof RecordedQueue) { + final RecordedQueue q = (RecordedQueue) entity; + recoverQueue(q.getName(), q); + } else if (entity instanceof RecordedBinding) { + recoverBinding((RecordedBinding) entity); + } else if (entity instanceof RecordedConsumer) { + final RecordedConsumer c = (RecordedConsumer) entity; + recoverConsumer(c.getConsumerTag(), c); + } + } + } + })); + } + return callables; + } void recordQueueBinding(AutorecoveringChannel ch, String queue, diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedConsumer.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedConsumer.java index 3cb1698732..748c184bd2 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedConsumer.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedConsumer.java @@ -77,4 +77,9 @@ public void setQueue(String queue) { public String getConsumerTag() { return consumerTag; } + + @Override + public String toString() { + return "RecordedConsumer[tag=" + consumerTag + ", queue=" + queue + ", autoAck=" + autoAck + ", exclusive=" + exclusive + ", arguments=" + arguments + ", consumer=" + consumer + ", channel=" + channel; + } } diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchange.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchange.java index 7ff9604a94..565846dcc9 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchange.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchange.java @@ -58,4 +58,9 @@ public RecordedExchange arguments(Map value) { public boolean isAutoDelete() { return autoDelete; } + + @Override + public String toString() { + return "RecordedExchange[name=" + name + ", type=" + type + ", durable=" + durable + ", autoDelete=" + autoDelete + ", arguments=" + arguments + ", channel=" + channel; + } } diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchangeBinding.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchangeBinding.java index 209d37f4b0..1e1ca5c179 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchangeBinding.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchangeBinding.java @@ -29,4 +29,9 @@ public RecordedExchangeBinding(AutorecoveringChannel channel) { public void recover() throws IOException { this.channel.getDelegate().exchangeBind(this.destination, this.source, this.routingKey, this.arguments); } + + @Override + public String toString() { + return "RecordedExchangeBinding[source=" + source + ", destination=" + destination + ", routingKey=" + routingKey + ", arguments=" + arguments + ", channel=" + channel; + } } diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java index 855350825b..d515a6af54 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java @@ -79,4 +79,9 @@ public RecordedQueue arguments(Map value) { this.arguments = value; return this; } + + @Override + public String toString() { + return "RecordedQueue[name=" + name + ", durable=" + durable + ", autoDelete=" + autoDelete + ", exclusive=" + exclusive + ", arguments=" + arguments + "serverNamed=" + serverNamed + ", channel=" + channel; + } } diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java index f593c5ff86..a5bb0f7b76 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java @@ -29,4 +29,9 @@ public RecordedQueueBinding(AutorecoveringChannel channel) { public void recover() throws IOException { this.channel.getDelegate().queueBind(this.getDestination(), this.getSource(), this.routingKey, this.arguments); } + + @Override + public String toString() { + return "RecordedQueueBinding[source=" + source + ", destination=" + destination + ", routingKey=" + routingKey + ", arguments=" + arguments + ", channel=" + channel; + } } From ee0ff2331115f03333ed34f5419389bac5198bc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 15 May 2018 15:53:52 +0200 Subject: [PATCH 0771/2114] Fail test if exception not thrown on priority queue creation Part of rabbitmq/rabbitmq-server#1590. [#157380396] --- .../java/com/rabbitmq/client/test/server/PriorityQueues.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/java/com/rabbitmq/client/test/server/PriorityQueues.java b/src/test/java/com/rabbitmq/client/test/server/PriorityQueues.java index a8687a5108..ad1629bd62 100644 --- a/src/test/java/com/rabbitmq/client/test/server/PriorityQueues.java +++ b/src/test/java/com/rabbitmq/client/test/server/PriorityQueues.java @@ -16,6 +16,7 @@ package com.rabbitmq.client.test.server; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; import java.io.IOException; import java.util.ArrayList; @@ -53,6 +54,7 @@ public class PriorityQueues extends BrokerTestCase { int n = -10; try { channel.queueDeclare(q, true, false, false, argsWithPriorities(n)); + fail("Negative priority, the queue creation should have failed"); } catch (IOException ioe) { checkShutdownSignal(AMQP.PRECONDITION_FAILED, ioe); } @@ -63,6 +65,7 @@ public class PriorityQueues extends BrokerTestCase { int n = 260; try { channel.queueDeclare(q, true, false, false, argsWithPriorities(n)); + fail("Priority too high (> 255), the queue creation should have failed"); } catch (IOException ioe) { checkShutdownSignal(AMQP.PRECONDITION_FAILED, ioe); } From 7b35960badb13a4f6f4c935a92960e149cef178a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 17 May 2018 10:07:21 +0200 Subject: [PATCH 0772/2114] Reduce channel max to 2047 Max number of channels has been reduced from unlimited to 2048 as of RabbitMQ 3.7.5. This is to avoid applications that leak channels to starve the broker resources. 2048 has been picked up scientifically: more than 1 K channels per connection is hard to justify, so we doubled the value to leave existing applications some room. Java client uses 2047 as it uses channel 0 for negotiation and error handling. Part of rabbitmq/rabbitmq-server#1593. Fixes #366 --- src/main/java/com/rabbitmq/client/ConnectionFactory.java | 6 ++++-- .../rabbitmq/client/test/ChannelNumberAllocationTests.java | 6 ++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 9546be9f07..cb62392f3b 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -63,8 +63,10 @@ public class ConnectionFactory implements Cloneable { /** Default virtual host */ public static final String DEFAULT_VHOST = "/"; /** Default maximum channel number; - * zero for unlimited */ - public static final int DEFAULT_CHANNEL_MAX = 0; + * 2047 because it's 2048 on the server side minus channel 0, + * which each connection uses for negotiation + * and error communication */ + public static final int DEFAULT_CHANNEL_MAX = 2047; /** Default maximum frame size; * zero means no limit */ public static final int DEFAULT_FRAME_MAX = 0; diff --git a/src/test/java/com/rabbitmq/client/test/ChannelNumberAllocationTests.java b/src/test/java/com/rabbitmq/client/test/ChannelNumberAllocationTests.java index 589381579f..93329ab822 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelNumberAllocationTests.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelNumberAllocationTests.java @@ -119,4 +119,10 @@ public int compare(Channel x, Channel y){ assertNotNull(connection.createChannel(5)); assertNotNull(connection.createChannel(1)); } + + @Test public void channelMaxIs2047() { + int channelMaxServerSide = 2048; + int defaultChannelCount = 1; + assertEquals(channelMaxServerSide - defaultChannelCount, connection.getChannelMax()); + } } From 209703fc9d9f23b66a345ba1f40393daafb1aaae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 18 May 2018 15:42:05 +0200 Subject: [PATCH 0773/2114] Looping 500 times instead of 5K in recovery test Should be still trustworthy but much faster. --- .../client/test/functional/ConnectionRecovery.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java index 7099c5c490..928cd46d8f 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -45,6 +45,8 @@ public class ConnectionRecovery extends BrokerTestCase { private static final long RECOVERY_INTERVAL = 2000; + private static final int MANY_DECLARATIONS_LOOP_COUNT = 500; + @Test public void connectionRecovery() throws IOException, InterruptedException { assertTrue(connection.isOpen()); closeAndWaitForRecovery(); @@ -416,7 +418,7 @@ public void queueRecovered(String oldName, String newName) { @Test public void declarationOfManyAutoDeleteQueuesWithTransientConsumer() throws IOException, TimeoutException { Channel ch = connection.createChannel(); assertRecordedQueues(connection, 0); - for(int i = 0; i < 5000; i++) { + for(int i = 0; i < MANY_DECLARATIONS_LOOP_COUNT; i++) { String q = UUID.randomUUID().toString(); ch.queueDeclare(q, false, false, true, null); DefaultConsumer dummy = new DefaultConsumer(ch); @@ -430,7 +432,7 @@ public void queueRecovered(String oldName, String newName) { @Test public void declarationOfManyAutoDeleteExchangesWithTransientQueuesThatAreUnbound() throws IOException, TimeoutException { Channel ch = connection.createChannel(); assertRecordedExchanges(connection, 0); - for(int i = 0; i < 5000; i++) { + for(int i = 0; i < MANY_DECLARATIONS_LOOP_COUNT; i++) { String x = UUID.randomUUID().toString(); ch.exchangeDeclare(x, "fanout", false, true, null); String q = ch.queueDeclare().getQueue(); @@ -446,7 +448,7 @@ public void queueRecovered(String oldName, String newName) { @Test public void declarationOfManyAutoDeleteExchangesWithTransientQueuesThatAreDeleted() throws IOException, TimeoutException { Channel ch = connection.createChannel(); assertRecordedExchanges(connection, 0); - for(int i = 0; i < 5000; i++) { + for(int i = 0; i < MANY_DECLARATIONS_LOOP_COUNT; i++) { String x = UUID.randomUUID().toString(); ch.exchangeDeclare(x, "fanout", false, true, null); String q = ch.queueDeclare().getQueue(); @@ -460,7 +462,7 @@ public void queueRecovered(String oldName, String newName) { @Test public void declarationOfManyAutoDeleteExchangesWithTransientExchangesThatAreUnbound() throws IOException, TimeoutException { Channel ch = connection.createChannel(); assertRecordedExchanges(connection, 0); - for(int i = 0; i < 5000; i++) { + for(int i = 0; i < MANY_DECLARATIONS_LOOP_COUNT; i++) { String src = "src-" + UUID.randomUUID().toString(); String dest = "dest-" + UUID.randomUUID().toString(); ch.exchangeDeclare(src, "fanout", false, true, null); @@ -477,7 +479,7 @@ public void queueRecovered(String oldName, String newName) { @Test public void declarationOfManyAutoDeleteExchangesWithTransientExchangesThatAreDeleted() throws IOException, TimeoutException { Channel ch = connection.createChannel(); assertRecordedExchanges(connection, 0); - for(int i = 0; i < 5000; i++) { + for(int i = 0; i < MANY_DECLARATIONS_LOOP_COUNT; i++) { String src = "src-" + UUID.randomUUID().toString(); String dest = "dest-" + UUID.randomUUID().toString(); ch.exchangeDeclare(src, "fanout", false, true, null); From e238df34dc5b12f5db987abbdd6d30233b452379 Mon Sep 17 00:00:00 2001 From: Michael Dent Date: Fri, 18 May 2018 10:39:30 -0500 Subject: [PATCH 0774/2114] logging changes --- .../com/rabbitmq/client/ConnectionFactory.java | 2 +- .../impl/recovery/AutorecoveringConnection.java | 17 +++++++---------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 5a7e8c0582..f8a329124a 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -127,7 +127,7 @@ public class ConnectionFactory implements Cloneable { private boolean automaticRecovery = true; private boolean topologyRecovery = true; - private int topologyRecoveryThreads = 1; + private int topologyRecoveryThreads = 1; // long is used to make sure the users can use both ints // and longs safely. It is unlikely that anybody'd need diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index e225800c5c..ad337f49e7 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -536,7 +536,7 @@ private synchronized void beginAutomaticRecovery() throws InterruptedException { if (newConn == null) { return; } - + LOGGER.debug("Connection {} has recovered", newConn); this.addAutomaticRecoveryListener(newConn); this.recoverShutdownListeners(newConn); this.recoverBlockedListeners(newConn); @@ -591,7 +591,6 @@ private RecoveryAwareAMQConnection recoverConnection() throws InterruptedExcepti private void recoverChannels(final RecoveryAwareAMQConnection newConn) { for (AutorecoveringChannel ch : this.channels.values()) { - LOGGER.debug("Recovering channel {}", ch); try { ch.automaticallyRecover(this, newConn); LOGGER.debug("Channel {} has recovered", ch); @@ -652,10 +651,9 @@ private void recoverTopology(final int recoveryThreads) throws InterruptedExcept private void recoverExchange(final RecordedExchange x) { // recorded exchanges are guaranteed to be non-predefined (we filter out predefined ones in exchangeDeclare). MK. - LOGGER.debug("Recovering exchange {}", x); try { x.recover(); - LOGGER.debug("Exchange {} has recovered", x); + LOGGER.debug("{} has recovered", x); } catch (Exception cause) { final String message = "Caught an exception while recovering exchange " + x.getName() + ": " + cause.getMessage(); @@ -665,7 +663,7 @@ private void recoverExchange(final RecordedExchange x) { } private void recoverQueue(final String oldName, final RecordedQueue q) { - LOGGER.debug("Recovering queue {}", q); + LOGGER.debug("Recovering {}", q); try { q.recover(); String newName = q.getName(); @@ -688,7 +686,7 @@ private void recoverQueue(final String oldName, final RecordedQueue q) { for (QueueRecoveryListener qrl : Utility.copy(this.queueRecoveryListeners)) { qrl.queueRecovered(oldName, newName); } - LOGGER.debug("Queue {} has recovered", q); + LOGGER.debug("{} has recovered", q); } catch (Exception cause) { final String message = "Caught an exception while recovering queue " + oldName + ": " + cause.getMessage(); @@ -698,10 +696,9 @@ private void recoverQueue(final String oldName, final RecordedQueue q) { } private void recoverBinding(final RecordedBinding b) { - LOGGER.debug("Recovering binding {}", b); try { b.recover(); - LOGGER.debug("Binding {} has recovered", b); + LOGGER.debug("{} has recovered", b); } catch (Exception cause) { String message = "Caught an exception while recovering binding between " + b.getSource() + " and " + b.getDestination() + ": " + cause.getMessage(); @@ -711,7 +708,7 @@ private void recoverBinding(final RecordedBinding b) { } private void recoverConsumer(final String tag, final RecordedConsumer consumer) { - LOGGER.debug("Recovering consumer {}", consumer); + LOGGER.debug("Recovering {}", consumer); try { String newTag = consumer.recover(); // make sure server-generated tags are re-added. MK. @@ -726,7 +723,7 @@ private void recoverConsumer(final String tag, final RecordedConsumer consumer) for (ConsumerRecoveryListener crl : Utility.copy(this.consumerRecoveryListeners)) { crl.consumerRecovered(tag, newTag); } - LOGGER.debug("Consumer {} has recovered", consumer); + LOGGER.debug("{} has recovered", consumer); } catch (Exception cause) { final String message = "Caught an exception while recovering consumer " + tag + ": " + cause.getMessage(); From abd993180a4777e98f600e950caba2b1e348166c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 21 May 2018 15:29:25 +0200 Subject: [PATCH 0775/2114] Use default client properties when reading from properties file This commit adds the default client properties when reading connection factory settings from a properties file. Default client properties can be customized and gotten rid of as well. Originally pointed out by @dgoetsch. Fixes #368 --- .../client/ConnectionFactoryConfigurator.java | 28 +++++++++++-------- .../test/PropertyFileInitialisationTest.java | 26 ++++++++++++----- 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java b/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java index 73ef9da038..2052e4da1c 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java @@ -41,9 +41,10 @@ * but also from the classpath, by using the classpath: prefix * in the location. * - * If default client properties should be set, set the use.default.client.properties - * key to true. Custom client properties can be set by using - * the client.properties., e.g. client.properties.app.name. + * Client properties can be set by using + * the client.properties. prefix, e.g. client.properties.app.name. + * Default client properties and custom client properties are merged. To remove + * a default client property, set its key to an empty value. * * @since 4.4.0 * @see ConnectionFactory#load(String, String) @@ -63,7 +64,6 @@ public class ConnectionFactoryConfigurator { public static final String CONNECTION_TIMEOUT = "connection.timeout"; public static final String HANDSHAKE_TIMEOUT = "handshake.timeout"; public static final String SHUTDOWN_TIMEOUT = "shutdown.timeout"; - public static final String USE_DEFAULT_CLIENT_PROPERTIES = "use.default.client.properties"; public static final String CLIENT_PROPERTIES_PREFIX = "client.properties."; public static final String CONNECTION_RECOVERY_ENABLED = "connection.recovery.enabled"; public static final String TOPOLOGY_RECOVERY_ENABLED = "topology.recovery.enabled"; @@ -169,17 +169,21 @@ public static void load(ConnectionFactory cf, Map properties, St } Map clientProperties = new HashMap(); - String useDefaultClientProperties = properties.get(prefix + USE_DEFAULT_CLIENT_PROPERTIES); - if (useDefaultClientProperties != null && Boolean.valueOf(useDefaultClientProperties)) { - clientProperties.putAll(AMQConnection.defaultClientProperties()); - } + Map defaultClientProperties = AMQConnection.defaultClientProperties(); + clientProperties.putAll(defaultClientProperties); for (Map.Entry entry : properties.entrySet()) { if (entry.getKey().startsWith(prefix + CLIENT_PROPERTIES_PREFIX)) { - clientProperties.put( - entry.getKey().substring((prefix + CLIENT_PROPERTIES_PREFIX).length()), - entry.getValue() - ); + String clientPropertyKey = entry.getKey().substring((prefix + CLIENT_PROPERTIES_PREFIX).length()); + if (defaultClientProperties.containsKey(clientPropertyKey) && (entry.getValue() == null || entry.getValue().trim().isEmpty())) { + // if default property and value is empty, remove this property + clientProperties.remove(clientPropertyKey); + } else { + clientProperties.put( + clientPropertyKey, + entry.getValue() + ); + } } } cf.setClientProperties(clientProperties); diff --git a/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java b/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java index 5bbd2e3de1..34b6a63054 100644 --- a/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java +++ b/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java @@ -91,22 +91,34 @@ public static Object[] data() { assertThat(cf.getPort(), is(5673)); } - @Test public void propertyInitialisationIncludeDefaultClientProperties() { + @Test public void propertyInitialisationIncludeDefaultClientPropertiesByDefault() { + cf.load(new HashMap()); + assertThat(cf.getClientProperties().entrySet(), hasSize(defaultClientProperties().size())); + } + + @Test public void propertyInitialisationAddCustomClientProperty() { cf.load(new HashMap() {{ - put("rabbitmq.use.default.client.properties", "true"); put("rabbitmq.client.properties.foo", "bar"); }}); assertThat(cf.getClientProperties().entrySet(), hasSize(defaultClientProperties().size() + 1)); assertThat(cf.getClientProperties().get("foo").toString(), is("bar")); } - @Test public void propertyInitialisationDoNotIncludeDefaultClientProperties() { + @Test public void propertyInitialisationGetRidOfDefaultClientPropertyWithEmptyValue() { + final String key = defaultClientProperties().entrySet().iterator().next().getKey(); cf.load(new HashMap() {{ - put("rabbitmq.use.default.client.properties", "false"); - put("rabbitmq.client.properties.foo", "bar"); + put("rabbitmq.client.properties." + key, ""); }}); - assertThat(cf.getClientProperties().entrySet(), hasSize(1)); - assertThat(cf.getClientProperties().get("foo").toString(), is("bar")); + assertThat(cf.getClientProperties().entrySet(), hasSize(defaultClientProperties().size() - 1)); + } + + @Test public void propertyInitialisationOverrideDefaultClientProperty() { + final String key = defaultClientProperties().entrySet().iterator().next().getKey(); + cf.load(new HashMap() {{ + put("rabbitmq.client.properties." + key, "whatever"); + }}); + assertThat(cf.getClientProperties().entrySet(), hasSize(defaultClientProperties().size())); + assertThat(cf.getClientProperties().get(key).toString(), is("whatever")); } @Test public void propertyInitialisationDoNotUseNio() throws Exception { From 774590a02a172be404aeb9b9f44a9d8c2d9793aa Mon Sep 17 00:00:00 2001 From: Michael Dent Date: Mon, 21 May 2018 13:30:40 -0500 Subject: [PATCH 0776/2114] recover channels in parallel too --- .../rabbitmq/client/ConnectionFactory.java | 12 +- .../client/impl/ConnectionParams.java | 10 +- .../recovery/AutorecoveringConnection.java | 83 ++++++++---- .../test/functional/ConnectionRecovery.java | 126 ++++++++++++++---- 4 files changed, 167 insertions(+), 64 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index f8a329124a..3bef76f712 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -127,7 +127,7 @@ public class ConnectionFactory implements Cloneable { private boolean automaticRecovery = true; private boolean topologyRecovery = true; - private int topologyRecoveryThreads = 1; + private int recoveryThreads = 1; // long is used to make sure the users can use both ints // and longs safely. It is unlikely that anybody'd need @@ -714,13 +714,13 @@ public void setTopologyRecoveryEnabled(boolean topologyRecovery) { this.topologyRecovery = topologyRecovery; } - public int getTopologyRecoveryThreadCount() { - return topologyRecoveryThreads; + public int getRecoveryThreadCount() { + return recoveryThreads; } // TODO Document that your exception handler method should be thread safe - public void setTopologyRecoveryThreadCount(final int topologyRecoveryThreads) { - this.topologyRecoveryThreads = topologyRecoveryThreads; + public void setRecoveryThreadCount(final int recoveryThreads) { + this.recoveryThreads = recoveryThreads; } public void setMetricsCollector(MetricsCollector metricsCollector) { @@ -1021,7 +1021,7 @@ public ConnectionParams params(ExecutorService consumerWorkServiceExecutor) { result.setNetworkRecoveryInterval(networkRecoveryInterval); result.setRecoveryDelayHandler(recoveryDelayHandler); result.setTopologyRecovery(topologyRecovery); - result.setTopologyRecoveryThreadCount(topologyRecoveryThreads); + result.setRecoveryThreadCount(recoveryThreads); result.setExceptionHandler(exceptionHandler); result.setThreadFactory(threadFactory); result.setHandshakeTimeout(handshakeTimeout); diff --git a/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java b/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java index 0fe4e7c2cd..e0cd00053e 100644 --- a/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java +++ b/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java @@ -41,7 +41,7 @@ public class ConnectionParams { private long networkRecoveryInterval; private RecoveryDelayHandler recoveryDelayHandler; private boolean topologyRecovery; - private int topologyRecoveryThreads = 1; + private int recoveryThreads = 1; private int channelRpcTimeout; private boolean channelShouldCheckRpcResponseType; private ErrorOnWriteListener errorOnWriteListener; @@ -116,8 +116,8 @@ public boolean isTopologyRecoveryEnabled() { return topologyRecovery; } - public int getTopologyRecoveryThreadCount() { - return topologyRecoveryThreads; + public int getRecoveryThreadCount() { + return recoveryThreads; } public ThreadFactory getThreadFactory() { @@ -180,8 +180,8 @@ public void setTopologyRecovery(boolean topologyRecovery) { this.topologyRecovery = topologyRecovery; } - public void setTopologyRecoveryThreadCount(final int topologyRecoveryThreads) { - this.topologyRecoveryThreads = topologyRecoveryThreads; + public void setRecoveryThreadCount(final int recoveryThreads) { + this.recoveryThreads = recoveryThreads; } public void setExceptionHandler(ExceptionHandler exceptionHandler) { diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index ad337f49e7..2bf06d9359 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -540,12 +540,25 @@ private synchronized void beginAutomaticRecovery() throws InterruptedException { this.addAutomaticRecoveryListener(newConn); this.recoverShutdownListeners(newConn); this.recoverBlockedListeners(newConn); - this.recoverChannels(newConn); - // don't assign new delegate connection until channel recovery is complete - this.delegate = newConn; - if (this.params.isTopologyRecoveryEnabled()) { - recoverTopology(params.getTopologyRecoveryThreadCount()); - } + + // Optionally support recovering channels & entities in parallel for connections that have a lot of channels, queues, bindings, etc. + ExecutorService executor = null; + if (params.getRecoveryThreadCount() > 1) { + executor = Executors.newFixedThreadPool(params.getRecoveryThreadCount(), delegate.getThreadFactory()); + } + try { + this.recoverChannels(newConn, executor); + // don't assign new delegate connection until channel recovery is complete + this.delegate = newConn; + // recover topology + if (this.params.isTopologyRecoveryEnabled()) { + recoverTopology(executor); + } + } finally { + if (executor != null) { + executor.shutdownNow(); + } + } this.notifyRecoveryListenersComplete(); } @@ -589,16 +602,34 @@ private RecoveryAwareAMQConnection recoverConnection() throws InterruptedExcepti return null; } - private void recoverChannels(final RecoveryAwareAMQConnection newConn) { - for (AutorecoveringChannel ch : this.channels.values()) { - try { - ch.automaticallyRecover(this, newConn); - LOGGER.debug("Channel {} has recovered", ch); - } catch (Throwable t) { - newConn.getExceptionHandler().handleChannelRecoveryException(ch, t); + private void recoverChannels(final RecoveryAwareAMQConnection newConn, final ExecutorService executor) throws InterruptedException { + if (executor != null) { + final List> tasks = new ArrayList>(); + for (final AutorecoveringChannel ch : this.channels.values()) { + tasks.add(Executors.callable(new Runnable() { + @Override + public void run() { + recoverChannel(newConn, ch); + } + })); + } + // invokeAll will block until all callables are completed + executor.invokeAll(tasks); + } else { + for (final AutorecoveringChannel ch : this.channels.values()) { + recoverChannel(newConn, ch); } } } + + private void recoverChannel(final RecoveryAwareAMQConnection newConn, final AutorecoveringChannel ch) { + try { + ch.automaticallyRecover(this, newConn); + LOGGER.debug("Channel {} has recovered", ch); + } catch (Throwable t) { + newConn.getExceptionHandler().handleChannelRecoveryException(ch, t); + } + } private void notifyRecoveryListenersComplete() { for (RecoveryListener f : Utility.copy(this.recoveryListeners)) { @@ -612,26 +643,20 @@ private void notifyRecoveryListenersStarted() { } } - private void recoverTopology(final int recoveryThreads) throws InterruptedException { + private void recoverTopology(final ExecutorService executor) throws InterruptedException { // The recovery sequence is the following: // 1. Recover exchanges // 2. Recover queues // 3. Recover bindings // 4. Recover consumers - if (recoveryThreads > 1) { - // Support recovering entities in parallel for connections that have a lot of queues, bindings, & consumers + if (executor != null) { // A channel is single threaded, so group things by channel and recover 1 entity at a time per channel // We still need to recover 1 type of entity at a time in case channel1 has a binding to a queue that is currently owned and being recovered by channel2 for example - final ExecutorService executor = Executors.newFixedThreadPool(recoveryThreads, delegate.getThreadFactory()); - try { - // invokeAll will block until all callables are completed - executor.invokeAll(groupEntitiesByChannel(Utility.copy(recordedExchanges).values())); - executor.invokeAll(groupEntitiesByChannel(Utility.copy(recordedQueues).values())); - executor.invokeAll(groupEntitiesByChannel(Utility.copy(recordedBindings))); - executor.invokeAll(groupEntitiesByChannel(Utility.copy(consumers).values())); - } finally { - executor.shutdownNow(); - } + // invokeAll will block until all callables are completed + executor.invokeAll(groupEntitiesByChannel(Utility.copy(recordedExchanges).values())); + executor.invokeAll(groupEntitiesByChannel(Utility.copy(recordedQueues).values())); + executor.invokeAll(groupEntitiesByChannel(Utility.copy(recordedBindings))); + executor.invokeAll(groupEntitiesByChannel(Utility.copy(consumers).values())); } else { // recover entities in serial on the main connection thread for (final RecordedExchange exchange : Utility.copy(recordedExchanges).values()) { @@ -760,9 +785,9 @@ private List> groupEntitiesByChannel list.add(entity); } // now create a runnable per channel - final List> callables = new ArrayList>(); + final List> tasks = new ArrayList>(); for (final List entityList : map.values()) { - callables.add(Executors.callable(new Runnable() { + tasks.add(Executors.callable(new Runnable() { @Override public void run() { for (final E entity : entityList) { @@ -781,7 +806,7 @@ public void run() { } })); } - return callables; + return tasks; } void recordQueueBinding(AutorecoveringChannel ch, diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java index 7099c5c490..a5c6f891ef 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -16,6 +16,7 @@ package com.rabbitmq.client.test.functional; import com.rabbitmq.client.*; +import com.rabbitmq.client.AMQP.BasicProperties; import com.rabbitmq.client.impl.CredentialsProvider; import com.rabbitmq.client.impl.NetworkConnection; import com.rabbitmq.client.impl.recovery.*; @@ -34,7 +35,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; import static org.hamcrest.Matchers.greaterThanOrEqualTo; @@ -168,11 +168,13 @@ public String getPassword() { final List events = new CopyOnWriteArrayList(); final CountDownLatch latch = new CountDownLatch(2); // one when started, another when complete connection.addShutdownListener(new ShutdownListener() { + @Override public void shutdownCompleted(ShutdownSignalException cause) { events.add("shutdown hook 1"); } }); connection.addShutdownListener(new ShutdownListener() { + @Override public void shutdownCompleted(ShutdownSignalException cause) { events.add("shutdown hook 2"); } @@ -211,6 +213,7 @@ public void handleRecoveryStarted(Recoverable recoverable) { @Test public void shutdownHooksRecoveryOnConnection() throws IOException, InterruptedException { final CountDownLatch latch = new CountDownLatch(2); connection.addShutdownListener(new ShutdownListener() { + @Override public void shutdownCompleted(ShutdownSignalException cause) { latch.countDown(); } @@ -225,6 +228,7 @@ public void shutdownCompleted(ShutdownSignalException cause) { @Test public void shutdownHooksRecoveryOnChannel() throws IOException, InterruptedException { final CountDownLatch latch = new CountDownLatch(3); channel.addShutdownListener(new ShutdownListener() { + @Override public void shutdownCompleted(ShutdownSignalException cause) { latch.countDown(); } @@ -241,10 +245,12 @@ public void shutdownCompleted(ShutdownSignalException cause) { @Test public void blockedListenerRecovery() throws IOException, InterruptedException { final CountDownLatch latch = new CountDownLatch(2); connection.addBlockedListener(new BlockedListener() { + @Override public void handleBlocked(String reason) throws IOException { latch.countDown(); } + @Override public void handleUnblocked() throws IOException { latch.countDown(); } @@ -270,6 +276,7 @@ public void handleUnblocked() throws IOException { @Test public void returnListenerRecovery() throws IOException, InterruptedException { final CountDownLatch latch = new CountDownLatch(1); channel.addReturnListener(new ReturnListener() { + @Override public void handleReturn(int replyCode, String replyText, String exchange, String routingKey, AMQP.BasicProperties properties, byte[] body) throws IOException { @@ -285,10 +292,12 @@ public void handleReturn(int replyCode, String replyText, String exchange, @Test public void confirmListenerRecovery() throws IOException, InterruptedException, TimeoutException { final CountDownLatch latch = new CountDownLatch(1); channel.addConfirmListener(new ConfirmListener() { + @Override public void handleAck(long deliveryTag, boolean multiple) throws IOException { latch.countDown(); } + @Override public void handleNack(long deliveryTag, boolean multiple) throws IOException { latch.countDown(); } @@ -693,9 +702,11 @@ public void consumerRecovered(String oldConsumerTag, String newConsumerTag) { final CountDownLatch latch = new CountDownLatch(2); final CountDownLatch startLatch = new CountDownLatch(2); final RecoveryListener listener = new RecoveryListener() { + @Override public void handleRecovery(Recoverable recoverable) { latch.countDown(); } + @Override public void handleRecoveryStarted(Recoverable recoverable) { startLatch.countDown(); } @@ -792,7 +803,66 @@ public void handleDelivery(String consumerTag, closeAndWaitForRecovery((RecoverableConnection) testConnection); assertTrue(testConnection.isOpen()); } finally { - connection.close(); + testConnection.close(); + } + } + + @Test public void recoveryWithMultipleThreads() throws Exception { + // test with 8 recovery threads + ConnectionFactory connectionFactory = buildConnectionFactoryWithRecoveryEnabled(false, 8); + assertEquals(8, connectionFactory.getRecoveryThreadCount()); + RecoverableConnection testConnection = (RecoverableConnection) connectionFactory.newConnection(); + try { + final List channels = new ArrayList(); + final List exchanges = new ArrayList(); + final List queues = new ArrayList(); + // create 16 channels + final int channelCount = 16; + final int queuesPerChannel = 20; + final CountDownLatch latch = new CountDownLatch(channelCount * queuesPerChannel); + for (int i=0; i < channelCount; i++) { + final Channel testChannel = testConnection.createChannel(); + String x = "tmp-x-topic-" + i; + exchanges.add(x); + testChannel.exchangeDeclare(x, "topic"); + // create 20 queues and bindings per channel + for (int j=0; j < queuesPerChannel; j++) { + String q = "tmp-q-" + i + "-" + j; + queues.add(q); + testChannel.queueDeclare(q, false, false, true, null); + testChannel.queueBind(q, x, "tmp-key-" + i + "-" + j); + testChannel.basicConsume(q, new DefaultConsumer(testChannel) { + @Override + public void handleDelivery(String consumerTag, Envelope envelope, BasicProperties properties, byte[] body) throws IOException { + testChannel.basicAck(envelope.getDeliveryTag(), false); + latch.countDown(); + } + }); + } + } + // now do recovery + closeAndWaitForRecovery(testConnection); + + // verify channels & topology recovered by publishing a message to each + for (int i=0; i < channelCount; i++) { + Channel ch = channels.get(i); + expectChannelRecovery(ch); + // publish message to each queue/consumer + for (int j=0; j < queuesPerChannel; j++) { + ch.basicPublish("tmp-x-topic-" + i, "tmp-key-" + i + "-" + j, null, "msg".getBytes()); + } + } + // verify all queues/consumers got it + assertTrue(latch.await(30, TimeUnit.SECONDS)); + + // cleanup + Channel cleanupChannel = testConnection.createChannel(); + for (String q : queues) + cleanupChannel.queueDelete(q); + for (String x : exchanges) + cleanupChannel.exchangeDelete(x); + } finally { + testConnection.close(); } } @@ -800,28 +870,28 @@ private void assertConsumerCount(int exp, String q) throws IOException { assertEquals(exp, channel.queueDeclarePassive(q).getConsumerCount()); } - private AMQP.Queue.DeclareOk declareClientNamedQueue(Channel ch, String q) throws IOException { + private static AMQP.Queue.DeclareOk declareClientNamedQueue(Channel ch, String q) throws IOException { return ch.queueDeclare(q, true, false, false, null); } - private AMQP.Queue.DeclareOk declareClientNamedAutoDeleteQueue(Channel ch, String q) throws IOException { + private static AMQP.Queue.DeclareOk declareClientNamedAutoDeleteQueue(Channel ch, String q) throws IOException { return ch.queueDeclare(q, true, false, true, null); } - private void declareClientNamedQueueNoWait(Channel ch, String q) throws IOException { + private static void declareClientNamedQueueNoWait(Channel ch, String q) throws IOException { ch.queueDeclareNoWait(q, true, false, false, null); } - private AMQP.Exchange.DeclareOk declareExchange(Channel ch, String x) throws IOException { + private static AMQP.Exchange.DeclareOk declareExchange(Channel ch, String x) throws IOException { return ch.exchangeDeclare(x, "fanout", false); } - private void declareExchangeNoWait(Channel ch, String x) throws IOException { + private static void declareExchangeNoWait(Channel ch, String x) throws IOException { ch.exchangeDeclareNoWait(x, "fanout", false, false, false, null); } - private void expectQueueRecovery(Channel ch, String q) throws IOException, InterruptedException, TimeoutException { + private static void expectQueueRecovery(Channel ch, String q) throws IOException, InterruptedException, TimeoutException { ch.confirmSelect(); ch.queuePurge(q); AMQP.Queue.DeclareOk ok1 = declareClientNamedQueue(ch, q); @@ -832,7 +902,7 @@ private void expectQueueRecovery(Channel ch, String q) throws IOException, Inter assertEquals(1, ok2.getMessageCount()); } - private void expectAutoDeleteQueueAndBindingRecovery(Channel ch, String x, String q) throws IOException, InterruptedException, + private static void expectAutoDeleteQueueAndBindingRecovery(Channel ch, String x, String q) throws IOException, InterruptedException, TimeoutException { ch.confirmSelect(); ch.queuePurge(q); @@ -845,7 +915,7 @@ private void expectAutoDeleteQueueAndBindingRecovery(Channel ch, String x, Strin assertEquals(1, ok2.getMessageCount()); } - private void expectExchangeRecovery(Channel ch, String x) throws IOException, InterruptedException, TimeoutException { + private static void expectExchangeRecovery(Channel ch, String x) throws IOException, InterruptedException, TimeoutException { ch.confirmSelect(); String q = ch.queueDeclare().getQueue(); final String rk = "routing-key"; @@ -855,12 +925,14 @@ private void expectExchangeRecovery(Channel ch, String x) throws IOException, In ch.exchangeDeclarePassive(x); } - private CountDownLatch prepareForRecovery(Connection conn) { + private static CountDownLatch prepareForRecovery(Connection conn) { final CountDownLatch latch = new CountDownLatch(1); ((AutorecoveringConnection)conn).addRecoveryListener(new RecoveryListener() { + @Override public void handleRecovery(Recoverable recoverable) { latch.countDown(); } + @Override public void handleRecoveryStarted(Recoverable recoverable) { // No-op } @@ -868,9 +940,10 @@ public void handleRecoveryStarted(Recoverable recoverable) { return latch; } - private CountDownLatch prepareForShutdown(Connection conn) throws InterruptedException { + private static CountDownLatch prepareForShutdown(Connection conn) { final CountDownLatch latch = new CountDownLatch(1); conn.addShutdownListener(new ShutdownListener() { + @Override public void shutdownCompleted(ShutdownSignalException cause) { latch.countDown(); } @@ -882,7 +955,7 @@ private void closeAndWaitForRecovery() throws IOException, InterruptedException closeAndWaitForRecovery((AutorecoveringConnection)this.connection); } - private void closeAndWaitForRecovery(RecoverableConnection connection) throws IOException, InterruptedException { + private static void closeAndWaitForRecovery(RecoverableConnection connection) throws IOException, InterruptedException { CountDownLatch latch = prepareForRecovery(connection); Host.closeConnection((NetworkConnection) connection); wait(latch); @@ -900,7 +973,7 @@ private void restartPrimaryAndWaitForRecovery(Connection connection) throws IOEx wait(latch); } - private void expectChannelRecovery(Channel ch) throws InterruptedException { + private static void expectChannelRecovery(Channel ch) { assertTrue(ch.isOpen()); } @@ -909,48 +982,53 @@ protected ConnectionFactory newConnectionFactory() { return buildConnectionFactoryWithRecoveryEnabled(false); } - private RecoverableConnection newRecoveringConnection(boolean disableTopologyRecovery) + private static RecoverableConnection newRecoveringConnection(boolean disableTopologyRecovery) throws IOException, TimeoutException { ConnectionFactory cf = buildConnectionFactoryWithRecoveryEnabled(disableTopologyRecovery); return (AutorecoveringConnection) cf.newConnection(); } - private RecoverableConnection newRecoveringConnection(Address[] addresses) + private static RecoverableConnection newRecoveringConnection(Address[] addresses) throws IOException, TimeoutException { ConnectionFactory cf = buildConnectionFactoryWithRecoveryEnabled(false); // specifically use the Address[] overload return (AutorecoveringConnection) cf.newConnection(addresses); } - private RecoverableConnection newRecoveringConnection(boolean disableTopologyRecovery, List

addresses) + private static RecoverableConnection newRecoveringConnection(boolean disableTopologyRecovery, List
addresses) throws IOException, TimeoutException { ConnectionFactory cf = buildConnectionFactoryWithRecoveryEnabled(disableTopologyRecovery); return (AutorecoveringConnection) cf.newConnection(addresses); } - private RecoverableConnection newRecoveringConnection(List
addresses) + private static RecoverableConnection newRecoveringConnection(List
addresses) throws IOException, TimeoutException { return newRecoveringConnection(false, addresses); } - private RecoverableConnection newRecoveringConnection(boolean disableTopologyRecovery, String connectionName) + private static RecoverableConnection newRecoveringConnection(boolean disableTopologyRecovery, String connectionName) throws IOException, TimeoutException { ConnectionFactory cf = buildConnectionFactoryWithRecoveryEnabled(disableTopologyRecovery); return (RecoverableConnection) cf.newConnection(connectionName); } - private RecoverableConnection newRecoveringConnection(String connectionName) + private static RecoverableConnection newRecoveringConnection(String connectionName) throws IOException, TimeoutException { return newRecoveringConnection(false, connectionName); } + + private static ConnectionFactory buildConnectionFactoryWithRecoveryEnabled(boolean disableTopologyRecovery) { + return buildConnectionFactoryWithRecoveryEnabled(disableTopologyRecovery, 1); + } - private ConnectionFactory buildConnectionFactoryWithRecoveryEnabled(boolean disableTopologyRecovery) { + private static ConnectionFactory buildConnectionFactoryWithRecoveryEnabled(boolean disableTopologyRecovery, final int recoveryThreads) { ConnectionFactory cf = TestUtils.connectionFactory(); cf.setNetworkRecoveryInterval(RECOVERY_INTERVAL); cf.setAutomaticRecoveryEnabled(true); if (disableTopologyRecovery) { cf.setTopologyRecoveryEnabled(false); } + cf.setRecoveryThreadCount(recoveryThreads); return cf; } @@ -960,15 +1038,15 @@ private static void wait(CountDownLatch latch) throws InterruptedException { assertTrue(latch.await(90, TimeUnit.SECONDS)); } - private void waitForConfirms(Channel ch) throws InterruptedException, TimeoutException { + private static void waitForConfirms(Channel ch) throws InterruptedException, TimeoutException { ch.waitForConfirms(30 * 60 * 1000); } - private void assertRecordedQueues(Connection conn, int size) { + private static void assertRecordedQueues(Connection conn, int size) { assertEquals(size, ((AutorecoveringConnection)conn).getRecordedQueues().size()); } - private void assertRecordedExchanges(Connection conn, int size) { + private static void assertRecordedExchanges(Connection conn, int size) { assertEquals(size, ((AutorecoveringConnection)conn).getRecordedExchanges().size()); } } From adb4187397efe498c2ef99ad7f872c11bea18c14 Mon Sep 17 00:00:00 2001 From: Michael Dent Date: Mon, 21 May 2018 14:12:36 -0500 Subject: [PATCH 0777/2114] Revert "recover channels in parallel too" This reverts commit 774590a02a172be404aeb9b9f44a9d8c2d9793aa. --- .../rabbitmq/client/ConnectionFactory.java | 12 +- .../client/impl/ConnectionParams.java | 10 +- .../recovery/AutorecoveringConnection.java | 83 ++++-------- .../test/functional/ConnectionRecovery.java | 126 ++++-------------- 4 files changed, 64 insertions(+), 167 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 3bef76f712..f8a329124a 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -127,7 +127,7 @@ public class ConnectionFactory implements Cloneable { private boolean automaticRecovery = true; private boolean topologyRecovery = true; - private int recoveryThreads = 1; + private int topologyRecoveryThreads = 1; // long is used to make sure the users can use both ints // and longs safely. It is unlikely that anybody'd need @@ -714,13 +714,13 @@ public void setTopologyRecoveryEnabled(boolean topologyRecovery) { this.topologyRecovery = topologyRecovery; } - public int getRecoveryThreadCount() { - return recoveryThreads; + public int getTopologyRecoveryThreadCount() { + return topologyRecoveryThreads; } // TODO Document that your exception handler method should be thread safe - public void setRecoveryThreadCount(final int recoveryThreads) { - this.recoveryThreads = recoveryThreads; + public void setTopologyRecoveryThreadCount(final int topologyRecoveryThreads) { + this.topologyRecoveryThreads = topologyRecoveryThreads; } public void setMetricsCollector(MetricsCollector metricsCollector) { @@ -1021,7 +1021,7 @@ public ConnectionParams params(ExecutorService consumerWorkServiceExecutor) { result.setNetworkRecoveryInterval(networkRecoveryInterval); result.setRecoveryDelayHandler(recoveryDelayHandler); result.setTopologyRecovery(topologyRecovery); - result.setRecoveryThreadCount(recoveryThreads); + result.setTopologyRecoveryThreadCount(topologyRecoveryThreads); result.setExceptionHandler(exceptionHandler); result.setThreadFactory(threadFactory); result.setHandshakeTimeout(handshakeTimeout); diff --git a/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java b/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java index e0cd00053e..0fe4e7c2cd 100644 --- a/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java +++ b/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java @@ -41,7 +41,7 @@ public class ConnectionParams { private long networkRecoveryInterval; private RecoveryDelayHandler recoveryDelayHandler; private boolean topologyRecovery; - private int recoveryThreads = 1; + private int topologyRecoveryThreads = 1; private int channelRpcTimeout; private boolean channelShouldCheckRpcResponseType; private ErrorOnWriteListener errorOnWriteListener; @@ -116,8 +116,8 @@ public boolean isTopologyRecoveryEnabled() { return topologyRecovery; } - public int getRecoveryThreadCount() { - return recoveryThreads; + public int getTopologyRecoveryThreadCount() { + return topologyRecoveryThreads; } public ThreadFactory getThreadFactory() { @@ -180,8 +180,8 @@ public void setTopologyRecovery(boolean topologyRecovery) { this.topologyRecovery = topologyRecovery; } - public void setRecoveryThreadCount(final int recoveryThreads) { - this.recoveryThreads = recoveryThreads; + public void setTopologyRecoveryThreadCount(final int topologyRecoveryThreads) { + this.topologyRecoveryThreads = topologyRecoveryThreads; } public void setExceptionHandler(ExceptionHandler exceptionHandler) { diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index 2bf06d9359..ad337f49e7 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -540,25 +540,12 @@ private synchronized void beginAutomaticRecovery() throws InterruptedException { this.addAutomaticRecoveryListener(newConn); this.recoverShutdownListeners(newConn); this.recoverBlockedListeners(newConn); - - // Optionally support recovering channels & entities in parallel for connections that have a lot of channels, queues, bindings, etc. - ExecutorService executor = null; - if (params.getRecoveryThreadCount() > 1) { - executor = Executors.newFixedThreadPool(params.getRecoveryThreadCount(), delegate.getThreadFactory()); - } - try { - this.recoverChannels(newConn, executor); - // don't assign new delegate connection until channel recovery is complete - this.delegate = newConn; - // recover topology - if (this.params.isTopologyRecoveryEnabled()) { - recoverTopology(executor); - } - } finally { - if (executor != null) { - executor.shutdownNow(); - } - } + this.recoverChannels(newConn); + // don't assign new delegate connection until channel recovery is complete + this.delegate = newConn; + if (this.params.isTopologyRecoveryEnabled()) { + recoverTopology(params.getTopologyRecoveryThreadCount()); + } this.notifyRecoveryListenersComplete(); } @@ -602,34 +589,16 @@ private RecoveryAwareAMQConnection recoverConnection() throws InterruptedExcepti return null; } - private void recoverChannels(final RecoveryAwareAMQConnection newConn, final ExecutorService executor) throws InterruptedException { - if (executor != null) { - final List> tasks = new ArrayList>(); - for (final AutorecoveringChannel ch : this.channels.values()) { - tasks.add(Executors.callable(new Runnable() { - @Override - public void run() { - recoverChannel(newConn, ch); - } - })); - } - // invokeAll will block until all callables are completed - executor.invokeAll(tasks); - } else { - for (final AutorecoveringChannel ch : this.channels.values()) { - recoverChannel(newConn, ch); + private void recoverChannels(final RecoveryAwareAMQConnection newConn) { + for (AutorecoveringChannel ch : this.channels.values()) { + try { + ch.automaticallyRecover(this, newConn); + LOGGER.debug("Channel {} has recovered", ch); + } catch (Throwable t) { + newConn.getExceptionHandler().handleChannelRecoveryException(ch, t); } } } - - private void recoverChannel(final RecoveryAwareAMQConnection newConn, final AutorecoveringChannel ch) { - try { - ch.automaticallyRecover(this, newConn); - LOGGER.debug("Channel {} has recovered", ch); - } catch (Throwable t) { - newConn.getExceptionHandler().handleChannelRecoveryException(ch, t); - } - } private void notifyRecoveryListenersComplete() { for (RecoveryListener f : Utility.copy(this.recoveryListeners)) { @@ -643,20 +612,26 @@ private void notifyRecoveryListenersStarted() { } } - private void recoverTopology(final ExecutorService executor) throws InterruptedException { + private void recoverTopology(final int recoveryThreads) throws InterruptedException { // The recovery sequence is the following: // 1. Recover exchanges // 2. Recover queues // 3. Recover bindings // 4. Recover consumers - if (executor != null) { + if (recoveryThreads > 1) { + // Support recovering entities in parallel for connections that have a lot of queues, bindings, & consumers // A channel is single threaded, so group things by channel and recover 1 entity at a time per channel // We still need to recover 1 type of entity at a time in case channel1 has a binding to a queue that is currently owned and being recovered by channel2 for example - // invokeAll will block until all callables are completed - executor.invokeAll(groupEntitiesByChannel(Utility.copy(recordedExchanges).values())); - executor.invokeAll(groupEntitiesByChannel(Utility.copy(recordedQueues).values())); - executor.invokeAll(groupEntitiesByChannel(Utility.copy(recordedBindings))); - executor.invokeAll(groupEntitiesByChannel(Utility.copy(consumers).values())); + final ExecutorService executor = Executors.newFixedThreadPool(recoveryThreads, delegate.getThreadFactory()); + try { + // invokeAll will block until all callables are completed + executor.invokeAll(groupEntitiesByChannel(Utility.copy(recordedExchanges).values())); + executor.invokeAll(groupEntitiesByChannel(Utility.copy(recordedQueues).values())); + executor.invokeAll(groupEntitiesByChannel(Utility.copy(recordedBindings))); + executor.invokeAll(groupEntitiesByChannel(Utility.copy(consumers).values())); + } finally { + executor.shutdownNow(); + } } else { // recover entities in serial on the main connection thread for (final RecordedExchange exchange : Utility.copy(recordedExchanges).values()) { @@ -785,9 +760,9 @@ private List> groupEntitiesByChannel list.add(entity); } // now create a runnable per channel - final List> tasks = new ArrayList>(); + final List> callables = new ArrayList>(); for (final List entityList : map.values()) { - tasks.add(Executors.callable(new Runnable() { + callables.add(Executors.callable(new Runnable() { @Override public void run() { for (final E entity : entityList) { @@ -806,7 +781,7 @@ public void run() { } })); } - return tasks; + return callables; } void recordQueueBinding(AutorecoveringChannel ch, diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java index a5c6f891ef..7099c5c490 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -16,7 +16,6 @@ package com.rabbitmq.client.test.functional; import com.rabbitmq.client.*; -import com.rabbitmq.client.AMQP.BasicProperties; import com.rabbitmq.client.impl.CredentialsProvider; import com.rabbitmq.client.impl.NetworkConnection; import com.rabbitmq.client.impl.recovery.*; @@ -35,6 +34,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; import static org.hamcrest.Matchers.greaterThanOrEqualTo; @@ -168,13 +168,11 @@ public String getPassword() { final List events = new CopyOnWriteArrayList(); final CountDownLatch latch = new CountDownLatch(2); // one when started, another when complete connection.addShutdownListener(new ShutdownListener() { - @Override public void shutdownCompleted(ShutdownSignalException cause) { events.add("shutdown hook 1"); } }); connection.addShutdownListener(new ShutdownListener() { - @Override public void shutdownCompleted(ShutdownSignalException cause) { events.add("shutdown hook 2"); } @@ -213,7 +211,6 @@ public void handleRecoveryStarted(Recoverable recoverable) { @Test public void shutdownHooksRecoveryOnConnection() throws IOException, InterruptedException { final CountDownLatch latch = new CountDownLatch(2); connection.addShutdownListener(new ShutdownListener() { - @Override public void shutdownCompleted(ShutdownSignalException cause) { latch.countDown(); } @@ -228,7 +225,6 @@ public void shutdownCompleted(ShutdownSignalException cause) { @Test public void shutdownHooksRecoveryOnChannel() throws IOException, InterruptedException { final CountDownLatch latch = new CountDownLatch(3); channel.addShutdownListener(new ShutdownListener() { - @Override public void shutdownCompleted(ShutdownSignalException cause) { latch.countDown(); } @@ -245,12 +241,10 @@ public void shutdownCompleted(ShutdownSignalException cause) { @Test public void blockedListenerRecovery() throws IOException, InterruptedException { final CountDownLatch latch = new CountDownLatch(2); connection.addBlockedListener(new BlockedListener() { - @Override public void handleBlocked(String reason) throws IOException { latch.countDown(); } - @Override public void handleUnblocked() throws IOException { latch.countDown(); } @@ -276,7 +270,6 @@ public void handleUnblocked() throws IOException { @Test public void returnListenerRecovery() throws IOException, InterruptedException { final CountDownLatch latch = new CountDownLatch(1); channel.addReturnListener(new ReturnListener() { - @Override public void handleReturn(int replyCode, String replyText, String exchange, String routingKey, AMQP.BasicProperties properties, byte[] body) throws IOException { @@ -292,12 +285,10 @@ public void handleReturn(int replyCode, String replyText, String exchange, @Test public void confirmListenerRecovery() throws IOException, InterruptedException, TimeoutException { final CountDownLatch latch = new CountDownLatch(1); channel.addConfirmListener(new ConfirmListener() { - @Override public void handleAck(long deliveryTag, boolean multiple) throws IOException { latch.countDown(); } - @Override public void handleNack(long deliveryTag, boolean multiple) throws IOException { latch.countDown(); } @@ -702,11 +693,9 @@ public void consumerRecovered(String oldConsumerTag, String newConsumerTag) { final CountDownLatch latch = new CountDownLatch(2); final CountDownLatch startLatch = new CountDownLatch(2); final RecoveryListener listener = new RecoveryListener() { - @Override public void handleRecovery(Recoverable recoverable) { latch.countDown(); } - @Override public void handleRecoveryStarted(Recoverable recoverable) { startLatch.countDown(); } @@ -803,66 +792,7 @@ public void handleDelivery(String consumerTag, closeAndWaitForRecovery((RecoverableConnection) testConnection); assertTrue(testConnection.isOpen()); } finally { - testConnection.close(); - } - } - - @Test public void recoveryWithMultipleThreads() throws Exception { - // test with 8 recovery threads - ConnectionFactory connectionFactory = buildConnectionFactoryWithRecoveryEnabled(false, 8); - assertEquals(8, connectionFactory.getRecoveryThreadCount()); - RecoverableConnection testConnection = (RecoverableConnection) connectionFactory.newConnection(); - try { - final List channels = new ArrayList(); - final List exchanges = new ArrayList(); - final List queues = new ArrayList(); - // create 16 channels - final int channelCount = 16; - final int queuesPerChannel = 20; - final CountDownLatch latch = new CountDownLatch(channelCount * queuesPerChannel); - for (int i=0; i < channelCount; i++) { - final Channel testChannel = testConnection.createChannel(); - String x = "tmp-x-topic-" + i; - exchanges.add(x); - testChannel.exchangeDeclare(x, "topic"); - // create 20 queues and bindings per channel - for (int j=0; j < queuesPerChannel; j++) { - String q = "tmp-q-" + i + "-" + j; - queues.add(q); - testChannel.queueDeclare(q, false, false, true, null); - testChannel.queueBind(q, x, "tmp-key-" + i + "-" + j); - testChannel.basicConsume(q, new DefaultConsumer(testChannel) { - @Override - public void handleDelivery(String consumerTag, Envelope envelope, BasicProperties properties, byte[] body) throws IOException { - testChannel.basicAck(envelope.getDeliveryTag(), false); - latch.countDown(); - } - }); - } - } - // now do recovery - closeAndWaitForRecovery(testConnection); - - // verify channels & topology recovered by publishing a message to each - for (int i=0; i < channelCount; i++) { - Channel ch = channels.get(i); - expectChannelRecovery(ch); - // publish message to each queue/consumer - for (int j=0; j < queuesPerChannel; j++) { - ch.basicPublish("tmp-x-topic-" + i, "tmp-key-" + i + "-" + j, null, "msg".getBytes()); - } - } - // verify all queues/consumers got it - assertTrue(latch.await(30, TimeUnit.SECONDS)); - - // cleanup - Channel cleanupChannel = testConnection.createChannel(); - for (String q : queues) - cleanupChannel.queueDelete(q); - for (String x : exchanges) - cleanupChannel.exchangeDelete(x); - } finally { - testConnection.close(); + connection.close(); } } @@ -870,28 +800,28 @@ private void assertConsumerCount(int exp, String q) throws IOException { assertEquals(exp, channel.queueDeclarePassive(q).getConsumerCount()); } - private static AMQP.Queue.DeclareOk declareClientNamedQueue(Channel ch, String q) throws IOException { + private AMQP.Queue.DeclareOk declareClientNamedQueue(Channel ch, String q) throws IOException { return ch.queueDeclare(q, true, false, false, null); } - private static AMQP.Queue.DeclareOk declareClientNamedAutoDeleteQueue(Channel ch, String q) throws IOException { + private AMQP.Queue.DeclareOk declareClientNamedAutoDeleteQueue(Channel ch, String q) throws IOException { return ch.queueDeclare(q, true, false, true, null); } - private static void declareClientNamedQueueNoWait(Channel ch, String q) throws IOException { + private void declareClientNamedQueueNoWait(Channel ch, String q) throws IOException { ch.queueDeclareNoWait(q, true, false, false, null); } - private static AMQP.Exchange.DeclareOk declareExchange(Channel ch, String x) throws IOException { + private AMQP.Exchange.DeclareOk declareExchange(Channel ch, String x) throws IOException { return ch.exchangeDeclare(x, "fanout", false); } - private static void declareExchangeNoWait(Channel ch, String x) throws IOException { + private void declareExchangeNoWait(Channel ch, String x) throws IOException { ch.exchangeDeclareNoWait(x, "fanout", false, false, false, null); } - private static void expectQueueRecovery(Channel ch, String q) throws IOException, InterruptedException, TimeoutException { + private void expectQueueRecovery(Channel ch, String q) throws IOException, InterruptedException, TimeoutException { ch.confirmSelect(); ch.queuePurge(q); AMQP.Queue.DeclareOk ok1 = declareClientNamedQueue(ch, q); @@ -902,7 +832,7 @@ private static void expectQueueRecovery(Channel ch, String q) throws IOException assertEquals(1, ok2.getMessageCount()); } - private static void expectAutoDeleteQueueAndBindingRecovery(Channel ch, String x, String q) throws IOException, InterruptedException, + private void expectAutoDeleteQueueAndBindingRecovery(Channel ch, String x, String q) throws IOException, InterruptedException, TimeoutException { ch.confirmSelect(); ch.queuePurge(q); @@ -915,7 +845,7 @@ private static void expectAutoDeleteQueueAndBindingRecovery(Channel ch, String x assertEquals(1, ok2.getMessageCount()); } - private static void expectExchangeRecovery(Channel ch, String x) throws IOException, InterruptedException, TimeoutException { + private void expectExchangeRecovery(Channel ch, String x) throws IOException, InterruptedException, TimeoutException { ch.confirmSelect(); String q = ch.queueDeclare().getQueue(); final String rk = "routing-key"; @@ -925,14 +855,12 @@ private static void expectExchangeRecovery(Channel ch, String x) throws IOExcept ch.exchangeDeclarePassive(x); } - private static CountDownLatch prepareForRecovery(Connection conn) { + private CountDownLatch prepareForRecovery(Connection conn) { final CountDownLatch latch = new CountDownLatch(1); ((AutorecoveringConnection)conn).addRecoveryListener(new RecoveryListener() { - @Override public void handleRecovery(Recoverable recoverable) { latch.countDown(); } - @Override public void handleRecoveryStarted(Recoverable recoverable) { // No-op } @@ -940,10 +868,9 @@ public void handleRecoveryStarted(Recoverable recoverable) { return latch; } - private static CountDownLatch prepareForShutdown(Connection conn) { + private CountDownLatch prepareForShutdown(Connection conn) throws InterruptedException { final CountDownLatch latch = new CountDownLatch(1); conn.addShutdownListener(new ShutdownListener() { - @Override public void shutdownCompleted(ShutdownSignalException cause) { latch.countDown(); } @@ -955,7 +882,7 @@ private void closeAndWaitForRecovery() throws IOException, InterruptedException closeAndWaitForRecovery((AutorecoveringConnection)this.connection); } - private static void closeAndWaitForRecovery(RecoverableConnection connection) throws IOException, InterruptedException { + private void closeAndWaitForRecovery(RecoverableConnection connection) throws IOException, InterruptedException { CountDownLatch latch = prepareForRecovery(connection); Host.closeConnection((NetworkConnection) connection); wait(latch); @@ -973,7 +900,7 @@ private void restartPrimaryAndWaitForRecovery(Connection connection) throws IOEx wait(latch); } - private static void expectChannelRecovery(Channel ch) { + private void expectChannelRecovery(Channel ch) throws InterruptedException { assertTrue(ch.isOpen()); } @@ -982,53 +909,48 @@ protected ConnectionFactory newConnectionFactory() { return buildConnectionFactoryWithRecoveryEnabled(false); } - private static RecoverableConnection newRecoveringConnection(boolean disableTopologyRecovery) + private RecoverableConnection newRecoveringConnection(boolean disableTopologyRecovery) throws IOException, TimeoutException { ConnectionFactory cf = buildConnectionFactoryWithRecoveryEnabled(disableTopologyRecovery); return (AutorecoveringConnection) cf.newConnection(); } - private static RecoverableConnection newRecoveringConnection(Address[] addresses) + private RecoverableConnection newRecoveringConnection(Address[] addresses) throws IOException, TimeoutException { ConnectionFactory cf = buildConnectionFactoryWithRecoveryEnabled(false); // specifically use the Address[] overload return (AutorecoveringConnection) cf.newConnection(addresses); } - private static RecoverableConnection newRecoveringConnection(boolean disableTopologyRecovery, List
addresses) + private RecoverableConnection newRecoveringConnection(boolean disableTopologyRecovery, List
addresses) throws IOException, TimeoutException { ConnectionFactory cf = buildConnectionFactoryWithRecoveryEnabled(disableTopologyRecovery); return (AutorecoveringConnection) cf.newConnection(addresses); } - private static RecoverableConnection newRecoveringConnection(List
addresses) + private RecoverableConnection newRecoveringConnection(List
addresses) throws IOException, TimeoutException { return newRecoveringConnection(false, addresses); } - private static RecoverableConnection newRecoveringConnection(boolean disableTopologyRecovery, String connectionName) + private RecoverableConnection newRecoveringConnection(boolean disableTopologyRecovery, String connectionName) throws IOException, TimeoutException { ConnectionFactory cf = buildConnectionFactoryWithRecoveryEnabled(disableTopologyRecovery); return (RecoverableConnection) cf.newConnection(connectionName); } - private static RecoverableConnection newRecoveringConnection(String connectionName) + private RecoverableConnection newRecoveringConnection(String connectionName) throws IOException, TimeoutException { return newRecoveringConnection(false, connectionName); } - - private static ConnectionFactory buildConnectionFactoryWithRecoveryEnabled(boolean disableTopologyRecovery) { - return buildConnectionFactoryWithRecoveryEnabled(disableTopologyRecovery, 1); - } - private static ConnectionFactory buildConnectionFactoryWithRecoveryEnabled(boolean disableTopologyRecovery, final int recoveryThreads) { + private ConnectionFactory buildConnectionFactoryWithRecoveryEnabled(boolean disableTopologyRecovery) { ConnectionFactory cf = TestUtils.connectionFactory(); cf.setNetworkRecoveryInterval(RECOVERY_INTERVAL); cf.setAutomaticRecoveryEnabled(true); if (disableTopologyRecovery) { cf.setTopologyRecoveryEnabled(false); } - cf.setRecoveryThreadCount(recoveryThreads); return cf; } @@ -1038,15 +960,15 @@ private static void wait(CountDownLatch latch) throws InterruptedException { assertTrue(latch.await(90, TimeUnit.SECONDS)); } - private static void waitForConfirms(Channel ch) throws InterruptedException, TimeoutException { + private void waitForConfirms(Channel ch) throws InterruptedException, TimeoutException { ch.waitForConfirms(30 * 60 * 1000); } - private static void assertRecordedQueues(Connection conn, int size) { + private void assertRecordedQueues(Connection conn, int size) { assertEquals(size, ((AutorecoveringConnection)conn).getRecordedQueues().size()); } - private static void assertRecordedExchanges(Connection conn, int size) { + private void assertRecordedExchanges(Connection conn, int size) { assertEquals(size, ((AutorecoveringConnection)conn).getRecordedExchanges().size()); } } From 84c891c7d9f83658482ea40c3011e5dc3a726283 Mon Sep 17 00:00:00 2001 From: Michael Dent Date: Mon, 21 May 2018 14:22:14 -0500 Subject: [PATCH 0778/2114] add test back --- .../test/functional/ConnectionRecovery.java | 125 ++++++++++++++---- 1 file changed, 102 insertions(+), 23 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java index 7099c5c490..401171a56c 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -16,6 +16,7 @@ package com.rabbitmq.client.test.functional; import com.rabbitmq.client.*; +import com.rabbitmq.client.AMQP.BasicProperties; import com.rabbitmq.client.impl.CredentialsProvider; import com.rabbitmq.client.impl.NetworkConnection; import com.rabbitmq.client.impl.recovery.*; @@ -34,7 +35,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; import static org.hamcrest.Matchers.greaterThanOrEqualTo; @@ -168,11 +168,13 @@ public String getPassword() { final List events = new CopyOnWriteArrayList(); final CountDownLatch latch = new CountDownLatch(2); // one when started, another when complete connection.addShutdownListener(new ShutdownListener() { + @Override public void shutdownCompleted(ShutdownSignalException cause) { events.add("shutdown hook 1"); } }); connection.addShutdownListener(new ShutdownListener() { + @Override public void shutdownCompleted(ShutdownSignalException cause) { events.add("shutdown hook 2"); } @@ -211,6 +213,7 @@ public void handleRecoveryStarted(Recoverable recoverable) { @Test public void shutdownHooksRecoveryOnConnection() throws IOException, InterruptedException { final CountDownLatch latch = new CountDownLatch(2); connection.addShutdownListener(new ShutdownListener() { + @Override public void shutdownCompleted(ShutdownSignalException cause) { latch.countDown(); } @@ -225,6 +228,7 @@ public void shutdownCompleted(ShutdownSignalException cause) { @Test public void shutdownHooksRecoveryOnChannel() throws IOException, InterruptedException { final CountDownLatch latch = new CountDownLatch(3); channel.addShutdownListener(new ShutdownListener() { + @Override public void shutdownCompleted(ShutdownSignalException cause) { latch.countDown(); } @@ -241,10 +245,12 @@ public void shutdownCompleted(ShutdownSignalException cause) { @Test public void blockedListenerRecovery() throws IOException, InterruptedException { final CountDownLatch latch = new CountDownLatch(2); connection.addBlockedListener(new BlockedListener() { + @Override public void handleBlocked(String reason) throws IOException { latch.countDown(); } + @Override public void handleUnblocked() throws IOException { latch.countDown(); } @@ -270,6 +276,7 @@ public void handleUnblocked() throws IOException { @Test public void returnListenerRecovery() throws IOException, InterruptedException { final CountDownLatch latch = new CountDownLatch(1); channel.addReturnListener(new ReturnListener() { + @Override public void handleReturn(int replyCode, String replyText, String exchange, String routingKey, AMQP.BasicProperties properties, byte[] body) throws IOException { @@ -285,10 +292,12 @@ public void handleReturn(int replyCode, String replyText, String exchange, @Test public void confirmListenerRecovery() throws IOException, InterruptedException, TimeoutException { final CountDownLatch latch = new CountDownLatch(1); channel.addConfirmListener(new ConfirmListener() { + @Override public void handleAck(long deliveryTag, boolean multiple) throws IOException { latch.countDown(); } + @Override public void handleNack(long deliveryTag, boolean multiple) throws IOException { latch.countDown(); } @@ -693,9 +702,11 @@ public void consumerRecovered(String oldConsumerTag, String newConsumerTag) { final CountDownLatch latch = new CountDownLatch(2); final CountDownLatch startLatch = new CountDownLatch(2); final RecoveryListener listener = new RecoveryListener() { + @Override public void handleRecovery(Recoverable recoverable) { latch.countDown(); } + @Override public void handleRecoveryStarted(Recoverable recoverable) { startLatch.countDown(); } @@ -795,33 +806,93 @@ public void handleDelivery(String consumerTag, connection.close(); } } + + @Test public void recoveryWithMultipleThreads() throws Exception { + // test with 8 recovery threads + ConnectionFactory connectionFactory = buildConnectionFactoryWithRecoveryEnabled(false, 8); + assertEquals(8, connectionFactory.getTopologyRecoveryThreadCount()); + RecoverableConnection testConnection = (RecoverableConnection) connectionFactory.newConnection(); + try { + final List channels = new ArrayList(); + final List exchanges = new ArrayList(); + final List queues = new ArrayList(); + // create 16 channels + final int channelCount = 16; + final int queuesPerChannel = 20; + final CountDownLatch latch = new CountDownLatch(channelCount * queuesPerChannel); + for (int i=0; i < channelCount; i++) { + final Channel testChannel = testConnection.createChannel(); + String x = "tmp-x-topic-" + i; + exchanges.add(x); + testChannel.exchangeDeclare(x, "topic"); + // create 20 queues and bindings per channel + for (int j=0; j < queuesPerChannel; j++) { + String q = "tmp-q-" + i + "-" + j; + queues.add(q); + testChannel.queueDeclare(q, false, false, true, null); + testChannel.queueBind(q, x, "tmp-key-" + i + "-" + j); + testChannel.basicConsume(q, new DefaultConsumer(testChannel) { + @Override + public void handleDelivery(String consumerTag, Envelope envelope, BasicProperties properties, byte[] body) + throws IOException { + testChannel.basicAck(envelope.getDeliveryTag(), false); + latch.countDown(); + } + }); + } + } + // now do recovery + closeAndWaitForRecovery(testConnection); + + // verify channels & topology recovered by publishing a message to each + for (int i=0; i < channelCount; i++) { + Channel ch = channels.get(i); + expectChannelRecovery(ch); + // publish message to each queue/consumer + for (int j=0; j < queuesPerChannel; j++) { + ch.basicPublish("tmp-x-topic-" + i, "tmp-key-" + i + "-" + j, null, "msg".getBytes()); + } + } + // verify all queues/consumers got it + assertTrue(latch.await(30, TimeUnit.SECONDS)); + + // cleanup + Channel cleanupChannel = testConnection.createChannel(); + for (String q : queues) + cleanupChannel.queueDelete(q); + for (String x : exchanges) + cleanupChannel.exchangeDelete(x); + } finally { + testConnection.close(); + } + } private void assertConsumerCount(int exp, String q) throws IOException { assertEquals(exp, channel.queueDeclarePassive(q).getConsumerCount()); } - private AMQP.Queue.DeclareOk declareClientNamedQueue(Channel ch, String q) throws IOException { + private static AMQP.Queue.DeclareOk declareClientNamedQueue(Channel ch, String q) throws IOException { return ch.queueDeclare(q, true, false, false, null); } - private AMQP.Queue.DeclareOk declareClientNamedAutoDeleteQueue(Channel ch, String q) throws IOException { + private static AMQP.Queue.DeclareOk declareClientNamedAutoDeleteQueue(Channel ch, String q) throws IOException { return ch.queueDeclare(q, true, false, true, null); } - private void declareClientNamedQueueNoWait(Channel ch, String q) throws IOException { + private static void declareClientNamedQueueNoWait(Channel ch, String q) throws IOException { ch.queueDeclareNoWait(q, true, false, false, null); } - private AMQP.Exchange.DeclareOk declareExchange(Channel ch, String x) throws IOException { + private static AMQP.Exchange.DeclareOk declareExchange(Channel ch, String x) throws IOException { return ch.exchangeDeclare(x, "fanout", false); } - private void declareExchangeNoWait(Channel ch, String x) throws IOException { + private static void declareExchangeNoWait(Channel ch, String x) throws IOException { ch.exchangeDeclareNoWait(x, "fanout", false, false, false, null); } - private void expectQueueRecovery(Channel ch, String q) throws IOException, InterruptedException, TimeoutException { + private static void expectQueueRecovery(Channel ch, String q) throws IOException, InterruptedException, TimeoutException { ch.confirmSelect(); ch.queuePurge(q); AMQP.Queue.DeclareOk ok1 = declareClientNamedQueue(ch, q); @@ -832,7 +903,7 @@ private void expectQueueRecovery(Channel ch, String q) throws IOException, Inter assertEquals(1, ok2.getMessageCount()); } - private void expectAutoDeleteQueueAndBindingRecovery(Channel ch, String x, String q) throws IOException, InterruptedException, + private static void expectAutoDeleteQueueAndBindingRecovery(Channel ch, String x, String q) throws IOException, InterruptedException, TimeoutException { ch.confirmSelect(); ch.queuePurge(q); @@ -845,7 +916,7 @@ private void expectAutoDeleteQueueAndBindingRecovery(Channel ch, String x, Strin assertEquals(1, ok2.getMessageCount()); } - private void expectExchangeRecovery(Channel ch, String x) throws IOException, InterruptedException, TimeoutException { + private static void expectExchangeRecovery(Channel ch, String x) throws IOException, InterruptedException, TimeoutException { ch.confirmSelect(); String q = ch.queueDeclare().getQueue(); final String rk = "routing-key"; @@ -855,12 +926,14 @@ private void expectExchangeRecovery(Channel ch, String x) throws IOException, In ch.exchangeDeclarePassive(x); } - private CountDownLatch prepareForRecovery(Connection conn) { + private static CountDownLatch prepareForRecovery(Connection conn) { final CountDownLatch latch = new CountDownLatch(1); ((AutorecoveringConnection)conn).addRecoveryListener(new RecoveryListener() { + @Override public void handleRecovery(Recoverable recoverable) { latch.countDown(); } + @Override public void handleRecoveryStarted(Recoverable recoverable) { // No-op } @@ -868,9 +941,10 @@ public void handleRecoveryStarted(Recoverable recoverable) { return latch; } - private CountDownLatch prepareForShutdown(Connection conn) throws InterruptedException { + private static CountDownLatch prepareForShutdown(Connection conn) { final CountDownLatch latch = new CountDownLatch(1); conn.addShutdownListener(new ShutdownListener() { + @Override public void shutdownCompleted(ShutdownSignalException cause) { latch.countDown(); } @@ -882,7 +956,7 @@ private void closeAndWaitForRecovery() throws IOException, InterruptedException closeAndWaitForRecovery((AutorecoveringConnection)this.connection); } - private void closeAndWaitForRecovery(RecoverableConnection connection) throws IOException, InterruptedException { + private static void closeAndWaitForRecovery(RecoverableConnection connection) throws IOException, InterruptedException { CountDownLatch latch = prepareForRecovery(connection); Host.closeConnection((NetworkConnection) connection); wait(latch); @@ -900,7 +974,7 @@ private void restartPrimaryAndWaitForRecovery(Connection connection) throws IOEx wait(latch); } - private void expectChannelRecovery(Channel ch) throws InterruptedException { + private static void expectChannelRecovery(Channel ch) { assertTrue(ch.isOpen()); } @@ -909,48 +983,53 @@ protected ConnectionFactory newConnectionFactory() { return buildConnectionFactoryWithRecoveryEnabled(false); } - private RecoverableConnection newRecoveringConnection(boolean disableTopologyRecovery) + private static RecoverableConnection newRecoveringConnection(boolean disableTopologyRecovery) throws IOException, TimeoutException { ConnectionFactory cf = buildConnectionFactoryWithRecoveryEnabled(disableTopologyRecovery); return (AutorecoveringConnection) cf.newConnection(); } - private RecoverableConnection newRecoveringConnection(Address[] addresses) + private static RecoverableConnection newRecoveringConnection(Address[] addresses) throws IOException, TimeoutException { ConnectionFactory cf = buildConnectionFactoryWithRecoveryEnabled(false); // specifically use the Address[] overload return (AutorecoveringConnection) cf.newConnection(addresses); } - private RecoverableConnection newRecoveringConnection(boolean disableTopologyRecovery, List
addresses) + private static RecoverableConnection newRecoveringConnection(boolean disableTopologyRecovery, List
addresses) throws IOException, TimeoutException { ConnectionFactory cf = buildConnectionFactoryWithRecoveryEnabled(disableTopologyRecovery); return (AutorecoveringConnection) cf.newConnection(addresses); } - private RecoverableConnection newRecoveringConnection(List
addresses) + private static RecoverableConnection newRecoveringConnection(List
addresses) throws IOException, TimeoutException { return newRecoveringConnection(false, addresses); } - private RecoverableConnection newRecoveringConnection(boolean disableTopologyRecovery, String connectionName) + private static RecoverableConnection newRecoveringConnection(boolean disableTopologyRecovery, String connectionName) throws IOException, TimeoutException { ConnectionFactory cf = buildConnectionFactoryWithRecoveryEnabled(disableTopologyRecovery); return (RecoverableConnection) cf.newConnection(connectionName); } - private RecoverableConnection newRecoveringConnection(String connectionName) + private static RecoverableConnection newRecoveringConnection(String connectionName) throws IOException, TimeoutException { return newRecoveringConnection(false, connectionName); } + + private static ConnectionFactory buildConnectionFactoryWithRecoveryEnabled(boolean disableTopologyRecovery) { + return buildConnectionFactoryWithRecoveryEnabled(disableTopologyRecovery, 1); + } - private ConnectionFactory buildConnectionFactoryWithRecoveryEnabled(boolean disableTopologyRecovery) { + private static ConnectionFactory buildConnectionFactoryWithRecoveryEnabled(boolean disableTopologyRecovery, final int recoveryThreads) { ConnectionFactory cf = TestUtils.connectionFactory(); cf.setNetworkRecoveryInterval(RECOVERY_INTERVAL); cf.setAutomaticRecoveryEnabled(true); if (disableTopologyRecovery) { cf.setTopologyRecoveryEnabled(false); } + cf.setTopologyRecoveryThreadCount(recoveryThreads); return cf; } @@ -960,15 +1039,15 @@ private static void wait(CountDownLatch latch) throws InterruptedException { assertTrue(latch.await(90, TimeUnit.SECONDS)); } - private void waitForConfirms(Channel ch) throws InterruptedException, TimeoutException { + private static void waitForConfirms(Channel ch) throws InterruptedException, TimeoutException { ch.waitForConfirms(30 * 60 * 1000); } - private void assertRecordedQueues(Connection conn, int size) { + private static void assertRecordedQueues(Connection conn, int size) { assertEquals(size, ((AutorecoveringConnection)conn).getRecordedQueues().size()); } - private void assertRecordedExchanges(Connection conn, int size) { + private static void assertRecordedExchanges(Connection conn, int size) { assertEquals(size, ((AutorecoveringConnection)conn).getRecordedExchanges().size()); } } From f55ad22ae3d99fa53beefa989dab2f41e9afb335 Mon Sep 17 00:00:00 2001 From: Michael Dent Date: Tue, 22 May 2018 10:47:19 -0500 Subject: [PATCH 0779/2114] fix toString --- .../com/rabbitmq/client/impl/recovery/RecordedConsumer.java | 2 +- .../com/rabbitmq/client/impl/recovery/RecordedExchange.java | 2 +- .../rabbitmq/client/impl/recovery/RecordedExchangeBinding.java | 2 +- .../java/com/rabbitmq/client/impl/recovery/RecordedQueue.java | 2 +- .../com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedConsumer.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedConsumer.java index 748c184bd2..1eb9c7a943 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedConsumer.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedConsumer.java @@ -80,6 +80,6 @@ public String getConsumerTag() { @Override public String toString() { - return "RecordedConsumer[tag=" + consumerTag + ", queue=" + queue + ", autoAck=" + autoAck + ", exclusive=" + exclusive + ", arguments=" + arguments + ", consumer=" + consumer + ", channel=" + channel; + return "RecordedConsumer[tag=" + consumerTag + ", queue=" + queue + ", autoAck=" + autoAck + ", exclusive=" + exclusive + ", arguments=" + arguments + ", consumer=" + consumer + ", channel=" + channel + "]"; } } diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchange.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchange.java index 565846dcc9..2884604fdc 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchange.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchange.java @@ -61,6 +61,6 @@ public boolean isAutoDelete() { @Override public String toString() { - return "RecordedExchange[name=" + name + ", type=" + type + ", durable=" + durable + ", autoDelete=" + autoDelete + ", arguments=" + arguments + ", channel=" + channel; + return "RecordedExchange[name=" + name + ", type=" + type + ", durable=" + durable + ", autoDelete=" + autoDelete + ", arguments=" + arguments + ", channel=" + channel + "]"; } } diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchangeBinding.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchangeBinding.java index 1e1ca5c179..3b6d72881d 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchangeBinding.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchangeBinding.java @@ -32,6 +32,6 @@ public void recover() throws IOException { @Override public String toString() { - return "RecordedExchangeBinding[source=" + source + ", destination=" + destination + ", routingKey=" + routingKey + ", arguments=" + arguments + ", channel=" + channel; + return "RecordedExchangeBinding[source=" + source + ", destination=" + destination + ", routingKey=" + routingKey + ", arguments=" + arguments + ", channel=" + channel + "]"; } } diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java index d515a6af54..f446e1682c 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java @@ -82,6 +82,6 @@ public RecordedQueue arguments(Map value) { @Override public String toString() { - return "RecordedQueue[name=" + name + ", durable=" + durable + ", autoDelete=" + autoDelete + ", exclusive=" + exclusive + ", arguments=" + arguments + "serverNamed=" + serverNamed + ", channel=" + channel; + return "RecordedQueue[name=" + name + ", durable=" + durable + ", autoDelete=" + autoDelete + ", exclusive=" + exclusive + ", arguments=" + arguments + "serverNamed=" + serverNamed + ", channel=" + channel + "]"; } } diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java index a5bb0f7b76..a933ce3acd 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java @@ -32,6 +32,6 @@ public void recover() throws IOException { @Override public String toString() { - return "RecordedQueueBinding[source=" + source + ", destination=" + destination + ", routingKey=" + routingKey + ", arguments=" + arguments + ", channel=" + channel; + return "RecordedQueueBinding[source=" + source + ", destination=" + destination + ", routingKey=" + routingKey + ", arguments=" + arguments + ", channel=" + channel + "]"; } } From b29ebe62e9132f50258166521df6b8128d709257 Mon Sep 17 00:00:00 2001 From: Michael Dent Date: Thu, 24 May 2018 09:50:25 -0500 Subject: [PATCH 0780/2114] code review comments --- .../rabbitmq/client/ConnectionFactory.java | 23 ++++++++---- .../com/rabbitmq/client/ExceptionHandler.java | 2 +- .../client/impl/ConnectionParams.java | 14 +++++--- .../recovery/AutorecoveringConnection.java | 35 ++++++++++--------- .../test/functional/ConnectionRecovery.java | 17 +++++---- 5 files changed, 54 insertions(+), 37 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index f8a329124a..ce04a0d83c 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -127,7 +127,7 @@ public class ConnectionFactory implements Cloneable { private boolean automaticRecovery = true; private boolean topologyRecovery = true; - private int topologyRecoveryThreads = 1; + private ExecutorService topologyRecoveryExecutor; // long is used to make sure the users can use both ints // and longs safely. It is unlikely that anybody'd need @@ -714,13 +714,22 @@ public void setTopologyRecoveryEnabled(boolean topologyRecovery) { this.topologyRecovery = topologyRecovery; } - public int getTopologyRecoveryThreadCount() { - return topologyRecoveryThreads; + /** + * Get the executor to use for parallel topology recovery. If null (the default), recovery is done single threaded on the main connection thread. + * @return thread pool executor + */ + public ExecutorService getTopologyRecoveryExecutor() { + return topologyRecoveryExecutor; } - // TODO Document that your exception handler method should be thread safe - public void setTopologyRecoveryThreadCount(final int topologyRecoveryThreads) { - this.topologyRecoveryThreads = topologyRecoveryThreads; + /** + * Set the executor to use for parallel topology recovery. If null (the default), recovery is done single threaded on the main connection thread. + * It is recommended to pass a ThreadPoolExecutor that will allow its core threads to timeout so these threads can die when recovery is complete. + * Note: your {@link ExceptionHandler#handleTopologyRecoveryException(Connection, Channel, TopologyRecoveryException)} method should be thread-safe. + * @param topologyRecoveryExecutor thread pool executor + */ + public void setTopologyRecoveryExecutor(final ExecutorService topologyRecoveryExecutor) { + this.topologyRecoveryExecutor = topologyRecoveryExecutor; } public void setMetricsCollector(MetricsCollector metricsCollector) { @@ -1021,7 +1030,7 @@ public ConnectionParams params(ExecutorService consumerWorkServiceExecutor) { result.setNetworkRecoveryInterval(networkRecoveryInterval); result.setRecoveryDelayHandler(recoveryDelayHandler); result.setTopologyRecovery(topologyRecovery); - result.setTopologyRecoveryThreadCount(topologyRecoveryThreads); + result.setTopologyRecoveryExecutor(topologyRecoveryExecutor); result.setExceptionHandler(exceptionHandler); result.setThreadFactory(threadFactory); result.setHandshakeTimeout(handshakeTimeout); diff --git a/src/main/java/com/rabbitmq/client/ExceptionHandler.java b/src/main/java/com/rabbitmq/client/ExceptionHandler.java index 958bb1c5df..b840c6d50e 100644 --- a/src/main/java/com/rabbitmq/client/ExceptionHandler.java +++ b/src/main/java/com/rabbitmq/client/ExceptionHandler.java @@ -108,7 +108,7 @@ void handleConsumerException(Channel channel, * during topology (exchanges, queues, bindings, consumers) recovery * that it can't otherwise deal with. * @param conn the Connection that caught the exception - * @param ch the Channel that caught the exception + * @param ch the Channel that caught the exception. May be null. * @param exception the exception caught in the driver thread */ diff --git a/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java b/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java index 0fe4e7c2cd..08c123bd81 100644 --- a/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java +++ b/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java @@ -41,7 +41,7 @@ public class ConnectionParams { private long networkRecoveryInterval; private RecoveryDelayHandler recoveryDelayHandler; private boolean topologyRecovery; - private int topologyRecoveryThreads = 1; + private ExecutorService topologyRecoveryExecutor; private int channelRpcTimeout; private boolean channelShouldCheckRpcResponseType; private ErrorOnWriteListener errorOnWriteListener; @@ -116,8 +116,12 @@ public boolean isTopologyRecoveryEnabled() { return topologyRecovery; } - public int getTopologyRecoveryThreadCount() { - return topologyRecoveryThreads; + /** + * Get the topology recovery executor. If null, the main connection thread should be used. + * @return executor. May be null. + */ + public ExecutorService getTopologyRecoveryExecutor() { + return topologyRecoveryExecutor; } public ThreadFactory getThreadFactory() { @@ -180,8 +184,8 @@ public void setTopologyRecovery(boolean topologyRecovery) { this.topologyRecovery = topologyRecovery; } - public void setTopologyRecoveryThreadCount(final int topologyRecoveryThreads) { - this.topologyRecoveryThreads = topologyRecoveryThreads; + public void setTopologyRecoveryExecutor(final ExecutorService topologyRecoveryExecutor) { + this.topologyRecoveryExecutor = topologyRecoveryExecutor; } public void setExceptionHandler(ExceptionHandler exceptionHandler) { diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index ad337f49e7..4c2f103dca 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -544,7 +544,7 @@ private synchronized void beginAutomaticRecovery() throws InterruptedException { // don't assign new delegate connection until channel recovery is complete this.delegate = newConn; if (this.params.isTopologyRecoveryEnabled()) { - recoverTopology(params.getTopologyRecoveryThreadCount()); + recoverTopology(params.getTopologyRecoveryExecutor()); } this.notifyRecoveryListenersComplete(); } @@ -612,27 +612,13 @@ private void notifyRecoveryListenersStarted() { } } - private void recoverTopology(final int recoveryThreads) throws InterruptedException { + private void recoverTopology(final ExecutorService executor) { // The recovery sequence is the following: // 1. Recover exchanges // 2. Recover queues // 3. Recover bindings // 4. Recover consumers - if (recoveryThreads > 1) { - // Support recovering entities in parallel for connections that have a lot of queues, bindings, & consumers - // A channel is single threaded, so group things by channel and recover 1 entity at a time per channel - // We still need to recover 1 type of entity at a time in case channel1 has a binding to a queue that is currently owned and being recovered by channel2 for example - final ExecutorService executor = Executors.newFixedThreadPool(recoveryThreads, delegate.getThreadFactory()); - try { - // invokeAll will block until all callables are completed - executor.invokeAll(groupEntitiesByChannel(Utility.copy(recordedExchanges).values())); - executor.invokeAll(groupEntitiesByChannel(Utility.copy(recordedQueues).values())); - executor.invokeAll(groupEntitiesByChannel(Utility.copy(recordedBindings))); - executor.invokeAll(groupEntitiesByChannel(Utility.copy(consumers).values())); - } finally { - executor.shutdownNow(); - } - } else { + if (executor == null) { // recover entities in serial on the main connection thread for (final RecordedExchange exchange : Utility.copy(recordedExchanges).values()) { recoverExchange(exchange); @@ -646,6 +632,21 @@ private void recoverTopology(final int recoveryThreads) throws InterruptedExcept for (final Map.Entry entry : Utility.copy(consumers).entrySet()) { recoverConsumer(entry.getKey(), entry.getValue()); } + } else { + // Support recovering entities in parallel for connections that have a lot of queues, bindings, & consumers + // A channel is single threaded, so group things by channel and recover 1 entity at a time per channel + // We also need to recover 1 type of entity at a time in case channel1 has a binding to a queue that is currently owned and being recovered by channel2 for example + // Note: invokeAll will block until all callables are completed and all returned futures will be complete + try { + executor.invokeAll(groupEntitiesByChannel(Utility.copy(recordedExchanges).values())); + executor.invokeAll(groupEntitiesByChannel(Utility.copy(recordedQueues).values())); + executor.invokeAll(groupEntitiesByChannel(Utility.copy(recordedBindings))); + executor.invokeAll(groupEntitiesByChannel(Utility.copy(consumers).values())); + } catch (final Exception cause) { + final String message = "Caught an exception while recovering toplogy: " + cause.getMessage(); + final TopologyRecoveryException e = new TopologyRecoveryException(message, cause); + getExceptionHandler().handleTopologyRecoveryException(delegate, null, e); + } } } diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java index 401171a56c..39a3984280 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -32,6 +32,9 @@ import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; @@ -809,8 +812,12 @@ public void handleDelivery(String consumerTag, @Test public void recoveryWithMultipleThreads() throws Exception { // test with 8 recovery threads - ConnectionFactory connectionFactory = buildConnectionFactoryWithRecoveryEnabled(false, 8); - assertEquals(8, connectionFactory.getTopologyRecoveryThreadCount()); + final ThreadPoolExecutor executor = new ThreadPoolExecutor(8, 8, 30, TimeUnit.SECONDS, new LinkedBlockingQueue()); + executor.allowCoreThreadTimeOut(true); + ConnectionFactory connectionFactory = buildConnectionFactoryWithRecoveryEnabled(false); + assertNull(connectionFactory.getTopologyRecoveryExecutor()); + connectionFactory.setTopologyRecoveryExecutor(executor); + assertEquals(executor, connectionFactory.getTopologyRecoveryExecutor()); RecoverableConnection testConnection = (RecoverableConnection) connectionFactory.newConnection(); try { final List channels = new ArrayList(); @@ -822,6 +829,7 @@ public void handleDelivery(String consumerTag, final CountDownLatch latch = new CountDownLatch(channelCount * queuesPerChannel); for (int i=0; i < channelCount; i++) { final Channel testChannel = testConnection.createChannel(); + channels.add(testChannel); String x = "tmp-x-topic-" + i; exchanges.add(x); testChannel.exchangeDeclare(x, "topic"); @@ -1019,17 +1027,12 @@ private static RecoverableConnection newRecoveringConnection(String connectionNa } private static ConnectionFactory buildConnectionFactoryWithRecoveryEnabled(boolean disableTopologyRecovery) { - return buildConnectionFactoryWithRecoveryEnabled(disableTopologyRecovery, 1); - } - - private static ConnectionFactory buildConnectionFactoryWithRecoveryEnabled(boolean disableTopologyRecovery, final int recoveryThreads) { ConnectionFactory cf = TestUtils.connectionFactory(); cf.setNetworkRecoveryInterval(RECOVERY_INTERVAL); cf.setAutomaticRecoveryEnabled(true); if (disableTopologyRecovery) { cf.setTopologyRecoveryEnabled(false); } - cf.setTopologyRecoveryThreadCount(recoveryThreads); return cf; } From 3499d2f4d1b2812768034320b30435d55d9b69c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 28 May 2018 10:43:00 +0200 Subject: [PATCH 0781/2114] Log unfinished multi-threaded topology recovery tasks References #370 --- .../rabbitmq/client/ConnectionFactory.java | 3 +++ .../recovery/AutorecoveringConnection.java | 27 +++++++++++++++---- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index d7926f0531..5364da2b78 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -719,6 +719,7 @@ public void setTopologyRecoveryEnabled(boolean topologyRecovery) { /** * Get the executor to use for parallel topology recovery. If null (the default), recovery is done single threaded on the main connection thread. * @return thread pool executor + * @since 4.7.0 */ public ExecutorService getTopologyRecoveryExecutor() { return topologyRecoveryExecutor; @@ -727,8 +728,10 @@ public ExecutorService getTopologyRecoveryExecutor() { /** * Set the executor to use for parallel topology recovery. If null (the default), recovery is done single threaded on the main connection thread. * It is recommended to pass a ThreadPoolExecutor that will allow its core threads to timeout so these threads can die when recovery is complete. + * It's developer's responsibility to shut down the executor when it is no longer needed. * Note: your {@link ExceptionHandler#handleTopologyRecoveryException(Connection, Channel, TopologyRecoveryException)} method should be thread-safe. * @param topologyRecoveryExecutor thread pool executor + * @since 4.7.0 */ public void setTopologyRecoveryExecutor(final ExecutorService topologyRecoveryExecutor) { this.topologyRecoveryExecutor = topologyRecoveryExecutor; diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index 4c2f103dca..85fe95ba2a 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -32,7 +32,9 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.Future; import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; @@ -638,10 +640,10 @@ private void recoverTopology(final ExecutorService executor) { // We also need to recover 1 type of entity at a time in case channel1 has a binding to a queue that is currently owned and being recovered by channel2 for example // Note: invokeAll will block until all callables are completed and all returned futures will be complete try { - executor.invokeAll(groupEntitiesByChannel(Utility.copy(recordedExchanges).values())); - executor.invokeAll(groupEntitiesByChannel(Utility.copy(recordedQueues).values())); - executor.invokeAll(groupEntitiesByChannel(Utility.copy(recordedBindings))); - executor.invokeAll(groupEntitiesByChannel(Utility.copy(consumers).values())); + recoverEntitiesAsynchronously(executor, Utility.copy(recordedExchanges).values()); + recoverEntitiesAsynchronously(executor, Utility.copy(recordedQueues).values()); + recoverEntitiesAsynchronously(executor, Utility.copy(recordedBindings)); + recoverEntitiesAsynchronously(executor, Utility.copy(consumers).values()); } catch (final Exception cause) { final String message = "Caught an exception while recovering toplogy: " + cause.getMessage(); final TopologyRecoveryException e = new TopologyRecoveryException(message, cause); @@ -748,7 +750,22 @@ private void propagateQueueNameChangeToConsumers(String oldName, String newName) } } } - + + private void recoverEntitiesAsynchronously(ExecutorService executor, Collection recordedEntities) throws InterruptedException { + List> tasks = executor.invokeAll(groupEntitiesByChannel(recordedEntities)); + for (Future task : tasks) { + if (!task.isDone()) { + LOGGER.warn("Recovery task should be done {}", task); + } else { + try { + task.get(1, TimeUnit.MILLISECONDS); + } catch (Exception e) { + LOGGER.warn("Recovery task is done but returned an exception", e); + } + } + } + } + private List> groupEntitiesByChannel(final Collection entities) { // map entities by channel final Map> map = new LinkedHashMap>(); From 897660979d6f24bf12e5b7dc753f176e77193694 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 28 May 2018 10:47:44 +0200 Subject: [PATCH 0782/2114] Use lambda References #370 --- .../recovery/AutorecoveringConnection.java | 29 +++++++++---------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index d91248e4d1..17602b340b 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -792,23 +792,20 @@ private List> groupEntitiesByChannel list.add(entity); } // now create a runnable per channel - final List> callables = new ArrayList>(); + final List> callables = new ArrayList<>(); for (final List entityList : map.values()) { - callables.add(Executors.callable(new Runnable() { - @Override - public void run() { - for (final E entity : entityList) { - if (entity instanceof RecordedExchange) { - recoverExchange((RecordedExchange)entity); - } else if (entity instanceof RecordedQueue) { - final RecordedQueue q = (RecordedQueue) entity; - recoverQueue(q.getName(), q); - } else if (entity instanceof RecordedBinding) { - recoverBinding((RecordedBinding) entity); - } else if (entity instanceof RecordedConsumer) { - final RecordedConsumer c = (RecordedConsumer) entity; - recoverConsumer(c.getConsumerTag(), c); - } + callables.add(Executors.callable(() -> { + for (final E entity : entityList) { + if (entity instanceof RecordedExchange) { + recoverExchange((RecordedExchange)entity); + } else if (entity instanceof RecordedQueue) { + final RecordedQueue q = (RecordedQueue) entity; + recoverQueue(q.getName(), q); + } else if (entity instanceof RecordedBinding) { + recoverBinding((RecordedBinding) entity); + } else if (entity instanceof RecordedConsumer) { + final RecordedConsumer c = (RecordedConsumer) entity; + recoverConsumer(c.getConsumerTag(), c); } } })); From 171116b53b297a96d5fa4254ed7c45a1491b784c Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Fri, 1 Jun 2018 14:52:25 +0000 Subject: [PATCH 0783/2114] [maven-release-plugin] prepare release v4.7.0.RC1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 487314e695..ae8ce1cad2 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.7.0-SNAPSHOT + 4.7.0.RC1 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v4.7.0.RC1 From da7d1f14d46e38e08d794663a6b49c12c7171621 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Fri, 1 Jun 2018 14:52:30 +0000 Subject: [PATCH 0784/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index ae8ce1cad2..487314e695 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.7.0.RC1 + 4.7.0-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v4.7.0.RC1 + HEAD From 8c18b326c11aa2adcb75462f649ba221a0e2add5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 1 Jun 2018 17:03:40 +0200 Subject: [PATCH 0785/2114] Set release version to 4.7.0.RC1 --- release-versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-versions.txt b/release-versions.txt index 5dc8075f18..94ba8c6ae0 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="4.7.0.RC1" +RELEASE_VERSION="4.7.0.RC2" DEVELOPMENT_VERSION="4.7.0-SNAPSHOT" From b173c45d9fa267866b5e3f9cc16c7537db9839cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Turek?= Date: Sat, 2 Jun 2018 10:28:59 +0200 Subject: [PATCH 0786/2114] #354 | add unit tests for publishing acks, nacks and unrouted --- .../client/test/MetricsCollectorTest.java | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java b/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java index d6b5095ed0..2afe01ed37 100644 --- a/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java +++ b/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java @@ -147,6 +147,66 @@ public void basicGetAndAck() { metrics.cleanStaleState(); assertThat(failedToPublishMessages(metrics), is(2L)); assertThat(publishedMessages(metrics), is(2L)); + + long anyDeliveryTag = 123L; + metrics.basicNack(channel, anyDeliveryTag); + } + + + @Test public void publishingAcknowledgements() { + long anyDeliveryTag = 123L; + AbstractMetricsCollector metrics = factory.create(); + Channel channel = mock(Channel.class); + // begins with no messages acknowledged + assertThat(publishAck(metrics), is(0)); + // first acknowledgement gets tracked + metrics.basicPublishAck(channel, anyDeliveryTag, false); + assertThat(publishAck(metrics), is(1)); + // second acknowledgement gets tracked + metrics.basicPublishAck(channel, anyDeliveryTag, false); + assertThat(publishAck(metrics), is(2)); + // multiple deliveries aren't tracked + metrics.basicPublishAck(channel, anyDeliveryTag, true); + assertThat(publishAck(metrics), is(2)); + // cleaning stale state doesn't affect the metric + metrics.cleanStaleState(); + assertThat(publishAck(metrics), is(2)); + } + + @Test public void publishingNotAcknowledgements() { + long anyDeliveryTag = 123L; + AbstractMetricsCollector metrics = factory.create(); + Channel channel = mock(Channel.class); + // begins with no messages not-acknowledged + assertThat(publishNack(metrics), is(0)); + // first not-acknowledgement gets tracked + metrics.basicPublishNack(channel, anyDeliveryTag, false); + assertThat(publishNack(metrics), is(1)); + // second not-acknowledgement gets tracked + metrics.basicPublishNack(channel, anyDeliveryTag, false); + assertThat(publishNack(metrics), is(2)); + // multiple deliveries aren't tracked + metrics.basicPublishNack(channel, anyDeliveryTag, true); + assertThat(publishNack(metrics), is(2)); + // cleaning stale state doesn't affect the metric + metrics.cleanStaleState(); + assertThat(publishNack(metrics), is(2)); + } + + @Test public void publishingUnrouted() { + AbstractMetricsCollector metrics = factory.create(); + Channel channel = mock(Channel.class); + // begins with no messages not-acknowledged + assertThat(publishUnrouted(metrics), is(0)); + // first unrouted gets tracked + metrics.basicPublishUnrouted(channel); + assertThat(publishUnrouted(metrics), is(1)); + // second unrouted gets tracked + metrics.basicPublishUnrouted(channel); + assertThat(publishUnrouted(metrics), is(2)); + // cleaning stale state doesn't affect the metric + metrics.cleanStaleState(); + assertThat(publishUnrouted(metrics), is(2)); } @Test public void cleanStaleState() { @@ -189,6 +249,31 @@ public void basicGetAndAck() { assertThat(channels(metrics), is(1L)); } + + long publishAck(MetricsCollector metrics) { + if (metrics instanceof StandardMetricsCollector) { + return ((StandardMetricsCollector) metrics).getPublishAcknowledgedMessages().getCount(); + } else { + return (long) ((MicrometerMetricsCollector) metrics).getAckedPublishedMessages().count(); + } + } + + long publishNack(MetricsCollector metrics) { + if (metrics instanceof StandardMetricsCollector) { + return ((StandardMetricsCollector) metrics).getPublishNotAcknowledgedMessages().getCount(); + } else { + return (long) ((MicrometerMetricsCollector) metrics).getNackedPublishedMessages().count(); + } + } + + long publishUnrouted(MetricsCollector metrics) { + if (metrics instanceof StandardMetricsCollector) { + return ((StandardMetricsCollector) metrics).getPublishUnroutedMessages().getCount(); + } else { + return (long) ((MicrometerMetricsCollector) metrics).getUnroutedPublishedMessages().count(); + } + } + long publishedMessages(MetricsCollector metrics) { if (metrics instanceof StandardMetricsCollector) { return ((StandardMetricsCollector) metrics).getPublishedMessages().getCount(); From aae9e7be811548be13fd66347bb593df926dbec6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Turek?= Date: Sat, 2 Jun 2018 13:05:12 +0200 Subject: [PATCH 0787/2114] #354 | compare to longs rather than ints --- .../client/test/MetricsCollectorTest.java | 31 +++++++++---------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java b/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java index 2afe01ed37..e07628149a 100644 --- a/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java +++ b/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java @@ -147,9 +147,6 @@ public void basicGetAndAck() { metrics.cleanStaleState(); assertThat(failedToPublishMessages(metrics), is(2L)); assertThat(publishedMessages(metrics), is(2L)); - - long anyDeliveryTag = 123L; - metrics.basicNack(channel, anyDeliveryTag); } @@ -158,19 +155,19 @@ public void basicGetAndAck() { AbstractMetricsCollector metrics = factory.create(); Channel channel = mock(Channel.class); // begins with no messages acknowledged - assertThat(publishAck(metrics), is(0)); + assertThat(publishAck(metrics), is(0L)); // first acknowledgement gets tracked metrics.basicPublishAck(channel, anyDeliveryTag, false); - assertThat(publishAck(metrics), is(1)); + assertThat(publishAck(metrics), is(1L)); // second acknowledgement gets tracked metrics.basicPublishAck(channel, anyDeliveryTag, false); - assertThat(publishAck(metrics), is(2)); + assertThat(publishAck(metrics), is(2L)); // multiple deliveries aren't tracked metrics.basicPublishAck(channel, anyDeliveryTag, true); - assertThat(publishAck(metrics), is(2)); + assertThat(publishAck(metrics), is(2L)); // cleaning stale state doesn't affect the metric metrics.cleanStaleState(); - assertThat(publishAck(metrics), is(2)); + assertThat(publishAck(metrics), is(2L)); } @Test public void publishingNotAcknowledgements() { @@ -178,35 +175,35 @@ public void basicGetAndAck() { AbstractMetricsCollector metrics = factory.create(); Channel channel = mock(Channel.class); // begins with no messages not-acknowledged - assertThat(publishNack(metrics), is(0)); + assertThat(publishNack(metrics), is(0L)); // first not-acknowledgement gets tracked metrics.basicPublishNack(channel, anyDeliveryTag, false); - assertThat(publishNack(metrics), is(1)); + assertThat(publishNack(metrics), is(1L)); // second not-acknowledgement gets tracked metrics.basicPublishNack(channel, anyDeliveryTag, false); - assertThat(publishNack(metrics), is(2)); + assertThat(publishNack(metrics), is(2L)); // multiple deliveries aren't tracked metrics.basicPublishNack(channel, anyDeliveryTag, true); - assertThat(publishNack(metrics), is(2)); + assertThat(publishNack(metrics), is(2L)); // cleaning stale state doesn't affect the metric metrics.cleanStaleState(); - assertThat(publishNack(metrics), is(2)); + assertThat(publishNack(metrics), is(2L)); } @Test public void publishingUnrouted() { AbstractMetricsCollector metrics = factory.create(); Channel channel = mock(Channel.class); // begins with no messages not-acknowledged - assertThat(publishUnrouted(metrics), is(0)); + assertThat(publishUnrouted(metrics), is(0L)); // first unrouted gets tracked metrics.basicPublishUnrouted(channel); - assertThat(publishUnrouted(metrics), is(1)); + assertThat(publishUnrouted(metrics), is(1L)); // second unrouted gets tracked metrics.basicPublishUnrouted(channel); - assertThat(publishUnrouted(metrics), is(2)); + assertThat(publishUnrouted(metrics), is(2L)); // cleaning stale state doesn't affect the metric metrics.cleanStaleState(); - assertThat(publishUnrouted(metrics), is(2)); + assertThat(publishUnrouted(metrics), is(2L)); } @Test public void cleanStaleState() { From c3ac0113d8d42d589f91493bf8a432a38007d87c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Turek?= Date: Sat, 2 Jun 2018 13:05:40 +0200 Subject: [PATCH 0788/2114] #354 | remove unnecessary newline --- src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java b/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java index e07628149a..74f85ac668 100644 --- a/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java +++ b/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java @@ -149,7 +149,6 @@ public void basicGetAndAck() { assertThat(publishedMessages(metrics), is(2L)); } - @Test public void publishingAcknowledgements() { long anyDeliveryTag = 123L; AbstractMetricsCollector metrics = factory.create(); From 5998ffaa6ceb72c6328d1e3c85970c66d44ad7c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Turek?= Date: Sat, 2 Jun 2018 15:25:21 +0200 Subject: [PATCH 0789/2114] #354 | Implement integration tests --- .../client/test/functional/Metrics.java | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java index 70400627f8..27a77c42a4 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java @@ -139,6 +139,49 @@ protected void releaseResources() throws IOException { } } + @Test public void metricsPublisherUnrouted() throws IOException, TimeoutException, InterruptedException { + StandardMetricsCollector metrics = new StandardMetricsCollector(); + connectionFactory.setMetricsCollector(metrics); + Connection connection = null; + try { + connection = connectionFactory.newConnection(); + Channel channel = connection.createChannel(); + channel.confirmSelect(); + assertThat(metrics.getPublishUnroutedMessages(), is(1L)); + // when + channel.basicPublish( + "any-exchange", + "any-routing-key", + MessageProperties.MINIMAL_BASIC, + "any-message".getBytes() + ); + channel.waitForConfirms(30 * 60 * 1000); + // then + assertThat(metrics.getPublishUnroutedMessages(), is(1L)); + } finally { + safeClose(connection); + } + } + + @Test public void metricsPublisherAck() throws IOException, TimeoutException, InterruptedException { + StandardMetricsCollector metrics = new StandardMetricsCollector(); + connectionFactory.setMetricsCollector(metrics); + Connection connection = null; + try { + connection = connectionFactory.newConnection(); + Channel channel = connection.createChannel(); + channel.confirmSelect(); + assertThat(metrics.getPublishAcknowledgedMessages(), is(0L)); + channel.basicConsume(QUEUE, false, new MultipleAckConsumer(channel, false)); + // when + sendMessage(channel); + channel.waitForConfirms(30 * 60 * 1000); + // then + assertThat(metrics.getPublishAcknowledgedMessages(), is(1L)); + } finally { + safeClose(connection); + } + } @Test public void metricsAck() throws IOException, TimeoutException { StandardMetricsCollector metrics = new StandardMetricsCollector(); From 1f1821f067bdd228456e5629eb7b0aeafea984b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Turek?= Date: Sat, 2 Jun 2018 15:32:06 +0200 Subject: [PATCH 0790/2114] #354 | Add missing import --- src/test/java/com/rabbitmq/client/test/functional/Metrics.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java index 27a77c42a4..dd5a37d0a2 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java @@ -22,6 +22,7 @@ import com.rabbitmq.client.DefaultConsumer; import com.rabbitmq.client.Envelope; import com.rabbitmq.client.GetResponse; +import com.rabbitmq.client.MessageProperties; import com.rabbitmq.client.Recoverable; import com.rabbitmq.client.RecoveryListener; import com.rabbitmq.client.impl.StandardMetricsCollector; From 3f546aab4811b6c10edf304b7397f93dad6a2f02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Turek?= Date: Sat, 2 Jun 2018 16:24:44 +0200 Subject: [PATCH 0791/2114] #354 | Assert counts --- .../java/com/rabbitmq/client/test/functional/Metrics.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java index dd5a37d0a2..26f0a5aafc 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java @@ -148,7 +148,7 @@ protected void releaseResources() throws IOException { connection = connectionFactory.newConnection(); Channel channel = connection.createChannel(); channel.confirmSelect(); - assertThat(metrics.getPublishUnroutedMessages(), is(1L)); + assertThat(metrics.getPublishUnroutedMessages().getCount(), is(1L)); // when channel.basicPublish( "any-exchange", @@ -158,7 +158,7 @@ protected void releaseResources() throws IOException { ); channel.waitForConfirms(30 * 60 * 1000); // then - assertThat(metrics.getPublishUnroutedMessages(), is(1L)); + assertThat(metrics.getPublishUnroutedMessages().getCount(), is(1L)); } finally { safeClose(connection); } @@ -172,13 +172,13 @@ protected void releaseResources() throws IOException { connection = connectionFactory.newConnection(); Channel channel = connection.createChannel(); channel.confirmSelect(); - assertThat(metrics.getPublishAcknowledgedMessages(), is(0L)); + assertThat(metrics.getPublishAcknowledgedMessages().getCount(), is(0L)); channel.basicConsume(QUEUE, false, new MultipleAckConsumer(channel, false)); // when sendMessage(channel); channel.waitForConfirms(30 * 60 * 1000); // then - assertThat(metrics.getPublishAcknowledgedMessages(), is(1L)); + assertThat(metrics.getPublishAcknowledgedMessages().getCount(), is(1L)); } finally { safeClose(connection); } From c45ad735495d4cce992b052fbf7098a6666c5f62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Turek?= Date: Sun, 3 Jun 2018 01:13:08 +0200 Subject: [PATCH 0792/2114] #354 | Declare the exchange and wait until unrouted --- .../java/com/rabbitmq/client/test/functional/Metrics.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java index 26f0a5aafc..06c73c026a 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java @@ -150,14 +150,18 @@ protected void releaseResources() throws IOException { channel.confirmSelect(); assertThat(metrics.getPublishUnroutedMessages().getCount(), is(1L)); // when + channel.exchangeDeclare("any-exchange", "direct"); channel.basicPublish( "any-exchange", "any-routing-key", MessageProperties.MINIMAL_BASIC, "any-message".getBytes() ); - channel.waitForConfirms(30 * 60 * 1000); // then + waitAtMost(timeout()).until( + () -> metrics.getPublishUnroutedMessages().getCount(), + equalTo(1L) + ); assertThat(metrics.getPublishUnroutedMessages().getCount(), is(1L)); } finally { safeClose(connection); From d85920516c595cb7e97e32d87b65223288778948 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Turek?= Date: Sun, 3 Jun 2018 10:10:35 +0200 Subject: [PATCH 0793/2114] #354 | Message has to be mandatory for basic.return to be sent back --- src/test/java/com/rabbitmq/client/test/functional/Metrics.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java index 06c73c026a..4c8d6e485d 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java @@ -154,6 +154,7 @@ protected void releaseResources() throws IOException { channel.basicPublish( "any-exchange", "any-routing-key", + /* basic.return will be sent back only if the message is mandatory */ true, MessageProperties.MINIMAL_BASIC, "any-message".getBytes() ); @@ -162,7 +163,6 @@ protected void releaseResources() throws IOException { () -> metrics.getPublishUnroutedMessages().getCount(), equalTo(1L) ); - assertThat(metrics.getPublishUnroutedMessages().getCount(), is(1L)); } finally { safeClose(connection); } From b3d2733c13c30938a66143a249156705d5e3cafd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Turek?= Date: Sun, 3 Jun 2018 11:38:36 +0200 Subject: [PATCH 0794/2114] #354 | Fix pre-condition --- .../com/rabbitmq/client/test/functional/Metrics.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java index 4c8d6e485d..783d9e197f 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java @@ -140,7 +140,7 @@ protected void releaseResources() throws IOException { } } - @Test public void metricsPublisherUnrouted() throws IOException, TimeoutException, InterruptedException { + @Test public void metricsPublisherUnrouted() throws IOException, TimeoutException { StandardMetricsCollector metrics = new StandardMetricsCollector(); connectionFactory.setMetricsCollector(metrics); Connection connection = null; @@ -148,12 +148,11 @@ protected void releaseResources() throws IOException { connection = connectionFactory.newConnection(); Channel channel = connection.createChannel(); channel.confirmSelect(); - assertThat(metrics.getPublishUnroutedMessages().getCount(), is(1L)); + assertThat(metrics.getPublishUnroutedMessages().getCount(), is(0L)); // when - channel.exchangeDeclare("any-exchange", "direct"); channel.basicPublish( - "any-exchange", - "any-routing-key", + "amq.direct", + "any-unroutable-routing-key", /* basic.return will be sent back only if the message is mandatory */ true, MessageProperties.MINIMAL_BASIC, "any-message".getBytes() From 524988e412b76688dccc671b307e35152a8329d7 Mon Sep 17 00:00:00 2001 From: igor_bolotin Date: Fri, 27 Apr 2018 21:57:05 -0700 Subject: [PATCH 0795/2114] Throw an exception instead of trying to transmit a header frame that exceeds max frame size --- .../com/rabbitmq/client/impl/AMQCommand.java | 13 +++-- .../client/test/functional/FrameMax.java | 47 +++++++++++++++++++ 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/AMQCommand.java b/src/main/java/com/rabbitmq/client/impl/AMQCommand.java index 5543ee7c1f..e4457076c9 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQCommand.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQCommand.java @@ -101,17 +101,22 @@ public void transmit(AMQChannel channel) throws IOException { synchronized (assembler) { Method m = this.assembler.getMethod(); - connection.writeFrame(m.toFrame(channelNumber)); if (m.hasContent()) { byte[] body = this.assembler.getContentBody(); - connection.writeFrame(this.assembler.getContentHeader() - .toFrame(channelNumber, body.length)); + Frame headerFrame = this.assembler.getContentHeader().toFrame(channelNumber, body.length); int frameMax = connection.getFrameMax(); int bodyPayloadMax = (frameMax == 0) ? body.length : frameMax - EMPTY_FRAME_SIZE; + if (headerFrame.size() > frameMax) { + throw new IllegalArgumentException("Content headers exceeded max frame size: " + + headerFrame.size() + " > " + frameMax); + } + connection.writeFrame(m.toFrame(channelNumber)); + connection.writeFrame(headerFrame); + for (int offset = 0; offset < body.length; offset += bodyPayloadMax) { int remaining = body.length - offset; @@ -121,6 +126,8 @@ public void transmit(AMQChannel channel) throws IOException { offset, fragmentLength); connection.writeFrame(frame); } + } else { + connection.writeFrame(m.toFrame(channelNumber)); } } diff --git a/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java b/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java index 7e1019c4cb..07d7eb9d9f 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java +++ b/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java @@ -17,11 +17,16 @@ package com.rabbitmq.client.test.functional; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; import java.io.IOException; import java.net.Socket; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeoutException; @@ -35,6 +40,7 @@ import com.rabbitmq.client.GetResponse; import com.rabbitmq.client.impl.AMQCommand; import com.rabbitmq.client.impl.AMQConnection; +import com.rabbitmq.client.impl.ContentHeaderPropertyWriter; import com.rabbitmq.client.impl.Frame; import com.rabbitmq.client.impl.FrameHandler; import com.rabbitmq.client.impl.LongStringHelper; @@ -104,6 +110,47 @@ public FrameMax() { expectError(AMQP.FRAME_ERROR); } + /* client should throw exception if headers exceed negotiated + * frame size */ + @Test public void rejectHeadersExceedingFrameMax() + throws IOException, TimeoutException { + declareTransientTopicExchange("x"); + String queueName = channel.queueDeclare().getQueue(); + channel.queueBind(queueName, "x", "foobar"); + + Map headers = new HashMap(); + String headerName = "x-huge-header"; + + // create headers with zero-length value to calculate maximum header value size before exceeding frame_max + headers.put(headerName, LongStringHelper.asLongString(new byte[0])); + AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder().headers(headers).build(); + Frame minimalHeaderFrame = properties.toFrame(0, 0); + int maxHeaderValueSize = FRAME_MAX - minimalHeaderFrame.size(); + + // create headers with maximum header value size (frame size equals frame_max) + headers.put(headerName, LongStringHelper.asLongString(new byte[maxHeaderValueSize])); + properties = new AMQP.BasicProperties.Builder().headers(headers).build(); + + basicPublishVolatile(new byte[100], "x", "foobar", properties); + assertDelivered(queueName, 1); + + // create headers with frame size exceeding frame_max by 1 + headers.put(headerName, LongStringHelper.asLongString(new byte[maxHeaderValueSize + 1])); + properties = new AMQP.BasicProperties.Builder().headers(headers).build(); + try { + basicPublishVolatile(new byte[100], "x", "foobar", properties); + fail("expected rejectHeadersExceedingFrameMax to throw"); + } catch (IllegalArgumentException iae) { + assertTrue(iae.getMessage().startsWith("Content headers exceeded max frame size")); + // check that the channel is still operational + assertDelivered(queueName, 0); + } + + // cleanup + deleteExchange("x"); + } + + /* ConnectionFactory that uses MyFrameHandler rather than * SocketFrameHandler. */ private static class MyConnectionFactory extends ConnectionFactory { From dd30f7ce0fdc1b87e8e80f72e60970c7d725b04e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 4 Jun 2018 10:29:00 +0200 Subject: [PATCH 0796/2114] Set release version to 5.3.0.RC1 --- pom.xml | 2 +- release-versions.txt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index cffa40bab2..57862b4f3f 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.2.1-SNAPSHOT + 5.3.0-SNAPSHOT jar RabbitMQ Java Client diff --git a/release-versions.txt b/release-versions.txt index d91f0a9eb3..86b93080e4 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="5.2.1.RC1" -DEVELOPMENT_VERSION="5.2.1-SNAPSHOT" +RELEASE_VERSION="5.3.0.RC1" +DEVELOPMENT_VERSION="5.3.0-SNAPSHOT" From b68c70d10056f6c903c4a92a45d4127b4d06f57d Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Mon, 4 Jun 2018 11:37:44 +0000 Subject: [PATCH 0797/2114] [maven-release-plugin] prepare release v5.3.0.RC1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 57862b4f3f..42d33b8f9c 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.3.0-SNAPSHOT + 5.3.0.RC1 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v5.3.0.RC1 From c3b0d6a7daf5d7d8de31e9a65d9ff90758f5af8a Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Mon, 4 Jun 2018 11:37:50 +0000 Subject: [PATCH 0798/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 42d33b8f9c..57862b4f3f 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.3.0.RC1 + 5.3.0-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v5.3.0.RC1 + HEAD From 152f4b72979e9eae91978eea314728917cf0ad5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 4 Jun 2018 13:57:48 +0200 Subject: [PATCH 0799/2114] Set release version to 6.0.0.M1 --- pom.xml | 2 +- release-versions.txt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 57862b4f3f..d437c401bd 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.3.0-SNAPSHOT + 6.0.0-SNAPSHOT jar RabbitMQ Java Client diff --git a/release-versions.txt b/release-versions.txt index 86b93080e4..45e63327f8 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="5.3.0.RC1" -DEVELOPMENT_VERSION="5.3.0-SNAPSHOT" +RELEASE_VERSION="6.0.0.M1" +DEVELOPMENT_VERSION="6.0.0-SNAPSHOT" From 52eb8830a8c28b08782b26c1d43ed3c3641ecfa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 5 Jun 2018 09:35:36 +0200 Subject: [PATCH 0800/2114] Add dependency coordinates for 4.x and 5.x series Remove mention of 3.6.x. --- README.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 43fe167209..53f312e343 100644 --- a/README.md +++ b/README.md @@ -14,10 +14,10 @@ a [Maven repository with milestone releases](https://bintray.com/rabbitmq/maven- [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.rabbitmq/amqp-client/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.rabbitmq/amqp-client) -#### 4.x+ Series +#### 5.x Series -Starting with `4.0`, this client releases are independent from RabbitMQ server releases. -These versions can still be used with RabbitMQ server `3.x`. +This client releases are independent from RabbitMQ server releases and can be used with RabbitMQ server `3.x`. +They require Java 8 or more. ``` xml @@ -33,22 +33,23 @@ These versions can still be used with RabbitMQ server `3.x`. compile 'com.rabbitmq:amqp-client:5.2.0' ``` -#### 3.6.x Series +#### 4.x Series -`3.6.x` series are released in concert with RabbitMQ server for historical reasons. +This client releases are independent from RabbitMQ server releases and can be used with RabbitMQ server `3.x`. +They require Java 6 or more. ``` xml com.rabbitmq amqp-client - 3.6.6 + 4.6.0 ``` ### Gradle ``` groovy -compile 'com.rabbitmq:amqp-client:3.6.6' +compile 'com.rabbitmq:amqp-client:4.6.0' ``` From 1f97ed4e70429ab5219e6be4bf205bda93c5e3f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 8 Jun 2018 13:55:08 +0200 Subject: [PATCH 0801/2114] Phrasing in readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 53f312e343..47e7ae1d06 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ a [Maven repository with milestone releases](https://bintray.com/rabbitmq/maven- #### 5.x Series This client releases are independent from RabbitMQ server releases and can be used with RabbitMQ server `3.x`. -They require Java 8 or more. +They require Java 8 or higher. ``` xml @@ -36,7 +36,7 @@ compile 'com.rabbitmq:amqp-client:5.2.0' #### 4.x Series This client releases are independent from RabbitMQ server releases and can be used with RabbitMQ server `3.x`. -They require Java 6 or more. +They require Java 6 or higher. ``` xml From 2554f228d022f6dd1ce0edc55277eb6c45bfa36c Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Fri, 8 Jun 2018 12:02:07 +0000 Subject: [PATCH 0802/2114] [maven-release-plugin] prepare release v6.0.0.M1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index d437c401bd..3a658e634f 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 6.0.0-SNAPSHOT + 6.0.0.M1 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v6.0.0.M1 From f4d0f765503db9e38307209d4f711923222842de Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Fri, 8 Jun 2018 12:02:12 +0000 Subject: [PATCH 0803/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 3a658e634f..d437c401bd 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 6.0.0.M1 + 6.0.0-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v6.0.0.M1 + HEAD From 14ccf2f81047af1d3c9e28cf75322d7f70d3ad60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 8 Jun 2018 14:50:43 +0200 Subject: [PATCH 0804/2114] Set release version to 6.0.0.M2 --- release-versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-versions.txt b/release-versions.txt index 45e63327f8..222a336b2d 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="6.0.0.M1" +RELEASE_VERSION="6.0.0.M2" DEVELOPMENT_VERSION="6.0.0-SNAPSHOT" From 00232a321c2a603f7dd502df55f183a37eebd917 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 8 Jun 2018 14:52:56 +0200 Subject: [PATCH 0805/2114] Bump Maven version to 3.5.3 in wrapper --- .mvn/wrapper/maven-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index a447c9fa81..b573bb50d5 100755 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -1 +1 @@ -distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.2/apache-maven-3.5.2-bin.zip \ No newline at end of file +distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.3/apache-maven-3.5.3-bin.zip From 7b231c43e2454abe6f16797c425c4be407de7470 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 14 Jun 2018 11:39:49 +0200 Subject: [PATCH 0806/2114] Set release version to 4.7.0 --- release-versions.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release-versions.txt b/release-versions.txt index 94ba8c6ae0..746070d45e 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="4.7.0.RC2" -DEVELOPMENT_VERSION="4.7.0-SNAPSHOT" +RELEASE_VERSION="4.7.0" +DEVELOPMENT_VERSION="4.7.1-SNAPSHOT" From b0fae4370d800067dbce57f557afba3a6c13bf4f Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Thu, 14 Jun 2018 09:42:01 +0000 Subject: [PATCH 0807/2114] [maven-release-plugin] prepare release v4.7.0 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 487314e695..eae874e775 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.7.0-SNAPSHOT + 4.7.0 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v4.7.0 From 7b8af0bfefc74274eb13b0c89a265aa9184c924b Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Thu, 14 Jun 2018 09:42:09 +0000 Subject: [PATCH 0808/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index eae874e775..9acb11b371 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.7.0 + 4.7.1-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v4.7.0 + HEAD From 1a552cb339c8c85f40ebafab04e70a0f41dd4f34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 14 Jun 2018 11:59:27 +0200 Subject: [PATCH 0809/2114] Set release version to 4.8.0.RC1 --- pom.xml | 2 +- release-versions.txt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 9acb11b371..bd33233a45 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 4.7.1-SNAPSHOT + 4.8.0-SNAPSHOT jar RabbitMQ Java Client diff --git a/release-versions.txt b/release-versions.txt index 746070d45e..456b31c5f8 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="4.7.0" -DEVELOPMENT_VERSION="4.7.1-SNAPSHOT" +RELEASE_VERSION="4.8.0.RC1" +DEVELOPMENT_VERSION="4.8.0-SNAPSHOT" From 01d84e8ff1d2ac3cf80a8b9f7242c51688e9ed14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 14 Jun 2018 12:02:13 +0200 Subject: [PATCH 0810/2114] Set release version to 5.3.0 --- release-versions.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release-versions.txt b/release-versions.txt index 86b93080e4..c3a37cf7a0 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="5.3.0.RC1" -DEVELOPMENT_VERSION="5.3.0-SNAPSHOT" +RELEASE_VERSION="5.3.0" +DEVELOPMENT_VERSION="5.3.1-SNAPSHOT" From 9b0b839073a4a2d5810840f08ef226cecdc166c8 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Thu, 14 Jun 2018 11:46:08 +0000 Subject: [PATCH 0811/2114] [maven-release-plugin] prepare release v5.3.0 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 57862b4f3f..9320a079b4 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.3.0-SNAPSHOT + 5.3.0 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v5.3.0 From 9325c886d2ad5b9b19c451f4974bd036df32f82f Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Thu, 14 Jun 2018 11:46:13 +0000 Subject: [PATCH 0812/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 9320a079b4..107be3f9fe 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.3.0 + 5.3.1-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v5.3.0 + HEAD From 3989149659aae62595b8fa35b6f975ed0bf2e073 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 14 Jun 2018 13:58:37 +0200 Subject: [PATCH 0813/2114] Set release version to 5.4.0.RC1 --- pom.xml | 2 +- release-versions.txt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 107be3f9fe..b26766262b 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.3.1-SNAPSHOT + 5.4.0-SNAPSHOT jar RabbitMQ Java Client diff --git a/release-versions.txt b/release-versions.txt index c3a37cf7a0..3b0c3ec1b0 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="5.3.0" -DEVELOPMENT_VERSION="5.3.1-SNAPSHOT" +RELEASE_VERSION="5.4.0.RC1" +DEVELOPMENT_VERSION="5.4.0-SNAPSHOT" From 668a3f7eef524cfd7bb53f40d73882a6d577a9a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 14 Jun 2018 14:11:35 +0200 Subject: [PATCH 0814/2114] Set release version to 5.4.0.RC1 --- pom.xml | 2 +- release-versions.txt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index d437c401bd..b26766262b 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 6.0.0-SNAPSHOT + 5.4.0-SNAPSHOT jar RabbitMQ Java Client diff --git a/release-versions.txt b/release-versions.txt index 222a336b2d..3b0c3ec1b0 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="6.0.0.M2" -DEVELOPMENT_VERSION="6.0.0-SNAPSHOT" +RELEASE_VERSION="5.4.0.RC1" +DEVELOPMENT_VERSION="5.4.0-SNAPSHOT" From 6ab417e9a1732434954afc8146e23cdea81eac6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 14 Jun 2018 14:13:23 +0200 Subject: [PATCH 0815/2114] Set release version to 6.0.0.M2 --- pom.xml | 2 +- release-versions.txt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index b26766262b..d437c401bd 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.4.0-SNAPSHOT + 6.0.0-SNAPSHOT jar RabbitMQ Java Client diff --git a/release-versions.txt b/release-versions.txt index 3b0c3ec1b0..222a336b2d 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="5.4.0.RC1" -DEVELOPMENT_VERSION="5.4.0-SNAPSHOT" +RELEASE_VERSION="6.0.0.M2" +DEVELOPMENT_VERSION="6.0.0-SNAPSHOT" From b55bd20a1a236fc2d1ea9369b579770fa0237615 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 14 Jun 2018 15:22:39 +0200 Subject: [PATCH 0816/2114] Set versions to 5.3.0 and 4.7.0 in readme --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 47e7ae1d06..bd1c9311a0 100644 --- a/README.md +++ b/README.md @@ -23,14 +23,14 @@ They require Java 8 or higher. com.rabbitmq amqp-client - 5.2.0 + 5.3.0 ``` ### Gradle ``` groovy -compile 'com.rabbitmq:amqp-client:5.2.0' +compile 'com.rabbitmq:amqp-client:5.3.0' ``` #### 4.x Series @@ -42,14 +42,14 @@ They require Java 6 or higher. com.rabbitmq amqp-client - 4.6.0 + 4.7.0 ``` ### Gradle ``` groovy -compile 'com.rabbitmq:amqp-client:4.6.0' +compile 'com.rabbitmq:amqp-client:4.7.0' ``` From d3ff8efb8f0e555194a971c35fd56c14fb28ba2a Mon Sep 17 00:00:00 2001 From: John Lilley Date: Wed, 27 Jun 2018 12:07:01 -0600 Subject: [PATCH 0817/2114] Issue 375: RpcClient potential memory leak fix. --- .../java/com/rabbitmq/client/RpcClient.java | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/RpcClient.java b/src/main/java/com/rabbitmq/client/RpcClient.java index 928d819585..230c2022dc 100644 --- a/src/main/java/com/rabbitmq/client/RpcClient.java +++ b/src/main/java/com/rabbitmq/client/RpcClient.java @@ -191,10 +191,11 @@ public void handleDelivery(String consumerTag, synchronized (_continuationMap) { String replyId = properties.getCorrelationId(); BlockingCell blocker =_continuationMap.remove(replyId); - if (blocker == null) { - throw new IllegalStateException("No outstanding request for correlation ID " + replyId); - } - blocker.set(new Response(consumerTag, envelope, properties, body)); + if (blocker != null) { + blocker.set(new Response(consumerTag, envelope, properties, body)); + } else { + // Not an error. Entry will have been removed if request timed out. + } } } }; @@ -217,15 +218,23 @@ public Response doCall(AMQP.BasicProperties props, byte[] message, int timeout) throws IOException, ShutdownSignalException, TimeoutException { checkConsumer(); BlockingCell k = new BlockingCell(); + String replyId; synchronized (_continuationMap) { _correlationId++; - String replyId = "" + _correlationId; + replyId = "" + _correlationId; props = ((props==null) ? new AMQP.BasicProperties.Builder() : props.builder()) .correlationId(replyId).replyTo(_replyTo).build(); _continuationMap.put(replyId, k); } publish(props, message); - Object reply = k.uninterruptibleGet(timeout); + Object reply; + try { + reply = k.uninterruptibleGet(timeout); + } catch (TimeoutException ex) { + // Avoid potential leak. This entry is no longer needed by caller. + _continuationMap.remove(replyId); + throw ex; + } if (reply instanceof ShutdownSignalException) { ShutdownSignalException sig = (ShutdownSignalException) reply; ShutdownSignalException wrapper = From e162936051567f00cd011a50347f76ab93aa0c9a Mon Sep 17 00:00:00 2001 From: John Lilley Date: Wed, 27 Jun 2018 12:22:58 -0600 Subject: [PATCH 0818/2114] Fix tabs->spaces in previous change --- .../java/com/rabbitmq/client/RpcClient.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/RpcClient.java b/src/main/java/com/rabbitmq/client/RpcClient.java index 230c2022dc..9323b2e7db 100644 --- a/src/main/java/com/rabbitmq/client/RpcClient.java +++ b/src/main/java/com/rabbitmq/client/RpcClient.java @@ -192,10 +192,10 @@ public void handleDelivery(String consumerTag, String replyId = properties.getCorrelationId(); BlockingCell blocker =_continuationMap.remove(replyId); if (blocker != null) { - blocker.set(new Response(consumerTag, envelope, properties, body)); + blocker.set(new Response(consumerTag, envelope, properties, body)); } else { - // Not an error. Entry will have been removed if request timed out. - } + // Not an error. Entry will have been removed if request timed out. + } } } }; @@ -218,7 +218,7 @@ public Response doCall(AMQP.BasicProperties props, byte[] message, int timeout) throws IOException, ShutdownSignalException, TimeoutException { checkConsumer(); BlockingCell k = new BlockingCell(); - String replyId; + String replyId; synchronized (_continuationMap) { _correlationId++; replyId = "" + _correlationId; @@ -227,14 +227,14 @@ public Response doCall(AMQP.BasicProperties props, byte[] message, int timeout) _continuationMap.put(replyId, k); } publish(props, message); - Object reply; + Object reply; try { - reply = k.uninterruptibleGet(timeout); - } catch (TimeoutException ex) { - // Avoid potential leak. This entry is no longer needed by caller. - _continuationMap.remove(replyId); - throw ex; - } + reply = k.uninterruptibleGet(timeout); + } catch (TimeoutException ex) { + // Avoid potential leak. This entry is no longer needed by caller. + _continuationMap.remove(replyId); + throw ex; + } if (reply instanceof ShutdownSignalException) { ShutdownSignalException sig = (ShutdownSignalException) reply; ShutdownSignalException wrapper = From 0b7a46daf27d995642deb99b0515c53b5c9b71f9 Mon Sep 17 00:00:00 2001 From: John Lilley Date: Wed, 27 Jun 2018 12:07:01 -0600 Subject: [PATCH 0819/2114] Issue 375: RpcClient potential memory leak fix. (cherry picked from commit d3ff8efb8f0e555194a971c35fd56c14fb28ba2a) --- .../java/com/rabbitmq/client/RpcClient.java | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/RpcClient.java b/src/main/java/com/rabbitmq/client/RpcClient.java index 928d819585..230c2022dc 100644 --- a/src/main/java/com/rabbitmq/client/RpcClient.java +++ b/src/main/java/com/rabbitmq/client/RpcClient.java @@ -191,10 +191,11 @@ public void handleDelivery(String consumerTag, synchronized (_continuationMap) { String replyId = properties.getCorrelationId(); BlockingCell blocker =_continuationMap.remove(replyId); - if (blocker == null) { - throw new IllegalStateException("No outstanding request for correlation ID " + replyId); - } - blocker.set(new Response(consumerTag, envelope, properties, body)); + if (blocker != null) { + blocker.set(new Response(consumerTag, envelope, properties, body)); + } else { + // Not an error. Entry will have been removed if request timed out. + } } } }; @@ -217,15 +218,23 @@ public Response doCall(AMQP.BasicProperties props, byte[] message, int timeout) throws IOException, ShutdownSignalException, TimeoutException { checkConsumer(); BlockingCell k = new BlockingCell(); + String replyId; synchronized (_continuationMap) { _correlationId++; - String replyId = "" + _correlationId; + replyId = "" + _correlationId; props = ((props==null) ? new AMQP.BasicProperties.Builder() : props.builder()) .correlationId(replyId).replyTo(_replyTo).build(); _continuationMap.put(replyId, k); } publish(props, message); - Object reply = k.uninterruptibleGet(timeout); + Object reply; + try { + reply = k.uninterruptibleGet(timeout); + } catch (TimeoutException ex) { + // Avoid potential leak. This entry is no longer needed by caller. + _continuationMap.remove(replyId); + throw ex; + } if (reply instanceof ShutdownSignalException) { ShutdownSignalException sig = (ShutdownSignalException) reply; ShutdownSignalException wrapper = From 11baba6cba665209d8efaa68ff2a96b5b0c85ef4 Mon Sep 17 00:00:00 2001 From: John Lilley Date: Wed, 27 Jun 2018 12:22:58 -0600 Subject: [PATCH 0820/2114] Fix tabs->spaces in previous change (cherry picked from commit e162936051567f00cd011a50347f76ab93aa0c9a) --- .../java/com/rabbitmq/client/RpcClient.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/RpcClient.java b/src/main/java/com/rabbitmq/client/RpcClient.java index 230c2022dc..9323b2e7db 100644 --- a/src/main/java/com/rabbitmq/client/RpcClient.java +++ b/src/main/java/com/rabbitmq/client/RpcClient.java @@ -192,10 +192,10 @@ public void handleDelivery(String consumerTag, String replyId = properties.getCorrelationId(); BlockingCell blocker =_continuationMap.remove(replyId); if (blocker != null) { - blocker.set(new Response(consumerTag, envelope, properties, body)); + blocker.set(new Response(consumerTag, envelope, properties, body)); } else { - // Not an error. Entry will have been removed if request timed out. - } + // Not an error. Entry will have been removed if request timed out. + } } } }; @@ -218,7 +218,7 @@ public Response doCall(AMQP.BasicProperties props, byte[] message, int timeout) throws IOException, ShutdownSignalException, TimeoutException { checkConsumer(); BlockingCell k = new BlockingCell(); - String replyId; + String replyId; synchronized (_continuationMap) { _correlationId++; replyId = "" + _correlationId; @@ -227,14 +227,14 @@ public Response doCall(AMQP.BasicProperties props, byte[] message, int timeout) _continuationMap.put(replyId, k); } publish(props, message); - Object reply; + Object reply; try { - reply = k.uninterruptibleGet(timeout); - } catch (TimeoutException ex) { - // Avoid potential leak. This entry is no longer needed by caller. - _continuationMap.remove(replyId); - throw ex; - } + reply = k.uninterruptibleGet(timeout); + } catch (TimeoutException ex) { + // Avoid potential leak. This entry is no longer needed by caller. + _continuationMap.remove(replyId); + throw ex; + } if (reply instanceof ShutdownSignalException) { ShutdownSignalException sig = (ShutdownSignalException) reply; ShutdownSignalException wrapper = From 11fdaa9c1f0f4ea102cba49ec9c820b1092e1d61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 28 Jun 2018 09:48:04 +0200 Subject: [PATCH 0821/2114] Log warning when correlation ID isn't found in RpcClient Add a test as well to check the outstanding request map is cleaned after a timeout. References #375 --- src/main/java/com/rabbitmq/client/RpcClient.java | 13 ++++++++++--- src/test/java/com/rabbitmq/client/test/RpcTest.java | 12 ++++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/RpcClient.java b/src/main/java/com/rabbitmq/client/RpcClient.java index 9323b2e7db..cbc8e79035 100644 --- a/src/main/java/com/rabbitmq/client/RpcClient.java +++ b/src/main/java/com/rabbitmq/client/RpcClient.java @@ -33,6 +33,8 @@ import com.rabbitmq.client.impl.ValueReader; import com.rabbitmq.client.impl.ValueWriter; import com.rabbitmq.utility.BlockingCell; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Convenience class which manages simple RPC-style communication. @@ -41,6 +43,9 @@ * and waiting for a response. */ public class RpcClient { + + private static final Logger LOGGER = LoggerFactory.getLogger(RpcClient.class); + /** Channel we are communicating on */ private final Channel _channel; /** Exchange to send requests to */ @@ -191,10 +196,12 @@ public void handleDelivery(String consumerTag, synchronized (_continuationMap) { String replyId = properties.getCorrelationId(); BlockingCell blocker =_continuationMap.remove(replyId); - if (blocker != null) { - blocker.set(new Response(consumerTag, envelope, properties, body)); + if (blocker == null) { + // Entry should have been removed if request timed out, + // log a warning nevertheless. + LOGGER.warn("No outstanding request for correlation ID {}", replyId); } else { - // Not an error. Entry will have been removed if request timed out. + blocker.set(new Response(consumerTag, envelope, properties, body)); } } } diff --git a/src/test/java/com/rabbitmq/client/test/RpcTest.java b/src/test/java/com/rabbitmq/client/test/RpcTest.java index d9ad7e3110..6691361392 100644 --- a/src/test/java/com/rabbitmq/client/test/RpcTest.java +++ b/src/test/java/com/rabbitmq/client/test/RpcTest.java @@ -24,6 +24,7 @@ import java.io.IOException; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.TimeoutException; import static org.junit.Assert.assertEquals; @@ -72,6 +73,17 @@ public void rpc() throws Exception { client.close(); } + @Test public void rpcResponseTimeout() throws Exception { + RpcClient client = new RpcClient(clientChannel, "", queue); + try { + client.doCall(null, "hello".getBytes(), 200); + } catch (TimeoutException e) { + // OK + } + assertEquals(0, client.getContinuationMap().size()); + client.close(); + } + private static class TestRpcServer extends RpcServer { public TestRpcServer(Channel channel, String queueName) throws IOException { From 2b251b019bb845c0bba6ce8a6a53783e63e901a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 25 Jul 2018 14:28:56 +0200 Subject: [PATCH 0822/2114] Add option for connection recovery triggering Fixes #379 --- .../rabbitmq/client/ConnectionFactory.java | 18 +++++++++++ .../client/impl/ConnectionParams.java | 11 +++++++ .../recovery/AutorecoveringConnection.java | 30 ++++++++++++------- 3 files changed, 48 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 51b954e563..c26e03bf58 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -46,6 +46,7 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeoutException; +import java.util.function.Predicate; import javax.net.SocketFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; @@ -177,6 +178,12 @@ public class ConnectionFactory implements Cloneable { */ private int workPoolTimeout = DEFAULT_WORK_POOL_TIMEOUT; + /** + * Condition to trigger automatic connection recovery. + * @since 5.4.0 + */ + private Predicate connectionRecoveryTriggeringCondition; + /** @return the default host to use for connections */ public String getHost() { return host; @@ -1070,6 +1077,7 @@ public ConnectionParams params(ExecutorService consumerWorkServiceExecutor) { result.setChannelShouldCheckRpcResponseType(channelShouldCheckRpcResponseType); result.setWorkPoolTimeout(workPoolTimeout); result.setErrorOnWriteListener(errorOnWriteListener); + result.setConnectionRecoveryTriggeringCondition(connectionRecoveryTriggeringCondition); return result; } @@ -1419,4 +1427,14 @@ public int getWorkPoolTimeout() { public void setErrorOnWriteListener(ErrorOnWriteListener errorOnWriteListener) { this.errorOnWriteListener = errorOnWriteListener; } + + /** + * Allows to decide on automatic connection recovery is triggered. + * Default is for shutdown not initiated by application or missed heartbeat errors. + * @param connectionRecoveryTriggeringCondition + */ + public void setConnectionRecoveryTriggeringCondition(Predicate connectionRecoveryTriggeringCondition) { + this.connectionRecoveryTriggeringCondition = connectionRecoveryTriggeringCondition; + } + } diff --git a/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java b/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java index 08c123bd81..2ad422070f 100644 --- a/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java +++ b/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java @@ -19,11 +19,13 @@ import com.rabbitmq.client.RecoveryDelayHandler; import com.rabbitmq.client.RecoveryDelayHandler.DefaultRecoveryDelayHandler; import com.rabbitmq.client.SaslConfig; +import com.rabbitmq.client.ShutdownSignalException; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadFactory; +import java.util.function.Predicate; public class ConnectionParams { private CredentialsProvider credentialsProvider; @@ -46,6 +48,7 @@ public class ConnectionParams { private boolean channelShouldCheckRpcResponseType; private ErrorOnWriteListener errorOnWriteListener; private int workPoolTimeout = -1; + private Predicate connectionRecoveryTriggeringCondition; private ExceptionHandler exceptionHandler; private ThreadFactory threadFactory; @@ -235,4 +238,12 @@ public void setWorkPoolTimeout(int workPoolTimeout) { public int getWorkPoolTimeout() { return workPoolTimeout; } + + public void setConnectionRecoveryTriggeringCondition(Predicate connectionRecoveryTriggeringCondition) { + this.connectionRecoveryTriggeringCondition = connectionRecoveryTriggeringCondition; + } + + public Predicate getConnectionRecoveryTriggeringCondition() { + return connectionRecoveryTriggeringCondition; + } } diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index 17602b340b..f3c3c13d10 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -37,6 +37,7 @@ import java.util.concurrent.TimeoutException; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; +import java.util.function.Predicate; /** * Connection implementation that performs automatic recovery when @@ -61,6 +62,9 @@ */ public class AutorecoveringConnection implements RecoverableConnection, NetworkConnection { + public static final Predicate DEFAULT_CONNECTION_RECOVERY_TRIGGERING_CONDITION = + cause -> !cause.isInitiatedByApplication() || (cause.getCause() instanceof MissedHeartbeatException); + private static final Logger LOGGER = LoggerFactory.getLogger(AutorecoveringConnection.class); private final RecoveryAwareAMQConnectionFactory cf; @@ -87,6 +91,8 @@ public class AutorecoveringConnection implements RecoverableConnection, NetworkC // be created after application code has initiated shutdown. private final Object recoveryLock = new Object(); + private final Predicate connectionRecoveryTriggeringCondition; + public AutorecoveringConnection(ConnectionParams params, FrameHandlerFactory f, List
addrs) { this(params, f, new ListAddressResolver(addrs)); } @@ -99,9 +105,14 @@ public AutorecoveringConnection(ConnectionParams params, FrameHandlerFactory f, this.cf = new RecoveryAwareAMQConnectionFactory(params, f, addressResolver, metricsCollector); this.params = params; + this.connectionRecoveryTriggeringCondition = params.getConnectionRecoveryTriggeringCondition() == null ? + DEFAULT_CONNECTION_RECOVERY_TRIGGERING_CONDITION : params.getConnectionRecoveryTriggeringCondition(); + + System.out.println(this.connectionRecoveryTriggeringCondition); + setupErrorOnWriteListenerForPotentialRecovery(); - this.channels = new ConcurrentHashMap(); + this.channels = new ConcurrentHashMap<>(); } private void setupErrorOnWriteListenerForPotentialRecovery() { @@ -484,16 +495,13 @@ private void addAutomaticRecoveryListener(final RecoveryAwareAMQConnection newCo final AutorecoveringConnection c = this; // this listener will run after shutdown listeners, // see https://github.com/rabbitmq/rabbitmq-java-client/issues/135 - RecoveryCanBeginListener starter = new RecoveryCanBeginListener() { - @Override - public void recoveryCanBegin(ShutdownSignalException cause) { - try { - if (shouldTriggerConnectionRecovery(cause)) { - c.beginAutomaticRecovery(); - } - } catch (Exception e) { - newConn.getExceptionHandler().handleConnectionRecoveryException(c, e); + RecoveryCanBeginListener starter = cause -> { + try { + if (shouldTriggerConnectionRecovery(cause)) { + c.beginAutomaticRecovery(); } + } catch (Exception e) { + newConn.getExceptionHandler().handleConnectionRecoveryException(c, e); } }; synchronized (this) { @@ -502,7 +510,7 @@ public void recoveryCanBegin(ShutdownSignalException cause) { } protected boolean shouldTriggerConnectionRecovery(ShutdownSignalException cause) { - return !cause.isInitiatedByApplication() || (cause.getCause() instanceof MissedHeartbeatException); + return connectionRecoveryTriggeringCondition.test(cause); } /** From 7a6a513b9728bf4943b528f04eee6c154331f2fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 27 Jul 2018 17:59:46 +0200 Subject: [PATCH 0823/2114] Add test cases for JSON RPC support References #378 --- .../client/impl/nio/NioLoopContext.java | 16 ++ .../rabbitmq/tools/jsonrpc/JsonRpcClient.java | 19 +- .../rabbitmq/tools/jsonrpc/JsonRpcServer.java | 75 +++++--- .../java/com/rabbitmq/client/JsonRpcTest.java | 176 ++++++++++++++++++ .../com/rabbitmq/client/test/ClientTests.java | 4 +- 5 files changed, 262 insertions(+), 28 deletions(-) create mode 100644 src/test/java/com/rabbitmq/client/JsonRpcTest.java diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioLoopContext.java b/src/main/java/com/rabbitmq/client/impl/nio/NioLoopContext.java index 70211ccfcb..8226929115 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioLoopContext.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioLoopContext.java @@ -1,3 +1,18 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.impl.nio; import com.rabbitmq.client.impl.Environment; @@ -38,6 +53,7 @@ public NioLoopContext(SocketChannelFrameHandlerFactory socketChannelFrameHandler } void initStateIfNecessary() throws IOException { + // FIXME this should be synchronized if (this.readSelectorState == null) { this.readSelectorState = new SelectorHolder(Selector.open()); this.writeSelectorState = new SelectorHolder(Selector.open()); diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java index 995b93b170..31822da6d0 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java @@ -28,6 +28,8 @@ import com.rabbitmq.client.ShutdownSignalException; import com.rabbitmq.tools.json.JSONReader; import com.rabbitmq.tools.json.JSONWriter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** JSON-RPC is a lightweight @@ -54,6 +56,9 @@ @see #call(String[]) */ public class JsonRpcClient extends RpcClient implements InvocationHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger(JsonRpcClient.class); + /** Holds the JSON-RPC service description for this client. */ private ServiceDescription serviceDescription; @@ -92,7 +97,6 @@ public static Object checkReply(Map reply) } Object result = reply.get("result"); - //System.out.println(new JSONWriter().write(result)); return result; } @@ -113,8 +117,12 @@ public Object call(String method, Object[] params) throws IOException, JsonRpcEx String requestStr = new JSONWriter().write(request); try { String replyStr = this.stringCall(requestStr); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Reply string: {}", replyStr); + } @SuppressWarnings("unchecked") Map map = (Map) (new JSONReader().read(replyStr)); + return checkReply(map); } catch(ShutdownSignalException ex) { throw new IOException(ex.getMessage()); // wrap, re-throw @@ -137,10 +145,11 @@ public Object invoke(Object proxy, Method method, Object[] args) /** * Public API - gets a dynamic proxy for a particular interface class. */ - public Object createProxy(Class klass) + @SuppressWarnings("unchecked") + public T createProxy(Class klass) throws IllegalArgumentException { - return Proxy.newProxyInstance(klass.getClassLoader(), + return (T) Proxy.newProxyInstance(klass.getClassLoader(), new Class[] { klass }, this); } @@ -161,8 +170,8 @@ public static Object coerce(String val, String type) return Double.valueOf(val); } } else if ("str".equals(type)) { - return val; - } else if ("arr".equals(type) || "obj".equals(type) || "any".equals(type)) { + return val; + } else if ("arr".equals(type) || "obj".equals(type) || "any".equals(type)) { return new JSONReader().read(val); } else if ("nil".equals(type)) { return null; diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java index d7ee1fd021..138f654b12 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java @@ -18,6 +18,8 @@ import java.io.IOException; import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -27,6 +29,8 @@ import com.rabbitmq.client.StringRpcServer; import com.rabbitmq.tools.json.JSONReader; import com.rabbitmq.tools.json.JSONWriter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * JSON-RPC Server class. @@ -41,6 +45,9 @@ * @see JsonRpcClient */ public class JsonRpcServer extends StringRpcServer { + + private static final Logger LOGGER = LoggerFactory.getLogger(JsonRpcServer.class); + /** Holds the JSON-RPC service description for this client. */ public ServiceDescription serviceDescription; /** The interface this server implements. */ @@ -114,38 +121,62 @@ public String doCall(String requestBody) Object id; String method; Object[] params; + String response; + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Request: {}", requestBody); + } try { @SuppressWarnings("unchecked") Map request = (Map) new JSONReader().read(requestBody); if (request == null) { - return errorResponse(null, 400, "Bad Request", null); - } - if (!ServiceDescription.JSON_RPC_VERSION.equals(request.get("version"))) { - return errorResponse(null, 505, "JSONRPC version not supported", null); + response = errorResponse(null, 400, "Bad Request", null); + } else if (!ServiceDescription.JSON_RPC_VERSION.equals(request.get("version"))) { + response = errorResponse(null, 505, "JSONRPC version not supported", null); + } else { + id = request.get("id"); + method = (String) request.get("method"); + List parmList = (List) request.get("params"); + params = parmList.toArray(); + if (method.equals("system.describe")) { + response = resultResponse(id, serviceDescription); + } else if (method.startsWith("system.")) { + response = errorResponse(id, 403, "System methods forbidden", null); + } else { + Object result; + try { + Method matchingMethod = matchingMethod(method, params); + if (LOGGER.isDebugEnabled()) { + Collection parametersValuesAndTypes = new ArrayList(); + if (params != null) { + for (Object param : params) { + parametersValuesAndTypes.add( + String.format("%s (%s)", param, param == null ? "?" : param.getClass()) + ); + } + } + LOGGER.debug("About to invoke {} method with parameters {}", matchingMethod, parametersValuesAndTypes); + } + result = matchingMethod.invoke(interfaceInstance, params); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Invocation returned {} ({})", result, result == null ? "?" : result.getClass()); + } + response = resultResponse(id, result); + } catch (Throwable t) { + LOGGER.info("Error while processing JSON RPC request", t); + response = errorResponse(id, 500, "Internal Server Error", t); + } + } } - - id = request.get("id"); - method = (String) request.get("method"); - List parmList = (List) request.get("params"); - params = parmList.toArray(); } catch (ClassCastException cce) { // Bogus request! - return errorResponse(null, 400, "Bad Request", null); + response = errorResponse(null, 400, "Bad Request", null); } - if (method.equals("system.describe")) { - return resultResponse(id, serviceDescription); - } else if (method.startsWith("system.")) { - return errorResponse(id, 403, "System methods forbidden", null); - } else { - Object result; - try { - result = matchingMethod(method, params).invoke(interfaceInstance, params); - } catch (Throwable t) { - return errorResponse(id, 500, "Internal Server Error", t); - } - return resultResponse(id, result); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Response: {}", response); } + + return response; } /** diff --git a/src/test/java/com/rabbitmq/client/JsonRpcTest.java b/src/test/java/com/rabbitmq/client/JsonRpcTest.java new file mode 100644 index 0000000000..b6f73c824e --- /dev/null +++ b/src/test/java/com/rabbitmq/client/JsonRpcTest.java @@ -0,0 +1,176 @@ +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client; + +import com.rabbitmq.client.test.TestUtils; +import com.rabbitmq.tools.jsonrpc.JsonRpcClient; +import com.rabbitmq.tools.jsonrpc.JsonRpcServer; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.lang.reflect.UndeclaredThrowableException; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +public class JsonRpcTest { + + Connection clientConnection, serverConnection; + Channel clientChannel, serverChannel; + String queue = "json.rpc.queue"; + JsonRpcServer server; + JsonRpcClient client; + RpcService service; + + @Before + public void init() throws Exception { + clientConnection = TestUtils.connectionFactory().newConnection(); + clientChannel = clientConnection.createChannel(); + serverConnection = TestUtils.connectionFactory().newConnection(); + serverChannel = serverConnection.createChannel(); + serverChannel.queueDeclare(queue, false, false, false, null); + server = new JsonRpcServer(serverChannel, queue, RpcService.class, new DefaultRpcservice()); + new Thread(new Runnable() { + + @Override + public void run() { + try { + server.mainloop(); + } catch (Exception e) { + // safe to ignore when loops ends/server is canceled + } + } + }).start(); + client = new JsonRpcClient(clientChannel, "", queue, 1000); + service = client.createProxy(RpcService.class); + } + + @After + public void tearDown() throws Exception { + if (server != null) { + server.terminateMainloop(); + } + if (client != null) { + client.close(); + } + if (serverChannel != null) { + serverChannel.queueDelete(queue); + } + clientConnection.close(); + serverConnection.close(); + } + + @Test + public void rpc() { + assertEquals("hello1", service.procedureString("hello")); + assertEquals(2, service.procedureInteger(1).intValue()); + assertEquals(2, service.procedurePrimitiveInteger(1)); + assertEquals(2, service.procedureDouble(1.0).intValue()); + assertEquals(2, (int) service.procedurePrimitiveDouble(1.0)); + + try { + assertEquals(2, (int) service.procedureLongToInteger(1L)); + fail("Long argument isn't supported"); + } catch (UndeclaredThrowableException e) { + // OK + } + assertEquals(2, service.procedurePrimitiveLongToInteger(1L)); + + try { + assertEquals(2, service.procedurePrimitiveLong(1L)); + fail("Long return type not supported"); + } catch (ClassCastException e) { + // OK + } + + try { + assertEquals(2, service.procedureLong(1L).longValue()); + fail("Long argument isn't supported"); + } catch (UndeclaredThrowableException e) { + // OK + } + } + + public interface RpcService { + + String procedureString(String input); + + int procedurePrimitiveInteger(int input); + + Integer procedureInteger(Integer input); + + Double procedureDouble(Double input); + + double procedurePrimitiveDouble(double input); + + Integer procedureLongToInteger(Long input); + + int procedurePrimitiveLongToInteger(long input); + + Long procedureLong(Long input); + + long procedurePrimitiveLong(long input); + } + + public class DefaultRpcservice implements RpcService { + + @Override + public String procedureString(String input) { + return input + 1; + } + + @Override + public int procedurePrimitiveInteger(int input) { + return input + 1; + } + + @Override + public Integer procedureInteger(Integer input) { + return input + 1; + } + + @Override + public Long procedureLong(Long input) { + return input + 1; + } + + @Override + public long procedurePrimitiveLong(long input) { + return input + 1L; + } + + @Override + public Double procedureDouble(Double input) { + return input + 1; + } + + @Override + public double procedurePrimitiveDouble(double input) { + return input + 1; + } + + @Override + public Integer procedureLongToInteger(Long input) { + return (int) (input + 1); + } + + @Override + public int procedurePrimitiveLongToInteger(long input) { + return (int) input + 1; + } + } +} diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index 73258f1e59..0500dd75b1 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -16,6 +16,7 @@ package com.rabbitmq.client.test; +import com.rabbitmq.client.JsonRpcTest; import com.rabbitmq.utility.IntAllocatorTests; import org.junit.runner.RunWith; import org.junit.runners.Suite; @@ -55,7 +56,8 @@ PropertyFileInitialisationTest.class, ClientVersionTest.class, StrictExceptionHandlerTest.class, - NoAutoRecoveryWhenTcpWindowIsFullTest.class + NoAutoRecoveryWhenTcpWindowIsFullTest.class, + JsonRpcTest.class }) public class ClientTests { From 1abb5c2e96b5ba4d18626a69e1ae06dfbcfb7fd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 31 Jul 2018 16:17:15 +0200 Subject: [PATCH 0824/2114] Add test case for broken RpcClient on broker restart The RpcClient registers a reply consumer on the direct-reply pseudo-queue and doesn't cancel it when the connection fails. The RpcClient is then unusable by design (it nullifies the consumer on connection failure). Nevertheless, the consumer must be cancelled after recovery to be able to create a new RpcClient on the same channel. Disabling topology recovery makes this work: the consumer isn't re-registered during topology recovery and a new RpcClient can be created on the same (recovered) channel. References #382 --- .../com/rabbitmq/client/test/RpcTest.java | 56 ++++++++++++++++++- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/RpcTest.java b/src/test/java/com/rabbitmq/client/test/RpcTest.java index 3b76dc82d3..4c919d4ed9 100644 --- a/src/test/java/com/rabbitmq/client/test/RpcTest.java +++ b/src/test/java/com/rabbitmq/client/test/RpcTest.java @@ -17,16 +17,21 @@ package com.rabbitmq.client.test; import com.rabbitmq.client.*; +import com.rabbitmq.client.impl.NetworkConnection; +import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; +import com.rabbitmq.tools.Host; import org.junit.After; import org.junit.Before; import org.junit.Test; import java.io.IOException; -import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; public class RpcTest { @@ -35,7 +40,6 @@ public class RpcTest { String queue = "rpc.queue"; RpcServer rpcServer; - @Before public void init() throws Exception { clientConnection = TestUtils.connectionFactory().newConnection(); clientChannel = clientConnection.createChannel(); @@ -77,6 +81,54 @@ public void run() { client.close(); } + @Test public void brokenAfterBrokerRestart() throws Exception { + // see https://github.com/rabbitmq/rabbitmq-java-client/issues/382 + rpcServer = new TestRpcServer(serverChannel, queue); + new Thread(new Runnable() { + @Override + public void run() { + try { + rpcServer.mainloop(); + } catch (Exception e) { + // safe to ignore when loops ends/server is canceled + } + } + }).start(); + + ConnectionFactory cf = TestUtils.connectionFactory(); + cf.setTopologyRecoveryEnabled(false); + cf.setNetworkRecoveryInterval(2000); + Connection connection = null; + try { + connection = cf.newConnection(); + Channel channel = connection.createChannel(); + RpcClient client = new RpcClient(channel, "", queue, 1000); + RpcClient.Response response = client.doCall(null, "hello".getBytes()); + assertEquals("*** hello ***", new String(response.getBody())); + final CountDownLatch recoveryLatch = new CountDownLatch(1); + ((AutorecoveringConnection) connection).addRecoveryListener(new RecoveryListener() { + @Override + public void handleRecovery(Recoverable recoverable) { + recoveryLatch.countDown(); + } + @Override + public void handleRecoveryStarted(Recoverable recoverable) { + + } + }); + Host.closeConnection((NetworkConnection) connection); + assertTrue("Connection should have recovered by now", recoveryLatch.await(10, TimeUnit.SECONDS)); + client = new RpcClient(channel, "", queue, 1000); + response = client.doCall(null, "hello".getBytes()); + assertEquals("*** hello ***", new String(response.getBody())); + } finally { + if (connection != null) { + connection.close(); + } + } + + } + private static class TestRpcServer extends RpcServer { public TestRpcServer(Channel channel, String queueName) throws IOException { From a89dd9aaa47f9bfbb9066a00906996506d6f675e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 1 Aug 2018 12:49:41 +0200 Subject: [PATCH 0825/2114] Add filter to skip entities on topology recovery [#159461281] References #382 Fixes #383 --- .../rabbitmq/client/ConnectionFactory.java | 17 + .../client/impl/ConnectionParams.java | 10 + .../recovery/AutorecoveringConnection.java | 112 ++++--- .../client/impl/recovery/RecordedBinding.java | 4 + .../impl/recovery/TopologyRecoveryFilter.java | 52 +++ .../rabbitmq/client/test/BrokerTestCase.java | 16 + .../test/functional/ConnectionRecovery.java | 1 - .../test/functional/FunctionalTests.java | 3 +- .../functional/TopologyRecoveryFiltering.java | 306 ++++++++++++++++++ 9 files changed, 483 insertions(+), 38 deletions(-) create mode 100644 src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryFilter.java create mode 100644 src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 5364da2b78..cbbc4338fe 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -29,6 +29,8 @@ import com.rabbitmq.client.impl.nio.NioParams; import com.rabbitmq.client.impl.nio.SocketChannelFrameHandlerFactory; import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; +import com.rabbitmq.client.impl.recovery.TopologyRecoveryFilter; + import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; @@ -172,6 +174,12 @@ public class ConnectionFactory implements Cloneable { */ private int workPoolTimeout = DEFAULT_WORK_POOL_TIMEOUT; + /** + * Filter to include/exclude entities from topology recovery. + * @since 4.8.0 + */ + private TopologyRecoveryFilter topologyRecoveryFilter; + /** @return the default host to use for connections */ public String getHost() { return host; @@ -1046,6 +1054,7 @@ public ConnectionParams params(ExecutorService consumerWorkServiceExecutor) { result.setChannelShouldCheckRpcResponseType(channelShouldCheckRpcResponseType); result.setWorkPoolTimeout(workPoolTimeout); result.setErrorOnWriteListener(errorOnWriteListener); + result.setTopologyRecoveryFilter(topologyRecoveryFilter); return result; } @@ -1379,4 +1388,12 @@ public int getWorkPoolTimeout() { public void setErrorOnWriteListener(ErrorOnWriteListener errorOnWriteListener) { this.errorOnWriteListener = errorOnWriteListener; } + + /** + * Set filter to include/exclude entities from topology recovery. + * @since 4.8.0 + */ + public void setTopologyRecoveryFilter(TopologyRecoveryFilter topologyRecoveryFilter) { + this.topologyRecoveryFilter = topologyRecoveryFilter; + } } diff --git a/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java b/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java index 08c123bd81..093142b296 100644 --- a/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java +++ b/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java @@ -19,6 +19,7 @@ import com.rabbitmq.client.RecoveryDelayHandler; import com.rabbitmq.client.RecoveryDelayHandler.DefaultRecoveryDelayHandler; import com.rabbitmq.client.SaslConfig; +import com.rabbitmq.client.impl.recovery.TopologyRecoveryFilter; import java.util.Map; import java.util.concurrent.ExecutorService; @@ -46,6 +47,7 @@ public class ConnectionParams { private boolean channelShouldCheckRpcResponseType; private ErrorOnWriteListener errorOnWriteListener; private int workPoolTimeout = -1; + private TopologyRecoveryFilter topologyRecoveryFilter; private ExceptionHandler exceptionHandler; private ThreadFactory threadFactory; @@ -235,4 +237,12 @@ public void setWorkPoolTimeout(int workPoolTimeout) { public int getWorkPoolTimeout() { return workPoolTimeout; } + + public void setTopologyRecoveryFilter(TopologyRecoveryFilter topologyRecoveryFilter) { + this.topologyRecoveryFilter = topologyRecoveryFilter; + } + + public TopologyRecoveryFilter getTopologyRecoveryFilter() { + return topologyRecoveryFilter; + } } diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index 85fe95ba2a..28d64747d1 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -80,6 +80,8 @@ public class AutorecoveringConnection implements RecoverableConnection, NetworkC private final Map consumers = Collections.synchronizedMap(new LinkedHashMap()); private final List consumerRecoveryListeners = Collections.synchronizedList(new ArrayList()); private final List queueRecoveryListeners = Collections.synchronizedList(new ArrayList()); + + private final TopologyRecoveryFilter topologyRecoveryFilter; // Used to block connection recovery attempts after close() is invoked. private volatile boolean manuallyClosed = false; @@ -103,6 +105,10 @@ public AutorecoveringConnection(ConnectionParams params, FrameHandlerFactory f, setupErrorOnWriteListenerForPotentialRecovery(); this.channels = new ConcurrentHashMap(); + + + this.topologyRecoveryFilter = params.getTopologyRecoveryFilter() == null ? + letAllPassFilter() : params.getTopologyRecoveryFilter(); } private void setupErrorOnWriteListenerForPotentialRecovery() { @@ -133,6 +139,31 @@ public void run() { }); } + private TopologyRecoveryFilter letAllPassFilter() { + return new TopologyRecoveryFilter() { + + @Override + public boolean filterExchange(RecordedExchange recordedExchange) { + return true; + } + + @Override + public boolean filterQueue(RecordedQueue recordedQueue) { + return true; + } + + @Override + public boolean filterBinding(RecordedBinding recordedBinding) { + return true; + } + + @Override + public boolean filterConsumer(RecordedConsumer recordedConsumer) { + return true; + } + }; + } + /** * Private API. * @throws IOException @@ -655,8 +686,10 @@ private void recoverTopology(final ExecutorService executor) { private void recoverExchange(final RecordedExchange x) { // recorded exchanges are guaranteed to be non-predefined (we filter out predefined ones in exchangeDeclare). MK. try { - x.recover(); - LOGGER.debug("{} has recovered", x); + if (topologyRecoveryFilter.filterExchange(x)) { + x.recover(); + LOGGER.debug("{} has recovered", x); + } } catch (Exception cause) { final String message = "Caught an exception while recovering exchange " + x.getName() + ": " + cause.getMessage(); @@ -666,30 +699,33 @@ private void recoverExchange(final RecordedExchange x) { } private void recoverQueue(final String oldName, final RecordedQueue q) { - LOGGER.debug("Recovering {}", q); + try { - q.recover(); - String newName = q.getName(); - if (!oldName.equals(newName)) { - // make sure server-named queues are re-added with - // their new names. MK. - synchronized (this.recordedQueues) { - this.propagateQueueNameChangeToBindings(oldName, newName); - this.propagateQueueNameChangeToConsumers(oldName, newName); - // bug26552: - // remove old name after we've updated the bindings and consumers, - // plus only for server-named queues, both to make sure we don't lose - // anything to recover. MK. - if(q.isServerNamed()) { - deleteRecordedQueue(oldName); + if (topologyRecoveryFilter.filterQueue(q)) { + LOGGER.debug("Recovering {}", q); + q.recover(); + String newName = q.getName(); + if (!oldName.equals(newName)) { + // make sure server-named queues are re-added with + // their new names. MK. + synchronized (this.recordedQueues) { + this.propagateQueueNameChangeToBindings(oldName, newName); + this.propagateQueueNameChangeToConsumers(oldName, newName); + // bug26552: + // remove old name after we've updated the bindings and consumers, + // plus only for server-named queues, both to make sure we don't lose + // anything to recover. MK. + if(q.isServerNamed()) { + deleteRecordedQueue(oldName); + } + this.recordedQueues.put(newName, q); } - this.recordedQueues.put(newName, q); } + for (QueueRecoveryListener qrl : Utility.copy(this.queueRecoveryListeners)) { + qrl.queueRecovered(oldName, newName); + } + LOGGER.debug("{} has recovered", q); } - for (QueueRecoveryListener qrl : Utility.copy(this.queueRecoveryListeners)) { - qrl.queueRecovered(oldName, newName); - } - LOGGER.debug("{} has recovered", q); } catch (Exception cause) { final String message = "Caught an exception while recovering queue " + oldName + ": " + cause.getMessage(); @@ -700,8 +736,10 @@ private void recoverQueue(final String oldName, final RecordedQueue q) { private void recoverBinding(final RecordedBinding b) { try { - b.recover(); - LOGGER.debug("{} has recovered", b); + if (this.topologyRecoveryFilter.filterBinding(b)) { + b.recover(); + LOGGER.debug("{} has recovered", b); + } } catch (Exception cause) { String message = "Caught an exception while recovering binding between " + b.getSource() + " and " + b.getDestination() + ": " + cause.getMessage(); @@ -711,22 +749,24 @@ private void recoverBinding(final RecordedBinding b) { } private void recoverConsumer(final String tag, final RecordedConsumer consumer) { - LOGGER.debug("Recovering {}", consumer); try { - String newTag = consumer.recover(); - // make sure server-generated tags are re-added. MK. - if(tag != null && !tag.equals(newTag)) { - synchronized (this.consumers) { - this.consumers.remove(tag); - this.consumers.put(newTag, consumer); + if (this.topologyRecoveryFilter.filterConsumer(consumer)) { + LOGGER.debug("Recovering {}", consumer); + String newTag = consumer.recover(); + // make sure server-generated tags are re-added. MK. + if(tag != null && !tag.equals(newTag)) { + synchronized (this.consumers) { + this.consumers.remove(tag); + this.consumers.put(newTag, consumer); + } + consumer.getChannel().updateConsumerTag(tag, newTag); } - consumer.getChannel().updateConsumerTag(tag, newTag); - } - for (ConsumerRecoveryListener crl : Utility.copy(this.consumerRecoveryListeners)) { - crl.consumerRecovered(tag, newTag); + for (ConsumerRecoveryListener crl : Utility.copy(this.consumerRecoveryListeners)) { + crl.consumerRecovered(tag, newTag); + } + LOGGER.debug("{} has recovered", consumer); } - LOGGER.debug("{} has recovered", consumer); } catch (Exception cause) { final String message = "Caught an exception while recovering consumer " + tag + ": " + cause.getMessage(); diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedBinding.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedBinding.java index 578ce31dce..4b144ae00b 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedBinding.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedBinding.java @@ -59,6 +59,10 @@ public String getDestination() { return destination; } + public String getRoutingKey() { + return routingKey; + } + public Map getArguments() { return arguments; } diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryFilter.java b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryFilter.java new file mode 100644 index 0000000000..443866fbb8 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryFilter.java @@ -0,0 +1,52 @@ +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl.recovery; + +/** + * Filter to know whether entities should be recovered or not. + * @since 4.8.0 + */ +public interface TopologyRecoveryFilter { + + /** + * Decides whether an exchange is recovered or not. + * @param recordedExchange + * @return true to recover the exchange, false otherwise + */ + boolean filterExchange(RecordedExchange recordedExchange); + + /** + * Decides whether a queue is recovered or not. + * @param recordedQueue + * @return true to recover the queue, false otherwise + */ + boolean filterQueue(RecordedQueue recordedQueue); + + /** + * Decides whether a binding is recovered or not. + * @param recordedBinding + * @return true to recover the binding, false otherwise + */ + boolean filterBinding(RecordedBinding recordedBinding); + + /** + * Decides whether a consumer is recovered or not. + * @param recordedConsumer + * @return true to recover the consumer, false otherwise + */ + boolean filterConsumer(RecordedConsumer recordedConsumer); + +} diff --git a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java index 7a0b508e9d..27ea0cbd0d 100644 --- a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java +++ b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java @@ -300,10 +300,26 @@ protected void deleteExchange(String x) throws IOException { channel.exchangeDelete(x); } + protected void deleteExchanges(String [] exchanges) throws IOException { + if (exchanges != null) { + for (String exchange : exchanges) { + deleteExchange(exchange); + } + } + } + protected void deleteQueue(String q) throws IOException { channel.queueDelete(q); } + protected void deleteQueues(String [] queues) throws IOException { + if (queues != null) { + for (String queue : queues) { + deleteQueue(queue); + } + } + } + protected void clearAllResourceAlarms() throws IOException, InterruptedException { clearResourceAlarm("memory"); clearResourceAlarm("disk"); diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java index 50a0c6350e..a89bb16995 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -32,7 +32,6 @@ import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; diff --git a/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java b/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java index c88b2a7f19..aeadb303dd 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java +++ b/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java @@ -77,7 +77,8 @@ BasicGet.class, Nack.class, ExceptionMessages.class, - Metrics.class + Metrics.class, + TopologyRecoveryFiltering.class }) public class FunctionalTests { diff --git a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java new file mode 100644 index 0000000000..9655aa42fc --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java @@ -0,0 +1,306 @@ +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.test.functional; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.DefaultConsumer; +import com.rabbitmq.client.Envelope; +import com.rabbitmq.client.Recoverable; +import com.rabbitmq.client.RecoverableConnection; +import com.rabbitmq.client.RecoveryListener; +import com.rabbitmq.client.ShutdownSignalException; +import com.rabbitmq.client.impl.NetworkConnection; +import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; +import com.rabbitmq.client.impl.recovery.RecordedBinding; +import com.rabbitmq.client.impl.recovery.RecordedConsumer; +import com.rabbitmq.client.impl.recovery.RecordedExchange; +import com.rabbitmq.client.impl.recovery.RecordedQueue; +import com.rabbitmq.client.impl.recovery.TopologyRecoveryFilter; +import com.rabbitmq.client.test.BrokerTestCase; +import com.rabbitmq.client.test.TestUtils; +import com.rabbitmq.tools.Host; +import org.junit.Test; + +import java.io.IOException; +import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.awaitility.Awaitility.waitAtMost; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * + */ +public class TopologyRecoveryFiltering extends BrokerTestCase { + + static { + System.setProperty("rabbitmqctl.bin", "/home/acogoluegnes/Downloads/rabbitmq_server-3.7.7/sbin/rabbitmqctl"); + System.setProperty("test-broker.A.nodename", "rabbit@acogoluegnes-xps"); + } + + String[] exchangesToDelete = new String[] { + "recovered.exchange", "filtered.exchange", "topology.recovery.exchange" + }; + String[] queuesToDelete = new String[] { + "topology.recovery.queue.1", "topology.recovery.queue.2" + }; + Connection c; + + private static boolean sendAndConsumeMessage(String exchange, String routingKey, String queue, Connection c) + throws IOException, TimeoutException, InterruptedException { + Channel ch = c.createChannel(); + try { + ch.confirmSelect(); + final CountDownLatch latch = new CountDownLatch(1); + ch.basicConsume(queue, true, new DefaultConsumer(ch) { + + @Override + public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { + latch.countDown(); + } + }); + ch.basicPublish(exchange, routingKey, null, "".getBytes()); + ch.waitForConfirmsOrDie(5000); + return latch.await(5, TimeUnit.SECONDS); + } finally { + if (ch != null && ch.isOpen()) { + ch.close(); + } + } + } + + private static boolean resourceExists(Callable callback) throws Exception { + Channel declarePassiveChannel = null; + try { + declarePassiveChannel = callback.call(); + return true; + } catch (IOException e) { + if (e.getCause() instanceof ShutdownSignalException) { + ShutdownSignalException cause = (ShutdownSignalException) e.getCause(); + if (cause.getReason() instanceof AMQP.Channel.Close) { + if (((AMQP.Channel.Close) cause.getReason()).getReplyCode() == 404) { + return false; + } else { + throw e; + } + } + return false; + } else { + throw e; + } + } finally { + if (declarePassiveChannel != null && declarePassiveChannel.isOpen()) { + declarePassiveChannel.close(); + } + } + } + + private static boolean queueExists(final String queue, final Connection connection) throws Exception { + return resourceExists(new Callable() { + + @Override + public Channel call() throws Exception { + Channel channel = connection.createChannel(); + channel.queueDeclarePassive(queue); + return channel; + } + }); + } + + private static boolean exchangeExists(final String exchange, final Connection connection) throws Exception { + return resourceExists(new Callable() { + + @Override + public Channel call() throws Exception { + Channel channel = connection.createChannel(); + channel.exchangeDeclarePassive(exchange); + return channel; + } + }); + } + + private static void closeAndWaitForRecovery(RecoverableConnection connection) throws IOException, InterruptedException { + CountDownLatch latch = prepareForRecovery(connection); + Host.closeConnection((NetworkConnection) connection); + wait(latch); + } + + private static CountDownLatch prepareForRecovery(Connection conn) { + final CountDownLatch latch = new CountDownLatch(1); + ((AutorecoveringConnection) conn).addRecoveryListener(new RecoveryListener() { + + @Override + public void handleRecovery(Recoverable recoverable) { + latch.countDown(); + } + + @Override + public void handleRecoveryStarted(Recoverable recoverable) { + // No-op + } + }); + return latch; + } + + private static void wait(CountDownLatch latch) throws InterruptedException { + assertTrue(latch.await(20, TimeUnit.SECONDS)); + } + + @Override + protected ConnectionFactory newConnectionFactory() { + ConnectionFactory connectionFactory = TestUtils.connectionFactory(); + connectionFactory.setTopologyRecoveryFilter(new SimpleTopologyRecoveryFilter()); + connectionFactory.setNetworkRecoveryInterval(1000); + return connectionFactory; + } + + @Override + protected void createResources() throws IOException, TimeoutException { + super.createResources(); + c = connectionFactory.newConnection(); + deleteExchanges(exchangesToDelete); + deleteQueues(queuesToDelete); + } + + @Override + protected void releaseResources() throws IOException { + super.releaseResources(); + c.close(); + deleteExchanges(exchangesToDelete); + deleteQueues(queuesToDelete); + } + + @Test + public void topologyRecoveryFilteringExchangesAndQueues() throws Exception { + Channel ch = c.createChannel(); + ch.exchangeDeclare("recovered.exchange", "direct"); + ch.exchangeDeclare("filtered.exchange", "direct"); + ch.queueDeclare("recovered.queue", false, true, true, null); + ch.queueDeclare("filtered.queue", false, true, true, null); + + // to check whether the other connection recovers them or not + channel.exchangeDelete("recovered.exchange"); + channel.exchangeDelete("filtered.exchange"); + + closeAndWaitForRecovery((RecoverableConnection) c); + + assertTrue(exchangeExists("recovered.exchange", c)); + assertFalse(exchangeExists("filtered.exchange", c)); + + assertTrue(queueExists("recovered.queue", c)); + assertFalse(queueExists("filtered.queue", c)); + } + + @Test + public void topologyRecoveryFilteringBindings() throws Exception { + Channel ch = c.createChannel(); + + ch.exchangeDeclare("topology.recovery.exchange", "direct"); + ch.queueDeclare("topology.recovery.queue.1", false, false, false, null); + ch.queueDeclare("topology.recovery.queue.2", false, false, false, null); + ch.queueBind("topology.recovery.queue.1", "topology.recovery.exchange", "recovered.binding"); + ch.queueBind("topology.recovery.queue.2", "topology.recovery.exchange", "filtered.binding"); + + // to check whether the other connection recovers them or not + channel.queueUnbind("topology.recovery.queue.1", "topology.recovery.exchange", "recovered.binding"); + channel.queueUnbind("topology.recovery.queue.2", "topology.recovery.exchange", "filtered.binding"); + + closeAndWaitForRecovery((RecoverableConnection) c); + + assertTrue("The message should have been received by now", sendAndConsumeMessage( + "topology.recovery.exchange", "recovered.binding", "topology.recovery.queue.1", c + )); + assertFalse("Binding shouldn't recover, no messages should have been received", sendAndConsumeMessage( + "topology.recovery.exchange", "filtered.binding", "topology.recovery.queue.2", c + )); + } + + @Test + public void topologyRecoveryFilteringConsumers() throws Exception { + Channel ch = c.createChannel(); + + ch.exchangeDeclare("topology.recovery.exchange", "direct"); + ch.queueDeclare("topology.recovery.queue.1", false, false, false, null); + ch.queueDeclare("topology.recovery.queue.2", false, false, false, null); + ch.queueBind("topology.recovery.queue.1", "topology.recovery.exchange", "recovered.consumer"); + ch.queueBind("topology.recovery.queue.2", "topology.recovery.exchange", "filtered.consumer"); + + final AtomicInteger recoveredConsumerMessageCount = new AtomicInteger(0); + ch.basicConsume("topology.recovery.queue.1", true, "recovered.consumer", new DefaultConsumer(ch) { + + @Override + public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { + recoveredConsumerMessageCount.incrementAndGet(); + } + }); + ch.basicPublish("topology.recovery.exchange", "recovered.consumer", null, "".getBytes()); + waitAtMost(5, TimeUnit.SECONDS).untilAtomic(recoveredConsumerMessageCount, is(1)); + + final AtomicInteger filteredConsumerMessageCount = new AtomicInteger(0); + final CountDownLatch filteredConsumerLatch = new CountDownLatch(2); + ch.basicConsume("topology.recovery.queue.2", true, "filtered.consumer", new DefaultConsumer(ch) { + + @Override + public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { + filteredConsumerMessageCount.incrementAndGet(); + filteredConsumerLatch.countDown(); + } + }); + ch.basicPublish("topology.recovery.exchange", "filtered.consumer", null, "".getBytes()); + waitAtMost(5, TimeUnit.SECONDS).untilAtomic(filteredConsumerMessageCount, is(1)); + + closeAndWaitForRecovery((RecoverableConnection) c); + + int initialCount = recoveredConsumerMessageCount.get(); + ch.basicPublish("topology.recovery.exchange", "recovered.consumer", null, "".getBytes()); + waitAtMost(5, TimeUnit.SECONDS).untilAtomic(recoveredConsumerMessageCount, is(initialCount + 1)); + + ch.basicPublish("topology.recovery.exchange", "filtered.consumer", null, "".getBytes()); + assertFalse("Consumer shouldn't recover, no extra messages should have been received", + filteredConsumerLatch.await(5, TimeUnit.SECONDS)); + } + + private static class SimpleTopologyRecoveryFilter implements TopologyRecoveryFilter { + + @Override + public boolean filterExchange(RecordedExchange recordedExchange) { + return !recordedExchange.getName().contains("filtered"); + } + + @Override + public boolean filterQueue(RecordedQueue recordedQueue) { + return !recordedQueue.getName().contains("filtered"); + } + + @Override + public boolean filterBinding(RecordedBinding recordedBinding) { + return !recordedBinding.getRoutingKey().contains("filtered"); + } + + @Override + public boolean filterConsumer(RecordedConsumer recordedConsumer) { + return !recordedConsumer.getConsumerTag().contains("filtered"); + } + } +} From 16fb6251624d6f8c7a4b16ebb7b60b63405d0fa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 1 Aug 2018 12:52:35 +0200 Subject: [PATCH 0826/2114] Remove local testing code --- .../client/test/functional/TopologyRecoveryFiltering.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java index 9655aa42fc..803fcf3cc9 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java +++ b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java @@ -54,11 +54,6 @@ */ public class TopologyRecoveryFiltering extends BrokerTestCase { - static { - System.setProperty("rabbitmqctl.bin", "/home/acogoluegnes/Downloads/rabbitmq_server-3.7.7/sbin/rabbitmqctl"); - System.setProperty("test-broker.A.nodename", "rabbit@acogoluegnes-xps"); - } - String[] exchangesToDelete = new String[] { "recovered.exchange", "filtered.exchange", "topology.recovery.exchange" }; From 305af33df9923313527b86643be09429a60fc8ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 1 Aug 2018 13:11:23 +0200 Subject: [PATCH 0827/2114] Add test case to avoid broken RpcClient after broken restart [#159461281] References #383 Fixes #382 --- .../com/rabbitmq/client/test/RpcTest.java | 117 ++++++++++++++++-- 1 file changed, 108 insertions(+), 9 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/RpcTest.java b/src/test/java/com/rabbitmq/client/test/RpcTest.java index 4c919d4ed9..b7a11ce9a5 100644 --- a/src/test/java/com/rabbitmq/client/test/RpcTest.java +++ b/src/test/java/com/rabbitmq/client/test/RpcTest.java @@ -13,12 +13,25 @@ // If you have any questions regarding licensing, please contact us at // info@rabbitmq.com. - package com.rabbitmq.client.test; -import com.rabbitmq.client.*; +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.QueueingConsumer; +import com.rabbitmq.client.Recoverable; +import com.rabbitmq.client.RecoveryListener; +import com.rabbitmq.client.RpcClient; +import com.rabbitmq.client.RpcServer; +import com.rabbitmq.client.ShutdownSignalException; import com.rabbitmq.client.impl.NetworkConnection; import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; +import com.rabbitmq.client.impl.recovery.RecordedBinding; +import com.rabbitmq.client.impl.recovery.RecordedConsumer; +import com.rabbitmq.client.impl.recovery.RecordedExchange; +import com.rabbitmq.client.impl.recovery.RecordedQueue; +import com.rabbitmq.client.impl.recovery.TopologyRecoveryFilter; import com.rabbitmq.tools.Host; import org.junit.After; import org.junit.Before; @@ -32,6 +45,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; public class RpcTest { @@ -40,7 +54,8 @@ public class RpcTest { String queue = "rpc.queue"; RpcServer rpcServer; - @Before public void init() throws Exception { + @Before + public void init() throws Exception { clientConnection = TestUtils.connectionFactory().newConnection(); clientChannel = clientConnection.createChannel(); serverConnection = TestUtils.connectionFactory().newConnection(); @@ -48,11 +63,12 @@ public class RpcTest { serverChannel.queueDeclare(queue, false, false, false, null); } - @After public void tearDown() throws Exception { - if(rpcServer != null) { + @After + public void tearDown() throws Exception { + if (rpcServer != null) { rpcServer.terminateMainloop(); } - if(serverChannel != null) { + if (serverChannel != null) { serverChannel.queueDelete(queue); } clientConnection.close(); @@ -63,6 +79,7 @@ public class RpcTest { public void rpc() throws Exception { rpcServer = new TestRpcServer(serverChannel, queue); new Thread(new Runnable() { + @Override public void run() { try { @@ -81,10 +98,12 @@ public void run() { client.close(); } - @Test public void brokenAfterBrokerRestart() throws Exception { + @Test + public void givenConsumerNotRecoveredCanCreateNewClientOnSameChannelAfterConnectionFailure() throws Exception { // see https://github.com/rabbitmq/rabbitmq-java-client/issues/382 rpcServer = new TestRpcServer(serverChannel, queue); new Thread(new Runnable() { + @Override public void run() { try { @@ -96,8 +115,8 @@ public void run() { }).start(); ConnectionFactory cf = TestUtils.connectionFactory(); - cf.setTopologyRecoveryEnabled(false); - cf.setNetworkRecoveryInterval(2000); + cf.setTopologyRecoveryFilter(new NoDirectReplyToConsumerTopologyRecoveryFilter()); + cf.setNetworkRecoveryInterval(1000); Connection connection = null; try { connection = cf.newConnection(); @@ -107,10 +126,12 @@ public void run() { assertEquals("*** hello ***", new String(response.getBody())); final CountDownLatch recoveryLatch = new CountDownLatch(1); ((AutorecoveringConnection) connection).addRecoveryListener(new RecoveryListener() { + @Override public void handleRecovery(Recoverable recoverable) { recoveryLatch.countDown(); } + @Override public void handleRecoveryStarted(Recoverable recoverable) { @@ -126,7 +147,62 @@ public void handleRecoveryStarted(Recoverable recoverable) { connection.close(); } } + } + + @Test + public void givenConsumerIsRecoveredCanNotCreateNewClientOnSameChannelAfterConnectionFailure() throws Exception { + // see https://github.com/rabbitmq/rabbitmq-java-client/issues/382 + rpcServer = new TestRpcServer(serverChannel, queue); + new Thread(new Runnable() { + + @Override + public void run() { + try { + rpcServer.mainloop(); + } catch (Exception e) { + // safe to ignore when loops ends/server is canceled + } + } + }).start(); + + ConnectionFactory cf = TestUtils.connectionFactory(); + cf.setNetworkRecoveryInterval(1000); + Connection connection = null; + try { + connection = cf.newConnection(); + Channel channel = connection.createChannel(); + RpcClient client = new RpcClient(channel, "", queue, 1000); + RpcClient.Response response = client.doCall(null, "hello".getBytes()); + assertEquals("*** hello ***", new String(response.getBody())); + final CountDownLatch recoveryLatch = new CountDownLatch(1); + ((AutorecoveringConnection) connection).addRecoveryListener(new RecoveryListener() { + @Override + public void handleRecovery(Recoverable recoverable) { + recoveryLatch.countDown(); + } + + @Override + public void handleRecoveryStarted(Recoverable recoverable) { + + } + }); + Host.closeConnection((NetworkConnection) connection); + assertTrue("Connection should have recovered by now", recoveryLatch.await(10, TimeUnit.SECONDS)); + try { + new RpcClient(channel, "", queue, 1000); + fail("Cannot create RPC client on same channel, an exception should have been thrown"); + } catch (IOException e) { + assertTrue(e.getCause() instanceof ShutdownSignalException); + ShutdownSignalException cause = (ShutdownSignalException) e.getCause(); + assertTrue(cause.getReason() instanceof AMQP.Channel.Close); + assertEquals(406, ((AMQP.Channel.Close) cause.getReason()).getReplyCode()); + } + } finally { + if (connection != null) { + connection.close(); + } + } } private static class TestRpcServer extends RpcServer { @@ -157,4 +233,27 @@ protected AMQP.BasicProperties postprocessReplyProperties(QueueingConsumer.Deliv return builder.build(); } } + + private static class NoDirectReplyToConsumerTopologyRecoveryFilter implements TopologyRecoveryFilter { + + @Override + public boolean filterExchange(RecordedExchange recordedExchange) { + return true; + } + + @Override + public boolean filterQueue(RecordedQueue recordedQueue) { + return true; + } + + @Override + public boolean filterBinding(RecordedBinding recordedBinding) { + return true; + } + + @Override + public boolean filterConsumer(RecordedConsumer recordedConsumer) { + return !"amq.rabbitmq.reply-to".equals(recordedConsumer.getQueue()); + } + } } From 47dc236f292153a74922e34b57f26cc536ce2310 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 1 Aug 2018 18:29:39 +0300 Subject: [PATCH 0828/2114] Drive-by change: correct a path in RUNNING_TESTS.md --- RUNNING_TESTS.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/RUNNING_TESTS.md b/RUNNING_TESTS.md index 2619d9699f..a449a0d099 100644 --- a/RUNNING_TESTS.md +++ b/RUNNING_TESTS.md @@ -41,7 +41,7 @@ For details on running specific tests, see below. ## Running a Specific Test Suite -To run a specific test suite you should execute one of the following in the +To run a specific test suite, execute one of the following in the top-level directory of the source tree: * To run the client unit tests: @@ -59,7 +59,14 @@ top-level directory of the source tree: * To run a single test: ``` -./mvnw -Ddeps.dir=$(pwd)/deps/deps verify -Dit.test=DeadLetterExchange +./mvnw -Ddeps.dir=$(pwd)/deps verify -Dit.test=DeadLetterExchange +``` + +When running from the repository cloned as part of the [RabbitMQ public umbrella](https://github.com/rabbitmq/rabbitmq-public-umbrella), +the `deps.dir` property path may have to change, e.g. + +``` +./mvnw -Ddeps.dir=$(pwd)/.. verify -Dit.test=ConnectionRecovery ``` For example, to run the client tests: @@ -175,4 +182,4 @@ mvn verify -P '!setup-test-cluster' ``` Note that by doing so some tests will fail as they require `rabbitmqctl` to -control the running nodes. \ No newline at end of file +control the running nodes. From 2e042e5a4b51390b8f47a5acec90b553395f833e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 2 Aug 2018 14:01:26 +0200 Subject: [PATCH 0829/2114] Refine topology recovery filter with JDK 8 stuff [#159461281] References #382, #383 --- .../recovery/AutorecoveringConnection.java | 41 +++++-------------- .../impl/recovery/TopologyRecoveryFilter.java | 16 ++++++-- .../functional/TopologyRecoveryFiltering.java | 24 ++++------- 3 files changed, 30 insertions(+), 51 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index 93bc68a0fd..9223cb11aa 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -72,17 +72,17 @@ public class AutorecoveringConnection implements RecoverableConnection, NetworkC private final ConnectionParams params; private volatile RecoveryAwareAMQConnection delegate; - private final List shutdownHooks = Collections.synchronizedList(new ArrayList()); - private final List recoveryListeners = Collections.synchronizedList(new ArrayList()); - private final List blockedListeners = Collections.synchronizedList(new ArrayList()); + private final List shutdownHooks = Collections.synchronizedList(new ArrayList<>()); + private final List recoveryListeners = Collections.synchronizedList(new ArrayList<>()); + private final List blockedListeners = Collections.synchronizedList(new ArrayList<>()); // Records topology changes - private final Map recordedQueues = Collections.synchronizedMap(new LinkedHashMap()); - private final List recordedBindings = Collections.synchronizedList(new ArrayList()); - private final Map recordedExchanges = Collections.synchronizedMap(new LinkedHashMap()); - private final Map consumers = Collections.synchronizedMap(new LinkedHashMap()); - private final List consumerRecoveryListeners = Collections.synchronizedList(new ArrayList()); - private final List queueRecoveryListeners = Collections.synchronizedList(new ArrayList()); + private final Map recordedQueues = Collections.synchronizedMap(new LinkedHashMap<>()); + private final List recordedBindings = Collections.synchronizedList(new ArrayList<>()); + private final Map recordedExchanges = Collections.synchronizedMap(new LinkedHashMap<>()); + private final Map consumers = Collections.synchronizedMap(new LinkedHashMap<>()); + private final List consumerRecoveryListeners = Collections.synchronizedList(new ArrayList<>()); + private final List queueRecoveryListeners = Collections.synchronizedList(new ArrayList<>()); private final TopologyRecoveryFilter topologyRecoveryFilter; @@ -143,28 +143,7 @@ public void run() { } private TopologyRecoveryFilter letAllPassFilter() { - return new TopologyRecoveryFilter() { - - @Override - public boolean filterExchange(RecordedExchange recordedExchange) { - return true; - } - - @Override - public boolean filterQueue(RecordedQueue recordedQueue) { - return true; - } - - @Override - public boolean filterBinding(RecordedBinding recordedBinding) { - return true; - } - - @Override - public boolean filterConsumer(RecordedConsumer recordedConsumer) { - return true; - } - }; + return new TopologyRecoveryFilter() {}; } /** diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryFilter.java b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryFilter.java index 443866fbb8..d5f0ec9a26 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryFilter.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryFilter.java @@ -26,27 +26,35 @@ public interface TopologyRecoveryFilter { * @param recordedExchange * @return true to recover the exchange, false otherwise */ - boolean filterExchange(RecordedExchange recordedExchange); + default boolean filterExchange(RecordedExchange recordedExchange) { + return true; + } /** * Decides whether a queue is recovered or not. * @param recordedQueue * @return true to recover the queue, false otherwise */ - boolean filterQueue(RecordedQueue recordedQueue); + default boolean filterQueue(RecordedQueue recordedQueue) { + return true; + } /** * Decides whether a binding is recovered or not. * @param recordedBinding * @return true to recover the binding, false otherwise */ - boolean filterBinding(RecordedBinding recordedBinding); + default boolean filterBinding(RecordedBinding recordedBinding) { + return true; + } /** * Decides whether a consumer is recovered or not. * @param recordedConsumer * @return true to recover the consumer, false otherwise */ - boolean filterConsumer(RecordedConsumer recordedConsumer); + default boolean filterConsumer(RecordedConsumer recordedConsumer) { + return true; + } } diff --git a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java index 803fcf3cc9..480075258f 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java +++ b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java @@ -112,26 +112,18 @@ private static boolean resourceExists(Callable callback) throws Excepti } private static boolean queueExists(final String queue, final Connection connection) throws Exception { - return resourceExists(new Callable() { - - @Override - public Channel call() throws Exception { - Channel channel = connection.createChannel(); - channel.queueDeclarePassive(queue); - return channel; - } + return resourceExists(() -> { + Channel channel = connection.createChannel(); + channel.queueDeclarePassive(queue); + return channel; }); } private static boolean exchangeExists(final String exchange, final Connection connection) throws Exception { - return resourceExists(new Callable() { - - @Override - public Channel call() throws Exception { - Channel channel = connection.createChannel(); - channel.exchangeDeclarePassive(exchange); - return channel; - } + return resourceExists(() -> { + Channel channel = connection.createChannel(); + channel.exchangeDeclarePassive(exchange); + return channel; }); } From d2829282006355022785979b07fc7f73be3cc4c4 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Thu, 2 Aug 2018 18:48:15 +0300 Subject: [PATCH 0830/2114] Make sure Address.parseAddress can handle quoted IPv6 addresses Closes #385. [#159499428] --- .../java/com/rabbitmq/client/Address.java | 101 ++++++++++++++++-- .../com/rabbitmq/client/test/AddressTest.java | 90 ++++++++++++++++ 2 files changed, 184 insertions(+), 7 deletions(-) create mode 100644 src/test/java/com/rabbitmq/client/test/AddressTest.java diff --git a/src/main/java/com/rabbitmq/client/Address.java b/src/main/java/com/rabbitmq/client/Address.java index a0ebf8372d..c70ae34df7 100644 --- a/src/main/java/com/rabbitmq/client/Address.java +++ b/src/main/java/com/rabbitmq/client/Address.java @@ -16,18 +16,28 @@ package com.rabbitmq.client; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * A representation of network addresses, i.e. host/port pairs, * with some utility functions for parsing address strings. */ public class Address { - /** host name **/ + private static final Logger LOGGER = LoggerFactory.getLogger(Address.class); + + /** + * host name + **/ private final String _host; - /** port number **/ + /** + * port number + **/ private final int _port; /** * Construct an address from a host name and port number. + * * @param host the host name * @param port the port number */ @@ -38,6 +48,7 @@ public Address(String host, int port) { /** * Construct an address from a host. + * * @param host the host name */ public Address(String host) { @@ -47,6 +58,7 @@ public Address(String host) { /** * Get the host name + * * @return the host name */ public String getHost() { @@ -55,23 +67,98 @@ public String getHost() { /** * Get the port number + * * @return the port number */ public int getPort() { return _port; } + /** + * Extracts hostname or IP address from a string containing a hostname, IP address, + * hostname:port pair or IP address:port pair. + * Note that IPv6 addresses must be quoted with square brackets, e.g. [2001:db8:85a3:8d3:1319:8a2e:370:7348]. + * + * @param addressString the string to extract hostname from + * @return the hostname or IP address + */ + public static String parseHost(String addressString) { + // we need to handle cases such as [2001:db8:85a3:8d3:1319:8a2e:370:7348]:5671 + int lastColon = addressString.lastIndexOf(":"); + int lastClosingSquareBracket = addressString.lastIndexOf("]"); + if (lastClosingSquareBracket == -1) { + String[] parts = addressString.split(":"); + if (parts.length > 2) { + String msg = "Address " + + addressString + + " seems to contain an unquoted IPv6 address. Make sure you quote IPv6 addresses like so: [2001:db8:85a3:8d3:1319:8a2e:370:7348]"; + LOGGER.error(msg); + throw new IllegalArgumentException(msg); + } + + return parts[0]; + } + + if (lastClosingSquareBracket < lastColon) { + // there is a port + return addressString.substring(0, lastColon); + } else { + return addressString; + } + } + + public static int parsePort(String addressString) { + // we need to handle cases such as [2001:db8:85a3:8d3:1319:8a2e:370:7348]:5671 + int lastColon = addressString.lastIndexOf(":"); + int lastClosingSquareBracket = addressString.lastIndexOf("]"); + if (lastClosingSquareBracket == -1) { + String[] parts = addressString.split(":"); + if (parts.length > 2) { + String msg = "Address " + + addressString + + " seems to contain an unquoted IPv6 address. Make sure you quote IPv6 addresses like so: [2001:db8:85a3:8d3:1319:8a2e:370:7348]"; + LOGGER.error(msg); + throw new IllegalArgumentException(msg); + } + + if (parts.length == 2) { + return Integer.parseInt(parts[1]); + } + + return ConnectionFactory.USE_DEFAULT_PORT; + } + + if (lastClosingSquareBracket < lastColon) { + // there is a port + return Integer.parseInt(addressString.substring(lastColon + 1)); + } + + return ConnectionFactory.USE_DEFAULT_PORT; + } + + public static boolean isHostWithPort(String addressString) { + // we need to handle cases such as [2001:db8:85a3:8d3:1319:8a2e:370:7348]:5671 + int lastColon = addressString.lastIndexOf(":"); + int lastClosingSquareBracket = addressString.lastIndexOf("]"); + + if (lastClosingSquareBracket == -1) { + return addressString.contains(":"); + } else { + return lastClosingSquareBracket < lastColon; + } + } + /** * Factory method: takes a formatted addressString string as construction parameter * @param addressString an addressString of the form "host[:port]". * @return an {@link Address} from the given data */ public static Address parseAddress(String addressString) { - int idx = addressString.indexOf(':'); - return (idx == -1) ? - new Address(addressString) : - new Address(addressString.substring(0, idx), - Integer.parseInt(addressString.substring(idx+1))); + if (isHostWithPort(addressString)) { + return new Address(parseHost(addressString), parsePort(addressString)); + } else { + return new Address(addressString); + } } /** diff --git a/src/test/java/com/rabbitmq/client/test/AddressTest.java b/src/test/java/com/rabbitmq/client/test/AddressTest.java new file mode 100644 index 0000000000..a67bd96c86 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/AddressTest.java @@ -0,0 +1,90 @@ +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.test; + +import com.rabbitmq.client.Address; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * + */ +public class AddressTest { + + @Test public void isHostWithPort() { + assertTrue(Address.isHostWithPort("127.0.0.1:5672")); + assertTrue(Address.isHostWithPort("[1080:0:0:0:8:800:200C:417A]:5672")); + assertTrue(Address.isHostWithPort("[::1]:5672")); + + assertFalse(Address.isHostWithPort("127.0.0.1")); + assertFalse(Address.isHostWithPort("[1080:0:0:0:8:800:200C:417A]")); + assertFalse(Address.isHostWithPort("[::1]")); + } + + @Test public void parseHost() { + assertEquals("127.0.0.1", Address.parseHost("127.0.0.1:5672")); + assertEquals("[1080:0:0:0:8:800:200C:417A]", Address.parseHost("[1080:0:0:0:8:800:200C:417A]:5673")); + assertEquals("[::1]", Address.parseHost("[::1]:5672")); + + assertEquals("127.0.0.1", Address.parseHost("127.0.0.1")); + assertEquals("[1080:0:0:0:8:800:200C:417A]", Address.parseHost("[1080:0:0:0:8:800:200C:417A]")); + assertEquals("[::1]", Address.parseHost("[::1]")); + } + + @Test public void parsePort() { + assertEquals(5672, Address.parsePort("127.0.0.1:5672")); + assertEquals(5673, Address.parsePort("[1080:0:0:0:8:800:200C:417A]:5673")); + assertEquals(5672, Address.parsePort("[::1]:5672")); + + // "use default port" value + assertEquals(-1, Address.parsePort("127.0.0.1")); + assertEquals(-1, Address.parsePort("[1080:0:0:0:8:800:200C:417A]")); + assertEquals(-1, Address.parsePort("[::1]")); + } + + @Test public void parseIPv4() { + assertEquals(addr("192.168.1.10"), Address.parseAddress("192.168.1.10")); + assertEquals(addr("192.168.1.10", 5682), Address.parseAddress("192.168.1.10:5682")); + } + + @Test public void parseIPv6() { + // quoted IPv6 addresses without a port + assertEquals(addr("[1080:0:0:0:8:800:200C:417A]"), Address.parseAddress("[1080:0:0:0:8:800:200C:417A]")); + assertEquals(addr("[::1]"), Address.parseAddress("[::1]")); + + // quoted IPv6 addresses with a port + assertEquals(addr("[1080:0:0:0:8:800:200C:417A]", 5673), Address.parseAddress("[1080:0:0:0:8:800:200C:417A]:5673")); + assertEquals(addr("[::1]", 5673), Address.parseAddress("[::1]:5673")); + } + + @Test(expected = IllegalArgumentException.class) + public void parseUnquotedIPv6() { + // using a non-quoted IPv6 addresses with a port + Address.parseAddress("::1:5673"); + } + + private Address addr(String addr) { + return new Address(addr); + } + + private Address addr(String addr, int port) { + return new Address(addr, port); + } + +} From 1ba531b1bcbc26297200ea6f1c5e8f0b19ee5fe2 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Thu, 2 Aug 2018 18:48:15 +0300 Subject: [PATCH 0831/2114] Make sure Address.parseAddress can handle quoted IPv6 addresses Closes #385. [#159499428] (cherry picked from commit d2829282006355022785979b07fc7f73be3cc4c4) --- .../java/com/rabbitmq/client/Address.java | 101 ++++++++++++++++-- .../com/rabbitmq/client/test/AddressTest.java | 90 ++++++++++++++++ 2 files changed, 184 insertions(+), 7 deletions(-) create mode 100644 src/test/java/com/rabbitmq/client/test/AddressTest.java diff --git a/src/main/java/com/rabbitmq/client/Address.java b/src/main/java/com/rabbitmq/client/Address.java index a0ebf8372d..c70ae34df7 100644 --- a/src/main/java/com/rabbitmq/client/Address.java +++ b/src/main/java/com/rabbitmq/client/Address.java @@ -16,18 +16,28 @@ package com.rabbitmq.client; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * A representation of network addresses, i.e. host/port pairs, * with some utility functions for parsing address strings. */ public class Address { - /** host name **/ + private static final Logger LOGGER = LoggerFactory.getLogger(Address.class); + + /** + * host name + **/ private final String _host; - /** port number **/ + /** + * port number + **/ private final int _port; /** * Construct an address from a host name and port number. + * * @param host the host name * @param port the port number */ @@ -38,6 +48,7 @@ public Address(String host, int port) { /** * Construct an address from a host. + * * @param host the host name */ public Address(String host) { @@ -47,6 +58,7 @@ public Address(String host) { /** * Get the host name + * * @return the host name */ public String getHost() { @@ -55,23 +67,98 @@ public String getHost() { /** * Get the port number + * * @return the port number */ public int getPort() { return _port; } + /** + * Extracts hostname or IP address from a string containing a hostname, IP address, + * hostname:port pair or IP address:port pair. + * Note that IPv6 addresses must be quoted with square brackets, e.g. [2001:db8:85a3:8d3:1319:8a2e:370:7348]. + * + * @param addressString the string to extract hostname from + * @return the hostname or IP address + */ + public static String parseHost(String addressString) { + // we need to handle cases such as [2001:db8:85a3:8d3:1319:8a2e:370:7348]:5671 + int lastColon = addressString.lastIndexOf(":"); + int lastClosingSquareBracket = addressString.lastIndexOf("]"); + if (lastClosingSquareBracket == -1) { + String[] parts = addressString.split(":"); + if (parts.length > 2) { + String msg = "Address " + + addressString + + " seems to contain an unquoted IPv6 address. Make sure you quote IPv6 addresses like so: [2001:db8:85a3:8d3:1319:8a2e:370:7348]"; + LOGGER.error(msg); + throw new IllegalArgumentException(msg); + } + + return parts[0]; + } + + if (lastClosingSquareBracket < lastColon) { + // there is a port + return addressString.substring(0, lastColon); + } else { + return addressString; + } + } + + public static int parsePort(String addressString) { + // we need to handle cases such as [2001:db8:85a3:8d3:1319:8a2e:370:7348]:5671 + int lastColon = addressString.lastIndexOf(":"); + int lastClosingSquareBracket = addressString.lastIndexOf("]"); + if (lastClosingSquareBracket == -1) { + String[] parts = addressString.split(":"); + if (parts.length > 2) { + String msg = "Address " + + addressString + + " seems to contain an unquoted IPv6 address. Make sure you quote IPv6 addresses like so: [2001:db8:85a3:8d3:1319:8a2e:370:7348]"; + LOGGER.error(msg); + throw new IllegalArgumentException(msg); + } + + if (parts.length == 2) { + return Integer.parseInt(parts[1]); + } + + return ConnectionFactory.USE_DEFAULT_PORT; + } + + if (lastClosingSquareBracket < lastColon) { + // there is a port + return Integer.parseInt(addressString.substring(lastColon + 1)); + } + + return ConnectionFactory.USE_DEFAULT_PORT; + } + + public static boolean isHostWithPort(String addressString) { + // we need to handle cases such as [2001:db8:85a3:8d3:1319:8a2e:370:7348]:5671 + int lastColon = addressString.lastIndexOf(":"); + int lastClosingSquareBracket = addressString.lastIndexOf("]"); + + if (lastClosingSquareBracket == -1) { + return addressString.contains(":"); + } else { + return lastClosingSquareBracket < lastColon; + } + } + /** * Factory method: takes a formatted addressString string as construction parameter * @param addressString an addressString of the form "host[:port]". * @return an {@link Address} from the given data */ public static Address parseAddress(String addressString) { - int idx = addressString.indexOf(':'); - return (idx == -1) ? - new Address(addressString) : - new Address(addressString.substring(0, idx), - Integer.parseInt(addressString.substring(idx+1))); + if (isHostWithPort(addressString)) { + return new Address(parseHost(addressString), parsePort(addressString)); + } else { + return new Address(addressString); + } } /** diff --git a/src/test/java/com/rabbitmq/client/test/AddressTest.java b/src/test/java/com/rabbitmq/client/test/AddressTest.java new file mode 100644 index 0000000000..a67bd96c86 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/AddressTest.java @@ -0,0 +1,90 @@ +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.test; + +import com.rabbitmq.client.Address; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * + */ +public class AddressTest { + + @Test public void isHostWithPort() { + assertTrue(Address.isHostWithPort("127.0.0.1:5672")); + assertTrue(Address.isHostWithPort("[1080:0:0:0:8:800:200C:417A]:5672")); + assertTrue(Address.isHostWithPort("[::1]:5672")); + + assertFalse(Address.isHostWithPort("127.0.0.1")); + assertFalse(Address.isHostWithPort("[1080:0:0:0:8:800:200C:417A]")); + assertFalse(Address.isHostWithPort("[::1]")); + } + + @Test public void parseHost() { + assertEquals("127.0.0.1", Address.parseHost("127.0.0.1:5672")); + assertEquals("[1080:0:0:0:8:800:200C:417A]", Address.parseHost("[1080:0:0:0:8:800:200C:417A]:5673")); + assertEquals("[::1]", Address.parseHost("[::1]:5672")); + + assertEquals("127.0.0.1", Address.parseHost("127.0.0.1")); + assertEquals("[1080:0:0:0:8:800:200C:417A]", Address.parseHost("[1080:0:0:0:8:800:200C:417A]")); + assertEquals("[::1]", Address.parseHost("[::1]")); + } + + @Test public void parsePort() { + assertEquals(5672, Address.parsePort("127.0.0.1:5672")); + assertEquals(5673, Address.parsePort("[1080:0:0:0:8:800:200C:417A]:5673")); + assertEquals(5672, Address.parsePort("[::1]:5672")); + + // "use default port" value + assertEquals(-1, Address.parsePort("127.0.0.1")); + assertEquals(-1, Address.parsePort("[1080:0:0:0:8:800:200C:417A]")); + assertEquals(-1, Address.parsePort("[::1]")); + } + + @Test public void parseIPv4() { + assertEquals(addr("192.168.1.10"), Address.parseAddress("192.168.1.10")); + assertEquals(addr("192.168.1.10", 5682), Address.parseAddress("192.168.1.10:5682")); + } + + @Test public void parseIPv6() { + // quoted IPv6 addresses without a port + assertEquals(addr("[1080:0:0:0:8:800:200C:417A]"), Address.parseAddress("[1080:0:0:0:8:800:200C:417A]")); + assertEquals(addr("[::1]"), Address.parseAddress("[::1]")); + + // quoted IPv6 addresses with a port + assertEquals(addr("[1080:0:0:0:8:800:200C:417A]", 5673), Address.parseAddress("[1080:0:0:0:8:800:200C:417A]:5673")); + assertEquals(addr("[::1]", 5673), Address.parseAddress("[::1]:5673")); + } + + @Test(expected = IllegalArgumentException.class) + public void parseUnquotedIPv6() { + // using a non-quoted IPv6 addresses with a port + Address.parseAddress("::1:5673"); + } + + private Address addr(String addr) { + return new Address(addr); + } + + private Address addr(String addr, int port) { + return new Address(addr, port); + } + +} From 5677b79af00e8e39ccaf86e8e689b18f0de9a8f9 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Thu, 2 Aug 2018 18:48:15 +0300 Subject: [PATCH 0832/2114] Make sure Address.parseAddress can handle quoted IPv6 addresses Closes #385. [#159499428] (cherry picked from commit d2829282006355022785979b07fc7f73be3cc4c4) --- .../java/com/rabbitmq/client/Address.java | 101 ++++++++++++++++-- .../com/rabbitmq/client/test/AddressTest.java | 90 ++++++++++++++++ 2 files changed, 184 insertions(+), 7 deletions(-) create mode 100644 src/test/java/com/rabbitmq/client/test/AddressTest.java diff --git a/src/main/java/com/rabbitmq/client/Address.java b/src/main/java/com/rabbitmq/client/Address.java index a0ebf8372d..c70ae34df7 100644 --- a/src/main/java/com/rabbitmq/client/Address.java +++ b/src/main/java/com/rabbitmq/client/Address.java @@ -16,18 +16,28 @@ package com.rabbitmq.client; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * A representation of network addresses, i.e. host/port pairs, * with some utility functions for parsing address strings. */ public class Address { - /** host name **/ + private static final Logger LOGGER = LoggerFactory.getLogger(Address.class); + + /** + * host name + **/ private final String _host; - /** port number **/ + /** + * port number + **/ private final int _port; /** * Construct an address from a host name and port number. + * * @param host the host name * @param port the port number */ @@ -38,6 +48,7 @@ public Address(String host, int port) { /** * Construct an address from a host. + * * @param host the host name */ public Address(String host) { @@ -47,6 +58,7 @@ public Address(String host) { /** * Get the host name + * * @return the host name */ public String getHost() { @@ -55,23 +67,98 @@ public String getHost() { /** * Get the port number + * * @return the port number */ public int getPort() { return _port; } + /** + * Extracts hostname or IP address from a string containing a hostname, IP address, + * hostname:port pair or IP address:port pair. + * Note that IPv6 addresses must be quoted with square brackets, e.g. [2001:db8:85a3:8d3:1319:8a2e:370:7348]. + * + * @param addressString the string to extract hostname from + * @return the hostname or IP address + */ + public static String parseHost(String addressString) { + // we need to handle cases such as [2001:db8:85a3:8d3:1319:8a2e:370:7348]:5671 + int lastColon = addressString.lastIndexOf(":"); + int lastClosingSquareBracket = addressString.lastIndexOf("]"); + if (lastClosingSquareBracket == -1) { + String[] parts = addressString.split(":"); + if (parts.length > 2) { + String msg = "Address " + + addressString + + " seems to contain an unquoted IPv6 address. Make sure you quote IPv6 addresses like so: [2001:db8:85a3:8d3:1319:8a2e:370:7348]"; + LOGGER.error(msg); + throw new IllegalArgumentException(msg); + } + + return parts[0]; + } + + if (lastClosingSquareBracket < lastColon) { + // there is a port + return addressString.substring(0, lastColon); + } else { + return addressString; + } + } + + public static int parsePort(String addressString) { + // we need to handle cases such as [2001:db8:85a3:8d3:1319:8a2e:370:7348]:5671 + int lastColon = addressString.lastIndexOf(":"); + int lastClosingSquareBracket = addressString.lastIndexOf("]"); + if (lastClosingSquareBracket == -1) { + String[] parts = addressString.split(":"); + if (parts.length > 2) { + String msg = "Address " + + addressString + + " seems to contain an unquoted IPv6 address. Make sure you quote IPv6 addresses like so: [2001:db8:85a3:8d3:1319:8a2e:370:7348]"; + LOGGER.error(msg); + throw new IllegalArgumentException(msg); + } + + if (parts.length == 2) { + return Integer.parseInt(parts[1]); + } + + return ConnectionFactory.USE_DEFAULT_PORT; + } + + if (lastClosingSquareBracket < lastColon) { + // there is a port + return Integer.parseInt(addressString.substring(lastColon + 1)); + } + + return ConnectionFactory.USE_DEFAULT_PORT; + } + + public static boolean isHostWithPort(String addressString) { + // we need to handle cases such as [2001:db8:85a3:8d3:1319:8a2e:370:7348]:5671 + int lastColon = addressString.lastIndexOf(":"); + int lastClosingSquareBracket = addressString.lastIndexOf("]"); + + if (lastClosingSquareBracket == -1) { + return addressString.contains(":"); + } else { + return lastClosingSquareBracket < lastColon; + } + } + /** * Factory method: takes a formatted addressString string as construction parameter * @param addressString an addressString of the form "host[:port]". * @return an {@link Address} from the given data */ public static Address parseAddress(String addressString) { - int idx = addressString.indexOf(':'); - return (idx == -1) ? - new Address(addressString) : - new Address(addressString.substring(0, idx), - Integer.parseInt(addressString.substring(idx+1))); + if (isHostWithPort(addressString)) { + return new Address(parseHost(addressString), parsePort(addressString)); + } else { + return new Address(addressString); + } } /** diff --git a/src/test/java/com/rabbitmq/client/test/AddressTest.java b/src/test/java/com/rabbitmq/client/test/AddressTest.java new file mode 100644 index 0000000000..a67bd96c86 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/AddressTest.java @@ -0,0 +1,90 @@ +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.test; + +import com.rabbitmq.client.Address; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * + */ +public class AddressTest { + + @Test public void isHostWithPort() { + assertTrue(Address.isHostWithPort("127.0.0.1:5672")); + assertTrue(Address.isHostWithPort("[1080:0:0:0:8:800:200C:417A]:5672")); + assertTrue(Address.isHostWithPort("[::1]:5672")); + + assertFalse(Address.isHostWithPort("127.0.0.1")); + assertFalse(Address.isHostWithPort("[1080:0:0:0:8:800:200C:417A]")); + assertFalse(Address.isHostWithPort("[::1]")); + } + + @Test public void parseHost() { + assertEquals("127.0.0.1", Address.parseHost("127.0.0.1:5672")); + assertEquals("[1080:0:0:0:8:800:200C:417A]", Address.parseHost("[1080:0:0:0:8:800:200C:417A]:5673")); + assertEquals("[::1]", Address.parseHost("[::1]:5672")); + + assertEquals("127.0.0.1", Address.parseHost("127.0.0.1")); + assertEquals("[1080:0:0:0:8:800:200C:417A]", Address.parseHost("[1080:0:0:0:8:800:200C:417A]")); + assertEquals("[::1]", Address.parseHost("[::1]")); + } + + @Test public void parsePort() { + assertEquals(5672, Address.parsePort("127.0.0.1:5672")); + assertEquals(5673, Address.parsePort("[1080:0:0:0:8:800:200C:417A]:5673")); + assertEquals(5672, Address.parsePort("[::1]:5672")); + + // "use default port" value + assertEquals(-1, Address.parsePort("127.0.0.1")); + assertEquals(-1, Address.parsePort("[1080:0:0:0:8:800:200C:417A]")); + assertEquals(-1, Address.parsePort("[::1]")); + } + + @Test public void parseIPv4() { + assertEquals(addr("192.168.1.10"), Address.parseAddress("192.168.1.10")); + assertEquals(addr("192.168.1.10", 5682), Address.parseAddress("192.168.1.10:5682")); + } + + @Test public void parseIPv6() { + // quoted IPv6 addresses without a port + assertEquals(addr("[1080:0:0:0:8:800:200C:417A]"), Address.parseAddress("[1080:0:0:0:8:800:200C:417A]")); + assertEquals(addr("[::1]"), Address.parseAddress("[::1]")); + + // quoted IPv6 addresses with a port + assertEquals(addr("[1080:0:0:0:8:800:200C:417A]", 5673), Address.parseAddress("[1080:0:0:0:8:800:200C:417A]:5673")); + assertEquals(addr("[::1]", 5673), Address.parseAddress("[::1]:5673")); + } + + @Test(expected = IllegalArgumentException.class) + public void parseUnquotedIPv6() { + // using a non-quoted IPv6 addresses with a port + Address.parseAddress("::1:5673"); + } + + private Address addr(String addr) { + return new Address(addr); + } + + private Address addr(String addr, int port) { + return new Address(addr, port); + } + +} From 77b97472ce70c82cedeee6759204fce31013d87e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 3 Aug 2018 14:20:05 +0200 Subject: [PATCH 0833/2114] Add AddressTest to test suite --- src/test/java/com/rabbitmq/client/test/ClientTests.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index 0500dd75b1..c63145f445 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -57,7 +57,8 @@ ClientVersionTest.class, StrictExceptionHandlerTest.class, NoAutoRecoveryWhenTcpWindowIsFullTest.class, - JsonRpcTest.class + JsonRpcTest.class, + AddressTest.class }) public class ClientTests { From 34e33ea80b9c71dfc0b2cb929b40e707e6e0fcac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 7 Aug 2018 11:23:21 +0200 Subject: [PATCH 0834/2114] Add optional retry logic to topology recovery There's no topology recovery retry by default. The default implementation is composable: not all have the recoverable entities have to retry and the retry operations don't have to be only the corresponding entity recovery, but also other operations, like recovering the corresponding channel. Fixes #387 --- .../rabbitmq/client/ConnectionFactory.java | 18 ++ .../client/impl/ConnectionParams.java | 9 + .../recovery/AutorecoveringConnection.java | 109 ++++++-- .../client/impl/recovery/BackoffPolicy.java | 34 +++ .../impl/recovery/DefaultRetryHandler.java | 131 +++++++++ .../client/impl/recovery/RetryContext.java | 99 +++++++ .../client/impl/recovery/RetryHandler.java | 62 +++++ .../client/impl/recovery/RetryResult.java | 57 ++++ .../TopologyRecoveryRetryHandlerBuilder.java | 115 ++++++++ .../recovery/TopologyRecoveryRetryLogic.java | 85 ++++++ .../com/rabbitmq/client/test/ClientTests.java | 3 +- .../client/test/DefaultRetryHandlerTest.java | 257 ++++++++++++++++++ .../com/rabbitmq/client/test/TestUtils.java | 120 +++++++- .../test/functional/ConnectionRecovery.java | 36 +-- .../test/functional/FunctionalTests.java | 3 +- .../functional/TopologyRecoveryFiltering.java | 103 +------ .../functional/TopologyRecoveryRetry.java | 70 +++++ src/test/java/com/rabbitmq/tools/Host.java | 4 + 18 files changed, 1160 insertions(+), 155 deletions(-) create mode 100644 src/main/java/com/rabbitmq/client/impl/recovery/BackoffPolicy.java create mode 100644 src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java create mode 100644 src/main/java/com/rabbitmq/client/impl/recovery/RetryContext.java create mode 100644 src/main/java/com/rabbitmq/client/impl/recovery/RetryHandler.java create mode 100644 src/main/java/com/rabbitmq/client/impl/recovery/RetryResult.java create mode 100644 src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryHandlerBuilder.java create mode 100644 src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java create mode 100644 src/test/java/com/rabbitmq/client/test/DefaultRetryHandlerTest.java create mode 100644 src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index a35a55f64d..0816abdde3 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -29,6 +29,7 @@ import com.rabbitmq.client.impl.nio.NioParams; import com.rabbitmq.client.impl.nio.SocketChannelFrameHandlerFactory; import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; +import com.rabbitmq.client.impl.recovery.RetryHandler; import com.rabbitmq.client.impl.recovery.TopologyRecoveryFilter; import java.io.IOException; @@ -192,6 +193,13 @@ public class ConnectionFactory implements Cloneable { */ private Predicate connectionRecoveryTriggeringCondition; + /** + * Retry handler for topology recovery. + * Default is no retry. + * @since 5.4.0 + */ + private RetryHandler topologyRecoveryRetryHandler; + /** @return the default host to use for connections */ public String getHost() { return host; @@ -1087,6 +1095,7 @@ public ConnectionParams params(ExecutorService consumerWorkServiceExecutor) { result.setErrorOnWriteListener(errorOnWriteListener); result.setTopologyRecoveryFilter(topologyRecoveryFilter); result.setConnectionRecoveryTriggeringCondition(connectionRecoveryTriggeringCondition); + result.setTopologyRecoveryRetryHandler(topologyRecoveryRetryHandler); return result; } @@ -1454,4 +1463,13 @@ public void setConnectionRecoveryTriggeringCondition(Predicate connectionRecoveryTriggeringCondition; + private RetryHandler topologyRecoveryRetryHandler; private ExceptionHandler exceptionHandler; private ThreadFactory threadFactory; @@ -257,4 +259,11 @@ public Predicate getConnectionRecoveryTriggeringConditi return connectionRecoveryTriggeringCondition; } + public void setTopologyRecoveryRetryHandler(RetryHandler topologyRecoveryRetryHandler) { + this.topologyRecoveryRetryHandler = topologyRecoveryRetryHandler; + } + + public RetryHandler getTopologyRecoveryRetryHandler() { + return topologyRecoveryRetryHandler; + } } diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index 9223cb11aa..c3e66e0d2f 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -95,6 +95,8 @@ public class AutorecoveringConnection implements RecoverableConnection, NetworkC private final Predicate connectionRecoveryTriggeringCondition; + private final RetryHandler retryHandler; + public AutorecoveringConnection(ConnectionParams params, FrameHandlerFactory f, List
addrs) { this(params, f, new ListAddressResolver(addrs)); } @@ -115,6 +117,8 @@ public AutorecoveringConnection(ConnectionParams params, FrameHandlerFactory f, this.channels = new ConcurrentHashMap<>(); this.topologyRecoveryFilter = params.getTopologyRecoveryFilter() == null ? letAllPassFilter() : params.getTopologyRecoveryFilter(); + + this.retryHandler = params.getTopologyRecoveryRetryHandler(); } private void setupErrorOnWriteListenerForPotentialRecovery() { @@ -125,12 +129,9 @@ private void setupErrorOnWriteListenerForPotentialRecovery() { // we should trigger the error handling and the recovery only once if (errorOnWriteLock.tryLock()) { try { - Thread recoveryThread = threadFactory.newThread(new Runnable() { - @Override - public void run() { - AMQConnection c = (AMQConnection) connection; - c.handleIoError(exception); - } + Thread recoveryThread = threadFactory.newThread(() -> { + AMQConnection c = (AMQConnection) connection; + c.handleIoError(exception); }); recoveryThread.setName("RabbitMQ Error On Write Thread"); recoveryThread.start(); @@ -630,6 +631,10 @@ private void recoverChannels(final RecoveryAwareAMQConnection newConn) { } } + void recoverChannel(AutorecoveringChannel channel) throws IOException { + channel.automaticallyRecover(this, this.delegate); + } + private void notifyRecoveryListenersComplete() { for (RecoveryListener f : Utility.copy(this.recoveryListeners)) { f.handleRecovery(this); @@ -651,16 +656,16 @@ private void recoverTopology(final ExecutorService executor) { if (executor == null) { // recover entities in serial on the main connection thread for (final RecordedExchange exchange : Utility.copy(recordedExchanges).values()) { - recoverExchange(exchange); + recoverExchange(exchange, true); } for (final Map.Entry entry : Utility.copy(recordedQueues).entrySet()) { - recoverQueue(entry.getKey(), entry.getValue()); + recoverQueue(entry.getKey(), entry.getValue(), true); } for (final RecordedBinding b : Utility.copy(recordedBindings)) { - recoverBinding(b); + recoverBinding(b, true); } for (final Map.Entry entry : Utility.copy(consumers).entrySet()) { - recoverConsumer(entry.getKey(), entry.getValue()); + recoverConsumer(entry.getKey(), entry.getValue(), true); } } else { // Support recovering entities in parallel for connections that have a lot of queues, bindings, & consumers @@ -680,11 +685,19 @@ private void recoverTopology(final ExecutorService executor) { } } - private void recoverExchange(final RecordedExchange x) { + private void recoverExchange(RecordedExchange x, boolean retry) { // recorded exchanges are guaranteed to be non-predefined (we filter out predefined ones in exchangeDeclare). MK. try { if (topologyRecoveryFilter.filterExchange(x)) { - x.recover(); + if (retry) { + final RecordedExchange entity = x; + x = (RecordedExchange) wrapRetryIfNecessary(x, () -> { + entity.recover(); + return null; + }).getRecordedEntity(); + } else { + x.recover(); + } LOGGER.debug("{} has recovered", x); } } catch (Exception cause) { @@ -695,12 +708,20 @@ private void recoverExchange(final RecordedExchange x) { } } - private void recoverQueue(final String oldName, final RecordedQueue q) { + void recoverQueue(final String oldName, RecordedQueue q, boolean retry) { try { if (topologyRecoveryFilter.filterQueue(q)) { LOGGER.debug("Recovering {}", q); - q.recover(); + if (retry) { + final RecordedQueue entity = q; + q = (RecordedQueue) wrapRetryIfNecessary(q, () -> { + entity.recover(); + return null; + }).getRecordedEntity(); + } else { + q.recover(); + } String newName = q.getName(); if (!oldName.equals(newName)) { // make sure server-named queues are re-added with @@ -731,10 +752,18 @@ private void recoverQueue(final String oldName, final RecordedQueue q) { } } - private void recoverBinding(final RecordedBinding b) { + private void recoverBinding(RecordedBinding b, boolean retry) { try { if (this.topologyRecoveryFilter.filterBinding(b)) { - b.recover(); + if (retry) { + final RecordedBinding entity = b; + b = (RecordedBinding) wrapRetryIfNecessary(b, () -> { + entity.recover(); + return null; + }).getRecordedEntity(); + } else { + b.recover(); + } LOGGER.debug("{} has recovered", b); } } catch (Exception cause) { @@ -745,11 +774,20 @@ private void recoverBinding(final RecordedBinding b) { } } - private void recoverConsumer(final String tag, final RecordedConsumer consumer) { + private void recoverConsumer(final String tag, RecordedConsumer consumer, boolean retry) { try { if (this.topologyRecoveryFilter.filterConsumer(consumer)) { LOGGER.debug("Recovering {}", consumer); - String newTag = consumer.recover(); + String newTag = null; + if (retry) { + final RecordedConsumer entity = consumer; + RetryResult retryResult = wrapRetryIfNecessary(consumer, () -> entity.recover()); + consumer = (RecordedConsumer) retryResult.getRecordedEntity(); + newTag = (String) retryResult.getResult(); + } else { + newTag = consumer.recover(); + } + // make sure server-generated tags are re-added. MK. if(tag != null && !tag.equals(newTag)) { synchronized (this.consumers) { @@ -772,6 +810,33 @@ private void recoverConsumer(final String tag, final RecordedConsumer consumer) } } + private RetryResult wrapRetryIfNecessary(RecordedEntity entity, Callable recoveryAction) throws Exception { + if (this.retryHandler == null) { + T result = recoveryAction.call(); + return new RetryResult(entity, result); + } else { + try { + T result = recoveryAction.call(); + return new RetryResult(entity, result); + } catch (Exception e) { + RetryContext retryContext = new RetryContext(entity, e, this); + RetryResult retryResult; + if (entity instanceof RecordedQueue) { + retryResult = this.retryHandler.retryQueueRecovery(retryContext); + } else if (entity instanceof RecordedExchange) { + retryResult = this.retryHandler.retryExchangeRecovery(retryContext); + } else if (entity instanceof RecordedBinding) { + retryResult = this.retryHandler.retryBindingRecovery(retryContext); + } else if (entity instanceof RecordedConsumer) { + retryResult = this.retryHandler.retryConsumerRecovery(retryContext); + } else { + throw new IllegalArgumentException("Unknown type of recorded entity: " + entity); + } + return retryResult; + } + } + } + private void propagateQueueNameChangeToBindings(String oldName, String newName) { for (RecordedBinding b : Utility.copy(this.recordedBindings)) { if (b.getDestination().equals(oldName)) { @@ -820,15 +885,15 @@ private List> groupEntitiesByChannel callables.add(Executors.callable(() -> { for (final E entity : entityList) { if (entity instanceof RecordedExchange) { - recoverExchange((RecordedExchange)entity); + recoverExchange((RecordedExchange)entity, true); } else if (entity instanceof RecordedQueue) { final RecordedQueue q = (RecordedQueue) entity; - recoverQueue(q.getName(), q); + recoverQueue(q.getName(), q, true); } else if (entity instanceof RecordedBinding) { - recoverBinding((RecordedBinding) entity); + recoverBinding((RecordedBinding) entity, true); } else if (entity instanceof RecordedConsumer) { final RecordedConsumer c = (RecordedConsumer) entity; - recoverConsumer(c.getConsumerTag(), c); + recoverConsumer(c.getConsumerTag(), c, true); } } })); diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/BackoffPolicy.java b/src/main/java/com/rabbitmq/client/impl/recovery/BackoffPolicy.java new file mode 100644 index 0000000000..a05c2a8a3c --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/recovery/BackoffPolicy.java @@ -0,0 +1,34 @@ +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl.recovery; + +/** + * Backoff policy for topology recovery retry attempts. + * + * @see DefaultRetryHandler + * @see TopologyRecoveryRetryHandlerBuilder + * @since 5.4.0 + */ +@FunctionalInterface +public interface BackoffPolicy { + + /** + * Wait depending on the current attempt number (1, 2, 3, etc) + * @param attemptNumber current attempt number + * @throws InterruptedException + */ + void backoff(int attemptNumber) throws InterruptedException; +} diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java b/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java new file mode 100644 index 0000000000..8c9b1df3fd --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java @@ -0,0 +1,131 @@ +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl.recovery; + +import java.util.Objects; +import java.util.function.BiPredicate; + +/** + * Composable topology recovery retry handler. + * This retry handler implementations let the user choose the condition + * to trigger retry and the retry operation for each type of recoverable + * entities. The number of attempts and the backoff policy (time to wait + * between retries) are also configurable. + *

+ * See also {@link TopologyRecoveryRetryHandlerBuilder} to easily create + * instances and {@link TopologyRecoveryRetryLogic} for ready-to-use + * conditions and operations. + * + * @see TopologyRecoveryRetryHandlerBuilder + * @see TopologyRecoveryRetryLogic + * @since 5.4.0 + */ +public class DefaultRetryHandler implements RetryHandler { + + private final BiPredicate queueRecoveryRetryCondition; + private final BiPredicate exchangeRecoveryRetryCondition; + private final BiPredicate bindingRecoveryRetryCondition; + private final BiPredicate consumerRecoveryRetryCondition; + + private final RetryOperation queueRecoveryRetryOperation; + private final RetryOperation exchangeRecoveryRetryOperation; + private final RetryOperation bindingRecoveryRetryOperation; + private final RetryOperation consumerRecoveryRetryOperation; + + private final int retryAttempts; + + private final BackoffPolicy backoffPolicy; + + public DefaultRetryHandler(BiPredicate queueRecoveryRetryCondition, + BiPredicate exchangeRecoveryRetryCondition, + BiPredicate bindingRecoveryRetryCondition, + BiPredicate consumerRecoveryRetryCondition, + RetryOperation queueRecoveryRetryOperation, + RetryOperation exchangeRecoveryRetryOperation, + RetryOperation bindingRecoveryRetryOperation, + RetryOperation consumerRecoveryRetryOperation, int retryAttempts, BackoffPolicy backoffPolicy) { + this.queueRecoveryRetryCondition = queueRecoveryRetryCondition; + this.exchangeRecoveryRetryCondition = exchangeRecoveryRetryCondition; + this.bindingRecoveryRetryCondition = bindingRecoveryRetryCondition; + this.consumerRecoveryRetryCondition = consumerRecoveryRetryCondition; + this.queueRecoveryRetryOperation = queueRecoveryRetryOperation; + this.exchangeRecoveryRetryOperation = exchangeRecoveryRetryOperation; + this.bindingRecoveryRetryOperation = bindingRecoveryRetryOperation; + this.consumerRecoveryRetryOperation = consumerRecoveryRetryOperation; + this.backoffPolicy = backoffPolicy; + if (retryAttempts <= 0) { + throw new IllegalArgumentException("Number of retry attempts must be greater than 0"); + } + this.retryAttempts = retryAttempts; + } + + @Override + public RetryResult retryQueueRecovery(RetryContext context) throws Exception { + return doRetry(queueRecoveryRetryCondition, queueRecoveryRetryOperation, context.queue(), context); + } + + @Override + public RetryResult retryExchangeRecovery(RetryContext context) throws Exception { + return doRetry(exchangeRecoveryRetryCondition, exchangeRecoveryRetryOperation, context.exchange(), context); + } + + @Override + public RetryResult retryBindingRecovery(RetryContext context) throws Exception { + return doRetry(bindingRecoveryRetryCondition, bindingRecoveryRetryOperation, context.binding(), context); + } + + @Override + public RetryResult retryConsumerRecovery(RetryContext context) throws Exception { + return doRetry(consumerRecoveryRetryCondition, consumerRecoveryRetryOperation, context.consumer(), context); + } + + protected RetryResult doRetry(BiPredicate condition, RetryOperation operation, T entity, RetryContext context) + throws Exception { + int attempts = 0; + Exception exception = context.exception(); + while (attempts < retryAttempts) { + if (condition.test(entity, exception)) { + backoffPolicy.backoff(attempts + 1); + try { + Object result = operation.call(context); + return new RetryResult( + entity, result == null ? null : result.toString() + ); + } catch (Exception e) { + exception = e; + attempts++; + continue; + } + } else { + throw exception; + } + } + throw context.exception(); + } + + public interface RetryOperation { + + T call(RetryContext context) throws Exception; + + default RetryOperation andThen(RetryOperation after) { + Objects.requireNonNull(after); + return (context) -> { + call(context); + return after.call(context); + }; + } + } +} diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RetryContext.java b/src/main/java/com/rabbitmq/client/impl/recovery/RetryContext.java new file mode 100644 index 0000000000..a9bdc05e5f --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RetryContext.java @@ -0,0 +1,99 @@ +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl.recovery; + +/** + * The context of a topology recovery retry operation. + * + * @since 5.4.0 + */ +public class RetryContext { + + private final RecordedEntity entity; + + private final Exception exception; + + private final AutorecoveringConnection connection; + + public RetryContext(RecordedEntity entity, Exception exception, AutorecoveringConnection connection) { + this.entity = entity; + this.exception = exception; + this.connection = connection; + } + + /** + * The underlying connection. + * + * @return + */ + public AutorecoveringConnection connection() { + return connection; + } + + /** + * The exception that triggered the retry attempt. + * + * @return + */ + public Exception exception() { + return exception; + } + + /** + * The to-be-recovered entity. + * + * @return + */ + public RecordedEntity entity() { + return entity; + } + + /** + * The to-be-recovered entity as a queue. + * + * @return + */ + public RecordedQueue queue() { + return (RecordedQueue) entity; + } + + /** + * The to-be-recovered entity as an exchange. + * + * @return + */ + public RecordedExchange exchange() { + return (RecordedExchange) entity; + } + + /** + * The to-be-recovered entity as a binding. + * + * @return + */ + public RecordedBinding binding() { + return (RecordedBinding) entity; + } + + /** + * The to-be-recovered entity as a consumer. + * + * @return + */ + public RecordedConsumer consumer() { + return (RecordedConsumer) entity; + } +} diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RetryHandler.java b/src/main/java/com/rabbitmq/client/impl/recovery/RetryHandler.java new file mode 100644 index 0000000000..5ed7f823f0 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RetryHandler.java @@ -0,0 +1,62 @@ +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl.recovery; + +/** + * Contract to retry failed operations during topology recovery. + * Not all operations have to be retried, it's a decision of the + * underlying implementation. + * + * @since 5.4.0 + */ +public interface RetryHandler { + + /** + * Retry a failed queue recovery operation. + * + * @param context the context of the retry + * @return the result of the retry attempt + * @throws Exception if the retry fails + */ + RetryResult retryQueueRecovery(RetryContext context) throws Exception; + + /** + * Retry a failed exchange recovery operation. + * + * @param context the context of the retry + * @return the result of the retry attempt + * @throws Exception if the retry fails + */ + RetryResult retryExchangeRecovery(RetryContext context) throws Exception; + + /** + * Retry a failed binding recovery operation. + * + * @param context the context of the retry + * @return the result of the retry attempt + * @throws Exception if the retry fails + */ + RetryResult retryBindingRecovery(RetryContext context) throws Exception; + + /** + * Retry a failed consumer recovery operation. + * + * @param context the context of the retry + * @return the result of the retry attempt + * @throws Exception if the retry fails + */ + RetryResult retryConsumerRecovery(RetryContext context) throws Exception; +} diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RetryResult.java b/src/main/java/com/rabbitmq/client/impl/recovery/RetryResult.java new file mode 100644 index 0000000000..c4797c39bf --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RetryResult.java @@ -0,0 +1,57 @@ +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl.recovery; + +/** + * The retry of a retried topology recovery operation. + * + * @since 5.4.0 + */ +public class RetryResult { + + /** + * The entity to recover. + */ + private final RecordedEntity recordedEntity; + + /** + * The result of the recovery operation. + * E.g. a consumer tag when recovering a consumer. + */ + private final Object result; + + public RetryResult(RecordedEntity recordedEntity, Object result) { + this.recordedEntity = recordedEntity; + this.result = result; + } + + /** + * The entity to recover. + * + * @return + */ + public RecordedEntity getRecordedEntity() { + return recordedEntity; + } + + /** + * The result of the recovery operation. + * E.g. a consumer tag when recovering a consumer. + */ + public Object getResult() { + return result; + } +} diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryHandlerBuilder.java b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryHandlerBuilder.java new file mode 100644 index 0000000000..07141b43e5 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryHandlerBuilder.java @@ -0,0 +1,115 @@ +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl.recovery; + +import java.util.function.BiPredicate; + +/** + * Builder to ease creation of {@link DefaultRetryHandler} instances. + *

+ * Just override what you need. By default, retry conditions don't trigger retry, + * retry operations are no-op, the number of retry attempts is 1, and the backoff + * policy doesn't wait at all. + * + * @see DefaultRetryHandler + * @see TopologyRecoveryRetryLogic + * @since 5.4.0 + */ +public class TopologyRecoveryRetryHandlerBuilder { + + private BiPredicate queueRecoveryRetryCondition = (q, e) -> false; + private BiPredicate exchangeRecoveryRetryCondition = (ex, e) -> false; + private BiPredicate bindingRecoveryRetryCondition = (b, e) -> false; + private BiPredicate consumerRecoveryRetryCondition = (c, e) -> false; + + private DefaultRetryHandler.RetryOperation queueRecoveryRetryOperation = context -> null; + private DefaultRetryHandler.RetryOperation exchangeRecoveryRetryOperation = context -> null; + private DefaultRetryHandler.RetryOperation bindingRecoveryRetryOperation = context -> null; + private DefaultRetryHandler.RetryOperation consumerRecoveryRetryOperation = context -> null; + + private int retryAttempts = 1; + + private BackoffPolicy backoffPolicy = nbAttempts -> { + }; + + public static TopologyRecoveryRetryHandlerBuilder builder() { + return new TopologyRecoveryRetryHandlerBuilder(); + } + + public TopologyRecoveryRetryHandlerBuilder queueRecoveryRetryCondition( + BiPredicate queueRecoveryRetryCondition) { + this.queueRecoveryRetryCondition = queueRecoveryRetryCondition; + return this; + } + + public TopologyRecoveryRetryHandlerBuilder exchangeRecoveryRetryCondition( + BiPredicate exchangeRecoveryRetryCondition) { + this.exchangeRecoveryRetryCondition = exchangeRecoveryRetryCondition; + return this; + } + + public TopologyRecoveryRetryHandlerBuilder bindingRecoveryRetryCondition( + BiPredicate bindingRecoveryRetryCondition) { + this.bindingRecoveryRetryCondition = bindingRecoveryRetryCondition; + return this; + } + + public TopologyRecoveryRetryHandlerBuilder consumerRecoveryRetryCondition( + BiPredicate consumerRecoveryRetryCondition) { + this.consumerRecoveryRetryCondition = consumerRecoveryRetryCondition; + return this; + } + + public TopologyRecoveryRetryHandlerBuilder queueRecoveryRetryOperation(DefaultRetryHandler.RetryOperation queueRecoveryRetryOperation) { + this.queueRecoveryRetryOperation = queueRecoveryRetryOperation; + return this; + } + + public TopologyRecoveryRetryHandlerBuilder exchangeRecoveryRetryOperation(DefaultRetryHandler.RetryOperation exchangeRecoveryRetryOperation) { + this.exchangeRecoveryRetryOperation = exchangeRecoveryRetryOperation; + return this; + } + + public TopologyRecoveryRetryHandlerBuilder bindingRecoveryRetryOperation(DefaultRetryHandler.RetryOperation bindingRecoveryRetryOperation) { + this.bindingRecoveryRetryOperation = bindingRecoveryRetryOperation; + return this; + } + + public TopologyRecoveryRetryHandlerBuilder consumerRecoveryRetryOperation(DefaultRetryHandler.RetryOperation consumerRecoveryRetryOperation) { + this.consumerRecoveryRetryOperation = consumerRecoveryRetryOperation; + return this; + } + + public TopologyRecoveryRetryHandlerBuilder backoffPolicy(BackoffPolicy backoffPolicy) { + this.backoffPolicy = backoffPolicy; + return this; + } + + public TopologyRecoveryRetryHandlerBuilder retryAttempts(int retryAttempts) { + this.retryAttempts = retryAttempts; + return this; + } + + public RetryHandler build() { + return new DefaultRetryHandler( + queueRecoveryRetryCondition, exchangeRecoveryRetryCondition, + bindingRecoveryRetryCondition, consumerRecoveryRetryCondition, + queueRecoveryRetryOperation, exchangeRecoveryRetryOperation, + bindingRecoveryRetryOperation, consumerRecoveryRetryOperation, + retryAttempts, + backoffPolicy); + } +} diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java new file mode 100644 index 0000000000..8e6e16a790 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java @@ -0,0 +1,85 @@ +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl.recovery; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.ShutdownSignalException; + +import java.util.function.Predicate; + +/** + * Useful ready-to-use conditions and operations for {@link DefaultRetryHandler}. + * They're composed and used with the {@link TopologyRecoveryRetryHandlerBuilder}. + * + * @see DefaultRetryHandler + * @see RetryHandler + * @see TopologyRecoveryRetryHandlerBuilder + * @since 5.4.0 + */ +public abstract class TopologyRecoveryRetryLogic { + + public static final Predicate CHANNEL_CLOSED_NOT_FOUND = e -> { + if (e.getCause() instanceof ShutdownSignalException) { + ShutdownSignalException cause = (ShutdownSignalException) e.getCause(); + if (cause.getReason() instanceof AMQP.Channel.Close) { + return ((AMQP.Channel.Close) cause.getReason()).getReplyCode() == 404; + } + } + return false; + }; + + public static final DefaultRetryHandler.RetryOperation RECOVER_CHANNEL = context -> { + if (!context.entity().getChannel().isOpen()) { + context.connection().recoverChannel(context.entity().getChannel()); + } + return null; + }; + + public static final DefaultRetryHandler.RetryOperation RECOVER_BINDING_QUEUE = context -> { + if (context.entity() instanceof RecordedQueueBinding) { + RecordedBinding binding = context.binding(); + AutorecoveringConnection connection = context.connection(); + RecordedQueue recordedQueue = connection.getRecordedQueues().get(binding.getDestination()); + if (recordedQueue != null) { + connection.recoverQueue( + recordedQueue.getName(), recordedQueue, false + ); + } + } + return null; + }; + + public static final DefaultRetryHandler.RetryOperation RECOVER_BINDING = context -> { + context.binding().recover(); + return null; + }; + + public static final DefaultRetryHandler.RetryOperation RECOVER_CONSUMER_QUEUE = context -> { + if (context.entity() instanceof RecordedConsumer) { + RecordedConsumer consumer = context.consumer(); + AutorecoveringConnection connection = context.connection(); + RecordedQueue recordedQueue = connection.getRecordedQueues().get(consumer.getQueue()); + if (recordedQueue != null) { + connection.recoverQueue( + recordedQueue.getName(), recordedQueue, false + ); + } + } + return null; + }; + + public static final DefaultRetryHandler.RetryOperation RECOVER_CONSUMER = context -> context.consumer().recover(); +} diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index 3747c71be9..9c2994b671 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -62,7 +62,8 @@ StrictExceptionHandlerTest.class, NoAutoRecoveryWhenTcpWindowIsFullTest.class, JsonRpcTest.class, - AddressTest.class + AddressTest.class, + DefaultRetryHandlerTest.class }) public class ClientTests { diff --git a/src/test/java/com/rabbitmq/client/test/DefaultRetryHandlerTest.java b/src/test/java/com/rabbitmq/client/test/DefaultRetryHandlerTest.java new file mode 100644 index 0000000000..cc105304a7 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/DefaultRetryHandlerTest.java @@ -0,0 +1,257 @@ +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.test; + +import com.rabbitmq.client.impl.recovery.BackoffPolicy; +import com.rabbitmq.client.impl.recovery.DefaultRetryHandler; +import com.rabbitmq.client.impl.recovery.RecordedBinding; +import com.rabbitmq.client.impl.recovery.RecordedConsumer; +import com.rabbitmq.client.impl.recovery.RecordedExchange; +import com.rabbitmq.client.impl.recovery.RecordedQueue; +import com.rabbitmq.client.impl.recovery.RetryContext; +import com.rabbitmq.client.impl.recovery.RetryHandler; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.verification.VerificationMode; + +import java.util.concurrent.Callable; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.BiPredicate; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.intThat; +import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +/** + * + */ +public class DefaultRetryHandlerTest { + + RetryHandler handler; + + @Mock + BiPredicate queueRecoveryRetryCondition; + @Mock + BiPredicate exchangeRecoveryRetryCondition; + @Mock + BiPredicate bindingRecoveryRetryCondition; + @Mock + BiPredicate consumerRecoveryRetryCondition; + + @Mock + DefaultRetryHandler.RetryOperation queueRecoveryRetryOperation; + @Mock + DefaultRetryHandler.RetryOperation exchangeRecoveryRetryOperation; + @Mock + DefaultRetryHandler.RetryOperation bindingRecoveryRetryOperation; + @Mock + DefaultRetryHandler.RetryOperation consumerRecoveryRetryOperation; + + @Mock + BackoffPolicy backoffPolicy; + + @Before + public void init() { + initMocks(this); + } + + @Test + public void shouldNotRetryWhenConditionReturnsFalse() throws Exception { + conditionsReturn(false); + handler = handler(); + assertExceptionIsThrown( + "No retry, initial exception should have been re-thrown", + () -> handler.retryQueueRecovery(retryContext()) + ); + assertExceptionIsThrown( + "No retry, initial exception should have been re-thrown", + () -> handler.retryExchangeRecovery(retryContext()) + ); + assertExceptionIsThrown( + "No retry, initial exception should have been re-thrown", + () -> handler.retryBindingRecovery(retryContext()) + ); + assertExceptionIsThrown( + "No retry, initial exception should have been re-thrown", + () -> handler.retryConsumerRecovery(retryContext()) + ); + verifyConditionsInvocation(times(1)); + verifyOperationsInvocation(never()); + verify(backoffPolicy, never()).backoff(anyInt()); + } + + @Test + public void shouldReturnOperationResultInRetryResultWhenRetrying() throws Exception { + conditionsReturn(true); + when(queueRecoveryRetryOperation.call(any(RetryContext.class))).thenReturn("queue"); + when(exchangeRecoveryRetryOperation.call(any(RetryContext.class))).thenReturn("exchange"); + when(bindingRecoveryRetryOperation.call(any(RetryContext.class))).thenReturn("binding"); + when(consumerRecoveryRetryOperation.call(any(RetryContext.class))).thenReturn("consumer"); + handler = handler(); + assertEquals( + "queue", + handler.retryQueueRecovery(retryContext()).getResult() + ); + assertEquals( + "exchange", + handler.retryExchangeRecovery(retryContext()).getResult() + ); + assertEquals( + "binding", + handler.retryBindingRecovery(retryContext()).getResult() + ); + assertEquals( + "consumer", + handler.retryConsumerRecovery(retryContext()).getResult() + ); + verifyConditionsInvocation(times(1)); + verifyOperationsInvocation(times(1)); + verify(backoffPolicy, times(1 * 4)).backoff(1); + } + + @Test + public void shouldRetryWhenOperationFailsAndConditionIsTrue() throws Exception { + conditionsReturn(true); + when(queueRecoveryRetryOperation.call(any(RetryContext.class))) + .thenThrow(new Exception()).thenReturn("queue"); + when(exchangeRecoveryRetryOperation.call(any(RetryContext.class))) + .thenThrow(new Exception()).thenReturn("exchange"); + when(bindingRecoveryRetryOperation.call(any(RetryContext.class))) + .thenThrow(new Exception()).thenReturn("binding"); + when(consumerRecoveryRetryOperation.call(any(RetryContext.class))) + .thenThrow(new Exception()).thenReturn("consumer"); + handler = handler(2); + assertEquals( + "queue", + handler.retryQueueRecovery(retryContext()).getResult() + ); + assertEquals( + "exchange", + handler.retryExchangeRecovery(retryContext()).getResult() + ); + assertEquals( + "binding", + handler.retryBindingRecovery(retryContext()).getResult() + ); + assertEquals( + "consumer", + handler.retryConsumerRecovery(retryContext()).getResult() + ); + verifyConditionsInvocation(times(2)); + verifyOperationsInvocation(times(2)); + checkBackoffSequence(1, 2, 1, 2, 1, 2, 1, 2); + } + + @Test + public void shouldThrowExceptionWhenRetryAttemptsIsExceeded() throws Exception { + conditionsReturn(true); + when(queueRecoveryRetryOperation.call(any(RetryContext.class))) + .thenThrow(new Exception()); + when(exchangeRecoveryRetryOperation.call(any(RetryContext.class))) + .thenThrow(new Exception()); + when(bindingRecoveryRetryOperation.call(any(RetryContext.class))) + .thenThrow(new Exception()); + when(consumerRecoveryRetryOperation.call(any(RetryContext.class))) + .thenThrow(new Exception()); + handler = handler(3); + assertExceptionIsThrown( + "Retry exhausted, an exception should have been thrown", + () -> handler.retryQueueRecovery(retryContext()) + ); + assertExceptionIsThrown( + "Retry exhausted, an exception should have been thrown", + () -> handler.retryExchangeRecovery(retryContext()) + ); + assertExceptionIsThrown( + "Retry exhausted, an exception should have been thrown", + () -> handler.retryBindingRecovery(retryContext()) + ); + assertExceptionIsThrown( + "Retry exhausted, an exception should have been thrown", + () -> handler.retryConsumerRecovery(retryContext()) + ); + verifyConditionsInvocation(times(3)); + verifyOperationsInvocation(times(3)); + checkBackoffSequence(1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3); + } + + private void assertExceptionIsThrown(String message, Callable action) { + try { + action.call(); + fail(message); + } catch (Exception e) { + } + } + + private void conditionsReturn(boolean shouldRetry) { + when(queueRecoveryRetryCondition.test(nullable(RecordedQueue.class), nullable(Exception.class))) + .thenReturn(shouldRetry); + when(exchangeRecoveryRetryCondition.test(nullable(RecordedExchange.class), nullable(Exception.class))) + .thenReturn(shouldRetry); + when(bindingRecoveryRetryCondition.test(nullable(RecordedBinding.class), nullable(Exception.class))) + .thenReturn(shouldRetry); + when(consumerRecoveryRetryCondition.test(nullable(RecordedConsumer.class), nullable(Exception.class))) + .thenReturn(shouldRetry); + } + + private void verifyConditionsInvocation(VerificationMode mode) { + verify(queueRecoveryRetryCondition, mode).test(nullable(RecordedQueue.class), any(Exception.class)); + verify(exchangeRecoveryRetryCondition, mode).test(nullable(RecordedExchange.class), any(Exception.class)); + verify(bindingRecoveryRetryCondition, mode).test(nullable(RecordedBinding.class), any(Exception.class)); + verify(consumerRecoveryRetryCondition, mode).test(nullable(RecordedConsumer.class), any(Exception.class)); + } + + private void verifyOperationsInvocation(VerificationMode mode) throws Exception { + verify(queueRecoveryRetryOperation, mode).call(any(RetryContext.class)); + verify(exchangeRecoveryRetryOperation, mode).call(any(RetryContext.class)); + verify(bindingRecoveryRetryOperation, mode).call(any(RetryContext.class)); + verify(consumerRecoveryRetryOperation, mode).call(any(RetryContext.class)); + } + + private RetryHandler handler() { + return handler(1); + } + + private RetryHandler handler(int retryAttempts) { + return new DefaultRetryHandler( + queueRecoveryRetryCondition, exchangeRecoveryRetryCondition, + bindingRecoveryRetryCondition, consumerRecoveryRetryCondition, + queueRecoveryRetryOperation, exchangeRecoveryRetryOperation, + bindingRecoveryRetryOperation, consumerRecoveryRetryOperation, + retryAttempts, + backoffPolicy); + } + + private RetryContext retryContext() { + return new RetryContext(null, new Exception(), null); + } + + private void checkBackoffSequence(int... sequence) throws InterruptedException { + AtomicInteger count = new AtomicInteger(0); + verify(backoffPolicy, times(sequence.length)) + // for some reason Mockito calls the matchers twice as many times as the target method + .backoff(intThat(i -> i == sequence[count.getAndIncrement() % sequence.length])); + } +} diff --git a/src/test/java/com/rabbitmq/client/test/TestUtils.java b/src/test/java/com/rabbitmq/client/test/TestUtils.java index 644f3a1707..c44e8b26a4 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtils.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtils.java @@ -15,11 +15,28 @@ package com.rabbitmq.client.test; +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.DefaultConsumer; +import com.rabbitmq.client.Envelope; +import com.rabbitmq.client.Recoverable; +import com.rabbitmq.client.RecoverableConnection; +import com.rabbitmq.client.RecoveryListener; +import com.rabbitmq.client.ShutdownSignalException; +import com.rabbitmq.client.impl.NetworkConnection; +import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; +import com.rabbitmq.tools.Host; import org.slf4j.LoggerFactory; import java.io.IOException; +import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import static org.junit.Assert.assertTrue; public class TestUtils { @@ -27,7 +44,7 @@ public class TestUtils { public static ConnectionFactory connectionFactory() { ConnectionFactory connectionFactory = new ConnectionFactory(); - if(USE_NIO) { + if (USE_NIO) { connectionFactory.useNio(); } else { connectionFactory.useBlockingIo(); @@ -36,7 +53,7 @@ public static ConnectionFactory connectionFactory() { } public static void close(Connection connection) { - if(connection != null) { + if (connection != null) { try { connection.close(); } catch (IOException e) { @@ -66,12 +83,108 @@ public static boolean isVersion37orLater(Connection connection) { LoggerFactory.getLogger(TestUtils.class).warn("Unable to parse broker version {}", currentVersion, e); throw e; } + } + + public static boolean sendAndConsumeMessage(String exchange, String routingKey, String queue, Connection c) + throws IOException, TimeoutException, InterruptedException { + Channel ch = c.createChannel(); + try { + ch.confirmSelect(); + final CountDownLatch latch = new CountDownLatch(1); + ch.basicConsume(queue, true, new DefaultConsumer(ch) { + @Override + public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { + latch.countDown(); + } + }); + ch.basicPublish(exchange, routingKey, null, "".getBytes()); + ch.waitForConfirmsOrDie(5000); + return latch.await(5, TimeUnit.SECONDS); + } finally { + if (ch != null && ch.isOpen()) { + ch.close(); + } + } + } + + public static boolean resourceExists(Callable callback) throws Exception { + Channel declarePassiveChannel = null; + try { + declarePassiveChannel = callback.call(); + return true; + } catch (IOException e) { + if (e.getCause() instanceof ShutdownSignalException) { + ShutdownSignalException cause = (ShutdownSignalException) e.getCause(); + if (cause.getReason() instanceof AMQP.Channel.Close) { + if (((AMQP.Channel.Close) cause.getReason()).getReplyCode() == 404) { + return false; + } else { + throw e; + } + } + return false; + } else { + throw e; + } + } finally { + if (declarePassiveChannel != null && declarePassiveChannel.isOpen()) { + declarePassiveChannel.close(); + } + } + } + + public static boolean queueExists(final String queue, final Connection connection) throws Exception { + return resourceExists(() -> { + Channel channel = connection.createChannel(); + channel.queueDeclarePassive(queue); + return channel; + }); + } + + public static boolean exchangeExists(final String exchange, final Connection connection) throws Exception { + return resourceExists(() -> { + Channel channel = connection.createChannel(); + channel.exchangeDeclarePassive(exchange); + return channel; + }); + } + + public static void closeAndWaitForRecovery(RecoverableConnection connection) throws IOException, InterruptedException { + CountDownLatch latch = prepareForRecovery(connection); + Host.closeConnection((NetworkConnection) connection); + wait(latch); + } + + public static void closeAllConnectionsAndWaitForRecovery(Connection connection) throws IOException, InterruptedException { + CountDownLatch latch = prepareForRecovery(connection); + Host.closeAllConnections(); + wait(latch); + } + + public static CountDownLatch prepareForRecovery(Connection conn) { + final CountDownLatch latch = new CountDownLatch(1); + ((AutorecoveringConnection) conn).addRecoveryListener(new RecoveryListener() { + + @Override + public void handleRecovery(Recoverable recoverable) { + latch.countDown(); + } + + @Override + public void handleRecoveryStarted(Recoverable recoverable) { + // No-op + } + }); + return latch; + } + + private static void wait(CountDownLatch latch) throws InterruptedException { + assertTrue(latch.await(90, TimeUnit.SECONDS)); } /** * http://stackoverflow.com/questions/6701948/efficient-way-to-compare-version-strings-in-java - * */ static int versionCompare(String str1, String str2) { String[] vals1 = str1.split("\\."); @@ -90,5 +203,4 @@ static int versionCompare(String str1, String str2) { // e.g. "1.2.3" = "1.2.3" or "1.2.3" < "1.2.3.4" return Integer.signum(vals1.length - vals2.length); } - } diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java index a89bb16995..04cf8b04d2 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -39,6 +39,7 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; +import static com.rabbitmq.client.test.TestUtils.prepareForRecovery; import static org.hamcrest.Matchers.greaterThanOrEqualTo; import static org.hamcrest.Matchers.is; import static org.junit.Assert.*; @@ -62,7 +63,7 @@ public class ConnectionRecovery extends BrokerTestCase { try { assertTrue(c.isOpen()); assertEquals(connectionName, c.getClientProvidedName()); - closeAndWaitForRecovery(c); + TestUtils.closeAndWaitForRecovery(c); assertTrue(c.isOpen()); assertEquals(connectionName, c.getClientProvidedName()); } finally { @@ -82,7 +83,7 @@ public class ConnectionRecovery extends BrokerTestCase { RecoverableConnection c = newRecoveringConnection(addresses); try { assertTrue(c.isOpen()); - closeAndWaitForRecovery(c); + TestUtils.closeAndWaitForRecovery(c); assertTrue(c.isOpen()); } finally { c.abort(); @@ -98,7 +99,7 @@ public class ConnectionRecovery extends BrokerTestCase { RecoverableConnection c = newRecoveringConnection(addresses); try { assertTrue(c.isOpen()); - closeAndWaitForRecovery(c); + TestUtils.closeAndWaitForRecovery(c); assertTrue(c.isOpen()); } finally { c.abort(); @@ -157,7 +158,7 @@ public String getPassword() { assertThat(usernameRequested.get(), is(1)); assertThat(passwordRequested.get(), is(1)); - closeAndWaitForRecovery(c); + TestUtils.closeAndWaitForRecovery(c); assertTrue(c.isOpen()); // username is requested in AMQConnection#toString, so it can be accessed at any time assertThat(usernameRequested.get(), greaterThanOrEqualTo(2)); @@ -804,7 +805,7 @@ public void handleDelivery(String consumerTag, Connection testConnection = connectionFactory.newConnection(); try { assertTrue(testConnection.isOpen()); - closeAndWaitForRecovery((RecoverableConnection) testConnection); + TestUtils.closeAndWaitForRecovery((RecoverableConnection) testConnection); assertTrue(testConnection.isOpen()); } finally { connection.close(); @@ -851,7 +852,7 @@ public void handleDelivery(String consumerTag, Envelope envelope, BasicPropertie } } // now do recovery - closeAndWaitForRecovery(testConnection); + TestUtils.closeAndWaitForRecovery(testConnection); // verify channels & topology recovered by publishing a message to each for (int i=0; i < channelCount; i++) { @@ -935,21 +936,6 @@ private static void expectExchangeRecovery(Channel ch, String x) throws IOExcept ch.exchangeDeclarePassive(x); } - private static CountDownLatch prepareForRecovery(Connection conn) { - final CountDownLatch latch = new CountDownLatch(1); - ((AutorecoveringConnection)conn).addRecoveryListener(new RecoveryListener() { - @Override - public void handleRecovery(Recoverable recoverable) { - latch.countDown(); - } - @Override - public void handleRecoveryStarted(Recoverable recoverable) { - // No-op - } - }); - return latch; - } - private static CountDownLatch prepareForShutdown(Connection conn) { final CountDownLatch latch = new CountDownLatch(1); conn.addShutdownListener(new ShutdownListener() { @@ -962,13 +948,7 @@ public void shutdownCompleted(ShutdownSignalException cause) { } private void closeAndWaitForRecovery() throws IOException, InterruptedException { - closeAndWaitForRecovery((AutorecoveringConnection)this.connection); - } - - private static void closeAndWaitForRecovery(RecoverableConnection connection) throws IOException, InterruptedException { - CountDownLatch latch = prepareForRecovery(connection); - Host.closeConnection((NetworkConnection) connection); - wait(latch); + TestUtils.closeAndWaitForRecovery((AutorecoveringConnection)this.connection); } private void restartPrimaryAndWaitForRecovery() throws IOException, InterruptedException { diff --git a/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java b/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java index aeadb303dd..fb48f29585 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java +++ b/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java @@ -78,7 +78,8 @@ Nack.class, ExceptionMessages.class, Metrics.class, - TopologyRecoveryFiltering.class + TopologyRecoveryFiltering.class, + TopologyRecoveryRetry.class }) public class FunctionalTests { diff --git a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java index 480075258f..3eb9687eea 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java +++ b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java @@ -21,12 +21,7 @@ import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.DefaultConsumer; import com.rabbitmq.client.Envelope; -import com.rabbitmq.client.Recoverable; import com.rabbitmq.client.RecoverableConnection; -import com.rabbitmq.client.RecoveryListener; -import com.rabbitmq.client.ShutdownSignalException; -import com.rabbitmq.client.impl.NetworkConnection; -import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; import com.rabbitmq.client.impl.recovery.RecordedBinding; import com.rabbitmq.client.impl.recovery.RecordedConsumer; import com.rabbitmq.client.impl.recovery.RecordedExchange; @@ -34,16 +29,18 @@ import com.rabbitmq.client.impl.recovery.TopologyRecoveryFilter; import com.rabbitmq.client.test.BrokerTestCase; import com.rabbitmq.client.test.TestUtils; -import com.rabbitmq.tools.Host; import org.junit.Test; import java.io.IOException; -import java.util.concurrent.Callable; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; +import static com.rabbitmq.client.test.TestUtils.closeAndWaitForRecovery; +import static com.rabbitmq.client.test.TestUtils.exchangeExists; +import static com.rabbitmq.client.test.TestUtils.queueExists; +import static com.rabbitmq.client.test.TestUtils.sendAndConsumeMessage; import static org.awaitility.Awaitility.waitAtMost; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertFalse; @@ -62,98 +59,6 @@ public class TopologyRecoveryFiltering extends BrokerTestCase { }; Connection c; - private static boolean sendAndConsumeMessage(String exchange, String routingKey, String queue, Connection c) - throws IOException, TimeoutException, InterruptedException { - Channel ch = c.createChannel(); - try { - ch.confirmSelect(); - final CountDownLatch latch = new CountDownLatch(1); - ch.basicConsume(queue, true, new DefaultConsumer(ch) { - - @Override - public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { - latch.countDown(); - } - }); - ch.basicPublish(exchange, routingKey, null, "".getBytes()); - ch.waitForConfirmsOrDie(5000); - return latch.await(5, TimeUnit.SECONDS); - } finally { - if (ch != null && ch.isOpen()) { - ch.close(); - } - } - } - - private static boolean resourceExists(Callable callback) throws Exception { - Channel declarePassiveChannel = null; - try { - declarePassiveChannel = callback.call(); - return true; - } catch (IOException e) { - if (e.getCause() instanceof ShutdownSignalException) { - ShutdownSignalException cause = (ShutdownSignalException) e.getCause(); - if (cause.getReason() instanceof AMQP.Channel.Close) { - if (((AMQP.Channel.Close) cause.getReason()).getReplyCode() == 404) { - return false; - } else { - throw e; - } - } - return false; - } else { - throw e; - } - } finally { - if (declarePassiveChannel != null && declarePassiveChannel.isOpen()) { - declarePassiveChannel.close(); - } - } - } - - private static boolean queueExists(final String queue, final Connection connection) throws Exception { - return resourceExists(() -> { - Channel channel = connection.createChannel(); - channel.queueDeclarePassive(queue); - return channel; - }); - } - - private static boolean exchangeExists(final String exchange, final Connection connection) throws Exception { - return resourceExists(() -> { - Channel channel = connection.createChannel(); - channel.exchangeDeclarePassive(exchange); - return channel; - }); - } - - private static void closeAndWaitForRecovery(RecoverableConnection connection) throws IOException, InterruptedException { - CountDownLatch latch = prepareForRecovery(connection); - Host.closeConnection((NetworkConnection) connection); - wait(latch); - } - - private static CountDownLatch prepareForRecovery(Connection conn) { - final CountDownLatch latch = new CountDownLatch(1); - ((AutorecoveringConnection) conn).addRecoveryListener(new RecoveryListener() { - - @Override - public void handleRecovery(Recoverable recoverable) { - latch.countDown(); - } - - @Override - public void handleRecoveryStarted(Recoverable recoverable) { - // No-op - } - }); - return latch; - } - - private static void wait(CountDownLatch latch) throws InterruptedException { - assertTrue(latch.await(20, TimeUnit.SECONDS)); - } - @Override protected ConnectionFactory newConnectionFactory() { ConnectionFactory connectionFactory = TestUtils.connectionFactory(); diff --git a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java new file mode 100644 index 0000000000..4f8ab6054a --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java @@ -0,0 +1,70 @@ +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.test.functional; + +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.DefaultConsumer; +import com.rabbitmq.client.test.BrokerTestCase; +import com.rabbitmq.client.test.TestUtils; +import org.junit.Test; + +import java.util.HashMap; + +import static com.rabbitmq.client.impl.recovery.TopologyRecoveryRetryHandlerBuilder.builder; +import static com.rabbitmq.client.impl.recovery.TopologyRecoveryRetryLogic.CHANNEL_CLOSED_NOT_FOUND; +import static com.rabbitmq.client.impl.recovery.TopologyRecoveryRetryLogic.RECOVER_BINDING; +import static com.rabbitmq.client.impl.recovery.TopologyRecoveryRetryLogic.RECOVER_BINDING_QUEUE; +import static com.rabbitmq.client.impl.recovery.TopologyRecoveryRetryLogic.RECOVER_CHANNEL; +import static com.rabbitmq.client.impl.recovery.TopologyRecoveryRetryLogic.RECOVER_CONSUMER; +import static com.rabbitmq.client.impl.recovery.TopologyRecoveryRetryLogic.RECOVER_CONSUMER_QUEUE; +import static com.rabbitmq.client.test.TestUtils.closeAllConnectionsAndWaitForRecovery; +import static org.junit.Assert.assertTrue; + +/** + * + */ +public class TopologyRecoveryRetry extends BrokerTestCase { + + @Test + public void topologyRecoveryRetry() throws Exception { + int nbQueues = 2000; + String prefix = "topology-recovery-retry-" + System.currentTimeMillis(); + for (int i = 0; i < nbQueues; i++) { + String queue = prefix + i; + channel.queueDeclare(queue, false, false, true, new HashMap<>()); + channel.queueBind(queue, "amq.direct", queue); + channel.basicConsume(queue, true, new DefaultConsumer(channel)); + } + + closeAllConnectionsAndWaitForRecovery(this.connection); + + assertTrue(channel.isOpen()); + } + + @Override + protected ConnectionFactory newConnectionFactory() { + ConnectionFactory connectionFactory = TestUtils.connectionFactory(); + connectionFactory.setTopologyRecoveryRetryHandler( + builder().bindingRecoveryRetryCondition((b, e) -> CHANNEL_CLOSED_NOT_FOUND.test(e)) + .consumerRecoveryRetryCondition((b, e) -> CHANNEL_CLOSED_NOT_FOUND.test(e)) + .bindingRecoveryRetryOperation(RECOVER_CHANNEL.andThen(RECOVER_BINDING_QUEUE).andThen(RECOVER_BINDING)) + .consumerRecoveryRetryOperation(RECOVER_CHANNEL.andThen(RECOVER_CONSUMER_QUEUE.andThen(RECOVER_CONSUMER))) + .build() + ); + connectionFactory.setNetworkRecoveryInterval(1000); + return connectionFactory; + } +} diff --git a/src/test/java/com/rabbitmq/tools/Host.java b/src/test/java/com/rabbitmq/tools/Host.java index 5924e5931d..c919d78621 100644 --- a/src/test/java/com/rabbitmq/tools/Host.java +++ b/src/test/java/com/rabbitmq/tools/Host.java @@ -169,6 +169,10 @@ public static void closeConnection(String pid) throws IOException { rabbitmqctl("close_connection '" + pid + "' 'Closed via rabbitmqctl'"); } + public static void closeAllConnections() throws IOException { + rabbitmqctl("close_all_connections 'Closed via rabbitmqctl'"); + } + public static void closeConnection(NetworkConnection c) throws IOException { Host.ConnectionInfo ci = findConnectionInfoFor(Host.listConnections(), c); closeConnection(ci.getPid()); From e460887d87382e16badebc205ad77ae49d63bfdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 7 Aug 2018 11:23:21 +0200 Subject: [PATCH 0835/2114] Add optional retry logic to topology recovery There's no topology recovery retry by default. The default implementation is composable: not all have the recoverable entities have to retry and the retry operations don't have to be only the corresponding entity recovery, but also other operations, like recovering the corresponding channel. Fixes #387 (cherry picked from commit 34e33ea80b9c71dfc0b2cb929b40e707e6e0fcac) --- .../rabbitmq/client/ConnectionFactory.java | 18 ++ .../client/impl/ConnectionParams.java | 9 + .../recovery/AutorecoveringConnection.java | 109 ++++++-- .../client/impl/recovery/BackoffPolicy.java | 34 +++ .../impl/recovery/DefaultRetryHandler.java | 131 +++++++++ .../client/impl/recovery/RetryContext.java | 99 +++++++ .../client/impl/recovery/RetryHandler.java | 62 +++++ .../client/impl/recovery/RetryResult.java | 57 ++++ .../TopologyRecoveryRetryHandlerBuilder.java | 115 ++++++++ .../recovery/TopologyRecoveryRetryLogic.java | 85 ++++++ .../com/rabbitmq/client/test/ClientTests.java | 3 +- .../client/test/DefaultRetryHandlerTest.java | 257 ++++++++++++++++++ .../com/rabbitmq/client/test/TestUtils.java | 120 +++++++- .../test/functional/ConnectionRecovery.java | 36 +-- .../test/functional/FunctionalTests.java | 3 +- .../functional/TopologyRecoveryFiltering.java | 103 +------ .../functional/TopologyRecoveryRetry.java | 70 +++++ src/test/java/com/rabbitmq/tools/Host.java | 4 + 18 files changed, 1160 insertions(+), 155 deletions(-) create mode 100644 src/main/java/com/rabbitmq/client/impl/recovery/BackoffPolicy.java create mode 100644 src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java create mode 100644 src/main/java/com/rabbitmq/client/impl/recovery/RetryContext.java create mode 100644 src/main/java/com/rabbitmq/client/impl/recovery/RetryHandler.java create mode 100644 src/main/java/com/rabbitmq/client/impl/recovery/RetryResult.java create mode 100644 src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryHandlerBuilder.java create mode 100644 src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java create mode 100644 src/test/java/com/rabbitmq/client/test/DefaultRetryHandlerTest.java create mode 100644 src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index a35a55f64d..0816abdde3 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -29,6 +29,7 @@ import com.rabbitmq.client.impl.nio.NioParams; import com.rabbitmq.client.impl.nio.SocketChannelFrameHandlerFactory; import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; +import com.rabbitmq.client.impl.recovery.RetryHandler; import com.rabbitmq.client.impl.recovery.TopologyRecoveryFilter; import java.io.IOException; @@ -192,6 +193,13 @@ public class ConnectionFactory implements Cloneable { */ private Predicate connectionRecoveryTriggeringCondition; + /** + * Retry handler for topology recovery. + * Default is no retry. + * @since 5.4.0 + */ + private RetryHandler topologyRecoveryRetryHandler; + /** @return the default host to use for connections */ public String getHost() { return host; @@ -1087,6 +1095,7 @@ public ConnectionParams params(ExecutorService consumerWorkServiceExecutor) { result.setErrorOnWriteListener(errorOnWriteListener); result.setTopologyRecoveryFilter(topologyRecoveryFilter); result.setConnectionRecoveryTriggeringCondition(connectionRecoveryTriggeringCondition); + result.setTopologyRecoveryRetryHandler(topologyRecoveryRetryHandler); return result; } @@ -1454,4 +1463,13 @@ public void setConnectionRecoveryTriggeringCondition(Predicate connectionRecoveryTriggeringCondition; + private RetryHandler topologyRecoveryRetryHandler; private ExceptionHandler exceptionHandler; private ThreadFactory threadFactory; @@ -257,4 +259,11 @@ public Predicate getConnectionRecoveryTriggeringConditi return connectionRecoveryTriggeringCondition; } + public void setTopologyRecoveryRetryHandler(RetryHandler topologyRecoveryRetryHandler) { + this.topologyRecoveryRetryHandler = topologyRecoveryRetryHandler; + } + + public RetryHandler getTopologyRecoveryRetryHandler() { + return topologyRecoveryRetryHandler; + } } diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index 9223cb11aa..c3e66e0d2f 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -95,6 +95,8 @@ public class AutorecoveringConnection implements RecoverableConnection, NetworkC private final Predicate connectionRecoveryTriggeringCondition; + private final RetryHandler retryHandler; + public AutorecoveringConnection(ConnectionParams params, FrameHandlerFactory f, List

addrs) { this(params, f, new ListAddressResolver(addrs)); } @@ -115,6 +117,8 @@ public AutorecoveringConnection(ConnectionParams params, FrameHandlerFactory f, this.channels = new ConcurrentHashMap<>(); this.topologyRecoveryFilter = params.getTopologyRecoveryFilter() == null ? letAllPassFilter() : params.getTopologyRecoveryFilter(); + + this.retryHandler = params.getTopologyRecoveryRetryHandler(); } private void setupErrorOnWriteListenerForPotentialRecovery() { @@ -125,12 +129,9 @@ private void setupErrorOnWriteListenerForPotentialRecovery() { // we should trigger the error handling and the recovery only once if (errorOnWriteLock.tryLock()) { try { - Thread recoveryThread = threadFactory.newThread(new Runnable() { - @Override - public void run() { - AMQConnection c = (AMQConnection) connection; - c.handleIoError(exception); - } + Thread recoveryThread = threadFactory.newThread(() -> { + AMQConnection c = (AMQConnection) connection; + c.handleIoError(exception); }); recoveryThread.setName("RabbitMQ Error On Write Thread"); recoveryThread.start(); @@ -630,6 +631,10 @@ private void recoverChannels(final RecoveryAwareAMQConnection newConn) { } } + void recoverChannel(AutorecoveringChannel channel) throws IOException { + channel.automaticallyRecover(this, this.delegate); + } + private void notifyRecoveryListenersComplete() { for (RecoveryListener f : Utility.copy(this.recoveryListeners)) { f.handleRecovery(this); @@ -651,16 +656,16 @@ private void recoverTopology(final ExecutorService executor) { if (executor == null) { // recover entities in serial on the main connection thread for (final RecordedExchange exchange : Utility.copy(recordedExchanges).values()) { - recoverExchange(exchange); + recoverExchange(exchange, true); } for (final Map.Entry entry : Utility.copy(recordedQueues).entrySet()) { - recoverQueue(entry.getKey(), entry.getValue()); + recoverQueue(entry.getKey(), entry.getValue(), true); } for (final RecordedBinding b : Utility.copy(recordedBindings)) { - recoverBinding(b); + recoverBinding(b, true); } for (final Map.Entry entry : Utility.copy(consumers).entrySet()) { - recoverConsumer(entry.getKey(), entry.getValue()); + recoverConsumer(entry.getKey(), entry.getValue(), true); } } else { // Support recovering entities in parallel for connections that have a lot of queues, bindings, & consumers @@ -680,11 +685,19 @@ private void recoverTopology(final ExecutorService executor) { } } - private void recoverExchange(final RecordedExchange x) { + private void recoverExchange(RecordedExchange x, boolean retry) { // recorded exchanges are guaranteed to be non-predefined (we filter out predefined ones in exchangeDeclare). MK. try { if (topologyRecoveryFilter.filterExchange(x)) { - x.recover(); + if (retry) { + final RecordedExchange entity = x; + x = (RecordedExchange) wrapRetryIfNecessary(x, () -> { + entity.recover(); + return null; + }).getRecordedEntity(); + } else { + x.recover(); + } LOGGER.debug("{} has recovered", x); } } catch (Exception cause) { @@ -695,12 +708,20 @@ private void recoverExchange(final RecordedExchange x) { } } - private void recoverQueue(final String oldName, final RecordedQueue q) { + void recoverQueue(final String oldName, RecordedQueue q, boolean retry) { try { if (topologyRecoveryFilter.filterQueue(q)) { LOGGER.debug("Recovering {}", q); - q.recover(); + if (retry) { + final RecordedQueue entity = q; + q = (RecordedQueue) wrapRetryIfNecessary(q, () -> { + entity.recover(); + return null; + }).getRecordedEntity(); + } else { + q.recover(); + } String newName = q.getName(); if (!oldName.equals(newName)) { // make sure server-named queues are re-added with @@ -731,10 +752,18 @@ private void recoverQueue(final String oldName, final RecordedQueue q) { } } - private void recoverBinding(final RecordedBinding b) { + private void recoverBinding(RecordedBinding b, boolean retry) { try { if (this.topologyRecoveryFilter.filterBinding(b)) { - b.recover(); + if (retry) { + final RecordedBinding entity = b; + b = (RecordedBinding) wrapRetryIfNecessary(b, () -> { + entity.recover(); + return null; + }).getRecordedEntity(); + } else { + b.recover(); + } LOGGER.debug("{} has recovered", b); } } catch (Exception cause) { @@ -745,11 +774,20 @@ private void recoverBinding(final RecordedBinding b) { } } - private void recoverConsumer(final String tag, final RecordedConsumer consumer) { + private void recoverConsumer(final String tag, RecordedConsumer consumer, boolean retry) { try { if (this.topologyRecoveryFilter.filterConsumer(consumer)) { LOGGER.debug("Recovering {}", consumer); - String newTag = consumer.recover(); + String newTag = null; + if (retry) { + final RecordedConsumer entity = consumer; + RetryResult retryResult = wrapRetryIfNecessary(consumer, () -> entity.recover()); + consumer = (RecordedConsumer) retryResult.getRecordedEntity(); + newTag = (String) retryResult.getResult(); + } else { + newTag = consumer.recover(); + } + // make sure server-generated tags are re-added. MK. if(tag != null && !tag.equals(newTag)) { synchronized (this.consumers) { @@ -772,6 +810,33 @@ private void recoverConsumer(final String tag, final RecordedConsumer consumer) } } + private RetryResult wrapRetryIfNecessary(RecordedEntity entity, Callable recoveryAction) throws Exception { + if (this.retryHandler == null) { + T result = recoveryAction.call(); + return new RetryResult(entity, result); + } else { + try { + T result = recoveryAction.call(); + return new RetryResult(entity, result); + } catch (Exception e) { + RetryContext retryContext = new RetryContext(entity, e, this); + RetryResult retryResult; + if (entity instanceof RecordedQueue) { + retryResult = this.retryHandler.retryQueueRecovery(retryContext); + } else if (entity instanceof RecordedExchange) { + retryResult = this.retryHandler.retryExchangeRecovery(retryContext); + } else if (entity instanceof RecordedBinding) { + retryResult = this.retryHandler.retryBindingRecovery(retryContext); + } else if (entity instanceof RecordedConsumer) { + retryResult = this.retryHandler.retryConsumerRecovery(retryContext); + } else { + throw new IllegalArgumentException("Unknown type of recorded entity: " + entity); + } + return retryResult; + } + } + } + private void propagateQueueNameChangeToBindings(String oldName, String newName) { for (RecordedBinding b : Utility.copy(this.recordedBindings)) { if (b.getDestination().equals(oldName)) { @@ -820,15 +885,15 @@ private List> groupEntitiesByChannel callables.add(Executors.callable(() -> { for (final E entity : entityList) { if (entity instanceof RecordedExchange) { - recoverExchange((RecordedExchange)entity); + recoverExchange((RecordedExchange)entity, true); } else if (entity instanceof RecordedQueue) { final RecordedQueue q = (RecordedQueue) entity; - recoverQueue(q.getName(), q); + recoverQueue(q.getName(), q, true); } else if (entity instanceof RecordedBinding) { - recoverBinding((RecordedBinding) entity); + recoverBinding((RecordedBinding) entity, true); } else if (entity instanceof RecordedConsumer) { final RecordedConsumer c = (RecordedConsumer) entity; - recoverConsumer(c.getConsumerTag(), c); + recoverConsumer(c.getConsumerTag(), c, true); } } })); diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/BackoffPolicy.java b/src/main/java/com/rabbitmq/client/impl/recovery/BackoffPolicy.java new file mode 100644 index 0000000000..a05c2a8a3c --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/recovery/BackoffPolicy.java @@ -0,0 +1,34 @@ +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl.recovery; + +/** + * Backoff policy for topology recovery retry attempts. + * + * @see DefaultRetryHandler + * @see TopologyRecoveryRetryHandlerBuilder + * @since 5.4.0 + */ +@FunctionalInterface +public interface BackoffPolicy { + + /** + * Wait depending on the current attempt number (1, 2, 3, etc) + * @param attemptNumber current attempt number + * @throws InterruptedException + */ + void backoff(int attemptNumber) throws InterruptedException; +} diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java b/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java new file mode 100644 index 0000000000..8c9b1df3fd --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java @@ -0,0 +1,131 @@ +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl.recovery; + +import java.util.Objects; +import java.util.function.BiPredicate; + +/** + * Composable topology recovery retry handler. + * This retry handler implementations let the user choose the condition + * to trigger retry and the retry operation for each type of recoverable + * entities. The number of attempts and the backoff policy (time to wait + * between retries) are also configurable. + *

+ * See also {@link TopologyRecoveryRetryHandlerBuilder} to easily create + * instances and {@link TopologyRecoveryRetryLogic} for ready-to-use + * conditions and operations. + * + * @see TopologyRecoveryRetryHandlerBuilder + * @see TopologyRecoveryRetryLogic + * @since 5.4.0 + */ +public class DefaultRetryHandler implements RetryHandler { + + private final BiPredicate queueRecoveryRetryCondition; + private final BiPredicate exchangeRecoveryRetryCondition; + private final BiPredicate bindingRecoveryRetryCondition; + private final BiPredicate consumerRecoveryRetryCondition; + + private final RetryOperation queueRecoveryRetryOperation; + private final RetryOperation exchangeRecoveryRetryOperation; + private final RetryOperation bindingRecoveryRetryOperation; + private final RetryOperation consumerRecoveryRetryOperation; + + private final int retryAttempts; + + private final BackoffPolicy backoffPolicy; + + public DefaultRetryHandler(BiPredicate queueRecoveryRetryCondition, + BiPredicate exchangeRecoveryRetryCondition, + BiPredicate bindingRecoveryRetryCondition, + BiPredicate consumerRecoveryRetryCondition, + RetryOperation queueRecoveryRetryOperation, + RetryOperation exchangeRecoveryRetryOperation, + RetryOperation bindingRecoveryRetryOperation, + RetryOperation consumerRecoveryRetryOperation, int retryAttempts, BackoffPolicy backoffPolicy) { + this.queueRecoveryRetryCondition = queueRecoveryRetryCondition; + this.exchangeRecoveryRetryCondition = exchangeRecoveryRetryCondition; + this.bindingRecoveryRetryCondition = bindingRecoveryRetryCondition; + this.consumerRecoveryRetryCondition = consumerRecoveryRetryCondition; + this.queueRecoveryRetryOperation = queueRecoveryRetryOperation; + this.exchangeRecoveryRetryOperation = exchangeRecoveryRetryOperation; + this.bindingRecoveryRetryOperation = bindingRecoveryRetryOperation; + this.consumerRecoveryRetryOperation = consumerRecoveryRetryOperation; + this.backoffPolicy = backoffPolicy; + if (retryAttempts <= 0) { + throw new IllegalArgumentException("Number of retry attempts must be greater than 0"); + } + this.retryAttempts = retryAttempts; + } + + @Override + public RetryResult retryQueueRecovery(RetryContext context) throws Exception { + return doRetry(queueRecoveryRetryCondition, queueRecoveryRetryOperation, context.queue(), context); + } + + @Override + public RetryResult retryExchangeRecovery(RetryContext context) throws Exception { + return doRetry(exchangeRecoveryRetryCondition, exchangeRecoveryRetryOperation, context.exchange(), context); + } + + @Override + public RetryResult retryBindingRecovery(RetryContext context) throws Exception { + return doRetry(bindingRecoveryRetryCondition, bindingRecoveryRetryOperation, context.binding(), context); + } + + @Override + public RetryResult retryConsumerRecovery(RetryContext context) throws Exception { + return doRetry(consumerRecoveryRetryCondition, consumerRecoveryRetryOperation, context.consumer(), context); + } + + protected RetryResult doRetry(BiPredicate condition, RetryOperation operation, T entity, RetryContext context) + throws Exception { + int attempts = 0; + Exception exception = context.exception(); + while (attempts < retryAttempts) { + if (condition.test(entity, exception)) { + backoffPolicy.backoff(attempts + 1); + try { + Object result = operation.call(context); + return new RetryResult( + entity, result == null ? null : result.toString() + ); + } catch (Exception e) { + exception = e; + attempts++; + continue; + } + } else { + throw exception; + } + } + throw context.exception(); + } + + public interface RetryOperation { + + T call(RetryContext context) throws Exception; + + default RetryOperation andThen(RetryOperation after) { + Objects.requireNonNull(after); + return (context) -> { + call(context); + return after.call(context); + }; + } + } +} diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RetryContext.java b/src/main/java/com/rabbitmq/client/impl/recovery/RetryContext.java new file mode 100644 index 0000000000..a9bdc05e5f --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RetryContext.java @@ -0,0 +1,99 @@ +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl.recovery; + +/** + * The context of a topology recovery retry operation. + * + * @since 5.4.0 + */ +public class RetryContext { + + private final RecordedEntity entity; + + private final Exception exception; + + private final AutorecoveringConnection connection; + + public RetryContext(RecordedEntity entity, Exception exception, AutorecoveringConnection connection) { + this.entity = entity; + this.exception = exception; + this.connection = connection; + } + + /** + * The underlying connection. + * + * @return + */ + public AutorecoveringConnection connection() { + return connection; + } + + /** + * The exception that triggered the retry attempt. + * + * @return + */ + public Exception exception() { + return exception; + } + + /** + * The to-be-recovered entity. + * + * @return + */ + public RecordedEntity entity() { + return entity; + } + + /** + * The to-be-recovered entity as a queue. + * + * @return + */ + public RecordedQueue queue() { + return (RecordedQueue) entity; + } + + /** + * The to-be-recovered entity as an exchange. + * + * @return + */ + public RecordedExchange exchange() { + return (RecordedExchange) entity; + } + + /** + * The to-be-recovered entity as a binding. + * + * @return + */ + public RecordedBinding binding() { + return (RecordedBinding) entity; + } + + /** + * The to-be-recovered entity as a consumer. + * + * @return + */ + public RecordedConsumer consumer() { + return (RecordedConsumer) entity; + } +} diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RetryHandler.java b/src/main/java/com/rabbitmq/client/impl/recovery/RetryHandler.java new file mode 100644 index 0000000000..5ed7f823f0 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RetryHandler.java @@ -0,0 +1,62 @@ +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl.recovery; + +/** + * Contract to retry failed operations during topology recovery. + * Not all operations have to be retried, it's a decision of the + * underlying implementation. + * + * @since 5.4.0 + */ +public interface RetryHandler { + + /** + * Retry a failed queue recovery operation. + * + * @param context the context of the retry + * @return the result of the retry attempt + * @throws Exception if the retry fails + */ + RetryResult retryQueueRecovery(RetryContext context) throws Exception; + + /** + * Retry a failed exchange recovery operation. + * + * @param context the context of the retry + * @return the result of the retry attempt + * @throws Exception if the retry fails + */ + RetryResult retryExchangeRecovery(RetryContext context) throws Exception; + + /** + * Retry a failed binding recovery operation. + * + * @param context the context of the retry + * @return the result of the retry attempt + * @throws Exception if the retry fails + */ + RetryResult retryBindingRecovery(RetryContext context) throws Exception; + + /** + * Retry a failed consumer recovery operation. + * + * @param context the context of the retry + * @return the result of the retry attempt + * @throws Exception if the retry fails + */ + RetryResult retryConsumerRecovery(RetryContext context) throws Exception; +} diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RetryResult.java b/src/main/java/com/rabbitmq/client/impl/recovery/RetryResult.java new file mode 100644 index 0000000000..c4797c39bf --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RetryResult.java @@ -0,0 +1,57 @@ +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl.recovery; + +/** + * The retry of a retried topology recovery operation. + * + * @since 5.4.0 + */ +public class RetryResult { + + /** + * The entity to recover. + */ + private final RecordedEntity recordedEntity; + + /** + * The result of the recovery operation. + * E.g. a consumer tag when recovering a consumer. + */ + private final Object result; + + public RetryResult(RecordedEntity recordedEntity, Object result) { + this.recordedEntity = recordedEntity; + this.result = result; + } + + /** + * The entity to recover. + * + * @return + */ + public RecordedEntity getRecordedEntity() { + return recordedEntity; + } + + /** + * The result of the recovery operation. + * E.g. a consumer tag when recovering a consumer. + */ + public Object getResult() { + return result; + } +} diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryHandlerBuilder.java b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryHandlerBuilder.java new file mode 100644 index 0000000000..07141b43e5 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryHandlerBuilder.java @@ -0,0 +1,115 @@ +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl.recovery; + +import java.util.function.BiPredicate; + +/** + * Builder to ease creation of {@link DefaultRetryHandler} instances. + *

+ * Just override what you need. By default, retry conditions don't trigger retry, + * retry operations are no-op, the number of retry attempts is 1, and the backoff + * policy doesn't wait at all. + * + * @see DefaultRetryHandler + * @see TopologyRecoveryRetryLogic + * @since 5.4.0 + */ +public class TopologyRecoveryRetryHandlerBuilder { + + private BiPredicate queueRecoveryRetryCondition = (q, e) -> false; + private BiPredicate exchangeRecoveryRetryCondition = (ex, e) -> false; + private BiPredicate bindingRecoveryRetryCondition = (b, e) -> false; + private BiPredicate consumerRecoveryRetryCondition = (c, e) -> false; + + private DefaultRetryHandler.RetryOperation queueRecoveryRetryOperation = context -> null; + private DefaultRetryHandler.RetryOperation exchangeRecoveryRetryOperation = context -> null; + private DefaultRetryHandler.RetryOperation bindingRecoveryRetryOperation = context -> null; + private DefaultRetryHandler.RetryOperation consumerRecoveryRetryOperation = context -> null; + + private int retryAttempts = 1; + + private BackoffPolicy backoffPolicy = nbAttempts -> { + }; + + public static TopologyRecoveryRetryHandlerBuilder builder() { + return new TopologyRecoveryRetryHandlerBuilder(); + } + + public TopologyRecoveryRetryHandlerBuilder queueRecoveryRetryCondition( + BiPredicate queueRecoveryRetryCondition) { + this.queueRecoveryRetryCondition = queueRecoveryRetryCondition; + return this; + } + + public TopologyRecoveryRetryHandlerBuilder exchangeRecoveryRetryCondition( + BiPredicate exchangeRecoveryRetryCondition) { + this.exchangeRecoveryRetryCondition = exchangeRecoveryRetryCondition; + return this; + } + + public TopologyRecoveryRetryHandlerBuilder bindingRecoveryRetryCondition( + BiPredicate bindingRecoveryRetryCondition) { + this.bindingRecoveryRetryCondition = bindingRecoveryRetryCondition; + return this; + } + + public TopologyRecoveryRetryHandlerBuilder consumerRecoveryRetryCondition( + BiPredicate consumerRecoveryRetryCondition) { + this.consumerRecoveryRetryCondition = consumerRecoveryRetryCondition; + return this; + } + + public TopologyRecoveryRetryHandlerBuilder queueRecoveryRetryOperation(DefaultRetryHandler.RetryOperation queueRecoveryRetryOperation) { + this.queueRecoveryRetryOperation = queueRecoveryRetryOperation; + return this; + } + + public TopologyRecoveryRetryHandlerBuilder exchangeRecoveryRetryOperation(DefaultRetryHandler.RetryOperation exchangeRecoveryRetryOperation) { + this.exchangeRecoveryRetryOperation = exchangeRecoveryRetryOperation; + return this; + } + + public TopologyRecoveryRetryHandlerBuilder bindingRecoveryRetryOperation(DefaultRetryHandler.RetryOperation bindingRecoveryRetryOperation) { + this.bindingRecoveryRetryOperation = bindingRecoveryRetryOperation; + return this; + } + + public TopologyRecoveryRetryHandlerBuilder consumerRecoveryRetryOperation(DefaultRetryHandler.RetryOperation consumerRecoveryRetryOperation) { + this.consumerRecoveryRetryOperation = consumerRecoveryRetryOperation; + return this; + } + + public TopologyRecoveryRetryHandlerBuilder backoffPolicy(BackoffPolicy backoffPolicy) { + this.backoffPolicy = backoffPolicy; + return this; + } + + public TopologyRecoveryRetryHandlerBuilder retryAttempts(int retryAttempts) { + this.retryAttempts = retryAttempts; + return this; + } + + public RetryHandler build() { + return new DefaultRetryHandler( + queueRecoveryRetryCondition, exchangeRecoveryRetryCondition, + bindingRecoveryRetryCondition, consumerRecoveryRetryCondition, + queueRecoveryRetryOperation, exchangeRecoveryRetryOperation, + bindingRecoveryRetryOperation, consumerRecoveryRetryOperation, + retryAttempts, + backoffPolicy); + } +} diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java new file mode 100644 index 0000000000..8e6e16a790 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java @@ -0,0 +1,85 @@ +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl.recovery; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.ShutdownSignalException; + +import java.util.function.Predicate; + +/** + * Useful ready-to-use conditions and operations for {@link DefaultRetryHandler}. + * They're composed and used with the {@link TopologyRecoveryRetryHandlerBuilder}. + * + * @see DefaultRetryHandler + * @see RetryHandler + * @see TopologyRecoveryRetryHandlerBuilder + * @since 5.4.0 + */ +public abstract class TopologyRecoveryRetryLogic { + + public static final Predicate CHANNEL_CLOSED_NOT_FOUND = e -> { + if (e.getCause() instanceof ShutdownSignalException) { + ShutdownSignalException cause = (ShutdownSignalException) e.getCause(); + if (cause.getReason() instanceof AMQP.Channel.Close) { + return ((AMQP.Channel.Close) cause.getReason()).getReplyCode() == 404; + } + } + return false; + }; + + public static final DefaultRetryHandler.RetryOperation RECOVER_CHANNEL = context -> { + if (!context.entity().getChannel().isOpen()) { + context.connection().recoverChannel(context.entity().getChannel()); + } + return null; + }; + + public static final DefaultRetryHandler.RetryOperation RECOVER_BINDING_QUEUE = context -> { + if (context.entity() instanceof RecordedQueueBinding) { + RecordedBinding binding = context.binding(); + AutorecoveringConnection connection = context.connection(); + RecordedQueue recordedQueue = connection.getRecordedQueues().get(binding.getDestination()); + if (recordedQueue != null) { + connection.recoverQueue( + recordedQueue.getName(), recordedQueue, false + ); + } + } + return null; + }; + + public static final DefaultRetryHandler.RetryOperation RECOVER_BINDING = context -> { + context.binding().recover(); + return null; + }; + + public static final DefaultRetryHandler.RetryOperation RECOVER_CONSUMER_QUEUE = context -> { + if (context.entity() instanceof RecordedConsumer) { + RecordedConsumer consumer = context.consumer(); + AutorecoveringConnection connection = context.connection(); + RecordedQueue recordedQueue = connection.getRecordedQueues().get(consumer.getQueue()); + if (recordedQueue != null) { + connection.recoverQueue( + recordedQueue.getName(), recordedQueue, false + ); + } + } + return null; + }; + + public static final DefaultRetryHandler.RetryOperation RECOVER_CONSUMER = context -> context.consumer().recover(); +} diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index 3747c71be9..9c2994b671 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -62,7 +62,8 @@ StrictExceptionHandlerTest.class, NoAutoRecoveryWhenTcpWindowIsFullTest.class, JsonRpcTest.class, - AddressTest.class + AddressTest.class, + DefaultRetryHandlerTest.class }) public class ClientTests { diff --git a/src/test/java/com/rabbitmq/client/test/DefaultRetryHandlerTest.java b/src/test/java/com/rabbitmq/client/test/DefaultRetryHandlerTest.java new file mode 100644 index 0000000000..cc105304a7 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/DefaultRetryHandlerTest.java @@ -0,0 +1,257 @@ +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.test; + +import com.rabbitmq.client.impl.recovery.BackoffPolicy; +import com.rabbitmq.client.impl.recovery.DefaultRetryHandler; +import com.rabbitmq.client.impl.recovery.RecordedBinding; +import com.rabbitmq.client.impl.recovery.RecordedConsumer; +import com.rabbitmq.client.impl.recovery.RecordedExchange; +import com.rabbitmq.client.impl.recovery.RecordedQueue; +import com.rabbitmq.client.impl.recovery.RetryContext; +import com.rabbitmq.client.impl.recovery.RetryHandler; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.verification.VerificationMode; + +import java.util.concurrent.Callable; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.BiPredicate; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.intThat; +import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +/** + * + */ +public class DefaultRetryHandlerTest { + + RetryHandler handler; + + @Mock + BiPredicate queueRecoveryRetryCondition; + @Mock + BiPredicate exchangeRecoveryRetryCondition; + @Mock + BiPredicate bindingRecoveryRetryCondition; + @Mock + BiPredicate consumerRecoveryRetryCondition; + + @Mock + DefaultRetryHandler.RetryOperation queueRecoveryRetryOperation; + @Mock + DefaultRetryHandler.RetryOperation exchangeRecoveryRetryOperation; + @Mock + DefaultRetryHandler.RetryOperation bindingRecoveryRetryOperation; + @Mock + DefaultRetryHandler.RetryOperation consumerRecoveryRetryOperation; + + @Mock + BackoffPolicy backoffPolicy; + + @Before + public void init() { + initMocks(this); + } + + @Test + public void shouldNotRetryWhenConditionReturnsFalse() throws Exception { + conditionsReturn(false); + handler = handler(); + assertExceptionIsThrown( + "No retry, initial exception should have been re-thrown", + () -> handler.retryQueueRecovery(retryContext()) + ); + assertExceptionIsThrown( + "No retry, initial exception should have been re-thrown", + () -> handler.retryExchangeRecovery(retryContext()) + ); + assertExceptionIsThrown( + "No retry, initial exception should have been re-thrown", + () -> handler.retryBindingRecovery(retryContext()) + ); + assertExceptionIsThrown( + "No retry, initial exception should have been re-thrown", + () -> handler.retryConsumerRecovery(retryContext()) + ); + verifyConditionsInvocation(times(1)); + verifyOperationsInvocation(never()); + verify(backoffPolicy, never()).backoff(anyInt()); + } + + @Test + public void shouldReturnOperationResultInRetryResultWhenRetrying() throws Exception { + conditionsReturn(true); + when(queueRecoveryRetryOperation.call(any(RetryContext.class))).thenReturn("queue"); + when(exchangeRecoveryRetryOperation.call(any(RetryContext.class))).thenReturn("exchange"); + when(bindingRecoveryRetryOperation.call(any(RetryContext.class))).thenReturn("binding"); + when(consumerRecoveryRetryOperation.call(any(RetryContext.class))).thenReturn("consumer"); + handler = handler(); + assertEquals( + "queue", + handler.retryQueueRecovery(retryContext()).getResult() + ); + assertEquals( + "exchange", + handler.retryExchangeRecovery(retryContext()).getResult() + ); + assertEquals( + "binding", + handler.retryBindingRecovery(retryContext()).getResult() + ); + assertEquals( + "consumer", + handler.retryConsumerRecovery(retryContext()).getResult() + ); + verifyConditionsInvocation(times(1)); + verifyOperationsInvocation(times(1)); + verify(backoffPolicy, times(1 * 4)).backoff(1); + } + + @Test + public void shouldRetryWhenOperationFailsAndConditionIsTrue() throws Exception { + conditionsReturn(true); + when(queueRecoveryRetryOperation.call(any(RetryContext.class))) + .thenThrow(new Exception()).thenReturn("queue"); + when(exchangeRecoveryRetryOperation.call(any(RetryContext.class))) + .thenThrow(new Exception()).thenReturn("exchange"); + when(bindingRecoveryRetryOperation.call(any(RetryContext.class))) + .thenThrow(new Exception()).thenReturn("binding"); + when(consumerRecoveryRetryOperation.call(any(RetryContext.class))) + .thenThrow(new Exception()).thenReturn("consumer"); + handler = handler(2); + assertEquals( + "queue", + handler.retryQueueRecovery(retryContext()).getResult() + ); + assertEquals( + "exchange", + handler.retryExchangeRecovery(retryContext()).getResult() + ); + assertEquals( + "binding", + handler.retryBindingRecovery(retryContext()).getResult() + ); + assertEquals( + "consumer", + handler.retryConsumerRecovery(retryContext()).getResult() + ); + verifyConditionsInvocation(times(2)); + verifyOperationsInvocation(times(2)); + checkBackoffSequence(1, 2, 1, 2, 1, 2, 1, 2); + } + + @Test + public void shouldThrowExceptionWhenRetryAttemptsIsExceeded() throws Exception { + conditionsReturn(true); + when(queueRecoveryRetryOperation.call(any(RetryContext.class))) + .thenThrow(new Exception()); + when(exchangeRecoveryRetryOperation.call(any(RetryContext.class))) + .thenThrow(new Exception()); + when(bindingRecoveryRetryOperation.call(any(RetryContext.class))) + .thenThrow(new Exception()); + when(consumerRecoveryRetryOperation.call(any(RetryContext.class))) + .thenThrow(new Exception()); + handler = handler(3); + assertExceptionIsThrown( + "Retry exhausted, an exception should have been thrown", + () -> handler.retryQueueRecovery(retryContext()) + ); + assertExceptionIsThrown( + "Retry exhausted, an exception should have been thrown", + () -> handler.retryExchangeRecovery(retryContext()) + ); + assertExceptionIsThrown( + "Retry exhausted, an exception should have been thrown", + () -> handler.retryBindingRecovery(retryContext()) + ); + assertExceptionIsThrown( + "Retry exhausted, an exception should have been thrown", + () -> handler.retryConsumerRecovery(retryContext()) + ); + verifyConditionsInvocation(times(3)); + verifyOperationsInvocation(times(3)); + checkBackoffSequence(1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3); + } + + private void assertExceptionIsThrown(String message, Callable action) { + try { + action.call(); + fail(message); + } catch (Exception e) { + } + } + + private void conditionsReturn(boolean shouldRetry) { + when(queueRecoveryRetryCondition.test(nullable(RecordedQueue.class), nullable(Exception.class))) + .thenReturn(shouldRetry); + when(exchangeRecoveryRetryCondition.test(nullable(RecordedExchange.class), nullable(Exception.class))) + .thenReturn(shouldRetry); + when(bindingRecoveryRetryCondition.test(nullable(RecordedBinding.class), nullable(Exception.class))) + .thenReturn(shouldRetry); + when(consumerRecoveryRetryCondition.test(nullable(RecordedConsumer.class), nullable(Exception.class))) + .thenReturn(shouldRetry); + } + + private void verifyConditionsInvocation(VerificationMode mode) { + verify(queueRecoveryRetryCondition, mode).test(nullable(RecordedQueue.class), any(Exception.class)); + verify(exchangeRecoveryRetryCondition, mode).test(nullable(RecordedExchange.class), any(Exception.class)); + verify(bindingRecoveryRetryCondition, mode).test(nullable(RecordedBinding.class), any(Exception.class)); + verify(consumerRecoveryRetryCondition, mode).test(nullable(RecordedConsumer.class), any(Exception.class)); + } + + private void verifyOperationsInvocation(VerificationMode mode) throws Exception { + verify(queueRecoveryRetryOperation, mode).call(any(RetryContext.class)); + verify(exchangeRecoveryRetryOperation, mode).call(any(RetryContext.class)); + verify(bindingRecoveryRetryOperation, mode).call(any(RetryContext.class)); + verify(consumerRecoveryRetryOperation, mode).call(any(RetryContext.class)); + } + + private RetryHandler handler() { + return handler(1); + } + + private RetryHandler handler(int retryAttempts) { + return new DefaultRetryHandler( + queueRecoveryRetryCondition, exchangeRecoveryRetryCondition, + bindingRecoveryRetryCondition, consumerRecoveryRetryCondition, + queueRecoveryRetryOperation, exchangeRecoveryRetryOperation, + bindingRecoveryRetryOperation, consumerRecoveryRetryOperation, + retryAttempts, + backoffPolicy); + } + + private RetryContext retryContext() { + return new RetryContext(null, new Exception(), null); + } + + private void checkBackoffSequence(int... sequence) throws InterruptedException { + AtomicInteger count = new AtomicInteger(0); + verify(backoffPolicy, times(sequence.length)) + // for some reason Mockito calls the matchers twice as many times as the target method + .backoff(intThat(i -> i == sequence[count.getAndIncrement() % sequence.length])); + } +} diff --git a/src/test/java/com/rabbitmq/client/test/TestUtils.java b/src/test/java/com/rabbitmq/client/test/TestUtils.java index 644f3a1707..c44e8b26a4 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtils.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtils.java @@ -15,11 +15,28 @@ package com.rabbitmq.client.test; +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.DefaultConsumer; +import com.rabbitmq.client.Envelope; +import com.rabbitmq.client.Recoverable; +import com.rabbitmq.client.RecoverableConnection; +import com.rabbitmq.client.RecoveryListener; +import com.rabbitmq.client.ShutdownSignalException; +import com.rabbitmq.client.impl.NetworkConnection; +import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; +import com.rabbitmq.tools.Host; import org.slf4j.LoggerFactory; import java.io.IOException; +import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import static org.junit.Assert.assertTrue; public class TestUtils { @@ -27,7 +44,7 @@ public class TestUtils { public static ConnectionFactory connectionFactory() { ConnectionFactory connectionFactory = new ConnectionFactory(); - if(USE_NIO) { + if (USE_NIO) { connectionFactory.useNio(); } else { connectionFactory.useBlockingIo(); @@ -36,7 +53,7 @@ public static ConnectionFactory connectionFactory() { } public static void close(Connection connection) { - if(connection != null) { + if (connection != null) { try { connection.close(); } catch (IOException e) { @@ -66,12 +83,108 @@ public static boolean isVersion37orLater(Connection connection) { LoggerFactory.getLogger(TestUtils.class).warn("Unable to parse broker version {}", currentVersion, e); throw e; } + } + + public static boolean sendAndConsumeMessage(String exchange, String routingKey, String queue, Connection c) + throws IOException, TimeoutException, InterruptedException { + Channel ch = c.createChannel(); + try { + ch.confirmSelect(); + final CountDownLatch latch = new CountDownLatch(1); + ch.basicConsume(queue, true, new DefaultConsumer(ch) { + @Override + public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { + latch.countDown(); + } + }); + ch.basicPublish(exchange, routingKey, null, "".getBytes()); + ch.waitForConfirmsOrDie(5000); + return latch.await(5, TimeUnit.SECONDS); + } finally { + if (ch != null && ch.isOpen()) { + ch.close(); + } + } + } + + public static boolean resourceExists(Callable callback) throws Exception { + Channel declarePassiveChannel = null; + try { + declarePassiveChannel = callback.call(); + return true; + } catch (IOException e) { + if (e.getCause() instanceof ShutdownSignalException) { + ShutdownSignalException cause = (ShutdownSignalException) e.getCause(); + if (cause.getReason() instanceof AMQP.Channel.Close) { + if (((AMQP.Channel.Close) cause.getReason()).getReplyCode() == 404) { + return false; + } else { + throw e; + } + } + return false; + } else { + throw e; + } + } finally { + if (declarePassiveChannel != null && declarePassiveChannel.isOpen()) { + declarePassiveChannel.close(); + } + } + } + + public static boolean queueExists(final String queue, final Connection connection) throws Exception { + return resourceExists(() -> { + Channel channel = connection.createChannel(); + channel.queueDeclarePassive(queue); + return channel; + }); + } + + public static boolean exchangeExists(final String exchange, final Connection connection) throws Exception { + return resourceExists(() -> { + Channel channel = connection.createChannel(); + channel.exchangeDeclarePassive(exchange); + return channel; + }); + } + + public static void closeAndWaitForRecovery(RecoverableConnection connection) throws IOException, InterruptedException { + CountDownLatch latch = prepareForRecovery(connection); + Host.closeConnection((NetworkConnection) connection); + wait(latch); + } + + public static void closeAllConnectionsAndWaitForRecovery(Connection connection) throws IOException, InterruptedException { + CountDownLatch latch = prepareForRecovery(connection); + Host.closeAllConnections(); + wait(latch); + } + + public static CountDownLatch prepareForRecovery(Connection conn) { + final CountDownLatch latch = new CountDownLatch(1); + ((AutorecoveringConnection) conn).addRecoveryListener(new RecoveryListener() { + + @Override + public void handleRecovery(Recoverable recoverable) { + latch.countDown(); + } + + @Override + public void handleRecoveryStarted(Recoverable recoverable) { + // No-op + } + }); + return latch; + } + + private static void wait(CountDownLatch latch) throws InterruptedException { + assertTrue(latch.await(90, TimeUnit.SECONDS)); } /** * http://stackoverflow.com/questions/6701948/efficient-way-to-compare-version-strings-in-java - * */ static int versionCompare(String str1, String str2) { String[] vals1 = str1.split("\\."); @@ -90,5 +203,4 @@ static int versionCompare(String str1, String str2) { // e.g. "1.2.3" = "1.2.3" or "1.2.3" < "1.2.3.4" return Integer.signum(vals1.length - vals2.length); } - } diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java index a89bb16995..04cf8b04d2 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -39,6 +39,7 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; +import static com.rabbitmq.client.test.TestUtils.prepareForRecovery; import static org.hamcrest.Matchers.greaterThanOrEqualTo; import static org.hamcrest.Matchers.is; import static org.junit.Assert.*; @@ -62,7 +63,7 @@ public class ConnectionRecovery extends BrokerTestCase { try { assertTrue(c.isOpen()); assertEquals(connectionName, c.getClientProvidedName()); - closeAndWaitForRecovery(c); + TestUtils.closeAndWaitForRecovery(c); assertTrue(c.isOpen()); assertEquals(connectionName, c.getClientProvidedName()); } finally { @@ -82,7 +83,7 @@ public class ConnectionRecovery extends BrokerTestCase { RecoverableConnection c = newRecoveringConnection(addresses); try { assertTrue(c.isOpen()); - closeAndWaitForRecovery(c); + TestUtils.closeAndWaitForRecovery(c); assertTrue(c.isOpen()); } finally { c.abort(); @@ -98,7 +99,7 @@ public class ConnectionRecovery extends BrokerTestCase { RecoverableConnection c = newRecoveringConnection(addresses); try { assertTrue(c.isOpen()); - closeAndWaitForRecovery(c); + TestUtils.closeAndWaitForRecovery(c); assertTrue(c.isOpen()); } finally { c.abort(); @@ -157,7 +158,7 @@ public String getPassword() { assertThat(usernameRequested.get(), is(1)); assertThat(passwordRequested.get(), is(1)); - closeAndWaitForRecovery(c); + TestUtils.closeAndWaitForRecovery(c); assertTrue(c.isOpen()); // username is requested in AMQConnection#toString, so it can be accessed at any time assertThat(usernameRequested.get(), greaterThanOrEqualTo(2)); @@ -804,7 +805,7 @@ public void handleDelivery(String consumerTag, Connection testConnection = connectionFactory.newConnection(); try { assertTrue(testConnection.isOpen()); - closeAndWaitForRecovery((RecoverableConnection) testConnection); + TestUtils.closeAndWaitForRecovery((RecoverableConnection) testConnection); assertTrue(testConnection.isOpen()); } finally { connection.close(); @@ -851,7 +852,7 @@ public void handleDelivery(String consumerTag, Envelope envelope, BasicPropertie } } // now do recovery - closeAndWaitForRecovery(testConnection); + TestUtils.closeAndWaitForRecovery(testConnection); // verify channels & topology recovered by publishing a message to each for (int i=0; i < channelCount; i++) { @@ -935,21 +936,6 @@ private static void expectExchangeRecovery(Channel ch, String x) throws IOExcept ch.exchangeDeclarePassive(x); } - private static CountDownLatch prepareForRecovery(Connection conn) { - final CountDownLatch latch = new CountDownLatch(1); - ((AutorecoveringConnection)conn).addRecoveryListener(new RecoveryListener() { - @Override - public void handleRecovery(Recoverable recoverable) { - latch.countDown(); - } - @Override - public void handleRecoveryStarted(Recoverable recoverable) { - // No-op - } - }); - return latch; - } - private static CountDownLatch prepareForShutdown(Connection conn) { final CountDownLatch latch = new CountDownLatch(1); conn.addShutdownListener(new ShutdownListener() { @@ -962,13 +948,7 @@ public void shutdownCompleted(ShutdownSignalException cause) { } private void closeAndWaitForRecovery() throws IOException, InterruptedException { - closeAndWaitForRecovery((AutorecoveringConnection)this.connection); - } - - private static void closeAndWaitForRecovery(RecoverableConnection connection) throws IOException, InterruptedException { - CountDownLatch latch = prepareForRecovery(connection); - Host.closeConnection((NetworkConnection) connection); - wait(latch); + TestUtils.closeAndWaitForRecovery((AutorecoveringConnection)this.connection); } private void restartPrimaryAndWaitForRecovery() throws IOException, InterruptedException { diff --git a/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java b/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java index aeadb303dd..fb48f29585 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java +++ b/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java @@ -78,7 +78,8 @@ Nack.class, ExceptionMessages.class, Metrics.class, - TopologyRecoveryFiltering.class + TopologyRecoveryFiltering.class, + TopologyRecoveryRetry.class }) public class FunctionalTests { diff --git a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java index 480075258f..3eb9687eea 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java +++ b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java @@ -21,12 +21,7 @@ import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.DefaultConsumer; import com.rabbitmq.client.Envelope; -import com.rabbitmq.client.Recoverable; import com.rabbitmq.client.RecoverableConnection; -import com.rabbitmq.client.RecoveryListener; -import com.rabbitmq.client.ShutdownSignalException; -import com.rabbitmq.client.impl.NetworkConnection; -import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; import com.rabbitmq.client.impl.recovery.RecordedBinding; import com.rabbitmq.client.impl.recovery.RecordedConsumer; import com.rabbitmq.client.impl.recovery.RecordedExchange; @@ -34,16 +29,18 @@ import com.rabbitmq.client.impl.recovery.TopologyRecoveryFilter; import com.rabbitmq.client.test.BrokerTestCase; import com.rabbitmq.client.test.TestUtils; -import com.rabbitmq.tools.Host; import org.junit.Test; import java.io.IOException; -import java.util.concurrent.Callable; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; +import static com.rabbitmq.client.test.TestUtils.closeAndWaitForRecovery; +import static com.rabbitmq.client.test.TestUtils.exchangeExists; +import static com.rabbitmq.client.test.TestUtils.queueExists; +import static com.rabbitmq.client.test.TestUtils.sendAndConsumeMessage; import static org.awaitility.Awaitility.waitAtMost; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertFalse; @@ -62,98 +59,6 @@ public class TopologyRecoveryFiltering extends BrokerTestCase { }; Connection c; - private static boolean sendAndConsumeMessage(String exchange, String routingKey, String queue, Connection c) - throws IOException, TimeoutException, InterruptedException { - Channel ch = c.createChannel(); - try { - ch.confirmSelect(); - final CountDownLatch latch = new CountDownLatch(1); - ch.basicConsume(queue, true, new DefaultConsumer(ch) { - - @Override - public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { - latch.countDown(); - } - }); - ch.basicPublish(exchange, routingKey, null, "".getBytes()); - ch.waitForConfirmsOrDie(5000); - return latch.await(5, TimeUnit.SECONDS); - } finally { - if (ch != null && ch.isOpen()) { - ch.close(); - } - } - } - - private static boolean resourceExists(Callable callback) throws Exception { - Channel declarePassiveChannel = null; - try { - declarePassiveChannel = callback.call(); - return true; - } catch (IOException e) { - if (e.getCause() instanceof ShutdownSignalException) { - ShutdownSignalException cause = (ShutdownSignalException) e.getCause(); - if (cause.getReason() instanceof AMQP.Channel.Close) { - if (((AMQP.Channel.Close) cause.getReason()).getReplyCode() == 404) { - return false; - } else { - throw e; - } - } - return false; - } else { - throw e; - } - } finally { - if (declarePassiveChannel != null && declarePassiveChannel.isOpen()) { - declarePassiveChannel.close(); - } - } - } - - private static boolean queueExists(final String queue, final Connection connection) throws Exception { - return resourceExists(() -> { - Channel channel = connection.createChannel(); - channel.queueDeclarePassive(queue); - return channel; - }); - } - - private static boolean exchangeExists(final String exchange, final Connection connection) throws Exception { - return resourceExists(() -> { - Channel channel = connection.createChannel(); - channel.exchangeDeclarePassive(exchange); - return channel; - }); - } - - private static void closeAndWaitForRecovery(RecoverableConnection connection) throws IOException, InterruptedException { - CountDownLatch latch = prepareForRecovery(connection); - Host.closeConnection((NetworkConnection) connection); - wait(latch); - } - - private static CountDownLatch prepareForRecovery(Connection conn) { - final CountDownLatch latch = new CountDownLatch(1); - ((AutorecoveringConnection) conn).addRecoveryListener(new RecoveryListener() { - - @Override - public void handleRecovery(Recoverable recoverable) { - latch.countDown(); - } - - @Override - public void handleRecoveryStarted(Recoverable recoverable) { - // No-op - } - }); - return latch; - } - - private static void wait(CountDownLatch latch) throws InterruptedException { - assertTrue(latch.await(20, TimeUnit.SECONDS)); - } - @Override protected ConnectionFactory newConnectionFactory() { ConnectionFactory connectionFactory = TestUtils.connectionFactory(); diff --git a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java new file mode 100644 index 0000000000..4f8ab6054a --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java @@ -0,0 +1,70 @@ +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.test.functional; + +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.DefaultConsumer; +import com.rabbitmq.client.test.BrokerTestCase; +import com.rabbitmq.client.test.TestUtils; +import org.junit.Test; + +import java.util.HashMap; + +import static com.rabbitmq.client.impl.recovery.TopologyRecoveryRetryHandlerBuilder.builder; +import static com.rabbitmq.client.impl.recovery.TopologyRecoveryRetryLogic.CHANNEL_CLOSED_NOT_FOUND; +import static com.rabbitmq.client.impl.recovery.TopologyRecoveryRetryLogic.RECOVER_BINDING; +import static com.rabbitmq.client.impl.recovery.TopologyRecoveryRetryLogic.RECOVER_BINDING_QUEUE; +import static com.rabbitmq.client.impl.recovery.TopologyRecoveryRetryLogic.RECOVER_CHANNEL; +import static com.rabbitmq.client.impl.recovery.TopologyRecoveryRetryLogic.RECOVER_CONSUMER; +import static com.rabbitmq.client.impl.recovery.TopologyRecoveryRetryLogic.RECOVER_CONSUMER_QUEUE; +import static com.rabbitmq.client.test.TestUtils.closeAllConnectionsAndWaitForRecovery; +import static org.junit.Assert.assertTrue; + +/** + * + */ +public class TopologyRecoveryRetry extends BrokerTestCase { + + @Test + public void topologyRecoveryRetry() throws Exception { + int nbQueues = 2000; + String prefix = "topology-recovery-retry-" + System.currentTimeMillis(); + for (int i = 0; i < nbQueues; i++) { + String queue = prefix + i; + channel.queueDeclare(queue, false, false, true, new HashMap<>()); + channel.queueBind(queue, "amq.direct", queue); + channel.basicConsume(queue, true, new DefaultConsumer(channel)); + } + + closeAllConnectionsAndWaitForRecovery(this.connection); + + assertTrue(channel.isOpen()); + } + + @Override + protected ConnectionFactory newConnectionFactory() { + ConnectionFactory connectionFactory = TestUtils.connectionFactory(); + connectionFactory.setTopologyRecoveryRetryHandler( + builder().bindingRecoveryRetryCondition((b, e) -> CHANNEL_CLOSED_NOT_FOUND.test(e)) + .consumerRecoveryRetryCondition((b, e) -> CHANNEL_CLOSED_NOT_FOUND.test(e)) + .bindingRecoveryRetryOperation(RECOVER_CHANNEL.andThen(RECOVER_BINDING_QUEUE).andThen(RECOVER_BINDING)) + .consumerRecoveryRetryOperation(RECOVER_CHANNEL.andThen(RECOVER_CONSUMER_QUEUE.andThen(RECOVER_CONSUMER))) + .build() + ); + connectionFactory.setNetworkRecoveryInterval(1000); + return connectionFactory; + } +} diff --git a/src/test/java/com/rabbitmq/tools/Host.java b/src/test/java/com/rabbitmq/tools/Host.java index 5924e5931d..c919d78621 100644 --- a/src/test/java/com/rabbitmq/tools/Host.java +++ b/src/test/java/com/rabbitmq/tools/Host.java @@ -169,6 +169,10 @@ public static void closeConnection(String pid) throws IOException { rabbitmqctl("close_connection '" + pid + "' 'Closed via rabbitmqctl'"); } + public static void closeAllConnections() throws IOException { + rabbitmqctl("close_all_connections 'Closed via rabbitmqctl'"); + } + public static void closeConnection(NetworkConnection c) throws IOException { Host.ConnectionInfo ci = findConnectionInfoFor(Host.listConnections(), c); closeConnection(ci.getPid()); From 917606253931ee515c9beb55349a35929eadc82e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 10 Aug 2018 09:16:16 +0200 Subject: [PATCH 0836/2114] Retry twice in topology recovery retry Instead of 1 by default. References #387 --- .../impl/recovery/TopologyRecoveryRetryHandlerBuilder.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryHandlerBuilder.java b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryHandlerBuilder.java index 07141b43e5..9ef35677df 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryHandlerBuilder.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryHandlerBuilder.java @@ -21,7 +21,7 @@ * Builder to ease creation of {@link DefaultRetryHandler} instances. *

* Just override what you need. By default, retry conditions don't trigger retry, - * retry operations are no-op, the number of retry attempts is 1, and the backoff + * retry operations are no-op, the number of retry attempts is 2, and the backoff * policy doesn't wait at all. * * @see DefaultRetryHandler @@ -40,7 +40,7 @@ public class TopologyRecoveryRetryHandlerBuilder { private DefaultRetryHandler.RetryOperation bindingRecoveryRetryOperation = context -> null; private DefaultRetryHandler.RetryOperation consumerRecoveryRetryOperation = context -> null; - private int retryAttempts = 1; + private int retryAttempts = 2; private BackoffPolicy backoffPolicy = nbAttempts -> { }; From 2a784544fd49b6faaf1719a9880ccf11d1552b83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 10 Aug 2018 09:16:16 +0200 Subject: [PATCH 0837/2114] Retry twice in topology recovery retry Instead of 1 by default. References #387 (cherry picked from commit 917606253931ee515c9beb55349a35929eadc82e) --- .../impl/recovery/TopologyRecoveryRetryHandlerBuilder.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryHandlerBuilder.java b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryHandlerBuilder.java index 07141b43e5..9ef35677df 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryHandlerBuilder.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryHandlerBuilder.java @@ -21,7 +21,7 @@ * Builder to ease creation of {@link DefaultRetryHandler} instances. *

* Just override what you need. By default, retry conditions don't trigger retry, - * retry operations are no-op, the number of retry attempts is 1, and the backoff + * retry operations are no-op, the number of retry attempts is 2, and the backoff * policy doesn't wait at all. * * @see DefaultRetryHandler @@ -40,7 +40,7 @@ public class TopologyRecoveryRetryHandlerBuilder { private DefaultRetryHandler.RetryOperation bindingRecoveryRetryOperation = context -> null; private DefaultRetryHandler.RetryOperation consumerRecoveryRetryOperation = context -> null; - private int retryAttempts = 1; + private int retryAttempts = 2; private BackoffPolicy backoffPolicy = nbAttempts -> { }; From 97114065b8fe15508aa4e42dbd86d77c2dda6498 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 10 Aug 2018 11:26:13 +0200 Subject: [PATCH 0838/2114] Make retry condition more tolerant with wildcards References #387 --- .../impl/recovery/DefaultRetryHandler.java | 31 ++++++++++--------- .../TopologyRecoveryRetryHandlerBuilder.java | 16 +++++----- .../recovery/TopologyRecoveryRetryLogic.java | 7 +++-- .../functional/TopologyRecoveryRetry.java | 4 +-- 4 files changed, 31 insertions(+), 27 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java b/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java index 8c9b1df3fd..350eb8fa8f 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java @@ -35,10 +35,10 @@ */ public class DefaultRetryHandler implements RetryHandler { - private final BiPredicate queueRecoveryRetryCondition; - private final BiPredicate exchangeRecoveryRetryCondition; - private final BiPredicate bindingRecoveryRetryCondition; - private final BiPredicate consumerRecoveryRetryCondition; + private final BiPredicate queueRecoveryRetryCondition; + private final BiPredicate exchangeRecoveryRetryCondition; + private final BiPredicate bindingRecoveryRetryCondition; + private final BiPredicate consumerRecoveryRetryCondition; private final RetryOperation queueRecoveryRetryOperation; private final RetryOperation exchangeRecoveryRetryOperation; @@ -49,10 +49,10 @@ public class DefaultRetryHandler implements RetryHandler { private final BackoffPolicy backoffPolicy; - public DefaultRetryHandler(BiPredicate queueRecoveryRetryCondition, - BiPredicate exchangeRecoveryRetryCondition, - BiPredicate bindingRecoveryRetryCondition, - BiPredicate consumerRecoveryRetryCondition, + public DefaultRetryHandler(BiPredicate queueRecoveryRetryCondition, + BiPredicate exchangeRecoveryRetryCondition, + BiPredicate bindingRecoveryRetryCondition, + BiPredicate consumerRecoveryRetryCondition, RetryOperation queueRecoveryRetryOperation, RetryOperation exchangeRecoveryRetryOperation, RetryOperation bindingRecoveryRetryOperation, @@ -72,27 +72,31 @@ public DefaultRetryHandler(BiPredicate queueRecoveryRe this.retryAttempts = retryAttempts; } + @SuppressWarnings("unchecked") @Override public RetryResult retryQueueRecovery(RetryContext context) throws Exception { - return doRetry(queueRecoveryRetryCondition, queueRecoveryRetryOperation, context.queue(), context); + return doRetry((BiPredicate) queueRecoveryRetryCondition, queueRecoveryRetryOperation, context.queue(), context); } + @SuppressWarnings("unchecked") @Override public RetryResult retryExchangeRecovery(RetryContext context) throws Exception { - return doRetry(exchangeRecoveryRetryCondition, exchangeRecoveryRetryOperation, context.exchange(), context); + return doRetry((BiPredicate) exchangeRecoveryRetryCondition, exchangeRecoveryRetryOperation, context.exchange(), context); } + @SuppressWarnings("unchecked") @Override public RetryResult retryBindingRecovery(RetryContext context) throws Exception { - return doRetry(bindingRecoveryRetryCondition, bindingRecoveryRetryOperation, context.binding(), context); + return doRetry((BiPredicate) bindingRecoveryRetryCondition, bindingRecoveryRetryOperation, context.binding(), context); } + @SuppressWarnings("unchecked") @Override public RetryResult retryConsumerRecovery(RetryContext context) throws Exception { - return doRetry(consumerRecoveryRetryCondition, consumerRecoveryRetryOperation, context.consumer(), context); + return doRetry((BiPredicate) consumerRecoveryRetryCondition, consumerRecoveryRetryOperation, context.consumer(), context); } - protected RetryResult doRetry(BiPredicate condition, RetryOperation operation, T entity, RetryContext context) + protected RetryResult doRetry(BiPredicate condition, RetryOperation operation, RecordedEntity entity, RetryContext context) throws Exception { int attempts = 0; Exception exception = context.exception(); @@ -107,7 +111,6 @@ protected RetryResult doRetry(BiPredicate queueRecoveryRetryCondition = (q, e) -> false; - private BiPredicate exchangeRecoveryRetryCondition = (ex, e) -> false; - private BiPredicate bindingRecoveryRetryCondition = (b, e) -> false; - private BiPredicate consumerRecoveryRetryCondition = (c, e) -> false; + private BiPredicate queueRecoveryRetryCondition = (q, e) -> false; + private BiPredicate exchangeRecoveryRetryCondition = (ex, e) -> false; + private BiPredicate bindingRecoveryRetryCondition = (b, e) -> false; + private BiPredicate consumerRecoveryRetryCondition = (c, e) -> false; private DefaultRetryHandler.RetryOperation queueRecoveryRetryOperation = context -> null; private DefaultRetryHandler.RetryOperation exchangeRecoveryRetryOperation = context -> null; @@ -50,25 +50,25 @@ public static TopologyRecoveryRetryHandlerBuilder builder() { } public TopologyRecoveryRetryHandlerBuilder queueRecoveryRetryCondition( - BiPredicate queueRecoveryRetryCondition) { + BiPredicate queueRecoveryRetryCondition) { this.queueRecoveryRetryCondition = queueRecoveryRetryCondition; return this; } public TopologyRecoveryRetryHandlerBuilder exchangeRecoveryRetryCondition( - BiPredicate exchangeRecoveryRetryCondition) { + BiPredicate exchangeRecoveryRetryCondition) { this.exchangeRecoveryRetryCondition = exchangeRecoveryRetryCondition; return this; } public TopologyRecoveryRetryHandlerBuilder bindingRecoveryRetryCondition( - BiPredicate bindingRecoveryRetryCondition) { + BiPredicate bindingRecoveryRetryCondition) { this.bindingRecoveryRetryCondition = bindingRecoveryRetryCondition; return this; } public TopologyRecoveryRetryHandlerBuilder consumerRecoveryRetryCondition( - BiPredicate consumerRecoveryRetryCondition) { + BiPredicate consumerRecoveryRetryCondition) { this.consumerRecoveryRetryCondition = consumerRecoveryRetryCondition; return this; } diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java index 8e6e16a790..582475b702 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java @@ -18,6 +18,7 @@ import com.rabbitmq.client.AMQP; import com.rabbitmq.client.ShutdownSignalException; +import java.util.function.BiPredicate; import java.util.function.Predicate; /** @@ -31,9 +32,9 @@ */ public abstract class TopologyRecoveryRetryLogic { - public static final Predicate CHANNEL_CLOSED_NOT_FOUND = e -> { - if (e.getCause() instanceof ShutdownSignalException) { - ShutdownSignalException cause = (ShutdownSignalException) e.getCause(); + public static final BiPredicate CHANNEL_CLOSED_NOT_FOUND = (entity, ex) -> { + if (ex.getCause() instanceof ShutdownSignalException) { + ShutdownSignalException cause = (ShutdownSignalException) ex.getCause(); if (cause.getReason() instanceof AMQP.Channel.Close) { return ((AMQP.Channel.Close) cause.getReason()).getReplyCode() == 404; } diff --git a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java index 4f8ab6054a..49819ce8d3 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java +++ b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java @@ -58,8 +58,8 @@ public void topologyRecoveryRetry() throws Exception { protected ConnectionFactory newConnectionFactory() { ConnectionFactory connectionFactory = TestUtils.connectionFactory(); connectionFactory.setTopologyRecoveryRetryHandler( - builder().bindingRecoveryRetryCondition((b, e) -> CHANNEL_CLOSED_NOT_FOUND.test(e)) - .consumerRecoveryRetryCondition((b, e) -> CHANNEL_CLOSED_NOT_FOUND.test(e)) + builder().bindingRecoveryRetryCondition(CHANNEL_CLOSED_NOT_FOUND) + .consumerRecoveryRetryCondition(CHANNEL_CLOSED_NOT_FOUND) .bindingRecoveryRetryOperation(RECOVER_CHANNEL.andThen(RECOVER_BINDING_QUEUE).andThen(RECOVER_BINDING)) .consumerRecoveryRetryOperation(RECOVER_CHANNEL.andThen(RECOVER_CONSUMER_QUEUE.andThen(RECOVER_CONSUMER))) .build() From f8b15528ad9fa763a4ca813454c9c42227fe87be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 10 Aug 2018 11:26:13 +0200 Subject: [PATCH 0839/2114] Make retry condition more tolerant with wildcards References #387 (cherry picked from commit 97114065b8fe15508aa4e42dbd86d77c2dda6498) --- .../impl/recovery/DefaultRetryHandler.java | 31 ++++++++++--------- .../TopologyRecoveryRetryHandlerBuilder.java | 16 +++++----- .../recovery/TopologyRecoveryRetryLogic.java | 7 +++-- .../functional/TopologyRecoveryRetry.java | 4 +-- 4 files changed, 31 insertions(+), 27 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java b/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java index 8c9b1df3fd..350eb8fa8f 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java @@ -35,10 +35,10 @@ */ public class DefaultRetryHandler implements RetryHandler { - private final BiPredicate queueRecoveryRetryCondition; - private final BiPredicate exchangeRecoveryRetryCondition; - private final BiPredicate bindingRecoveryRetryCondition; - private final BiPredicate consumerRecoveryRetryCondition; + private final BiPredicate queueRecoveryRetryCondition; + private final BiPredicate exchangeRecoveryRetryCondition; + private final BiPredicate bindingRecoveryRetryCondition; + private final BiPredicate consumerRecoveryRetryCondition; private final RetryOperation queueRecoveryRetryOperation; private final RetryOperation exchangeRecoveryRetryOperation; @@ -49,10 +49,10 @@ public class DefaultRetryHandler implements RetryHandler { private final BackoffPolicy backoffPolicy; - public DefaultRetryHandler(BiPredicate queueRecoveryRetryCondition, - BiPredicate exchangeRecoveryRetryCondition, - BiPredicate bindingRecoveryRetryCondition, - BiPredicate consumerRecoveryRetryCondition, + public DefaultRetryHandler(BiPredicate queueRecoveryRetryCondition, + BiPredicate exchangeRecoveryRetryCondition, + BiPredicate bindingRecoveryRetryCondition, + BiPredicate consumerRecoveryRetryCondition, RetryOperation queueRecoveryRetryOperation, RetryOperation exchangeRecoveryRetryOperation, RetryOperation bindingRecoveryRetryOperation, @@ -72,27 +72,31 @@ public DefaultRetryHandler(BiPredicate queueRecoveryRe this.retryAttempts = retryAttempts; } + @SuppressWarnings("unchecked") @Override public RetryResult retryQueueRecovery(RetryContext context) throws Exception { - return doRetry(queueRecoveryRetryCondition, queueRecoveryRetryOperation, context.queue(), context); + return doRetry((BiPredicate) queueRecoveryRetryCondition, queueRecoveryRetryOperation, context.queue(), context); } + @SuppressWarnings("unchecked") @Override public RetryResult retryExchangeRecovery(RetryContext context) throws Exception { - return doRetry(exchangeRecoveryRetryCondition, exchangeRecoveryRetryOperation, context.exchange(), context); + return doRetry((BiPredicate) exchangeRecoveryRetryCondition, exchangeRecoveryRetryOperation, context.exchange(), context); } + @SuppressWarnings("unchecked") @Override public RetryResult retryBindingRecovery(RetryContext context) throws Exception { - return doRetry(bindingRecoveryRetryCondition, bindingRecoveryRetryOperation, context.binding(), context); + return doRetry((BiPredicate) bindingRecoveryRetryCondition, bindingRecoveryRetryOperation, context.binding(), context); } + @SuppressWarnings("unchecked") @Override public RetryResult retryConsumerRecovery(RetryContext context) throws Exception { - return doRetry(consumerRecoveryRetryCondition, consumerRecoveryRetryOperation, context.consumer(), context); + return doRetry((BiPredicate) consumerRecoveryRetryCondition, consumerRecoveryRetryOperation, context.consumer(), context); } - protected RetryResult doRetry(BiPredicate condition, RetryOperation operation, T entity, RetryContext context) + protected RetryResult doRetry(BiPredicate condition, RetryOperation operation, RecordedEntity entity, RetryContext context) throws Exception { int attempts = 0; Exception exception = context.exception(); @@ -107,7 +111,6 @@ protected RetryResult doRetry(BiPredicate queueRecoveryRetryCondition = (q, e) -> false; - private BiPredicate exchangeRecoveryRetryCondition = (ex, e) -> false; - private BiPredicate bindingRecoveryRetryCondition = (b, e) -> false; - private BiPredicate consumerRecoveryRetryCondition = (c, e) -> false; + private BiPredicate queueRecoveryRetryCondition = (q, e) -> false; + private BiPredicate exchangeRecoveryRetryCondition = (ex, e) -> false; + private BiPredicate bindingRecoveryRetryCondition = (b, e) -> false; + private BiPredicate consumerRecoveryRetryCondition = (c, e) -> false; private DefaultRetryHandler.RetryOperation queueRecoveryRetryOperation = context -> null; private DefaultRetryHandler.RetryOperation exchangeRecoveryRetryOperation = context -> null; @@ -50,25 +50,25 @@ public static TopologyRecoveryRetryHandlerBuilder builder() { } public TopologyRecoveryRetryHandlerBuilder queueRecoveryRetryCondition( - BiPredicate queueRecoveryRetryCondition) { + BiPredicate queueRecoveryRetryCondition) { this.queueRecoveryRetryCondition = queueRecoveryRetryCondition; return this; } public TopologyRecoveryRetryHandlerBuilder exchangeRecoveryRetryCondition( - BiPredicate exchangeRecoveryRetryCondition) { + BiPredicate exchangeRecoveryRetryCondition) { this.exchangeRecoveryRetryCondition = exchangeRecoveryRetryCondition; return this; } public TopologyRecoveryRetryHandlerBuilder bindingRecoveryRetryCondition( - BiPredicate bindingRecoveryRetryCondition) { + BiPredicate bindingRecoveryRetryCondition) { this.bindingRecoveryRetryCondition = bindingRecoveryRetryCondition; return this; } public TopologyRecoveryRetryHandlerBuilder consumerRecoveryRetryCondition( - BiPredicate consumerRecoveryRetryCondition) { + BiPredicate consumerRecoveryRetryCondition) { this.consumerRecoveryRetryCondition = consumerRecoveryRetryCondition; return this; } diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java index 8e6e16a790..582475b702 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java @@ -18,6 +18,7 @@ import com.rabbitmq.client.AMQP; import com.rabbitmq.client.ShutdownSignalException; +import java.util.function.BiPredicate; import java.util.function.Predicate; /** @@ -31,9 +32,9 @@ */ public abstract class TopologyRecoveryRetryLogic { - public static final Predicate CHANNEL_CLOSED_NOT_FOUND = e -> { - if (e.getCause() instanceof ShutdownSignalException) { - ShutdownSignalException cause = (ShutdownSignalException) e.getCause(); + public static final BiPredicate CHANNEL_CLOSED_NOT_FOUND = (entity, ex) -> { + if (ex.getCause() instanceof ShutdownSignalException) { + ShutdownSignalException cause = (ShutdownSignalException) ex.getCause(); if (cause.getReason() instanceof AMQP.Channel.Close) { return ((AMQP.Channel.Close) cause.getReason()).getReplyCode() == 404; } diff --git a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java index 4f8ab6054a..49819ce8d3 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java +++ b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java @@ -58,8 +58,8 @@ public void topologyRecoveryRetry() throws Exception { protected ConnectionFactory newConnectionFactory() { ConnectionFactory connectionFactory = TestUtils.connectionFactory(); connectionFactory.setTopologyRecoveryRetryHandler( - builder().bindingRecoveryRetryCondition((b, e) -> CHANNEL_CLOSED_NOT_FOUND.test(e)) - .consumerRecoveryRetryCondition((b, e) -> CHANNEL_CLOSED_NOT_FOUND.test(e)) + builder().bindingRecoveryRetryCondition(CHANNEL_CLOSED_NOT_FOUND) + .consumerRecoveryRetryCondition(CHANNEL_CLOSED_NOT_FOUND) .bindingRecoveryRetryOperation(RECOVER_CHANNEL.andThen(RECOVER_BINDING_QUEUE).andThen(RECOVER_BINDING)) .consumerRecoveryRetryOperation(RECOVER_CHANNEL.andThen(RECOVER_CONSUMER_QUEUE.andThen(RECOVER_CONSUMER))) .build() From 514f9bddf0badbfbf27b51f45ec5418d873315e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 10 Aug 2018 11:50:37 +0200 Subject: [PATCH 0840/2114] Set release version to 5.4.0.M1 --- release-versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-versions.txt b/release-versions.txt index 3b0c3ec1b0..5a62e85797 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="5.4.0.RC1" +RELEASE_VERSION="5.4.0.M1" DEVELOPMENT_VERSION="5.4.0-SNAPSHOT" From 12bd625216f1d12f7b9a0ca886586e4d6b202448 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Fri, 10 Aug 2018 11:43:26 +0000 Subject: [PATCH 0841/2114] [maven-release-plugin] prepare release v5.4.0.M1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index b26766262b..60f6a45297 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.4.0-SNAPSHOT + 5.4.0.M1 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v5.4.0.M1 From 26a8dae5d135b1b846d3fa7ffb8bf3093f2c8ffb Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Fri, 10 Aug 2018 11:43:31 +0000 Subject: [PATCH 0842/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 60f6a45297..b26766262b 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.4.0.M1 + 5.4.0-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v5.4.0.M1 + HEAD From 2b8d257ddd2a87d98aa74bd6da9f49f8c7b25782 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 13 Aug 2018 10:53:36 +0200 Subject: [PATCH 0843/2114] Polish recovery retry Add log in default retry handler, add operation to recover all the bindings of a queue (useful when the recovery of a consumer fails because isn't found), make AutorecoveringConnection#recoverConsumer and AutorecoveringConnection#recoverQueue public as they contain useful logic that some client code should be able to use, and declared a pre-configured retry handler for the deleted queue case. References #387 --- .../recovery/AutorecoveringConnection.java | 8 ++- .../impl/recovery/DefaultRetryHandler.java | 10 ++++ .../recovery/TopologyRecoveryRetryLogic.java | 50 +++++++++++++++++++ .../functional/TopologyRecoveryRetry.java | 16 +----- 4 files changed, 68 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index c3e66e0d2f..c200c8fd59 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -709,7 +709,7 @@ private void recoverExchange(RecordedExchange x, boolean retry) { } - void recoverQueue(final String oldName, RecordedQueue q, boolean retry) { + public void recoverQueue(final String oldName, RecordedQueue q, boolean retry) { try { if (topologyRecoveryFilter.filterQueue(q)) { LOGGER.debug("Recovering {}", q); @@ -774,7 +774,7 @@ private void recoverBinding(RecordedBinding b, boolean retry) { } } - private void recoverConsumer(final String tag, RecordedConsumer consumer, boolean retry) { + public void recoverConsumer(final String tag, RecordedConsumer consumer, boolean retry) { try { if (this.topologyRecoveryFilter.filterConsumer(consumer)) { LOGGER.debug("Recovering {}", consumer); @@ -1087,6 +1087,10 @@ public Map getRecordedExchanges() { return recordedExchanges; } + public List getRecordedBindings() { + return recordedBindings; + } + @Override public String toString() { return this.delegate.toString(); diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java b/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java index 350eb8fa8f..98978eb6d1 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java @@ -15,6 +15,9 @@ package com.rabbitmq.client.impl.recovery; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.util.Objects; import java.util.function.BiPredicate; @@ -35,6 +38,8 @@ */ public class DefaultRetryHandler implements RetryHandler { + private static final Logger LOGGER = LoggerFactory.getLogger(DefaultRetryHandler.class); + private final BiPredicate queueRecoveryRetryCondition; private final BiPredicate exchangeRecoveryRetryCondition; private final BiPredicate bindingRecoveryRetryCondition; @@ -98,6 +103,7 @@ public RetryResult retryConsumerRecovery(RetryContext context) throws Exception protected RetryResult doRetry(BiPredicate condition, RetryOperation operation, RecordedEntity entity, RetryContext context) throws Exception { + log(entity, context.exception()); int attempts = 0; Exception exception = context.exception(); while (attempts < retryAttempts) { @@ -119,6 +125,10 @@ protected RetryResult doRetry(BiPredicate condition, throw context.exception(); } + protected void log(RecordedEntity entity, Exception exception) { + LOGGER.info("Error while recovering {}, retrying with {} attempt(s).", entity, retryAttempts, exception); + } + public interface RetryOperation { T call(RetryContext context) throws Exception; diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java index 582475b702..9d8d2be9a5 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java @@ -18,9 +18,12 @@ import com.rabbitmq.client.AMQP; import com.rabbitmq.client.ShutdownSignalException; +import java.util.List; import java.util.function.BiPredicate; import java.util.function.Predicate; +import static com.rabbitmq.client.impl.recovery.TopologyRecoveryRetryHandlerBuilder.builder; + /** * Useful ready-to-use conditions and operations for {@link DefaultRetryHandler}. * They're composed and used with the {@link TopologyRecoveryRetryHandlerBuilder}. @@ -32,6 +35,9 @@ */ public abstract class TopologyRecoveryRetryLogic { + /** + * Channel has been closed because of a resource that doesn't exist. + */ public static final BiPredicate CHANNEL_CLOSED_NOT_FOUND = (entity, ex) -> { if (ex.getCause() instanceof ShutdownSignalException) { ShutdownSignalException cause = (ShutdownSignalException) ex.getCause(); @@ -42,6 +48,9 @@ public abstract class TopologyRecoveryRetryLogic { return false; }; + /** + * Recover a channel. + */ public static final DefaultRetryHandler.RetryOperation RECOVER_CHANNEL = context -> { if (!context.entity().getChannel().isOpen()) { context.connection().recoverChannel(context.entity().getChannel()); @@ -49,6 +58,9 @@ public abstract class TopologyRecoveryRetryLogic { return null; }; + /** + * Recover the destination queue of a binding. + */ public static final DefaultRetryHandler.RetryOperation RECOVER_BINDING_QUEUE = context -> { if (context.entity() instanceof RecordedQueueBinding) { RecordedBinding binding = context.binding(); @@ -63,11 +75,17 @@ public abstract class TopologyRecoveryRetryLogic { return null; }; + /** + * Recover a binding. + */ public static final DefaultRetryHandler.RetryOperation RECOVER_BINDING = context -> { context.binding().recover(); return null; }; + /** + * Recover the queue of a consumer. + */ public static final DefaultRetryHandler.RetryOperation RECOVER_CONSUMER_QUEUE = context -> { if (context.entity() instanceof RecordedConsumer) { RecordedConsumer consumer = context.consumer(); @@ -82,5 +100,37 @@ public abstract class TopologyRecoveryRetryLogic { return null; }; + /** + * Recover all the bindings of the queue of a consumer. + */ + public static final DefaultRetryHandler.RetryOperation RECOVER_CONSUMER_QUEUE_BINDINGS = context -> { + if (context.entity() instanceof RecordedConsumer) { + String queue = context.consumer().getQueue(); + for (RecordedBinding recordedBinding : context.connection().getRecordedBindings()) { + if (recordedBinding instanceof RecordedQueueBinding && queue.equals(recordedBinding.getDestination())) { + recordedBinding.recover(); + } + } + } + return null; + }; + + /** + * Recover a consumer. + */ public static final DefaultRetryHandler.RetryOperation RECOVER_CONSUMER = context -> context.consumer().recover(); + + /** + * Pre-configured {@link DefaultRetryHandler} that retries recovery of bindings and consumers + * when their respective queue is not found. + * This retry handler can be useful for long recovery processes, whereby auto-delete queues + * can be deleted between queue recovery and binding/consumer recovery. + */ + public static final RetryHandler RETRY_ON_QUEUE_NOT_FOUND_RETRY_HANDLER = builder() + .bindingRecoveryRetryCondition(CHANNEL_CLOSED_NOT_FOUND) + .consumerRecoveryRetryCondition(CHANNEL_CLOSED_NOT_FOUND) + .bindingRecoveryRetryOperation(RECOVER_CHANNEL.andThen(RECOVER_BINDING_QUEUE).andThen(RECOVER_BINDING)) + .consumerRecoveryRetryOperation(RECOVER_CHANNEL.andThen(RECOVER_CONSUMER_QUEUE.andThen(RECOVER_CONSUMER) + .andThen(RECOVER_CONSUMER_QUEUE_BINDINGS))) + .build(); } diff --git a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java index 49819ce8d3..71277c9826 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java +++ b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java @@ -23,13 +23,7 @@ import java.util.HashMap; -import static com.rabbitmq.client.impl.recovery.TopologyRecoveryRetryHandlerBuilder.builder; -import static com.rabbitmq.client.impl.recovery.TopologyRecoveryRetryLogic.CHANNEL_CLOSED_NOT_FOUND; -import static com.rabbitmq.client.impl.recovery.TopologyRecoveryRetryLogic.RECOVER_BINDING; -import static com.rabbitmq.client.impl.recovery.TopologyRecoveryRetryLogic.RECOVER_BINDING_QUEUE; -import static com.rabbitmq.client.impl.recovery.TopologyRecoveryRetryLogic.RECOVER_CHANNEL; -import static com.rabbitmq.client.impl.recovery.TopologyRecoveryRetryLogic.RECOVER_CONSUMER; -import static com.rabbitmq.client.impl.recovery.TopologyRecoveryRetryLogic.RECOVER_CONSUMER_QUEUE; +import static com.rabbitmq.client.impl.recovery.TopologyRecoveryRetryLogic.RETRY_ON_QUEUE_NOT_FOUND_RETRY_HANDLER; import static com.rabbitmq.client.test.TestUtils.closeAllConnectionsAndWaitForRecovery; import static org.junit.Assert.assertTrue; @@ -57,13 +51,7 @@ public void topologyRecoveryRetry() throws Exception { @Override protected ConnectionFactory newConnectionFactory() { ConnectionFactory connectionFactory = TestUtils.connectionFactory(); - connectionFactory.setTopologyRecoveryRetryHandler( - builder().bindingRecoveryRetryCondition(CHANNEL_CLOSED_NOT_FOUND) - .consumerRecoveryRetryCondition(CHANNEL_CLOSED_NOT_FOUND) - .bindingRecoveryRetryOperation(RECOVER_CHANNEL.andThen(RECOVER_BINDING_QUEUE).andThen(RECOVER_BINDING)) - .consumerRecoveryRetryOperation(RECOVER_CHANNEL.andThen(RECOVER_CONSUMER_QUEUE.andThen(RECOVER_CONSUMER))) - .build() - ); + connectionFactory.setTopologyRecoveryRetryHandler(RETRY_ON_QUEUE_NOT_FOUND_RETRY_HANDLER); connectionFactory.setNetworkRecoveryInterval(1000); return connectionFactory; } From f4978bc66473ae0afdce144603d2c419b99a2fa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 13 Aug 2018 10:53:36 +0200 Subject: [PATCH 0844/2114] Polish recovery retry Add log in default retry handler, add operation to recover all the bindings of a queue (useful when the recovery of a consumer fails because isn't found), make AutorecoveringConnection#recoverConsumer and AutorecoveringConnection#recoverQueue public as they contain useful logic that some client code should be able to use, and declared a pre-configured retry handler for the deleted queue case. References #387 (cherry picked from commit 2b8d257ddd2a87d98aa74bd6da9f49f8c7b25782) --- .../recovery/AutorecoveringConnection.java | 8 ++- .../impl/recovery/DefaultRetryHandler.java | 10 ++++ .../recovery/TopologyRecoveryRetryLogic.java | 50 +++++++++++++++++++ .../functional/TopologyRecoveryRetry.java | 16 +----- 4 files changed, 68 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index c3e66e0d2f..c200c8fd59 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -709,7 +709,7 @@ private void recoverExchange(RecordedExchange x, boolean retry) { } - void recoverQueue(final String oldName, RecordedQueue q, boolean retry) { + public void recoverQueue(final String oldName, RecordedQueue q, boolean retry) { try { if (topologyRecoveryFilter.filterQueue(q)) { LOGGER.debug("Recovering {}", q); @@ -774,7 +774,7 @@ private void recoverBinding(RecordedBinding b, boolean retry) { } } - private void recoverConsumer(final String tag, RecordedConsumer consumer, boolean retry) { + public void recoverConsumer(final String tag, RecordedConsumer consumer, boolean retry) { try { if (this.topologyRecoveryFilter.filterConsumer(consumer)) { LOGGER.debug("Recovering {}", consumer); @@ -1087,6 +1087,10 @@ public Map getRecordedExchanges() { return recordedExchanges; } + public List getRecordedBindings() { + return recordedBindings; + } + @Override public String toString() { return this.delegate.toString(); diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java b/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java index 350eb8fa8f..98978eb6d1 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java @@ -15,6 +15,9 @@ package com.rabbitmq.client.impl.recovery; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.util.Objects; import java.util.function.BiPredicate; @@ -35,6 +38,8 @@ */ public class DefaultRetryHandler implements RetryHandler { + private static final Logger LOGGER = LoggerFactory.getLogger(DefaultRetryHandler.class); + private final BiPredicate queueRecoveryRetryCondition; private final BiPredicate exchangeRecoveryRetryCondition; private final BiPredicate bindingRecoveryRetryCondition; @@ -98,6 +103,7 @@ public RetryResult retryConsumerRecovery(RetryContext context) throws Exception protected RetryResult doRetry(BiPredicate condition, RetryOperation operation, RecordedEntity entity, RetryContext context) throws Exception { + log(entity, context.exception()); int attempts = 0; Exception exception = context.exception(); while (attempts < retryAttempts) { @@ -119,6 +125,10 @@ protected RetryResult doRetry(BiPredicate condition, throw context.exception(); } + protected void log(RecordedEntity entity, Exception exception) { + LOGGER.info("Error while recovering {}, retrying with {} attempt(s).", entity, retryAttempts, exception); + } + public interface RetryOperation { T call(RetryContext context) throws Exception; diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java index 582475b702..9d8d2be9a5 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java @@ -18,9 +18,12 @@ import com.rabbitmq.client.AMQP; import com.rabbitmq.client.ShutdownSignalException; +import java.util.List; import java.util.function.BiPredicate; import java.util.function.Predicate; +import static com.rabbitmq.client.impl.recovery.TopologyRecoveryRetryHandlerBuilder.builder; + /** * Useful ready-to-use conditions and operations for {@link DefaultRetryHandler}. * They're composed and used with the {@link TopologyRecoveryRetryHandlerBuilder}. @@ -32,6 +35,9 @@ */ public abstract class TopologyRecoveryRetryLogic { + /** + * Channel has been closed because of a resource that doesn't exist. + */ public static final BiPredicate CHANNEL_CLOSED_NOT_FOUND = (entity, ex) -> { if (ex.getCause() instanceof ShutdownSignalException) { ShutdownSignalException cause = (ShutdownSignalException) ex.getCause(); @@ -42,6 +48,9 @@ public abstract class TopologyRecoveryRetryLogic { return false; }; + /** + * Recover a channel. + */ public static final DefaultRetryHandler.RetryOperation RECOVER_CHANNEL = context -> { if (!context.entity().getChannel().isOpen()) { context.connection().recoverChannel(context.entity().getChannel()); @@ -49,6 +58,9 @@ public abstract class TopologyRecoveryRetryLogic { return null; }; + /** + * Recover the destination queue of a binding. + */ public static final DefaultRetryHandler.RetryOperation RECOVER_BINDING_QUEUE = context -> { if (context.entity() instanceof RecordedQueueBinding) { RecordedBinding binding = context.binding(); @@ -63,11 +75,17 @@ public abstract class TopologyRecoveryRetryLogic { return null; }; + /** + * Recover a binding. + */ public static final DefaultRetryHandler.RetryOperation RECOVER_BINDING = context -> { context.binding().recover(); return null; }; + /** + * Recover the queue of a consumer. + */ public static final DefaultRetryHandler.RetryOperation RECOVER_CONSUMER_QUEUE = context -> { if (context.entity() instanceof RecordedConsumer) { RecordedConsumer consumer = context.consumer(); @@ -82,5 +100,37 @@ public abstract class TopologyRecoveryRetryLogic { return null; }; + /** + * Recover all the bindings of the queue of a consumer. + */ + public static final DefaultRetryHandler.RetryOperation RECOVER_CONSUMER_QUEUE_BINDINGS = context -> { + if (context.entity() instanceof RecordedConsumer) { + String queue = context.consumer().getQueue(); + for (RecordedBinding recordedBinding : context.connection().getRecordedBindings()) { + if (recordedBinding instanceof RecordedQueueBinding && queue.equals(recordedBinding.getDestination())) { + recordedBinding.recover(); + } + } + } + return null; + }; + + /** + * Recover a consumer. + */ public static final DefaultRetryHandler.RetryOperation RECOVER_CONSUMER = context -> context.consumer().recover(); + + /** + * Pre-configured {@link DefaultRetryHandler} that retries recovery of bindings and consumers + * when their respective queue is not found. + * This retry handler can be useful for long recovery processes, whereby auto-delete queues + * can be deleted between queue recovery and binding/consumer recovery. + */ + public static final RetryHandler RETRY_ON_QUEUE_NOT_FOUND_RETRY_HANDLER = builder() + .bindingRecoveryRetryCondition(CHANNEL_CLOSED_NOT_FOUND) + .consumerRecoveryRetryCondition(CHANNEL_CLOSED_NOT_FOUND) + .bindingRecoveryRetryOperation(RECOVER_CHANNEL.andThen(RECOVER_BINDING_QUEUE).andThen(RECOVER_BINDING)) + .consumerRecoveryRetryOperation(RECOVER_CHANNEL.andThen(RECOVER_CONSUMER_QUEUE.andThen(RECOVER_CONSUMER) + .andThen(RECOVER_CONSUMER_QUEUE_BINDINGS))) + .build(); } diff --git a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java index 49819ce8d3..71277c9826 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java +++ b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java @@ -23,13 +23,7 @@ import java.util.HashMap; -import static com.rabbitmq.client.impl.recovery.TopologyRecoveryRetryHandlerBuilder.builder; -import static com.rabbitmq.client.impl.recovery.TopologyRecoveryRetryLogic.CHANNEL_CLOSED_NOT_FOUND; -import static com.rabbitmq.client.impl.recovery.TopologyRecoveryRetryLogic.RECOVER_BINDING; -import static com.rabbitmq.client.impl.recovery.TopologyRecoveryRetryLogic.RECOVER_BINDING_QUEUE; -import static com.rabbitmq.client.impl.recovery.TopologyRecoveryRetryLogic.RECOVER_CHANNEL; -import static com.rabbitmq.client.impl.recovery.TopologyRecoveryRetryLogic.RECOVER_CONSUMER; -import static com.rabbitmq.client.impl.recovery.TopologyRecoveryRetryLogic.RECOVER_CONSUMER_QUEUE; +import static com.rabbitmq.client.impl.recovery.TopologyRecoveryRetryLogic.RETRY_ON_QUEUE_NOT_FOUND_RETRY_HANDLER; import static com.rabbitmq.client.test.TestUtils.closeAllConnectionsAndWaitForRecovery; import static org.junit.Assert.assertTrue; @@ -57,13 +51,7 @@ public void topologyRecoveryRetry() throws Exception { @Override protected ConnectionFactory newConnectionFactory() { ConnectionFactory connectionFactory = TestUtils.connectionFactory(); - connectionFactory.setTopologyRecoveryRetryHandler( - builder().bindingRecoveryRetryCondition(CHANNEL_CLOSED_NOT_FOUND) - .consumerRecoveryRetryCondition(CHANNEL_CLOSED_NOT_FOUND) - .bindingRecoveryRetryOperation(RECOVER_CHANNEL.andThen(RECOVER_BINDING_QUEUE).andThen(RECOVER_BINDING)) - .consumerRecoveryRetryOperation(RECOVER_CHANNEL.andThen(RECOVER_CONSUMER_QUEUE.andThen(RECOVER_CONSUMER))) - .build() - ); + connectionFactory.setTopologyRecoveryRetryHandler(RETRY_ON_QUEUE_NOT_FOUND_RETRY_HANDLER); connectionFactory.setNetworkRecoveryInterval(1000); return connectionFactory; } From 0a3bed1ae57c308f806c476f1c89f951a41888ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 13 Aug 2018 11:28:08 +0200 Subject: [PATCH 0845/2114] Introduce JsonRpcMapper abstract WIP References #378 --- .../com/rabbitmq/tools/json/JSONUtil.java | 2 - .../tools/jsonrpc/DefaultJsonRpcMapper.java | 72 +++++++++++++++ .../rabbitmq/tools/jsonrpc/JsonRpcClient.java | 25 +++--- .../tools/jsonrpc/JsonRpcException.java | 35 ++++---- .../rabbitmq/tools/jsonrpc/JsonRpcMapper.java | 89 +++++++++++++++++++ .../rabbitmq/tools/jsonrpc/JsonRpcServer.java | 30 ++++--- .../tools/jsonrpc/ServiceDescription.java | 4 +- .../java/com/rabbitmq/client/JsonRpcTest.java | 63 ++++++++++--- 8 files changed, 263 insertions(+), 57 deletions(-) create mode 100644 src/main/java/com/rabbitmq/tools/jsonrpc/DefaultJsonRpcMapper.java create mode 100644 src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java diff --git a/src/main/java/com/rabbitmq/tools/json/JSONUtil.java b/src/main/java/com/rabbitmq/tools/json/JSONUtil.java index 6050482f5e..c40727d6e8 100644 --- a/src/main/java/com/rabbitmq/tools/json/JSONUtil.java +++ b/src/main/java/com/rabbitmq/tools/json/JSONUtil.java @@ -61,7 +61,6 @@ public static Object fill(Object target, Map source, boolean use String name = prop.getName(); Method setter = prop.getWriteMethod(); if (setter != null && !Modifier.isStatic(setter.getModifiers())) { - //System.out.println(target + " " + name + " <- " + source.get(name)); setter.invoke(target, source.get(name)); } } @@ -74,7 +73,6 @@ public static Object fill(Object target, Map source, boolean use if (Modifier.isPublic(fieldMod) && !(Modifier.isFinal(fieldMod) || Modifier.isStatic(fieldMod))) { - //System.out.println(target + " " + field.getName() + " := " + source.get(field.getName())); try { field.set(target, source.get(field.getName())); } catch (IllegalArgumentException iae) { diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/DefaultJsonRpcMapper.java b/src/main/java/com/rabbitmq/tools/jsonrpc/DefaultJsonRpcMapper.java new file mode 100644 index 0000000000..358284d650 --- /dev/null +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/DefaultJsonRpcMapper.java @@ -0,0 +1,72 @@ +package com.rabbitmq.tools.jsonrpc; + +import com.rabbitmq.tools.json.JSONReader; +import com.rabbitmq.tools.json.JSONWriter; + +import java.lang.reflect.Method; +import java.util.List; +import java.util.Map; + +/** + * + */ +public class DefaultJsonRpcMapper implements JsonRpcMapper { + + @Override + public JsonRpcRequest parse(String requestBody, ServiceDescription description) { + Map request = (Map) new JSONReader().read(requestBody); + + return new JsonRpcRequest( + request.get("id"), request.get("version").toString(), request.get("method").toString(), + ((List) request.get("params")).toArray() + ); + } + + @Override + public JsonRpcResponse parse(String responseBody) { + Map map = (Map) (new JSONReader().read(responseBody)); + Map error; + JsonRpcException exception = null; + if (map.containsKey("error")) { + error = (Map) map.get("error"); + exception = new JsonRpcException( + new JSONWriter().write(error), + (String) error.get("name"), + error.get("code") == null ? 0 : (Integer) error.get("code"), + (String) error.get("message"), + error + ); + } + return new JsonRpcResponse(map, map.get("result"), map.get("error"), exception); + } + + @Override + public Object[] parameters(JsonRpcRequest request, Method method) { + Object[] parameters = request.getParameters(); + Object[] convertedParameters = new Object[parameters.length]; + Class[] parameterTypes = method.getParameterTypes(); + for (int i = 0; i < parameters.length; i++) { + convertedParameters[i] = convert(parameters[i], parameterTypes[i]); + } + return convertedParameters; + } + + @Override + public String write(Object input) { + return new JSONWriter().write(input); + } + + protected Object convert(Object input, Class expectedClass) { + return input; +// if (input == null || input.getClass().equals(expectedClass)) { +// return input; +// } +// System.err.println(input.getClass() + " " + expectedClass); +// if (Long.class.equals(expectedClass) && input instanceof Integer) { +// return Long.valueOf(((Integer) input).longValue()); +// } else if (long.class.equals(expectedClass) && input instanceof Integer) { +// return +// } +// return input; + } +} diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java index 31822da6d0..581e304f83 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java @@ -62,6 +62,8 @@ public class JsonRpcClient extends RpcClient implements InvocationHandler { /** Holds the JSON-RPC service description for this client. */ private ServiceDescription serviceDescription; + private final JsonRpcMapper mapper; + /** * Construct a new JsonRpcClient, passing the parameters through * to RpcClient's constructor. The service description record is @@ -72,6 +74,7 @@ public JsonRpcClient(Channel channel, String exchange, String routingKey, int ti throws IOException, JsonRpcException, TimeoutException { super(channel, exchange, routingKey, timeout); + this.mapper = new DefaultJsonRpcMapper(); retrieveServiceDescription(); } @@ -86,18 +89,14 @@ public JsonRpcClient(Channel channel, String exchange, String routingKey) * @return the result contained within the reply, if no exception is found * Throws JsonRpcException if the reply object contained an exception */ - public static Object checkReply(Map reply) + private Object checkReply(JsonRpcMapper.JsonRpcResponse reply) throws JsonRpcException { - if (reply.containsKey("error")) { - @SuppressWarnings("unchecked") - Map map = (Map) reply.get("error"); - // actually a Map - throw new JsonRpcException(map); - } + if (reply.getError() != null) { + throw reply.getException(); + } - Object result = reply.get("result"); - return result; + return reply.getResult(); } /** @@ -114,16 +113,16 @@ public Object call(String method, Object[] params) throws IOException, JsonRpcEx request.put("method", method); request.put("version", ServiceDescription.JSON_RPC_VERSION); request.put("params", (params == null) ? new Object[0] : params); - String requestStr = new JSONWriter().write(request); + String requestStr = mapper.write(request); try { String replyStr = this.stringCall(requestStr); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Reply string: {}", replyStr); } - @SuppressWarnings("unchecked") - Map map = (Map) (new JSONReader().read(replyStr)); - return checkReply(map); + JsonRpcMapper.JsonRpcResponse reply = mapper.parse(replyStr); + + return checkReply(reply); } catch(ShutdownSignalException ex) { throw new IOException(ex.getMessage()); // wrap, re-throw } diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java index cbefc4fb21..fafb9457d0 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java @@ -13,40 +13,43 @@ // If you have any questions regarding licensing, please contact us at // info@rabbitmq.com. - package com.rabbitmq.tools.jsonrpc; -import java.util.Map; - -import com.rabbitmq.tools.json.JSONWriter; - /** * Thrown when a JSON-RPC service indicates an error occurred during a call. */ public class JsonRpcException extends Exception { + /** * Default serialized version ID */ private static final long serialVersionUID = 1L; - /** Usually the constant string, "JSONRPCError" */ + /** + * Usually the constant string, "JSONRPCError" + */ public String name; - /** Error code */ + /** + * Error code + */ public int code; - /** Error message */ + /** + * Error message + */ public String message; - /** Error detail object - may not always be present or meaningful */ + /** + * Error detail object - may not always be present or meaningful + */ public Object error; public JsonRpcException() { // no work needed in default no-arg constructor } - public JsonRpcException(Map errorMap) { - super(new JSONWriter().write(errorMap)); - name = (String) errorMap.get("name"); - code = 0; - if (errorMap.get("code") != null) { code = ((Integer) errorMap.get("code")); } - message = (String) errorMap.get("message"); - error = errorMap.get("error"); + public JsonRpcException(String detailMessage, String name, int code, String message, Object error) { + super(detailMessage); + this.name = name; + this.code = code; + this.message = message; + this.error = error; } } diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java new file mode 100644 index 0000000000..d1e32b0492 --- /dev/null +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java @@ -0,0 +1,89 @@ +package com.rabbitmq.tools.jsonrpc; + +import java.lang.reflect.Method; + +/** + * + */ +public interface JsonRpcMapper { + + JsonRpcRequest parse(String requestBody, ServiceDescription description); + + JsonRpcResponse parse(String responseBody); + + Object[] parameters(JsonRpcRequest request, Method method); + + String write(Object input); + + class JsonRpcRequest { + + private final Object id; + private final String version; + private final String method; + private final Object[] parameters; + + public JsonRpcRequest(Object id, String version, String method, Object[] parameters) { + this.id = id; + this.version = version; + this.method = method; + this.parameters = parameters; + } + + public Object getId() { + return id; + } + + public String getVersion() { + return version; + } + + public String getMethod() { + return method; + } + + public Object[] getParameters() { + return parameters; + } + + public boolean isSystem() { + return method.startsWith("system."); + } + + public boolean isSystemDescribe() { + return "system.describe".equals(method); + } + + } + + class JsonRpcResponse { + + private final Object reply; + private final Object result; + private final Object error; + private final JsonRpcException exception; + + public JsonRpcResponse(Object reply, Object result, Object error, JsonRpcException exception) { + this.reply = reply; + this.result = result; + this.error = error; + this.exception = exception; + } + + public Object getReply() { + return reply; + } + + public Object getError() { + return error; + } + + public Object getResult() { + return result; + } + + public JsonRpcException getException() { + return exception; + } + } + +} diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java index 138f654b12..068fae1546 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java @@ -55,6 +55,8 @@ public class JsonRpcServer extends StringRpcServer { /** The instance backing this server. */ public Object interfaceInstance; + private final JsonRpcMapper mapper; + /** * Construct a server that talks to the outside world using the * given channel, and constructs a fresh temporary @@ -70,6 +72,7 @@ public JsonRpcServer(Channel channel, throws IOException { super(channel); + this.mapper = new DefaultJsonRpcMapper(); init(interfaceClass, interfaceInstance); } @@ -98,6 +101,7 @@ public JsonRpcServer(Channel channel, throws IOException { super(channel, queueName); + this.mapper = new DefaultJsonRpcMapper(); init(interfaceClass, interfaceInstance); } @@ -126,25 +130,24 @@ public String doCall(String requestBody) LOGGER.debug("Request: {}", requestBody); } try { - @SuppressWarnings("unchecked") - Map request = (Map) new JSONReader().read(requestBody); + JsonRpcMapper.JsonRpcRequest request = mapper.parse(requestBody, serviceDescription); if (request == null) { response = errorResponse(null, 400, "Bad Request", null); - } else if (!ServiceDescription.JSON_RPC_VERSION.equals(request.get("version"))) { + } else if (!ServiceDescription.JSON_RPC_VERSION.equals(request.getVersion())) { response = errorResponse(null, 505, "JSONRPC version not supported", null); } else { - id = request.get("id"); - method = (String) request.get("method"); - List parmList = (List) request.get("params"); - params = parmList.toArray(); - if (method.equals("system.describe")) { + id = request.getId(); + method = request.getMethod(); + params = request.getParameters(); + if (request.isSystemDescribe()) { response = resultResponse(id, serviceDescription); - } else if (method.startsWith("system.")) { + } else if (request.isSystem()) { response = errorResponse(id, 403, "System methods forbidden", null); } else { Object result; try { Method matchingMethod = matchingMethod(method, params); + params = mapper.parameters(request, matchingMethod); if (LOGGER.isDebugEnabled()) { Collection parametersValuesAndTypes = new ArrayList(); if (params != null) { @@ -197,7 +200,7 @@ public Method matchingMethod(String methodName, Object[] params) * ID given, using the code, message, and possible * (JSON-encodable) argument passed in. */ - public static String errorResponse(Object id, int code, String message, Object errorArg) { + private String errorResponse(Object id, int code, String message, Object errorArg) { Map err = new HashMap(); err.put("name", "JSONRPCError"); err.put("code", code); @@ -210,22 +213,21 @@ public static String errorResponse(Object id, int code, String message, Object e * Construct and encode a JSON-RPC success response for the * request ID given, using the result value passed in. */ - public static String resultResponse(Object id, Object result) { + private String resultResponse(Object id, Object result) { return response(id, "result", result); } /** * Private API - used by errorResponse and resultResponse. */ - public static String response(Object id, String label, Object value) { + private String response(Object id, String label, Object value) { Map resp = new HashMap(); resp.put("version", ServiceDescription.JSON_RPC_VERSION); if (id != null) { resp.put("id", id); } resp.put(label, value); - String respStr = new JSONWriter().write(resp); - //System.err.println(respStr); + String respStr = mapper.write(resp); return respStr; } diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java b/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java index 79d750278b..4cb6d3bf66 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java @@ -48,7 +48,7 @@ public ServiceDescription(Map rawServiceDescription) { } public ServiceDescription(Class klass) { - this.procedures = new HashMap(); + this.procedures = new HashMap<>(); for (Method m: klass.getMethods()) { ProcedureDescription proc = new ProcedureDescription(m); addProcedure(proc); @@ -66,7 +66,7 @@ public Collection getProcs() { /** Private API - used via reflection during parsing/loading */ public void setProcs(Collection> p) { - procedures = new HashMap(); + procedures = new HashMap<>(); for (Map pm: p) { ProcedureDescription proc = new ProcedureDescription(pm); addProcedure(proc); diff --git a/src/test/java/com/rabbitmq/client/JsonRpcTest.java b/src/test/java/com/rabbitmq/client/JsonRpcTest.java index b6f73c824e..f13b5b4036 100644 --- a/src/test/java/com/rabbitmq/client/JsonRpcTest.java +++ b/src/test/java/com/rabbitmq/client/JsonRpcTest.java @@ -44,15 +44,11 @@ public void init() throws Exception { serverChannel = serverConnection.createChannel(); serverChannel.queueDeclare(queue, false, false, false, null); server = new JsonRpcServer(serverChannel, queue, RpcService.class, new DefaultRpcservice()); - new Thread(new Runnable() { - - @Override - public void run() { - try { - server.mainloop(); - } catch (Exception e) { - // safe to ignore when loops ends/server is canceled - } + new Thread(() -> { + try { + server.mainloop(); + } catch (Exception e) { + // safe to ignore when loops ends/server is canceled } }).start(); client = new JsonRpcClient(clientChannel, "", queue, 1000); @@ -103,6 +99,23 @@ public void rpc() { } catch (UndeclaredThrowableException e) { // OK } + + try { + assertEquals("123", service.procedureIntegerToPojo(123).getStringProperty()); + fail("Complex return type not supported"); + } catch (ClassCastException e) { + // OK + } + + try { + Pojo pojo = new Pojo(); + pojo.setStringProperty("hello"); + assertEquals("hello", service.procedurePojoToString(pojo)); + fail("Complex type argument not supported"); + } catch (UndeclaredThrowableException e) { + // OK + } + } public interface RpcService { @@ -124,9 +137,14 @@ public interface RpcService { Long procedureLong(Long input); long procedurePrimitiveLong(long input); + + Pojo procedureIntegerToPojo(Integer id); + + String procedurePojoToString(Pojo pojo); + } - public class DefaultRpcservice implements RpcService { + public static class DefaultRpcservice implements RpcService { @Override public String procedureString(String input) { @@ -172,5 +190,30 @@ public Integer procedureLongToInteger(Long input) { public int procedurePrimitiveLongToInteger(long input) { return (int) input + 1; } + + @Override + public Pojo procedureIntegerToPojo(Integer id) { + Pojo pojo = new Pojo(); + pojo.setStringProperty(id.toString()); + return pojo; + } + + @Override + public String procedurePojoToString(Pojo pojo) { + return pojo.getStringProperty(); + } + } + + public static class Pojo { + + private String stringProperty; + + public String getStringProperty() { + return stringProperty; + } + + public void setStringProperty(String stringProperty) { + this.stringProperty = stringProperty; + } } } From e28b34ad8094b47a7fa46112490d1308bf8418b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 13 Aug 2018 18:10:02 +0200 Subject: [PATCH 0846/2114] Adding Jackson support in JSON RPC WIP References #378 --- pom.xml | 7 + .../tools/jsonrpc/DefaultJsonRpcMapper.java | 29 ++- .../tools/jsonrpc/JacksonJsonRpcMapper.java | 178 ++++++++++++++ .../rabbitmq/tools/jsonrpc/JsonRpcClient.java | 221 +++++++++--------- .../rabbitmq/tools/jsonrpc/JsonRpcMapper.java | 23 +- .../jsonrpc/JsonRpcMappingException.java | 26 +++ .../rabbitmq/tools/jsonrpc/JsonRpcServer.java | 30 ++- .../tools/jsonrpc/ProcedureDescription.java | 44 ++++ .../rabbitmq/client/AbstractJsonRpcTest.java | 202 ++++++++++++++++ .../com/rabbitmq/client/JacksonRpcTest.java | 64 +++++ .../java/com/rabbitmq/client/JsonRpcTest.java | 167 ++----------- .../com/rabbitmq/client/test/ClientTests.java | 2 + 12 files changed, 724 insertions(+), 269 deletions(-) create mode 100644 src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java create mode 100644 src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMappingException.java create mode 100644 src/test/java/com/rabbitmq/client/AbstractJsonRpcTest.java create mode 100644 src/test/java/com/rabbitmq/client/JacksonRpcTest.java diff --git a/pom.xml b/pom.xml index d437c401bd..a87e3edddc 100644 --- a/pom.xml +++ b/pom.xml @@ -57,6 +57,7 @@ 1.7.25 3.2.6 1.0.2 + 2.9.6 1.2.3 1.1 4.12 @@ -640,6 +641,12 @@ ${micrometer.version} true + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + true + commons-cli commons-cli diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/DefaultJsonRpcMapper.java b/src/main/java/com/rabbitmq/tools/jsonrpc/DefaultJsonRpcMapper.java index 358284d650..c522d24767 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/DefaultJsonRpcMapper.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/DefaultJsonRpcMapper.java @@ -1,3 +1,18 @@ +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.tools.jsonrpc; import com.rabbitmq.tools.json.JSONReader; @@ -23,7 +38,7 @@ public JsonRpcRequest parse(String requestBody, ServiceDescription description) } @Override - public JsonRpcResponse parse(String responseBody) { + public JsonRpcResponse parse(String responseBody, Class expectedType) { Map map = (Map) (new JSONReader().read(responseBody)); Map error; JsonRpcException exception = null; @@ -40,6 +55,12 @@ public JsonRpcResponse parse(String responseBody) { return new JsonRpcResponse(map, map.get("result"), map.get("error"), exception); } + @Override + public String write(Object input) { + return new JSONWriter().write(input); + } + + /* @Override public Object[] parameters(JsonRpcRequest request, Method method) { Object[] parameters = request.getParameters(); @@ -51,10 +72,7 @@ public Object[] parameters(JsonRpcRequest request, Method method) { return convertedParameters; } - @Override - public String write(Object input) { - return new JSONWriter().write(input); - } + protected Object convert(Object input, Class expectedClass) { return input; @@ -69,4 +87,5 @@ protected Object convert(Object input, Class expectedClass) { // } // return input; } + */ } diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java new file mode 100644 index 0000000000..0a19f53921 --- /dev/null +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java @@ -0,0 +1,178 @@ +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.tools.jsonrpc; + +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.core.TreeNode; +import com.fasterxml.jackson.databind.MappingJsonFactory; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ValueNode; +import com.rabbitmq.tools.json.JSONReader; +import com.rabbitmq.tools.json.JSONWriter; + +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * + */ +public class JacksonJsonRpcMapper implements JsonRpcMapper { + + private final ObjectMapper mapper; + + public JacksonJsonRpcMapper(ObjectMapper mapper) { + this.mapper = mapper; + } + + public JacksonJsonRpcMapper() { + this(new ObjectMapper()); + } + + @Override + public JsonRpcRequest parse(String requestBody, ServiceDescription description) { + JsonFactory jsonFactory = new MappingJsonFactory(); + String method = null, version = null; + final List parameters = new ArrayList<>(); + Object id = null; + try (JsonParser parser = jsonFactory.createParser(requestBody)) { + while (parser.nextToken() != null) { + JsonToken token = parser.currentToken(); + if (token == JsonToken.FIELD_NAME) { + String name = parser.currentName(); + token = parser.nextToken(); + if ("method".equals(name)) { + method = parser.getValueAsString(); + } else if ("id".equals(name)) { + // FIXME parse id, can be any type (handle only primitive and wrapper) + } else if ("version".equals(name)) { + version = parser.getValueAsString(); + } else if ("params".equals(name)) { + if (token == JsonToken.START_ARRAY) { + while (parser.nextToken() != JsonToken.END_ARRAY) { + parameters.add(parser.readValueAsTree()); + } + } else { + throw new IllegalStateException("Field params must be an array"); + } + } + } + } + } catch (IOException e) { + throw new JsonRpcMappingException("Error during JSON parsing", e); + } + + List convertedParameters = new ArrayList<>(parameters.size()); + if (!parameters.isEmpty()) { + ProcedureDescription proc = description.getProcedure(method, parameters.size()); + Method internalMethod = proc.internal_getMethod(); + for (int i = 0; i < internalMethod.getParameterCount(); i++) { + TreeNode parameterNode = parameters.get(i); + try { + Class parameterType = internalMethod.getParameterTypes()[i]; + Object value = convert(parameterNode, parameterType); + convertedParameters.add(value); + } catch (IOException e) { + throw new JsonRpcMappingException("Error during parameter conversion", e); + } + } + } + + return new JsonRpcRequest( + id, version, method, + convertedParameters.toArray() + ); + } + + protected Object convert(TreeNode node, Class expectedType) throws IOException { + Object value; + if (expectedType.isPrimitive()) { + ValueNode valueNode = (ValueNode) node; + if (expectedType == Boolean.TYPE) { + value = valueNode.booleanValue(); + } else if (expectedType == Character.TYPE) { + value = valueNode.textValue().charAt(0); + } else if (expectedType == Short.TYPE) { + value = valueNode.shortValue(); + } else if (expectedType == Integer.TYPE) { + value = valueNode.intValue(); + } else if (expectedType == Long.TYPE) { + value = valueNode.longValue(); + } else if (expectedType == Float.TYPE) { + value = valueNode.floatValue(); + } else if (expectedType == Double.TYPE) { + value = valueNode.doubleValue(); + } else { + throw new IllegalArgumentException("Primitive type not supported: " + expectedType); + } + } else { + value = mapper.readValue(node.traverse(), expectedType); + } + return value; + } + + @Override + public JsonRpcResponse parse(String responseBody, Class expectedReturnType) { + JsonFactory jsonFactory = new MappingJsonFactory(); + Object result = null; + try (JsonParser parser = jsonFactory.createParser(responseBody)) { + while (parser.nextToken() != null) { + JsonToken token = parser.currentToken(); + if (token == JsonToken.FIELD_NAME) { + String name = parser.currentName(); + parser.nextToken(); + if ("result".equals(name)) { + if (expectedReturnType == Void.TYPE) { + result = null; + } else { + result = convert(parser.readValueAsTree(), expectedReturnType); + } + } + } + } + } catch (IOException e) { + throw new JsonRpcMappingException("Error during JSON parsing", e); + } + Map map = (Map) (new JSONReader().read(responseBody)); + Map error; + JsonRpcException exception = null; + if (map.containsKey("error")) { + error = (Map) map.get("error"); + exception = new JsonRpcException( + new JSONWriter().write(error), + (String) error.get("name"), + error.get("code") == null ? 0 : (Integer) error.get("code"), + (String) error.get("message"), + error + ); + } + return new JsonRpcResponse(map, result, map.get("error"), exception); + } + + @Override + public String write(Object input) { + try { + return mapper.writeValueAsString(input); + } catch (JsonProcessingException e) { + throw new JsonRpcMappingException("Error during JSON serialization", e); + } + } +} diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java index 581e304f83..12032941f3 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java @@ -15,6 +15,13 @@ package com.rabbitmq.tools.jsonrpc; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.RpcClient; +import com.rabbitmq.client.ShutdownSignalException; +import com.rabbitmq.tools.json.JSONReader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.IOException; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; @@ -23,78 +30,106 @@ import java.util.Map; import java.util.concurrent.TimeoutException; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.RpcClient; -import com.rabbitmq.client.ShutdownSignalException; -import com.rabbitmq.tools.json.JSONReader; -import com.rabbitmq.tools.json.JSONWriter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - /** - JSON-RPC is a lightweight - RPC mechanism using JSON - as a data language for request and reply messages. It is - rapidly becoming a standard in web development, where it is - used to make RPC requests over HTTP. RabbitMQ provides an - AMQP transport binding for JSON-RPC in the form of the - JsonRpcClient class. - - JSON-RPC services are self-describing - each service is able - to list its supported procedures, and each procedure - describes its parameters and types. An instance of - JsonRpcClient retrieves its service description using the - standard system.describe procedure when it is - constructed, and uses the information to coerce parameter - types appropriately. A JSON service description is parsed - into instances of ServiceDescription. Client - code can access the service description by reading the - serviceDescription field of - JsonRpcClient instances. - - @see #call(String, Object[]) - @see #call(String[]) + * JSON-RPC is a lightweight + * RPC mechanism using JSON + * as a data language for request and reply messages. It is + * rapidly becoming a standard in web development, where it is + * used to make RPC requests over HTTP. RabbitMQ provides an + * AMQP transport binding for JSON-RPC in the form of the + * JsonRpcClient class. + *

+ * JSON-RPC services are self-describing - each service is able + * to list its supported procedures, and each procedure + * describes its parameters and types. An instance of + * JsonRpcClient retrieves its service description using the + * standard system.describe procedure when it is + * constructed, and uses the information to coerce parameter + * types appropriately. A JSON service description is parsed + * into instances of ServiceDescription. Client + * code can access the service description by reading the + * serviceDescription field of + * JsonRpcClient instances. + * + * @see #call(String, Object[]) + * @see #call(String[]) */ public class JsonRpcClient extends RpcClient implements InvocationHandler { private static final Logger LOGGER = LoggerFactory.getLogger(JsonRpcClient.class); - - /** Holds the JSON-RPC service description for this client. */ + private final JsonRpcMapper mapper; + /** + * Holds the JSON-RPC service description for this client. + */ private ServiceDescription serviceDescription; - private final JsonRpcMapper mapper; + /** + * Construct a new JsonRpcClient, passing the parameters through + * to RpcClient's constructor. The service description record is + * retrieved from the server during construction. + * + * @throws TimeoutException if a response is not received within the timeout specified, if any + */ + public JsonRpcClient(Channel channel, String exchange, String routingKey, int timeout, JsonRpcMapper mapper) + throws IOException, JsonRpcException, TimeoutException { + super(channel, exchange, routingKey, timeout); + this.mapper = mapper; + retrieveServiceDescription(); + } /** * Construct a new JsonRpcClient, passing the parameters through * to RpcClient's constructor. The service description record is * retrieved from the server during construction. + * * @throws TimeoutException if a response is not received within the timeout specified, if any */ public JsonRpcClient(Channel channel, String exchange, String routingKey, int timeout) - throws IOException, JsonRpcException, TimeoutException - { - super(channel, exchange, routingKey, timeout); - this.mapper = new DefaultJsonRpcMapper(); - retrieveServiceDescription(); + throws IOException, JsonRpcException, TimeoutException { + this(channel, exchange, routingKey, timeout, new DefaultJsonRpcMapper()); } public JsonRpcClient(Channel channel, String exchange, String routingKey) - throws IOException, JsonRpcException, TimeoutException - { + throws IOException, JsonRpcException, TimeoutException { this(channel, exchange, routingKey, RpcClient.NO_TIMEOUT); } + /** + * Private API - used by {@link #call(String[])} to ad-hoc convert + * strings into the required data types for a call. + */ + public static Object coerce(String val, String type) + throws NumberFormatException { + if ("bit".equals(type)) { + return Boolean.getBoolean(val) ? Boolean.TRUE : Boolean.FALSE; + } else if ("num".equals(type)) { + try { + return Integer.valueOf(val); + } catch (NumberFormatException nfe) { + return Double.valueOf(val); + } + } else if ("str".equals(type)) { + return val; + } else if ("arr".equals(type) || "obj".equals(type) || "any".equals(type)) { + return new JSONReader().read(val); + } else if ("nil".equals(type)) { + return null; + } else { + throw new IllegalArgumentException("Bad type: " + type); + } + } + /** * Private API - parses a JSON-RPC reply object, checking it for exceptions. + * * @return the result contained within the reply, if no exception is found * Throws JsonRpcException if the reply object contained an exception */ private Object checkReply(JsonRpcMapper.JsonRpcResponse reply) - throws JsonRpcException - { - if (reply.getError() != null) { - throw reply.getException(); - } + throws JsonRpcException { + if (reply.getError() != null) { + throw reply.getException(); + } return reply.getResult(); } @@ -102,31 +137,37 @@ private Object checkReply(JsonRpcMapper.JsonRpcResponse reply) /** * Public API - builds, encodes and sends a JSON-RPC request, and * waits for the response. + * * @return the result contained within the reply, if no exception is found * @throws JsonRpcException if the reply object contained an exception * @throws TimeoutException if a response is not received within the timeout specified, if any */ - public Object call(String method, Object[] params) throws IOException, JsonRpcException, TimeoutException - { - HashMap request = new HashMap(); + public Object call(String method, Object[] params) throws IOException, JsonRpcException, TimeoutException { + Map request = new HashMap(); request.put("id", null); request.put("method", method); request.put("version", ServiceDescription.JSON_RPC_VERSION); - request.put("params", (params == null) ? new Object[0] : params); + params = (params == null) ? new Object[0] : params; + request.put("params", params); String requestStr = mapper.write(request); try { String replyStr = this.stringCall(requestStr); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Reply string: {}", replyStr); } - - JsonRpcMapper.JsonRpcResponse reply = mapper.parse(replyStr); + Class expectedType; + if ("system.describe".equals(method) && params.length == 0) { + expectedType = Map.class; + } else { + ProcedureDescription proc = serviceDescription.getProcedure(method, params.length); + expectedType = proc.getReturnType(); + } + JsonRpcMapper.JsonRpcResponse reply = mapper.parse(replyStr, expectedType); return checkReply(reply); - } catch(ShutdownSignalException ex) { + } catch (ShutdownSignalException ex) { throw new IOException(ex.getMessage()); // wrap, re-throw } - } /** @@ -136,8 +177,7 @@ public Object call(String method, Object[] params) throws IOException, JsonRpcEx */ @Override public Object invoke(Object proxy, Method method, Object[] args) - throws Throwable - { + throws Throwable { return call(method.getName(), args); } @@ -146,69 +186,42 @@ public Object invoke(Object proxy, Method method, Object[] args) */ @SuppressWarnings("unchecked") public T createProxy(Class klass) - throws IllegalArgumentException - { + throws IllegalArgumentException { return (T) Proxy.newProxyInstance(klass.getClassLoader(), - new Class[] { klass }, - this); - } - - /** - * Private API - used by {@link #call(String[])} to ad-hoc convert - * strings into the required data types for a call. - */ - public static Object coerce(String val, String type) - throws NumberFormatException - { - if ("bit".equals(type)) { - return Boolean.getBoolean(val) ? Boolean.TRUE : Boolean.FALSE; - } else if ("num".equals(type)) { - try { - return Integer.valueOf(val); - } catch (NumberFormatException nfe) { - return Double.valueOf(val); - } - } else if ("str".equals(type)) { - return val; - } else if ("arr".equals(type) || "obj".equals(type) || "any".equals(type)) { - return new JSONReader().read(val); - } else if ("nil".equals(type)) { - return null; - } else { - throw new IllegalArgumentException("Bad type: " + type); - } + new Class[] { klass }, + this); } /** - * Public API - as {@link #call(String,Object[])}, but takes the + * Public API - as {@link #call(String, Object[])}, but takes the * method name from the first entry in args, and the * parameters from subsequent entries. All parameter values are * passed through coerce() to attempt to make them the types the * server is expecting. + * * @return the result contained within the reply, if no exception is found - * @throws JsonRpcException if the reply object contained an exception + * @throws JsonRpcException if the reply object contained an exception * @throws NumberFormatException if a coercion failed - * @throws TimeoutException if a response is not received within the timeout specified, if any + * @throws TimeoutException if a response is not received within the timeout specified, if any * @see #coerce */ public Object call(String[] args) - throws NumberFormatException, IOException, JsonRpcException, TimeoutException - { - if (args.length == 0) { - throw new IllegalArgumentException("First string argument must be method name"); - } + throws NumberFormatException, IOException, JsonRpcException, TimeoutException { + if (args.length == 0) { + throw new IllegalArgumentException("First string argument must be method name"); + } - String method = args[0]; + String method = args[0]; int arity = args.length - 1; - ProcedureDescription proc = serviceDescription.getProcedure(method, arity); - ParameterDescription[] params = proc.getParams(); + ProcedureDescription proc = serviceDescription.getProcedure(method, arity); + ParameterDescription[] params = proc.getParams(); - Object[] actuals = new Object[arity]; - for (int count = 0; count < params.length; count++) { - actuals[count] = coerce(args[count + 1], params[count].type); - } + Object[] actuals = new Object[arity]; + for (int count = 0; count < params.length; count++) { + actuals[count] = coerce(args[count + 1], params[count].type); + } - return call(method, actuals); + return call(method, actuals); } /** @@ -216,7 +229,7 @@ public Object call(String[] args) * service loaded from the server itself at construction time. */ public ServiceDescription getServiceDescription() { - return serviceDescription; + return serviceDescription; } /** @@ -224,10 +237,10 @@ public ServiceDescription getServiceDescription() { * server, and parses and stores the resulting service description * in this object. * TODO: Avoid calling this from the constructor. + * * @throws TimeoutException if a response is not received within the timeout specified, if any */ - private void retrieveServiceDescription() throws IOException, JsonRpcException, TimeoutException - { + private void retrieveServiceDescription() throws IOException, JsonRpcException, TimeoutException { @SuppressWarnings("unchecked") Map rawServiceDescription = (Map) call("system.describe", null); serviceDescription = new ServiceDescription(rawServiceDescription); diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java index d1e32b0492..36f1ad72b2 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java @@ -1,6 +1,19 @@ -package com.rabbitmq.tools.jsonrpc; +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. -import java.lang.reflect.Method; +package com.rabbitmq.tools.jsonrpc; /** * @@ -9,9 +22,7 @@ public interface JsonRpcMapper { JsonRpcRequest parse(String requestBody, ServiceDescription description); - JsonRpcResponse parse(String responseBody); - - Object[] parameters(JsonRpcRequest request, Method method); + JsonRpcResponse parse(String responseBody, Class expectedType); String write(Object input); @@ -52,7 +63,6 @@ public boolean isSystem() { public boolean isSystemDescribe() { return "system.describe".equals(method); } - } class JsonRpcResponse { @@ -85,5 +95,4 @@ public JsonRpcException getException() { return exception; } } - } diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMappingException.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMappingException.java new file mode 100644 index 0000000000..633a1d79d7 --- /dev/null +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMappingException.java @@ -0,0 +1,26 @@ +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.tools.jsonrpc; + +/** + * + */ +public class JsonRpcMappingException extends RuntimeException { + + public JsonRpcMappingException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java index 068fae1546..922fe35b1c 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java @@ -57,6 +57,16 @@ public class JsonRpcServer extends StringRpcServer { private final JsonRpcMapper mapper; + public JsonRpcServer(Channel channel, + Class interfaceClass, + Object interfaceInstance, JsonRpcMapper mapper) + throws IOException + { + super(channel); + this.mapper = mapper; + init(interfaceClass, interfaceInstance); + } + /** * Construct a server that talks to the outside world using the * given channel, and constructs a fresh temporary @@ -71,9 +81,7 @@ public JsonRpcServer(Channel channel, Object interfaceInstance) throws IOException { - super(channel); - this.mapper = new DefaultJsonRpcMapper(); - init(interfaceClass, interfaceInstance); + this(channel, interfaceClass, interfaceInstance, new DefaultJsonRpcMapper()); } private void init(Class interfaceClass, Object interfaceInstance) @@ -83,6 +91,17 @@ private void init(Class interfaceClass, Object interfaceInstance) this.serviceDescription = new ServiceDescription(interfaceClass); } + public JsonRpcServer(Channel channel, + String queueName, + Class interfaceClass, + Object interfaceInstance, JsonRpcMapper mapper) + throws IOException + { + super(channel, queueName); + this.mapper = mapper; + init(interfaceClass, interfaceInstance); + } + /** * Construct a server that talks to the outside world using the * given channel and queue name. Our superclass, @@ -100,9 +119,7 @@ public JsonRpcServer(Channel channel, Object interfaceInstance) throws IOException { - super(channel, queueName); - this.mapper = new DefaultJsonRpcMapper(); - init(interfaceClass, interfaceInstance); + this(channel, queueName, interfaceClass, interfaceInstance, new DefaultJsonRpcMapper()); } /** @@ -147,7 +164,6 @@ public String doCall(String requestBody) Object result; try { Method matchingMethod = matchingMethod(method, params); - params = mapper.parameters(request, matchingMethod); if (LOGGER.isDebugEnabled()) { Collection parametersValuesAndTypes = new ArrayList(); if (params != null) { diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java b/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java index 57dcc39b05..714db1da96 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java @@ -39,6 +39,8 @@ public class ProcedureDescription { private ParameterDescription[] params; /** Return type for this procedure */ private String returnType; + private String javaReturnType; + private Class _javaReturnTypeAsClass; /** Reflected method object, used for service invocation */ private Method method; @@ -68,6 +70,7 @@ public ProcedureDescription(Method m) { params[i] = new ParameterDescription(i, parameterTypes[i]); } this.returnType = ParameterDescription.lookup(m.getReturnType()); + this.javaReturnType = m.getReturnType().getName(); } public ProcedureDescription() { @@ -82,6 +85,47 @@ public ProcedureDescription() { /** Private API - used to get the reflected method object, for servers */ public Method internal_getMethod() { return method; } + public String getJavaReturnType() { + return javaReturnType; + } + + public void setJavaReturnType(String javaReturnType) { + this.javaReturnType = javaReturnType; + this._javaReturnTypeAsClass = computeReturnTypeAsJavaClass(); + } + + public Class getReturnType() { + return _javaReturnTypeAsClass; + } + + private Class computeReturnTypeAsJavaClass() { + try { + if ("int".equals(javaReturnType)) { + return Integer.TYPE; + } else if ("double".equals(javaReturnType)) { + return Double.TYPE; + } else if ("long".equals(javaReturnType)) { + return Long.TYPE; + } else if ("boolean".equals(javaReturnType)) { + return Boolean.TYPE; + } else if ("char".equals(javaReturnType)) { + return Character.TYPE; + } else if ("byte".equals(javaReturnType)) { + return Byte.TYPE; + } else if ("short".equals(javaReturnType)) { + return Short.TYPE; + } else if ("float".equals(javaReturnType)) { + return Float.TYPE; + } else if ("void".equals(javaReturnType)) { + return Void.TYPE; + } else { + return Class.forName(javaReturnType); + } + } catch (ClassNotFoundException e) { + throw new IllegalStateException("Unable to load class: " + javaReturnType, e); + } + } + /** Gets an array of parameter descriptions for all this procedure's parameters */ public ParameterDescription[] internal_getParams() { return params; diff --git a/src/test/java/com/rabbitmq/client/AbstractJsonRpcTest.java b/src/test/java/com/rabbitmq/client/AbstractJsonRpcTest.java new file mode 100644 index 0000000000..555d4c0b24 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/AbstractJsonRpcTest.java @@ -0,0 +1,202 @@ +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client; + +import com.rabbitmq.client.test.TestUtils; +import com.rabbitmq.tools.jsonrpc.JsonRpcClient; +import com.rabbitmq.tools.jsonrpc.JsonRpcMapper; +import com.rabbitmq.tools.jsonrpc.JsonRpcServer; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.lang.reflect.UndeclaredThrowableException; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +public abstract class AbstractJsonRpcTest { + + Connection clientConnection, serverConnection; + Channel clientChannel, serverChannel; + String queue = "json.rpc.queue"; + JsonRpcServer server; + JsonRpcClient client; + RpcService service; + + abstract JsonRpcMapper createMapper(); + + @Before + public void init() throws Exception { + clientConnection = TestUtils.connectionFactory().newConnection(); + clientChannel = clientConnection.createChannel(); + serverConnection = TestUtils.connectionFactory().newConnection(); + serverChannel = serverConnection.createChannel(); + serverChannel.queueDeclare(queue, false, false, false, null); + server = new JsonRpcServer(serverChannel, queue, RpcService.class, new DefaultRpcservice(), createMapper()); + new Thread(() -> { + try { + server.mainloop(); + } catch (Exception e) { + // safe to ignore when loops ends/server is canceled + } + }).start(); + client = new JsonRpcClient(clientChannel, "", queue, 1000, createMapper()); + service = client.createProxy(RpcService.class); + } + + @After + public void tearDown() throws Exception { + if (server != null) { + server.terminateMainloop(); + } + if (client != null) { + client.close(); + } + if (serverChannel != null) { + serverChannel.queueDelete(queue); + } + clientConnection.close(); + serverConnection.close(); + } + + public interface RpcService { + + boolean procedurePrimitiveBoolean(boolean input); + + Boolean procedureBoolean(Boolean input); + + String procedureString(String input); + + String procedureStringString(String input1, String input2); + + int procedurePrimitiveInteger(int input); + + Integer procedureInteger(Integer input); + + Double procedureDouble(Double input); + + double procedurePrimitiveDouble(double input); + + Integer procedureLongToInteger(Long input); + + int procedurePrimitiveLongToInteger(long input); + + Long procedureLong(Long input); + + long procedurePrimitiveLong(long input); + + Pojo procedureIntegerToPojo(Integer id); + + String procedurePojoToString(Pojo pojo); + + void procedureException(); + + } + + public static class DefaultRpcservice implements RpcService { + + @Override + public boolean procedurePrimitiveBoolean(boolean input) { + return !input; + } + + @Override + public Boolean procedureBoolean(Boolean input) { + return Boolean.valueOf(!input.booleanValue()); + } + + @Override + public String procedureString(String input) { + return input + 1; + } + + @Override + public String procedureStringString(String input1, String input2) { + return input1 + input2; + } + + @Override + public int procedurePrimitiveInteger(int input) { + return input + 1; + } + + @Override + public Integer procedureInteger(Integer input) { + return input + 1; + } + + @Override + public Long procedureLong(Long input) { + return input + 1; + } + + @Override + public long procedurePrimitiveLong(long input) { + return input + 1L; + } + + @Override + public Double procedureDouble(Double input) { + return input + 1; + } + + @Override + public double procedurePrimitiveDouble(double input) { + return input + 1; + } + + @Override + public Integer procedureLongToInteger(Long input) { + return (int) (input + 1); + } + + @Override + public int procedurePrimitiveLongToInteger(long input) { + return (int) input + 1; + } + + @Override + public Pojo procedureIntegerToPojo(Integer id) { + Pojo pojo = new Pojo(); + pojo.setStringProperty(id.toString()); + return pojo; + } + + @Override + public String procedurePojoToString(Pojo pojo) { + return pojo.getStringProperty(); + } + + @Override + public void procedureException() { + throw new RuntimeException(); + } + } + + public static class Pojo { + + private String stringProperty; + + public String getStringProperty() { + return stringProperty; + } + + public void setStringProperty(String stringProperty) { + this.stringProperty = stringProperty; + } + } +} diff --git a/src/test/java/com/rabbitmq/client/JacksonRpcTest.java b/src/test/java/com/rabbitmq/client/JacksonRpcTest.java new file mode 100644 index 0000000000..ba95efef98 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/JacksonRpcTest.java @@ -0,0 +1,64 @@ +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client; + +import com.rabbitmq.tools.jsonrpc.JacksonJsonRpcMapper; +import com.rabbitmq.tools.jsonrpc.JsonRpcException; +import com.rabbitmq.tools.jsonrpc.JsonRpcMapper; +import org.junit.Test; + +import java.lang.reflect.UndeclaredThrowableException; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +public class JacksonRpcTest extends AbstractJsonRpcTest { + + @Override + JsonRpcMapper createMapper() { + return new JacksonJsonRpcMapper(); + } + + @Test + public void rpc() { + assertFalse(service.procedurePrimitiveBoolean(true)); + assertFalse(service.procedureBoolean(Boolean.TRUE).booleanValue()); + assertEquals("hello1", service.procedureString("hello")); + assertEquals("hello1hello2", service.procedureStringString("hello1", "hello2")); + assertEquals(2, service.procedureInteger(1).intValue()); + assertEquals(2, service.procedurePrimitiveInteger(1)); + assertEquals(2, service.procedureDouble(1.0).intValue()); + assertEquals(2, (int) service.procedurePrimitiveDouble(1.0)); + assertEquals(2, (int) service.procedureLongToInteger(1L)); + assertEquals(2, service.procedurePrimitiveLongToInteger(1L)); + assertEquals(2, service.procedurePrimitiveLong(1L)); + assertEquals(2, service.procedureLong(1L).longValue()); + assertEquals("123", service.procedureIntegerToPojo(123).getStringProperty()); + + Pojo pojo = new Pojo(); + pojo.setStringProperty("hello"); + assertEquals("hello", service.procedurePojoToString(pojo)); + + try { + service.procedureException(); + fail("Remote procedure throwing exception, an exception should have been thrown"); + } catch (UndeclaredThrowableException e) { + assertTrue(e.getCause() instanceof JsonRpcException); + } + } +} diff --git a/src/test/java/com/rabbitmq/client/JsonRpcTest.java b/src/test/java/com/rabbitmq/client/JsonRpcTest.java index f13b5b4036..a4a18f9693 100644 --- a/src/test/java/com/rabbitmq/client/JsonRpcTest.java +++ b/src/test/java/com/rabbitmq/client/JsonRpcTest.java @@ -15,69 +15,44 @@ package com.rabbitmq.client; -import com.rabbitmq.client.test.TestUtils; -import com.rabbitmq.tools.jsonrpc.JsonRpcClient; -import com.rabbitmq.tools.jsonrpc.JsonRpcServer; -import org.junit.After; -import org.junit.Before; +import com.rabbitmq.tools.jsonrpc.DefaultJsonRpcMapper; +import com.rabbitmq.tools.jsonrpc.JacksonJsonRpcMapper; +import com.rabbitmq.tools.jsonrpc.JsonRpcException; +import com.rabbitmq.tools.jsonrpc.JsonRpcMapper; import org.junit.Test; import java.lang.reflect.UndeclaredThrowableException; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -public class JsonRpcTest { +public class JsonRpcTest extends AbstractJsonRpcTest { - Connection clientConnection, serverConnection; - Channel clientChannel, serverChannel; - String queue = "json.rpc.queue"; - JsonRpcServer server; - JsonRpcClient client; - RpcService service; - - @Before - public void init() throws Exception { - clientConnection = TestUtils.connectionFactory().newConnection(); - clientChannel = clientConnection.createChannel(); - serverConnection = TestUtils.connectionFactory().newConnection(); - serverChannel = serverConnection.createChannel(); - serverChannel.queueDeclare(queue, false, false, false, null); - server = new JsonRpcServer(serverChannel, queue, RpcService.class, new DefaultRpcservice()); - new Thread(() -> { - try { - server.mainloop(); - } catch (Exception e) { - // safe to ignore when loops ends/server is canceled - } - }).start(); - client = new JsonRpcClient(clientChannel, "", queue, 1000); - service = client.createProxy(RpcService.class); - } - - @After - public void tearDown() throws Exception { - if (server != null) { - server.terminateMainloop(); - } - if (client != null) { - client.close(); - } - if (serverChannel != null) { - serverChannel.queueDelete(queue); - } - clientConnection.close(); - serverConnection.close(); + @Override + JsonRpcMapper createMapper() { + return new DefaultJsonRpcMapper(); } @Test public void rpc() { + assertFalse(service.procedurePrimitiveBoolean(true)); + assertFalse(service.procedureBoolean(Boolean.TRUE).booleanValue()); assertEquals("hello1", service.procedureString("hello")); assertEquals(2, service.procedureInteger(1).intValue()); assertEquals(2, service.procedurePrimitiveInteger(1)); assertEquals(2, service.procedureDouble(1.0).intValue()); assertEquals(2, (int) service.procedurePrimitiveDouble(1.0)); + try { + service.procedureException(); + fail("Remote procedure throwing exception, an exception should have been thrown"); + } catch (UndeclaredThrowableException e) { + assertTrue(e.getCause() instanceof JsonRpcException); + } + + try { assertEquals(2, (int) service.procedureLongToInteger(1L)); fail("Long argument isn't supported"); @@ -115,105 +90,5 @@ public void rpc() { } catch (UndeclaredThrowableException e) { // OK } - - } - - public interface RpcService { - - String procedureString(String input); - - int procedurePrimitiveInteger(int input); - - Integer procedureInteger(Integer input); - - Double procedureDouble(Double input); - - double procedurePrimitiveDouble(double input); - - Integer procedureLongToInteger(Long input); - - int procedurePrimitiveLongToInteger(long input); - - Long procedureLong(Long input); - - long procedurePrimitiveLong(long input); - - Pojo procedureIntegerToPojo(Integer id); - - String procedurePojoToString(Pojo pojo); - - } - - public static class DefaultRpcservice implements RpcService { - - @Override - public String procedureString(String input) { - return input + 1; - } - - @Override - public int procedurePrimitiveInteger(int input) { - return input + 1; - } - - @Override - public Integer procedureInteger(Integer input) { - return input + 1; - } - - @Override - public Long procedureLong(Long input) { - return input + 1; - } - - @Override - public long procedurePrimitiveLong(long input) { - return input + 1L; - } - - @Override - public Double procedureDouble(Double input) { - return input + 1; - } - - @Override - public double procedurePrimitiveDouble(double input) { - return input + 1; - } - - @Override - public Integer procedureLongToInteger(Long input) { - return (int) (input + 1); - } - - @Override - public int procedurePrimitiveLongToInteger(long input) { - return (int) input + 1; - } - - @Override - public Pojo procedureIntegerToPojo(Integer id) { - Pojo pojo = new Pojo(); - pojo.setStringProperty(id.toString()); - return pojo; - } - - @Override - public String procedurePojoToString(Pojo pojo) { - return pojo.getStringProperty(); - } - } - - public static class Pojo { - - private String stringProperty; - - public String getStringProperty() { - return stringProperty; - } - - public void setStringProperty(String stringProperty) { - this.stringProperty = stringProperty; - } } -} +} \ No newline at end of file diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index 9c2994b671..78e8616d4b 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -16,6 +16,7 @@ package com.rabbitmq.client.test; +import com.rabbitmq.client.JacksonRpcTest; import com.rabbitmq.client.JsonRpcTest; import com.rabbitmq.utility.IntAllocatorTests; import org.junit.runner.RunWith; @@ -62,6 +63,7 @@ StrictExceptionHandlerTest.class, NoAutoRecoveryWhenTcpWindowIsFullTest.class, JsonRpcTest.class, + JacksonRpcTest.class, AddressTest.class, DefaultRetryHandlerTest.class }) From 01f10d6cf7c55167f40c7f82fe8459341c4e93f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 14 Aug 2018 10:13:12 +0200 Subject: [PATCH 0847/2114] Add JSON abstraction for JSON RPC support [#159302201] Fixes #378 --- .../com/rabbitmq/tools/json/JSONReader.java | 5 + .../rabbitmq/tools/json/JSONSerializable.java | 4 + .../com/rabbitmq/tools/json/JSONUtil.java | 79 ++++++------ .../com/rabbitmq/tools/json/JSONWriter.java | 4 + .../tools/jsonrpc/DefaultJsonRpcMapper.java | 45 ++----- .../tools/jsonrpc/JacksonJsonRpcMapper.java | 112 +++++++++++------- .../rabbitmq/tools/jsonrpc/JsonRpcClient.java | 5 + .../rabbitmq/tools/jsonrpc/JsonRpcMapper.java | 31 +++-- .../jsonrpc/JsonRpcMappingException.java | 1 + .../rabbitmq/tools/jsonrpc/JsonRpcServer.java | 100 ++++++++-------- .../rabbitmq/client/AbstractJsonRpcTest.java | 19 ++- .../client/BlockingCellBenchmark.java | 38 ------ ...onRpcTest.java => DefaultJsonRpcTest.java} | 5 +- ...onRpcTest.java => JacksonJsonRpcTest.java} | 17 ++- .../com/rabbitmq/client/test/ClientTests.java | 8 +- 15 files changed, 246 insertions(+), 227 deletions(-) delete mode 100644 src/test/java/com/rabbitmq/client/BlockingCellBenchmark.java rename src/test/java/com/rabbitmq/client/{JsonRpcTest.java => DefaultJsonRpcTest.java} (96%) rename src/test/java/com/rabbitmq/client/{JacksonRpcTest.java => JacksonJsonRpcTest.java} (80%) diff --git a/src/main/java/com/rabbitmq/tools/json/JSONReader.java b/src/main/java/com/rabbitmq/tools/json/JSONReader.java index 6c9420767e..fa4c43643d 100644 --- a/src/main/java/com/rabbitmq/tools/json/JSONReader.java +++ b/src/main/java/com/rabbitmq/tools/json/JSONReader.java @@ -44,6 +44,11 @@ import java.util.List; import java.util.Map; +/** + * Will be removed in 6.0 + * + * @deprecated Use a third-party JSON library, e.g. Jackson or GJSON + */ public class JSONReader { private static final Object OBJECT_END = new Object(); diff --git a/src/main/java/com/rabbitmq/tools/json/JSONSerializable.java b/src/main/java/com/rabbitmq/tools/json/JSONSerializable.java index 1cb1b0a77e..f453de5038 100644 --- a/src/main/java/com/rabbitmq/tools/json/JSONSerializable.java +++ b/src/main/java/com/rabbitmq/tools/json/JSONSerializable.java @@ -18,6 +18,10 @@ /** * Interface for classes that wish to control their own serialization. + * + * Will be removed in 6.0 + * + * @deprecated Use a third-party JSON library, e.g. Jackson or GJSON */ public interface JSONSerializable { /** diff --git a/src/main/java/com/rabbitmq/tools/json/JSONUtil.java b/src/main/java/com/rabbitmq/tools/json/JSONUtil.java index c40727d6e8..c024e142c8 100644 --- a/src/main/java/com/rabbitmq/tools/json/JSONUtil.java +++ b/src/main/java/com/rabbitmq/tools/json/JSONUtil.java @@ -13,7 +13,6 @@ // If you have any questions regarding licensing, please contact us at // info@rabbitmq.com. - package com.rabbitmq.tools.json; import org.slf4j.Logger; @@ -34,15 +33,15 @@ */ public class JSONUtil { - private static final Logger LOGGER = LoggerFactory.getLogger(JSONUtil.class); + private static final Logger LOGGER = LoggerFactory.getLogger(JSONUtil.class); + /** * Uses reflection to fill public fields and Bean properties of * the target object from the source Map. */ public static Object fill(Object target, Map source) - throws IntrospectionException, IllegalAccessException, InvocationTargetException - { - return fill(target, source, true); + throws IntrospectionException, IllegalAccessException, InvocationTargetException { + return fill(target, source, true); } /** @@ -50,38 +49,36 @@ public static Object fill(Object target, Map source) * properties of the target object from the source Map. */ public static Object fill(Object target, Map source, boolean useProperties) - throws IntrospectionException, IllegalAccessException, InvocationTargetException - { - if (useProperties) { - BeanInfo info = Introspector.getBeanInfo(target.getClass()); + throws IntrospectionException, IllegalAccessException, InvocationTargetException { + if (useProperties) { + BeanInfo info = Introspector.getBeanInfo(target.getClass()); - PropertyDescriptor[] props = info.getPropertyDescriptors(); - for (int i = 0; i < props.length; ++i) { - PropertyDescriptor prop = props[i]; - String name = prop.getName(); - Method setter = prop.getWriteMethod(); - if (setter != null && !Modifier.isStatic(setter.getModifiers())) { - setter.invoke(target, source.get(name)); - } - } - } + PropertyDescriptor[] props = info.getPropertyDescriptors(); + for (int i = 0; i < props.length; ++i) { + PropertyDescriptor prop = props[i]; + String name = prop.getName(); + Method setter = prop.getWriteMethod(); + if (setter != null && !Modifier.isStatic(setter.getModifiers())) { + setter.invoke(target, source.get(name)); + } + } + } - Field[] ff = target.getClass().getDeclaredFields(); - for (int i = 0; i < ff.length; ++i) { - Field field = ff[i]; + Field[] ff = target.getClass().getDeclaredFields(); + for (int i = 0; i < ff.length; ++i) { + Field field = ff[i]; int fieldMod = field.getModifiers(); - if (Modifier.isPublic(fieldMod) && !(Modifier.isFinal(fieldMod) || - Modifier.isStatic(fieldMod))) - { - try { - field.set(target, source.get(field.getName())); - } catch (IllegalArgumentException iae) { - // no special error processing required + if (Modifier.isPublic(fieldMod) && !(Modifier.isFinal(fieldMod) || + Modifier.isStatic(fieldMod))) { + try { + field.set(target, source.get(field.getName())); + } catch (IllegalArgumentException iae) { + // no special error processing required } - } - } + } + } - return target; + return target; } /** @@ -90,14 +87,14 @@ public static Object fill(Object target, Map source, boolean use * source Map. */ public static void tryFill(Object target, Map source) { - try { - fill(target, source); - } catch (IntrospectionException ie) { - LOGGER.error("Error in tryFill", ie); - } catch (IllegalAccessException iae) { - LOGGER.error("Error in tryFill", iae); - } catch (InvocationTargetException ite) { - LOGGER.error("Error in tryFill", ite); - } + try { + fill(target, source); + } catch (IntrospectionException ie) { + LOGGER.error("Error in tryFill", ie); + } catch (IllegalAccessException iae) { + LOGGER.error("Error in tryFill", iae); + } catch (InvocationTargetException ite) { + LOGGER.error("Error in tryFill", ite); + } } } diff --git a/src/main/java/com/rabbitmq/tools/json/JSONWriter.java b/src/main/java/com/rabbitmq/tools/json/JSONWriter.java index 4a7f78c7f0..eb82cc7751 100644 --- a/src/main/java/com/rabbitmq/tools/json/JSONWriter.java +++ b/src/main/java/com/rabbitmq/tools/json/JSONWriter.java @@ -53,6 +53,10 @@ import java.util.Map; import java.util.Set; +/** + * Will be removed in 6.0 + * @deprecated Use a third-party JSON library, e.g. Jackson or GJSON + */ public class JSONWriter { private boolean indentMode = false; private int indentLevel = 0; diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/DefaultJsonRpcMapper.java b/src/main/java/com/rabbitmq/tools/jsonrpc/DefaultJsonRpcMapper.java index c522d24767..db6cda0b6d 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/DefaultJsonRpcMapper.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/DefaultJsonRpcMapper.java @@ -18,19 +18,27 @@ import com.rabbitmq.tools.json.JSONReader; import com.rabbitmq.tools.json.JSONWriter; -import java.lang.reflect.Method; import java.util.List; import java.util.Map; /** + * Simple {@link JsonRpcMapper} based on homegrown JSON utilities. + * Handles integers, doubles, strings, booleans, and arrays of those types. + *

+ * For a more comprehensive set of features, use {@link JacksonJsonRpcMapper}. + *

+ * Will be removed in 6.0 * + * @see JsonRpcMapper + * @see JacksonJsonRpcMapper + * @since 5.4.0 + * @deprecated use {@link JacksonJsonRpcMapper} instead */ public class DefaultJsonRpcMapper implements JsonRpcMapper { @Override public JsonRpcRequest parse(String requestBody, ServiceDescription description) { - Map request = (Map) new JSONReader().read(requestBody); - + Map request = (Map) new JSONReader().read(requestBody); return new JsonRpcRequest( request.get("id"), request.get("version").toString(), request.get("method").toString(), ((List) request.get("params")).toArray() @@ -52,40 +60,11 @@ public JsonRpcResponse parse(String responseBody, Class expectedType) { error ); } - return new JsonRpcResponse(map, map.get("result"), map.get("error"), exception); + return new JsonRpcResponse(map.get("result"), map.get("error"), exception); } @Override public String write(Object input) { return new JSONWriter().write(input); } - - /* - @Override - public Object[] parameters(JsonRpcRequest request, Method method) { - Object[] parameters = request.getParameters(); - Object[] convertedParameters = new Object[parameters.length]; - Class[] parameterTypes = method.getParameterTypes(); - for (int i = 0; i < parameters.length; i++) { - convertedParameters[i] = convert(parameters[i], parameterTypes[i]); - } - return convertedParameters; - } - - - - protected Object convert(Object input, Class expectedClass) { - return input; -// if (input == null || input.getClass().equals(expectedClass)) { -// return input; -// } -// System.err.println(input.getClass() + " " + expectedClass); -// if (Long.class.equals(expectedClass) && input instanceof Integer) { -// return Long.valueOf(((Integer) input).longValue()); -// } else if (long.class.equals(expectedClass) && input instanceof Integer) { -// return -// } -// return input; - } - */ } diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java index 0a19f53921..9cb5411b25 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java @@ -23,8 +23,8 @@ import com.fasterxml.jackson.databind.MappingJsonFactory; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ValueNode; -import com.rabbitmq.tools.json.JSONReader; -import com.rabbitmq.tools.json.JSONWriter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; import java.lang.reflect.Method; @@ -33,10 +33,16 @@ import java.util.Map; /** + * {@link JsonRpcMapper} based on Jackson. + * Uses the streaming and databind modules. * + * @see JsonRpcMapper + * @since 5.4.0 */ public class JacksonJsonRpcMapper implements JsonRpcMapper { + private static final Logger LOGGER = LoggerFactory.getLogger(JacksonJsonRpcMapper.class); + private final ObjectMapper mapper; public JacksonJsonRpcMapper(ObjectMapper mapper) { @@ -62,7 +68,21 @@ public JsonRpcRequest parse(String requestBody, ServiceDescription description) if ("method".equals(name)) { method = parser.getValueAsString(); } else if ("id".equals(name)) { - // FIXME parse id, can be any type (handle only primitive and wrapper) + TreeNode node = parser.readValueAsTree(); + if (node instanceof ValueNode) { + ValueNode idNode = (ValueNode) node; + if (idNode.isNull()) { + id = null; + } else if (idNode.isTextual()) { + id = idNode.asText(); + } else if (idNode.isNumber()) { + id = Long.valueOf(idNode.asLong()); + } else { + LOGGER.warn("ID type not null, text, or number {}, ignoring", idNode); + } + } else { + LOGGER.warn("ID not a scalar value {}, ignoring", node); + } } else if ("version".equals(name)) { version = parser.getValueAsString(); } else if ("params".equals(name)) { @@ -80,6 +100,10 @@ public JsonRpcRequest parse(String requestBody, ServiceDescription description) throw new JsonRpcMappingException("Error during JSON parsing", e); } + if (method == null) { + throw new IllegalArgumentException("Could not find method to invoke in request"); + } + List convertedParameters = new ArrayList<>(parameters.size()); if (!parameters.isEmpty()) { ProcedureDescription proc = description.getProcedure(method, parameters.size()); @@ -102,69 +126,40 @@ public JsonRpcRequest parse(String requestBody, ServiceDescription description) ); } - protected Object convert(TreeNode node, Class expectedType) throws IOException { - Object value; - if (expectedType.isPrimitive()) { - ValueNode valueNode = (ValueNode) node; - if (expectedType == Boolean.TYPE) { - value = valueNode.booleanValue(); - } else if (expectedType == Character.TYPE) { - value = valueNode.textValue().charAt(0); - } else if (expectedType == Short.TYPE) { - value = valueNode.shortValue(); - } else if (expectedType == Integer.TYPE) { - value = valueNode.intValue(); - } else if (expectedType == Long.TYPE) { - value = valueNode.longValue(); - } else if (expectedType == Float.TYPE) { - value = valueNode.floatValue(); - } else if (expectedType == Double.TYPE) { - value = valueNode.doubleValue(); - } else { - throw new IllegalArgumentException("Primitive type not supported: " + expectedType); - } - } else { - value = mapper.readValue(node.traverse(), expectedType); - } - return value; - } - @Override public JsonRpcResponse parse(String responseBody, Class expectedReturnType) { JsonFactory jsonFactory = new MappingJsonFactory(); Object result = null; + JsonRpcException exception = null; + Map errorMap = null; try (JsonParser parser = jsonFactory.createParser(responseBody)) { while (parser.nextToken() != null) { JsonToken token = parser.currentToken(); if (token == JsonToken.FIELD_NAME) { String name = parser.currentName(); - parser.nextToken(); if ("result".equals(name)) { + parser.nextToken(); if (expectedReturnType == Void.TYPE) { result = null; } else { result = convert(parser.readValueAsTree(), expectedReturnType); } + } else if ("error".equals(name)) { + errorMap = (Map) convert(parser.readValueAsTree(), Map.class); + exception = new JsonRpcException( + errorMap.toString(), + (String) errorMap.get("name"), + errorMap.get("code") == null ? 0 : (Integer) errorMap.get("code"), + (String) errorMap.get("message"), + errorMap + ); } } } } catch (IOException e) { throw new JsonRpcMappingException("Error during JSON parsing", e); } - Map map = (Map) (new JSONReader().read(responseBody)); - Map error; - JsonRpcException exception = null; - if (map.containsKey("error")) { - error = (Map) map.get("error"); - exception = new JsonRpcException( - new JSONWriter().write(error), - (String) error.get("name"), - error.get("code") == null ? 0 : (Integer) error.get("code"), - (String) error.get("message"), - error - ); - } - return new JsonRpcResponse(map, result, map.get("error"), exception); + return new JsonRpcResponse(result, errorMap, exception); } @Override @@ -175,4 +170,31 @@ public String write(Object input) { throw new JsonRpcMappingException("Error during JSON serialization", e); } } + + protected Object convert(TreeNode node, Class expectedType) throws IOException { + Object value; + if (expectedType.isPrimitive()) { + ValueNode valueNode = (ValueNode) node; + if (expectedType == Boolean.TYPE) { + value = valueNode.booleanValue(); + } else if (expectedType == Character.TYPE) { + value = valueNode.textValue().charAt(0); + } else if (expectedType == Short.TYPE) { + value = valueNode.shortValue(); + } else if (expectedType == Integer.TYPE) { + value = valueNode.intValue(); + } else if (expectedType == Long.TYPE) { + value = valueNode.longValue(); + } else if (expectedType == Float.TYPE) { + value = valueNode.floatValue(); + } else if (expectedType == Double.TYPE) { + value = valueNode.doubleValue(); + } else { + throw new IllegalArgumentException("Primitive type not supported: " + expectedType); + } + } else { + value = mapper.readValue(node.traverse(), expectedType); + } + return value; + } } diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java index 12032941f3..f64b9f47f0 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java @@ -50,9 +50,14 @@ * code can access the service description by reading the * serviceDescription field of * JsonRpcClient instances. + *

+ * {@link JsonRpcClient} delegates JSON parsing and generating to + * a {@link JsonRpcMapper}. * * @see #call(String, Object[]) * @see #call(String[]) + * @see JsonRpcMapper + * @see JacksonJsonRpcMapper */ public class JsonRpcClient extends RpcClient implements InvocationHandler { diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java index 36f1ad72b2..fdad5e1960 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java @@ -16,14 +16,37 @@ package com.rabbitmq.tools.jsonrpc; /** + * Abstraction to handle JSON parsing and generation. + * Used by {@link JsonRpcServer} and {@link JsonRpcClient}. * + * @since 5.4.0 */ public interface JsonRpcMapper { + /** + * Parses a JSON RPC request. + * The {@link ServiceDescription} can be used + * to look up the invoked procedure and learn about + * its signature. + * @param requestBody + * @param description + * @return + */ JsonRpcRequest parse(String requestBody, ServiceDescription description); + /** + * Parses a JSON RPC response. + * @param responseBody + * @param expectedType + * @return + */ JsonRpcResponse parse(String responseBody, Class expectedType); + /** + * Serialize an object into JSON. + * @param input + * @return + */ String write(Object input); class JsonRpcRequest { @@ -67,22 +90,16 @@ public boolean isSystemDescribe() { class JsonRpcResponse { - private final Object reply; private final Object result; private final Object error; private final JsonRpcException exception; - public JsonRpcResponse(Object reply, Object result, Object error, JsonRpcException exception) { - this.reply = reply; + public JsonRpcResponse(Object result, Object error, JsonRpcException exception) { this.result = result; this.error = error; this.exception = exception; } - public Object getReply() { - return reply; - } - public Object getError() { return error; } diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMappingException.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMappingException.java index 633a1d79d7..03a7d12b91 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMappingException.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMappingException.java @@ -17,6 +17,7 @@ /** * + * @since 5.4.0 */ public class JsonRpcMappingException extends RuntimeException { diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java index 922fe35b1c..723664c3b5 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java @@ -13,55 +13,59 @@ // If you have any questions regarding licensing, please contact us at // info@rabbitmq.com. - package com.rabbitmq.tools.jsonrpc; +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.StringRpcServer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.IOException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; -import java.util.List; import java.util.Map; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.StringRpcServer; -import com.rabbitmq.tools.json.JSONReader; -import com.rabbitmq.tools.json.JSONWriter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - /** * JSON-RPC Server class. - * + *

* Given a Java {@link Class}, representing an interface, and an * implementation of that interface, JsonRpcServer will reflect on the * class to construct the {@link ServiceDescription}, and will route * incoming requests for methods on the interface to the * implementation object while the mainloop() is running. + *

+ * {@link JsonRpcServer} delegates JSON parsing and generating to + * a {@link JsonRpcMapper}. * * @see com.rabbitmq.client.RpcServer * @see JsonRpcClient + * @see JsonRpcMapper + * @see JacksonJsonRpcMapper */ public class JsonRpcServer extends StringRpcServer { private static final Logger LOGGER = LoggerFactory.getLogger(JsonRpcServer.class); - - /** Holds the JSON-RPC service description for this client. */ + private final JsonRpcMapper mapper; + /** + * Holds the JSON-RPC service description for this client. + */ public ServiceDescription serviceDescription; - /** The interface this server implements. */ + /** + * The interface this server implements. + */ public Class interfaceClass; - /** The instance backing this server. */ + /** + * The instance backing this server. + */ public Object interfaceInstance; - private final JsonRpcMapper mapper; - public JsonRpcServer(Channel channel, Class interfaceClass, Object interfaceInstance, JsonRpcMapper mapper) - throws IOException - { + throws IOException { super(channel); this.mapper = mapper; init(interfaceClass, interfaceInstance); @@ -71,32 +75,24 @@ public JsonRpcServer(Channel channel, * Construct a server that talks to the outside world using the * given channel, and constructs a fresh temporary * queue. Use getQueueName() to discover the created queue name. - * @param channel AMQP channel to use - * @param interfaceClass Java interface that this server is exposing to the world + * + * @param channel AMQP channel to use + * @param interfaceClass Java interface that this server is exposing to the world * @param interfaceInstance Java instance (of interfaceClass) that is being exposed * @throws IOException if something goes wrong during an AMQP operation */ public JsonRpcServer(Channel channel, - Class interfaceClass, - Object interfaceInstance) - throws IOException - { + Class interfaceClass, + Object interfaceInstance) + throws IOException { this(channel, interfaceClass, interfaceInstance, new DefaultJsonRpcMapper()); } - private void init(Class interfaceClass, Object interfaceInstance) - { - this.interfaceClass = interfaceClass; - this.interfaceInstance = interfaceInstance; - this.serviceDescription = new ServiceDescription(interfaceClass); - } - public JsonRpcServer(Channel channel, String queueName, Class interfaceClass, Object interfaceInstance, JsonRpcMapper mapper) - throws IOException - { + throws IOException { super(channel, queueName); this.mapper = mapper; init(interfaceClass, interfaceInstance); @@ -107,38 +103,43 @@ public JsonRpcServer(Channel channel, * given channel and queue name. Our superclass, * RpcServer, expects the queue to exist at the time of * construction. - * @param channel AMQP channel to use - * @param queueName AMQP queue name to listen for requests on - * @param interfaceClass Java interface that this server is exposing to the world + * + * @param channel AMQP channel to use + * @param queueName AMQP queue name to listen for requests on + * @param interfaceClass Java interface that this server is exposing to the world * @param interfaceInstance Java instance (of interfaceClass) that is being exposed * @throws IOException if something goes wrong during an AMQP operation */ public JsonRpcServer(Channel channel, - String queueName, - Class interfaceClass, - Object interfaceInstance) - throws IOException - { + String queueName, + Class interfaceClass, + Object interfaceInstance) + throws IOException { this(channel, queueName, interfaceClass, interfaceInstance, new DefaultJsonRpcMapper()); } + private void init(Class interfaceClass, Object interfaceInstance) { + this.interfaceClass = interfaceClass; + this.interfaceInstance = interfaceInstance; + this.serviceDescription = new ServiceDescription(interfaceClass); + } + /** * Override our superclass' method, dispatching to doCall. */ @Override - public String handleStringCall(String requestBody, AMQP.BasicProperties replyProperties) - { + public String handleStringCall(String requestBody, AMQP.BasicProperties replyProperties) { String replyBody = doCall(requestBody); return replyBody; } /** * Runs a single JSON-RPC request. + * * @param requestBody the JSON-RPC request string (a JSON encoded value) * @return a JSON-RPC response string (a JSON encoded value) */ - public String doCall(String requestBody) - { + public String doCall(String requestBody) { Object id; String method; Object[] params; @@ -188,7 +189,7 @@ public String doCall(String requestBody) } } catch (ClassCastException cce) { // Bogus request! - response = errorResponse(null, 400, "Bad Request", null); + response = errorResponse(null, 400, "Bad Request", null); } if (LOGGER.isDebugEnabled()) { @@ -200,13 +201,12 @@ public String doCall(String requestBody) /** * Retrieves the best matching method for the given method name and parameters. - * + *

* Subclasses may override this if they have specialised * dispatching requirements, so long as they continue to honour * their ServiceDescription. */ - public Method matchingMethod(String methodName, Object[] params) - { + public Method matchingMethod(String methodName, Object[] params) { ProcedureDescription proc = serviceDescription.getProcedure(methodName, params.length); return proc.internal_getMethod(); } diff --git a/src/test/java/com/rabbitmq/client/AbstractJsonRpcTest.java b/src/test/java/com/rabbitmq/client/AbstractJsonRpcTest.java index 555d4c0b24..079dcf00a7 100644 --- a/src/test/java/com/rabbitmq/client/AbstractJsonRpcTest.java +++ b/src/test/java/com/rabbitmq/client/AbstractJsonRpcTest.java @@ -21,12 +21,8 @@ import com.rabbitmq.tools.jsonrpc.JsonRpcServer; import org.junit.After; import org.junit.Before; -import org.junit.Test; -import java.lang.reflect.UndeclaredThrowableException; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; +import java.util.Date; public abstract class AbstractJsonRpcTest { @@ -105,6 +101,9 @@ public interface RpcService { void procedureException(); + void procedureNoArgumentVoid(); + + Date procedureDateDate(Date date); } public static class DefaultRpcservice implements RpcService { @@ -185,6 +184,16 @@ public String procedurePojoToString(Pojo pojo) { public void procedureException() { throw new RuntimeException(); } + + @Override + public void procedureNoArgumentVoid() { + + } + + @Override + public Date procedureDateDate(Date date) { + return date; + } } public static class Pojo { diff --git a/src/test/java/com/rabbitmq/client/BlockingCellBenchmark.java b/src/test/java/com/rabbitmq/client/BlockingCellBenchmark.java deleted file mode 100644 index d65d01f956..0000000000 --- a/src/test/java/com/rabbitmq/client/BlockingCellBenchmark.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.rabbitmq.client; - -import com.rabbitmq.utility.BlockingCell; - -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -/** - * - */ -public class BlockingCellBenchmark { - - public static void main(String[] args) { - - } - - public void legacyBlockingCell() { - ExecutorService executorService = Executors.newFixedThreadPool(10); - - for (int i = 0; i < 1000; i++) { - final BlockingCell cell = new BlockingCell(); - executorService.submit(new Callable() { - - @Override - public Void call() throws Exception { - cell.set("whatever"); - return null; - } - }); - - cell.uninterruptibleGet(); - - } - - } - -} diff --git a/src/test/java/com/rabbitmq/client/JsonRpcTest.java b/src/test/java/com/rabbitmq/client/DefaultJsonRpcTest.java similarity index 96% rename from src/test/java/com/rabbitmq/client/JsonRpcTest.java rename to src/test/java/com/rabbitmq/client/DefaultJsonRpcTest.java index a4a18f9693..049554d1d2 100644 --- a/src/test/java/com/rabbitmq/client/JsonRpcTest.java +++ b/src/test/java/com/rabbitmq/client/DefaultJsonRpcTest.java @@ -16,7 +16,6 @@ package com.rabbitmq.client; import com.rabbitmq.tools.jsonrpc.DefaultJsonRpcMapper; -import com.rabbitmq.tools.jsonrpc.JacksonJsonRpcMapper; import com.rabbitmq.tools.jsonrpc.JsonRpcException; import com.rabbitmq.tools.jsonrpc.JsonRpcMapper; import org.junit.Test; @@ -28,7 +27,7 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -public class JsonRpcTest extends AbstractJsonRpcTest { +public class DefaultJsonRpcTest extends AbstractJsonRpcTest { @Override JsonRpcMapper createMapper() { @@ -44,6 +43,7 @@ public void rpc() { assertEquals(2, service.procedurePrimitiveInteger(1)); assertEquals(2, service.procedureDouble(1.0).intValue()); assertEquals(2, (int) service.procedurePrimitiveDouble(1.0)); + service.procedureNoArgumentVoid(); try { service.procedureException(); @@ -52,7 +52,6 @@ public void rpc() { assertTrue(e.getCause() instanceof JsonRpcException); } - try { assertEquals(2, (int) service.procedureLongToInteger(1L)); fail("Long argument isn't supported"); diff --git a/src/test/java/com/rabbitmq/client/JacksonRpcTest.java b/src/test/java/com/rabbitmq/client/JacksonJsonRpcTest.java similarity index 80% rename from src/test/java/com/rabbitmq/client/JacksonRpcTest.java rename to src/test/java/com/rabbitmq/client/JacksonJsonRpcTest.java index ba95efef98..6ccb2c4751 100644 --- a/src/test/java/com/rabbitmq/client/JacksonRpcTest.java +++ b/src/test/java/com/rabbitmq/client/JacksonJsonRpcTest.java @@ -21,13 +21,15 @@ import org.junit.Test; import java.lang.reflect.UndeclaredThrowableException; +import java.util.Calendar; +import java.util.Date; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -public class JacksonRpcTest extends AbstractJsonRpcTest { +public class JacksonJsonRpcTest extends AbstractJsonRpcTest { @Override JsonRpcMapper createMapper() { @@ -49,6 +51,19 @@ public void rpc() { assertEquals(2, service.procedurePrimitiveLong(1L)); assertEquals(2, service.procedureLong(1L).longValue()); assertEquals("123", service.procedureIntegerToPojo(123).getStringProperty()); + service.procedureNoArgumentVoid(); + + Calendar calendar = Calendar.getInstance(); + Date date = calendar.getTime(); + Date returnedDate = service.procedureDateDate(date); + assertEquals(date.getTime(), returnedDate.getTime()); + + try { + service.procedureException(); + fail("Remote procedure throwing exception, an exception should have been thrown"); + } catch (UndeclaredThrowableException e) { + assertTrue(e.getCause() instanceof JsonRpcException); + } Pojo pojo = new Pojo(); pojo.setStringProperty("hello"); diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index 78e8616d4b..e79c40df73 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -16,8 +16,8 @@ package com.rabbitmq.client.test; -import com.rabbitmq.client.JacksonRpcTest; -import com.rabbitmq.client.JsonRpcTest; +import com.rabbitmq.client.JacksonJsonRpcTest; +import com.rabbitmq.client.DefaultJsonRpcTest; import com.rabbitmq.utility.IntAllocatorTests; import org.junit.runner.RunWith; import org.junit.runners.Suite; @@ -62,8 +62,8 @@ TestUtilsTest.class, StrictExceptionHandlerTest.class, NoAutoRecoveryWhenTcpWindowIsFullTest.class, - JsonRpcTest.class, - JacksonRpcTest.class, + DefaultJsonRpcTest.class, + JacksonJsonRpcTest.class, AddressTest.class, DefaultRetryHandlerTest.class }) From d79a8b06d209e62d21c08e041d89c14261fc56f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 14 Aug 2018 10:35:26 +0200 Subject: [PATCH 0848/2114] Polish JSON RPC support References #378 --- src/main/java/com/rabbitmq/tools/json/JSONReader.java | 2 +- .../java/com/rabbitmq/tools/json/JSONSerializable.java | 2 +- src/main/java/com/rabbitmq/tools/json/JSONWriter.java | 2 +- .../com/rabbitmq/tools/jsonrpc/DefaultJsonRpcMapper.java | 2 ++ src/test/java/com/rabbitmq/client/JacksonJsonRpcTest.java | 7 ------- 5 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/rabbitmq/tools/json/JSONReader.java b/src/main/java/com/rabbitmq/tools/json/JSONReader.java index fa4c43643d..14c690e6e2 100644 --- a/src/main/java/com/rabbitmq/tools/json/JSONReader.java +++ b/src/main/java/com/rabbitmq/tools/json/JSONReader.java @@ -47,7 +47,7 @@ /** * Will be removed in 6.0 * - * @deprecated Use a third-party JSON library, e.g. Jackson or GJSON + * @deprecated Use a third-party JSON library, e.g. Jackson or Gson */ public class JSONReader { diff --git a/src/main/java/com/rabbitmq/tools/json/JSONSerializable.java b/src/main/java/com/rabbitmq/tools/json/JSONSerializable.java index f453de5038..39f72d4ac2 100644 --- a/src/main/java/com/rabbitmq/tools/json/JSONSerializable.java +++ b/src/main/java/com/rabbitmq/tools/json/JSONSerializable.java @@ -21,7 +21,7 @@ * * Will be removed in 6.0 * - * @deprecated Use a third-party JSON library, e.g. Jackson or GJSON + * @deprecated Use a third-party JSON library, e.g. Jackson or Gson */ public interface JSONSerializable { /** diff --git a/src/main/java/com/rabbitmq/tools/json/JSONWriter.java b/src/main/java/com/rabbitmq/tools/json/JSONWriter.java index eb82cc7751..7101598040 100644 --- a/src/main/java/com/rabbitmq/tools/json/JSONWriter.java +++ b/src/main/java/com/rabbitmq/tools/json/JSONWriter.java @@ -55,7 +55,7 @@ /** * Will be removed in 6.0 - * @deprecated Use a third-party JSON library, e.g. Jackson or GJSON + * @deprecated Use a third-party JSON library, e.g. Jackson or Gson */ public class JSONWriter { private boolean indentMode = false; diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/DefaultJsonRpcMapper.java b/src/main/java/com/rabbitmq/tools/jsonrpc/DefaultJsonRpcMapper.java index db6cda0b6d..b40789e380 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/DefaultJsonRpcMapper.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/DefaultJsonRpcMapper.java @@ -38,6 +38,7 @@ public class DefaultJsonRpcMapper implements JsonRpcMapper { @Override public JsonRpcRequest parse(String requestBody, ServiceDescription description) { + @SuppressWarnings("unchecked") Map request = (Map) new JSONReader().read(requestBody); return new JsonRpcRequest( request.get("id"), request.get("version").toString(), request.get("method").toString(), @@ -47,6 +48,7 @@ public JsonRpcRequest parse(String requestBody, ServiceDescription description) @Override public JsonRpcResponse parse(String responseBody, Class expectedType) { + @SuppressWarnings("unchecked") Map map = (Map) (new JSONReader().read(responseBody)); Map error; JsonRpcException exception = null; diff --git a/src/test/java/com/rabbitmq/client/JacksonJsonRpcTest.java b/src/test/java/com/rabbitmq/client/JacksonJsonRpcTest.java index 6ccb2c4751..091ce44680 100644 --- a/src/test/java/com/rabbitmq/client/JacksonJsonRpcTest.java +++ b/src/test/java/com/rabbitmq/client/JacksonJsonRpcTest.java @@ -58,13 +58,6 @@ public void rpc() { Date returnedDate = service.procedureDateDate(date); assertEquals(date.getTime(), returnedDate.getTime()); - try { - service.procedureException(); - fail("Remote procedure throwing exception, an exception should have been thrown"); - } catch (UndeclaredThrowableException e) { - assertTrue(e.getCause() instanceof JsonRpcException); - } - Pojo pojo = new Pojo(); pojo.setStringProperty("hello"); assertEquals("hello", service.procedurePojoToString(pojo)); From 0a7e7e563db93e9e886a3bfd3c0e3cf7840e6a74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 14 Aug 2018 15:25:10 +0200 Subject: [PATCH 0849/2114] Add dedicated executor to close connection in NIO mode When sharing the same executor for NIO and connection closing, all the threads of the pool can be busy recovering connections, leaving no thread left for IO. This commit add a new executor service to the NIO mode to submit all the connection closing to. This is useful when an application maintains dozens or hundreds of connections and suffers massive connection lost. Hundreds of connection closing tasks can be submitted very quickly, so controlling the number of threads and leaving some threads available for IO is critical. If an application maintain just a few connections and can deal with the creation of a few threads, using the new executor isn't necessary. Fixes #380 --- .../com/rabbitmq/client/impl/nio/NioLoop.java | 19 ++-- .../rabbitmq/client/impl/nio/NioParams.java | 45 ++++++++- .../com/rabbitmq/client/test/ClientTests.java | 3 +- .../test/NioDeadlockOnConnectionClosing.java | 98 +++++++++++++++++++ .../com/rabbitmq/client/test/TestUtils.java | 40 +++++--- 5 files changed, 176 insertions(+), 29 deletions(-) create mode 100644 src/test/java/com/rabbitmq/client/test/NioDeadlockOnConnectionClosing.java diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java b/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java index d4ce97dde6..6e1c1f6352 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java @@ -41,9 +41,12 @@ public class NioLoop implements Runnable { private final NioParams nioParams; + private final ExecutorService connectionShutdownExecutor; + public NioLoop(NioParams nioParams, NioLoopContext loopContext) { this.nioParams = nioParams; this.context = loopContext; + this.connectionShutdownExecutor = nioParams.getConnectionShutdownExecutor(); } @Override @@ -283,19 +286,15 @@ protected void dispatchIoErrorToConnection(final SocketChannelFrameHandlerState } protected void dispatchShutdownToConnection(final SocketChannelFrameHandlerState state) { - Runnable shutdown = new Runnable() { - - @Override - public void run() { - state.getConnection().doFinalShutdown(); - } - }; - if (executorService() == null) { + Runnable shutdown = () -> state.getConnection().doFinalShutdown(); + if (this.connectionShutdownExecutor != null) { + connectionShutdownExecutor.execute(shutdown); + } else if (executorService() != null) { + executorService().execute(shutdown); + } else { String name = "rabbitmq-connection-shutdown-" + state.getConnection(); Thread shutdownThread = Environment.newThread(threadFactory(), shutdown, name); shutdownThread.start(); - } else { - executorService().submit(shutdown); } } diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java b/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java index 0dbe627808..6652a7843f 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java @@ -55,10 +55,10 @@ public class NioParams { private SocketChannelConfigurator socketChannelConfigurator = new DefaultSocketChannelConfigurator(); /** the hook to configure the SSL engine before the connection is open */ - private SslEngineConfigurator sslEngineConfigurator = new SslEngineConfigurator() { - @Override - public void configure(SSLEngine sslEngine) throws IOException { } - }; + private SslEngineConfigurator sslEngineConfigurator = sslEngine -> { }; + + /** the executor service used for connection shutdown */ + private ExecutorService connectionShutdownExecutor; public NioParams() { } @@ -72,6 +72,7 @@ public NioParams(NioParams nioParams) { setNioExecutor(nioParams.getNioExecutor()); setThreadFactory(nioParams.getThreadFactory()); setSslEngineConfigurator(nioParams.getSslEngineConfigurator()); + setConnectionShutdownExecutor(nioParams.getConnectionShutdownExecutor()); } public int getReadByteBufferSize() { @@ -186,6 +187,9 @@ public ExecutorService getNioExecutor() { * number of requested IO threads, plus a few more, as it's also * used to dispatch the shutdown of connections. * + * Connection shutdown can also be handled by a dedicated {@link ExecutorService}, + * see {@link #setConnectionShutdownExecutor(ExecutorService)}. + * * It's developer's responsibility to shut down the executor * when it is no longer needed. * @@ -195,6 +199,7 @@ public ExecutorService getNioExecutor() { * @return this {@link NioParams} instance * @see NioParams#setNbIoThreads(int) * @see NioParams#setThreadFactory(ThreadFactory) + * @see NioParams#setConnectionShutdownExecutor(ExecutorService) */ public NioParams setNioExecutor(ExecutorService nioExecutor) { this.nioExecutor = nioExecutor; @@ -275,4 +280,36 @@ public void setSslEngineConfigurator(SslEngineConfigurator configurator) { public SslEngineConfigurator getSslEngineConfigurator() { return sslEngineConfigurator; } + + /** + * Set the {@link ExecutorService} used for connection shutdown. + * If not set, falls back to the NIO executor and then the thread factory. + * This executor service is useful when strict control of the number of threads + * is necessary, the application can experience the closing of several connections + * at once, and automatic recovery is enabled. In such cases, the connection recovery + * can take place in the same pool of threads as the NIO operations, which can + * create deadlocks (all the threads of the pool are busy recovering, and there's no + * thread left for NIO, so connections never recover). + *

+ * Note it's developer's responsibility to shut down the executor + * when it is no longer needed. + *

+ * Using the thread factory for such scenarios avoid the deadlocks, at the price + * of potentially creating many short-lived threads in case of massive connection lost. + *

+ * With both the NIO and connection shutdown executor services set and configured + * accordingly, the application can control reliably the number of threads used. + * + * @param connectionShutdownExecutor the executor service to use + * @return this {@link NioParams} instance + * @see NioParams#setNioExecutor(ExecutorService) + */ + public NioParams setConnectionShutdownExecutor(ExecutorService connectionShutdownExecutor) { + this.connectionShutdownExecutor = connectionShutdownExecutor; + return this; + } + + public ExecutorService getConnectionShutdownExecutor() { + return connectionShutdownExecutor; + } } diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index 9c2994b671..2b4c8ea04a 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -63,7 +63,8 @@ NoAutoRecoveryWhenTcpWindowIsFullTest.class, JsonRpcTest.class, AddressTest.class, - DefaultRetryHandlerTest.class + DefaultRetryHandlerTest.class, + NioDeadlockOnConnectionClosing.class }) public class ClientTests { diff --git a/src/test/java/com/rabbitmq/client/test/NioDeadlockOnConnectionClosing.java b/src/test/java/com/rabbitmq/client/test/NioDeadlockOnConnectionClosing.java new file mode 100644 index 0000000000..78082344b1 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/NioDeadlockOnConnectionClosing.java @@ -0,0 +1,98 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.test; + +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.impl.nio.NioParams; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import static com.rabbitmq.client.test.TestUtils.closeAllConnectionsAndWaitForRecovery; +import static org.junit.Assert.assertTrue; + +/** + * + */ +public class NioDeadlockOnConnectionClosing { + + static final Logger LOGGER = LoggerFactory.getLogger(NioDeadlockOnConnectionClosing.class); + + ExecutorService nioExecutorService, connectionShutdownExecutorService; + ConnectionFactory cf; + List connections; + + @Before + public void setUp() { + nioExecutorService = Executors.newFixedThreadPool(2); + connectionShutdownExecutorService = Executors.newFixedThreadPool(2); + cf = TestUtils.connectionFactory(); + cf.setAutomaticRecoveryEnabled(true); + cf.useNio(); + cf.setNetworkRecoveryInterval(1000); + NioParams params = new NioParams() + .setNioExecutor(nioExecutorService) + .setConnectionShutdownExecutor(connectionShutdownExecutorService) + .setNbIoThreads(2); + cf.setNioParams(params); + connections = new ArrayList<>(); + } + + @After + public void tearDown() throws Exception { + for (Connection connection : connections) { + try { + connection.close(2000); + } catch (Exception e) { + LOGGER.warn("Error while closing test connection", e); + } + } + + shutdownExecutorService(nioExecutorService); + shutdownExecutorService(connectionShutdownExecutorService); + } + + private void shutdownExecutorService(ExecutorService executorService) throws InterruptedException { + if (executorService == null) { + return; + } + executorService.shutdown(); + boolean terminated = executorService.awaitTermination(5, TimeUnit.SECONDS); + if (!terminated) { + LOGGER.warn("Couldn't terminate executor after 5 seconds"); + } + } + + @Test + public void connectionClosing() throws Exception { + for (int i = 0; i < 10; i++) { + connections.add(cf.newConnection()); + } + closeAllConnectionsAndWaitForRecovery(connections); + for (Connection connection : connections) { + assertTrue(connection.isOpen()); + } + } +} diff --git a/src/test/java/com/rabbitmq/client/test/TestUtils.java b/src/test/java/com/rabbitmq/client/test/TestUtils.java index c44e8b26a4..5b0b7d0d7e 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtils.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtils.java @@ -31,6 +31,8 @@ import org.slf4j.LoggerFactory; import java.io.IOException; +import java.util.Collection; +import java.util.Collections; import java.util.concurrent.Callable; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -156,26 +158,36 @@ public static void closeAndWaitForRecovery(RecoverableConnection connection) thr wait(latch); } - public static void closeAllConnectionsAndWaitForRecovery(Connection connection) throws IOException, InterruptedException { - CountDownLatch latch = prepareForRecovery(connection); + public static void closeAllConnectionsAndWaitForRecovery(Collection connections) throws IOException, InterruptedException { + CountDownLatch latch = prepareForRecovery(connections); Host.closeAllConnections(); wait(latch); } - public static CountDownLatch prepareForRecovery(Connection conn) { - final CountDownLatch latch = new CountDownLatch(1); - ((AutorecoveringConnection) conn).addRecoveryListener(new RecoveryListener() { + public static void closeAllConnectionsAndWaitForRecovery(Connection connection) throws IOException, InterruptedException { + closeAllConnectionsAndWaitForRecovery(Collections.singletonList(connection)); + } - @Override - public void handleRecovery(Recoverable recoverable) { - latch.countDown(); - } + public static CountDownLatch prepareForRecovery(Connection connection) { + return prepareForRecovery(Collections.singletonList(connection)); + } - @Override - public void handleRecoveryStarted(Recoverable recoverable) { - // No-op - } - }); + public static CountDownLatch prepareForRecovery(Collection connections) { + final CountDownLatch latch = new CountDownLatch(connections.size()); + for (Connection conn : connections) { + ((AutorecoveringConnection) conn).addRecoveryListener(new RecoveryListener() { + + @Override + public void handleRecovery(Recoverable recoverable) { + latch.countDown(); + } + + @Override + public void handleRecoveryStarted(Recoverable recoverable) { + // No-op + } + }); + } return latch; } From 22ca4c8be29b0c235663db4c19291eacafe98f04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 16 Aug 2018 11:03:25 +0200 Subject: [PATCH 0850/2114] Add equals and hashCode to generate classes Fixes #377 --- codegen.py | 48 +++++++ .../com/rabbitmq/client/test/ClientTests.java | 3 +- .../client/test/GeneratedClassesTest.java | 135 ++++++++++++++++++ 3 files changed, 185 insertions(+), 1 deletion(-) create mode 100644 src/test/java/com/rabbitmq/client/test/GeneratedClassesTest.java diff --git a/codegen.py b/codegen.py index 7ef06b4141..3a67ce435d 100755 --- a/codegen.py +++ b/codegen.py @@ -368,6 +368,9 @@ def printGetter(fieldType, fieldName): print(" public int getClassId() { return %i; }" % (c.index)) print(" public String getClassName() { return \"%s\"; }" % (c.name)) + if c.fields: + equalsHashCode(spec, c.fields, java_class_name(c.name), 'Properties', False) + printPropertiesBuilder(c) #accessor methods @@ -400,6 +403,49 @@ def printPropertiesClasses(): #-------------------------------------------------------------------------------- +def equalsHashCode(spec, fields, jClassName, classSuffix, usePrimitiveType): + print() + print() + print(" @Override") + print(" public boolean equals(Object o) {") + print(" if (this == o)") + print(" return true;") + print(" if (o == null || getClass() != o.getClass())") + print(" return false;") + print(" %s%s that = (%s%s) o;" % (jClassName, classSuffix, jClassName, classSuffix)) + + for f in fields: + (fType, fName) = (java_field_type(spec, f.domain), java_field_name(f.name)) + if usePrimitiveType and fType in javaScalarTypes: + print(" if (%s != that.%s)" % (fName, fName)) + else: + print(" if (%s != null ? !%s.equals(that.%s) : that.%s != null)" % (fName, fName, fName, fName)) + + print(" return false;") + + print(" return true;") + print(" }") + + print() + print(" @Override") + print(" public int hashCode() {") + print(" int result = 0;") + + for f in fields: + (fType, fName) = (java_field_type(spec, f.domain), java_field_name(f.name)) + if usePrimitiveType and fType in javaScalarTypes: + if fType == 'boolean': + print(" result = 31 * result + (%s ? 1 : 0);" % fName) + elif fType == 'long': + print(" result = 31 * result + (int) (%s ^ (%s >>> 32));" % (fName, fName)) + else: + print(" result = 31 * result + %s;" % fName) + else: + print(" result = 31 * result + (%s != null ? %s.hashCode() : 0);" % (fName, fName)) + + print(" return result;") + print(" }") + def genJavaImpl(spec): def printHeader(): printFileHeader() @@ -503,6 +549,8 @@ def write_arguments(): getters() constructors() others() + if m.arguments: + equalsHashCode(spec, m.arguments, java_class_name(m.name), '', True) argument_debug_string() write_arguments() diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index 2b4c8ea04a..c299764f31 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -64,7 +64,8 @@ JsonRpcTest.class, AddressTest.class, DefaultRetryHandlerTest.class, - NioDeadlockOnConnectionClosing.class + NioDeadlockOnConnectionClosing.class, + GeneratedClassesTest.class }) public class ClientTests { diff --git a/src/test/java/com/rabbitmq/client/test/GeneratedClassesTest.java b/src/test/java/com/rabbitmq/client/test/GeneratedClassesTest.java new file mode 100644 index 0000000000..e9dbcfca98 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/GeneratedClassesTest.java @@ -0,0 +1,135 @@ +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.test; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.impl.AMQImpl; +import org.junit.Test; + +import java.util.Calendar; +import java.util.Date; + +import static java.util.Collections.singletonMap; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; + +/** + * + */ +public class GeneratedClassesTest { + + @Test + public void amqpPropertiesEqualsHashCode() { + checkEquals( + new AMQP.BasicProperties.Builder().correlationId("one").build(), + new AMQP.BasicProperties.Builder().correlationId("one").build() + ); + checkNotEquals( + new AMQP.BasicProperties.Builder().correlationId("one").build(), + new AMQP.BasicProperties.Builder().correlationId("two").build() + ); + Date date = Calendar.getInstance().getTime(); + checkEquals( + new AMQP.BasicProperties.Builder() + .deliveryMode(1) + .headers(singletonMap("one", "two")) + .correlationId("123") + .expiration("later") + .priority(10) + .replyTo("me") + .contentType("text/plain") + .contentEncoding("UTF-8") + .userId("jdoe") + .appId("app1") + .clusterId("cluster1") + .messageId("message123") + .timestamp(date) + .type("type") + .build(), + new AMQP.BasicProperties.Builder() + .deliveryMode(1) + .headers(singletonMap("one", "two")) + .correlationId("123") + .expiration("later") + .priority(10) + .replyTo("me") + .contentType("text/plain") + .contentEncoding("UTF-8") + .userId("jdoe") + .appId("app1") + .clusterId("cluster1") + .messageId("message123") + .timestamp(date) + .type("type") + .build() + ); + checkNotEquals( + new AMQP.BasicProperties.Builder() + .deliveryMode(1) + .headers(singletonMap("one", "two")) + .correlationId("123") + .expiration("later") + .priority(10) + .replyTo("me") + .contentType("text/plain") + .contentEncoding("UTF-8") + .userId("jdoe") + .appId("app1") + .clusterId("cluster1") + .messageId("message123") + .timestamp(date) + .type("type") + .build(), + new AMQP.BasicProperties.Builder() + .deliveryMode(2) + .headers(singletonMap("one", "two")) + .correlationId("123") + .expiration("later") + .priority(10) + .replyTo("me") + .contentType("text/plain") + .contentEncoding("UTF-8") + .userId("jdoe") + .appId("app1") + .clusterId("cluster1") + .messageId("message123") + .timestamp(date) + .type("type") + .build() + ); + + } + + @Test public void amqImplEqualsHashCode() { + checkEquals( + new AMQImpl.Basic.Deliver("tag", 1L, false, "amq.direct","rk"), + new AMQImpl.Basic.Deliver("tag", 1L, false, "amq.direct","rk") + ); + checkNotEquals( + new AMQImpl.Basic.Deliver("tag", 1L, false, "amq.direct","rk"), + new AMQImpl.Basic.Deliver("tag", 2L, false, "amq.direct","rk") + ); + } + + private void checkEquals(Object o1, Object o2) { + assertEquals(o1, o2); + assertEquals(o1.hashCode(), o2.hashCode()); + } + + private void checkNotEquals(Object o1, Object o2) { + assertNotEquals(o1, o2); + } +} From 11b24403d79d3c8bc30a4ac76fa9e1a038d798a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 14 Aug 2018 15:25:10 +0200 Subject: [PATCH 0851/2114] Add dedicated executor to close connection in NIO mode When sharing the same executor for NIO and connection closing, all the threads of the pool can be busy recovering connections, leaving no thread left for IO. This commit add a new executor service to the NIO mode to submit all the connection closing to. This is useful when an application maintains dozens or hundreds of connections and suffers massive connection lost. Hundreds of connection closing tasks can be submitted very quickly, so controlling the number of threads and leaving some threads available for IO is critical. If an application maintain just a few connections and can deal with the creation of a few threads, using the new executor isn't necessary. Fixes #380 (cherry picked from commit 0a7e7e563db93e9e886a3bfd3c0e3cf7840e6a74) --- .../com/rabbitmq/client/impl/nio/NioLoop.java | 19 ++-- .../rabbitmq/client/impl/nio/NioParams.java | 45 ++++++++- .../com/rabbitmq/client/test/ClientTests.java | 3 +- .../test/NioDeadlockOnConnectionClosing.java | 98 +++++++++++++++++++ .../com/rabbitmq/client/test/TestUtils.java | 40 +++++--- 5 files changed, 176 insertions(+), 29 deletions(-) create mode 100644 src/test/java/com/rabbitmq/client/test/NioDeadlockOnConnectionClosing.java diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java b/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java index d4ce97dde6..6e1c1f6352 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java @@ -41,9 +41,12 @@ public class NioLoop implements Runnable { private final NioParams nioParams; + private final ExecutorService connectionShutdownExecutor; + public NioLoop(NioParams nioParams, NioLoopContext loopContext) { this.nioParams = nioParams; this.context = loopContext; + this.connectionShutdownExecutor = nioParams.getConnectionShutdownExecutor(); } @Override @@ -283,19 +286,15 @@ protected void dispatchIoErrorToConnection(final SocketChannelFrameHandlerState } protected void dispatchShutdownToConnection(final SocketChannelFrameHandlerState state) { - Runnable shutdown = new Runnable() { - - @Override - public void run() { - state.getConnection().doFinalShutdown(); - } - }; - if (executorService() == null) { + Runnable shutdown = () -> state.getConnection().doFinalShutdown(); + if (this.connectionShutdownExecutor != null) { + connectionShutdownExecutor.execute(shutdown); + } else if (executorService() != null) { + executorService().execute(shutdown); + } else { String name = "rabbitmq-connection-shutdown-" + state.getConnection(); Thread shutdownThread = Environment.newThread(threadFactory(), shutdown, name); shutdownThread.start(); - } else { - executorService().submit(shutdown); } } diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java b/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java index 0dbe627808..6652a7843f 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java @@ -55,10 +55,10 @@ public class NioParams { private SocketChannelConfigurator socketChannelConfigurator = new DefaultSocketChannelConfigurator(); /** the hook to configure the SSL engine before the connection is open */ - private SslEngineConfigurator sslEngineConfigurator = new SslEngineConfigurator() { - @Override - public void configure(SSLEngine sslEngine) throws IOException { } - }; + private SslEngineConfigurator sslEngineConfigurator = sslEngine -> { }; + + /** the executor service used for connection shutdown */ + private ExecutorService connectionShutdownExecutor; public NioParams() { } @@ -72,6 +72,7 @@ public NioParams(NioParams nioParams) { setNioExecutor(nioParams.getNioExecutor()); setThreadFactory(nioParams.getThreadFactory()); setSslEngineConfigurator(nioParams.getSslEngineConfigurator()); + setConnectionShutdownExecutor(nioParams.getConnectionShutdownExecutor()); } public int getReadByteBufferSize() { @@ -186,6 +187,9 @@ public ExecutorService getNioExecutor() { * number of requested IO threads, plus a few more, as it's also * used to dispatch the shutdown of connections. * + * Connection shutdown can also be handled by a dedicated {@link ExecutorService}, + * see {@link #setConnectionShutdownExecutor(ExecutorService)}. + * * It's developer's responsibility to shut down the executor * when it is no longer needed. * @@ -195,6 +199,7 @@ public ExecutorService getNioExecutor() { * @return this {@link NioParams} instance * @see NioParams#setNbIoThreads(int) * @see NioParams#setThreadFactory(ThreadFactory) + * @see NioParams#setConnectionShutdownExecutor(ExecutorService) */ public NioParams setNioExecutor(ExecutorService nioExecutor) { this.nioExecutor = nioExecutor; @@ -275,4 +280,36 @@ public void setSslEngineConfigurator(SslEngineConfigurator configurator) { public SslEngineConfigurator getSslEngineConfigurator() { return sslEngineConfigurator; } + + /** + * Set the {@link ExecutorService} used for connection shutdown. + * If not set, falls back to the NIO executor and then the thread factory. + * This executor service is useful when strict control of the number of threads + * is necessary, the application can experience the closing of several connections + * at once, and automatic recovery is enabled. In such cases, the connection recovery + * can take place in the same pool of threads as the NIO operations, which can + * create deadlocks (all the threads of the pool are busy recovering, and there's no + * thread left for NIO, so connections never recover). + *

+ * Note it's developer's responsibility to shut down the executor + * when it is no longer needed. + *

+ * Using the thread factory for such scenarios avoid the deadlocks, at the price + * of potentially creating many short-lived threads in case of massive connection lost. + *

+ * With both the NIO and connection shutdown executor services set and configured + * accordingly, the application can control reliably the number of threads used. + * + * @param connectionShutdownExecutor the executor service to use + * @return this {@link NioParams} instance + * @see NioParams#setNioExecutor(ExecutorService) + */ + public NioParams setConnectionShutdownExecutor(ExecutorService connectionShutdownExecutor) { + this.connectionShutdownExecutor = connectionShutdownExecutor; + return this; + } + + public ExecutorService getConnectionShutdownExecutor() { + return connectionShutdownExecutor; + } } diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index 9c2994b671..2b4c8ea04a 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -63,7 +63,8 @@ NoAutoRecoveryWhenTcpWindowIsFullTest.class, JsonRpcTest.class, AddressTest.class, - DefaultRetryHandlerTest.class + DefaultRetryHandlerTest.class, + NioDeadlockOnConnectionClosing.class }) public class ClientTests { diff --git a/src/test/java/com/rabbitmq/client/test/NioDeadlockOnConnectionClosing.java b/src/test/java/com/rabbitmq/client/test/NioDeadlockOnConnectionClosing.java new file mode 100644 index 0000000000..78082344b1 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/NioDeadlockOnConnectionClosing.java @@ -0,0 +1,98 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.test; + +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.impl.nio.NioParams; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import static com.rabbitmq.client.test.TestUtils.closeAllConnectionsAndWaitForRecovery; +import static org.junit.Assert.assertTrue; + +/** + * + */ +public class NioDeadlockOnConnectionClosing { + + static final Logger LOGGER = LoggerFactory.getLogger(NioDeadlockOnConnectionClosing.class); + + ExecutorService nioExecutorService, connectionShutdownExecutorService; + ConnectionFactory cf; + List connections; + + @Before + public void setUp() { + nioExecutorService = Executors.newFixedThreadPool(2); + connectionShutdownExecutorService = Executors.newFixedThreadPool(2); + cf = TestUtils.connectionFactory(); + cf.setAutomaticRecoveryEnabled(true); + cf.useNio(); + cf.setNetworkRecoveryInterval(1000); + NioParams params = new NioParams() + .setNioExecutor(nioExecutorService) + .setConnectionShutdownExecutor(connectionShutdownExecutorService) + .setNbIoThreads(2); + cf.setNioParams(params); + connections = new ArrayList<>(); + } + + @After + public void tearDown() throws Exception { + for (Connection connection : connections) { + try { + connection.close(2000); + } catch (Exception e) { + LOGGER.warn("Error while closing test connection", e); + } + } + + shutdownExecutorService(nioExecutorService); + shutdownExecutorService(connectionShutdownExecutorService); + } + + private void shutdownExecutorService(ExecutorService executorService) throws InterruptedException { + if (executorService == null) { + return; + } + executorService.shutdown(); + boolean terminated = executorService.awaitTermination(5, TimeUnit.SECONDS); + if (!terminated) { + LOGGER.warn("Couldn't terminate executor after 5 seconds"); + } + } + + @Test + public void connectionClosing() throws Exception { + for (int i = 0; i < 10; i++) { + connections.add(cf.newConnection()); + } + closeAllConnectionsAndWaitForRecovery(connections); + for (Connection connection : connections) { + assertTrue(connection.isOpen()); + } + } +} diff --git a/src/test/java/com/rabbitmq/client/test/TestUtils.java b/src/test/java/com/rabbitmq/client/test/TestUtils.java index c44e8b26a4..5b0b7d0d7e 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtils.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtils.java @@ -31,6 +31,8 @@ import org.slf4j.LoggerFactory; import java.io.IOException; +import java.util.Collection; +import java.util.Collections; import java.util.concurrent.Callable; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -156,26 +158,36 @@ public static void closeAndWaitForRecovery(RecoverableConnection connection) thr wait(latch); } - public static void closeAllConnectionsAndWaitForRecovery(Connection connection) throws IOException, InterruptedException { - CountDownLatch latch = prepareForRecovery(connection); + public static void closeAllConnectionsAndWaitForRecovery(Collection connections) throws IOException, InterruptedException { + CountDownLatch latch = prepareForRecovery(connections); Host.closeAllConnections(); wait(latch); } - public static CountDownLatch prepareForRecovery(Connection conn) { - final CountDownLatch latch = new CountDownLatch(1); - ((AutorecoveringConnection) conn).addRecoveryListener(new RecoveryListener() { + public static void closeAllConnectionsAndWaitForRecovery(Connection connection) throws IOException, InterruptedException { + closeAllConnectionsAndWaitForRecovery(Collections.singletonList(connection)); + } - @Override - public void handleRecovery(Recoverable recoverable) { - latch.countDown(); - } + public static CountDownLatch prepareForRecovery(Connection connection) { + return prepareForRecovery(Collections.singletonList(connection)); + } - @Override - public void handleRecoveryStarted(Recoverable recoverable) { - // No-op - } - }); + public static CountDownLatch prepareForRecovery(Collection connections) { + final CountDownLatch latch = new CountDownLatch(connections.size()); + for (Connection conn : connections) { + ((AutorecoveringConnection) conn).addRecoveryListener(new RecoveryListener() { + + @Override + public void handleRecovery(Recoverable recoverable) { + latch.countDown(); + } + + @Override + public void handleRecoveryStarted(Recoverable recoverable) { + // No-op + } + }); + } return latch; } From dcf1f5cc097f1fc1d653d9cb2d6ec52fc7023cfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 16 Aug 2018 11:30:28 +0200 Subject: [PATCH 0852/2114] Polish References #380 --- .../rabbitmq/client/impl/nio/NioParams.java | 84 ++++++++++++------- 1 file changed, 54 insertions(+), 30 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java b/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java index 6652a7843f..9f9da61795 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java @@ -20,44 +20,67 @@ import com.rabbitmq.client.SslEngineConfigurator; import javax.net.ssl.SSLEngine; -import java.io.IOException; import java.util.concurrent.ExecutorService; import java.util.concurrent.ThreadFactory; /** * Parameters used to configure the NIO mode of a {@link com.rabbitmq.client.ConnectionFactory}. + * * @since 4.0.0 */ public class NioParams { - /** size of the byte buffer used for inbound data */ + /** + * size of the byte buffer used for inbound data + */ private int readByteBufferSize = 32768; - /** size of the byte buffer used for outbound data */ + /** + * size of the byte buffer used for outbound data + */ private int writeByteBufferSize = 32768; - /** the max number of IO threads */ + /** + * the max number of IO threads + */ private int nbIoThreads = 1; - /** the timeout to enqueue outbound frames */ + /** + * the timeout to enqueue outbound frames + */ private int writeEnqueuingTimeoutInMs = 10 * 1000; - /** the capacity of the queue used for outbound frames */ + /** + * the capacity of the queue used for outbound frames + */ private int writeQueueCapacity = 10000; - /** the executor service used for IO threads and connections shutdown */ + /** + * the executor service used for IO threads and connections shutdown + */ private ExecutorService nioExecutor; - /** the thread factory used for IO threads and connections shutdown */ + /** + * the thread factory used for IO threads and connections shutdown + */ private ThreadFactory threadFactory; - /** the hook to configure the socket channel before it's open */ + /** + * the hook to configure the socket channel before it's open + */ private SocketChannelConfigurator socketChannelConfigurator = new DefaultSocketChannelConfigurator(); - /** the hook to configure the SSL engine before the connection is open */ - private SslEngineConfigurator sslEngineConfigurator = sslEngine -> { }; + /** + * the hook to configure the SSL engine before the connection is open + */ + private SslEngineConfigurator sslEngineConfigurator = sslEngine -> { + }; - /** the executor service used for connection shutdown */ + /** + * the executor service used for connection shutdown + * + * @since 5.4.0 + */ private ExecutorService connectionShutdownExecutor; public NioParams() { @@ -82,7 +105,7 @@ public int getReadByteBufferSize() { /** * Sets the size in byte of the read {@link java.nio.ByteBuffer} used in the NIO loop. * Default is 32768. - * + *

* This parameter isn't used when using SSL/TLS, where {@link java.nio.ByteBuffer} * size is set up according to the {@link javax.net.ssl.SSLSession} packet size. * @@ -104,7 +127,7 @@ public int getWriteByteBufferSize() { /** * Sets the size in byte of the write {@link java.nio.ByteBuffer} used in the NIO loop. * Default is 32768. - * + *

* This parameter isn't used when using SSL/TLS, where {@link java.nio.ByteBuffer} * size is set up according to the {@link javax.net.ssl.SSLSession} packet size. * @@ -131,7 +154,7 @@ public int getNbIoThreads() { * 10 connections have been created). * Once a connection is created, it's assigned to a thread/task and * all its IO activity is handled by this thread/task. - * + *

* When idle for a few seconds (i.e. without any connection to perform IO for), * a thread/task stops and is recreated if necessary. * @@ -155,14 +178,14 @@ public int getWriteEnqueuingTimeoutInMs() { * Every requests to the server is divided into frames * that are then queued in a {@link java.util.concurrent.BlockingQueue} before * being sent on the network by a IO thread. - * + *

* If the IO thread cannot cope with the frames dispatch, the * {@link java.util.concurrent.BlockingQueue} gets filled up and blocks * (blocking the calling thread by the same occasion). This timeout is the * time the {@link java.util.concurrent.BlockingQueue} will wait before * rejecting the outbound frame. The calling thread will then received * an exception. - * + *

* The appropriate value depends on the application scenarios: * rate of outbound data (published messages, acknowledgment, etc), network speed... * @@ -182,17 +205,17 @@ public ExecutorService getNioExecutor() { /** * Sets the {@link ExecutorService} to use for NIO threads/tasks. * Default is to use the thread factory. - * + *

* The {@link ExecutorService} should be able to run the * number of requested IO threads, plus a few more, as it's also * used to dispatch the shutdown of connections. - * + *

* Connection shutdown can also be handled by a dedicated {@link ExecutorService}, * see {@link #setConnectionShutdownExecutor(ExecutorService)}. - * + *

* It's developer's responsibility to shut down the executor * when it is no longer needed. - * + *

* The thread factory isn't used if an executor service is set up. * * @param nioExecutor {@link ExecutorService} used for IO threads and connection shutdown @@ -214,7 +237,7 @@ public ThreadFactory getThreadFactory() { * Sets the {@link ThreadFactory} to use for NIO threads/tasks. * Default is to use the {@link com.rabbitmq.client.ConnectionFactory}'s * {@link ThreadFactory}. - * + *

* The {@link ThreadFactory} is used to spawn the IO threads * and dispatch the shutdown of connections. * @@ -248,6 +271,10 @@ public NioParams setWriteQueueCapacity(int writeQueueCapacity) { return this; } + public SocketChannelConfigurator getSocketChannelConfigurator() { + return socketChannelConfigurator; + } + /** * Set the {@link java.nio.channels.SocketChannel} configurator. * This gets a chance to "configure" a socket channel @@ -260,8 +287,8 @@ public void setSocketChannelConfigurator(SocketChannelConfigurator configurator) this.socketChannelConfigurator = configurator; } - public SocketChannelConfigurator getSocketChannelConfigurator() { - return socketChannelConfigurator; + public SslEngineConfigurator getSslEngineConfigurator() { + return sslEngineConfigurator; } /** @@ -277,8 +304,8 @@ public void setSslEngineConfigurator(SslEngineConfigurator configurator) { this.sslEngineConfigurator = configurator; } - public SslEngineConfigurator getSslEngineConfigurator() { - return sslEngineConfigurator; + public ExecutorService getConnectionShutdownExecutor() { + return connectionShutdownExecutor; } /** @@ -303,13 +330,10 @@ public SslEngineConfigurator getSslEngineConfigurator() { * @param connectionShutdownExecutor the executor service to use * @return this {@link NioParams} instance * @see NioParams#setNioExecutor(ExecutorService) + * @since 5.4.0 */ public NioParams setConnectionShutdownExecutor(ExecutorService connectionShutdownExecutor) { this.connectionShutdownExecutor = connectionShutdownExecutor; return this; } - - public ExecutorService getConnectionShutdownExecutor() { - return connectionShutdownExecutor; - } } From 0e38d5f8f1618bf9180674aef4c83b46fb9374fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 16 Aug 2018 11:30:28 +0200 Subject: [PATCH 0853/2114] Polish References #380 (cherry picked from commit dcf1f5cc097f1fc1d653d9cb2d6ec52fc7023cfe) --- .../rabbitmq/client/impl/nio/NioParams.java | 84 ++++++++++++------- 1 file changed, 54 insertions(+), 30 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java b/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java index 6652a7843f..9f9da61795 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java @@ -20,44 +20,67 @@ import com.rabbitmq.client.SslEngineConfigurator; import javax.net.ssl.SSLEngine; -import java.io.IOException; import java.util.concurrent.ExecutorService; import java.util.concurrent.ThreadFactory; /** * Parameters used to configure the NIO mode of a {@link com.rabbitmq.client.ConnectionFactory}. + * * @since 4.0.0 */ public class NioParams { - /** size of the byte buffer used for inbound data */ + /** + * size of the byte buffer used for inbound data + */ private int readByteBufferSize = 32768; - /** size of the byte buffer used for outbound data */ + /** + * size of the byte buffer used for outbound data + */ private int writeByteBufferSize = 32768; - /** the max number of IO threads */ + /** + * the max number of IO threads + */ private int nbIoThreads = 1; - /** the timeout to enqueue outbound frames */ + /** + * the timeout to enqueue outbound frames + */ private int writeEnqueuingTimeoutInMs = 10 * 1000; - /** the capacity of the queue used for outbound frames */ + /** + * the capacity of the queue used for outbound frames + */ private int writeQueueCapacity = 10000; - /** the executor service used for IO threads and connections shutdown */ + /** + * the executor service used for IO threads and connections shutdown + */ private ExecutorService nioExecutor; - /** the thread factory used for IO threads and connections shutdown */ + /** + * the thread factory used for IO threads and connections shutdown + */ private ThreadFactory threadFactory; - /** the hook to configure the socket channel before it's open */ + /** + * the hook to configure the socket channel before it's open + */ private SocketChannelConfigurator socketChannelConfigurator = new DefaultSocketChannelConfigurator(); - /** the hook to configure the SSL engine before the connection is open */ - private SslEngineConfigurator sslEngineConfigurator = sslEngine -> { }; + /** + * the hook to configure the SSL engine before the connection is open + */ + private SslEngineConfigurator sslEngineConfigurator = sslEngine -> { + }; - /** the executor service used for connection shutdown */ + /** + * the executor service used for connection shutdown + * + * @since 5.4.0 + */ private ExecutorService connectionShutdownExecutor; public NioParams() { @@ -82,7 +105,7 @@ public int getReadByteBufferSize() { /** * Sets the size in byte of the read {@link java.nio.ByteBuffer} used in the NIO loop. * Default is 32768. - * + *

* This parameter isn't used when using SSL/TLS, where {@link java.nio.ByteBuffer} * size is set up according to the {@link javax.net.ssl.SSLSession} packet size. * @@ -104,7 +127,7 @@ public int getWriteByteBufferSize() { /** * Sets the size in byte of the write {@link java.nio.ByteBuffer} used in the NIO loop. * Default is 32768. - * + *

* This parameter isn't used when using SSL/TLS, where {@link java.nio.ByteBuffer} * size is set up according to the {@link javax.net.ssl.SSLSession} packet size. * @@ -131,7 +154,7 @@ public int getNbIoThreads() { * 10 connections have been created). * Once a connection is created, it's assigned to a thread/task and * all its IO activity is handled by this thread/task. - * + *

* When idle for a few seconds (i.e. without any connection to perform IO for), * a thread/task stops and is recreated if necessary. * @@ -155,14 +178,14 @@ public int getWriteEnqueuingTimeoutInMs() { * Every requests to the server is divided into frames * that are then queued in a {@link java.util.concurrent.BlockingQueue} before * being sent on the network by a IO thread. - * + *

* If the IO thread cannot cope with the frames dispatch, the * {@link java.util.concurrent.BlockingQueue} gets filled up and blocks * (blocking the calling thread by the same occasion). This timeout is the * time the {@link java.util.concurrent.BlockingQueue} will wait before * rejecting the outbound frame. The calling thread will then received * an exception. - * + *

* The appropriate value depends on the application scenarios: * rate of outbound data (published messages, acknowledgment, etc), network speed... * @@ -182,17 +205,17 @@ public ExecutorService getNioExecutor() { /** * Sets the {@link ExecutorService} to use for NIO threads/tasks. * Default is to use the thread factory. - * + *

* The {@link ExecutorService} should be able to run the * number of requested IO threads, plus a few more, as it's also * used to dispatch the shutdown of connections. - * + *

* Connection shutdown can also be handled by a dedicated {@link ExecutorService}, * see {@link #setConnectionShutdownExecutor(ExecutorService)}. - * + *

* It's developer's responsibility to shut down the executor * when it is no longer needed. - * + *

* The thread factory isn't used if an executor service is set up. * * @param nioExecutor {@link ExecutorService} used for IO threads and connection shutdown @@ -214,7 +237,7 @@ public ThreadFactory getThreadFactory() { * Sets the {@link ThreadFactory} to use for NIO threads/tasks. * Default is to use the {@link com.rabbitmq.client.ConnectionFactory}'s * {@link ThreadFactory}. - * + *

* The {@link ThreadFactory} is used to spawn the IO threads * and dispatch the shutdown of connections. * @@ -248,6 +271,10 @@ public NioParams setWriteQueueCapacity(int writeQueueCapacity) { return this; } + public SocketChannelConfigurator getSocketChannelConfigurator() { + return socketChannelConfigurator; + } + /** * Set the {@link java.nio.channels.SocketChannel} configurator. * This gets a chance to "configure" a socket channel @@ -260,8 +287,8 @@ public void setSocketChannelConfigurator(SocketChannelConfigurator configurator) this.socketChannelConfigurator = configurator; } - public SocketChannelConfigurator getSocketChannelConfigurator() { - return socketChannelConfigurator; + public SslEngineConfigurator getSslEngineConfigurator() { + return sslEngineConfigurator; } /** @@ -277,8 +304,8 @@ public void setSslEngineConfigurator(SslEngineConfigurator configurator) { this.sslEngineConfigurator = configurator; } - public SslEngineConfigurator getSslEngineConfigurator() { - return sslEngineConfigurator; + public ExecutorService getConnectionShutdownExecutor() { + return connectionShutdownExecutor; } /** @@ -303,13 +330,10 @@ public SslEngineConfigurator getSslEngineConfigurator() { * @param connectionShutdownExecutor the executor service to use * @return this {@link NioParams} instance * @see NioParams#setNioExecutor(ExecutorService) + * @since 5.4.0 */ public NioParams setConnectionShutdownExecutor(ExecutorService connectionShutdownExecutor) { this.connectionShutdownExecutor = connectionShutdownExecutor; return this; } - - public ExecutorService getConnectionShutdownExecutor() { - return connectionShutdownExecutor; - } } From 95843e79b3759ae0f774fff3f7adc0414805b1d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 16 Aug 2018 11:41:56 +0200 Subject: [PATCH 0854/2114] Remove deprecated method --- .../client/impl/MicrometerMetricsCollector.java | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java index ee17194538..d7b9d566d7 100644 --- a/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java @@ -254,17 +254,6 @@ Object create(MeterRegistry registry, String prefix, Iterable tags) { } }; - /** - * - * @param registry - * @param prefix - * @deprecated will be removed in 6.0.0 - */ - @Deprecated - Object create(MeterRegistry registry, String prefix) { - return this.create(registry, prefix, Collections.emptyList()); - } - abstract Object create(MeterRegistry registry, String prefix, Iterable tags); } From 82c18e910d141984f159a081a7938a77d2689476 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 16 Aug 2018 11:59:21 +0200 Subject: [PATCH 0855/2114] Backport publishing metrics to 5.x Fixes #374 --- .../com/rabbitmq/client/MetricsCollector.java | 16 ++++++++++++---- .../client/impl/AbstractMetricsCollector.java | 6 +++--- .../client/impl/MicrometerMetricsCollector.java | 2 +- .../client/impl/StandardMetricsCollector.java | 2 +- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/MetricsCollector.java b/src/main/java/com/rabbitmq/client/MetricsCollector.java index 101948e6b9..31d4480423 100644 --- a/src/main/java/com/rabbitmq/client/MetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/MetricsCollector.java @@ -36,13 +36,21 @@ public interface MetricsCollector { void basicPublish(Channel channel); - void basicPublishFailure(Channel channel, Throwable cause); + default void basicPublishFailure(Channel channel, Throwable cause) { - void basicPublishAck(Channel channel, long deliveryTag, boolean multiple); + } - void basicPublishNack(Channel channel, long deliveryTag, boolean multiple); + default void basicPublishAck(Channel channel, long deliveryTag, boolean multiple) { - void basicPublishUnrouted(Channel channel); + } + + default void basicPublishNack(Channel channel, long deliveryTag, boolean multiple) { + + } + + default void basicPublishUnrouted(Channel channel) { + + } void consumedMessage(Channel channel, long deliveryTag, boolean autoAck); diff --git a/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java index 99a5b7a138..435a794481 100644 --- a/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java @@ -140,9 +140,9 @@ public void basicPublishNack(Channel channel, long deliveryTag, boolean multiple @Override public void basicPublishUnrouted(Channel channel) { try { - markPublishedMessageNotRouted(); + markPublishedMessageUnrouted(); } catch(Exception e) { - LOGGER.info("Error while computing metrics in markPublishedMessageNotRouted: " + e.getMessage()); + LOGGER.info("Error while computing metrics in markPublishedMessageUnrouted: " + e.getMessage()); } } @@ -407,5 +407,5 @@ private ChannelState(Channel channel) { /** * Marks the event of a published message not being routed. */ - protected abstract void markPublishedMessageNotRouted(); + protected abstract void markPublishedMessageUnrouted(); } diff --git a/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java index ee17194538..17db75e9d9 100644 --- a/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java @@ -148,7 +148,7 @@ protected void markMessagePublishNotAcknowledged() { } @Override - protected void markPublishedMessageNotRouted() { + protected void markPublishedMessageUnrouted() { unroutedPublishedMessages.increment(); } diff --git a/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java index 29240bcc48..ac5896c472 100644 --- a/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java @@ -125,7 +125,7 @@ protected void markMessagePublishNotAcknowledged() { } @Override - protected void markPublishedMessageNotRouted() { + protected void markPublishedMessageUnrouted() { publishUnroutedMessages.mark(); } From 119a95796aa6e73cbb1bf2f1baacacc63e11e185 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 13 Aug 2018 11:28:08 +0200 Subject: [PATCH 0856/2114] Introduce JsonRpcMapper abstract WIP References #378 (cherry picked from commit 0a3bed1ae57c308f806c476f1c89f951a41888ba) --- .../com/rabbitmq/tools/json/JSONUtil.java | 2 - .../tools/jsonrpc/DefaultJsonRpcMapper.java | 72 +++++++++++++++ .../rabbitmq/tools/jsonrpc/JsonRpcClient.java | 25 +++--- .../tools/jsonrpc/JsonRpcException.java | 35 ++++---- .../rabbitmq/tools/jsonrpc/JsonRpcMapper.java | 89 +++++++++++++++++++ .../rabbitmq/tools/jsonrpc/JsonRpcServer.java | 30 ++++--- .../tools/jsonrpc/ServiceDescription.java | 4 +- .../java/com/rabbitmq/client/JsonRpcTest.java | 63 ++++++++++--- 8 files changed, 263 insertions(+), 57 deletions(-) create mode 100644 src/main/java/com/rabbitmq/tools/jsonrpc/DefaultJsonRpcMapper.java create mode 100644 src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java diff --git a/src/main/java/com/rabbitmq/tools/json/JSONUtil.java b/src/main/java/com/rabbitmq/tools/json/JSONUtil.java index 6050482f5e..c40727d6e8 100644 --- a/src/main/java/com/rabbitmq/tools/json/JSONUtil.java +++ b/src/main/java/com/rabbitmq/tools/json/JSONUtil.java @@ -61,7 +61,6 @@ public static Object fill(Object target, Map source, boolean use String name = prop.getName(); Method setter = prop.getWriteMethod(); if (setter != null && !Modifier.isStatic(setter.getModifiers())) { - //System.out.println(target + " " + name + " <- " + source.get(name)); setter.invoke(target, source.get(name)); } } @@ -74,7 +73,6 @@ public static Object fill(Object target, Map source, boolean use if (Modifier.isPublic(fieldMod) && !(Modifier.isFinal(fieldMod) || Modifier.isStatic(fieldMod))) { - //System.out.println(target + " " + field.getName() + " := " + source.get(field.getName())); try { field.set(target, source.get(field.getName())); } catch (IllegalArgumentException iae) { diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/DefaultJsonRpcMapper.java b/src/main/java/com/rabbitmq/tools/jsonrpc/DefaultJsonRpcMapper.java new file mode 100644 index 0000000000..358284d650 --- /dev/null +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/DefaultJsonRpcMapper.java @@ -0,0 +1,72 @@ +package com.rabbitmq.tools.jsonrpc; + +import com.rabbitmq.tools.json.JSONReader; +import com.rabbitmq.tools.json.JSONWriter; + +import java.lang.reflect.Method; +import java.util.List; +import java.util.Map; + +/** + * + */ +public class DefaultJsonRpcMapper implements JsonRpcMapper { + + @Override + public JsonRpcRequest parse(String requestBody, ServiceDescription description) { + Map request = (Map) new JSONReader().read(requestBody); + + return new JsonRpcRequest( + request.get("id"), request.get("version").toString(), request.get("method").toString(), + ((List) request.get("params")).toArray() + ); + } + + @Override + public JsonRpcResponse parse(String responseBody) { + Map map = (Map) (new JSONReader().read(responseBody)); + Map error; + JsonRpcException exception = null; + if (map.containsKey("error")) { + error = (Map) map.get("error"); + exception = new JsonRpcException( + new JSONWriter().write(error), + (String) error.get("name"), + error.get("code") == null ? 0 : (Integer) error.get("code"), + (String) error.get("message"), + error + ); + } + return new JsonRpcResponse(map, map.get("result"), map.get("error"), exception); + } + + @Override + public Object[] parameters(JsonRpcRequest request, Method method) { + Object[] parameters = request.getParameters(); + Object[] convertedParameters = new Object[parameters.length]; + Class[] parameterTypes = method.getParameterTypes(); + for (int i = 0; i < parameters.length; i++) { + convertedParameters[i] = convert(parameters[i], parameterTypes[i]); + } + return convertedParameters; + } + + @Override + public String write(Object input) { + return new JSONWriter().write(input); + } + + protected Object convert(Object input, Class expectedClass) { + return input; +// if (input == null || input.getClass().equals(expectedClass)) { +// return input; +// } +// System.err.println(input.getClass() + " " + expectedClass); +// if (Long.class.equals(expectedClass) && input instanceof Integer) { +// return Long.valueOf(((Integer) input).longValue()); +// } else if (long.class.equals(expectedClass) && input instanceof Integer) { +// return +// } +// return input; + } +} diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java index 31822da6d0..581e304f83 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java @@ -62,6 +62,8 @@ public class JsonRpcClient extends RpcClient implements InvocationHandler { /** Holds the JSON-RPC service description for this client. */ private ServiceDescription serviceDescription; + private final JsonRpcMapper mapper; + /** * Construct a new JsonRpcClient, passing the parameters through * to RpcClient's constructor. The service description record is @@ -72,6 +74,7 @@ public JsonRpcClient(Channel channel, String exchange, String routingKey, int ti throws IOException, JsonRpcException, TimeoutException { super(channel, exchange, routingKey, timeout); + this.mapper = new DefaultJsonRpcMapper(); retrieveServiceDescription(); } @@ -86,18 +89,14 @@ public JsonRpcClient(Channel channel, String exchange, String routingKey) * @return the result contained within the reply, if no exception is found * Throws JsonRpcException if the reply object contained an exception */ - public static Object checkReply(Map reply) + private Object checkReply(JsonRpcMapper.JsonRpcResponse reply) throws JsonRpcException { - if (reply.containsKey("error")) { - @SuppressWarnings("unchecked") - Map map = (Map) reply.get("error"); - // actually a Map - throw new JsonRpcException(map); - } + if (reply.getError() != null) { + throw reply.getException(); + } - Object result = reply.get("result"); - return result; + return reply.getResult(); } /** @@ -114,16 +113,16 @@ public Object call(String method, Object[] params) throws IOException, JsonRpcEx request.put("method", method); request.put("version", ServiceDescription.JSON_RPC_VERSION); request.put("params", (params == null) ? new Object[0] : params); - String requestStr = new JSONWriter().write(request); + String requestStr = mapper.write(request); try { String replyStr = this.stringCall(requestStr); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Reply string: {}", replyStr); } - @SuppressWarnings("unchecked") - Map map = (Map) (new JSONReader().read(replyStr)); - return checkReply(map); + JsonRpcMapper.JsonRpcResponse reply = mapper.parse(replyStr); + + return checkReply(reply); } catch(ShutdownSignalException ex) { throw new IOException(ex.getMessage()); // wrap, re-throw } diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java index cbefc4fb21..fafb9457d0 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java @@ -13,40 +13,43 @@ // If you have any questions regarding licensing, please contact us at // info@rabbitmq.com. - package com.rabbitmq.tools.jsonrpc; -import java.util.Map; - -import com.rabbitmq.tools.json.JSONWriter; - /** * Thrown when a JSON-RPC service indicates an error occurred during a call. */ public class JsonRpcException extends Exception { + /** * Default serialized version ID */ private static final long serialVersionUID = 1L; - /** Usually the constant string, "JSONRPCError" */ + /** + * Usually the constant string, "JSONRPCError" + */ public String name; - /** Error code */ + /** + * Error code + */ public int code; - /** Error message */ + /** + * Error message + */ public String message; - /** Error detail object - may not always be present or meaningful */ + /** + * Error detail object - may not always be present or meaningful + */ public Object error; public JsonRpcException() { // no work needed in default no-arg constructor } - public JsonRpcException(Map errorMap) { - super(new JSONWriter().write(errorMap)); - name = (String) errorMap.get("name"); - code = 0; - if (errorMap.get("code") != null) { code = ((Integer) errorMap.get("code")); } - message = (String) errorMap.get("message"); - error = errorMap.get("error"); + public JsonRpcException(String detailMessage, String name, int code, String message, Object error) { + super(detailMessage); + this.name = name; + this.code = code; + this.message = message; + this.error = error; } } diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java new file mode 100644 index 0000000000..d1e32b0492 --- /dev/null +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java @@ -0,0 +1,89 @@ +package com.rabbitmq.tools.jsonrpc; + +import java.lang.reflect.Method; + +/** + * + */ +public interface JsonRpcMapper { + + JsonRpcRequest parse(String requestBody, ServiceDescription description); + + JsonRpcResponse parse(String responseBody); + + Object[] parameters(JsonRpcRequest request, Method method); + + String write(Object input); + + class JsonRpcRequest { + + private final Object id; + private final String version; + private final String method; + private final Object[] parameters; + + public JsonRpcRequest(Object id, String version, String method, Object[] parameters) { + this.id = id; + this.version = version; + this.method = method; + this.parameters = parameters; + } + + public Object getId() { + return id; + } + + public String getVersion() { + return version; + } + + public String getMethod() { + return method; + } + + public Object[] getParameters() { + return parameters; + } + + public boolean isSystem() { + return method.startsWith("system."); + } + + public boolean isSystemDescribe() { + return "system.describe".equals(method); + } + + } + + class JsonRpcResponse { + + private final Object reply; + private final Object result; + private final Object error; + private final JsonRpcException exception; + + public JsonRpcResponse(Object reply, Object result, Object error, JsonRpcException exception) { + this.reply = reply; + this.result = result; + this.error = error; + this.exception = exception; + } + + public Object getReply() { + return reply; + } + + public Object getError() { + return error; + } + + public Object getResult() { + return result; + } + + public JsonRpcException getException() { + return exception; + } + } + +} diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java index 138f654b12..068fae1546 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java @@ -55,6 +55,8 @@ public class JsonRpcServer extends StringRpcServer { /** The instance backing this server. */ public Object interfaceInstance; + private final JsonRpcMapper mapper; + /** * Construct a server that talks to the outside world using the * given channel, and constructs a fresh temporary @@ -70,6 +72,7 @@ public JsonRpcServer(Channel channel, throws IOException { super(channel); + this.mapper = new DefaultJsonRpcMapper(); init(interfaceClass, interfaceInstance); } @@ -98,6 +101,7 @@ public JsonRpcServer(Channel channel, throws IOException { super(channel, queueName); + this.mapper = new DefaultJsonRpcMapper(); init(interfaceClass, interfaceInstance); } @@ -126,25 +130,24 @@ public String doCall(String requestBody) LOGGER.debug("Request: {}", requestBody); } try { - @SuppressWarnings("unchecked") - Map request = (Map) new JSONReader().read(requestBody); + JsonRpcMapper.JsonRpcRequest request = mapper.parse(requestBody, serviceDescription); if (request == null) { response = errorResponse(null, 400, "Bad Request", null); - } else if (!ServiceDescription.JSON_RPC_VERSION.equals(request.get("version"))) { + } else if (!ServiceDescription.JSON_RPC_VERSION.equals(request.getVersion())) { response = errorResponse(null, 505, "JSONRPC version not supported", null); } else { - id = request.get("id"); - method = (String) request.get("method"); - List parmList = (List) request.get("params"); - params = parmList.toArray(); - if (method.equals("system.describe")) { + id = request.getId(); + method = request.getMethod(); + params = request.getParameters(); + if (request.isSystemDescribe()) { response = resultResponse(id, serviceDescription); - } else if (method.startsWith("system.")) { + } else if (request.isSystem()) { response = errorResponse(id, 403, "System methods forbidden", null); } else { Object result; try { Method matchingMethod = matchingMethod(method, params); + params = mapper.parameters(request, matchingMethod); if (LOGGER.isDebugEnabled()) { Collection parametersValuesAndTypes = new ArrayList(); if (params != null) { @@ -197,7 +200,7 @@ public Method matchingMethod(String methodName, Object[] params) * ID given, using the code, message, and possible * (JSON-encodable) argument passed in. */ - public static String errorResponse(Object id, int code, String message, Object errorArg) { + private String errorResponse(Object id, int code, String message, Object errorArg) { Map err = new HashMap(); err.put("name", "JSONRPCError"); err.put("code", code); @@ -210,22 +213,21 @@ public static String errorResponse(Object id, int code, String message, Object e * Construct and encode a JSON-RPC success response for the * request ID given, using the result value passed in. */ - public static String resultResponse(Object id, Object result) { + private String resultResponse(Object id, Object result) { return response(id, "result", result); } /** * Private API - used by errorResponse and resultResponse. */ - public static String response(Object id, String label, Object value) { + private String response(Object id, String label, Object value) { Map resp = new HashMap(); resp.put("version", ServiceDescription.JSON_RPC_VERSION); if (id != null) { resp.put("id", id); } resp.put(label, value); - String respStr = new JSONWriter().write(resp); - //System.err.println(respStr); + String respStr = mapper.write(resp); return respStr; } diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java b/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java index 79d750278b..4cb6d3bf66 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java @@ -48,7 +48,7 @@ public ServiceDescription(Map rawServiceDescription) { } public ServiceDescription(Class klass) { - this.procedures = new HashMap(); + this.procedures = new HashMap<>(); for (Method m: klass.getMethods()) { ProcedureDescription proc = new ProcedureDescription(m); addProcedure(proc); @@ -66,7 +66,7 @@ public Collection getProcs() { /** Private API - used via reflection during parsing/loading */ public void setProcs(Collection> p) { - procedures = new HashMap(); + procedures = new HashMap<>(); for (Map pm: p) { ProcedureDescription proc = new ProcedureDescription(pm); addProcedure(proc); diff --git a/src/test/java/com/rabbitmq/client/JsonRpcTest.java b/src/test/java/com/rabbitmq/client/JsonRpcTest.java index b6f73c824e..f13b5b4036 100644 --- a/src/test/java/com/rabbitmq/client/JsonRpcTest.java +++ b/src/test/java/com/rabbitmq/client/JsonRpcTest.java @@ -44,15 +44,11 @@ public void init() throws Exception { serverChannel = serverConnection.createChannel(); serverChannel.queueDeclare(queue, false, false, false, null); server = new JsonRpcServer(serverChannel, queue, RpcService.class, new DefaultRpcservice()); - new Thread(new Runnable() { - - @Override - public void run() { - try { - server.mainloop(); - } catch (Exception e) { - // safe to ignore when loops ends/server is canceled - } + new Thread(() -> { + try { + server.mainloop(); + } catch (Exception e) { + // safe to ignore when loops ends/server is canceled } }).start(); client = new JsonRpcClient(clientChannel, "", queue, 1000); @@ -103,6 +99,23 @@ public void rpc() { } catch (UndeclaredThrowableException e) { // OK } + + try { + assertEquals("123", service.procedureIntegerToPojo(123).getStringProperty()); + fail("Complex return type not supported"); + } catch (ClassCastException e) { + // OK + } + + try { + Pojo pojo = new Pojo(); + pojo.setStringProperty("hello"); + assertEquals("hello", service.procedurePojoToString(pojo)); + fail("Complex type argument not supported"); + } catch (UndeclaredThrowableException e) { + // OK + } + } public interface RpcService { @@ -124,9 +137,14 @@ public interface RpcService { Long procedureLong(Long input); long procedurePrimitiveLong(long input); + + Pojo procedureIntegerToPojo(Integer id); + + String procedurePojoToString(Pojo pojo); + } - public class DefaultRpcservice implements RpcService { + public static class DefaultRpcservice implements RpcService { @Override public String procedureString(String input) { @@ -172,5 +190,30 @@ public Integer procedureLongToInteger(Long input) { public int procedurePrimitiveLongToInteger(long input) { return (int) input + 1; } + + @Override + public Pojo procedureIntegerToPojo(Integer id) { + Pojo pojo = new Pojo(); + pojo.setStringProperty(id.toString()); + return pojo; + } + + @Override + public String procedurePojoToString(Pojo pojo) { + return pojo.getStringProperty(); + } + } + + public static class Pojo { + + private String stringProperty; + + public String getStringProperty() { + return stringProperty; + } + + public void setStringProperty(String stringProperty) { + this.stringProperty = stringProperty; + } } } From 31a144e2a569d122a51066e33e21fcb787241076 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 13 Aug 2018 18:10:02 +0200 Subject: [PATCH 0857/2114] Adding Jackson support in JSON RPC WIP References #378 (cherry picked from commit e28b34ad8094b47a7fa46112490d1308bf8418b9) --- pom.xml | 7 + .../tools/jsonrpc/DefaultJsonRpcMapper.java | 29 ++- .../tools/jsonrpc/JacksonJsonRpcMapper.java | 178 ++++++++++++++ .../rabbitmq/tools/jsonrpc/JsonRpcClient.java | 221 +++++++++--------- .../rabbitmq/tools/jsonrpc/JsonRpcMapper.java | 23 +- .../jsonrpc/JsonRpcMappingException.java | 26 +++ .../rabbitmq/tools/jsonrpc/JsonRpcServer.java | 30 ++- .../tools/jsonrpc/ProcedureDescription.java | 44 ++++ .../rabbitmq/client/AbstractJsonRpcTest.java | 202 ++++++++++++++++ .../com/rabbitmq/client/JacksonRpcTest.java | 64 +++++ .../java/com/rabbitmq/client/JsonRpcTest.java | 167 ++----------- .../com/rabbitmq/client/test/ClientTests.java | 2 + 12 files changed, 724 insertions(+), 269 deletions(-) create mode 100644 src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java create mode 100644 src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMappingException.java create mode 100644 src/test/java/com/rabbitmq/client/AbstractJsonRpcTest.java create mode 100644 src/test/java/com/rabbitmq/client/JacksonRpcTest.java diff --git a/pom.xml b/pom.xml index b26766262b..7104624064 100644 --- a/pom.xml +++ b/pom.xml @@ -57,6 +57,7 @@ 1.7.25 3.2.6 1.0.2 + 2.9.6 1.2.3 1.1 4.12 @@ -640,6 +641,12 @@ ${micrometer.version} true + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + true + commons-cli commons-cli diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/DefaultJsonRpcMapper.java b/src/main/java/com/rabbitmq/tools/jsonrpc/DefaultJsonRpcMapper.java index 358284d650..c522d24767 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/DefaultJsonRpcMapper.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/DefaultJsonRpcMapper.java @@ -1,3 +1,18 @@ +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.tools.jsonrpc; import com.rabbitmq.tools.json.JSONReader; @@ -23,7 +38,7 @@ public JsonRpcRequest parse(String requestBody, ServiceDescription description) } @Override - public JsonRpcResponse parse(String responseBody) { + public JsonRpcResponse parse(String responseBody, Class expectedType) { Map map = (Map) (new JSONReader().read(responseBody)); Map error; JsonRpcException exception = null; @@ -40,6 +55,12 @@ public JsonRpcResponse parse(String responseBody) { return new JsonRpcResponse(map, map.get("result"), map.get("error"), exception); } + @Override + public String write(Object input) { + return new JSONWriter().write(input); + } + + /* @Override public Object[] parameters(JsonRpcRequest request, Method method) { Object[] parameters = request.getParameters(); @@ -51,10 +72,7 @@ public Object[] parameters(JsonRpcRequest request, Method method) { return convertedParameters; } - @Override - public String write(Object input) { - return new JSONWriter().write(input); - } + protected Object convert(Object input, Class expectedClass) { return input; @@ -69,4 +87,5 @@ protected Object convert(Object input, Class expectedClass) { // } // return input; } + */ } diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java new file mode 100644 index 0000000000..0a19f53921 --- /dev/null +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java @@ -0,0 +1,178 @@ +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.tools.jsonrpc; + +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.core.TreeNode; +import com.fasterxml.jackson.databind.MappingJsonFactory; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ValueNode; +import com.rabbitmq.tools.json.JSONReader; +import com.rabbitmq.tools.json.JSONWriter; + +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * + */ +public class JacksonJsonRpcMapper implements JsonRpcMapper { + + private final ObjectMapper mapper; + + public JacksonJsonRpcMapper(ObjectMapper mapper) { + this.mapper = mapper; + } + + public JacksonJsonRpcMapper() { + this(new ObjectMapper()); + } + + @Override + public JsonRpcRequest parse(String requestBody, ServiceDescription description) { + JsonFactory jsonFactory = new MappingJsonFactory(); + String method = null, version = null; + final List parameters = new ArrayList<>(); + Object id = null; + try (JsonParser parser = jsonFactory.createParser(requestBody)) { + while (parser.nextToken() != null) { + JsonToken token = parser.currentToken(); + if (token == JsonToken.FIELD_NAME) { + String name = parser.currentName(); + token = parser.nextToken(); + if ("method".equals(name)) { + method = parser.getValueAsString(); + } else if ("id".equals(name)) { + // FIXME parse id, can be any type (handle only primitive and wrapper) + } else if ("version".equals(name)) { + version = parser.getValueAsString(); + } else if ("params".equals(name)) { + if (token == JsonToken.START_ARRAY) { + while (parser.nextToken() != JsonToken.END_ARRAY) { + parameters.add(parser.readValueAsTree()); + } + } else { + throw new IllegalStateException("Field params must be an array"); + } + } + } + } + } catch (IOException e) { + throw new JsonRpcMappingException("Error during JSON parsing", e); + } + + List convertedParameters = new ArrayList<>(parameters.size()); + if (!parameters.isEmpty()) { + ProcedureDescription proc = description.getProcedure(method, parameters.size()); + Method internalMethod = proc.internal_getMethod(); + for (int i = 0; i < internalMethod.getParameterCount(); i++) { + TreeNode parameterNode = parameters.get(i); + try { + Class parameterType = internalMethod.getParameterTypes()[i]; + Object value = convert(parameterNode, parameterType); + convertedParameters.add(value); + } catch (IOException e) { + throw new JsonRpcMappingException("Error during parameter conversion", e); + } + } + } + + return new JsonRpcRequest( + id, version, method, + convertedParameters.toArray() + ); + } + + protected Object convert(TreeNode node, Class expectedType) throws IOException { + Object value; + if (expectedType.isPrimitive()) { + ValueNode valueNode = (ValueNode) node; + if (expectedType == Boolean.TYPE) { + value = valueNode.booleanValue(); + } else if (expectedType == Character.TYPE) { + value = valueNode.textValue().charAt(0); + } else if (expectedType == Short.TYPE) { + value = valueNode.shortValue(); + } else if (expectedType == Integer.TYPE) { + value = valueNode.intValue(); + } else if (expectedType == Long.TYPE) { + value = valueNode.longValue(); + } else if (expectedType == Float.TYPE) { + value = valueNode.floatValue(); + } else if (expectedType == Double.TYPE) { + value = valueNode.doubleValue(); + } else { + throw new IllegalArgumentException("Primitive type not supported: " + expectedType); + } + } else { + value = mapper.readValue(node.traverse(), expectedType); + } + return value; + } + + @Override + public JsonRpcResponse parse(String responseBody, Class expectedReturnType) { + JsonFactory jsonFactory = new MappingJsonFactory(); + Object result = null; + try (JsonParser parser = jsonFactory.createParser(responseBody)) { + while (parser.nextToken() != null) { + JsonToken token = parser.currentToken(); + if (token == JsonToken.FIELD_NAME) { + String name = parser.currentName(); + parser.nextToken(); + if ("result".equals(name)) { + if (expectedReturnType == Void.TYPE) { + result = null; + } else { + result = convert(parser.readValueAsTree(), expectedReturnType); + } + } + } + } + } catch (IOException e) { + throw new JsonRpcMappingException("Error during JSON parsing", e); + } + Map map = (Map) (new JSONReader().read(responseBody)); + Map error; + JsonRpcException exception = null; + if (map.containsKey("error")) { + error = (Map) map.get("error"); + exception = new JsonRpcException( + new JSONWriter().write(error), + (String) error.get("name"), + error.get("code") == null ? 0 : (Integer) error.get("code"), + (String) error.get("message"), + error + ); + } + return new JsonRpcResponse(map, result, map.get("error"), exception); + } + + @Override + public String write(Object input) { + try { + return mapper.writeValueAsString(input); + } catch (JsonProcessingException e) { + throw new JsonRpcMappingException("Error during JSON serialization", e); + } + } +} diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java index 581e304f83..12032941f3 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java @@ -15,6 +15,13 @@ package com.rabbitmq.tools.jsonrpc; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.RpcClient; +import com.rabbitmq.client.ShutdownSignalException; +import com.rabbitmq.tools.json.JSONReader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.IOException; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; @@ -23,78 +30,106 @@ import java.util.Map; import java.util.concurrent.TimeoutException; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.RpcClient; -import com.rabbitmq.client.ShutdownSignalException; -import com.rabbitmq.tools.json.JSONReader; -import com.rabbitmq.tools.json.JSONWriter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - /** - JSON-RPC is a lightweight - RPC mechanism using JSON - as a data language for request and reply messages. It is - rapidly becoming a standard in web development, where it is - used to make RPC requests over HTTP. RabbitMQ provides an - AMQP transport binding for JSON-RPC in the form of the - JsonRpcClient class. - - JSON-RPC services are self-describing - each service is able - to list its supported procedures, and each procedure - describes its parameters and types. An instance of - JsonRpcClient retrieves its service description using the - standard system.describe procedure when it is - constructed, and uses the information to coerce parameter - types appropriately. A JSON service description is parsed - into instances of ServiceDescription. Client - code can access the service description by reading the - serviceDescription field of - JsonRpcClient instances. - - @see #call(String, Object[]) - @see #call(String[]) + * JSON-RPC is a lightweight + * RPC mechanism using JSON + * as a data language for request and reply messages. It is + * rapidly becoming a standard in web development, where it is + * used to make RPC requests over HTTP. RabbitMQ provides an + * AMQP transport binding for JSON-RPC in the form of the + * JsonRpcClient class. + *

+ * JSON-RPC services are self-describing - each service is able + * to list its supported procedures, and each procedure + * describes its parameters and types. An instance of + * JsonRpcClient retrieves its service description using the + * standard system.describe procedure when it is + * constructed, and uses the information to coerce parameter + * types appropriately. A JSON service description is parsed + * into instances of ServiceDescription. Client + * code can access the service description by reading the + * serviceDescription field of + * JsonRpcClient instances. + * + * @see #call(String, Object[]) + * @see #call(String[]) */ public class JsonRpcClient extends RpcClient implements InvocationHandler { private static final Logger LOGGER = LoggerFactory.getLogger(JsonRpcClient.class); - - /** Holds the JSON-RPC service description for this client. */ + private final JsonRpcMapper mapper; + /** + * Holds the JSON-RPC service description for this client. + */ private ServiceDescription serviceDescription; - private final JsonRpcMapper mapper; + /** + * Construct a new JsonRpcClient, passing the parameters through + * to RpcClient's constructor. The service description record is + * retrieved from the server during construction. + * + * @throws TimeoutException if a response is not received within the timeout specified, if any + */ + public JsonRpcClient(Channel channel, String exchange, String routingKey, int timeout, JsonRpcMapper mapper) + throws IOException, JsonRpcException, TimeoutException { + super(channel, exchange, routingKey, timeout); + this.mapper = mapper; + retrieveServiceDescription(); + } /** * Construct a new JsonRpcClient, passing the parameters through * to RpcClient's constructor. The service description record is * retrieved from the server during construction. + * * @throws TimeoutException if a response is not received within the timeout specified, if any */ public JsonRpcClient(Channel channel, String exchange, String routingKey, int timeout) - throws IOException, JsonRpcException, TimeoutException - { - super(channel, exchange, routingKey, timeout); - this.mapper = new DefaultJsonRpcMapper(); - retrieveServiceDescription(); + throws IOException, JsonRpcException, TimeoutException { + this(channel, exchange, routingKey, timeout, new DefaultJsonRpcMapper()); } public JsonRpcClient(Channel channel, String exchange, String routingKey) - throws IOException, JsonRpcException, TimeoutException - { + throws IOException, JsonRpcException, TimeoutException { this(channel, exchange, routingKey, RpcClient.NO_TIMEOUT); } + /** + * Private API - used by {@link #call(String[])} to ad-hoc convert + * strings into the required data types for a call. + */ + public static Object coerce(String val, String type) + throws NumberFormatException { + if ("bit".equals(type)) { + return Boolean.getBoolean(val) ? Boolean.TRUE : Boolean.FALSE; + } else if ("num".equals(type)) { + try { + return Integer.valueOf(val); + } catch (NumberFormatException nfe) { + return Double.valueOf(val); + } + } else if ("str".equals(type)) { + return val; + } else if ("arr".equals(type) || "obj".equals(type) || "any".equals(type)) { + return new JSONReader().read(val); + } else if ("nil".equals(type)) { + return null; + } else { + throw new IllegalArgumentException("Bad type: " + type); + } + } + /** * Private API - parses a JSON-RPC reply object, checking it for exceptions. + * * @return the result contained within the reply, if no exception is found * Throws JsonRpcException if the reply object contained an exception */ private Object checkReply(JsonRpcMapper.JsonRpcResponse reply) - throws JsonRpcException - { - if (reply.getError() != null) { - throw reply.getException(); - } + throws JsonRpcException { + if (reply.getError() != null) { + throw reply.getException(); + } return reply.getResult(); } @@ -102,31 +137,37 @@ private Object checkReply(JsonRpcMapper.JsonRpcResponse reply) /** * Public API - builds, encodes and sends a JSON-RPC request, and * waits for the response. + * * @return the result contained within the reply, if no exception is found * @throws JsonRpcException if the reply object contained an exception * @throws TimeoutException if a response is not received within the timeout specified, if any */ - public Object call(String method, Object[] params) throws IOException, JsonRpcException, TimeoutException - { - HashMap request = new HashMap(); + public Object call(String method, Object[] params) throws IOException, JsonRpcException, TimeoutException { + Map request = new HashMap(); request.put("id", null); request.put("method", method); request.put("version", ServiceDescription.JSON_RPC_VERSION); - request.put("params", (params == null) ? new Object[0] : params); + params = (params == null) ? new Object[0] : params; + request.put("params", params); String requestStr = mapper.write(request); try { String replyStr = this.stringCall(requestStr); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Reply string: {}", replyStr); } - - JsonRpcMapper.JsonRpcResponse reply = mapper.parse(replyStr); + Class expectedType; + if ("system.describe".equals(method) && params.length == 0) { + expectedType = Map.class; + } else { + ProcedureDescription proc = serviceDescription.getProcedure(method, params.length); + expectedType = proc.getReturnType(); + } + JsonRpcMapper.JsonRpcResponse reply = mapper.parse(replyStr, expectedType); return checkReply(reply); - } catch(ShutdownSignalException ex) { + } catch (ShutdownSignalException ex) { throw new IOException(ex.getMessage()); // wrap, re-throw } - } /** @@ -136,8 +177,7 @@ public Object call(String method, Object[] params) throws IOException, JsonRpcEx */ @Override public Object invoke(Object proxy, Method method, Object[] args) - throws Throwable - { + throws Throwable { return call(method.getName(), args); } @@ -146,69 +186,42 @@ public Object invoke(Object proxy, Method method, Object[] args) */ @SuppressWarnings("unchecked") public T createProxy(Class klass) - throws IllegalArgumentException - { + throws IllegalArgumentException { return (T) Proxy.newProxyInstance(klass.getClassLoader(), - new Class[] { klass }, - this); - } - - /** - * Private API - used by {@link #call(String[])} to ad-hoc convert - * strings into the required data types for a call. - */ - public static Object coerce(String val, String type) - throws NumberFormatException - { - if ("bit".equals(type)) { - return Boolean.getBoolean(val) ? Boolean.TRUE : Boolean.FALSE; - } else if ("num".equals(type)) { - try { - return Integer.valueOf(val); - } catch (NumberFormatException nfe) { - return Double.valueOf(val); - } - } else if ("str".equals(type)) { - return val; - } else if ("arr".equals(type) || "obj".equals(type) || "any".equals(type)) { - return new JSONReader().read(val); - } else if ("nil".equals(type)) { - return null; - } else { - throw new IllegalArgumentException("Bad type: " + type); - } + new Class[] { klass }, + this); } /** - * Public API - as {@link #call(String,Object[])}, but takes the + * Public API - as {@link #call(String, Object[])}, but takes the * method name from the first entry in args, and the * parameters from subsequent entries. All parameter values are * passed through coerce() to attempt to make them the types the * server is expecting. + * * @return the result contained within the reply, if no exception is found - * @throws JsonRpcException if the reply object contained an exception + * @throws JsonRpcException if the reply object contained an exception * @throws NumberFormatException if a coercion failed - * @throws TimeoutException if a response is not received within the timeout specified, if any + * @throws TimeoutException if a response is not received within the timeout specified, if any * @see #coerce */ public Object call(String[] args) - throws NumberFormatException, IOException, JsonRpcException, TimeoutException - { - if (args.length == 0) { - throw new IllegalArgumentException("First string argument must be method name"); - } + throws NumberFormatException, IOException, JsonRpcException, TimeoutException { + if (args.length == 0) { + throw new IllegalArgumentException("First string argument must be method name"); + } - String method = args[0]; + String method = args[0]; int arity = args.length - 1; - ProcedureDescription proc = serviceDescription.getProcedure(method, arity); - ParameterDescription[] params = proc.getParams(); + ProcedureDescription proc = serviceDescription.getProcedure(method, arity); + ParameterDescription[] params = proc.getParams(); - Object[] actuals = new Object[arity]; - for (int count = 0; count < params.length; count++) { - actuals[count] = coerce(args[count + 1], params[count].type); - } + Object[] actuals = new Object[arity]; + for (int count = 0; count < params.length; count++) { + actuals[count] = coerce(args[count + 1], params[count].type); + } - return call(method, actuals); + return call(method, actuals); } /** @@ -216,7 +229,7 @@ public Object call(String[] args) * service loaded from the server itself at construction time. */ public ServiceDescription getServiceDescription() { - return serviceDescription; + return serviceDescription; } /** @@ -224,10 +237,10 @@ public ServiceDescription getServiceDescription() { * server, and parses and stores the resulting service description * in this object. * TODO: Avoid calling this from the constructor. + * * @throws TimeoutException if a response is not received within the timeout specified, if any */ - private void retrieveServiceDescription() throws IOException, JsonRpcException, TimeoutException - { + private void retrieveServiceDescription() throws IOException, JsonRpcException, TimeoutException { @SuppressWarnings("unchecked") Map rawServiceDescription = (Map) call("system.describe", null); serviceDescription = new ServiceDescription(rawServiceDescription); diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java index d1e32b0492..36f1ad72b2 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java @@ -1,6 +1,19 @@ -package com.rabbitmq.tools.jsonrpc; +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. -import java.lang.reflect.Method; +package com.rabbitmq.tools.jsonrpc; /** * @@ -9,9 +22,7 @@ public interface JsonRpcMapper { JsonRpcRequest parse(String requestBody, ServiceDescription description); - JsonRpcResponse parse(String responseBody); - - Object[] parameters(JsonRpcRequest request, Method method); + JsonRpcResponse parse(String responseBody, Class expectedType); String write(Object input); @@ -52,7 +63,6 @@ public boolean isSystem() { public boolean isSystemDescribe() { return "system.describe".equals(method); } - } class JsonRpcResponse { @@ -85,5 +95,4 @@ public JsonRpcException getException() { return exception; } } - } diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMappingException.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMappingException.java new file mode 100644 index 0000000000..633a1d79d7 --- /dev/null +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMappingException.java @@ -0,0 +1,26 @@ +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.tools.jsonrpc; + +/** + * + */ +public class JsonRpcMappingException extends RuntimeException { + + public JsonRpcMappingException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java index 068fae1546..922fe35b1c 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java @@ -57,6 +57,16 @@ public class JsonRpcServer extends StringRpcServer { private final JsonRpcMapper mapper; + public JsonRpcServer(Channel channel, + Class interfaceClass, + Object interfaceInstance, JsonRpcMapper mapper) + throws IOException + { + super(channel); + this.mapper = mapper; + init(interfaceClass, interfaceInstance); + } + /** * Construct a server that talks to the outside world using the * given channel, and constructs a fresh temporary @@ -71,9 +81,7 @@ public JsonRpcServer(Channel channel, Object interfaceInstance) throws IOException { - super(channel); - this.mapper = new DefaultJsonRpcMapper(); - init(interfaceClass, interfaceInstance); + this(channel, interfaceClass, interfaceInstance, new DefaultJsonRpcMapper()); } private void init(Class interfaceClass, Object interfaceInstance) @@ -83,6 +91,17 @@ private void init(Class interfaceClass, Object interfaceInstance) this.serviceDescription = new ServiceDescription(interfaceClass); } + public JsonRpcServer(Channel channel, + String queueName, + Class interfaceClass, + Object interfaceInstance, JsonRpcMapper mapper) + throws IOException + { + super(channel, queueName); + this.mapper = mapper; + init(interfaceClass, interfaceInstance); + } + /** * Construct a server that talks to the outside world using the * given channel and queue name. Our superclass, @@ -100,9 +119,7 @@ public JsonRpcServer(Channel channel, Object interfaceInstance) throws IOException { - super(channel, queueName); - this.mapper = new DefaultJsonRpcMapper(); - init(interfaceClass, interfaceInstance); + this(channel, queueName, interfaceClass, interfaceInstance, new DefaultJsonRpcMapper()); } /** @@ -147,7 +164,6 @@ public String doCall(String requestBody) Object result; try { Method matchingMethod = matchingMethod(method, params); - params = mapper.parameters(request, matchingMethod); if (LOGGER.isDebugEnabled()) { Collection parametersValuesAndTypes = new ArrayList(); if (params != null) { diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java b/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java index 57dcc39b05..714db1da96 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java @@ -39,6 +39,8 @@ public class ProcedureDescription { private ParameterDescription[] params; /** Return type for this procedure */ private String returnType; + private String javaReturnType; + private Class _javaReturnTypeAsClass; /** Reflected method object, used for service invocation */ private Method method; @@ -68,6 +70,7 @@ public ProcedureDescription(Method m) { params[i] = new ParameterDescription(i, parameterTypes[i]); } this.returnType = ParameterDescription.lookup(m.getReturnType()); + this.javaReturnType = m.getReturnType().getName(); } public ProcedureDescription() { @@ -82,6 +85,47 @@ public ProcedureDescription() { /** Private API - used to get the reflected method object, for servers */ public Method internal_getMethod() { return method; } + public String getJavaReturnType() { + return javaReturnType; + } + + public void setJavaReturnType(String javaReturnType) { + this.javaReturnType = javaReturnType; + this._javaReturnTypeAsClass = computeReturnTypeAsJavaClass(); + } + + public Class getReturnType() { + return _javaReturnTypeAsClass; + } + + private Class computeReturnTypeAsJavaClass() { + try { + if ("int".equals(javaReturnType)) { + return Integer.TYPE; + } else if ("double".equals(javaReturnType)) { + return Double.TYPE; + } else if ("long".equals(javaReturnType)) { + return Long.TYPE; + } else if ("boolean".equals(javaReturnType)) { + return Boolean.TYPE; + } else if ("char".equals(javaReturnType)) { + return Character.TYPE; + } else if ("byte".equals(javaReturnType)) { + return Byte.TYPE; + } else if ("short".equals(javaReturnType)) { + return Short.TYPE; + } else if ("float".equals(javaReturnType)) { + return Float.TYPE; + } else if ("void".equals(javaReturnType)) { + return Void.TYPE; + } else { + return Class.forName(javaReturnType); + } + } catch (ClassNotFoundException e) { + throw new IllegalStateException("Unable to load class: " + javaReturnType, e); + } + } + /** Gets an array of parameter descriptions for all this procedure's parameters */ public ParameterDescription[] internal_getParams() { return params; diff --git a/src/test/java/com/rabbitmq/client/AbstractJsonRpcTest.java b/src/test/java/com/rabbitmq/client/AbstractJsonRpcTest.java new file mode 100644 index 0000000000..555d4c0b24 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/AbstractJsonRpcTest.java @@ -0,0 +1,202 @@ +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client; + +import com.rabbitmq.client.test.TestUtils; +import com.rabbitmq.tools.jsonrpc.JsonRpcClient; +import com.rabbitmq.tools.jsonrpc.JsonRpcMapper; +import com.rabbitmq.tools.jsonrpc.JsonRpcServer; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.lang.reflect.UndeclaredThrowableException; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +public abstract class AbstractJsonRpcTest { + + Connection clientConnection, serverConnection; + Channel clientChannel, serverChannel; + String queue = "json.rpc.queue"; + JsonRpcServer server; + JsonRpcClient client; + RpcService service; + + abstract JsonRpcMapper createMapper(); + + @Before + public void init() throws Exception { + clientConnection = TestUtils.connectionFactory().newConnection(); + clientChannel = clientConnection.createChannel(); + serverConnection = TestUtils.connectionFactory().newConnection(); + serverChannel = serverConnection.createChannel(); + serverChannel.queueDeclare(queue, false, false, false, null); + server = new JsonRpcServer(serverChannel, queue, RpcService.class, new DefaultRpcservice(), createMapper()); + new Thread(() -> { + try { + server.mainloop(); + } catch (Exception e) { + // safe to ignore when loops ends/server is canceled + } + }).start(); + client = new JsonRpcClient(clientChannel, "", queue, 1000, createMapper()); + service = client.createProxy(RpcService.class); + } + + @After + public void tearDown() throws Exception { + if (server != null) { + server.terminateMainloop(); + } + if (client != null) { + client.close(); + } + if (serverChannel != null) { + serverChannel.queueDelete(queue); + } + clientConnection.close(); + serverConnection.close(); + } + + public interface RpcService { + + boolean procedurePrimitiveBoolean(boolean input); + + Boolean procedureBoolean(Boolean input); + + String procedureString(String input); + + String procedureStringString(String input1, String input2); + + int procedurePrimitiveInteger(int input); + + Integer procedureInteger(Integer input); + + Double procedureDouble(Double input); + + double procedurePrimitiveDouble(double input); + + Integer procedureLongToInteger(Long input); + + int procedurePrimitiveLongToInteger(long input); + + Long procedureLong(Long input); + + long procedurePrimitiveLong(long input); + + Pojo procedureIntegerToPojo(Integer id); + + String procedurePojoToString(Pojo pojo); + + void procedureException(); + + } + + public static class DefaultRpcservice implements RpcService { + + @Override + public boolean procedurePrimitiveBoolean(boolean input) { + return !input; + } + + @Override + public Boolean procedureBoolean(Boolean input) { + return Boolean.valueOf(!input.booleanValue()); + } + + @Override + public String procedureString(String input) { + return input + 1; + } + + @Override + public String procedureStringString(String input1, String input2) { + return input1 + input2; + } + + @Override + public int procedurePrimitiveInteger(int input) { + return input + 1; + } + + @Override + public Integer procedureInteger(Integer input) { + return input + 1; + } + + @Override + public Long procedureLong(Long input) { + return input + 1; + } + + @Override + public long procedurePrimitiveLong(long input) { + return input + 1L; + } + + @Override + public Double procedureDouble(Double input) { + return input + 1; + } + + @Override + public double procedurePrimitiveDouble(double input) { + return input + 1; + } + + @Override + public Integer procedureLongToInteger(Long input) { + return (int) (input + 1); + } + + @Override + public int procedurePrimitiveLongToInteger(long input) { + return (int) input + 1; + } + + @Override + public Pojo procedureIntegerToPojo(Integer id) { + Pojo pojo = new Pojo(); + pojo.setStringProperty(id.toString()); + return pojo; + } + + @Override + public String procedurePojoToString(Pojo pojo) { + return pojo.getStringProperty(); + } + + @Override + public void procedureException() { + throw new RuntimeException(); + } + } + + public static class Pojo { + + private String stringProperty; + + public String getStringProperty() { + return stringProperty; + } + + public void setStringProperty(String stringProperty) { + this.stringProperty = stringProperty; + } + } +} diff --git a/src/test/java/com/rabbitmq/client/JacksonRpcTest.java b/src/test/java/com/rabbitmq/client/JacksonRpcTest.java new file mode 100644 index 0000000000..ba95efef98 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/JacksonRpcTest.java @@ -0,0 +1,64 @@ +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client; + +import com.rabbitmq.tools.jsonrpc.JacksonJsonRpcMapper; +import com.rabbitmq.tools.jsonrpc.JsonRpcException; +import com.rabbitmq.tools.jsonrpc.JsonRpcMapper; +import org.junit.Test; + +import java.lang.reflect.UndeclaredThrowableException; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +public class JacksonRpcTest extends AbstractJsonRpcTest { + + @Override + JsonRpcMapper createMapper() { + return new JacksonJsonRpcMapper(); + } + + @Test + public void rpc() { + assertFalse(service.procedurePrimitiveBoolean(true)); + assertFalse(service.procedureBoolean(Boolean.TRUE).booleanValue()); + assertEquals("hello1", service.procedureString("hello")); + assertEquals("hello1hello2", service.procedureStringString("hello1", "hello2")); + assertEquals(2, service.procedureInteger(1).intValue()); + assertEquals(2, service.procedurePrimitiveInteger(1)); + assertEquals(2, service.procedureDouble(1.0).intValue()); + assertEquals(2, (int) service.procedurePrimitiveDouble(1.0)); + assertEquals(2, (int) service.procedureLongToInteger(1L)); + assertEquals(2, service.procedurePrimitiveLongToInteger(1L)); + assertEquals(2, service.procedurePrimitiveLong(1L)); + assertEquals(2, service.procedureLong(1L).longValue()); + assertEquals("123", service.procedureIntegerToPojo(123).getStringProperty()); + + Pojo pojo = new Pojo(); + pojo.setStringProperty("hello"); + assertEquals("hello", service.procedurePojoToString(pojo)); + + try { + service.procedureException(); + fail("Remote procedure throwing exception, an exception should have been thrown"); + } catch (UndeclaredThrowableException e) { + assertTrue(e.getCause() instanceof JsonRpcException); + } + } +} diff --git a/src/test/java/com/rabbitmq/client/JsonRpcTest.java b/src/test/java/com/rabbitmq/client/JsonRpcTest.java index f13b5b4036..a4a18f9693 100644 --- a/src/test/java/com/rabbitmq/client/JsonRpcTest.java +++ b/src/test/java/com/rabbitmq/client/JsonRpcTest.java @@ -15,69 +15,44 @@ package com.rabbitmq.client; -import com.rabbitmq.client.test.TestUtils; -import com.rabbitmq.tools.jsonrpc.JsonRpcClient; -import com.rabbitmq.tools.jsonrpc.JsonRpcServer; -import org.junit.After; -import org.junit.Before; +import com.rabbitmq.tools.jsonrpc.DefaultJsonRpcMapper; +import com.rabbitmq.tools.jsonrpc.JacksonJsonRpcMapper; +import com.rabbitmq.tools.jsonrpc.JsonRpcException; +import com.rabbitmq.tools.jsonrpc.JsonRpcMapper; import org.junit.Test; import java.lang.reflect.UndeclaredThrowableException; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -public class JsonRpcTest { +public class JsonRpcTest extends AbstractJsonRpcTest { - Connection clientConnection, serverConnection; - Channel clientChannel, serverChannel; - String queue = "json.rpc.queue"; - JsonRpcServer server; - JsonRpcClient client; - RpcService service; - - @Before - public void init() throws Exception { - clientConnection = TestUtils.connectionFactory().newConnection(); - clientChannel = clientConnection.createChannel(); - serverConnection = TestUtils.connectionFactory().newConnection(); - serverChannel = serverConnection.createChannel(); - serverChannel.queueDeclare(queue, false, false, false, null); - server = new JsonRpcServer(serverChannel, queue, RpcService.class, new DefaultRpcservice()); - new Thread(() -> { - try { - server.mainloop(); - } catch (Exception e) { - // safe to ignore when loops ends/server is canceled - } - }).start(); - client = new JsonRpcClient(clientChannel, "", queue, 1000); - service = client.createProxy(RpcService.class); - } - - @After - public void tearDown() throws Exception { - if (server != null) { - server.terminateMainloop(); - } - if (client != null) { - client.close(); - } - if (serverChannel != null) { - serverChannel.queueDelete(queue); - } - clientConnection.close(); - serverConnection.close(); + @Override + JsonRpcMapper createMapper() { + return new DefaultJsonRpcMapper(); } @Test public void rpc() { + assertFalse(service.procedurePrimitiveBoolean(true)); + assertFalse(service.procedureBoolean(Boolean.TRUE).booleanValue()); assertEquals("hello1", service.procedureString("hello")); assertEquals(2, service.procedureInteger(1).intValue()); assertEquals(2, service.procedurePrimitiveInteger(1)); assertEquals(2, service.procedureDouble(1.0).intValue()); assertEquals(2, (int) service.procedurePrimitiveDouble(1.0)); + try { + service.procedureException(); + fail("Remote procedure throwing exception, an exception should have been thrown"); + } catch (UndeclaredThrowableException e) { + assertTrue(e.getCause() instanceof JsonRpcException); + } + + try { assertEquals(2, (int) service.procedureLongToInteger(1L)); fail("Long argument isn't supported"); @@ -115,105 +90,5 @@ public void rpc() { } catch (UndeclaredThrowableException e) { // OK } - - } - - public interface RpcService { - - String procedureString(String input); - - int procedurePrimitiveInteger(int input); - - Integer procedureInteger(Integer input); - - Double procedureDouble(Double input); - - double procedurePrimitiveDouble(double input); - - Integer procedureLongToInteger(Long input); - - int procedurePrimitiveLongToInteger(long input); - - Long procedureLong(Long input); - - long procedurePrimitiveLong(long input); - - Pojo procedureIntegerToPojo(Integer id); - - String procedurePojoToString(Pojo pojo); - - } - - public static class DefaultRpcservice implements RpcService { - - @Override - public String procedureString(String input) { - return input + 1; - } - - @Override - public int procedurePrimitiveInteger(int input) { - return input + 1; - } - - @Override - public Integer procedureInteger(Integer input) { - return input + 1; - } - - @Override - public Long procedureLong(Long input) { - return input + 1; - } - - @Override - public long procedurePrimitiveLong(long input) { - return input + 1L; - } - - @Override - public Double procedureDouble(Double input) { - return input + 1; - } - - @Override - public double procedurePrimitiveDouble(double input) { - return input + 1; - } - - @Override - public Integer procedureLongToInteger(Long input) { - return (int) (input + 1); - } - - @Override - public int procedurePrimitiveLongToInteger(long input) { - return (int) input + 1; - } - - @Override - public Pojo procedureIntegerToPojo(Integer id) { - Pojo pojo = new Pojo(); - pojo.setStringProperty(id.toString()); - return pojo; - } - - @Override - public String procedurePojoToString(Pojo pojo) { - return pojo.getStringProperty(); - } - } - - public static class Pojo { - - private String stringProperty; - - public String getStringProperty() { - return stringProperty; - } - - public void setStringProperty(String stringProperty) { - this.stringProperty = stringProperty; - } } -} +} \ No newline at end of file diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index 2b4c8ea04a..1224dea66e 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -16,6 +16,7 @@ package com.rabbitmq.client.test; +import com.rabbitmq.client.JacksonRpcTest; import com.rabbitmq.client.JsonRpcTest; import com.rabbitmq.utility.IntAllocatorTests; import org.junit.runner.RunWith; @@ -62,6 +63,7 @@ StrictExceptionHandlerTest.class, NoAutoRecoveryWhenTcpWindowIsFullTest.class, JsonRpcTest.class, + JacksonRpcTest.class, AddressTest.class, DefaultRetryHandlerTest.class, NioDeadlockOnConnectionClosing.class From 06c5152b3960b5ab44106019a76d02a321bb13db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 14 Aug 2018 10:13:12 +0200 Subject: [PATCH 0858/2114] Add JSON abstraction for JSON RPC support [#159302201] Fixes #378 (cherry picked from commit 01f10d6cf7c55167f40c7f82fe8459341c4e93f2) --- .../com/rabbitmq/tools/json/JSONReader.java | 5 + .../rabbitmq/tools/json/JSONSerializable.java | 4 + .../com/rabbitmq/tools/json/JSONUtil.java | 79 ++++++------ .../com/rabbitmq/tools/json/JSONWriter.java | 4 + .../tools/jsonrpc/DefaultJsonRpcMapper.java | 45 ++----- .../tools/jsonrpc/JacksonJsonRpcMapper.java | 112 +++++++++++------- .../rabbitmq/tools/jsonrpc/JsonRpcClient.java | 5 + .../rabbitmq/tools/jsonrpc/JsonRpcMapper.java | 31 +++-- .../jsonrpc/JsonRpcMappingException.java | 1 + .../rabbitmq/tools/jsonrpc/JsonRpcServer.java | 100 ++++++++-------- .../rabbitmq/client/AbstractJsonRpcTest.java | 19 ++- ...onRpcTest.java => DefaultJsonRpcTest.java} | 5 +- ...onRpcTest.java => JacksonJsonRpcTest.java} | 17 ++- .../com/rabbitmq/client/test/ClientTests.java | 8 +- 14 files changed, 246 insertions(+), 189 deletions(-) rename src/test/java/com/rabbitmq/client/{JsonRpcTest.java => DefaultJsonRpcTest.java} (96%) rename src/test/java/com/rabbitmq/client/{JacksonRpcTest.java => JacksonJsonRpcTest.java} (80%) diff --git a/src/main/java/com/rabbitmq/tools/json/JSONReader.java b/src/main/java/com/rabbitmq/tools/json/JSONReader.java index 6c9420767e..fa4c43643d 100644 --- a/src/main/java/com/rabbitmq/tools/json/JSONReader.java +++ b/src/main/java/com/rabbitmq/tools/json/JSONReader.java @@ -44,6 +44,11 @@ import java.util.List; import java.util.Map; +/** + * Will be removed in 6.0 + * + * @deprecated Use a third-party JSON library, e.g. Jackson or GJSON + */ public class JSONReader { private static final Object OBJECT_END = new Object(); diff --git a/src/main/java/com/rabbitmq/tools/json/JSONSerializable.java b/src/main/java/com/rabbitmq/tools/json/JSONSerializable.java index 1cb1b0a77e..f453de5038 100644 --- a/src/main/java/com/rabbitmq/tools/json/JSONSerializable.java +++ b/src/main/java/com/rabbitmq/tools/json/JSONSerializable.java @@ -18,6 +18,10 @@ /** * Interface for classes that wish to control their own serialization. + * + * Will be removed in 6.0 + * + * @deprecated Use a third-party JSON library, e.g. Jackson or GJSON */ public interface JSONSerializable { /** diff --git a/src/main/java/com/rabbitmq/tools/json/JSONUtil.java b/src/main/java/com/rabbitmq/tools/json/JSONUtil.java index c40727d6e8..c024e142c8 100644 --- a/src/main/java/com/rabbitmq/tools/json/JSONUtil.java +++ b/src/main/java/com/rabbitmq/tools/json/JSONUtil.java @@ -13,7 +13,6 @@ // If you have any questions regarding licensing, please contact us at // info@rabbitmq.com. - package com.rabbitmq.tools.json; import org.slf4j.Logger; @@ -34,15 +33,15 @@ */ public class JSONUtil { - private static final Logger LOGGER = LoggerFactory.getLogger(JSONUtil.class); + private static final Logger LOGGER = LoggerFactory.getLogger(JSONUtil.class); + /** * Uses reflection to fill public fields and Bean properties of * the target object from the source Map. */ public static Object fill(Object target, Map source) - throws IntrospectionException, IllegalAccessException, InvocationTargetException - { - return fill(target, source, true); + throws IntrospectionException, IllegalAccessException, InvocationTargetException { + return fill(target, source, true); } /** @@ -50,38 +49,36 @@ public static Object fill(Object target, Map source) * properties of the target object from the source Map. */ public static Object fill(Object target, Map source, boolean useProperties) - throws IntrospectionException, IllegalAccessException, InvocationTargetException - { - if (useProperties) { - BeanInfo info = Introspector.getBeanInfo(target.getClass()); + throws IntrospectionException, IllegalAccessException, InvocationTargetException { + if (useProperties) { + BeanInfo info = Introspector.getBeanInfo(target.getClass()); - PropertyDescriptor[] props = info.getPropertyDescriptors(); - for (int i = 0; i < props.length; ++i) { - PropertyDescriptor prop = props[i]; - String name = prop.getName(); - Method setter = prop.getWriteMethod(); - if (setter != null && !Modifier.isStatic(setter.getModifiers())) { - setter.invoke(target, source.get(name)); - } - } - } + PropertyDescriptor[] props = info.getPropertyDescriptors(); + for (int i = 0; i < props.length; ++i) { + PropertyDescriptor prop = props[i]; + String name = prop.getName(); + Method setter = prop.getWriteMethod(); + if (setter != null && !Modifier.isStatic(setter.getModifiers())) { + setter.invoke(target, source.get(name)); + } + } + } - Field[] ff = target.getClass().getDeclaredFields(); - for (int i = 0; i < ff.length; ++i) { - Field field = ff[i]; + Field[] ff = target.getClass().getDeclaredFields(); + for (int i = 0; i < ff.length; ++i) { + Field field = ff[i]; int fieldMod = field.getModifiers(); - if (Modifier.isPublic(fieldMod) && !(Modifier.isFinal(fieldMod) || - Modifier.isStatic(fieldMod))) - { - try { - field.set(target, source.get(field.getName())); - } catch (IllegalArgumentException iae) { - // no special error processing required + if (Modifier.isPublic(fieldMod) && !(Modifier.isFinal(fieldMod) || + Modifier.isStatic(fieldMod))) { + try { + field.set(target, source.get(field.getName())); + } catch (IllegalArgumentException iae) { + // no special error processing required } - } - } + } + } - return target; + return target; } /** @@ -90,14 +87,14 @@ public static Object fill(Object target, Map source, boolean use * source Map. */ public static void tryFill(Object target, Map source) { - try { - fill(target, source); - } catch (IntrospectionException ie) { - LOGGER.error("Error in tryFill", ie); - } catch (IllegalAccessException iae) { - LOGGER.error("Error in tryFill", iae); - } catch (InvocationTargetException ite) { - LOGGER.error("Error in tryFill", ite); - } + try { + fill(target, source); + } catch (IntrospectionException ie) { + LOGGER.error("Error in tryFill", ie); + } catch (IllegalAccessException iae) { + LOGGER.error("Error in tryFill", iae); + } catch (InvocationTargetException ite) { + LOGGER.error("Error in tryFill", ite); + } } } diff --git a/src/main/java/com/rabbitmq/tools/json/JSONWriter.java b/src/main/java/com/rabbitmq/tools/json/JSONWriter.java index 4a7f78c7f0..eb82cc7751 100644 --- a/src/main/java/com/rabbitmq/tools/json/JSONWriter.java +++ b/src/main/java/com/rabbitmq/tools/json/JSONWriter.java @@ -53,6 +53,10 @@ import java.util.Map; import java.util.Set; +/** + * Will be removed in 6.0 + * @deprecated Use a third-party JSON library, e.g. Jackson or GJSON + */ public class JSONWriter { private boolean indentMode = false; private int indentLevel = 0; diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/DefaultJsonRpcMapper.java b/src/main/java/com/rabbitmq/tools/jsonrpc/DefaultJsonRpcMapper.java index c522d24767..db6cda0b6d 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/DefaultJsonRpcMapper.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/DefaultJsonRpcMapper.java @@ -18,19 +18,27 @@ import com.rabbitmq.tools.json.JSONReader; import com.rabbitmq.tools.json.JSONWriter; -import java.lang.reflect.Method; import java.util.List; import java.util.Map; /** + * Simple {@link JsonRpcMapper} based on homegrown JSON utilities. + * Handles integers, doubles, strings, booleans, and arrays of those types. + *

+ * For a more comprehensive set of features, use {@link JacksonJsonRpcMapper}. + *

+ * Will be removed in 6.0 * + * @see JsonRpcMapper + * @see JacksonJsonRpcMapper + * @since 5.4.0 + * @deprecated use {@link JacksonJsonRpcMapper} instead */ public class DefaultJsonRpcMapper implements JsonRpcMapper { @Override public JsonRpcRequest parse(String requestBody, ServiceDescription description) { - Map request = (Map) new JSONReader().read(requestBody); - + Map request = (Map) new JSONReader().read(requestBody); return new JsonRpcRequest( request.get("id"), request.get("version").toString(), request.get("method").toString(), ((List) request.get("params")).toArray() @@ -52,40 +60,11 @@ public JsonRpcResponse parse(String responseBody, Class expectedType) { error ); } - return new JsonRpcResponse(map, map.get("result"), map.get("error"), exception); + return new JsonRpcResponse(map.get("result"), map.get("error"), exception); } @Override public String write(Object input) { return new JSONWriter().write(input); } - - /* - @Override - public Object[] parameters(JsonRpcRequest request, Method method) { - Object[] parameters = request.getParameters(); - Object[] convertedParameters = new Object[parameters.length]; - Class[] parameterTypes = method.getParameterTypes(); - for (int i = 0; i < parameters.length; i++) { - convertedParameters[i] = convert(parameters[i], parameterTypes[i]); - } - return convertedParameters; - } - - - - protected Object convert(Object input, Class expectedClass) { - return input; -// if (input == null || input.getClass().equals(expectedClass)) { -// return input; -// } -// System.err.println(input.getClass() + " " + expectedClass); -// if (Long.class.equals(expectedClass) && input instanceof Integer) { -// return Long.valueOf(((Integer) input).longValue()); -// } else if (long.class.equals(expectedClass) && input instanceof Integer) { -// return -// } -// return input; - } - */ } diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java index 0a19f53921..9cb5411b25 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java @@ -23,8 +23,8 @@ import com.fasterxml.jackson.databind.MappingJsonFactory; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ValueNode; -import com.rabbitmq.tools.json.JSONReader; -import com.rabbitmq.tools.json.JSONWriter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; import java.lang.reflect.Method; @@ -33,10 +33,16 @@ import java.util.Map; /** + * {@link JsonRpcMapper} based on Jackson. + * Uses the streaming and databind modules. * + * @see JsonRpcMapper + * @since 5.4.0 */ public class JacksonJsonRpcMapper implements JsonRpcMapper { + private static final Logger LOGGER = LoggerFactory.getLogger(JacksonJsonRpcMapper.class); + private final ObjectMapper mapper; public JacksonJsonRpcMapper(ObjectMapper mapper) { @@ -62,7 +68,21 @@ public JsonRpcRequest parse(String requestBody, ServiceDescription description) if ("method".equals(name)) { method = parser.getValueAsString(); } else if ("id".equals(name)) { - // FIXME parse id, can be any type (handle only primitive and wrapper) + TreeNode node = parser.readValueAsTree(); + if (node instanceof ValueNode) { + ValueNode idNode = (ValueNode) node; + if (idNode.isNull()) { + id = null; + } else if (idNode.isTextual()) { + id = idNode.asText(); + } else if (idNode.isNumber()) { + id = Long.valueOf(idNode.asLong()); + } else { + LOGGER.warn("ID type not null, text, or number {}, ignoring", idNode); + } + } else { + LOGGER.warn("ID not a scalar value {}, ignoring", node); + } } else if ("version".equals(name)) { version = parser.getValueAsString(); } else if ("params".equals(name)) { @@ -80,6 +100,10 @@ public JsonRpcRequest parse(String requestBody, ServiceDescription description) throw new JsonRpcMappingException("Error during JSON parsing", e); } + if (method == null) { + throw new IllegalArgumentException("Could not find method to invoke in request"); + } + List convertedParameters = new ArrayList<>(parameters.size()); if (!parameters.isEmpty()) { ProcedureDescription proc = description.getProcedure(method, parameters.size()); @@ -102,69 +126,40 @@ public JsonRpcRequest parse(String requestBody, ServiceDescription description) ); } - protected Object convert(TreeNode node, Class expectedType) throws IOException { - Object value; - if (expectedType.isPrimitive()) { - ValueNode valueNode = (ValueNode) node; - if (expectedType == Boolean.TYPE) { - value = valueNode.booleanValue(); - } else if (expectedType == Character.TYPE) { - value = valueNode.textValue().charAt(0); - } else if (expectedType == Short.TYPE) { - value = valueNode.shortValue(); - } else if (expectedType == Integer.TYPE) { - value = valueNode.intValue(); - } else if (expectedType == Long.TYPE) { - value = valueNode.longValue(); - } else if (expectedType == Float.TYPE) { - value = valueNode.floatValue(); - } else if (expectedType == Double.TYPE) { - value = valueNode.doubleValue(); - } else { - throw new IllegalArgumentException("Primitive type not supported: " + expectedType); - } - } else { - value = mapper.readValue(node.traverse(), expectedType); - } - return value; - } - @Override public JsonRpcResponse parse(String responseBody, Class expectedReturnType) { JsonFactory jsonFactory = new MappingJsonFactory(); Object result = null; + JsonRpcException exception = null; + Map errorMap = null; try (JsonParser parser = jsonFactory.createParser(responseBody)) { while (parser.nextToken() != null) { JsonToken token = parser.currentToken(); if (token == JsonToken.FIELD_NAME) { String name = parser.currentName(); - parser.nextToken(); if ("result".equals(name)) { + parser.nextToken(); if (expectedReturnType == Void.TYPE) { result = null; } else { result = convert(parser.readValueAsTree(), expectedReturnType); } + } else if ("error".equals(name)) { + errorMap = (Map) convert(parser.readValueAsTree(), Map.class); + exception = new JsonRpcException( + errorMap.toString(), + (String) errorMap.get("name"), + errorMap.get("code") == null ? 0 : (Integer) errorMap.get("code"), + (String) errorMap.get("message"), + errorMap + ); } } } } catch (IOException e) { throw new JsonRpcMappingException("Error during JSON parsing", e); } - Map map = (Map) (new JSONReader().read(responseBody)); - Map error; - JsonRpcException exception = null; - if (map.containsKey("error")) { - error = (Map) map.get("error"); - exception = new JsonRpcException( - new JSONWriter().write(error), - (String) error.get("name"), - error.get("code") == null ? 0 : (Integer) error.get("code"), - (String) error.get("message"), - error - ); - } - return new JsonRpcResponse(map, result, map.get("error"), exception); + return new JsonRpcResponse(result, errorMap, exception); } @Override @@ -175,4 +170,31 @@ public String write(Object input) { throw new JsonRpcMappingException("Error during JSON serialization", e); } } + + protected Object convert(TreeNode node, Class expectedType) throws IOException { + Object value; + if (expectedType.isPrimitive()) { + ValueNode valueNode = (ValueNode) node; + if (expectedType == Boolean.TYPE) { + value = valueNode.booleanValue(); + } else if (expectedType == Character.TYPE) { + value = valueNode.textValue().charAt(0); + } else if (expectedType == Short.TYPE) { + value = valueNode.shortValue(); + } else if (expectedType == Integer.TYPE) { + value = valueNode.intValue(); + } else if (expectedType == Long.TYPE) { + value = valueNode.longValue(); + } else if (expectedType == Float.TYPE) { + value = valueNode.floatValue(); + } else if (expectedType == Double.TYPE) { + value = valueNode.doubleValue(); + } else { + throw new IllegalArgumentException("Primitive type not supported: " + expectedType); + } + } else { + value = mapper.readValue(node.traverse(), expectedType); + } + return value; + } } diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java index 12032941f3..f64b9f47f0 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java @@ -50,9 +50,14 @@ * code can access the service description by reading the * serviceDescription field of * JsonRpcClient instances. + *

+ * {@link JsonRpcClient} delegates JSON parsing and generating to + * a {@link JsonRpcMapper}. * * @see #call(String, Object[]) * @see #call(String[]) + * @see JsonRpcMapper + * @see JacksonJsonRpcMapper */ public class JsonRpcClient extends RpcClient implements InvocationHandler { diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java index 36f1ad72b2..fdad5e1960 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java @@ -16,14 +16,37 @@ package com.rabbitmq.tools.jsonrpc; /** + * Abstraction to handle JSON parsing and generation. + * Used by {@link JsonRpcServer} and {@link JsonRpcClient}. * + * @since 5.4.0 */ public interface JsonRpcMapper { + /** + * Parses a JSON RPC request. + * The {@link ServiceDescription} can be used + * to look up the invoked procedure and learn about + * its signature. + * @param requestBody + * @param description + * @return + */ JsonRpcRequest parse(String requestBody, ServiceDescription description); + /** + * Parses a JSON RPC response. + * @param responseBody + * @param expectedType + * @return + */ JsonRpcResponse parse(String responseBody, Class expectedType); + /** + * Serialize an object into JSON. + * @param input + * @return + */ String write(Object input); class JsonRpcRequest { @@ -67,22 +90,16 @@ public boolean isSystemDescribe() { class JsonRpcResponse { - private final Object reply; private final Object result; private final Object error; private final JsonRpcException exception; - public JsonRpcResponse(Object reply, Object result, Object error, JsonRpcException exception) { - this.reply = reply; + public JsonRpcResponse(Object result, Object error, JsonRpcException exception) { this.result = result; this.error = error; this.exception = exception; } - public Object getReply() { - return reply; - } - public Object getError() { return error; } diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMappingException.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMappingException.java index 633a1d79d7..03a7d12b91 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMappingException.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMappingException.java @@ -17,6 +17,7 @@ /** * + * @since 5.4.0 */ public class JsonRpcMappingException extends RuntimeException { diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java index 922fe35b1c..723664c3b5 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java @@ -13,55 +13,59 @@ // If you have any questions regarding licensing, please contact us at // info@rabbitmq.com. - package com.rabbitmq.tools.jsonrpc; +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.StringRpcServer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.IOException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; -import java.util.List; import java.util.Map; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.StringRpcServer; -import com.rabbitmq.tools.json.JSONReader; -import com.rabbitmq.tools.json.JSONWriter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - /** * JSON-RPC Server class. - * + *

* Given a Java {@link Class}, representing an interface, and an * implementation of that interface, JsonRpcServer will reflect on the * class to construct the {@link ServiceDescription}, and will route * incoming requests for methods on the interface to the * implementation object while the mainloop() is running. + *

+ * {@link JsonRpcServer} delegates JSON parsing and generating to + * a {@link JsonRpcMapper}. * * @see com.rabbitmq.client.RpcServer * @see JsonRpcClient + * @see JsonRpcMapper + * @see JacksonJsonRpcMapper */ public class JsonRpcServer extends StringRpcServer { private static final Logger LOGGER = LoggerFactory.getLogger(JsonRpcServer.class); - - /** Holds the JSON-RPC service description for this client. */ + private final JsonRpcMapper mapper; + /** + * Holds the JSON-RPC service description for this client. + */ public ServiceDescription serviceDescription; - /** The interface this server implements. */ + /** + * The interface this server implements. + */ public Class interfaceClass; - /** The instance backing this server. */ + /** + * The instance backing this server. + */ public Object interfaceInstance; - private final JsonRpcMapper mapper; - public JsonRpcServer(Channel channel, Class interfaceClass, Object interfaceInstance, JsonRpcMapper mapper) - throws IOException - { + throws IOException { super(channel); this.mapper = mapper; init(interfaceClass, interfaceInstance); @@ -71,32 +75,24 @@ public JsonRpcServer(Channel channel, * Construct a server that talks to the outside world using the * given channel, and constructs a fresh temporary * queue. Use getQueueName() to discover the created queue name. - * @param channel AMQP channel to use - * @param interfaceClass Java interface that this server is exposing to the world + * + * @param channel AMQP channel to use + * @param interfaceClass Java interface that this server is exposing to the world * @param interfaceInstance Java instance (of interfaceClass) that is being exposed * @throws IOException if something goes wrong during an AMQP operation */ public JsonRpcServer(Channel channel, - Class interfaceClass, - Object interfaceInstance) - throws IOException - { + Class interfaceClass, + Object interfaceInstance) + throws IOException { this(channel, interfaceClass, interfaceInstance, new DefaultJsonRpcMapper()); } - private void init(Class interfaceClass, Object interfaceInstance) - { - this.interfaceClass = interfaceClass; - this.interfaceInstance = interfaceInstance; - this.serviceDescription = new ServiceDescription(interfaceClass); - } - public JsonRpcServer(Channel channel, String queueName, Class interfaceClass, Object interfaceInstance, JsonRpcMapper mapper) - throws IOException - { + throws IOException { super(channel, queueName); this.mapper = mapper; init(interfaceClass, interfaceInstance); @@ -107,38 +103,43 @@ public JsonRpcServer(Channel channel, * given channel and queue name. Our superclass, * RpcServer, expects the queue to exist at the time of * construction. - * @param channel AMQP channel to use - * @param queueName AMQP queue name to listen for requests on - * @param interfaceClass Java interface that this server is exposing to the world + * + * @param channel AMQP channel to use + * @param queueName AMQP queue name to listen for requests on + * @param interfaceClass Java interface that this server is exposing to the world * @param interfaceInstance Java instance (of interfaceClass) that is being exposed * @throws IOException if something goes wrong during an AMQP operation */ public JsonRpcServer(Channel channel, - String queueName, - Class interfaceClass, - Object interfaceInstance) - throws IOException - { + String queueName, + Class interfaceClass, + Object interfaceInstance) + throws IOException { this(channel, queueName, interfaceClass, interfaceInstance, new DefaultJsonRpcMapper()); } + private void init(Class interfaceClass, Object interfaceInstance) { + this.interfaceClass = interfaceClass; + this.interfaceInstance = interfaceInstance; + this.serviceDescription = new ServiceDescription(interfaceClass); + } + /** * Override our superclass' method, dispatching to doCall. */ @Override - public String handleStringCall(String requestBody, AMQP.BasicProperties replyProperties) - { + public String handleStringCall(String requestBody, AMQP.BasicProperties replyProperties) { String replyBody = doCall(requestBody); return replyBody; } /** * Runs a single JSON-RPC request. + * * @param requestBody the JSON-RPC request string (a JSON encoded value) * @return a JSON-RPC response string (a JSON encoded value) */ - public String doCall(String requestBody) - { + public String doCall(String requestBody) { Object id; String method; Object[] params; @@ -188,7 +189,7 @@ public String doCall(String requestBody) } } catch (ClassCastException cce) { // Bogus request! - response = errorResponse(null, 400, "Bad Request", null); + response = errorResponse(null, 400, "Bad Request", null); } if (LOGGER.isDebugEnabled()) { @@ -200,13 +201,12 @@ public String doCall(String requestBody) /** * Retrieves the best matching method for the given method name and parameters. - * + *

* Subclasses may override this if they have specialised * dispatching requirements, so long as they continue to honour * their ServiceDescription. */ - public Method matchingMethod(String methodName, Object[] params) - { + public Method matchingMethod(String methodName, Object[] params) { ProcedureDescription proc = serviceDescription.getProcedure(methodName, params.length); return proc.internal_getMethod(); } diff --git a/src/test/java/com/rabbitmq/client/AbstractJsonRpcTest.java b/src/test/java/com/rabbitmq/client/AbstractJsonRpcTest.java index 555d4c0b24..079dcf00a7 100644 --- a/src/test/java/com/rabbitmq/client/AbstractJsonRpcTest.java +++ b/src/test/java/com/rabbitmq/client/AbstractJsonRpcTest.java @@ -21,12 +21,8 @@ import com.rabbitmq.tools.jsonrpc.JsonRpcServer; import org.junit.After; import org.junit.Before; -import org.junit.Test; -import java.lang.reflect.UndeclaredThrowableException; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; +import java.util.Date; public abstract class AbstractJsonRpcTest { @@ -105,6 +101,9 @@ public interface RpcService { void procedureException(); + void procedureNoArgumentVoid(); + + Date procedureDateDate(Date date); } public static class DefaultRpcservice implements RpcService { @@ -185,6 +184,16 @@ public String procedurePojoToString(Pojo pojo) { public void procedureException() { throw new RuntimeException(); } + + @Override + public void procedureNoArgumentVoid() { + + } + + @Override + public Date procedureDateDate(Date date) { + return date; + } } public static class Pojo { diff --git a/src/test/java/com/rabbitmq/client/JsonRpcTest.java b/src/test/java/com/rabbitmq/client/DefaultJsonRpcTest.java similarity index 96% rename from src/test/java/com/rabbitmq/client/JsonRpcTest.java rename to src/test/java/com/rabbitmq/client/DefaultJsonRpcTest.java index a4a18f9693..049554d1d2 100644 --- a/src/test/java/com/rabbitmq/client/JsonRpcTest.java +++ b/src/test/java/com/rabbitmq/client/DefaultJsonRpcTest.java @@ -16,7 +16,6 @@ package com.rabbitmq.client; import com.rabbitmq.tools.jsonrpc.DefaultJsonRpcMapper; -import com.rabbitmq.tools.jsonrpc.JacksonJsonRpcMapper; import com.rabbitmq.tools.jsonrpc.JsonRpcException; import com.rabbitmq.tools.jsonrpc.JsonRpcMapper; import org.junit.Test; @@ -28,7 +27,7 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -public class JsonRpcTest extends AbstractJsonRpcTest { +public class DefaultJsonRpcTest extends AbstractJsonRpcTest { @Override JsonRpcMapper createMapper() { @@ -44,6 +43,7 @@ public void rpc() { assertEquals(2, service.procedurePrimitiveInteger(1)); assertEquals(2, service.procedureDouble(1.0).intValue()); assertEquals(2, (int) service.procedurePrimitiveDouble(1.0)); + service.procedureNoArgumentVoid(); try { service.procedureException(); @@ -52,7 +52,6 @@ public void rpc() { assertTrue(e.getCause() instanceof JsonRpcException); } - try { assertEquals(2, (int) service.procedureLongToInteger(1L)); fail("Long argument isn't supported"); diff --git a/src/test/java/com/rabbitmq/client/JacksonRpcTest.java b/src/test/java/com/rabbitmq/client/JacksonJsonRpcTest.java similarity index 80% rename from src/test/java/com/rabbitmq/client/JacksonRpcTest.java rename to src/test/java/com/rabbitmq/client/JacksonJsonRpcTest.java index ba95efef98..6ccb2c4751 100644 --- a/src/test/java/com/rabbitmq/client/JacksonRpcTest.java +++ b/src/test/java/com/rabbitmq/client/JacksonJsonRpcTest.java @@ -21,13 +21,15 @@ import org.junit.Test; import java.lang.reflect.UndeclaredThrowableException; +import java.util.Calendar; +import java.util.Date; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -public class JacksonRpcTest extends AbstractJsonRpcTest { +public class JacksonJsonRpcTest extends AbstractJsonRpcTest { @Override JsonRpcMapper createMapper() { @@ -49,6 +51,19 @@ public void rpc() { assertEquals(2, service.procedurePrimitiveLong(1L)); assertEquals(2, service.procedureLong(1L).longValue()); assertEquals("123", service.procedureIntegerToPojo(123).getStringProperty()); + service.procedureNoArgumentVoid(); + + Calendar calendar = Calendar.getInstance(); + Date date = calendar.getTime(); + Date returnedDate = service.procedureDateDate(date); + assertEquals(date.getTime(), returnedDate.getTime()); + + try { + service.procedureException(); + fail("Remote procedure throwing exception, an exception should have been thrown"); + } catch (UndeclaredThrowableException e) { + assertTrue(e.getCause() instanceof JsonRpcException); + } Pojo pojo = new Pojo(); pojo.setStringProperty("hello"); diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index 1224dea66e..7655f43d13 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -16,8 +16,8 @@ package com.rabbitmq.client.test; -import com.rabbitmq.client.JacksonRpcTest; -import com.rabbitmq.client.JsonRpcTest; +import com.rabbitmq.client.JacksonJsonRpcTest; +import com.rabbitmq.client.DefaultJsonRpcTest; import com.rabbitmq.utility.IntAllocatorTests; import org.junit.runner.RunWith; import org.junit.runners.Suite; @@ -62,8 +62,8 @@ TestUtilsTest.class, StrictExceptionHandlerTest.class, NoAutoRecoveryWhenTcpWindowIsFullTest.class, - JsonRpcTest.class, - JacksonRpcTest.class, + DefaultJsonRpcTest.class, + JacksonJsonRpcTest.class, AddressTest.class, DefaultRetryHandlerTest.class, NioDeadlockOnConnectionClosing.class From 6fecb1cf7c003bbf93423e2735af185191cf5894 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 14 Aug 2018 10:35:26 +0200 Subject: [PATCH 0859/2114] Polish JSON RPC support References #378 (cherry picked from commit d79a8b06d209e62d21c08e041d89c14261fc56f8) --- src/main/java/com/rabbitmq/tools/json/JSONReader.java | 2 +- .../java/com/rabbitmq/tools/json/JSONSerializable.java | 2 +- src/main/java/com/rabbitmq/tools/json/JSONWriter.java | 2 +- .../com/rabbitmq/tools/jsonrpc/DefaultJsonRpcMapper.java | 2 ++ src/test/java/com/rabbitmq/client/JacksonJsonRpcTest.java | 7 ------- 5 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/rabbitmq/tools/json/JSONReader.java b/src/main/java/com/rabbitmq/tools/json/JSONReader.java index fa4c43643d..14c690e6e2 100644 --- a/src/main/java/com/rabbitmq/tools/json/JSONReader.java +++ b/src/main/java/com/rabbitmq/tools/json/JSONReader.java @@ -47,7 +47,7 @@ /** * Will be removed in 6.0 * - * @deprecated Use a third-party JSON library, e.g. Jackson or GJSON + * @deprecated Use a third-party JSON library, e.g. Jackson or Gson */ public class JSONReader { diff --git a/src/main/java/com/rabbitmq/tools/json/JSONSerializable.java b/src/main/java/com/rabbitmq/tools/json/JSONSerializable.java index f453de5038..39f72d4ac2 100644 --- a/src/main/java/com/rabbitmq/tools/json/JSONSerializable.java +++ b/src/main/java/com/rabbitmq/tools/json/JSONSerializable.java @@ -21,7 +21,7 @@ * * Will be removed in 6.0 * - * @deprecated Use a third-party JSON library, e.g. Jackson or GJSON + * @deprecated Use a third-party JSON library, e.g. Jackson or Gson */ public interface JSONSerializable { /** diff --git a/src/main/java/com/rabbitmq/tools/json/JSONWriter.java b/src/main/java/com/rabbitmq/tools/json/JSONWriter.java index eb82cc7751..7101598040 100644 --- a/src/main/java/com/rabbitmq/tools/json/JSONWriter.java +++ b/src/main/java/com/rabbitmq/tools/json/JSONWriter.java @@ -55,7 +55,7 @@ /** * Will be removed in 6.0 - * @deprecated Use a third-party JSON library, e.g. Jackson or GJSON + * @deprecated Use a third-party JSON library, e.g. Jackson or Gson */ public class JSONWriter { private boolean indentMode = false; diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/DefaultJsonRpcMapper.java b/src/main/java/com/rabbitmq/tools/jsonrpc/DefaultJsonRpcMapper.java index db6cda0b6d..b40789e380 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/DefaultJsonRpcMapper.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/DefaultJsonRpcMapper.java @@ -38,6 +38,7 @@ public class DefaultJsonRpcMapper implements JsonRpcMapper { @Override public JsonRpcRequest parse(String requestBody, ServiceDescription description) { + @SuppressWarnings("unchecked") Map request = (Map) new JSONReader().read(requestBody); return new JsonRpcRequest( request.get("id"), request.get("version").toString(), request.get("method").toString(), @@ -47,6 +48,7 @@ public JsonRpcRequest parse(String requestBody, ServiceDescription description) @Override public JsonRpcResponse parse(String responseBody, Class expectedType) { + @SuppressWarnings("unchecked") Map map = (Map) (new JSONReader().read(responseBody)); Map error; JsonRpcException exception = null; diff --git a/src/test/java/com/rabbitmq/client/JacksonJsonRpcTest.java b/src/test/java/com/rabbitmq/client/JacksonJsonRpcTest.java index 6ccb2c4751..091ce44680 100644 --- a/src/test/java/com/rabbitmq/client/JacksonJsonRpcTest.java +++ b/src/test/java/com/rabbitmq/client/JacksonJsonRpcTest.java @@ -58,13 +58,6 @@ public void rpc() { Date returnedDate = service.procedureDateDate(date); assertEquals(date.getTime(), returnedDate.getTime()); - try { - service.procedureException(); - fail("Remote procedure throwing exception, an exception should have been thrown"); - } catch (UndeclaredThrowableException e) { - assertTrue(e.getCause() instanceof JsonRpcException); - } - Pojo pojo = new Pojo(); pojo.setStringProperty("hello"); assertEquals("hello", service.procedurePojoToString(pojo)); From de907f001ecce9460ba9d9997d4c56845b70c251 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 16 Aug 2018 11:03:25 +0200 Subject: [PATCH 0860/2114] Add equals and hashCode to generate classes Fixes #377 (cherry picked from commit 22ca4c8be29b0c235663db4c19291eacafe98f04) --- codegen.py | 48 +++++++ .../com/rabbitmq/client/test/ClientTests.java | 3 +- .../client/test/GeneratedClassesTest.java | 135 ++++++++++++++++++ 3 files changed, 185 insertions(+), 1 deletion(-) create mode 100644 src/test/java/com/rabbitmq/client/test/GeneratedClassesTest.java diff --git a/codegen.py b/codegen.py index 7ef06b4141..3a67ce435d 100755 --- a/codegen.py +++ b/codegen.py @@ -368,6 +368,9 @@ def printGetter(fieldType, fieldName): print(" public int getClassId() { return %i; }" % (c.index)) print(" public String getClassName() { return \"%s\"; }" % (c.name)) + if c.fields: + equalsHashCode(spec, c.fields, java_class_name(c.name), 'Properties', False) + printPropertiesBuilder(c) #accessor methods @@ -400,6 +403,49 @@ def printPropertiesClasses(): #-------------------------------------------------------------------------------- +def equalsHashCode(spec, fields, jClassName, classSuffix, usePrimitiveType): + print() + print() + print(" @Override") + print(" public boolean equals(Object o) {") + print(" if (this == o)") + print(" return true;") + print(" if (o == null || getClass() != o.getClass())") + print(" return false;") + print(" %s%s that = (%s%s) o;" % (jClassName, classSuffix, jClassName, classSuffix)) + + for f in fields: + (fType, fName) = (java_field_type(spec, f.domain), java_field_name(f.name)) + if usePrimitiveType and fType in javaScalarTypes: + print(" if (%s != that.%s)" % (fName, fName)) + else: + print(" if (%s != null ? !%s.equals(that.%s) : that.%s != null)" % (fName, fName, fName, fName)) + + print(" return false;") + + print(" return true;") + print(" }") + + print() + print(" @Override") + print(" public int hashCode() {") + print(" int result = 0;") + + for f in fields: + (fType, fName) = (java_field_type(spec, f.domain), java_field_name(f.name)) + if usePrimitiveType and fType in javaScalarTypes: + if fType == 'boolean': + print(" result = 31 * result + (%s ? 1 : 0);" % fName) + elif fType == 'long': + print(" result = 31 * result + (int) (%s ^ (%s >>> 32));" % (fName, fName)) + else: + print(" result = 31 * result + %s;" % fName) + else: + print(" result = 31 * result + (%s != null ? %s.hashCode() : 0);" % (fName, fName)) + + print(" return result;") + print(" }") + def genJavaImpl(spec): def printHeader(): printFileHeader() @@ -503,6 +549,8 @@ def write_arguments(): getters() constructors() others() + if m.arguments: + equalsHashCode(spec, m.arguments, java_class_name(m.name), '', True) argument_debug_string() write_arguments() diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index 7655f43d13..73a11f5af7 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -66,7 +66,8 @@ JacksonJsonRpcTest.class, AddressTest.class, DefaultRetryHandlerTest.class, - NioDeadlockOnConnectionClosing.class + NioDeadlockOnConnectionClosing.class, + GeneratedClassesTest.class }) public class ClientTests { diff --git a/src/test/java/com/rabbitmq/client/test/GeneratedClassesTest.java b/src/test/java/com/rabbitmq/client/test/GeneratedClassesTest.java new file mode 100644 index 0000000000..e9dbcfca98 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/GeneratedClassesTest.java @@ -0,0 +1,135 @@ +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.test; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.impl.AMQImpl; +import org.junit.Test; + +import java.util.Calendar; +import java.util.Date; + +import static java.util.Collections.singletonMap; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; + +/** + * + */ +public class GeneratedClassesTest { + + @Test + public void amqpPropertiesEqualsHashCode() { + checkEquals( + new AMQP.BasicProperties.Builder().correlationId("one").build(), + new AMQP.BasicProperties.Builder().correlationId("one").build() + ); + checkNotEquals( + new AMQP.BasicProperties.Builder().correlationId("one").build(), + new AMQP.BasicProperties.Builder().correlationId("two").build() + ); + Date date = Calendar.getInstance().getTime(); + checkEquals( + new AMQP.BasicProperties.Builder() + .deliveryMode(1) + .headers(singletonMap("one", "two")) + .correlationId("123") + .expiration("later") + .priority(10) + .replyTo("me") + .contentType("text/plain") + .contentEncoding("UTF-8") + .userId("jdoe") + .appId("app1") + .clusterId("cluster1") + .messageId("message123") + .timestamp(date) + .type("type") + .build(), + new AMQP.BasicProperties.Builder() + .deliveryMode(1) + .headers(singletonMap("one", "two")) + .correlationId("123") + .expiration("later") + .priority(10) + .replyTo("me") + .contentType("text/plain") + .contentEncoding("UTF-8") + .userId("jdoe") + .appId("app1") + .clusterId("cluster1") + .messageId("message123") + .timestamp(date) + .type("type") + .build() + ); + checkNotEquals( + new AMQP.BasicProperties.Builder() + .deliveryMode(1) + .headers(singletonMap("one", "two")) + .correlationId("123") + .expiration("later") + .priority(10) + .replyTo("me") + .contentType("text/plain") + .contentEncoding("UTF-8") + .userId("jdoe") + .appId("app1") + .clusterId("cluster1") + .messageId("message123") + .timestamp(date) + .type("type") + .build(), + new AMQP.BasicProperties.Builder() + .deliveryMode(2) + .headers(singletonMap("one", "two")) + .correlationId("123") + .expiration("later") + .priority(10) + .replyTo("me") + .contentType("text/plain") + .contentEncoding("UTF-8") + .userId("jdoe") + .appId("app1") + .clusterId("cluster1") + .messageId("message123") + .timestamp(date) + .type("type") + .build() + ); + + } + + @Test public void amqImplEqualsHashCode() { + checkEquals( + new AMQImpl.Basic.Deliver("tag", 1L, false, "amq.direct","rk"), + new AMQImpl.Basic.Deliver("tag", 1L, false, "amq.direct","rk") + ); + checkNotEquals( + new AMQImpl.Basic.Deliver("tag", 1L, false, "amq.direct","rk"), + new AMQImpl.Basic.Deliver("tag", 2L, false, "amq.direct","rk") + ); + } + + private void checkEquals(Object o1, Object o2) { + assertEquals(o1, o2); + assertEquals(o1.hashCode(), o2.hashCode()); + } + + private void checkNotEquals(Object o1, Object o2) { + assertNotEquals(o1, o2); + } +} From e4b93e7016a88eb2df7148ea9c155cc9a92ddef4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 17 Aug 2018 09:45:11 +0200 Subject: [PATCH 0861/2114] Set release version to 5.4.0.RC1 --- release-versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-versions.txt b/release-versions.txt index 5a62e85797..3b0c3ec1b0 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="5.4.0.M1" +RELEASE_VERSION="5.4.0.RC1" DEVELOPMENT_VERSION="5.4.0-SNAPSHOT" From 99b68a06d589883fb6ceaabba5da3c2df5f212cc Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Fri, 17 Aug 2018 07:52:32 +0000 Subject: [PATCH 0862/2114] [maven-release-plugin] prepare release v5.4.0.RC1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 7104624064..890b70584f 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.4.0-SNAPSHOT + 5.4.0.RC1 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v5.4.0.RC1 From 393704579ec12f84f1a104aea7181892841e8e9d Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Fri, 17 Aug 2018 07:52:37 +0000 Subject: [PATCH 0863/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 890b70584f..7104624064 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.4.0.RC1 + 5.4.0-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v5.4.0.RC1 + HEAD From d4d3561e28d655919315cea93f1bb9f1f624cbfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 17 Aug 2018 09:58:13 +0200 Subject: [PATCH 0864/2114] Set release version to 5.4.0.RC2 --- release-versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-versions.txt b/release-versions.txt index 3b0c3ec1b0..56eb83cff6 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="5.4.0.RC1" +RELEASE_VERSION="5.4.0.RC2" DEVELOPMENT_VERSION="5.4.0-SNAPSHOT" From 0d0ea4104a78af93b64ca484b3e939d46cf7afd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 17 Aug 2018 10:29:18 +0200 Subject: [PATCH 0865/2114] Remove JSON reader and writer Fixes #391 --- .../com/rabbitmq/tools/json/JSONReader.java | 269 ---------------- .../rabbitmq/tools/json/JSONSerializable.java | 31 -- .../com/rabbitmq/tools/json/JSONWriter.java | 293 ------------------ .../tools/jsonrpc/DefaultJsonRpcMapper.java | 72 ----- .../rabbitmq/tools/jsonrpc/JsonRpcClient.java | 59 +--- .../rabbitmq/tools/jsonrpc/JsonRpcServer.java | 4 +- .../rabbitmq/client/DefaultJsonRpcTest.java | 93 ------ .../com/rabbitmq/client/test/ClientTests.java | 3 - .../client/test/JSONReadWriteTest.java | 111 ------- 9 files changed, 3 insertions(+), 932 deletions(-) delete mode 100644 src/main/java/com/rabbitmq/tools/json/JSONReader.java delete mode 100644 src/main/java/com/rabbitmq/tools/json/JSONSerializable.java delete mode 100644 src/main/java/com/rabbitmq/tools/json/JSONWriter.java delete mode 100644 src/main/java/com/rabbitmq/tools/jsonrpc/DefaultJsonRpcMapper.java delete mode 100644 src/test/java/com/rabbitmq/client/DefaultJsonRpcTest.java delete mode 100644 src/test/java/com/rabbitmq/client/test/JSONReadWriteTest.java diff --git a/src/main/java/com/rabbitmq/tools/json/JSONReader.java b/src/main/java/com/rabbitmq/tools/json/JSONReader.java deleted file mode 100644 index 14c690e6e2..0000000000 --- a/src/main/java/com/rabbitmq/tools/json/JSONReader.java +++ /dev/null @@ -1,269 +0,0 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - -/* - Copyright (c) 2006-2007 Frank Carver - Copyright (c) 2007-2016 Pivotal Software, Inc. All Rights Reserved - - Licensed 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. -*/ -/* - * Based on org.stringtree.json.JSONReader, licensed under APL and - * LGPL. We've chosen APL (see above). The original code was written - * by Frank Carver. Tony Garnock-Jones has made many changes to it - * since then. - */ -package com.rabbitmq.tools.json; - -import java.text.CharacterIterator; -import java.text.StringCharacterIterator; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Will be removed in 6.0 - * - * @deprecated Use a third-party JSON library, e.g. Jackson or Gson - */ -public class JSONReader { - - private static final Object OBJECT_END = new Object(); - private static final Object ARRAY_END = new Object(); - private static final Object COLON = new Object(); - private static final Object COMMA = new Object(); - - private static final Map escapes = new HashMap(); - static { - escapes.put(Character.valueOf('"'), Character.valueOf('"')); - escapes.put(Character.valueOf('\\'), Character.valueOf('\\')); - escapes.put(Character.valueOf('/'), Character.valueOf('/')); - escapes.put(Character.valueOf('b'), Character.valueOf('\b')); - escapes.put(Character.valueOf('f'), Character.valueOf('\f')); - escapes.put(Character.valueOf('n'), Character.valueOf('\n')); - escapes.put(Character.valueOf('r'), Character.valueOf('\r')); - escapes.put(Character.valueOf('t'), Character.valueOf('\t')); - } - - private CharacterIterator it; - private char c; - private Object token; - private final StringBuilder buf = new StringBuilder(); - - private char next() { - c = it.next(); - return c; - } - - private void skipWhiteSpace() { - boolean cont; - - do { - cont = true; - if (Character.isWhitespace(c)) { - next(); - } - else if (c == '/' && next() == '/') { - while (c != '\n') { - next(); - } - } - else { - cont = false; - } - } while (cont); - } - - public Object read(String string) { - it = new StringCharacterIterator(string); - c = it.first(); - return read(); - } - - private Object read() { - Object ret = null; - skipWhiteSpace(); - - if (c == '"' || c == '\'') { - char sep = c; - next(); - ret = string(sep); - } else if (c == '[') { - next(); - ret = array(); - } else if (c == ']') { - ret = ARRAY_END; - next(); - } else if (c == ',') { - ret = COMMA; - next(); - } else if (c == '{') { - next(); - ret = object(); - } else if (c == '}') { - ret = OBJECT_END; - next(); - } else if (c == ':') { - ret = COLON; - next(); - } else if (c == 't' && next() == 'r' && next() == 'u' && next() == 'e') { - ret = Boolean.TRUE; - next(); - } else if (c == 'f' && next() == 'a' && next() == 'l' && next() == 's' && next() == 'e') { - ret = Boolean.FALSE; - next(); - } else if (c == 'n' && next() == 'u' && next() == 'l' && next() == 'l') { - next(); - } else if (Character.isDigit(c) || c == '-') { - ret = number(); - } - else { - throw new IllegalStateException("Found invalid token while parsing JSON (around character "+(it.getIndex()-it.getBeginIndex())+"): " + ret); - } - - token = ret; - return ret; - } - - private Object object() { - Map ret = new HashMap(); - String key = (String) read(); // JSON keys must be strings - while (token != OBJECT_END) { - read(); // should be a colon - if (token != OBJECT_END) { - ret.put(key, read()); - if (read() == COMMA) { - key = (String) read(); - } - } - } - - return ret; - } - - private Object array() { - List ret = new ArrayList(); - Object value = read(); - while (token != ARRAY_END) { - ret.add(value); - if (read() == COMMA) { - value = read(); - } - } - return ret; - } - - private Object number() { - buf.setLength(0); - if (c == '-') { - add(); - } - addDigits(); - if (c == '.') { - add(); - addDigits(); - } - if (c == 'e' || c == 'E') { - add(); - if (c == '+' || c == '-') { - add(); - } - addDigits(); - } - - String result = buf.toString(); - try { - return Integer.valueOf(result); - } catch (NumberFormatException nfe) { - return Double.valueOf(result); - } - } - - /** - * Read a string with a specific delimiter (either ' or ") - */ - private Object string(char sep) { - buf.setLength(0); - while (c != sep) { - if (c == '\\') { - next(); - if (c == 'u') { - add(unicode()); - } else { - Object value = escapes.get(Character.valueOf(c)); - if (value != null) { - add(((Character) value).charValue()); - } - // if escaping is invalid, if we're going to ignore the error, - // it makes more sense to put in the literal character instead - // of just skipping it, so we do that - else { - add(); - } - } - } else { - add(); - } - } - next(); - - return buf.toString(); - } - - private void add(char cc) { - buf.append(cc); - next(); - } - - private void add() { - add(c); - } - - private void addDigits() { - while (Character.isDigit(c)) { - add(); - } - } - - private char unicode() { - int value = 0; - for (int i = 0; i < 4; ++i) { - switch (next()) { - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - value = (value << 4) + c - '0'; - break; - case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': - value = (value << 4) + c - 'a' + 10; - break; - case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': - value = (value << 4) + c - 'A' + 10; - break; - } - } - return (char) value; - } -} diff --git a/src/main/java/com/rabbitmq/tools/json/JSONSerializable.java b/src/main/java/com/rabbitmq/tools/json/JSONSerializable.java deleted file mode 100644 index 39f72d4ac2..0000000000 --- a/src/main/java/com/rabbitmq/tools/json/JSONSerializable.java +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - - -package com.rabbitmq.tools.json; - -/** - * Interface for classes that wish to control their own serialization. - * - * Will be removed in 6.0 - * - * @deprecated Use a third-party JSON library, e.g. Jackson or Gson - */ -public interface JSONSerializable { - /** - * Called during serialization to JSON. - */ - void jsonSerialize(JSONWriter w); -} diff --git a/src/main/java/com/rabbitmq/tools/json/JSONWriter.java b/src/main/java/com/rabbitmq/tools/json/JSONWriter.java deleted file mode 100644 index 7101598040..0000000000 --- a/src/main/java/com/rabbitmq/tools/json/JSONWriter.java +++ /dev/null @@ -1,293 +0,0 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - -/* - Copyright (c) 2006-2007 Frank Carver - Copyright (c) 2007-2016 Pivotal Software, Inc. All Rights Reserved - - Licensed 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. -*/ -/* - * Based on org.stringtree.json.JSONWriter, licensed under APL and - * LGPL. We've chosen APL (see above). The original code was written - * by Frank Carver. Tony Garnock-Jones has made many changes to it - * since then. - */ -package com.rabbitmq.tools.json; - -import java.beans.BeanInfo; -import java.beans.IntrospectionException; -import java.beans.Introspector; -import java.beans.PropertyDescriptor; -import java.lang.reflect.Array; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.text.CharacterIterator; -import java.text.StringCharacterIterator; -import java.util.Collection; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; - -/** - * Will be removed in 6.0 - * @deprecated Use a third-party JSON library, e.g. Jackson or Gson - */ -public class JSONWriter { - private boolean indentMode = false; - private int indentLevel = 0; - private final StringBuilder buf = new StringBuilder(); - - public JSONWriter() {} - - public JSONWriter(boolean indenting) { - indentMode = indenting; - } - - public boolean getIndentMode() { - return indentMode; - } - - public void setIndentMode(boolean value) { - indentMode = value; - } - - private void newline() { - if (indentMode) { - add('\n'); - for (int i = 0; i < indentLevel; i++) add(' '); - } - } - - public String write(Object object) { - buf.setLength(0); - value(object); - return buf.toString(); - } - - public String write(long n) { - return write(Long.valueOf(n)); - } - - public Object write(double d) { - return write(Double.valueOf(d)); - } - - public String write(char c) { - return write(Character.valueOf(c)); - } - - public String write(boolean b) { - return write(Boolean.valueOf(b)); - } - - @SuppressWarnings("unchecked") - private void value(Object object) { - if (object == null) add("null"); - else if (object instanceof JSONSerializable) { - ((JSONSerializable) object).jsonSerialize(this); - } else if (object instanceof Class) string(object); - else if (object instanceof Boolean) bool(((Boolean) object).booleanValue()); - else if (object instanceof Number) add(object); - else if (object instanceof String) string(object); - else if (object instanceof Character) string(object); - else if (object instanceof Map) map((Map) object); - else if (object.getClass().isArray()) array(object); - else if (object instanceof Collection) array(((Collection) object).iterator()); - else bean(object); - } - - private void bean(Object object) { - writeLimited(object.getClass(), object, null); - } - - /** - * Write only a certain subset of the object's properties and fields. - * @param klass the class to look up properties etc in - * @param object the object - * @param properties explicit list of property/field names to include - may be null for "all" - */ - public void writeLimited(Class klass, Object object, String[] properties) { - Set propertiesSet = null; - if (properties != null) { - propertiesSet = new HashSet(); - for (String p: properties) { - propertiesSet.add(p); - } - } - - add('{'); indentLevel += 2; newline(); - boolean needComma = false; - - BeanInfo info; - try { - info = Introspector.getBeanInfo(klass); - } catch (IntrospectionException ie) { - info = null; - } - - if (info != null) { - PropertyDescriptor[] props = info.getPropertyDescriptors(); - for (int i = 0; i < props.length; ++i) { - PropertyDescriptor prop = props[i]; - String name = prop.getName(); - if (propertiesSet == null && name.equals("class")) { - // We usually don't want the class in there. - continue; - } - if (propertiesSet == null || propertiesSet.contains(name)) { - Method accessor = prop.getReadMethod(); - if (accessor != null && !Modifier.isStatic(accessor.getModifiers())) { - try { - Object value = accessor.invoke(object, (Object[])null); - if (needComma) { add(','); newline(); } - needComma = true; - add(name, value); - } catch (Exception e) { - // Ignore it. - } - } - } - } - } - - Field[] ff = object.getClass().getDeclaredFields(); - for (int i = 0; i < ff.length; ++i) { - Field field = ff[i]; - int fieldMod = field.getModifiers(); - String name = field.getName(); - if (propertiesSet == null || propertiesSet.contains(name)) { - if (!Modifier.isStatic(fieldMod)) { - try { - Object v = field.get(object); - if (needComma) { add(','); newline(); } - needComma = true; - add(name, v); - } catch (Exception e) { - // Ignore it. - } - } - } - } - - indentLevel -= 2; newline(); add('}'); - } - - private void add(String name, Object value) { - add('"'); - add(name); - add("\":"); - value(value); - } - - private void map(Map map) { - add('{'); indentLevel += 2; newline(); - Iterator it = map.keySet().iterator(); - if (it.hasNext()) { - mapEntry(it.next(), map); - } - while (it.hasNext()) { - add(','); newline(); - Object key = it.next(); - value(key); - add(':'); - value(map.get(key)); - } - indentLevel -= 2; newline(); add('}'); - } - private void mapEntry(Object key, Map map) { - value(key); - add(':'); - value(map.get(key)); - } - - private void array(Iterator it) { - add('['); - if (it.hasNext()) value(it.next()); - while (it.hasNext()) { - add(','); - value(it.next()); - } - add(']'); - } - - private void array(Object object) { - add('['); - int length = Array.getLength(object); - if (length > 0) value(Array.get(object, 0)); - for (int i = 1; i < length; ++i) { - add(','); - value(Array.get(object, i)); - } - add(']'); - } - - private void bool(boolean b) { - add(b ? "true" : "false"); - } - - private void string(Object obj) { - add('"'); - CharacterIterator it = new StringCharacterIterator(obj.toString()); - for (char c = it.first(); c != CharacterIterator.DONE; c = it.next()) { - if (c == '"') add("\\\""); - else if (c == '\\') add("\\\\"); - else if (c == '/') add("\\/"); - else if (c == '\b') add("\\b"); - else if (c == '\f') add("\\f"); - else if (c == '\n') add("\\n"); - else if (c == '\r') add("\\r"); - else if (c == '\t') add("\\t"); - else if (Character.isISOControl(c)) { - unicode(c); - } else { - add(c); - } - } - add('"'); - } - - private void add(Object obj) { - buf.append(obj); - } - - private void add(char c) { - buf.append(c); - } - - static final char[] hex = "0123456789ABCDEF".toCharArray(); - - private void unicode(char c) { - add("\\u"); - int n = c; - for (int i = 0; i < 4; ++i) { - int digit = (n & 0xf000) >> 12; - add(hex[digit]); - n <<= 4; - } - } -} diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/DefaultJsonRpcMapper.java b/src/main/java/com/rabbitmq/tools/jsonrpc/DefaultJsonRpcMapper.java deleted file mode 100644 index b40789e380..0000000000 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/DefaultJsonRpcMapper.java +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - -package com.rabbitmq.tools.jsonrpc; - -import com.rabbitmq.tools.json.JSONReader; -import com.rabbitmq.tools.json.JSONWriter; - -import java.util.List; -import java.util.Map; - -/** - * Simple {@link JsonRpcMapper} based on homegrown JSON utilities. - * Handles integers, doubles, strings, booleans, and arrays of those types. - *

- * For a more comprehensive set of features, use {@link JacksonJsonRpcMapper}. - *

- * Will be removed in 6.0 - * - * @see JsonRpcMapper - * @see JacksonJsonRpcMapper - * @since 5.4.0 - * @deprecated use {@link JacksonJsonRpcMapper} instead - */ -public class DefaultJsonRpcMapper implements JsonRpcMapper { - - @Override - public JsonRpcRequest parse(String requestBody, ServiceDescription description) { - @SuppressWarnings("unchecked") - Map request = (Map) new JSONReader().read(requestBody); - return new JsonRpcRequest( - request.get("id"), request.get("version").toString(), request.get("method").toString(), - ((List) request.get("params")).toArray() - ); - } - - @Override - public JsonRpcResponse parse(String responseBody, Class expectedType) { - @SuppressWarnings("unchecked") - Map map = (Map) (new JSONReader().read(responseBody)); - Map error; - JsonRpcException exception = null; - if (map.containsKey("error")) { - error = (Map) map.get("error"); - exception = new JsonRpcException( - new JSONWriter().write(error), - (String) error.get("name"), - error.get("code") == null ? 0 : (Integer) error.get("code"), - (String) error.get("message"), - error - ); - } - return new JsonRpcResponse(map.get("result"), map.get("error"), exception); - } - - @Override - public String write(Object input) { - return new JSONWriter().write(input); - } -} diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java index f64b9f47f0..9b90a0323b 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java @@ -18,7 +18,6 @@ import com.rabbitmq.client.Channel; import com.rabbitmq.client.RpcClient; import com.rabbitmq.client.ShutdownSignalException; -import com.rabbitmq.tools.json.JSONReader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -55,7 +54,6 @@ * a {@link JsonRpcMapper}. * * @see #call(String, Object[]) - * @see #call(String[]) * @see JsonRpcMapper * @see JacksonJsonRpcMapper */ @@ -91,7 +89,7 @@ public JsonRpcClient(Channel channel, String exchange, String routingKey, int ti */ public JsonRpcClient(Channel channel, String exchange, String routingKey, int timeout) throws IOException, JsonRpcException, TimeoutException { - this(channel, exchange, routingKey, timeout, new DefaultJsonRpcMapper()); + this(channel, exchange, routingKey, timeout, new JacksonJsonRpcMapper()); } public JsonRpcClient(Channel channel, String exchange, String routingKey) @@ -99,31 +97,6 @@ public JsonRpcClient(Channel channel, String exchange, String routingKey) this(channel, exchange, routingKey, RpcClient.NO_TIMEOUT); } - /** - * Private API - used by {@link #call(String[])} to ad-hoc convert - * strings into the required data types for a call. - */ - public static Object coerce(String val, String type) - throws NumberFormatException { - if ("bit".equals(type)) { - return Boolean.getBoolean(val) ? Boolean.TRUE : Boolean.FALSE; - } else if ("num".equals(type)) { - try { - return Integer.valueOf(val); - } catch (NumberFormatException nfe) { - return Double.valueOf(val); - } - } else if ("str".equals(type)) { - return val; - } else if ("arr".equals(type) || "obj".equals(type) || "any".equals(type)) { - return new JSONReader().read(val); - } else if ("nil".equals(type)) { - return null; - } else { - throw new IllegalArgumentException("Bad type: " + type); - } - } - /** * Private API - parses a JSON-RPC reply object, checking it for exceptions. * @@ -197,37 +170,7 @@ public T createProxy(Class klass) this); } - /** - * Public API - as {@link #call(String, Object[])}, but takes the - * method name from the first entry in args, and the - * parameters from subsequent entries. All parameter values are - * passed through coerce() to attempt to make them the types the - * server is expecting. - * - * @return the result contained within the reply, if no exception is found - * @throws JsonRpcException if the reply object contained an exception - * @throws NumberFormatException if a coercion failed - * @throws TimeoutException if a response is not received within the timeout specified, if any - * @see #coerce - */ - public Object call(String[] args) - throws NumberFormatException, IOException, JsonRpcException, TimeoutException { - if (args.length == 0) { - throw new IllegalArgumentException("First string argument must be method name"); - } - - String method = args[0]; - int arity = args.length - 1; - ProcedureDescription proc = serviceDescription.getProcedure(method, arity); - ParameterDescription[] params = proc.getParams(); - Object[] actuals = new Object[arity]; - for (int count = 0; count < params.length; count++) { - actuals[count] = coerce(args[count + 1], params[count].type); - } - - return call(method, actuals); - } /** * Public API - gets the service description record that this diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java index 723664c3b5..ec22770e7f 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java @@ -85,7 +85,7 @@ public JsonRpcServer(Channel channel, Class interfaceClass, Object interfaceInstance) throws IOException { - this(channel, interfaceClass, interfaceInstance, new DefaultJsonRpcMapper()); + this(channel, interfaceClass, interfaceInstance, new JacksonJsonRpcMapper()); } public JsonRpcServer(Channel channel, @@ -115,7 +115,7 @@ public JsonRpcServer(Channel channel, Class interfaceClass, Object interfaceInstance) throws IOException { - this(channel, queueName, interfaceClass, interfaceInstance, new DefaultJsonRpcMapper()); + this(channel, queueName, interfaceClass, interfaceInstance, new JacksonJsonRpcMapper()); } private void init(Class interfaceClass, Object interfaceInstance) { diff --git a/src/test/java/com/rabbitmq/client/DefaultJsonRpcTest.java b/src/test/java/com/rabbitmq/client/DefaultJsonRpcTest.java deleted file mode 100644 index 049554d1d2..0000000000 --- a/src/test/java/com/rabbitmq/client/DefaultJsonRpcTest.java +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - -package com.rabbitmq.client; - -import com.rabbitmq.tools.jsonrpc.DefaultJsonRpcMapper; -import com.rabbitmq.tools.jsonrpc.JsonRpcException; -import com.rabbitmq.tools.jsonrpc.JsonRpcMapper; -import org.junit.Test; - -import java.lang.reflect.UndeclaredThrowableException; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -public class DefaultJsonRpcTest extends AbstractJsonRpcTest { - - @Override - JsonRpcMapper createMapper() { - return new DefaultJsonRpcMapper(); - } - - @Test - public void rpc() { - assertFalse(service.procedurePrimitiveBoolean(true)); - assertFalse(service.procedureBoolean(Boolean.TRUE).booleanValue()); - assertEquals("hello1", service.procedureString("hello")); - assertEquals(2, service.procedureInteger(1).intValue()); - assertEquals(2, service.procedurePrimitiveInteger(1)); - assertEquals(2, service.procedureDouble(1.0).intValue()); - assertEquals(2, (int) service.procedurePrimitiveDouble(1.0)); - service.procedureNoArgumentVoid(); - - try { - service.procedureException(); - fail("Remote procedure throwing exception, an exception should have been thrown"); - } catch (UndeclaredThrowableException e) { - assertTrue(e.getCause() instanceof JsonRpcException); - } - - try { - assertEquals(2, (int) service.procedureLongToInteger(1L)); - fail("Long argument isn't supported"); - } catch (UndeclaredThrowableException e) { - // OK - } - assertEquals(2, service.procedurePrimitiveLongToInteger(1L)); - - try { - assertEquals(2, service.procedurePrimitiveLong(1L)); - fail("Long return type not supported"); - } catch (ClassCastException e) { - // OK - } - - try { - assertEquals(2, service.procedureLong(1L).longValue()); - fail("Long argument isn't supported"); - } catch (UndeclaredThrowableException e) { - // OK - } - - try { - assertEquals("123", service.procedureIntegerToPojo(123).getStringProperty()); - fail("Complex return type not supported"); - } catch (ClassCastException e) { - // OK - } - - try { - Pojo pojo = new Pojo(); - pojo.setStringProperty("hello"); - assertEquals("hello", service.procedurePojoToString(pojo)); - fail("Complex type argument not supported"); - } catch (UndeclaredThrowableException e) { - // OK - } - } -} \ No newline at end of file diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index 73a11f5af7..984ed83085 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -17,7 +17,6 @@ package com.rabbitmq.client.test; import com.rabbitmq.client.JacksonJsonRpcTest; -import com.rabbitmq.client.DefaultJsonRpcTest; import com.rabbitmq.utility.IntAllocatorTests; import org.junit.runner.RunWith; import org.junit.runners.Suite; @@ -42,7 +41,6 @@ IntAllocatorTests.class, AMQBuilderApiTest.class, AmqpUriTest.class, - JSONReadWriteTest.class, SharedThreadPoolTest.class, DnsRecordIpAddressResolverTests.class, MetricsCollectorTest.class, @@ -62,7 +60,6 @@ TestUtilsTest.class, StrictExceptionHandlerTest.class, NoAutoRecoveryWhenTcpWindowIsFullTest.class, - DefaultJsonRpcTest.class, JacksonJsonRpcTest.class, AddressTest.class, DefaultRetryHandlerTest.class, diff --git a/src/test/java/com/rabbitmq/client/test/JSONReadWriteTest.java b/src/test/java/com/rabbitmq/client/test/JSONReadWriteTest.java deleted file mode 100644 index 44f322f2e0..0000000000 --- a/src/test/java/com/rabbitmq/client/test/JSONReadWriteTest.java +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - - -package com.rabbitmq.client.test; - -import com.rabbitmq.tools.json.JSONReader; -import com.rabbitmq.tools.json.JSONWriter; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -public class JSONReadWriteTest { - - @Test public void readWriteSimple() throws Exception { - - Object myRet; - String myJson; - - // simple string - myRet = new JSONReader().read(myJson = new JSONWriter().write("blah")); - assertEquals("blah", myRet); - - // simple int - myRet = new JSONReader().read(myJson = new JSONWriter().write(1)); - assertEquals(1, myRet); - - // string with double quotes - myRet = new JSONReader().read(myJson = new JSONWriter().write("t1-blah\"blah")); - assertEquals("t1-blah\"blah", myRet); - // string with single quotes - myRet = new JSONReader().read(myJson = new JSONWriter().write("t2-blah'blah")); - assertEquals("t2-blah'blah", myRet); - // string with two double quotes - myRet = new JSONReader().read(myJson = new JSONWriter().write("t3-blah\"n\"blah")); - assertEquals("t3-blah\"n\"blah", myRet); - // string with two single quotes - myRet = new JSONReader().read(myJson = new JSONWriter().write("t4-blah'n'blah")); - assertEquals("t4-blah'n'blah", myRet); - // string with a single and a double quote - myRet = new JSONReader().read(myJson = new JSONWriter().write("t4-blah'n\"blah")); - assertEquals("t4-blah'n\"blah", myRet); - - // UTF-8 character - myRet = new JSONReader().read(myJson = new JSONWriter().write("smile \u9786")); - assertEquals("smile \u9786", myRet); - - // null byte - myRet = new JSONReader().read(myJson = new JSONWriter().write("smile \u0000")); - assertEquals("smile \u0000", myRet); - - } - - @Test public void moreComplicated() throws Exception { - - String v, s; - Object t; - - s = "[\"foo\",{\"bar\":[\"baz\",null,1.0,2]}]"; - v = new JSONWriter().write(new JSONReader().read(s)); - assertEquals(s, v); - - s = "[\"foo\",{\"bar\":[\"b\\\"az\",null,1.0,2]}]"; - t = new JSONReader().read(s); - v = new JSONWriter().write(t); - assertEquals(s, v); - - s = "[\"foo\",{\"bar\":[\"b'az\",null,1.0,2]}]"; - v = new JSONWriter().write(new JSONReader().read(s)); - assertEquals(s, v); - - s = "[\"foo\",{\"bar\":[\"b'a'z\",null,1.0,2]}]"; - v = new JSONWriter().write(new JSONReader().read(s)); - assertEquals(s, v); - - s = "[\"foo\",{\"bar\":[\"b\\\"a\\\"z\",null,1.0,2]}]"; - v = new JSONWriter().write(new JSONReader().read(s)); - assertEquals(s, v); - - } - - @Test public void badJSON() throws Exception { - - try { - new JSONReader().read("[\"foo\",{\"bar\":[\"b\"az\",null,1.0,2]}]"); - fail("Should not have parsed"); - } - catch (IllegalStateException e) {} - - try { - new JSONReader().read("[\"foo\",{\"bar\":[\"b\"a\"z\",null,1.0,2]}]"); - fail("Should not have parsed"); - } - catch (IllegalStateException e) {} - - } - -} From 3f079cf54c6960d759c32e0859760a5a7900adfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 17 Aug 2018 10:38:31 +0200 Subject: [PATCH 0866/2114] Deprecate methods in JSON RPC support References #378, #391 --- .../rabbitmq/tools/jsonrpc/JsonRpcClient.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java index f64b9f47f0..913cdc34b8 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java @@ -55,7 +55,6 @@ * a {@link JsonRpcMapper}. * * @see #call(String, Object[]) - * @see #call(String[]) * @see JsonRpcMapper * @see JacksonJsonRpcMapper */ @@ -102,7 +101,15 @@ public JsonRpcClient(Channel channel, String exchange, String routingKey) /** * Private API - used by {@link #call(String[])} to ad-hoc convert * strings into the required data types for a call. + * + * This method is deprecated because it uses homegrown JSON utilities + * that don't deal correctly with complex types. The {@link JacksonJsonRpcMapper} + * has been introduced to handle primitive and complex types, as well + * as primitive wrappers correctly. + * + * @deprecated This method will be removed in the next major version */ + @Deprecated public static Object coerce(String val, String type) throws NumberFormatException { if ("bit".equals(type)) { @@ -204,12 +211,19 @@ public T createProxy(Class klass) * passed through coerce() to attempt to make them the types the * server is expecting. * + * This method is deprecated because it uses homegrown JSON utilities + * that don't deal correctly with complex types. The {@link JacksonJsonRpcMapper} + * has been introduced to handle primitive and complex types, as well + * as primitive wrappers correctly. + * * @return the result contained within the reply, if no exception is found * @throws JsonRpcException if the reply object contained an exception * @throws NumberFormatException if a coercion failed * @throws TimeoutException if a response is not received within the timeout specified, if any * @see #coerce + * @deprecated This method will be removed in the next major version */ + @Deprecated public Object call(String[] args) throws NumberFormatException, IOException, JsonRpcException, TimeoutException { if (args.length == 0) { From 149b6c7cb598146e03458197cb03d4a7659d517c Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 17 Aug 2018 15:36:35 +0300 Subject: [PATCH 0867/2114] Stronger language around ConnectionFactory methods that enable TLS with a permissive TrustManager Make it clear which methods are offered for convenience in development environments. --- .../rabbitmq/client/ConnectionFactory.java | 48 ++++++++++++------- .../client/TrustEverythingTrustManager.java | 12 +++-- 2 files changed, 38 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 0816abdde3..279a015af7 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -653,12 +653,14 @@ public boolean isSSL(){ } /** - * Convenience method for setting up a SSL socket factory/engine, using - * the DEFAULT_SSL_PROTOCOL and a trusting TrustManager. - * Note the trust manager will trust every server certificate presented + * Convenience method for configuring TLS using + * the default set of TLS protocols and a trusting TrustManager. + * This setup is only suitable for development + * and QA environments. + * The trust manager will trust every server certificate presented * to it, this is convenient for local development but - * not recommended to use in production as it provides no protection - * against man-in-the-middle attacks. + * not recommended to use in production as it provides no protection + * against man-in-the-middle attacks. Prefer {@link #useSslProtocol(SSLContext)}. */ public void useSslProtocol() throws NoSuchAlgorithmException, KeyManagementException @@ -667,15 +669,19 @@ public void useSslProtocol() } /** - * Convenience method for setting up a SSL socket factory/engine, using - * the supplied protocol and a very trusting TrustManager. - * Note the trust manager will trust every server certificate presented + * Convenience method for configuring TLS using + * the supplied protocol and a very trusting TrustManager. This setup is only suitable for development + * and QA environments. + * The trust manager will trust every server certificate presented * to it, this is convenient for local development but - * not recommended to use in production as it provides no protection - * against man-in-the-middle attacks. + * not recommended to use in production as it provides no protection + * against man-in-the-middle attacks. + * + * Use {@link #useSslProtocol(SSLContext)} in production environments. * The produced {@link SSLContext} instance will be shared by all - * the connections created by this connection factory. Use - * {@link #setSslContextFactory(SslContextFactory)} for more flexibility. + * the connections created by this connection factory. + * + * Use {@link #setSslContextFactory(SslContextFactory)} for more flexibility. * @see #setSslContextFactory(SslContextFactory) */ public void useSslProtocol(String protocol) @@ -685,13 +691,18 @@ public void useSslProtocol(String protocol) } /** - * Convenience method for setting up an SSL socket factory/engine. - * Pass in the SSL protocol to use, e.g. "TLSv1" or "TLSv1.2". + * Convenience method for configuring TLS. + * Pass in the TLS protocol version to use, e.g. "TLSv1.2" or "TLSv1.1", and + * a desired {@link TrustManager}. + * + * * The produced {@link SSLContext} instance will be shared with all * the connections created by this connection factory. Use * {@link #setSslContextFactory(SslContextFactory)} for more flexibility. - * @param protocol SSL protocol to use. + * @param protocol the TLS protocol to use. + * @param trustManager the {@link TrustManager} implementation to use. * @see #setSslContextFactory(SslContextFactory) + * @see #useSslProtocol(SSLContext) */ public void useSslProtocol(String protocol, TrustManager trustManager) throws NoSuchAlgorithmException, KeyManagementException @@ -702,8 +713,11 @@ public void useSslProtocol(String protocol, TrustManager trustManager) } /** - * Convenience method for setting up an SSL socket socketFactory/engine. - * Pass in an initialized SSLContext. + * Sets up TLS with an initialized {@link SSLContext}. The caller is responsible + * for setting up the context with a {@link TrustManager} with suitable security guarantees, + * e.g. peer verification. + * + * * The {@link SSLContext} instance will be shared with all * the connections created by this connection factory. Use * {@link #setSslContextFactory(SslContextFactory)} for more flexibility. diff --git a/src/main/java/com/rabbitmq/client/TrustEverythingTrustManager.java b/src/main/java/com/rabbitmq/client/TrustEverythingTrustManager.java index d4f7e5dae6..7893eb7e16 100644 --- a/src/main/java/com/rabbitmq/client/TrustEverythingTrustManager.java +++ b/src/main/java/com/rabbitmq/client/TrustEverythingTrustManager.java @@ -22,16 +22,18 @@ import java.security.cert.X509Certificate; /** - * Convenience class providing a default implementation of javax.net.ssl.X509TrustManager. - * Trusts every single certificate presented to it. + * Convenience class providing a default implementation of {@link javax.net.ssl.X509TrustManager}. + * Trusts every single certificate presented to it. This implementation does not perform peer + * verification and provides no protection against Man-in-the-Middle (MITM) attacks and therefore + * only suitable for some development and QA environments. */ public class TrustEverythingTrustManager implements X509TrustManager { public TrustEverythingTrustManager() { LoggerFactory.getLogger(TrustEverythingTrustManager.class).warn( - "This trust manager trusts every certificate, effectively disabling peer verification. " + - "This is convenient for local development but prone to man-in-the-middle attacks. " + - "Please see http://www.rabbitmq.com/ssl.html#validating-cerficates to learn more about peer certificate validation." + "SECURITY ALERT: this trust manager trusts every certificate, effectively disabling peer verification. " + + "This is convenient for local development but offers no protection against man-in-the-middle attacks. " + + "Please see https://www.rabbitmq.com/ssl.html#validating-cerficates to learn more about peer certificate verification." ); } From 2e6bf274f04a06299a484daff3f666c00be15ffd Mon Sep 17 00:00:00 2001 From: Casper Mout Date: Mon, 20 Aug 2018 13:26:38 +0200 Subject: [PATCH 0868/2114] Handle realTag = 0 in RecoveryAwareChannelN --- .../impl/recovery/RecoveryAwareChannelN.java | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java index d910da496c..faaa095bf6 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java @@ -84,21 +84,27 @@ private AMQImpl.Basic.Deliver offsetDeliveryTag(AMQImpl.Basic.Deliver method) { @Override public void basicAck(long deliveryTag, boolean multiple) throws IOException { long realTag = deliveryTag - activeDeliveryTagOffset; - // 0 tag means ack all when multiple is set - if (realTag > 0 || (multiple && realTag == 0)) { - transmit(new Basic.Ack(realTag, multiple)); - metricsCollector.basicAck(this, deliveryTag, multiple); + if(multiple && deliveryTag == 0) { + // 0 tag means ack all when multiple is set + realTag = 0; + } else if(realTag <= 0) { + return; } + transmit(new Basic.Ack(realTag, multiple)); + metricsCollector.basicAck(this, deliveryTag, multiple); } @Override public void basicNack(long deliveryTag, boolean multiple, boolean requeue) throws IOException { long realTag = deliveryTag - activeDeliveryTagOffset; - // 0 tag means nack all when multiple is set - if (realTag > 0 || (multiple && realTag == 0)) { - transmit(new Basic.Nack(realTag, multiple, requeue)); - metricsCollector.basicNack(this, deliveryTag); + if(multiple && deliveryTag == 0) { + // 0 tag means nack all when multiple is set + realTag = 0; + } else if(realTag <= 0) { + return; } + transmit(new Basic.Nack(realTag, multiple, requeue)); + metricsCollector.basicNack(this, deliveryTag); } @Override From 763345f93a7338cf1cc9dd23d2508a25a2995e58 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Mon, 20 Aug 2018 16:42:27 +0300 Subject: [PATCH 0869/2114] Drive by change: suppress a warning --- .../java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java index 9cb5411b25..2b8b349b70 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java @@ -127,6 +127,7 @@ public JsonRpcRequest parse(String requestBody, ServiceDescription description) } @Override + @SuppressWarnings("unchecked") public JsonRpcResponse parse(String responseBody, Class expectedReturnType) { JsonFactory jsonFactory = new MappingJsonFactory(); Object result = null; From 73827afcf01315ed6c1dceb84a8781938f3e4878 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Mon, 20 Aug 2018 16:42:52 +0300 Subject: [PATCH 0870/2114] Explain the idea behind recovery-aware channels --- .../impl/recovery/RecoveryAwareChannelN.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java index faaa095bf6..c3cc81bed6 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java @@ -31,6 +31,15 @@ * tags and avoids sending

basic.ack
,
basic.nack
, and
basic.reject
* for stale tags. * + * Consider a long running task a consumer has to perform. Say, it takes 15 minutes to complete. In the + * 15 minute window there is a reasonable chance of connection failure and recovery events. All delivery tags + * for the deliveries being processed won't be valid after recovery because they are "reset" for + * newly opened channels. This channel implementation will avoid sending out acknowledgements for such + * stale delivery tags and avoid a guaranteed channel-level exception (and thus channel closure). + * + * This is a sufficient solution in practice because all unacknowledged deliveries will be requeued + * by RabbitMQ automatically when it detects client connection loss. + * * @since 3.3.0 */ public class RecoveryAwareChannelN extends ChannelN { @@ -84,10 +93,16 @@ private AMQImpl.Basic.Deliver offsetDeliveryTag(AMQImpl.Basic.Deliver method) { @Override public void basicAck(long deliveryTag, boolean multiple) throws IOException { long realTag = deliveryTag - activeDeliveryTagOffset; + // Last delivery is likely the same one a long running consumer is still processing, + // so realTag might end up being 0. + // has a special meaning in the protocol ("acknowledge all unacknowledged tags), + // so if the user explicitly asks for that with multiple = true, do it. if(multiple && deliveryTag == 0) { // 0 tag means ack all when multiple is set realTag = 0; } else if(realTag <= 0) { + // delivery tags start at 1, so the real tag is stale + // therefore we should do nothing return; } transmit(new Basic.Ack(realTag, multiple)); @@ -96,11 +111,14 @@ public void basicAck(long deliveryTag, boolean multiple) throws IOException { @Override public void basicNack(long deliveryTag, boolean multiple, boolean requeue) throws IOException { + // See the comment in basicAck above. long realTag = deliveryTag - activeDeliveryTagOffset; if(multiple && deliveryTag == 0) { // 0 tag means nack all when multiple is set realTag = 0; } else if(realTag <= 0) { + // delivery tags start at 1, so the real tag is stale + // therefore we should do nothing return; } transmit(new Basic.Nack(realTag, multiple, requeue)); @@ -109,6 +127,9 @@ public void basicNack(long deliveryTag, boolean multiple, boolean requeue) throw @Override public void basicReject(long deliveryTag, boolean requeue) throws IOException { + // note that the basicAck comment above does not apply + // here since basic.reject doesn't support rejecting + // multiple deliveries at once long realTag = deliveryTag - activeDeliveryTagOffset; if (realTag > 0) { transmit(new Basic.Reject(realTag, requeue)); From fcc3dbb5f797e7e340b6ddc5c2faa2fc77a1c905 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 20 Aug 2018 17:50:32 +0200 Subject: [PATCH 0871/2114] Add opt-in to enable server hostname verification Hostname verification isn't performed by default in the TLS handshake, this commit makes it easier to enable server hostname verification for both blocking and non-blocking IO modes. References #394 --- .../rabbitmq/client/ConnectionFactory.java | 52 +++++- .../client/SocketChannelConfigurator.java | 16 ++ .../client/SocketChannelConfigurators.java | 111 +++++++++++++ .../rabbitmq/client/SocketConfigurator.java | 20 +++ .../rabbitmq/client/SocketConfigurators.java | 153 ++++++++++++++++++ .../client/SslEngineConfigurator.java | 16 ++ .../client/SslEngineConfigurators.java | 116 +++++++++++++ .../rabbitmq/client/impl/nio/NioParams.java | 23 ++- .../ChannelRpcTimeoutIntegrationTest.java | 2 +- .../test/functional/UnexpectedFrames.java | 3 +- .../client/test/ssl/HostnameVerification.java | 104 ++++++++++++ .../test/ssl/NioTlsUnverifiedConnection.java | 7 +- .../rabbitmq/client/test/ssl/SSLTests.java | 3 +- .../client/test/ssl/UnverifiedConnection.java | 2 +- .../client/test/ssl/VerifiedConnection.java | 2 +- 15 files changed, 610 insertions(+), 20 deletions(-) create mode 100644 src/main/java/com/rabbitmq/client/SocketChannelConfigurators.java create mode 100644 src/main/java/com/rabbitmq/client/SocketConfigurators.java create mode 100644 src/main/java/com/rabbitmq/client/SslEngineConfigurators.java create mode 100644 src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 279a015af7..e9af65a6b5 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -15,8 +15,6 @@ package com.rabbitmq.client; -import static java.util.concurrent.TimeUnit.*; - import com.rabbitmq.client.impl.AMQConnection; import com.rabbitmq.client.impl.ConnectionParams; import com.rabbitmq.client.impl.CredentialsProvider; @@ -32,6 +30,10 @@ import com.rabbitmq.client.impl.recovery.RetryHandler; import com.rabbitmq.client.impl.recovery.TopologyRecoveryFilter; +import javax.net.SocketFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; @@ -50,10 +52,8 @@ import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeoutException; import java.util.function.Predicate; -import javax.net.SocketFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.TrustManager; + +import static java.util.concurrent.TimeUnit.MINUTES; /** * Convenience factory class to facilitate opening a {@link Connection} to a RabbitMQ node. @@ -132,7 +132,7 @@ public class ConnectionFactory implements Cloneable { // connections uses, see rabbitmq/rabbitmq-java-client#86 private ExecutorService shutdownExecutor; private ScheduledExecutorService heartbeatExecutor; - private SocketConfigurator socketConf = new DefaultSocketConfigurator(); + private SocketConfigurator socketConf = SocketConfigurators.defaultConfigurator(); private ExceptionHandler exceptionHandler = new DefaultExceptionHandler(); private CredentialsProvider credentialsProvider = new DefaultCredentialsProvider(DEFAULT_USER, DEFAULT_PASS); @@ -729,6 +729,44 @@ public void useSslProtocol(SSLContext context) { setSocketFactory(context.getSocketFactory()); } + /** + * Enable server hostname verification for TLS connections. + *

+ * This enables hostname verification regardless of the IO mode + * used (blocking or non-blocking IO). + *

+ * This can be called typically after setting the {@link SSLContext} + * with one of the useSslProtocol methods. + * + * @see NioParams#enableHostnameVerification() + * @see NioParams#setSslEngineConfigurator(SslEngineConfigurator) + * @see SslEngineConfigurators#ENABLE_HOSTNAME_VERIFICATION + * @see SocketConfigurators#ENABLE_HOSTNAME_VERIFICATION + * @see ConnectionFactory#useSslProtocol(String) + * @see ConnectionFactory#useSslProtocol(SSLContext) + * @see ConnectionFactory#useSslProtocol() + * @see ConnectionFactory#useSslProtocol(String, TrustManager) + */ + public void enableHostnameVerification() { + enableHostnameVerificationForNio(); + enableHostnameVerificationForBlockingIo(); + } + + protected void enableHostnameVerificationForNio() { + if (this.nioParams == null) { + this.nioParams = new NioParams(); + } + this.nioParams = this.nioParams.enableHostnameVerification(); + } + + protected void enableHostnameVerificationForBlockingIo() { + if (this.socketConf == null) { + this.socketConf = SocketConfigurators.builder().defaultConfigurator().enableHostnameVerification().build(); + } else { + this.socketConf = this.socketConf.andThen(SocketConfigurators.enableHostnameVerification()); + } + } + public static String computeDefaultTlsProcotol(String[] supportedProtocols) { if(supportedProtocols != null) { for (String supportedProtocol : supportedProtocols) { diff --git a/src/main/java/com/rabbitmq/client/SocketChannelConfigurator.java b/src/main/java/com/rabbitmq/client/SocketChannelConfigurator.java index 5aded698f9..ceb3a95a88 100644 --- a/src/main/java/com/rabbitmq/client/SocketChannelConfigurator.java +++ b/src/main/java/com/rabbitmq/client/SocketChannelConfigurator.java @@ -17,7 +17,9 @@ import java.io.IOException; import java.nio.channels.SocketChannel; +import java.util.Objects; +@FunctionalInterface public interface SocketChannelConfigurator { /** @@ -26,4 +28,18 @@ public interface SocketChannelConfigurator { */ void configure(SocketChannel socketChannel) throws IOException; + /** + * Returns a composed configurator that performs, in sequence, this + * operation followed by the {@code after} operation. + * + * @param after the operation to perform after this operation + * @return a composed configurator that performs in sequence this + * operation followed by the {@code after} operation + * @throws NullPointerException if {@code after} is null + */ + default SocketChannelConfigurator andThen(SocketChannelConfigurator after) { + Objects.requireNonNull(after); + return t -> { configure(t); after.configure(t); }; + } + } diff --git a/src/main/java/com/rabbitmq/client/SocketChannelConfigurators.java b/src/main/java/com/rabbitmq/client/SocketChannelConfigurators.java new file mode 100644 index 0000000000..d6af09d7de --- /dev/null +++ b/src/main/java/com/rabbitmq/client/SocketChannelConfigurators.java @@ -0,0 +1,111 @@ +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client; + +/** + * Ready-to-use instances and builder for {@link SocketChannelConfigurator}. + *

+ * Note {@link SocketChannelConfigurator}s can be combined with + * {@link SocketChannelConfigurator#andThen(SocketChannelConfigurator)}. + * + * @since 5.5.0 + */ +public abstract class SocketChannelConfigurators { + + /** + * Disable Nagle's algorithm. + */ + public static final SocketChannelConfigurator DISABLE_NAGLE_ALGORITHM = + socketChannel -> SocketConfigurators.DISABLE_NAGLE_ALGORITHM.configure(socketChannel.socket()); + + /** + * Default {@link SocketChannelConfigurator} that disables Nagle's algorithm. + */ + public static final SocketChannelConfigurator DEFAULT = DISABLE_NAGLE_ALGORITHM; + + /** + * The default {@link SocketChannelConfigurator} that disables Nagle's algorithm. + * + * @return + */ + public static SocketChannelConfigurator defaultConfigurator() { + return DEFAULT; + } + + /** + * {@link SocketChannelConfigurator} that disables Nagle's algorithm. + * + * @return + */ + public static SocketChannelConfigurator disableNagleAlgorithm() { + return DISABLE_NAGLE_ALGORITHM; + } + + /** + * Builder to configure and creates a {@link SocketChannelConfigurator} instance. + * + * @return + */ + public static SocketChannelConfigurators.Builder builder() { + return new SocketChannelConfigurators.Builder(); + } + + public static class Builder { + + private SocketChannelConfigurator configurator = channel -> { + }; + + /** + * Set default configuration. + * + * @return + */ + public Builder defaultConfigurator() { + configurator = configurator.andThen(DEFAULT); + return this; + } + + /** + * Disable Nagle's Algorithm. + * + * @return + */ + public Builder disableNagleAlgorithm() { + configurator = configurator.andThen(DISABLE_NAGLE_ALGORITHM); + return this; + } + + /** + * Add an extra configuration step. + * + * @param extraConfiguration + * @return + */ + public Builder add(SocketChannelConfigurator extraConfiguration) { + configurator = configurator.andThen(extraConfiguration); + return this; + } + + /** + * Return the configured {@link SocketConfigurator}. + * + * @return + */ + public SocketChannelConfigurator build() { + return configurator; + } + } +} diff --git a/src/main/java/com/rabbitmq/client/SocketConfigurator.java b/src/main/java/com/rabbitmq/client/SocketConfigurator.java index 8896baf3e5..30c9ed4bab 100644 --- a/src/main/java/com/rabbitmq/client/SocketConfigurator.java +++ b/src/main/java/com/rabbitmq/client/SocketConfigurator.java @@ -17,11 +17,31 @@ import java.io.IOException; import java.net.Socket; +import java.util.Objects; +@FunctionalInterface public interface SocketConfigurator { + /** * Provides a hook to insert custom configuration of the sockets * used to connect to an AMQP server before they connect. */ void configure(Socket socket) throws IOException; + + /** + * Returns a composed configurator that performs, in sequence, this + * operation followed by the {@code after} operation. + * + * @param after the operation to perform after this operation + * @return a composed configurator that performs in sequence this + * operation followed by the {@code after} operation + * @throws NullPointerException if {@code after} is null + */ + default SocketConfigurator andThen(SocketConfigurator after) { + Objects.requireNonNull(after); + return t -> { + configure(t); + after.configure(t); + }; + } } diff --git a/src/main/java/com/rabbitmq/client/SocketConfigurators.java b/src/main/java/com/rabbitmq/client/SocketConfigurators.java new file mode 100644 index 0000000000..127bddeb34 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/SocketConfigurators.java @@ -0,0 +1,153 @@ +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client; + +import javax.net.ssl.SSLParameters; +import javax.net.ssl.SSLSocket; + +/** + * Ready-to-use instances and builder for {@link SocketConfigurator}. + *

+ * Note {@link SocketConfigurator}s can be combined with + * {@link SocketConfigurator#andThen(SocketConfigurator)}. + * + * @since 5.5.0 + */ +public abstract class SocketConfigurators { + + /** + * Disable Nagle's algorithm. + */ + public static final SocketConfigurator DISABLE_NAGLE_ALGORITHM = socket -> socket.setTcpNoDelay(true); + + /** + * Default {@link SocketConfigurator} that disables Nagle's algorithm. + */ + public static final SocketConfigurator DEFAULT = DISABLE_NAGLE_ALGORITHM; + + /** + * Enable server hostname validation for TLS connections. + */ + public static final SocketConfigurator ENABLE_HOSTNAME_VERIFICATION = socket -> { + if (socket instanceof SSLSocket) { + SSLSocket sslSocket = (SSLSocket) socket; + SSLParameters sslParameters = enableHostnameVerification(sslSocket.getSSLParameters()); + sslSocket.setSSLParameters(sslParameters); + } + }; + + static final SSLParameters enableHostnameVerification(SSLParameters sslParameters) { + if (sslParameters == null) { + sslParameters = new SSLParameters(); + } + // It says HTTPS but works also for any TCP connection. + // It checks SAN (Subject Alternative Name) as well as CN. + sslParameters.setEndpointIdentificationAlgorithm("HTTPS"); + return sslParameters; + } + + /** + * The default {@link SocketConfigurator} that disables Nagle's algorithm. + * + * @return + */ + public static SocketConfigurator defaultConfigurator() { + return DEFAULT; + } + + /** + * {@link SocketConfigurator} that disables Nagle's algorithm. + * + * @return + */ + public static SocketConfigurator disableNagleAlgorithm() { + return DISABLE_NAGLE_ALGORITHM; + } + + /** + * {@link SocketConfigurator} that enable server hostname verification for TLS connections. + * + * @return + */ + public static SocketConfigurator enableHostnameVerification() { + return ENABLE_HOSTNAME_VERIFICATION; + } + + /** + * Builder to configure and creates a {@link SocketConfigurator} instance. + * + * @return + */ + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + + private SocketConfigurator configurator = socket -> { + }; + + /** + * Set default configuration. + * + * @return + */ + public Builder defaultConfigurator() { + configurator = configurator.andThen(DEFAULT); + return this; + } + + /** + * Disable Nagle's Algorithm. + * + * @return + */ + public Builder disableNagleAlgorithm() { + configurator = configurator.andThen(DISABLE_NAGLE_ALGORITHM); + return this; + } + + /** + * Enable server hostname verification for TLS connections. + * + * @return + */ + public Builder enableHostnameVerification() { + configurator = configurator.andThen(ENABLE_HOSTNAME_VERIFICATION); + return this; + } + + /** + * Add an extra configuration step. + * + * @param extraConfiguration + * @return + */ + public Builder add(SocketConfigurator extraConfiguration) { + configurator = configurator.andThen(extraConfiguration); + return this; + } + + /** + * Return the configured {@link SocketConfigurator}. + * + * @return + */ + public SocketConfigurator build() { + return configurator; + } + } +} diff --git a/src/main/java/com/rabbitmq/client/SslEngineConfigurator.java b/src/main/java/com/rabbitmq/client/SslEngineConfigurator.java index 7986d4b9d2..01b22c4c05 100644 --- a/src/main/java/com/rabbitmq/client/SslEngineConfigurator.java +++ b/src/main/java/com/rabbitmq/client/SslEngineConfigurator.java @@ -17,7 +17,9 @@ import javax.net.ssl.SSLEngine; import java.io.IOException; +import java.util.Objects; +@FunctionalInterface public interface SslEngineConfigurator { /** @@ -27,4 +29,18 @@ public interface SslEngineConfigurator { */ void configure(SSLEngine sslEngine) throws IOException; + /** + * Returns a composed configurator that performs, in sequence, this + * operation followed by the {@code after} operation. + * + * @param after the operation to perform after this operation + * @return a composed configurator that performs in sequence this + * operation followed by the {@code after} operation + * @throws NullPointerException if {@code after} is null + */ + default SslEngineConfigurator andThen(SslEngineConfigurator after) { + Objects.requireNonNull(after); + return t -> { configure(t); after.configure(t); }; + } + } diff --git a/src/main/java/com/rabbitmq/client/SslEngineConfigurators.java b/src/main/java/com/rabbitmq/client/SslEngineConfigurators.java new file mode 100644 index 0000000000..d84dfa304f --- /dev/null +++ b/src/main/java/com/rabbitmq/client/SslEngineConfigurators.java @@ -0,0 +1,116 @@ +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client; + +import javax.net.ssl.SSLParameters; + +/** + * Ready-to-use instances and builder for {@link SslEngineConfigurator}s. + *

+ * Note {@link SslEngineConfigurator}s can be combined with + * {@link SslEngineConfigurator#andThen(SslEngineConfigurator)}. + * + * @since 5.5.0 + */ +public abstract class SslEngineConfigurators { + + /** + * Default {@link SslEngineConfigurator}, does nothing. + */ + public static SslEngineConfigurator DEFAULT = sslEngine -> { + }; + + /** + * {@link SslEngineConfigurator} that enables server hostname verification. + */ + public static SslEngineConfigurator ENABLE_HOSTNAME_VERIFICATION = sslEngine -> { + SSLParameters sslParameters = SocketConfigurators.enableHostnameVerification(sslEngine.getSSLParameters()); + sslEngine.setSSLParameters(sslParameters); + }; + + /** + * Default {@link SslEngineConfigurator}, does nothing. + * + * @return + */ + public static SslEngineConfigurator defaultConfigurator() { + return DEFAULT; + } + + /** + * {@link SslEngineConfigurator} that enables server hostname verification. + * + * @return + */ + public static SslEngineConfigurator enableHostnameVerification() { + return ENABLE_HOSTNAME_VERIFICATION; + } + + /** + * Builder to configure and creates a {@link SslEngineConfigurator} instance. + * + * @return + */ + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + + private SslEngineConfigurator configurator = channel -> { + }; + + /** + * Set default configuration (no op). + * + * @return + */ + public Builder defaultConfigurator() { + configurator = configurator.andThen(DEFAULT); + return this; + } + + /** + * Enables server hostname verification. + * + * @return + */ + public Builder enableHostnameVerification() { + configurator = configurator.andThen(ENABLE_HOSTNAME_VERIFICATION); + return this; + } + + /** + * Add extra configuration step. + * + * @param extraConfiguration + * @return + */ + public Builder add(SslEngineConfigurator extraConfiguration) { + configurator = configurator.andThen(extraConfiguration); + return this; + } + + /** + * Return the configured {@link SslEngineConfigurator}. + * + * @return + */ + public SslEngineConfigurator build() { + return configurator; + } + } +} diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java b/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java index 9f9da61795..80b8624447 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java @@ -15,14 +15,16 @@ package com.rabbitmq.client.impl.nio; -import com.rabbitmq.client.DefaultSocketChannelConfigurator; import com.rabbitmq.client.SocketChannelConfigurator; +import com.rabbitmq.client.SocketChannelConfigurators; import com.rabbitmq.client.SslEngineConfigurator; import javax.net.ssl.SSLEngine; import java.util.concurrent.ExecutorService; import java.util.concurrent.ThreadFactory; +import static com.rabbitmq.client.SslEngineConfigurators.ENABLE_HOSTNAME_VERIFICATION; + /** * Parameters used to configure the NIO mode of a {@link com.rabbitmq.client.ConnectionFactory}. * @@ -68,7 +70,7 @@ public class NioParams { /** * the hook to configure the socket channel before it's open */ - private SocketChannelConfigurator socketChannelConfigurator = new DefaultSocketChannelConfigurator(); + private SocketChannelConfigurator socketChannelConfigurator = SocketChannelConfigurators.defaultConfigurator(); /** * the hook to configure the SSL engine before the connection is open @@ -94,10 +96,27 @@ public NioParams(NioParams nioParams) { setWriteQueueCapacity(nioParams.getWriteQueueCapacity()); setNioExecutor(nioParams.getNioExecutor()); setThreadFactory(nioParams.getThreadFactory()); + setSocketChannelConfigurator(nioParams.getSocketChannelConfigurator()); setSslEngineConfigurator(nioParams.getSslEngineConfigurator()); setConnectionShutdownExecutor(nioParams.getConnectionShutdownExecutor()); } + /** + * Enable server hostname verification for TLS connections. + * + * @return this {@link NioParams} instance + * @see NioParams#setSslEngineConfigurator(SslEngineConfigurator) + * @see com.rabbitmq.client.SslEngineConfigurators#ENABLE_HOSTNAME_VERIFICATION + */ + public NioParams enableHostnameVerification() { + if (this.sslEngineConfigurator == null) { + this.sslEngineConfigurator = ENABLE_HOSTNAME_VERIFICATION; + } else { + this.sslEngineConfigurator = this.sslEngineConfigurator.andThen(ENABLE_HOSTNAME_VERIFICATION); + } + return this; + } + public int getReadByteBufferSize() { return readByteBufferSize; } diff --git a/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java b/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java index 40d6a0ab5a..f880f617da 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java @@ -84,7 +84,7 @@ public void tearDown() throws Exception { private FrameHandler createFrameHandler() throws IOException { SocketFrameHandlerFactory socketFrameHandlerFactory = new SocketFrameHandlerFactory(ConnectionFactory.DEFAULT_CONNECTION_TIMEOUT, - SocketFactory.getDefault(), new DefaultSocketConfigurator(), false, null); + SocketFactory.getDefault(), SocketConfigurators.defaultConfigurator(), false, null); return socketFrameHandlerFactory.create(new Address("localhost"), null); } diff --git a/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java b/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java index 0ab8013969..698d8a8952 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java +++ b/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java @@ -18,6 +18,7 @@ import com.rabbitmq.client.AMQP; import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.DefaultSocketConfigurator; +import com.rabbitmq.client.SocketConfigurators; import com.rabbitmq.client.impl.*; import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; import com.rabbitmq.client.test.BrokerTestCase; @@ -85,7 +86,7 @@ public ConfusedConnectionFactory() { private static class ConfusedFrameHandlerFactory extends SocketFrameHandlerFactory { private ConfusedFrameHandlerFactory() { - super(1000, SocketFactory.getDefault(), new DefaultSocketConfigurator(), false); + super(1000, SocketFactory.getDefault(), SocketConfigurators.defaultConfigurator(), false); } @Override public FrameHandler create(Socket sock) throws IOException { diff --git a/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java new file mode 100644 index 0000000000..85f6f6735e --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java @@ -0,0 +1,104 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.test.ssl; + +import com.rabbitmq.client.Address; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.test.TestUtils; +import org.junit.Test; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLHandshakeException; +import javax.net.ssl.TrustManagerFactory; +import java.io.FileInputStream; +import java.io.IOException; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; +import java.util.concurrent.TimeoutException; + +import static java.util.Collections.singletonList; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + +public class HostnameVerification extends UnverifiedConnection { + + public void openConnection() + throws IOException, TimeoutException { + try { + String keystorePath = System.getProperty("test-keystore.ca"); + assertNotNull(keystorePath); + String keystorePasswd = System.getProperty("test-keystore.password"); + assertNotNull(keystorePasswd); + char[] keystorePassword = keystorePasswd.toCharArray(); + + KeyStore tks = KeyStore.getInstance("JKS"); + tks.load(new FileInputStream(keystorePath), keystorePassword); + + TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); + tmf.init(tks); + + String p12Path = System.getProperty("test-client-cert.path"); + assertNotNull(p12Path); + String p12Passwd = System.getProperty("test-client-cert.password"); + assertNotNull(p12Passwd); + KeyStore ks = KeyStore.getInstance("PKCS12"); + char[] p12Password = p12Passwd.toCharArray(); + ks.load(new FileInputStream(p12Path), p12Password); + + KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); + kmf.init(ks, p12Password); + + SSLContext c = getSSLContext(); + c.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); + c.init(null, tmf.getTrustManagers(), null); + + connectionFactory = TestUtils.connectionFactory(); + connectionFactory.useSslProtocol(c); + connectionFactory.enableHostnameVerification(); + } catch (NoSuchAlgorithmException ex) { + throw new IOException(ex.toString()); + } catch (KeyManagementException ex) { + throw new IOException(ex.toString()); + } catch (KeyStoreException ex) { + throw new IOException(ex.toString()); + } catch (CertificateException ex) { + throw new IOException(ex.toString()); + } catch (UnrecoverableKeyException ex) { + throw new IOException(ex.toString()); + } + + try { + connection = connectionFactory.newConnection( + () -> singletonList(new Address("127.0.0.1", ConnectionFactory.DEFAULT_AMQP_OVER_SSL_PORT))); + fail("The server certificate isn't issued for 127.0.0.1, the TLS handshake should have failed"); + } catch (SSLHandshakeException ignored) { + } catch (IOException e) { + fail(); + } + } + + public void openChannel() { + } + + @Test + public void sSL() { + } +} diff --git a/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java index 7312658894..07ac30a901 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java @@ -82,12 +82,7 @@ public void connectionGetConsume() throws Exception { connectionFactory.useSslProtocol(); NioParams nioParams = new NioParams(); final AtomicBoolean sslEngineHasBeenCalled = new AtomicBoolean(false); - nioParams.setSslEngineConfigurator(new SslEngineConfigurator() { - @Override - public void configure(SSLEngine sslEngine) throws IOException { - sslEngineHasBeenCalled.set(true); - } - }); + nioParams.setSslEngineConfigurator(sslEngine -> sslEngineHasBeenCalled.set(true)); connectionFactory.setNioParams(nioParams); diff --git a/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java index 21946066e6..679468a59f 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java @@ -32,7 +32,8 @@ VerifiedConnection.class, BadVerifiedConnection.class, ConnectionFactoryDefaultTlsVersion.class, - NioTlsUnverifiedConnection.class + NioTlsUnverifiedConnection.class, + HostnameVerification.class }) public class SSLTests { diff --git a/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java index 319ef82de9..6d65599b4c 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java @@ -54,7 +54,7 @@ public void openConnection() } } if(connection == null) { - fail("Couldn't open TLS connection after 3 attemps"); + fail("Couldn't open TLS connection after 3 attempts"); } } diff --git a/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java index 3083e6e2f2..e662113085 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java @@ -96,7 +96,7 @@ public void openConnection() } } if(connection == null) { - fail("Couldn't open TLS connection after 3 attemps"); + fail("Couldn't open TLS connection after 3 attempts"); } } } From d20e9a0cb933f355cfbb33da713f4f849dfb85b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 21 Aug 2018 09:38:07 +0200 Subject: [PATCH 0872/2114] Reduce number of queues in topology recovery retry test To mitigate test failure in CI environment. --- .../rabbitmq/client/test/functional/TopologyRecoveryRetry.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java index 71277c9826..273ebe1544 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java +++ b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java @@ -34,7 +34,7 @@ public class TopologyRecoveryRetry extends BrokerTestCase { @Test public void topologyRecoveryRetry() throws Exception { - int nbQueues = 2000; + int nbQueues = 200; String prefix = "topology-recovery-retry-" + System.currentTimeMillis(); for (int i = 0; i < nbQueues; i++) { String queue = prefix + i; From d3f47373b8ef259c82a6be26c4845d999d4e12a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 21 Aug 2018 09:38:07 +0200 Subject: [PATCH 0873/2114] Reduce number of queues in topology recovery retry test To mitigate test failure in CI environment. (cherry picked from commit d20e9a0cb933f355cfbb33da713f4f849dfb85b6) --- .../rabbitmq/client/test/functional/TopologyRecoveryRetry.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java index 71277c9826..273ebe1544 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java +++ b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java @@ -34,7 +34,7 @@ public class TopologyRecoveryRetry extends BrokerTestCase { @Test public void topologyRecoveryRetry() throws Exception { - int nbQueues = 2000; + int nbQueues = 200; String prefix = "topology-recovery-retry-" + System.currentTimeMillis(); for (int i = 0; i < nbQueues; i++) { String queue = prefix + i; From 5394d209f2d5f4a20ffc36e15b9bc58612f18a5d Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 17 Aug 2018 15:36:35 +0300 Subject: [PATCH 0874/2114] Stronger language around ConnectionFactory methods that enable TLS with a permissive TrustManager Make it clear which methods are offered for convenience in development environments. (cherry picked from commit 149b6c7cb598146e03458197cb03d4a7659d517c) --- .../rabbitmq/client/ConnectionFactory.java | 48 ++++++++++++------- .../client/TrustEverythingTrustManager.java | 12 +++-- 2 files changed, 38 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 0816abdde3..279a015af7 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -653,12 +653,14 @@ public boolean isSSL(){ } /** - * Convenience method for setting up a SSL socket factory/engine, using - * the DEFAULT_SSL_PROTOCOL and a trusting TrustManager. - * Note the trust manager will trust every server certificate presented + * Convenience method for configuring TLS using + * the default set of TLS protocols and a trusting TrustManager. + * This setup is only suitable for development + * and QA environments. + * The trust manager will trust every server certificate presented * to it, this is convenient for local development but - * not recommended to use in production as it provides no protection - * against man-in-the-middle attacks. + * not recommended to use in production as it provides no protection + * against man-in-the-middle attacks. Prefer {@link #useSslProtocol(SSLContext)}. */ public void useSslProtocol() throws NoSuchAlgorithmException, KeyManagementException @@ -667,15 +669,19 @@ public void useSslProtocol() } /** - * Convenience method for setting up a SSL socket factory/engine, using - * the supplied protocol and a very trusting TrustManager. - * Note the trust manager will trust every server certificate presented + * Convenience method for configuring TLS using + * the supplied protocol and a very trusting TrustManager. This setup is only suitable for development + * and QA environments. + * The trust manager will trust every server certificate presented * to it, this is convenient for local development but - * not recommended to use in production as it provides no protection - * against man-in-the-middle attacks. + * not recommended to use in production as it provides no protection + * against man-in-the-middle attacks. + * + * Use {@link #useSslProtocol(SSLContext)} in production environments. * The produced {@link SSLContext} instance will be shared by all - * the connections created by this connection factory. Use - * {@link #setSslContextFactory(SslContextFactory)} for more flexibility. + * the connections created by this connection factory. + * + * Use {@link #setSslContextFactory(SslContextFactory)} for more flexibility. * @see #setSslContextFactory(SslContextFactory) */ public void useSslProtocol(String protocol) @@ -685,13 +691,18 @@ public void useSslProtocol(String protocol) } /** - * Convenience method for setting up an SSL socket factory/engine. - * Pass in the SSL protocol to use, e.g. "TLSv1" or "TLSv1.2". + * Convenience method for configuring TLS. + * Pass in the TLS protocol version to use, e.g. "TLSv1.2" or "TLSv1.1", and + * a desired {@link TrustManager}. + * + * * The produced {@link SSLContext} instance will be shared with all * the connections created by this connection factory. Use * {@link #setSslContextFactory(SslContextFactory)} for more flexibility. - * @param protocol SSL protocol to use. + * @param protocol the TLS protocol to use. + * @param trustManager the {@link TrustManager} implementation to use. * @see #setSslContextFactory(SslContextFactory) + * @see #useSslProtocol(SSLContext) */ public void useSslProtocol(String protocol, TrustManager trustManager) throws NoSuchAlgorithmException, KeyManagementException @@ -702,8 +713,11 @@ public void useSslProtocol(String protocol, TrustManager trustManager) } /** - * Convenience method for setting up an SSL socket socketFactory/engine. - * Pass in an initialized SSLContext. + * Sets up TLS with an initialized {@link SSLContext}. The caller is responsible + * for setting up the context with a {@link TrustManager} with suitable security guarantees, + * e.g. peer verification. + * + * * The {@link SSLContext} instance will be shared with all * the connections created by this connection factory. Use * {@link #setSslContextFactory(SslContextFactory)} for more flexibility. diff --git a/src/main/java/com/rabbitmq/client/TrustEverythingTrustManager.java b/src/main/java/com/rabbitmq/client/TrustEverythingTrustManager.java index d4f7e5dae6..7893eb7e16 100644 --- a/src/main/java/com/rabbitmq/client/TrustEverythingTrustManager.java +++ b/src/main/java/com/rabbitmq/client/TrustEverythingTrustManager.java @@ -22,16 +22,18 @@ import java.security.cert.X509Certificate; /** - * Convenience class providing a default implementation of javax.net.ssl.X509TrustManager. - * Trusts every single certificate presented to it. + * Convenience class providing a default implementation of {@link javax.net.ssl.X509TrustManager}. + * Trusts every single certificate presented to it. This implementation does not perform peer + * verification and provides no protection against Man-in-the-Middle (MITM) attacks and therefore + * only suitable for some development and QA environments. */ public class TrustEverythingTrustManager implements X509TrustManager { public TrustEverythingTrustManager() { LoggerFactory.getLogger(TrustEverythingTrustManager.class).warn( - "This trust manager trusts every certificate, effectively disabling peer verification. " + - "This is convenient for local development but prone to man-in-the-middle attacks. " + - "Please see http://www.rabbitmq.com/ssl.html#validating-cerficates to learn more about peer certificate validation." + "SECURITY ALERT: this trust manager trusts every certificate, effectively disabling peer verification. " + + "This is convenient for local development but offers no protection against man-in-the-middle attacks. " + + "Please see https://www.rabbitmq.com/ssl.html#validating-cerficates to learn more about peer certificate verification." ); } From 7da0fd3e0d25f027f3467594a39a1db9d9cadbcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 22 Aug 2018 11:20:05 +0200 Subject: [PATCH 0875/2114] Test blocking IO and NIO in hostname verification test Not costly to test both IO modes and makes iterating easier. References #394 --- .../rabbitmq/client/test/BrokerTestCase.java | 14 +- .../com/rabbitmq/client/test/TestUtils.java | 19 +++ .../client/test/ssl/HostnameVerification.java | 136 +++++++++--------- 3 files changed, 91 insertions(+), 78 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java index 27ea0cbd0d..216cbb8e47 100644 --- a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java +++ b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java @@ -352,18 +352,6 @@ protected String generateExchangeName() { } protected SSLContext getSSLContext() throws NoSuchAlgorithmException { - SSLContext c = null; - - // pick the first protocol available, preferring TLSv1.2, then TLSv1, - // falling back to SSLv3 if running on an ancient/crippled JDK - for(String proto : Arrays.asList("TLSv1.2", "TLSv1", "SSLv3")) { - try { - c = SSLContext.getInstance(proto); - return c; - } catch (NoSuchAlgorithmException x) { - // keep trying - } - } - throw new NoSuchAlgorithmException(); + return TestUtils.getSSLContext(); } } diff --git a/src/test/java/com/rabbitmq/client/test/TestUtils.java b/src/test/java/com/rabbitmq/client/test/TestUtils.java index 5b0b7d0d7e..b6cb834773 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtils.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtils.java @@ -30,7 +30,10 @@ import com.rabbitmq.tools.Host; import org.slf4j.LoggerFactory; +import javax.net.ssl.SSLContext; import java.io.IOException; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.concurrent.Callable; @@ -64,6 +67,22 @@ public static void close(Connection connection) { } } + public static SSLContext getSSLContext() throws NoSuchAlgorithmException { + SSLContext c = null; + + // pick the first protocol available, preferring TLSv1.2, then TLSv1, + // falling back to SSLv3 if running on an ancient/crippled JDK + for(String proto : Arrays.asList("TLSv1.2", "TLSv1", "SSLv3")) { + try { + c = SSLContext.getInstance(proto); + return c; + } catch (NoSuchAlgorithmException x) { + // keep trying + } + } + throw new NoSuchAlgorithmException(); + } + public static boolean isVersion37orLater(Connection connection) { String currentVersion = null; try { diff --git a/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java index 85f6f6735e..1194ad7363 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java @@ -18,87 +18,93 @@ import com.rabbitmq.client.Address; import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.test.TestUtils; +import org.junit.BeforeClass; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLHandshakeException; import javax.net.ssl.TrustManagerFactory; import java.io.FileInputStream; -import java.io.IOException; -import java.security.KeyManagementException; import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.UnrecoverableKeyException; -import java.security.cert.CertificateException; -import java.util.concurrent.TimeoutException; +import java.util.function.Consumer; +import static com.rabbitmq.client.test.TestUtils.getSSLContext; import static java.util.Collections.singletonList; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; -public class HostnameVerification extends UnverifiedConnection { - - public void openConnection() - throws IOException, TimeoutException { - try { - String keystorePath = System.getProperty("test-keystore.ca"); - assertNotNull(keystorePath); - String keystorePasswd = System.getProperty("test-keystore.password"); - assertNotNull(keystorePasswd); - char[] keystorePassword = keystorePasswd.toCharArray(); - - KeyStore tks = KeyStore.getInstance("JKS"); - tks.load(new FileInputStream(keystorePath), keystorePassword); - - TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); - tmf.init(tks); - - String p12Path = System.getProperty("test-client-cert.path"); - assertNotNull(p12Path); - String p12Passwd = System.getProperty("test-client-cert.password"); - assertNotNull(p12Passwd); - KeyStore ks = KeyStore.getInstance("PKCS12"); - char[] p12Password = p12Passwd.toCharArray(); - ks.load(new FileInputStream(p12Path), p12Password); - - KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); - kmf.init(ks, p12Password); - - SSLContext c = getSSLContext(); - c.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); - c.init(null, tmf.getTrustManagers(), null); - - connectionFactory = TestUtils.connectionFactory(); - connectionFactory.useSslProtocol(c); - connectionFactory.enableHostnameVerification(); - } catch (NoSuchAlgorithmException ex) { - throw new IOException(ex.toString()); - } catch (KeyManagementException ex) { - throw new IOException(ex.toString()); - } catch (KeyStoreException ex) { - throw new IOException(ex.toString()); - } catch (CertificateException ex) { - throw new IOException(ex.toString()); - } catch (UnrecoverableKeyException ex) { - throw new IOException(ex.toString()); - } - - try { - connection = connectionFactory.newConnection( - () -> singletonList(new Address("127.0.0.1", ConnectionFactory.DEFAULT_AMQP_OVER_SSL_PORT))); - fail("The server certificate isn't issued for 127.0.0.1, the TLS handshake should have failed"); - } catch (SSLHandshakeException ignored) { - } catch (IOException e) { - fail(); - } +@RunWith(Parameterized.class) +public class HostnameVerification { + + static SSLContext sslContext; + @Parameterized.Parameter + public Consumer customizer; + + @Parameterized.Parameters + public static Object[] data() { + return new Object[] { + blockingIo(enableHostnameVerification()), + nio(enableHostnameVerification()), + }; + } + + private static Consumer blockingIo(final Consumer customizer) { + return connectionFactory -> { + connectionFactory.useBlockingIo(); + customizer.accept(connectionFactory); + }; } - public void openChannel() { + private static Consumer nio(final Consumer customizer) { + return connectionFactory -> { + connectionFactory.useNio(); + customizer.accept(connectionFactory); + }; + } + + private static Consumer enableHostnameVerification() { + return connectionFactory -> connectionFactory.enableHostnameVerification(); + } + + @BeforeClass + public static void initCrypto() throws Exception { + String keystorePath = System.getProperty("test-keystore.ca"); + assertNotNull(keystorePath); + String keystorePasswd = System.getProperty("test-keystore.password"); + assertNotNull(keystorePasswd); + char[] keystorePassword = keystorePasswd.toCharArray(); + + KeyStore tks = KeyStore.getInstance("JKS"); + tks.load(new FileInputStream(keystorePath), keystorePassword); + + TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); + tmf.init(tks); + + String p12Path = System.getProperty("test-client-cert.path"); + assertNotNull(p12Path); + String p12Passwd = System.getProperty("test-client-cert.password"); + assertNotNull(p12Passwd); + KeyStore ks = KeyStore.getInstance("PKCS12"); + char[] p12Password = p12Passwd.toCharArray(); + ks.load(new FileInputStream(p12Path), p12Password); + + KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); + kmf.init(ks, p12Password); + + sslContext = getSSLContext(); + sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); } - @Test - public void sSL() { + @Test(expected = SSLHandshakeException.class) + public void hostnameVerificationFailsBecauseCertificateNotIssuedForLoopbackInterface() throws Exception { + ConnectionFactory connectionFactory = TestUtils.connectionFactory(); + connectionFactory.useSslProtocol(sslContext); + customizer.accept(connectionFactory); + connectionFactory.newConnection( + () -> singletonList(new Address("127.0.0.1", ConnectionFactory.DEFAULT_AMQP_OVER_SSL_PORT))); + fail("The server certificate isn't issued for 127.0.0.1, the TLS handshake should have failed"); } } From 4abef1266eb7498c3add18732d59f1d185e6d0e2 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 22 Aug 2018 19:01:37 +0300 Subject: [PATCH 0876/2114] One more test --- .../client/test/ssl/HostnameVerification.java | 13 +++++++++++++ src/test/java/com/rabbitmq/tools/Host.java | 5 +++++ 2 files changed, 18 insertions(+) diff --git a/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java index 1194ad7363..06ee47c0a9 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java @@ -16,8 +16,10 @@ package com.rabbitmq.client.test.ssl; import com.rabbitmq.client.Address; +import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.test.TestUtils; +import com.rabbitmq.tools.Host; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; @@ -34,6 +36,7 @@ import static com.rabbitmq.client.test.TestUtils.getSSLContext; import static java.util.Collections.singletonList; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @RunWith(Parameterized.class) @@ -107,4 +110,14 @@ public void hostnameVerificationFailsBecauseCertificateNotIssuedForLoopbackInter () -> singletonList(new Address("127.0.0.1", ConnectionFactory.DEFAULT_AMQP_OVER_SSL_PORT))); fail("The server certificate isn't issued for 127.0.0.1, the TLS handshake should have failed"); } + + public void hostnameVerificationSucceeds() throws Exception { + ConnectionFactory connectionFactory = TestUtils.connectionFactory(); + connectionFactory.useSslProtocol(sslContext); + customizer.accept(connectionFactory); + Connection conn = connectionFactory.newConnection( + () -> singletonList(new Address(Host.systemHostname(), ConnectionFactory.DEFAULT_AMQP_OVER_SSL_PORT))); + assertTrue(conn.isOpen()); + conn.close(); + } } diff --git a/src/test/java/com/rabbitmq/tools/Host.java b/src/test/java/com/rabbitmq/tools/Host.java index c919d78621..ba77e03f4c 100644 --- a/src/test/java/com/rabbitmq/tools/Host.java +++ b/src/test/java/com/rabbitmq/tools/Host.java @@ -120,6 +120,11 @@ public static Process invokeMakeTarget(String command) throws IOException { " " + command); } + public static String systemHostname() throws IOException { + Process process = executeCommandIgnoringErrors("hostname"); + return capture(process.getInputStream()); + } + public static String makeCommand() { return System.getProperty("make.bin", "make"); From dc3454f32c29b29ebdc663ccc91f4f23b82c777b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 24 Aug 2018 12:03:52 +0200 Subject: [PATCH 0877/2114] Update Mockito to run on Java 11 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a87e3edddc..2a847d4409 100644 --- a/pom.xml +++ b/pom.xml @@ -62,7 +62,7 @@ 1.1 4.12 3.1.0 - 2.16.0 + 2.21.0 3.0.0 2.5.3 From 64611e7978e1f6f96fea14f949b953bae4ac74bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 24 Aug 2018 12:03:52 +0200 Subject: [PATCH 0878/2114] Update Mockito to run on Java 11 (cherry picked from commit dc3454f32c29b29ebdc663ccc91f4f23b82c777b) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7104624064..19350b6ff6 100644 --- a/pom.xml +++ b/pom.xml @@ -62,7 +62,7 @@ 1.1 4.12 3.1.0 - 2.16.0 + 2.21.0 3.0.0 2.5.3 From b5079b4a1b965dcf2ef3e3ff28c0776eda0ce28b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 24 Aug 2018 15:37:31 +0200 Subject: [PATCH 0879/2114] Add Javadoc @since 5.4.0 for hostname verification References #394 --- .../java/com/rabbitmq/client/SocketChannelConfigurators.java | 2 +- src/main/java/com/rabbitmq/client/SocketConfigurators.java | 2 +- src/main/java/com/rabbitmq/client/SslEngineConfigurators.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/SocketChannelConfigurators.java b/src/main/java/com/rabbitmq/client/SocketChannelConfigurators.java index d6af09d7de..566d3ddc13 100644 --- a/src/main/java/com/rabbitmq/client/SocketChannelConfigurators.java +++ b/src/main/java/com/rabbitmq/client/SocketChannelConfigurators.java @@ -21,7 +21,7 @@ * Note {@link SocketChannelConfigurator}s can be combined with * {@link SocketChannelConfigurator#andThen(SocketChannelConfigurator)}. * - * @since 5.5.0 + * @since 5.4.0 */ public abstract class SocketChannelConfigurators { diff --git a/src/main/java/com/rabbitmq/client/SocketConfigurators.java b/src/main/java/com/rabbitmq/client/SocketConfigurators.java index 127bddeb34..551ad95ca9 100644 --- a/src/main/java/com/rabbitmq/client/SocketConfigurators.java +++ b/src/main/java/com/rabbitmq/client/SocketConfigurators.java @@ -24,7 +24,7 @@ * Note {@link SocketConfigurator}s can be combined with * {@link SocketConfigurator#andThen(SocketConfigurator)}. * - * @since 5.5.0 + * @since 5.4.0 */ public abstract class SocketConfigurators { diff --git a/src/main/java/com/rabbitmq/client/SslEngineConfigurators.java b/src/main/java/com/rabbitmq/client/SslEngineConfigurators.java index d84dfa304f..119bb0314f 100644 --- a/src/main/java/com/rabbitmq/client/SslEngineConfigurators.java +++ b/src/main/java/com/rabbitmq/client/SslEngineConfigurators.java @@ -23,7 +23,7 @@ * Note {@link SslEngineConfigurator}s can be combined with * {@link SslEngineConfigurator#andThen(SslEngineConfigurator)}. * - * @since 5.5.0 + * @since 5.4.0 */ public abstract class SslEngineConfigurators { From 09a5334fa2bbf95b0b45306d36b176ea1455a02d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 20 Aug 2018 17:50:32 +0200 Subject: [PATCH 0880/2114] Add opt-in to enable server hostname verification Hostname verification isn't performed by default in the TLS handshake, this commit makes it easier to enable server hostname verification for both blocking and non-blocking IO modes. References #394 (cherry picked from commit fcc3dbb5f797e7e340b6ddc5c2faa2fc77a1c905) --- .../rabbitmq/client/ConnectionFactory.java | 52 +++++- .../client/SocketChannelConfigurator.java | 16 ++ .../client/SocketChannelConfigurators.java | 111 +++++++++++++ .../rabbitmq/client/SocketConfigurator.java | 20 +++ .../rabbitmq/client/SocketConfigurators.java | 153 ++++++++++++++++++ .../client/SslEngineConfigurator.java | 16 ++ .../client/SslEngineConfigurators.java | 116 +++++++++++++ .../rabbitmq/client/impl/nio/NioParams.java | 23 ++- .../ChannelRpcTimeoutIntegrationTest.java | 2 +- .../test/functional/UnexpectedFrames.java | 3 +- .../client/test/ssl/HostnameVerification.java | 104 ++++++++++++ .../test/ssl/NioTlsUnverifiedConnection.java | 7 +- .../rabbitmq/client/test/ssl/SSLTests.java | 3 +- .../client/test/ssl/UnverifiedConnection.java | 2 +- .../client/test/ssl/VerifiedConnection.java | 2 +- 15 files changed, 610 insertions(+), 20 deletions(-) create mode 100644 src/main/java/com/rabbitmq/client/SocketChannelConfigurators.java create mode 100644 src/main/java/com/rabbitmq/client/SocketConfigurators.java create mode 100644 src/main/java/com/rabbitmq/client/SslEngineConfigurators.java create mode 100644 src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 279a015af7..e9af65a6b5 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -15,8 +15,6 @@ package com.rabbitmq.client; -import static java.util.concurrent.TimeUnit.*; - import com.rabbitmq.client.impl.AMQConnection; import com.rabbitmq.client.impl.ConnectionParams; import com.rabbitmq.client.impl.CredentialsProvider; @@ -32,6 +30,10 @@ import com.rabbitmq.client.impl.recovery.RetryHandler; import com.rabbitmq.client.impl.recovery.TopologyRecoveryFilter; +import javax.net.SocketFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; @@ -50,10 +52,8 @@ import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeoutException; import java.util.function.Predicate; -import javax.net.SocketFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.TrustManager; + +import static java.util.concurrent.TimeUnit.MINUTES; /** * Convenience factory class to facilitate opening a {@link Connection} to a RabbitMQ node. @@ -132,7 +132,7 @@ public class ConnectionFactory implements Cloneable { // connections uses, see rabbitmq/rabbitmq-java-client#86 private ExecutorService shutdownExecutor; private ScheduledExecutorService heartbeatExecutor; - private SocketConfigurator socketConf = new DefaultSocketConfigurator(); + private SocketConfigurator socketConf = SocketConfigurators.defaultConfigurator(); private ExceptionHandler exceptionHandler = new DefaultExceptionHandler(); private CredentialsProvider credentialsProvider = new DefaultCredentialsProvider(DEFAULT_USER, DEFAULT_PASS); @@ -729,6 +729,44 @@ public void useSslProtocol(SSLContext context) { setSocketFactory(context.getSocketFactory()); } + /** + * Enable server hostname verification for TLS connections. + *

+ * This enables hostname verification regardless of the IO mode + * used (blocking or non-blocking IO). + *

+ * This can be called typically after setting the {@link SSLContext} + * with one of the useSslProtocol methods. + * + * @see NioParams#enableHostnameVerification() + * @see NioParams#setSslEngineConfigurator(SslEngineConfigurator) + * @see SslEngineConfigurators#ENABLE_HOSTNAME_VERIFICATION + * @see SocketConfigurators#ENABLE_HOSTNAME_VERIFICATION + * @see ConnectionFactory#useSslProtocol(String) + * @see ConnectionFactory#useSslProtocol(SSLContext) + * @see ConnectionFactory#useSslProtocol() + * @see ConnectionFactory#useSslProtocol(String, TrustManager) + */ + public void enableHostnameVerification() { + enableHostnameVerificationForNio(); + enableHostnameVerificationForBlockingIo(); + } + + protected void enableHostnameVerificationForNio() { + if (this.nioParams == null) { + this.nioParams = new NioParams(); + } + this.nioParams = this.nioParams.enableHostnameVerification(); + } + + protected void enableHostnameVerificationForBlockingIo() { + if (this.socketConf == null) { + this.socketConf = SocketConfigurators.builder().defaultConfigurator().enableHostnameVerification().build(); + } else { + this.socketConf = this.socketConf.andThen(SocketConfigurators.enableHostnameVerification()); + } + } + public static String computeDefaultTlsProcotol(String[] supportedProtocols) { if(supportedProtocols != null) { for (String supportedProtocol : supportedProtocols) { diff --git a/src/main/java/com/rabbitmq/client/SocketChannelConfigurator.java b/src/main/java/com/rabbitmq/client/SocketChannelConfigurator.java index 5aded698f9..ceb3a95a88 100644 --- a/src/main/java/com/rabbitmq/client/SocketChannelConfigurator.java +++ b/src/main/java/com/rabbitmq/client/SocketChannelConfigurator.java @@ -17,7 +17,9 @@ import java.io.IOException; import java.nio.channels.SocketChannel; +import java.util.Objects; +@FunctionalInterface public interface SocketChannelConfigurator { /** @@ -26,4 +28,18 @@ public interface SocketChannelConfigurator { */ void configure(SocketChannel socketChannel) throws IOException; + /** + * Returns a composed configurator that performs, in sequence, this + * operation followed by the {@code after} operation. + * + * @param after the operation to perform after this operation + * @return a composed configurator that performs in sequence this + * operation followed by the {@code after} operation + * @throws NullPointerException if {@code after} is null + */ + default SocketChannelConfigurator andThen(SocketChannelConfigurator after) { + Objects.requireNonNull(after); + return t -> { configure(t); after.configure(t); }; + } + } diff --git a/src/main/java/com/rabbitmq/client/SocketChannelConfigurators.java b/src/main/java/com/rabbitmq/client/SocketChannelConfigurators.java new file mode 100644 index 0000000000..d6af09d7de --- /dev/null +++ b/src/main/java/com/rabbitmq/client/SocketChannelConfigurators.java @@ -0,0 +1,111 @@ +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client; + +/** + * Ready-to-use instances and builder for {@link SocketChannelConfigurator}. + *

+ * Note {@link SocketChannelConfigurator}s can be combined with + * {@link SocketChannelConfigurator#andThen(SocketChannelConfigurator)}. + * + * @since 5.5.0 + */ +public abstract class SocketChannelConfigurators { + + /** + * Disable Nagle's algorithm. + */ + public static final SocketChannelConfigurator DISABLE_NAGLE_ALGORITHM = + socketChannel -> SocketConfigurators.DISABLE_NAGLE_ALGORITHM.configure(socketChannel.socket()); + + /** + * Default {@link SocketChannelConfigurator} that disables Nagle's algorithm. + */ + public static final SocketChannelConfigurator DEFAULT = DISABLE_NAGLE_ALGORITHM; + + /** + * The default {@link SocketChannelConfigurator} that disables Nagle's algorithm. + * + * @return + */ + public static SocketChannelConfigurator defaultConfigurator() { + return DEFAULT; + } + + /** + * {@link SocketChannelConfigurator} that disables Nagle's algorithm. + * + * @return + */ + public static SocketChannelConfigurator disableNagleAlgorithm() { + return DISABLE_NAGLE_ALGORITHM; + } + + /** + * Builder to configure and creates a {@link SocketChannelConfigurator} instance. + * + * @return + */ + public static SocketChannelConfigurators.Builder builder() { + return new SocketChannelConfigurators.Builder(); + } + + public static class Builder { + + private SocketChannelConfigurator configurator = channel -> { + }; + + /** + * Set default configuration. + * + * @return + */ + public Builder defaultConfigurator() { + configurator = configurator.andThen(DEFAULT); + return this; + } + + /** + * Disable Nagle's Algorithm. + * + * @return + */ + public Builder disableNagleAlgorithm() { + configurator = configurator.andThen(DISABLE_NAGLE_ALGORITHM); + return this; + } + + /** + * Add an extra configuration step. + * + * @param extraConfiguration + * @return + */ + public Builder add(SocketChannelConfigurator extraConfiguration) { + configurator = configurator.andThen(extraConfiguration); + return this; + } + + /** + * Return the configured {@link SocketConfigurator}. + * + * @return + */ + public SocketChannelConfigurator build() { + return configurator; + } + } +} diff --git a/src/main/java/com/rabbitmq/client/SocketConfigurator.java b/src/main/java/com/rabbitmq/client/SocketConfigurator.java index 8896baf3e5..30c9ed4bab 100644 --- a/src/main/java/com/rabbitmq/client/SocketConfigurator.java +++ b/src/main/java/com/rabbitmq/client/SocketConfigurator.java @@ -17,11 +17,31 @@ import java.io.IOException; import java.net.Socket; +import java.util.Objects; +@FunctionalInterface public interface SocketConfigurator { + /** * Provides a hook to insert custom configuration of the sockets * used to connect to an AMQP server before they connect. */ void configure(Socket socket) throws IOException; + + /** + * Returns a composed configurator that performs, in sequence, this + * operation followed by the {@code after} operation. + * + * @param after the operation to perform after this operation + * @return a composed configurator that performs in sequence this + * operation followed by the {@code after} operation + * @throws NullPointerException if {@code after} is null + */ + default SocketConfigurator andThen(SocketConfigurator after) { + Objects.requireNonNull(after); + return t -> { + configure(t); + after.configure(t); + }; + } } diff --git a/src/main/java/com/rabbitmq/client/SocketConfigurators.java b/src/main/java/com/rabbitmq/client/SocketConfigurators.java new file mode 100644 index 0000000000..127bddeb34 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/SocketConfigurators.java @@ -0,0 +1,153 @@ +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client; + +import javax.net.ssl.SSLParameters; +import javax.net.ssl.SSLSocket; + +/** + * Ready-to-use instances and builder for {@link SocketConfigurator}. + *

+ * Note {@link SocketConfigurator}s can be combined with + * {@link SocketConfigurator#andThen(SocketConfigurator)}. + * + * @since 5.5.0 + */ +public abstract class SocketConfigurators { + + /** + * Disable Nagle's algorithm. + */ + public static final SocketConfigurator DISABLE_NAGLE_ALGORITHM = socket -> socket.setTcpNoDelay(true); + + /** + * Default {@link SocketConfigurator} that disables Nagle's algorithm. + */ + public static final SocketConfigurator DEFAULT = DISABLE_NAGLE_ALGORITHM; + + /** + * Enable server hostname validation for TLS connections. + */ + public static final SocketConfigurator ENABLE_HOSTNAME_VERIFICATION = socket -> { + if (socket instanceof SSLSocket) { + SSLSocket sslSocket = (SSLSocket) socket; + SSLParameters sslParameters = enableHostnameVerification(sslSocket.getSSLParameters()); + sslSocket.setSSLParameters(sslParameters); + } + }; + + static final SSLParameters enableHostnameVerification(SSLParameters sslParameters) { + if (sslParameters == null) { + sslParameters = new SSLParameters(); + } + // It says HTTPS but works also for any TCP connection. + // It checks SAN (Subject Alternative Name) as well as CN. + sslParameters.setEndpointIdentificationAlgorithm("HTTPS"); + return sslParameters; + } + + /** + * The default {@link SocketConfigurator} that disables Nagle's algorithm. + * + * @return + */ + public static SocketConfigurator defaultConfigurator() { + return DEFAULT; + } + + /** + * {@link SocketConfigurator} that disables Nagle's algorithm. + * + * @return + */ + public static SocketConfigurator disableNagleAlgorithm() { + return DISABLE_NAGLE_ALGORITHM; + } + + /** + * {@link SocketConfigurator} that enable server hostname verification for TLS connections. + * + * @return + */ + public static SocketConfigurator enableHostnameVerification() { + return ENABLE_HOSTNAME_VERIFICATION; + } + + /** + * Builder to configure and creates a {@link SocketConfigurator} instance. + * + * @return + */ + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + + private SocketConfigurator configurator = socket -> { + }; + + /** + * Set default configuration. + * + * @return + */ + public Builder defaultConfigurator() { + configurator = configurator.andThen(DEFAULT); + return this; + } + + /** + * Disable Nagle's Algorithm. + * + * @return + */ + public Builder disableNagleAlgorithm() { + configurator = configurator.andThen(DISABLE_NAGLE_ALGORITHM); + return this; + } + + /** + * Enable server hostname verification for TLS connections. + * + * @return + */ + public Builder enableHostnameVerification() { + configurator = configurator.andThen(ENABLE_HOSTNAME_VERIFICATION); + return this; + } + + /** + * Add an extra configuration step. + * + * @param extraConfiguration + * @return + */ + public Builder add(SocketConfigurator extraConfiguration) { + configurator = configurator.andThen(extraConfiguration); + return this; + } + + /** + * Return the configured {@link SocketConfigurator}. + * + * @return + */ + public SocketConfigurator build() { + return configurator; + } + } +} diff --git a/src/main/java/com/rabbitmq/client/SslEngineConfigurator.java b/src/main/java/com/rabbitmq/client/SslEngineConfigurator.java index 7986d4b9d2..01b22c4c05 100644 --- a/src/main/java/com/rabbitmq/client/SslEngineConfigurator.java +++ b/src/main/java/com/rabbitmq/client/SslEngineConfigurator.java @@ -17,7 +17,9 @@ import javax.net.ssl.SSLEngine; import java.io.IOException; +import java.util.Objects; +@FunctionalInterface public interface SslEngineConfigurator { /** @@ -27,4 +29,18 @@ public interface SslEngineConfigurator { */ void configure(SSLEngine sslEngine) throws IOException; + /** + * Returns a composed configurator that performs, in sequence, this + * operation followed by the {@code after} operation. + * + * @param after the operation to perform after this operation + * @return a composed configurator that performs in sequence this + * operation followed by the {@code after} operation + * @throws NullPointerException if {@code after} is null + */ + default SslEngineConfigurator andThen(SslEngineConfigurator after) { + Objects.requireNonNull(after); + return t -> { configure(t); after.configure(t); }; + } + } diff --git a/src/main/java/com/rabbitmq/client/SslEngineConfigurators.java b/src/main/java/com/rabbitmq/client/SslEngineConfigurators.java new file mode 100644 index 0000000000..d84dfa304f --- /dev/null +++ b/src/main/java/com/rabbitmq/client/SslEngineConfigurators.java @@ -0,0 +1,116 @@ +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client; + +import javax.net.ssl.SSLParameters; + +/** + * Ready-to-use instances and builder for {@link SslEngineConfigurator}s. + *

+ * Note {@link SslEngineConfigurator}s can be combined with + * {@link SslEngineConfigurator#andThen(SslEngineConfigurator)}. + * + * @since 5.5.0 + */ +public abstract class SslEngineConfigurators { + + /** + * Default {@link SslEngineConfigurator}, does nothing. + */ + public static SslEngineConfigurator DEFAULT = sslEngine -> { + }; + + /** + * {@link SslEngineConfigurator} that enables server hostname verification. + */ + public static SslEngineConfigurator ENABLE_HOSTNAME_VERIFICATION = sslEngine -> { + SSLParameters sslParameters = SocketConfigurators.enableHostnameVerification(sslEngine.getSSLParameters()); + sslEngine.setSSLParameters(sslParameters); + }; + + /** + * Default {@link SslEngineConfigurator}, does nothing. + * + * @return + */ + public static SslEngineConfigurator defaultConfigurator() { + return DEFAULT; + } + + /** + * {@link SslEngineConfigurator} that enables server hostname verification. + * + * @return + */ + public static SslEngineConfigurator enableHostnameVerification() { + return ENABLE_HOSTNAME_VERIFICATION; + } + + /** + * Builder to configure and creates a {@link SslEngineConfigurator} instance. + * + * @return + */ + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + + private SslEngineConfigurator configurator = channel -> { + }; + + /** + * Set default configuration (no op). + * + * @return + */ + public Builder defaultConfigurator() { + configurator = configurator.andThen(DEFAULT); + return this; + } + + /** + * Enables server hostname verification. + * + * @return + */ + public Builder enableHostnameVerification() { + configurator = configurator.andThen(ENABLE_HOSTNAME_VERIFICATION); + return this; + } + + /** + * Add extra configuration step. + * + * @param extraConfiguration + * @return + */ + public Builder add(SslEngineConfigurator extraConfiguration) { + configurator = configurator.andThen(extraConfiguration); + return this; + } + + /** + * Return the configured {@link SslEngineConfigurator}. + * + * @return + */ + public SslEngineConfigurator build() { + return configurator; + } + } +} diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java b/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java index 9f9da61795..80b8624447 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java @@ -15,14 +15,16 @@ package com.rabbitmq.client.impl.nio; -import com.rabbitmq.client.DefaultSocketChannelConfigurator; import com.rabbitmq.client.SocketChannelConfigurator; +import com.rabbitmq.client.SocketChannelConfigurators; import com.rabbitmq.client.SslEngineConfigurator; import javax.net.ssl.SSLEngine; import java.util.concurrent.ExecutorService; import java.util.concurrent.ThreadFactory; +import static com.rabbitmq.client.SslEngineConfigurators.ENABLE_HOSTNAME_VERIFICATION; + /** * Parameters used to configure the NIO mode of a {@link com.rabbitmq.client.ConnectionFactory}. * @@ -68,7 +70,7 @@ public class NioParams { /** * the hook to configure the socket channel before it's open */ - private SocketChannelConfigurator socketChannelConfigurator = new DefaultSocketChannelConfigurator(); + private SocketChannelConfigurator socketChannelConfigurator = SocketChannelConfigurators.defaultConfigurator(); /** * the hook to configure the SSL engine before the connection is open @@ -94,10 +96,27 @@ public NioParams(NioParams nioParams) { setWriteQueueCapacity(nioParams.getWriteQueueCapacity()); setNioExecutor(nioParams.getNioExecutor()); setThreadFactory(nioParams.getThreadFactory()); + setSocketChannelConfigurator(nioParams.getSocketChannelConfigurator()); setSslEngineConfigurator(nioParams.getSslEngineConfigurator()); setConnectionShutdownExecutor(nioParams.getConnectionShutdownExecutor()); } + /** + * Enable server hostname verification for TLS connections. + * + * @return this {@link NioParams} instance + * @see NioParams#setSslEngineConfigurator(SslEngineConfigurator) + * @see com.rabbitmq.client.SslEngineConfigurators#ENABLE_HOSTNAME_VERIFICATION + */ + public NioParams enableHostnameVerification() { + if (this.sslEngineConfigurator == null) { + this.sslEngineConfigurator = ENABLE_HOSTNAME_VERIFICATION; + } else { + this.sslEngineConfigurator = this.sslEngineConfigurator.andThen(ENABLE_HOSTNAME_VERIFICATION); + } + return this; + } + public int getReadByteBufferSize() { return readByteBufferSize; } diff --git a/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java b/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java index 40d6a0ab5a..f880f617da 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java @@ -84,7 +84,7 @@ public void tearDown() throws Exception { private FrameHandler createFrameHandler() throws IOException { SocketFrameHandlerFactory socketFrameHandlerFactory = new SocketFrameHandlerFactory(ConnectionFactory.DEFAULT_CONNECTION_TIMEOUT, - SocketFactory.getDefault(), new DefaultSocketConfigurator(), false, null); + SocketFactory.getDefault(), SocketConfigurators.defaultConfigurator(), false, null); return socketFrameHandlerFactory.create(new Address("localhost"), null); } diff --git a/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java b/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java index 0ab8013969..698d8a8952 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java +++ b/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java @@ -18,6 +18,7 @@ import com.rabbitmq.client.AMQP; import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.DefaultSocketConfigurator; +import com.rabbitmq.client.SocketConfigurators; import com.rabbitmq.client.impl.*; import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; import com.rabbitmq.client.test.BrokerTestCase; @@ -85,7 +86,7 @@ public ConfusedConnectionFactory() { private static class ConfusedFrameHandlerFactory extends SocketFrameHandlerFactory { private ConfusedFrameHandlerFactory() { - super(1000, SocketFactory.getDefault(), new DefaultSocketConfigurator(), false); + super(1000, SocketFactory.getDefault(), SocketConfigurators.defaultConfigurator(), false); } @Override public FrameHandler create(Socket sock) throws IOException { diff --git a/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java new file mode 100644 index 0000000000..85f6f6735e --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java @@ -0,0 +1,104 @@ +// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.test.ssl; + +import com.rabbitmq.client.Address; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.test.TestUtils; +import org.junit.Test; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLHandshakeException; +import javax.net.ssl.TrustManagerFactory; +import java.io.FileInputStream; +import java.io.IOException; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; +import java.util.concurrent.TimeoutException; + +import static java.util.Collections.singletonList; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + +public class HostnameVerification extends UnverifiedConnection { + + public void openConnection() + throws IOException, TimeoutException { + try { + String keystorePath = System.getProperty("test-keystore.ca"); + assertNotNull(keystorePath); + String keystorePasswd = System.getProperty("test-keystore.password"); + assertNotNull(keystorePasswd); + char[] keystorePassword = keystorePasswd.toCharArray(); + + KeyStore tks = KeyStore.getInstance("JKS"); + tks.load(new FileInputStream(keystorePath), keystorePassword); + + TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); + tmf.init(tks); + + String p12Path = System.getProperty("test-client-cert.path"); + assertNotNull(p12Path); + String p12Passwd = System.getProperty("test-client-cert.password"); + assertNotNull(p12Passwd); + KeyStore ks = KeyStore.getInstance("PKCS12"); + char[] p12Password = p12Passwd.toCharArray(); + ks.load(new FileInputStream(p12Path), p12Password); + + KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); + kmf.init(ks, p12Password); + + SSLContext c = getSSLContext(); + c.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); + c.init(null, tmf.getTrustManagers(), null); + + connectionFactory = TestUtils.connectionFactory(); + connectionFactory.useSslProtocol(c); + connectionFactory.enableHostnameVerification(); + } catch (NoSuchAlgorithmException ex) { + throw new IOException(ex.toString()); + } catch (KeyManagementException ex) { + throw new IOException(ex.toString()); + } catch (KeyStoreException ex) { + throw new IOException(ex.toString()); + } catch (CertificateException ex) { + throw new IOException(ex.toString()); + } catch (UnrecoverableKeyException ex) { + throw new IOException(ex.toString()); + } + + try { + connection = connectionFactory.newConnection( + () -> singletonList(new Address("127.0.0.1", ConnectionFactory.DEFAULT_AMQP_OVER_SSL_PORT))); + fail("The server certificate isn't issued for 127.0.0.1, the TLS handshake should have failed"); + } catch (SSLHandshakeException ignored) { + } catch (IOException e) { + fail(); + } + } + + public void openChannel() { + } + + @Test + public void sSL() { + } +} diff --git a/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java index 7312658894..07ac30a901 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java @@ -82,12 +82,7 @@ public void connectionGetConsume() throws Exception { connectionFactory.useSslProtocol(); NioParams nioParams = new NioParams(); final AtomicBoolean sslEngineHasBeenCalled = new AtomicBoolean(false); - nioParams.setSslEngineConfigurator(new SslEngineConfigurator() { - @Override - public void configure(SSLEngine sslEngine) throws IOException { - sslEngineHasBeenCalled.set(true); - } - }); + nioParams.setSslEngineConfigurator(sslEngine -> sslEngineHasBeenCalled.set(true)); connectionFactory.setNioParams(nioParams); diff --git a/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java index 21946066e6..679468a59f 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java @@ -32,7 +32,8 @@ VerifiedConnection.class, BadVerifiedConnection.class, ConnectionFactoryDefaultTlsVersion.class, - NioTlsUnverifiedConnection.class + NioTlsUnverifiedConnection.class, + HostnameVerification.class }) public class SSLTests { diff --git a/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java index 319ef82de9..6d65599b4c 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java @@ -54,7 +54,7 @@ public void openConnection() } } if(connection == null) { - fail("Couldn't open TLS connection after 3 attemps"); + fail("Couldn't open TLS connection after 3 attempts"); } } diff --git a/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java index 3083e6e2f2..e662113085 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java @@ -96,7 +96,7 @@ public void openConnection() } } if(connection == null) { - fail("Couldn't open TLS connection after 3 attemps"); + fail("Couldn't open TLS connection after 3 attempts"); } } } From ad47e5bfede4beb022ffe51cda6a86cabee1ee97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 22 Aug 2018 11:20:05 +0200 Subject: [PATCH 0881/2114] Test blocking IO and NIO in hostname verification test Not costly to test both IO modes and makes iterating easier. References #394 (cherry picked from commit 7da0fd3e0d25f027f3467594a39a1db9d9cadbcd) --- .../rabbitmq/client/test/BrokerTestCase.java | 14 +- .../com/rabbitmq/client/test/TestUtils.java | 19 +++ .../client/test/ssl/HostnameVerification.java | 136 +++++++++--------- 3 files changed, 91 insertions(+), 78 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java index 27ea0cbd0d..216cbb8e47 100644 --- a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java +++ b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java @@ -352,18 +352,6 @@ protected String generateExchangeName() { } protected SSLContext getSSLContext() throws NoSuchAlgorithmException { - SSLContext c = null; - - // pick the first protocol available, preferring TLSv1.2, then TLSv1, - // falling back to SSLv3 if running on an ancient/crippled JDK - for(String proto : Arrays.asList("TLSv1.2", "TLSv1", "SSLv3")) { - try { - c = SSLContext.getInstance(proto); - return c; - } catch (NoSuchAlgorithmException x) { - // keep trying - } - } - throw new NoSuchAlgorithmException(); + return TestUtils.getSSLContext(); } } diff --git a/src/test/java/com/rabbitmq/client/test/TestUtils.java b/src/test/java/com/rabbitmq/client/test/TestUtils.java index 5b0b7d0d7e..b6cb834773 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtils.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtils.java @@ -30,7 +30,10 @@ import com.rabbitmq.tools.Host; import org.slf4j.LoggerFactory; +import javax.net.ssl.SSLContext; import java.io.IOException; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.concurrent.Callable; @@ -64,6 +67,22 @@ public static void close(Connection connection) { } } + public static SSLContext getSSLContext() throws NoSuchAlgorithmException { + SSLContext c = null; + + // pick the first protocol available, preferring TLSv1.2, then TLSv1, + // falling back to SSLv3 if running on an ancient/crippled JDK + for(String proto : Arrays.asList("TLSv1.2", "TLSv1", "SSLv3")) { + try { + c = SSLContext.getInstance(proto); + return c; + } catch (NoSuchAlgorithmException x) { + // keep trying + } + } + throw new NoSuchAlgorithmException(); + } + public static boolean isVersion37orLater(Connection connection) { String currentVersion = null; try { diff --git a/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java index 85f6f6735e..1194ad7363 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java @@ -18,87 +18,93 @@ import com.rabbitmq.client.Address; import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.test.TestUtils; +import org.junit.BeforeClass; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLHandshakeException; import javax.net.ssl.TrustManagerFactory; import java.io.FileInputStream; -import java.io.IOException; -import java.security.KeyManagementException; import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.UnrecoverableKeyException; -import java.security.cert.CertificateException; -import java.util.concurrent.TimeoutException; +import java.util.function.Consumer; +import static com.rabbitmq.client.test.TestUtils.getSSLContext; import static java.util.Collections.singletonList; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; -public class HostnameVerification extends UnverifiedConnection { - - public void openConnection() - throws IOException, TimeoutException { - try { - String keystorePath = System.getProperty("test-keystore.ca"); - assertNotNull(keystorePath); - String keystorePasswd = System.getProperty("test-keystore.password"); - assertNotNull(keystorePasswd); - char[] keystorePassword = keystorePasswd.toCharArray(); - - KeyStore tks = KeyStore.getInstance("JKS"); - tks.load(new FileInputStream(keystorePath), keystorePassword); - - TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); - tmf.init(tks); - - String p12Path = System.getProperty("test-client-cert.path"); - assertNotNull(p12Path); - String p12Passwd = System.getProperty("test-client-cert.password"); - assertNotNull(p12Passwd); - KeyStore ks = KeyStore.getInstance("PKCS12"); - char[] p12Password = p12Passwd.toCharArray(); - ks.load(new FileInputStream(p12Path), p12Password); - - KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); - kmf.init(ks, p12Password); - - SSLContext c = getSSLContext(); - c.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); - c.init(null, tmf.getTrustManagers(), null); - - connectionFactory = TestUtils.connectionFactory(); - connectionFactory.useSslProtocol(c); - connectionFactory.enableHostnameVerification(); - } catch (NoSuchAlgorithmException ex) { - throw new IOException(ex.toString()); - } catch (KeyManagementException ex) { - throw new IOException(ex.toString()); - } catch (KeyStoreException ex) { - throw new IOException(ex.toString()); - } catch (CertificateException ex) { - throw new IOException(ex.toString()); - } catch (UnrecoverableKeyException ex) { - throw new IOException(ex.toString()); - } - - try { - connection = connectionFactory.newConnection( - () -> singletonList(new Address("127.0.0.1", ConnectionFactory.DEFAULT_AMQP_OVER_SSL_PORT))); - fail("The server certificate isn't issued for 127.0.0.1, the TLS handshake should have failed"); - } catch (SSLHandshakeException ignored) { - } catch (IOException e) { - fail(); - } +@RunWith(Parameterized.class) +public class HostnameVerification { + + static SSLContext sslContext; + @Parameterized.Parameter + public Consumer customizer; + + @Parameterized.Parameters + public static Object[] data() { + return new Object[] { + blockingIo(enableHostnameVerification()), + nio(enableHostnameVerification()), + }; + } + + private static Consumer blockingIo(final Consumer customizer) { + return connectionFactory -> { + connectionFactory.useBlockingIo(); + customizer.accept(connectionFactory); + }; } - public void openChannel() { + private static Consumer nio(final Consumer customizer) { + return connectionFactory -> { + connectionFactory.useNio(); + customizer.accept(connectionFactory); + }; + } + + private static Consumer enableHostnameVerification() { + return connectionFactory -> connectionFactory.enableHostnameVerification(); + } + + @BeforeClass + public static void initCrypto() throws Exception { + String keystorePath = System.getProperty("test-keystore.ca"); + assertNotNull(keystorePath); + String keystorePasswd = System.getProperty("test-keystore.password"); + assertNotNull(keystorePasswd); + char[] keystorePassword = keystorePasswd.toCharArray(); + + KeyStore tks = KeyStore.getInstance("JKS"); + tks.load(new FileInputStream(keystorePath), keystorePassword); + + TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); + tmf.init(tks); + + String p12Path = System.getProperty("test-client-cert.path"); + assertNotNull(p12Path); + String p12Passwd = System.getProperty("test-client-cert.password"); + assertNotNull(p12Passwd); + KeyStore ks = KeyStore.getInstance("PKCS12"); + char[] p12Password = p12Passwd.toCharArray(); + ks.load(new FileInputStream(p12Path), p12Password); + + KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); + kmf.init(ks, p12Password); + + sslContext = getSSLContext(); + sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); } - @Test - public void sSL() { + @Test(expected = SSLHandshakeException.class) + public void hostnameVerificationFailsBecauseCertificateNotIssuedForLoopbackInterface() throws Exception { + ConnectionFactory connectionFactory = TestUtils.connectionFactory(); + connectionFactory.useSslProtocol(sslContext); + customizer.accept(connectionFactory); + connectionFactory.newConnection( + () -> singletonList(new Address("127.0.0.1", ConnectionFactory.DEFAULT_AMQP_OVER_SSL_PORT))); + fail("The server certificate isn't issued for 127.0.0.1, the TLS handshake should have failed"); } } From 16daff14c03265f5362e5abd330f7838b6bd4a65 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 22 Aug 2018 19:01:37 +0300 Subject: [PATCH 0882/2114] One more test (cherry picked from commit 4abef1266eb7498c3add18732d59f1d185e6d0e2) --- .../client/test/ssl/HostnameVerification.java | 13 +++++++++++++ src/test/java/com/rabbitmq/tools/Host.java | 5 +++++ 2 files changed, 18 insertions(+) diff --git a/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java index 1194ad7363..06ee47c0a9 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java @@ -16,8 +16,10 @@ package com.rabbitmq.client.test.ssl; import com.rabbitmq.client.Address; +import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.test.TestUtils; +import com.rabbitmq.tools.Host; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; @@ -34,6 +36,7 @@ import static com.rabbitmq.client.test.TestUtils.getSSLContext; import static java.util.Collections.singletonList; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @RunWith(Parameterized.class) @@ -107,4 +110,14 @@ public void hostnameVerificationFailsBecauseCertificateNotIssuedForLoopbackInter () -> singletonList(new Address("127.0.0.1", ConnectionFactory.DEFAULT_AMQP_OVER_SSL_PORT))); fail("The server certificate isn't issued for 127.0.0.1, the TLS handshake should have failed"); } + + public void hostnameVerificationSucceeds() throws Exception { + ConnectionFactory connectionFactory = TestUtils.connectionFactory(); + connectionFactory.useSslProtocol(sslContext); + customizer.accept(connectionFactory); + Connection conn = connectionFactory.newConnection( + () -> singletonList(new Address(Host.systemHostname(), ConnectionFactory.DEFAULT_AMQP_OVER_SSL_PORT))); + assertTrue(conn.isOpen()); + conn.close(); + } } diff --git a/src/test/java/com/rabbitmq/tools/Host.java b/src/test/java/com/rabbitmq/tools/Host.java index c919d78621..ba77e03f4c 100644 --- a/src/test/java/com/rabbitmq/tools/Host.java +++ b/src/test/java/com/rabbitmq/tools/Host.java @@ -120,6 +120,11 @@ public static Process invokeMakeTarget(String command) throws IOException { " " + command); } + public static String systemHostname() throws IOException { + Process process = executeCommandIgnoringErrors("hostname"); + return capture(process.getInputStream()); + } + public static String makeCommand() { return System.getProperty("make.bin", "make"); From 31bdd4745cf87a98e35af566bd415b765c9c89c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 24 Aug 2018 15:37:31 +0200 Subject: [PATCH 0883/2114] Add Javadoc @since 5.4.0 for hostname verification References #394 (cherry picked from commit b5079b4a1b965dcf2ef3e3ff28c0776eda0ce28b) --- .../java/com/rabbitmq/client/SocketChannelConfigurators.java | 2 +- src/main/java/com/rabbitmq/client/SocketConfigurators.java | 2 +- src/main/java/com/rabbitmq/client/SslEngineConfigurators.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/SocketChannelConfigurators.java b/src/main/java/com/rabbitmq/client/SocketChannelConfigurators.java index d6af09d7de..566d3ddc13 100644 --- a/src/main/java/com/rabbitmq/client/SocketChannelConfigurators.java +++ b/src/main/java/com/rabbitmq/client/SocketChannelConfigurators.java @@ -21,7 +21,7 @@ * Note {@link SocketChannelConfigurator}s can be combined with * {@link SocketChannelConfigurator#andThen(SocketChannelConfigurator)}. * - * @since 5.5.0 + * @since 5.4.0 */ public abstract class SocketChannelConfigurators { diff --git a/src/main/java/com/rabbitmq/client/SocketConfigurators.java b/src/main/java/com/rabbitmq/client/SocketConfigurators.java index 127bddeb34..551ad95ca9 100644 --- a/src/main/java/com/rabbitmq/client/SocketConfigurators.java +++ b/src/main/java/com/rabbitmq/client/SocketConfigurators.java @@ -24,7 +24,7 @@ * Note {@link SocketConfigurator}s can be combined with * {@link SocketConfigurator#andThen(SocketConfigurator)}. * - * @since 5.5.0 + * @since 5.4.0 */ public abstract class SocketConfigurators { diff --git a/src/main/java/com/rabbitmq/client/SslEngineConfigurators.java b/src/main/java/com/rabbitmq/client/SslEngineConfigurators.java index d84dfa304f..119bb0314f 100644 --- a/src/main/java/com/rabbitmq/client/SslEngineConfigurators.java +++ b/src/main/java/com/rabbitmq/client/SslEngineConfigurators.java @@ -23,7 +23,7 @@ * Note {@link SslEngineConfigurator}s can be combined with * {@link SslEngineConfigurator#andThen(SslEngineConfigurator)}. * - * @since 5.5.0 + * @since 5.4.0 */ public abstract class SslEngineConfigurators { From 9c8a12821fed8657c617f086be147a6a95a71812 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 27 Aug 2018 09:08:29 +0200 Subject: [PATCH 0884/2114] Add @since 5.4.0 to ConnectionFactory#enableHostnameVerification References #394 --- src/main/java/com/rabbitmq/client/ConnectionFactory.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index e9af65a6b5..2f8b55d050 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -746,6 +746,7 @@ public void useSslProtocol(SSLContext context) { * @see ConnectionFactory#useSslProtocol(SSLContext) * @see ConnectionFactory#useSslProtocol() * @see ConnectionFactory#useSslProtocol(String, TrustManager) + * @since 5.4.0 */ public void enableHostnameVerification() { enableHostnameVerificationForNio(); From 82bf1c776780f683849e1eb8e711962737ac0b20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 27 Aug 2018 09:08:29 +0200 Subject: [PATCH 0885/2114] Add @since 5.4.0 to ConnectionFactory#enableHostnameVerification References #394 (cherry picked from commit 9c8a12821fed8657c617f086be147a6a95a71812) --- src/main/java/com/rabbitmq/client/ConnectionFactory.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index e9af65a6b5..2f8b55d050 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -746,6 +746,7 @@ public void useSslProtocol(SSLContext context) { * @see ConnectionFactory#useSslProtocol(SSLContext) * @see ConnectionFactory#useSslProtocol() * @see ConnectionFactory#useSslProtocol(String, TrustManager) + * @since 5.4.0 */ public void enableHostnameVerification() { enableHostnameVerificationForNio(); From b8197cc9f1c8ecb085f1c2a5e2fe1060de01fbe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 27 Aug 2018 09:39:37 +0200 Subject: [PATCH 0886/2114] Fix hostname verification successful test case The capture of the hostname command would add a \n at the end of the line and the hostname resolution would fail. References #384 --- .../rabbitmq/client/test/ssl/HostnameVerification.java | 9 +++++---- src/test/java/com/rabbitmq/tools/Host.java | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java index 06ee47c0a9..54f3e5b947 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java @@ -111,13 +111,14 @@ public void hostnameVerificationFailsBecauseCertificateNotIssuedForLoopbackInter fail("The server certificate isn't issued for 127.0.0.1, the TLS handshake should have failed"); } + @Test public void hostnameVerificationSucceeds() throws Exception { ConnectionFactory connectionFactory = TestUtils.connectionFactory(); connectionFactory.useSslProtocol(sslContext); customizer.accept(connectionFactory); - Connection conn = connectionFactory.newConnection( - () -> singletonList(new Address(Host.systemHostname(), ConnectionFactory.DEFAULT_AMQP_OVER_SSL_PORT))); - assertTrue(conn.isOpen()); - conn.close(); + try (Connection conn = connectionFactory.newConnection( + () -> singletonList(new Address(Host.systemHostname(), ConnectionFactory.DEFAULT_AMQP_OVER_SSL_PORT)))) { + assertTrue(conn.isOpen()); + } } } diff --git a/src/test/java/com/rabbitmq/tools/Host.java b/src/test/java/com/rabbitmq/tools/Host.java index ba77e03f4c..69b7bac729 100644 --- a/src/test/java/com/rabbitmq/tools/Host.java +++ b/src/test/java/com/rabbitmq/tools/Host.java @@ -122,7 +122,7 @@ public static Process invokeMakeTarget(String command) throws IOException { public static String systemHostname() throws IOException { Process process = executeCommandIgnoringErrors("hostname"); - return capture(process.getInputStream()); + return capture(process.getInputStream()).trim(); } public static String makeCommand() From 02b21b60b136d8039b1815dd1ecffedfe1989c6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 27 Aug 2018 09:39:37 +0200 Subject: [PATCH 0887/2114] Fix hostname verification successful test case The capture of the hostname command would add a \n at the end of the line and the hostname resolution would fail. References #384 (cherry picked from commit b8197cc9f1c8ecb085f1c2a5e2fe1060de01fbe5) --- .../rabbitmq/client/test/ssl/HostnameVerification.java | 9 +++++---- src/test/java/com/rabbitmq/tools/Host.java | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java index 06ee47c0a9..54f3e5b947 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java @@ -111,13 +111,14 @@ public void hostnameVerificationFailsBecauseCertificateNotIssuedForLoopbackInter fail("The server certificate isn't issued for 127.0.0.1, the TLS handshake should have failed"); } + @Test public void hostnameVerificationSucceeds() throws Exception { ConnectionFactory connectionFactory = TestUtils.connectionFactory(); connectionFactory.useSslProtocol(sslContext); customizer.accept(connectionFactory); - Connection conn = connectionFactory.newConnection( - () -> singletonList(new Address(Host.systemHostname(), ConnectionFactory.DEFAULT_AMQP_OVER_SSL_PORT))); - assertTrue(conn.isOpen()); - conn.close(); + try (Connection conn = connectionFactory.newConnection( + () -> singletonList(new Address(Host.systemHostname(), ConnectionFactory.DEFAULT_AMQP_OVER_SSL_PORT)))) { + assertTrue(conn.isOpen()); + } } } diff --git a/src/test/java/com/rabbitmq/tools/Host.java b/src/test/java/com/rabbitmq/tools/Host.java index ba77e03f4c..69b7bac729 100644 --- a/src/test/java/com/rabbitmq/tools/Host.java +++ b/src/test/java/com/rabbitmq/tools/Host.java @@ -122,7 +122,7 @@ public static Process invokeMakeTarget(String command) throws IOException { public static String systemHostname() throws IOException { Process process = executeCommandIgnoringErrors("hostname"); - return capture(process.getInputStream()); + return capture(process.getInputStream()).trim(); } public static String makeCommand() From 8dde8b59eae20eab1614ae8a0c87d2e08a5d954b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 27 Aug 2018 10:18:05 +0200 Subject: [PATCH 0888/2114] Disable DNS resolution when using TLS Fixes #400 --- .../rabbitmq/client/ConnectionFactory.java | 2 +- .../client/test/ConnectionFactoryTest.java | 59 +++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 2f8b55d050..e2bd6ef507 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -1219,7 +1219,7 @@ public Connection newConnection(ExecutorService executor, String connectionName) } protected AddressResolver createAddressResolver(List

addresses) { - if(addresses.size() == 1) { + if(addresses.size() == 1 && !isSSL()) { return new DnsRecordIpAddressResolver(addresses.get(0), isSSL()); } else { return new ListAddressResolver(addresses); diff --git a/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java b/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java index cc81cc13a2..8d6e94e416 100644 --- a/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java +++ b/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java @@ -16,22 +16,32 @@ package com.rabbitmq.client.test; import com.rabbitmq.client.Address; +import com.rabbitmq.client.AddressResolver; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.DnsRecordIpAddressResolver; +import com.rabbitmq.client.ListAddressResolver; import com.rabbitmq.client.MetricsCollector; import com.rabbitmq.client.impl.AMQConnection; import com.rabbitmq.client.impl.ConnectionParams; import com.rabbitmq.client.impl.CredentialsProvider; import com.rabbitmq.client.impl.FrameHandler; import com.rabbitmq.client.impl.FrameHandlerFactory; +import org.hamcrest.Matchers; +import org.junit.Assert; import org.junit.Test; import java.io.IOException; +import java.util.List; import java.util.Queue; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.notNullValue; import static org.junit.Assert.*; import static org.mockito.Mockito.*; @@ -90,4 +100,53 @@ protected AMQConnection createConnection(ConnectionParams params, FrameHandler f assertTrue(createCalled.get()); } + @Test public void shouldUseDnsResolutionWhenOneAddressAndNoTls() throws Exception { + AMQConnection connection = mock(AMQConnection.class); + AtomicReference addressResolver = new AtomicReference<>(); + + ConnectionFactory connectionFactory = new ConnectionFactory() { + @Override + protected AMQConnection createConnection(ConnectionParams params, FrameHandler frameHandler, + MetricsCollector metricsCollector) { + return connection; + } + + @Override + protected AddressResolver createAddressResolver(List
addresses) { + addressResolver.set(super.createAddressResolver(addresses)); + return addressResolver.get(); + } + }; + + doNothing().when(connection).start(); + connectionFactory.newConnection(); + + assertThat(addressResolver.get(), allOf(notNullValue(), instanceOf(DnsRecordIpAddressResolver.class))); + } + + @Test public void shouldNotUseDnsResolutionWhenOneAddressAndNoTls() throws Exception { + AMQConnection connection = mock(AMQConnection.class); + AtomicReference addressResolver = new AtomicReference<>(); + + ConnectionFactory connectionFactory = new ConnectionFactory() { + @Override + protected AMQConnection createConnection(ConnectionParams params, FrameHandler frameHandler, + MetricsCollector metricsCollector) { + return connection; + } + + @Override + protected AddressResolver createAddressResolver(List
addresses) { + addressResolver.set(super.createAddressResolver(addresses)); + return addressResolver.get(); + } + }; + + doNothing().when(connection).start(); + connectionFactory.useSslProtocol(); + connectionFactory.newConnection(); + + assertThat(addressResolver.get(), allOf(notNullValue(), instanceOf(ListAddressResolver.class))); + } + } From 5a7af10cb28ea6bd4b159dcace0502e4dde20850 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 27 Aug 2018 10:24:11 +0200 Subject: [PATCH 0889/2114] Disable DNS resolution on connection creation This can interfer with hostname resolution when TLS is on. Fixes #401 --- .../rabbitmq/client/ConnectionFactory.java | 6 +- .../client/test/ConnectionFactoryTest.java | 57 +++++++++++++++++++ 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 2f8b55d050..8d7c18258a 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -1219,11 +1219,7 @@ public Connection newConnection(ExecutorService executor, String connectionName) } protected AddressResolver createAddressResolver(List
addresses) { - if(addresses.size() == 1) { - return new DnsRecordIpAddressResolver(addresses.get(0), isSSL()); - } else { - return new ListAddressResolver(addresses); - } + return new ListAddressResolver(addresses); } @Override public ConnectionFactory clone(){ diff --git a/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java b/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java index cc81cc13a2..08b66c4c90 100644 --- a/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java +++ b/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java @@ -16,8 +16,11 @@ package com.rabbitmq.client.test; import com.rabbitmq.client.Address; +import com.rabbitmq.client.AddressResolver; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.DnsRecordIpAddressResolver; +import com.rabbitmq.client.ListAddressResolver; import com.rabbitmq.client.MetricsCollector; import com.rabbitmq.client.impl.AMQConnection; import com.rabbitmq.client.impl.ConnectionParams; @@ -27,11 +30,16 @@ import org.junit.Test; import java.io.IOException; +import java.util.List; import java.util.Queue; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.notNullValue; import static org.junit.Assert.*; import static org.mockito.Mockito.*; @@ -90,4 +98,53 @@ protected AMQConnection createConnection(ConnectionParams params, FrameHandler f assertTrue(createCalled.get()); } + @Test public void shouldNotUseDnsResolutionWhenOneAddressAndNoTls() throws Exception { + AMQConnection connection = mock(AMQConnection.class); + AtomicReference addressResolver = new AtomicReference<>(); + + ConnectionFactory connectionFactory = new ConnectionFactory() { + @Override + protected AMQConnection createConnection(ConnectionParams params, FrameHandler frameHandler, + MetricsCollector metricsCollector) { + return connection; + } + + @Override + protected AddressResolver createAddressResolver(List
addresses) { + addressResolver.set(super.createAddressResolver(addresses)); + return addressResolver.get(); + } + }; + + doNothing().when(connection).start(); + connectionFactory.newConnection(); + + assertThat(addressResolver.get(), allOf(notNullValue(), instanceOf(ListAddressResolver.class))); + } + + @Test public void shouldNotUseDnsResolutionWhenOneAddressAndTls() throws Exception { + AMQConnection connection = mock(AMQConnection.class); + AtomicReference addressResolver = new AtomicReference<>(); + + ConnectionFactory connectionFactory = new ConnectionFactory() { + @Override + protected AMQConnection createConnection(ConnectionParams params, FrameHandler frameHandler, + MetricsCollector metricsCollector) { + return connection; + } + + @Override + protected AddressResolver createAddressResolver(List
addresses) { + addressResolver.set(super.createAddressResolver(addresses)); + return addressResolver.get(); + } + }; + + doNothing().when(connection).start(); + connectionFactory.useSslProtocol(); + connectionFactory.newConnection(); + + assertThat(addressResolver.get(), allOf(notNullValue(), instanceOf(ListAddressResolver.class))); + } + } From 02164d71c33db72649aeb1c646f57b8fbfda00ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 27 Aug 2018 10:25:01 +0200 Subject: [PATCH 0890/2114] Fix test method name References #400 --- .../java/com/rabbitmq/client/test/ConnectionFactoryTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java b/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java index 8d6e94e416..4cf56ae7b6 100644 --- a/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java +++ b/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java @@ -124,7 +124,7 @@ protected AddressResolver createAddressResolver(List
addresses) { assertThat(addressResolver.get(), allOf(notNullValue(), instanceOf(DnsRecordIpAddressResolver.class))); } - @Test public void shouldNotUseDnsResolutionWhenOneAddressAndNoTls() throws Exception { + @Test public void shouldNotUseDnsResolutionWhenOneAddressAndTls() throws Exception { AMQConnection connection = mock(AMQConnection.class); AtomicReference addressResolver = new AtomicReference<>(); From 7c3515b5c81a6779be0ef290839fcfbd815b50fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 27 Aug 2018 10:31:27 +0200 Subject: [PATCH 0891/2114] All setters in NioParams return the current instance It was not the case for a couple of setters. Fixes #396 --- src/main/java/com/rabbitmq/client/impl/nio/NioParams.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java b/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java index 80b8624447..c32d5350a9 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java @@ -301,9 +301,11 @@ public SocketChannelConfigurator getSocketChannelConfigurator() { * Nagle's algorithm. * * @param configurator the configurator to use + * @return this {@link NioParams} instance */ - public void setSocketChannelConfigurator(SocketChannelConfigurator configurator) { + public NioParams setSocketChannelConfigurator(SocketChannelConfigurator configurator) { this.socketChannelConfigurator = configurator; + return this; } public SslEngineConfigurator getSslEngineConfigurator() { @@ -318,9 +320,11 @@ public SslEngineConfigurator getSslEngineConfigurator() { * The default implementation doesn't do anything. * * @param configurator the configurator to use + * @return this {@link NioParams} instance */ - public void setSslEngineConfigurator(SslEngineConfigurator configurator) { + public NioParams setSslEngineConfigurator(SslEngineConfigurator configurator) { this.sslEngineConfigurator = configurator; + return this; } public ExecutorService getConnectionShutdownExecutor() { From f73b80ad4e93fd0ba6677be5aeadcd74779f1c98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 28 Aug 2018 09:41:04 +0200 Subject: [PATCH 0892/2114] Use localhost for hostname verification test localhost is now part of the SAN of the generated server certificate, so the hostname verification succeeds. References #394 --- .../java/com/rabbitmq/client/test/ssl/HostnameVerification.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java index 54f3e5b947..d7a3e407e3 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java @@ -117,7 +117,7 @@ public void hostnameVerificationSucceeds() throws Exception { connectionFactory.useSslProtocol(sslContext); customizer.accept(connectionFactory); try (Connection conn = connectionFactory.newConnection( - () -> singletonList(new Address(Host.systemHostname(), ConnectionFactory.DEFAULT_AMQP_OVER_SSL_PORT)))) { + () -> singletonList(new Address("localhost", ConnectionFactory.DEFAULT_AMQP_OVER_SSL_PORT)))) { assertTrue(conn.isOpen()); } } From b6b601d8192fa03bcced73442d2d41929583c9e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 28 Aug 2018 09:41:04 +0200 Subject: [PATCH 0893/2114] Use localhost for hostname verification test localhost is now part of the SAN of the generated server certificate, so the hostname verification succeeds. References #394 (cherry picked from commit f73b80ad4e93fd0ba6677be5aeadcd74779f1c98) --- .../java/com/rabbitmq/client/test/ssl/HostnameVerification.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java index 54f3e5b947..d7a3e407e3 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java @@ -117,7 +117,7 @@ public void hostnameVerificationSucceeds() throws Exception { connectionFactory.useSslProtocol(sslContext); customizer.accept(connectionFactory); try (Connection conn = connectionFactory.newConnection( - () -> singletonList(new Address(Host.systemHostname(), ConnectionFactory.DEFAULT_AMQP_OVER_SSL_PORT)))) { + () -> singletonList(new Address("localhost", ConnectionFactory.DEFAULT_AMQP_OVER_SSL_PORT)))) { assertTrue(conn.isOpen()); } } From ab97c012e85329f5049ba18fa4fbdd15413cb6d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 28 Aug 2018 09:47:51 +0200 Subject: [PATCH 0894/2114] Remove unused import in test --- .../java/com/rabbitmq/client/test/ssl/HostnameVerification.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java index d7a3e407e3..2ddef41aeb 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java @@ -19,7 +19,6 @@ import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.test.TestUtils; -import com.rabbitmq.tools.Host; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; From d5672cb618f1d447b3184527f104b60084cabbdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 28 Aug 2018 09:47:51 +0200 Subject: [PATCH 0895/2114] Remove unused import in test (cherry picked from commit ab97c012e85329f5049ba18fa4fbdd15413cb6d5) --- .../java/com/rabbitmq/client/test/ssl/HostnameVerification.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java index d7a3e407e3..2ddef41aeb 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java @@ -19,7 +19,6 @@ import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.test.TestUtils; -import com.rabbitmq.tools.Host; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; From e43f14e28675fa4a650c5800766ce89465220415 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Tue, 28 Aug 2018 12:06:21 +0000 Subject: [PATCH 0896/2114] [maven-release-plugin] prepare release v5.4.0.RC2 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 19350b6ff6..82a507e476 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.4.0-SNAPSHOT + 5.4.0.RC2 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v5.4.0.RC2 From 387438ac816973aa0d782597e92d6dcd6ec5b1a7 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Tue, 28 Aug 2018 12:06:26 +0000 Subject: [PATCH 0897/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 82a507e476..19350b6ff6 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.4.0.RC2 + 5.4.0-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v5.4.0.RC2 + HEAD From 8b8c58ae1bdb88027f6bdf37757fdadeeb245b24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 28 Aug 2018 14:15:10 +0200 Subject: [PATCH 0898/2114] Set release version to 5.4.0.RC3 --- release-versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-versions.txt b/release-versions.txt index 56eb83cff6..70f633ccd8 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="5.4.0.RC2" +RELEASE_VERSION="5.4.0.RC3" DEVELOPMENT_VERSION="5.4.0-SNAPSHOT" From 9dc2a6a145d6cc0071772d9b6a3acb30076d7d1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 28 Aug 2018 18:08:43 +0200 Subject: [PATCH 0899/2114] Use rabbitmqctl to manipulate alarms in tests Avoid using make and depending on the umbrella. --- .../java/com/rabbitmq/client/test/BrokerTestCase.java | 10 +++++----- .../com/rabbitmq/client/test/server/MemoryAlarms.java | 9 ++------- src/test/java/com/rabbitmq/tools/Host.java | 8 ++++++++ 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java index 216cbb8e47..b9ee4ecceb 100644 --- a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java +++ b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java @@ -320,17 +320,17 @@ protected void deleteQueues(String [] queues) throws IOException { } } - protected void clearAllResourceAlarms() throws IOException, InterruptedException { + protected void clearAllResourceAlarms() throws IOException { clearResourceAlarm("memory"); clearResourceAlarm("disk"); } - protected void setResourceAlarm(String source) throws IOException, InterruptedException { - Host.invokeMakeTarget("set-resource-alarm SOURCE=" + source); + protected void setResourceAlarm(String source) throws IOException { + Host.setResourceAlarm(source); } - protected void clearResourceAlarm(String source) throws IOException, InterruptedException { - Host.invokeMakeTarget("clear-resource-alarm SOURCE=" + source); + protected void clearResourceAlarm(String source) throws IOException { + Host.clearResourceAlarm(source); } protected void block() throws IOException, InterruptedException { diff --git a/src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java b/src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java index 998fecd987..76a092d868 100644 --- a/src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java +++ b/src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java @@ -47,6 +47,7 @@ public void setUp() throws IOException, TimeoutException { @Override public void tearDown() throws IOException, TimeoutException { + clearAllResourceAlarms(); if (channel2 != null) { channel2.abort(); channel2 = null; @@ -66,13 +67,7 @@ protected void createResources() throws IOException { @Override protected void releaseResources() throws IOException { - try { - clearAllResourceAlarms(); - } catch (InterruptedException e) { - e.printStackTrace(); - } finally { - channel.queueDelete(Q); - } + channel.queueDelete(Q); } @Test public void flowControl() throws IOException, InterruptedException { diff --git a/src/test/java/com/rabbitmq/tools/Host.java b/src/test/java/com/rabbitmq/tools/Host.java index 69b7bac729..1cae40f9b7 100644 --- a/src/test/java/com/rabbitmq/tools/Host.java +++ b/src/test/java/com/rabbitmq/tools/Host.java @@ -109,6 +109,14 @@ public static Process rabbitmqctlIgnoreErrors(String command) throws IOException " " + command); } + public static void setResourceAlarm(String source) throws IOException { + rabbitmqctl("eval 'rabbit_alarm:set_alarm({{resource_limit, " + source + ", node()}, []}).'"); + } + + public static void clearResourceAlarm(String source) throws IOException { + rabbitmqctl("eval 'rabbit_alarm:clear_alarm({resource_limit, " + source + ", node()}).'"); + } + public static Process invokeMakeTarget(String command) throws IOException { File rabbitmqctl = new File(rabbitmqctlCommand()); return executeCommand(makeCommand() + From 9b5adbe3c2ae68e99defb3fc50199a5ce8bc474b Mon Sep 17 00:00:00 2001 From: Michael Dent Date: Tue, 28 Aug 2018 13:20:43 -0500 Subject: [PATCH 0900/2114] tweaks to recovery retry helper --- .../client/impl/recovery/DefaultRetryHandler.java | 8 ++++---- .../impl/recovery/TopologyRecoveryRetryLogic.java | 13 +++++-------- .../test/functional/TopologyRecoveryRetry.java | 2 +- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java b/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java index 98978eb6d1..9b151ccd25 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java @@ -103,11 +103,11 @@ public RetryResult retryConsumerRecovery(RetryContext context) throws Exception protected RetryResult doRetry(BiPredicate condition, RetryOperation operation, RecordedEntity entity, RetryContext context) throws Exception { - log(entity, context.exception()); int attempts = 0; Exception exception = context.exception(); while (attempts < retryAttempts) { if (condition.test(entity, exception)) { + log(entity, context.exception(), attempts); backoffPolicy.backoff(attempts + 1); try { Object result = operation.call(context); @@ -122,11 +122,11 @@ protected RetryResult doRetry(BiPredicate condition, throw exception; } } - throw context.exception(); + throw exception; } - protected void log(RecordedEntity entity, Exception exception) { - LOGGER.info("Error while recovering {}, retrying with {} attempt(s).", entity, retryAttempts, exception); + protected void log(RecordedEntity entity, Exception exception, int attempts) { + LOGGER.info("Error while recovering {}, retrying with {} more attempt(s).", entity, retryAttempts - attempts, exception); } public interface RetryOperation { diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java index 9d8d2be9a5..26db1f27a8 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java @@ -17,11 +17,9 @@ import com.rabbitmq.client.AMQP; import com.rabbitmq.client.ShutdownSignalException; +import com.rabbitmq.utility.Utility; -import java.util.List; import java.util.function.BiPredicate; -import java.util.function.Predicate; - import static com.rabbitmq.client.impl.recovery.TopologyRecoveryRetryHandlerBuilder.builder; /** @@ -106,7 +104,7 @@ public abstract class TopologyRecoveryRetryLogic { public static final DefaultRetryHandler.RetryOperation RECOVER_CONSUMER_QUEUE_BINDINGS = context -> { if (context.entity() instanceof RecordedConsumer) { String queue = context.consumer().getQueue(); - for (RecordedBinding recordedBinding : context.connection().getRecordedBindings()) { + for (RecordedBinding recordedBinding : Utility.copy(context.connection().getRecordedBindings())) { if (recordedBinding instanceof RecordedQueueBinding && queue.equals(recordedBinding.getDestination())) { recordedBinding.recover(); } @@ -121,16 +119,15 @@ public abstract class TopologyRecoveryRetryLogic { public static final DefaultRetryHandler.RetryOperation RECOVER_CONSUMER = context -> context.consumer().recover(); /** - * Pre-configured {@link DefaultRetryHandler} that retries recovery of bindings and consumers + * Pre-configured {@link TopologyRecoveryRetryHandlerBuilder} that retries recovery of bindings and consumers * when their respective queue is not found. * This retry handler can be useful for long recovery processes, whereby auto-delete queues * can be deleted between queue recovery and binding/consumer recovery. */ - public static final RetryHandler RETRY_ON_QUEUE_NOT_FOUND_RETRY_HANDLER = builder() + public static final TopologyRecoveryRetryHandlerBuilder RETRY_ON_QUEUE_NOT_FOUND_RETRY_HANDLER = builder() .bindingRecoveryRetryCondition(CHANNEL_CLOSED_NOT_FOUND) .consumerRecoveryRetryCondition(CHANNEL_CLOSED_NOT_FOUND) .bindingRecoveryRetryOperation(RECOVER_CHANNEL.andThen(RECOVER_BINDING_QUEUE).andThen(RECOVER_BINDING)) .consumerRecoveryRetryOperation(RECOVER_CHANNEL.andThen(RECOVER_CONSUMER_QUEUE.andThen(RECOVER_CONSUMER) - .andThen(RECOVER_CONSUMER_QUEUE_BINDINGS))) - .build(); + .andThen(RECOVER_CONSUMER_QUEUE_BINDINGS))); } diff --git a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java index 71277c9826..ddfef8a823 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java +++ b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java @@ -51,7 +51,7 @@ public void topologyRecoveryRetry() throws Exception { @Override protected ConnectionFactory newConnectionFactory() { ConnectionFactory connectionFactory = TestUtils.connectionFactory(); - connectionFactory.setTopologyRecoveryRetryHandler(RETRY_ON_QUEUE_NOT_FOUND_RETRY_HANDLER); + connectionFactory.setTopologyRecoveryRetryHandler(RETRY_ON_QUEUE_NOT_FOUND_RETRY_HANDLER.build()); connectionFactory.setNetworkRecoveryInterval(1000); return connectionFactory; } From b88f7f587b5e15a7d20a8bf0d695440b1bcfae80 Mon Sep 17 00:00:00 2001 From: Michael Dent Date: Tue, 28 Aug 2018 13:42:15 -0500 Subject: [PATCH 0901/2114] was logging the wrong exception --- .../com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java b/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java index 9b151ccd25..ec9a86cbc8 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java @@ -107,7 +107,7 @@ protected RetryResult doRetry(BiPredicate condition, Exception exception = context.exception(); while (attempts < retryAttempts) { if (condition.test(entity, exception)) { - log(entity, context.exception(), attempts); + log(entity, exception, attempts); backoffPolicy.backoff(attempts + 1); try { Object result = operation.call(context); From 9bc27a7c03b88097e8d53380972dc61cb5bdfacf Mon Sep 17 00:00:00 2001 From: Luke Bakken Date: Tue, 28 Aug 2018 16:18:35 -0700 Subject: [PATCH 0902/2114] Update git-commit-msgs link --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 16ee8fb67d..592e7ced57 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -93,7 +93,7 @@ contribution. If something isn't clear, feel free to ask on our [mailing list][rmq-users]. [rmq-collect-env]: https://github.com/rabbitmq/support-tools/blob/master/scripts/rabbitmq-collect-env -[git-commit-msgs]: https://goo.gl/xwWq +[git-commit-msgs]: https://chris.beams.io/posts/git-commit/ [rmq-users]: https://groups.google.com/forum/#!forum/rabbitmq-users [ca-agreement]: https://cla.pivotal.io/sign/rabbitmq [github-fork]: https://help.github.com/articles/fork-a-repo/ From 6ff4fd60a413fa7e05073622f47916f22e4114ec Mon Sep 17 00:00:00 2001 From: Michael Dent Date: Tue, 28 Aug 2018 13:20:43 -0500 Subject: [PATCH 0903/2114] tweaks to recovery retry helper (cherry picked from commit 9b5adbe3c2ae68e99defb3fc50199a5ce8bc474b) --- .../client/impl/recovery/DefaultRetryHandler.java | 8 ++++---- .../impl/recovery/TopologyRecoveryRetryLogic.java | 13 +++++-------- .../test/functional/TopologyRecoveryRetry.java | 2 +- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java b/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java index 98978eb6d1..9b151ccd25 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java @@ -103,11 +103,11 @@ public RetryResult retryConsumerRecovery(RetryContext context) throws Exception protected RetryResult doRetry(BiPredicate condition, RetryOperation operation, RecordedEntity entity, RetryContext context) throws Exception { - log(entity, context.exception()); int attempts = 0; Exception exception = context.exception(); while (attempts < retryAttempts) { if (condition.test(entity, exception)) { + log(entity, context.exception(), attempts); backoffPolicy.backoff(attempts + 1); try { Object result = operation.call(context); @@ -122,11 +122,11 @@ protected RetryResult doRetry(BiPredicate condition, throw exception; } } - throw context.exception(); + throw exception; } - protected void log(RecordedEntity entity, Exception exception) { - LOGGER.info("Error while recovering {}, retrying with {} attempt(s).", entity, retryAttempts, exception); + protected void log(RecordedEntity entity, Exception exception, int attempts) { + LOGGER.info("Error while recovering {}, retrying with {} more attempt(s).", entity, retryAttempts - attempts, exception); } public interface RetryOperation { diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java index 9d8d2be9a5..26db1f27a8 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java @@ -17,11 +17,9 @@ import com.rabbitmq.client.AMQP; import com.rabbitmq.client.ShutdownSignalException; +import com.rabbitmq.utility.Utility; -import java.util.List; import java.util.function.BiPredicate; -import java.util.function.Predicate; - import static com.rabbitmq.client.impl.recovery.TopologyRecoveryRetryHandlerBuilder.builder; /** @@ -106,7 +104,7 @@ public abstract class TopologyRecoveryRetryLogic { public static final DefaultRetryHandler.RetryOperation RECOVER_CONSUMER_QUEUE_BINDINGS = context -> { if (context.entity() instanceof RecordedConsumer) { String queue = context.consumer().getQueue(); - for (RecordedBinding recordedBinding : context.connection().getRecordedBindings()) { + for (RecordedBinding recordedBinding : Utility.copy(context.connection().getRecordedBindings())) { if (recordedBinding instanceof RecordedQueueBinding && queue.equals(recordedBinding.getDestination())) { recordedBinding.recover(); } @@ -121,16 +119,15 @@ public abstract class TopologyRecoveryRetryLogic { public static final DefaultRetryHandler.RetryOperation RECOVER_CONSUMER = context -> context.consumer().recover(); /** - * Pre-configured {@link DefaultRetryHandler} that retries recovery of bindings and consumers + * Pre-configured {@link TopologyRecoveryRetryHandlerBuilder} that retries recovery of bindings and consumers * when their respective queue is not found. * This retry handler can be useful for long recovery processes, whereby auto-delete queues * can be deleted between queue recovery and binding/consumer recovery. */ - public static final RetryHandler RETRY_ON_QUEUE_NOT_FOUND_RETRY_HANDLER = builder() + public static final TopologyRecoveryRetryHandlerBuilder RETRY_ON_QUEUE_NOT_FOUND_RETRY_HANDLER = builder() .bindingRecoveryRetryCondition(CHANNEL_CLOSED_NOT_FOUND) .consumerRecoveryRetryCondition(CHANNEL_CLOSED_NOT_FOUND) .bindingRecoveryRetryOperation(RECOVER_CHANNEL.andThen(RECOVER_BINDING_QUEUE).andThen(RECOVER_BINDING)) .consumerRecoveryRetryOperation(RECOVER_CHANNEL.andThen(RECOVER_CONSUMER_QUEUE.andThen(RECOVER_CONSUMER) - .andThen(RECOVER_CONSUMER_QUEUE_BINDINGS))) - .build(); + .andThen(RECOVER_CONSUMER_QUEUE_BINDINGS))); } diff --git a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java index 273ebe1544..f6dc2ac5ae 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java +++ b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java @@ -51,7 +51,7 @@ public void topologyRecoveryRetry() throws Exception { @Override protected ConnectionFactory newConnectionFactory() { ConnectionFactory connectionFactory = TestUtils.connectionFactory(); - connectionFactory.setTopologyRecoveryRetryHandler(RETRY_ON_QUEUE_NOT_FOUND_RETRY_HANDLER); + connectionFactory.setTopologyRecoveryRetryHandler(RETRY_ON_QUEUE_NOT_FOUND_RETRY_HANDLER.build()); connectionFactory.setNetworkRecoveryInterval(1000); return connectionFactory; } From 87d7f40b90f0bdfae6419e4c0e34996c867c5f30 Mon Sep 17 00:00:00 2001 From: Michael Dent Date: Tue, 28 Aug 2018 13:42:15 -0500 Subject: [PATCH 0904/2114] was logging the wrong exception (cherry picked from commit b88f7f587b5e15a7d20a8bf0d695440b1bcfae80) --- .../com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java b/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java index 9b151ccd25..ec9a86cbc8 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java @@ -107,7 +107,7 @@ protected RetryResult doRetry(BiPredicate condition, Exception exception = context.exception(); while (attempts < retryAttempts) { if (condition.test(entity, exception)) { - log(entity, context.exception(), attempts); + log(entity, exception, attempts); backoffPolicy.backoff(attempts + 1); try { Object result = operation.call(context); From de58023986e4b0cd3d66159b5f6835b7f518d6f6 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Wed, 29 Aug 2018 09:19:53 +0000 Subject: [PATCH 0905/2114] [maven-release-plugin] prepare release v5.4.0.RC3 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 19350b6ff6..9597e0ca2e 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.4.0-SNAPSHOT + 5.4.0.RC3 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v5.4.0.RC3 From 6e51a3775a0dc404f8808bea4ecabdd58b76e4f9 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Wed, 29 Aug 2018 09:19:59 +0000 Subject: [PATCH 0906/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 9597e0ca2e..19350b6ff6 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.4.0.RC3 + 5.4.0-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v5.4.0.RC3 + HEAD From 714c8781872cc3f3cc271e826d059542e9fce7b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 29 Aug 2018 11:37:20 +0200 Subject: [PATCH 0907/2114] Set release version to 5.4.0.RC4 --- release-versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-versions.txt b/release-versions.txt index 70f633ccd8..84c22280ae 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="5.4.0.RC3" +RELEASE_VERSION="5.4.0.RC4" DEVELOPMENT_VERSION="5.4.0-SNAPSHOT" From 73a4c766d56681dbfad315ccf4975e05190f4a5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 29 Aug 2018 15:47:59 +0200 Subject: [PATCH 0908/2114] Use only rabbitmqctl to control nodes in tests No more dependency on make. This makes the test suite independant from make and runnable on vanilla nodes instead of nodes started with the umbrella. --- .../client/test/AbstractRMQTestSuite.java | 17 ----- .../rabbitmq/client/test/BrokerTestCase.java | 4 +- .../test/functional/ClusteredTestBase.java | 4 +- .../server/DeadLetterExchangeDurable.java | 4 +- .../test/server/DurableBindingLifecycle.java | 9 +-- src/test/java/com/rabbitmq/tools/Host.java | 68 ++++++++++++------- 6 files changed, 50 insertions(+), 56 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java b/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java index cb27d22e7c..ad8a59c2aa 100644 --- a/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java +++ b/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java @@ -43,23 +43,6 @@ public abstract class AbstractRMQTestSuite { } public static boolean requiredProperties() { - /* GNU Make. */ - String make = Host.makeCommand(); - boolean isGNUMake = false; - if (make != null) { - try { - Process makeProc = Host.executeCommandIgnoringErrors(make + " --version"); - String makeVersion = Host.capture(makeProc.getInputStream()); - isGNUMake = makeVersion.startsWith("GNU Make"); - } catch (IOException e) {} - } - if (!isGNUMake) { - System.err.println( - "GNU Make required; please set \"make.bin\" system property" + - " or \"$MAKE\" environment variable"); - return false; - } - /* Path to RabbitMQ. */ String rabbitmq = Host.rabbitmqDir(); if (rabbitmq == null || !new File(rabbitmq).isDirectory()) { diff --git a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java index b9ee4ecceb..1a00ca8c1b 100644 --- a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java +++ b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java @@ -143,8 +143,8 @@ protected void restart() protected void bareRestart() throws IOException { - Host.invokeMakeTarget( - "stop-rabbit-on-node start-rabbit-on-node"); + Host.stopRabbitOnNode(); + Host.startRabbitOnNode(); } public void openConnection() diff --git a/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java b/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java index c198db8bd0..c3fabd966b 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java @@ -124,10 +124,10 @@ public void closeConnection() throws IOException { } protected void stopSecondary() throws IOException { - Host.invokeMakeTarget("stop-rabbit-on-node RABBITMQ_NODENAME=\'" + Host.nodenameB() + "\'"); + Host.stopRabbitOnNode(Host.nodenameB()); } protected void startSecondary() throws IOException { - Host.invokeMakeTarget("start-rabbit-on-node RABBITMQ_NODENAME=\'" + Host.nodenameB() + "\'"); + Host.startRabbitOnNode(Host.nodenameB()); } } diff --git a/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java b/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java index 3973521128..c6c4e85c91 100644 --- a/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java +++ b/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java @@ -58,9 +58,9 @@ protected void releaseResources() throws IOException { } closeConnection(); - Host.invokeMakeTarget("stop-rabbit-on-node"); + Host.stopRabbitOnNode(); Thread.sleep(5000); - Host.invokeMakeTarget("start-rabbit-on-node"); + Host.startRabbitOnNode(); openConnection(); openChannel(); diff --git a/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java b/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java index 4c4b6fd910..d68de23811 100644 --- a/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java +++ b/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java @@ -47,13 +47,8 @@ protected void restart() throws IOException, TimeoutException { alternateConnection = null; alternateChannel = null; - Host.invokeMakeTarget( - "stop-node" + - " start-background-broker" + - " RABBITMQ_NODENAME=\'" + Host.nodenameB() + "\'" + - " RABBITMQ_NODE_PORT=" + Host.node_portB() + - " RABBITMQ_CONFIG_FILE=\'" + Host.config_fileB() + "\'" - ); + Host.rabbitmqctl("stop_app", Host.nodenameB()); + Host.rabbitmqctl("start_app", Host.nodenameB()); } restartPrimary(); } diff --git a/src/test/java/com/rabbitmq/tools/Host.java b/src/test/java/com/rabbitmq/tools/Host.java index 1cae40f9b7..e5ebaa042c 100644 --- a/src/test/java/com/rabbitmq/tools/Host.java +++ b/src/test/java/com/rabbitmq/tools/Host.java @@ -17,14 +17,16 @@ package com.rabbitmq.tools; import java.io.BufferedReader; -import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.impl.NetworkConnection; +import com.rabbitmq.client.test.TestUtils; public class Host { @@ -103,6 +105,12 @@ public static Process rabbitmqctl(String command) throws IOException { " " + command); } + public static Process rabbitmqctl(String command, String node) throws IOException { + return executeCommand(rabbitmqctlCommand() + + " -n \'" + node + "\'" + + " " + command); + } + public static Process rabbitmqctlIgnoreErrors(String command) throws IOException { return executeCommandIgnoringErrors(rabbitmqctlCommand() + " -n \'" + nodenameA() + "\'" + @@ -117,25 +125,43 @@ public static void clearResourceAlarm(String source) throws IOException { rabbitmqctl("eval 'rabbit_alarm:clear_alarm({resource_limit, " + source + ", node()}).'"); } - public static Process invokeMakeTarget(String command) throws IOException { - File rabbitmqctl = new File(rabbitmqctlCommand()); - return executeCommand(makeCommand() + - " -C \'" + rabbitmqDir() + "\'" + - " RABBITMQCTL=\'" + rabbitmqctl.getAbsolutePath() + "\'" + - " RABBITMQ_NODENAME=\'" + nodenameA() + "\'" + - " RABBITMQ_NODE_PORT=" + node_portA() + - " RABBITMQ_CONFIG_FILE=\'" + config_fileA() + "\'" + - " " + command); + public static void startRabbitOnNode(String node) throws IOException { + rabbitmqctl("eval 'rabbit:start().'", node); + String port = nodenameA().equals(node) ? node_portA() : node_portB(); + tryConnectFor(10_000, Integer.parseInt(port)); } - public static String systemHostname() throws IOException { - Process process = executeCommandIgnoringErrors("hostname"); - return capture(process.getInputStream()).trim(); + public static void startRabbitOnNode() throws IOException { + startRabbitOnNode(nodenameA()); } - public static String makeCommand() - { - return System.getProperty("make.bin", "make"); + public static void stopRabbitOnNode(String node) throws IOException { + rabbitmqctl("eval 'rabbit:stop().'", node); + } + + public static void stopRabbitOnNode() throws IOException { + stopRabbitOnNode(nodenameA()); + } + + public static void tryConnectFor(int timeoutInMs, int port) throws IOException { + int waitTime = 100; + int totalWaitTime = 0; + while (totalWaitTime <= timeoutInMs) { + try { + Thread.sleep(waitTime); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + totalWaitTime += waitTime; + ConnectionFactory connectionFactory = TestUtils.connectionFactory(); + connectionFactory.setPort(port); + try (Connection ignored = connectionFactory.newConnection()) { + return; + } catch (Exception e) { + // retrying + } + } + throw new IOException("Could not connect to broker for " + timeoutInMs + " ms"); } public static String nodenameA() @@ -148,11 +174,6 @@ public static String node_portA() return System.getProperty("test-broker.A.node_port"); } - public static String config_fileA() - { - return System.getProperty("test-broker.A.config_file"); - } - public static String nodenameB() { return System.getProperty("test-broker.B.nodename"); @@ -163,11 +184,6 @@ public static String node_portB() return System.getProperty("test-broker.B.node_port"); } - public static String config_fileB() - { - return System.getProperty("test-broker.B.config_file"); - } - public static String rabbitmqctlCommand() { return System.getProperty("rabbitmqctl.bin"); From 4199fb6553fbbeff6c232ecb99c3a9d5c907741e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 29 Aug 2018 16:49:43 +0200 Subject: [PATCH 0909/2114] Increase log level to debug tests --- src/test/resources/logback-test.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml index ee88f442c2..4bd2e37606 100644 --- a/src/test/resources/logback-test.xml +++ b/src/test/resources/logback-test.xml @@ -5,7 +5,7 @@ - + \ No newline at end of file From bf1af782e334428fc2092961a6e3c607637228e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 30 Aug 2018 10:26:37 +0200 Subject: [PATCH 0910/2114] Revert "Use only rabbitmqctl to control nodes in tests" This reverts commit 73a4c766d56681dbfad315ccf4975e05190f4a5c. The whole test suite would hang, at least on CI. --- .../client/test/AbstractRMQTestSuite.java | 17 +++++ .../rabbitmq/client/test/BrokerTestCase.java | 4 +- .../test/functional/ClusteredTestBase.java | 4 +- .../server/DeadLetterExchangeDurable.java | 4 +- .../test/server/DurableBindingLifecycle.java | 9 ++- src/test/java/com/rabbitmq/tools/Host.java | 68 +++++++------------ 6 files changed, 56 insertions(+), 50 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java b/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java index ad8a59c2aa..cb27d22e7c 100644 --- a/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java +++ b/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java @@ -43,6 +43,23 @@ public abstract class AbstractRMQTestSuite { } public static boolean requiredProperties() { + /* GNU Make. */ + String make = Host.makeCommand(); + boolean isGNUMake = false; + if (make != null) { + try { + Process makeProc = Host.executeCommandIgnoringErrors(make + " --version"); + String makeVersion = Host.capture(makeProc.getInputStream()); + isGNUMake = makeVersion.startsWith("GNU Make"); + } catch (IOException e) {} + } + if (!isGNUMake) { + System.err.println( + "GNU Make required; please set \"make.bin\" system property" + + " or \"$MAKE\" environment variable"); + return false; + } + /* Path to RabbitMQ. */ String rabbitmq = Host.rabbitmqDir(); if (rabbitmq == null || !new File(rabbitmq).isDirectory()) { diff --git a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java index 1a00ca8c1b..b9ee4ecceb 100644 --- a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java +++ b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java @@ -143,8 +143,8 @@ protected void restart() protected void bareRestart() throws IOException { - Host.stopRabbitOnNode(); - Host.startRabbitOnNode(); + Host.invokeMakeTarget( + "stop-rabbit-on-node start-rabbit-on-node"); } public void openConnection() diff --git a/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java b/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java index c3fabd966b..c198db8bd0 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java @@ -124,10 +124,10 @@ public void closeConnection() throws IOException { } protected void stopSecondary() throws IOException { - Host.stopRabbitOnNode(Host.nodenameB()); + Host.invokeMakeTarget("stop-rabbit-on-node RABBITMQ_NODENAME=\'" + Host.nodenameB() + "\'"); } protected void startSecondary() throws IOException { - Host.startRabbitOnNode(Host.nodenameB()); + Host.invokeMakeTarget("start-rabbit-on-node RABBITMQ_NODENAME=\'" + Host.nodenameB() + "\'"); } } diff --git a/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java b/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java index c6c4e85c91..3973521128 100644 --- a/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java +++ b/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java @@ -58,9 +58,9 @@ protected void releaseResources() throws IOException { } closeConnection(); - Host.stopRabbitOnNode(); + Host.invokeMakeTarget("stop-rabbit-on-node"); Thread.sleep(5000); - Host.startRabbitOnNode(); + Host.invokeMakeTarget("start-rabbit-on-node"); openConnection(); openChannel(); diff --git a/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java b/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java index d68de23811..4c4b6fd910 100644 --- a/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java +++ b/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java @@ -47,8 +47,13 @@ protected void restart() throws IOException, TimeoutException { alternateConnection = null; alternateChannel = null; - Host.rabbitmqctl("stop_app", Host.nodenameB()); - Host.rabbitmqctl("start_app", Host.nodenameB()); + Host.invokeMakeTarget( + "stop-node" + + " start-background-broker" + + " RABBITMQ_NODENAME=\'" + Host.nodenameB() + "\'" + + " RABBITMQ_NODE_PORT=" + Host.node_portB() + + " RABBITMQ_CONFIG_FILE=\'" + Host.config_fileB() + "\'" + ); } restartPrimary(); } diff --git a/src/test/java/com/rabbitmq/tools/Host.java b/src/test/java/com/rabbitmq/tools/Host.java index e5ebaa042c..1cae40f9b7 100644 --- a/src/test/java/com/rabbitmq/tools/Host.java +++ b/src/test/java/com/rabbitmq/tools/Host.java @@ -17,16 +17,14 @@ package com.rabbitmq.tools; import java.io.BufferedReader; +import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.impl.NetworkConnection; -import com.rabbitmq.client.test.TestUtils; public class Host { @@ -105,12 +103,6 @@ public static Process rabbitmqctl(String command) throws IOException { " " + command); } - public static Process rabbitmqctl(String command, String node) throws IOException { - return executeCommand(rabbitmqctlCommand() + - " -n \'" + node + "\'" + - " " + command); - } - public static Process rabbitmqctlIgnoreErrors(String command) throws IOException { return executeCommandIgnoringErrors(rabbitmqctlCommand() + " -n \'" + nodenameA() + "\'" + @@ -125,43 +117,25 @@ public static void clearResourceAlarm(String source) throws IOException { rabbitmqctl("eval 'rabbit_alarm:clear_alarm({resource_limit, " + source + ", node()}).'"); } - public static void startRabbitOnNode(String node) throws IOException { - rabbitmqctl("eval 'rabbit:start().'", node); - String port = nodenameA().equals(node) ? node_portA() : node_portB(); - tryConnectFor(10_000, Integer.parseInt(port)); - } - - public static void startRabbitOnNode() throws IOException { - startRabbitOnNode(nodenameA()); - } - - public static void stopRabbitOnNode(String node) throws IOException { - rabbitmqctl("eval 'rabbit:stop().'", node); + public static Process invokeMakeTarget(String command) throws IOException { + File rabbitmqctl = new File(rabbitmqctlCommand()); + return executeCommand(makeCommand() + + " -C \'" + rabbitmqDir() + "\'" + + " RABBITMQCTL=\'" + rabbitmqctl.getAbsolutePath() + "\'" + + " RABBITMQ_NODENAME=\'" + nodenameA() + "\'" + + " RABBITMQ_NODE_PORT=" + node_portA() + + " RABBITMQ_CONFIG_FILE=\'" + config_fileA() + "\'" + + " " + command); } - public static void stopRabbitOnNode() throws IOException { - stopRabbitOnNode(nodenameA()); + public static String systemHostname() throws IOException { + Process process = executeCommandIgnoringErrors("hostname"); + return capture(process.getInputStream()).trim(); } - public static void tryConnectFor(int timeoutInMs, int port) throws IOException { - int waitTime = 100; - int totalWaitTime = 0; - while (totalWaitTime <= timeoutInMs) { - try { - Thread.sleep(waitTime); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - totalWaitTime += waitTime; - ConnectionFactory connectionFactory = TestUtils.connectionFactory(); - connectionFactory.setPort(port); - try (Connection ignored = connectionFactory.newConnection()) { - return; - } catch (Exception e) { - // retrying - } - } - throw new IOException("Could not connect to broker for " + timeoutInMs + " ms"); + public static String makeCommand() + { + return System.getProperty("make.bin", "make"); } public static String nodenameA() @@ -174,6 +148,11 @@ public static String node_portA() return System.getProperty("test-broker.A.node_port"); } + public static String config_fileA() + { + return System.getProperty("test-broker.A.config_file"); + } + public static String nodenameB() { return System.getProperty("test-broker.B.nodename"); @@ -184,6 +163,11 @@ public static String node_portB() return System.getProperty("test-broker.B.node_port"); } + public static String config_fileB() + { + return System.getProperty("test-broker.B.config_file"); + } + public static String rabbitmqctlCommand() { return System.getProperty("rabbitmqctl.bin"); From 9177ae2bef4fe0c5f0e1be442793fdd7560f132e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 30 Aug 2018 11:57:59 +0200 Subject: [PATCH 0911/2114] Use rabbitmqctl to start/stop rabbit application on node Instead of using make. This way only HA tests need make to run. --- .../rabbitmq/client/test/BrokerTestCase.java | 4 +-- .../server/DeadLetterExchangeDurable.java | 4 +-- src/test/java/com/rabbitmq/tools/Host.java | 34 +++++++++++++++++-- 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java index b9ee4ecceb..1a00ca8c1b 100644 --- a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java +++ b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java @@ -143,8 +143,8 @@ protected void restart() protected void bareRestart() throws IOException { - Host.invokeMakeTarget( - "stop-rabbit-on-node start-rabbit-on-node"); + Host.stopRabbitOnNode(); + Host.startRabbitOnNode(); } public void openConnection() diff --git a/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java b/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java index 3973521128..c6c4e85c91 100644 --- a/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java +++ b/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java @@ -58,9 +58,9 @@ protected void releaseResources() throws IOException { } closeConnection(); - Host.invokeMakeTarget("stop-rabbit-on-node"); + Host.stopRabbitOnNode(); Thread.sleep(5000); - Host.invokeMakeTarget("start-rabbit-on-node"); + Host.startRabbitOnNode(); openConnection(); openChannel(); diff --git a/src/test/java/com/rabbitmq/tools/Host.java b/src/test/java/com/rabbitmq/tools/Host.java index 1cae40f9b7..4c995a1e1f 100644 --- a/src/test/java/com/rabbitmq/tools/Host.java +++ b/src/test/java/com/rabbitmq/tools/Host.java @@ -24,7 +24,10 @@ import java.util.ArrayList; import java.util.List; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.impl.NetworkConnection; +import com.rabbitmq.client.test.TestUtils; public class Host { @@ -128,9 +131,34 @@ public static Process invokeMakeTarget(String command) throws IOException { " " + command); } - public static String systemHostname() throws IOException { - Process process = executeCommandIgnoringErrors("hostname"); - return capture(process.getInputStream()).trim(); + public static void startRabbitOnNode() throws IOException { + rabbitmqctl("eval 'rabbit:start().'"); + tryConnectFor(10_000); + } + + public static void stopRabbitOnNode() throws IOException { + rabbitmqctl("eval 'rabbit:stop().'"); + } + + public static void tryConnectFor(int timeoutInMs) throws IOException { + int waitTime = 100; + int totalWaitTime = 0; + while (totalWaitTime <= timeoutInMs) { + try { + Thread.sleep(waitTime); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + totalWaitTime += waitTime; + ConnectionFactory connectionFactory = TestUtils.connectionFactory(); + try (Connection ignored = connectionFactory.newConnection()) { + return; + + } catch (Exception e) { + // retrying + } + } + throw new IOException("Could not connect to broker for " + timeoutInMs + " ms"); } public static String makeCommand() From 8394418ebabeff84156c10eb1ac0b7f6dfbcc400 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 30 Aug 2018 16:51:26 +0200 Subject: [PATCH 0912/2114] Use rabbitmqctl start_app/stop_app and not eval --- .../com/rabbitmq/client/test/ssl/HostnameVerification.java | 1 + src/test/java/com/rabbitmq/tools/Host.java | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java index 2ddef41aeb..9355fdddcb 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java @@ -89,6 +89,7 @@ public static void initCrypto() throws Exception { assertNotNull(p12Path); String p12Passwd = System.getProperty("test-client-cert.password"); assertNotNull(p12Passwd); +System.out.println(p12Passwd); KeyStore ks = KeyStore.getInstance("PKCS12"); char[] p12Password = p12Passwd.toCharArray(); ks.load(new FileInputStream(p12Path), p12Password); diff --git a/src/test/java/com/rabbitmq/tools/Host.java b/src/test/java/com/rabbitmq/tools/Host.java index 4c995a1e1f..b1fccf26a9 100644 --- a/src/test/java/com/rabbitmq/tools/Host.java +++ b/src/test/java/com/rabbitmq/tools/Host.java @@ -132,12 +132,12 @@ public static Process invokeMakeTarget(String command) throws IOException { } public static void startRabbitOnNode() throws IOException { - rabbitmqctl("eval 'rabbit:start().'"); + rabbitmqctl("start_app"); tryConnectFor(10_000); } public static void stopRabbitOnNode() throws IOException { - rabbitmqctl("eval 'rabbit:stop().'"); + rabbitmqctl("stop_app"); } public static void tryConnectFor(int timeoutInMs) throws IOException { From b8f04408e71f4a9007f254719ef984170175ffa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 31 Aug 2018 11:20:19 +0200 Subject: [PATCH 0913/2114] Set release version to 5.4.0 --- release-versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-versions.txt b/release-versions.txt index 84c22280ae..a74fd487b8 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="5.4.0.RC4" +RELEASE_VERSION="5.4.0" DEVELOPMENT_VERSION="5.4.0-SNAPSHOT" From b18bcab2b743d002465e2fa709a3787ac8dce767 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 31 Aug 2018 11:20:45 +0200 Subject: [PATCH 0914/2114] Update snapshot version in release file --- release-versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-versions.txt b/release-versions.txt index a74fd487b8..914629c9f6 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ RELEASE_VERSION="5.4.0" -DEVELOPMENT_VERSION="5.4.0-SNAPSHOT" +DEVELOPMENT_VERSION="5.4.1-SNAPSHOT" From 7f527b51a12f7905215a6be008ba9baca660ede2 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Fri, 31 Aug 2018 09:33:54 +0000 Subject: [PATCH 0915/2114] [maven-release-plugin] prepare release v5.4.0 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 19350b6ff6..f3a2d19102 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.4.0-SNAPSHOT + 5.4.0 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v5.4.0 From a561f5bd966ab27a6c63e07d1c67db1dc3806f6f Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Fri, 31 Aug 2018 09:33:59 +0000 Subject: [PATCH 0916/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index f3a2d19102..c2f738d501 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.4.0 + 5.4.1-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v5.4.0 + HEAD From 0163e581dc6e110805acedd79130a5dcfe76d2b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 31 Aug 2018 11:46:45 +0200 Subject: [PATCH 0917/2114] Set release version to 5.5.0.RC1 --- pom.xml | 2 +- release-versions.txt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index c2f738d501..8eb7a5f61d 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.4.1-SNAPSHOT + 5.5.0-SNAPSHOT jar RabbitMQ Java Client diff --git a/release-versions.txt b/release-versions.txt index 914629c9f6..bf45e0f32c 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="5.4.0" -DEVELOPMENT_VERSION="5.4.1-SNAPSHOT" +RELEASE_VERSION="5.5.0.RC1" +DEVELOPMENT_VERSION="5.5.0-SNAPSHOT" From b1d689bc49a53bd6e3b73aaf833fe481bfc77883 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 31 Aug 2018 13:45:11 +0200 Subject: [PATCH 0918/2114] Update to 5.4.0 and 4.8.0 in readme --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index bd1c9311a0..c05af9a5c9 100644 --- a/README.md +++ b/README.md @@ -23,14 +23,14 @@ They require Java 8 or higher. com.rabbitmq amqp-client - 5.3.0 + 5.4.0 ``` ### Gradle ``` groovy -compile 'com.rabbitmq:amqp-client:5.3.0' +compile 'com.rabbitmq:amqp-client:5.4.0' ``` #### 4.x Series @@ -42,14 +42,14 @@ They require Java 6 or higher. com.rabbitmq amqp-client - 4.7.0 + 4.8.0 ``` ### Gradle ``` groovy -compile 'com.rabbitmq:amqp-client:4.7.0' +compile 'com.rabbitmq:amqp-client:4.8.0' ``` From 5dbb9de8784381601b8b7a9329c2c7d96ca01dd4 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 31 Aug 2018 17:03:44 +0200 Subject: [PATCH 0919/2114] Don't use an anchor in the message (they change too often) --- .../java/com/rabbitmq/client/TrustEverythingTrustManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/TrustEverythingTrustManager.java b/src/main/java/com/rabbitmq/client/TrustEverythingTrustManager.java index 7893eb7e16..544c74f1d8 100644 --- a/src/main/java/com/rabbitmq/client/TrustEverythingTrustManager.java +++ b/src/main/java/com/rabbitmq/client/TrustEverythingTrustManager.java @@ -33,7 +33,7 @@ public TrustEverythingTrustManager() { LoggerFactory.getLogger(TrustEverythingTrustManager.class).warn( "SECURITY ALERT: this trust manager trusts every certificate, effectively disabling peer verification. " + "This is convenient for local development but offers no protection against man-in-the-middle attacks. " + - "Please see https://www.rabbitmq.com/ssl.html#validating-cerficates to learn more about peer certificate verification." + "Please see https://www.rabbitmq.com/ssl.html to learn more about peer certificate verification." ); } From a57adf1dd260813a12cd3695d072bfa2371591d9 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 31 Aug 2018 17:03:44 +0200 Subject: [PATCH 0920/2114] Don't use an anchor in the message (they change too often) (cherry picked from commit 5dbb9de8784381601b8b7a9329c2c7d96ca01dd4) --- .../java/com/rabbitmq/client/TrustEverythingTrustManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/TrustEverythingTrustManager.java b/src/main/java/com/rabbitmq/client/TrustEverythingTrustManager.java index 7893eb7e16..544c74f1d8 100644 --- a/src/main/java/com/rabbitmq/client/TrustEverythingTrustManager.java +++ b/src/main/java/com/rabbitmq/client/TrustEverythingTrustManager.java @@ -33,7 +33,7 @@ public TrustEverythingTrustManager() { LoggerFactory.getLogger(TrustEverythingTrustManager.class).warn( "SECURITY ALERT: this trust manager trusts every certificate, effectively disabling peer verification. " + "This is convenient for local development but offers no protection against man-in-the-middle attacks. " + - "Please see https://www.rabbitmq.com/ssl.html#validating-cerficates to learn more about peer certificate verification." + "Please see https://www.rabbitmq.com/ssl.html to learn more about peer certificate verification." ); } From ba92670602600d2b8266117a863a9db8b9b913c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 3 Sep 2018 13:11:48 +0200 Subject: [PATCH 0921/2114] Set version to 4.8.1 and 5.4.1 in readme --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c05af9a5c9..5bb0b7a3c1 100644 --- a/README.md +++ b/README.md @@ -23,14 +23,14 @@ They require Java 8 or higher. com.rabbitmq amqp-client - 5.4.0 + 5.4.1 ``` ### Gradle ``` groovy -compile 'com.rabbitmq:amqp-client:5.4.0' +compile 'com.rabbitmq:amqp-client:5.4.1' ``` #### 4.x Series @@ -42,14 +42,14 @@ They require Java 6 or higher. com.rabbitmq amqp-client - 4.8.0 + 4.8.1 ``` ### Gradle ``` groovy -compile 'com.rabbitmq:amqp-client:4.8.0' +compile 'com.rabbitmq:amqp-client:4.8.1' ``` From 256aff5cf7505bfa93ff0c2569d2fb1668050e5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 4 Sep 2018 12:42:53 +0200 Subject: [PATCH 0922/2114] Increase log level in tests --- src/test/resources/logback-test.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml index 4bd2e37606..ee88f442c2 100644 --- a/src/test/resources/logback-test.xml +++ b/src/test/resources/logback-test.xml @@ -5,7 +5,7 @@ - + \ No newline at end of file From 441396a2382c61eca7042e99c811bd0df920596d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 28 Aug 2018 18:08:43 +0200 Subject: [PATCH 0923/2114] Use rabbitmqctl to manipulate alarms in tests Avoid using make and depending on the umbrella. (cherry picked from commit 9dc2a6a145d6cc0071772d9b6a3acb30076d7d1a) --- .../java/com/rabbitmq/client/test/BrokerTestCase.java | 10 +++++----- .../com/rabbitmq/client/test/server/MemoryAlarms.java | 9 ++------- src/test/java/com/rabbitmq/tools/Host.java | 8 ++++++++ 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java index 216cbb8e47..b9ee4ecceb 100644 --- a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java +++ b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java @@ -320,17 +320,17 @@ protected void deleteQueues(String [] queues) throws IOException { } } - protected void clearAllResourceAlarms() throws IOException, InterruptedException { + protected void clearAllResourceAlarms() throws IOException { clearResourceAlarm("memory"); clearResourceAlarm("disk"); } - protected void setResourceAlarm(String source) throws IOException, InterruptedException { - Host.invokeMakeTarget("set-resource-alarm SOURCE=" + source); + protected void setResourceAlarm(String source) throws IOException { + Host.setResourceAlarm(source); } - protected void clearResourceAlarm(String source) throws IOException, InterruptedException { - Host.invokeMakeTarget("clear-resource-alarm SOURCE=" + source); + protected void clearResourceAlarm(String source) throws IOException { + Host.clearResourceAlarm(source); } protected void block() throws IOException, InterruptedException { diff --git a/src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java b/src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java index 998fecd987..76a092d868 100644 --- a/src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java +++ b/src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java @@ -47,6 +47,7 @@ public void setUp() throws IOException, TimeoutException { @Override public void tearDown() throws IOException, TimeoutException { + clearAllResourceAlarms(); if (channel2 != null) { channel2.abort(); channel2 = null; @@ -66,13 +67,7 @@ protected void createResources() throws IOException { @Override protected void releaseResources() throws IOException { - try { - clearAllResourceAlarms(); - } catch (InterruptedException e) { - e.printStackTrace(); - } finally { - channel.queueDelete(Q); - } + channel.queueDelete(Q); } @Test public void flowControl() throws IOException, InterruptedException { diff --git a/src/test/java/com/rabbitmq/tools/Host.java b/src/test/java/com/rabbitmq/tools/Host.java index 69b7bac729..1cae40f9b7 100644 --- a/src/test/java/com/rabbitmq/tools/Host.java +++ b/src/test/java/com/rabbitmq/tools/Host.java @@ -109,6 +109,14 @@ public static Process rabbitmqctlIgnoreErrors(String command) throws IOException " " + command); } + public static void setResourceAlarm(String source) throws IOException { + rabbitmqctl("eval 'rabbit_alarm:set_alarm({{resource_limit, " + source + ", node()}, []}).'"); + } + + public static void clearResourceAlarm(String source) throws IOException { + rabbitmqctl("eval 'rabbit_alarm:clear_alarm({resource_limit, " + source + ", node()}).'"); + } + public static Process invokeMakeTarget(String command) throws IOException { File rabbitmqctl = new File(rabbitmqctlCommand()); return executeCommand(makeCommand() + From b55534a5ad1f8e8b035a2d3a17b64acd77b5c82c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 30 Aug 2018 11:57:59 +0200 Subject: [PATCH 0924/2114] Use rabbitmqctl to start/stop rabbit application on node Instead of using make. This way only HA tests need make to run. (cherry picked from commit 9177ae2bef4fe0c5f0e1be442793fdd7560f132e) --- .../rabbitmq/client/test/BrokerTestCase.java | 4 +-- .../server/DeadLetterExchangeDurable.java | 4 +-- src/test/java/com/rabbitmq/tools/Host.java | 34 +++++++++++++++++-- 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java index b9ee4ecceb..1a00ca8c1b 100644 --- a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java +++ b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java @@ -143,8 +143,8 @@ protected void restart() protected void bareRestart() throws IOException { - Host.invokeMakeTarget( - "stop-rabbit-on-node start-rabbit-on-node"); + Host.stopRabbitOnNode(); + Host.startRabbitOnNode(); } public void openConnection() diff --git a/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java b/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java index 3973521128..c6c4e85c91 100644 --- a/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java +++ b/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java @@ -58,9 +58,9 @@ protected void releaseResources() throws IOException { } closeConnection(); - Host.invokeMakeTarget("stop-rabbit-on-node"); + Host.stopRabbitOnNode(); Thread.sleep(5000); - Host.invokeMakeTarget("start-rabbit-on-node"); + Host.startRabbitOnNode(); openConnection(); openChannel(); diff --git a/src/test/java/com/rabbitmq/tools/Host.java b/src/test/java/com/rabbitmq/tools/Host.java index 1cae40f9b7..4c995a1e1f 100644 --- a/src/test/java/com/rabbitmq/tools/Host.java +++ b/src/test/java/com/rabbitmq/tools/Host.java @@ -24,7 +24,10 @@ import java.util.ArrayList; import java.util.List; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.impl.NetworkConnection; +import com.rabbitmq.client.test.TestUtils; public class Host { @@ -128,9 +131,34 @@ public static Process invokeMakeTarget(String command) throws IOException { " " + command); } - public static String systemHostname() throws IOException { - Process process = executeCommandIgnoringErrors("hostname"); - return capture(process.getInputStream()).trim(); + public static void startRabbitOnNode() throws IOException { + rabbitmqctl("eval 'rabbit:start().'"); + tryConnectFor(10_000); + } + + public static void stopRabbitOnNode() throws IOException { + rabbitmqctl("eval 'rabbit:stop().'"); + } + + public static void tryConnectFor(int timeoutInMs) throws IOException { + int waitTime = 100; + int totalWaitTime = 0; + while (totalWaitTime <= timeoutInMs) { + try { + Thread.sleep(waitTime); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + totalWaitTime += waitTime; + ConnectionFactory connectionFactory = TestUtils.connectionFactory(); + try (Connection ignored = connectionFactory.newConnection()) { + return; + + } catch (Exception e) { + // retrying + } + } + throw new IOException("Could not connect to broker for " + timeoutInMs + " ms"); } public static String makeCommand() From 7b25dc5d442197c00e3835481b67b489b985f565 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 30 Aug 2018 16:51:26 +0200 Subject: [PATCH 0925/2114] Use rabbitmqctl start_app/stop_app and not eval (cherry picked from commit 8394418ebabeff84156c10eb1ac0b7f6dfbcc400) --- .../com/rabbitmq/client/test/ssl/HostnameVerification.java | 1 + src/test/java/com/rabbitmq/tools/Host.java | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java index 2ddef41aeb..9355fdddcb 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java @@ -89,6 +89,7 @@ public static void initCrypto() throws Exception { assertNotNull(p12Path); String p12Passwd = System.getProperty("test-client-cert.password"); assertNotNull(p12Passwd); +System.out.println(p12Passwd); KeyStore ks = KeyStore.getInstance("PKCS12"); char[] p12Password = p12Passwd.toCharArray(); ks.load(new FileInputStream(p12Path), p12Password); diff --git a/src/test/java/com/rabbitmq/tools/Host.java b/src/test/java/com/rabbitmq/tools/Host.java index 4c995a1e1f..b1fccf26a9 100644 --- a/src/test/java/com/rabbitmq/tools/Host.java +++ b/src/test/java/com/rabbitmq/tools/Host.java @@ -132,12 +132,12 @@ public static Process invokeMakeTarget(String command) throws IOException { } public static void startRabbitOnNode() throws IOException { - rabbitmqctl("eval 'rabbit:start().'"); + rabbitmqctl("start_app"); tryConnectFor(10_000); } public static void stopRabbitOnNode() throws IOException { - rabbitmqctl("eval 'rabbit:stop().'"); + rabbitmqctl("stop_app"); } public static void tryConnectFor(int timeoutInMs) throws IOException { From 0e5ae551a99c5db7400582ab662ce26227c35b87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 6 Sep 2018 16:35:05 +0200 Subject: [PATCH 0926/2114] Set test log level to info --- src/test/resources/logback-test.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml index ee88f442c2..4bd2e37606 100644 --- a/src/test/resources/logback-test.xml +++ b/src/test/resources/logback-test.xml @@ -5,7 +5,7 @@ - + \ No newline at end of file From 20453a0e872de3fc2121e04bbcd2fcf699916bab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 7 Sep 2018 09:06:38 +0200 Subject: [PATCH 0927/2114] Set log level for test to warn --- .../java/com/rabbitmq/client/test/ssl/HostnameVerification.java | 2 +- src/test/resources/logback-test.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java index 9355fdddcb..20f3d5c297 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java @@ -89,7 +89,7 @@ public static void initCrypto() throws Exception { assertNotNull(p12Path); String p12Passwd = System.getProperty("test-client-cert.password"); assertNotNull(p12Passwd); -System.out.println(p12Passwd); + KeyStore ks = KeyStore.getInstance("PKCS12"); char[] p12Password = p12Passwd.toCharArray(); ks.load(new FileInputStream(p12Path), p12Password); diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml index 4bd2e37606..ee88f442c2 100644 --- a/src/test/resources/logback-test.xml +++ b/src/test/resources/logback-test.xml @@ -5,7 +5,7 @@ - + \ No newline at end of file From ff7a9d620d140604cbc6608956e63981a9239b4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 7 Sep 2018 09:12:20 +0200 Subject: [PATCH 0928/2114] Bump Maven to 3.5.4 --- .mvn/wrapper/maven-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index b573bb50d5..6c8c0e080f 100755 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -1 +1 @@ -distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.3/apache-maven-3.5.3-bin.zip +distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.4/apache-maven-3.5.4-bin.zip From 00ae7858492cd6e1629f045ceccd27c72264accd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 7 Sep 2018 09:13:21 +0200 Subject: [PATCH 0929/2114] Bump Maven to 3.5.4 --- .mvn/wrapper/maven-wrapper.properties | 2 +- .../java/com/rabbitmq/client/test/ssl/HostnameVerification.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index b573bb50d5..6c8c0e080f 100755 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -1 +1 @@ -distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.3/apache-maven-3.5.3-bin.zip +distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.4/apache-maven-3.5.4-bin.zip diff --git a/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java index 9355fdddcb..71b6a497f9 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java @@ -89,7 +89,7 @@ public static void initCrypto() throws Exception { assertNotNull(p12Path); String p12Passwd = System.getProperty("test-client-cert.password"); assertNotNull(p12Passwd); -System.out.println(p12Passwd); + KeyStore ks = KeyStore.getInstance("PKCS12"); char[] p12Password = p12Passwd.toCharArray(); ks.load(new FileInputStream(p12Path), p12Password); From 73e353026dc235dfc63a9a633b5576b7d62357d6 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 19 Sep 2018 18:22:13 +0200 Subject: [PATCH 0930/2114] Only compare header size vs. max allowed frame size if the latter is limited Closes #407, references #362. [#160628331] --- .../com/rabbitmq/client/impl/AMQCommand.java | 10 +++--- .../client/test/functional/FrameMax.java | 35 +++++++++++++++++-- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/AMQCommand.java b/src/main/java/com/rabbitmq/client/impl/AMQCommand.java index e4457076c9..929eaa3804 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQCommand.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQCommand.java @@ -107,12 +107,12 @@ public void transmit(AMQChannel channel) throws IOException { Frame headerFrame = this.assembler.getContentHeader().toFrame(channelNumber, body.length); int frameMax = connection.getFrameMax(); - int bodyPayloadMax = (frameMax == 0) ? body.length : frameMax - - EMPTY_FRAME_SIZE; + boolean cappedFrameMax = frameMax > 0; + int bodyPayloadMax = cappedFrameMax ? frameMax - EMPTY_FRAME_SIZE : body.length; - if (headerFrame.size() > frameMax) { - throw new IllegalArgumentException("Content headers exceeded max frame size: " + - headerFrame.size() + " > " + frameMax); + if (cappedFrameMax && headerFrame.size() > frameMax) { + String msg = String.format("Content headers exceeded max frame size: %d > %d", headerFrame.size(), frameMax); + throw new IllegalArgumentException(msg); } connection.writeFrame(m.toFrame(channelNumber)); connection.writeFrame(headerFrame); diff --git a/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java b/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java index 07d7eb9d9f..303d01e00d 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java +++ b/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java @@ -30,6 +30,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeoutException; +import com.rabbitmq.client.impl.AMQBasicProperties; import com.rabbitmq.client.test.TestUtils; import org.junit.Test; @@ -104,9 +105,10 @@ public FrameMax() { closeChannel(); closeConnection(); ConnectionFactory cf = new GenerousConnectionFactory(); + cf.setRequestedFrameMax(8192); connection = cf.newConnection(); openChannel(); - basicPublishVolatile(new byte[connection.getFrameMax()], "void"); + basicPublishVolatile(new byte[connection.getFrameMax() * 2], "void"); expectError(AMQP.FRAME_ERROR); } @@ -123,7 +125,9 @@ public FrameMax() { // create headers with zero-length value to calculate maximum header value size before exceeding frame_max headers.put(headerName, LongStringHelper.asLongString(new byte[0])); - AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder().headers(headers).build(); + AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder() + .headers(headers) + .build(); Frame minimalHeaderFrame = properties.toFrame(0, 0); int maxHeaderValueSize = FRAME_MAX - minimalHeaderFrame.size(); @@ -151,6 +155,33 @@ public FrameMax() { } + // see rabbitmq/rabbitmq-java-client#407 + @Test public void unlimitedFrameMaxWithHeaders() + throws IOException, TimeoutException { + closeChannel(); + closeConnection(); + ConnectionFactory cf = newConnectionFactory(); + cf.setRequestedFrameMax(0); + connection = cf.newConnection(); + openChannel(); + + Map headers = new HashMap(); + headers.put("h1", LongStringHelper.asLongString(new byte[250])); + headers.put("h1", LongStringHelper.asLongString(new byte[500])); + headers.put("h1", LongStringHelper.asLongString(new byte[750])); + headers.put("h1", LongStringHelper.asLongString(new byte[5000])); + headers.put("h1", LongStringHelper.asLongString(new byte[50000])); + AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder() + .headers(headers) + .build(); + basicPublishVolatile(new byte[500000], "", "", properties); + } + + @Override + protected boolean isAutomaticRecoveryEnabled() { + return false; + } + /* ConnectionFactory that uses MyFrameHandler rather than * SocketFrameHandler. */ private static class MyConnectionFactory extends ConnectionFactory { From 5691a602f29fd1ccaa5592bfe5e6be28dadbf46c Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 19 Sep 2018 18:22:13 +0200 Subject: [PATCH 0931/2114] Only compare header size vs. max allowed frame size if the latter is limited Closes #407, references #362. [#160628331] (cherry picked from commit 73e353026dc235dfc63a9a633b5576b7d62357d6) --- .../com/rabbitmq/client/impl/AMQCommand.java | 10 +++--- .../client/test/functional/FrameMax.java | 35 +++++++++++++++++-- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/AMQCommand.java b/src/main/java/com/rabbitmq/client/impl/AMQCommand.java index e4457076c9..929eaa3804 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQCommand.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQCommand.java @@ -107,12 +107,12 @@ public void transmit(AMQChannel channel) throws IOException { Frame headerFrame = this.assembler.getContentHeader().toFrame(channelNumber, body.length); int frameMax = connection.getFrameMax(); - int bodyPayloadMax = (frameMax == 0) ? body.length : frameMax - - EMPTY_FRAME_SIZE; + boolean cappedFrameMax = frameMax > 0; + int bodyPayloadMax = cappedFrameMax ? frameMax - EMPTY_FRAME_SIZE : body.length; - if (headerFrame.size() > frameMax) { - throw new IllegalArgumentException("Content headers exceeded max frame size: " + - headerFrame.size() + " > " + frameMax); + if (cappedFrameMax && headerFrame.size() > frameMax) { + String msg = String.format("Content headers exceeded max frame size: %d > %d", headerFrame.size(), frameMax); + throw new IllegalArgumentException(msg); } connection.writeFrame(m.toFrame(channelNumber)); connection.writeFrame(headerFrame); diff --git a/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java b/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java index 07d7eb9d9f..303d01e00d 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java +++ b/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java @@ -30,6 +30,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeoutException; +import com.rabbitmq.client.impl.AMQBasicProperties; import com.rabbitmq.client.test.TestUtils; import org.junit.Test; @@ -104,9 +105,10 @@ public FrameMax() { closeChannel(); closeConnection(); ConnectionFactory cf = new GenerousConnectionFactory(); + cf.setRequestedFrameMax(8192); connection = cf.newConnection(); openChannel(); - basicPublishVolatile(new byte[connection.getFrameMax()], "void"); + basicPublishVolatile(new byte[connection.getFrameMax() * 2], "void"); expectError(AMQP.FRAME_ERROR); } @@ -123,7 +125,9 @@ public FrameMax() { // create headers with zero-length value to calculate maximum header value size before exceeding frame_max headers.put(headerName, LongStringHelper.asLongString(new byte[0])); - AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder().headers(headers).build(); + AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder() + .headers(headers) + .build(); Frame minimalHeaderFrame = properties.toFrame(0, 0); int maxHeaderValueSize = FRAME_MAX - minimalHeaderFrame.size(); @@ -151,6 +155,33 @@ public FrameMax() { } + // see rabbitmq/rabbitmq-java-client#407 + @Test public void unlimitedFrameMaxWithHeaders() + throws IOException, TimeoutException { + closeChannel(); + closeConnection(); + ConnectionFactory cf = newConnectionFactory(); + cf.setRequestedFrameMax(0); + connection = cf.newConnection(); + openChannel(); + + Map headers = new HashMap(); + headers.put("h1", LongStringHelper.asLongString(new byte[250])); + headers.put("h1", LongStringHelper.asLongString(new byte[500])); + headers.put("h1", LongStringHelper.asLongString(new byte[750])); + headers.put("h1", LongStringHelper.asLongString(new byte[5000])); + headers.put("h1", LongStringHelper.asLongString(new byte[50000])); + AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder() + .headers(headers) + .build(); + basicPublishVolatile(new byte[500000], "", "", properties); + } + + @Override + protected boolean isAutomaticRecoveryEnabled() { + return false; + } + /* ConnectionFactory that uses MyFrameHandler rather than * SocketFrameHandler. */ private static class MyConnectionFactory extends ConnectionFactory { From 60eb44d2baf7fbe4da36cee5978855cc0a068061 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 26 Sep 2018 14:02:55 +0300 Subject: [PATCH 0932/2114] Change default exponential backoff sequence to not start with zero Recovery delay was a connection recovery feature from day 1 for a reason: * In practice connection recovery often won't succeed the first time because network failures don't always go away in milliseconds. * There's a natural race condition between server state changes (cleanup of queues and such) and the operations a recovered connection will perform potentially on entities *with the same identifier* (e.g. name) Initial delay avoids a lot of scenarios that stem from the above race condition and can waste a lot of time for operators, developers and the RabbitMQ core team. References #307. --- .../rabbitmq/client/RecoveryDelayHandler.java | 9 +++--- .../client/test/RecoveryDelayHandlerTest.java | 30 +++++++++---------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/RecoveryDelayHandler.java b/src/main/java/com/rabbitmq/client/RecoveryDelayHandler.java index 045c11045c..524d3c1786 100644 --- a/src/main/java/com/rabbitmq/client/RecoveryDelayHandler.java +++ b/src/main/java/com/rabbitmq/client/RecoveryDelayHandler.java @@ -67,10 +67,10 @@ class ExponentialBackoffDelayHandler implements RecoveryDelayHandler { private final List sequence; /** - * Default Constructor. Uses the fibonacci sequence: {0, 1000, 1000, 2000, 3000, 5000, 8000, 13000, 21000}. + * Default Constructor. Uses the following sequence: 2000, 3000, 5000, 8000, 13000, 21000, 34000 */ public ExponentialBackoffDelayHandler() { - sequence = Arrays.asList(0L, 1000L, 1000L, 2000L, 3000L, 5000L, 8000L, 13000L, 21000L); + sequence = Arrays.asList(2000L, 3000L, 5000L, 8000L, 13000L, 21000L, 34000L); } /** @@ -88,7 +88,8 @@ public ExponentialBackoffDelayHandler(final List sequence) { @Override public long getDelay(int recoveryAttempts) { - return sequence.get(recoveryAttempts >= sequence.size() ? sequence.size() - 1 : recoveryAttempts); + int index = recoveryAttempts >= sequence.size() ? sequence.size() - 1 : recoveryAttempts; + return sequence.get(index); } } -} \ No newline at end of file +} diff --git a/src/test/java/com/rabbitmq/client/test/RecoveryDelayHandlerTest.java b/src/test/java/com/rabbitmq/client/test/RecoveryDelayHandlerTest.java index b73870784c..1b988251f3 100644 --- a/src/test/java/com/rabbitmq/client/test/RecoveryDelayHandlerTest.java +++ b/src/test/java/com/rabbitmq/client/test/RecoveryDelayHandlerTest.java @@ -37,23 +37,23 @@ public void testDefaultRecoveryDelayHandler() { } @Test - public void testExponentialBackoffDelayHandler_default() { + public void testExponentialBackoffDelayHandlerDefaults() { final RecoveryDelayHandler handler = new ExponentialBackoffDelayHandler(); - assertEquals(0, handler.getDelay(0)); - assertEquals(1000L, handler.getDelay(1)); - assertEquals(1000L, handler.getDelay(2)); - assertEquals(2000L, handler.getDelay(3)); - assertEquals(3000L, handler.getDelay(4)); - assertEquals(5000L, handler.getDelay(5)); - assertEquals(8000L, handler.getDelay(6)); - assertEquals(13000L, handler.getDelay(7)); - assertEquals(21000L, handler.getDelay(8)); - assertEquals(21000L, handler.getDelay(9)); - assertEquals(21000L, handler.getDelay(Integer.MAX_VALUE)); + assertEquals(2000L, handler.getDelay(0)); + assertEquals(3000L, handler.getDelay(1)); + assertEquals(5000L, handler.getDelay(2)); + assertEquals(8000L, handler.getDelay(3)); + assertEquals(13000L, handler.getDelay(4)); + assertEquals(21000L, handler.getDelay(5)); + assertEquals(34000L, handler.getDelay(6)); + assertEquals(34000L, handler.getDelay(7)); + assertEquals(34000L, handler.getDelay(8)); + assertEquals(34000L, handler.getDelay(9)); + assertEquals(34000L, handler.getDelay(Integer.MAX_VALUE)); } @Test - public void testExponentialBackoffDelayHandler_sequence() { + public void testExponentialBackoffDelayHandlerSequence() { final RecoveryDelayHandler handler = new ExponentialBackoffDelayHandler(Arrays.asList(1L, 2L)); assertEquals(1, handler.getDelay(0)); assertEquals(2, handler.getDelay(1)); @@ -62,12 +62,12 @@ public void testExponentialBackoffDelayHandler_sequence() { } @Test(expected=IllegalArgumentException.class) - public void testExponentialBackoffDelayHandler_sequence_null() { + public void testExponentialBackoffDelayHandlerWithNullSequence() { new ExponentialBackoffDelayHandler(null); } @Test(expected=IllegalArgumentException.class) - public void testExponentialBackoffDelayHandler_sequence_empty() { + public void testExponentialBackoffDelayHandlerWithEmptySequence() { new ExponentialBackoffDelayHandler(Collections.emptyList()); } } From 3427adbfe54b1c8b0b770d22117b0b88ad074366 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 26 Sep 2018 14:02:55 +0300 Subject: [PATCH 0933/2114] Change default exponential backoff sequence to not start with zero Recovery delay was a connection recovery feature from day 1 for a reason: * In practice connection recovery often won't succeed the first time because network failures don't always go away in milliseconds. * There's a natural race condition between server state changes (cleanup of queues and such) and the operations a recovered connection will perform potentially on entities *with the same identifier* (e.g. name) Initial delay avoids a lot of scenarios that stem from the above race condition and can waste a lot of time for operators, developers and the RabbitMQ core team. References #307. (cherry picked from commit 60eb44d2baf7fbe4da36cee5978855cc0a068061) --- .../rabbitmq/client/RecoveryDelayHandler.java | 9 +++--- .../client/test/RecoveryDelayHandlerTest.java | 30 +++++++++---------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/RecoveryDelayHandler.java b/src/main/java/com/rabbitmq/client/RecoveryDelayHandler.java index 045c11045c..524d3c1786 100644 --- a/src/main/java/com/rabbitmq/client/RecoveryDelayHandler.java +++ b/src/main/java/com/rabbitmq/client/RecoveryDelayHandler.java @@ -67,10 +67,10 @@ class ExponentialBackoffDelayHandler implements RecoveryDelayHandler { private final List sequence; /** - * Default Constructor. Uses the fibonacci sequence: {0, 1000, 1000, 2000, 3000, 5000, 8000, 13000, 21000}. + * Default Constructor. Uses the following sequence: 2000, 3000, 5000, 8000, 13000, 21000, 34000 */ public ExponentialBackoffDelayHandler() { - sequence = Arrays.asList(0L, 1000L, 1000L, 2000L, 3000L, 5000L, 8000L, 13000L, 21000L); + sequence = Arrays.asList(2000L, 3000L, 5000L, 8000L, 13000L, 21000L, 34000L); } /** @@ -88,7 +88,8 @@ public ExponentialBackoffDelayHandler(final List sequence) { @Override public long getDelay(int recoveryAttempts) { - return sequence.get(recoveryAttempts >= sequence.size() ? sequence.size() - 1 : recoveryAttempts); + int index = recoveryAttempts >= sequence.size() ? sequence.size() - 1 : recoveryAttempts; + return sequence.get(index); } } -} \ No newline at end of file +} diff --git a/src/test/java/com/rabbitmq/client/test/RecoveryDelayHandlerTest.java b/src/test/java/com/rabbitmq/client/test/RecoveryDelayHandlerTest.java index b73870784c..1b988251f3 100644 --- a/src/test/java/com/rabbitmq/client/test/RecoveryDelayHandlerTest.java +++ b/src/test/java/com/rabbitmq/client/test/RecoveryDelayHandlerTest.java @@ -37,23 +37,23 @@ public void testDefaultRecoveryDelayHandler() { } @Test - public void testExponentialBackoffDelayHandler_default() { + public void testExponentialBackoffDelayHandlerDefaults() { final RecoveryDelayHandler handler = new ExponentialBackoffDelayHandler(); - assertEquals(0, handler.getDelay(0)); - assertEquals(1000L, handler.getDelay(1)); - assertEquals(1000L, handler.getDelay(2)); - assertEquals(2000L, handler.getDelay(3)); - assertEquals(3000L, handler.getDelay(4)); - assertEquals(5000L, handler.getDelay(5)); - assertEquals(8000L, handler.getDelay(6)); - assertEquals(13000L, handler.getDelay(7)); - assertEquals(21000L, handler.getDelay(8)); - assertEquals(21000L, handler.getDelay(9)); - assertEquals(21000L, handler.getDelay(Integer.MAX_VALUE)); + assertEquals(2000L, handler.getDelay(0)); + assertEquals(3000L, handler.getDelay(1)); + assertEquals(5000L, handler.getDelay(2)); + assertEquals(8000L, handler.getDelay(3)); + assertEquals(13000L, handler.getDelay(4)); + assertEquals(21000L, handler.getDelay(5)); + assertEquals(34000L, handler.getDelay(6)); + assertEquals(34000L, handler.getDelay(7)); + assertEquals(34000L, handler.getDelay(8)); + assertEquals(34000L, handler.getDelay(9)); + assertEquals(34000L, handler.getDelay(Integer.MAX_VALUE)); } @Test - public void testExponentialBackoffDelayHandler_sequence() { + public void testExponentialBackoffDelayHandlerSequence() { final RecoveryDelayHandler handler = new ExponentialBackoffDelayHandler(Arrays.asList(1L, 2L)); assertEquals(1, handler.getDelay(0)); assertEquals(2, handler.getDelay(1)); @@ -62,12 +62,12 @@ public void testExponentialBackoffDelayHandler_sequence() { } @Test(expected=IllegalArgumentException.class) - public void testExponentialBackoffDelayHandler_sequence_null() { + public void testExponentialBackoffDelayHandlerWithNullSequence() { new ExponentialBackoffDelayHandler(null); } @Test(expected=IllegalArgumentException.class) - public void testExponentialBackoffDelayHandler_sequence_empty() { + public void testExponentialBackoffDelayHandlerWithEmptySequence() { new ExponentialBackoffDelayHandler(Collections.emptyList()); } } From b58358b1432fea4db6711b48c1e8c1a2cf11f760 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 4 Oct 2018 17:22:12 +0200 Subject: [PATCH 0934/2114] Use PackageCloud to deploy milestones [#160253747] --- pom.xml | 46 +++++++++++++++++++++++++--- src/main/scripts/sanity-check.groovy | 2 +- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index 2a847d4409..411a697ef9 100644 --- a/pom.xml +++ b/pom.xml @@ -79,6 +79,8 @@ 1.6 3.0.2 3.2.0 + 0.0.6 + 1.8 milestone @@ -593,6 +595,36 @@ + + net.nicoulaj.maven.plugins + checksum-maven-plugin + ${checksum.maven.plugin.version} + + + sign-artifacts + package + + files + + + + + ${project.build.directory} + + *.jar + *.pom + + + + + MD5 + SHA-1 + + + + + + org.apache.maven.plugins maven-gpg-plugin @@ -614,9 +646,8 @@ - bintray-rabbitmq-maven-milestones - rabbitmq-maven-milestones - https://api.bintray.com/maven/rabbitmq/maven-milestones/com.rabbitmq:amqp-client/;publish=1 + packagecloud-rabbitmq-maven-milestones + packagecloud+https://packagecloud.io/rabbitmq/maven-milestones @@ -942,6 +973,13 @@ + + + io.packagecloud.maven.wagon + maven-packagecloud-wagon + ${maven.packagecloud.wagon.version} + + diff --git a/src/main/scripts/sanity-check.groovy b/src/main/scripts/sanity-check.groovy index e1c9d48686..4447359a9c 100644 --- a/src/main/scripts/sanity-check.groovy +++ b/src/main/scripts/sanity-check.groovy @@ -1,5 +1,5 @@ @GrabResolver(name = 'rabbitmq-bintray', root = 'http://dl.bintray.com/rabbitmq/maven') -@GrabResolver(name = 'rabbitmq-bintray-milestones', root = 'http://dl.bintray.com/rabbitmq/maven-milestones') +@GrabResolver(name = 'rabbitmq-packagecloud-milestones', root = 'https://packagecloud.io/rabbitmq/maven-milestones/maven2') @Grab(group = 'com.rabbitmq', module = 'amqp-client', version = "${version}") @Grab(group = 'org.slf4j', module = 'slf4j-simple', version = '1.7.25') import com.rabbitmq.client.AMQP From f7b34e9ac2ed33ec953e7b6ca6c7f0a1dbf7561b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 4 Oct 2018 17:22:12 +0200 Subject: [PATCH 0935/2114] Use PackageCloud to deploy milestones [#160253747] (cherry picked from commit b58358b1432fea4db6711b48c1e8c1a2cf11f760) --- pom.xml | 46 +++++++++++++++++++++++++--- src/main/scripts/sanity-check.groovy | 2 +- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index 8eb7a5f61d..f17917fadb 100644 --- a/pom.xml +++ b/pom.xml @@ -79,6 +79,8 @@ 1.6 3.0.2 3.2.0 + 0.0.6 + 1.8 milestone @@ -593,6 +595,36 @@ + + net.nicoulaj.maven.plugins + checksum-maven-plugin + ${checksum.maven.plugin.version} + + + sign-artifacts + package + + files + + + + + ${project.build.directory} + + *.jar + *.pom + + + + + MD5 + SHA-1 + + + + + + org.apache.maven.plugins maven-gpg-plugin @@ -614,9 +646,8 @@ - bintray-rabbitmq-maven-milestones - rabbitmq-maven-milestones - https://api.bintray.com/maven/rabbitmq/maven-milestones/com.rabbitmq:amqp-client/;publish=1 + packagecloud-rabbitmq-maven-milestones + packagecloud+https://packagecloud.io/rabbitmq/maven-milestones @@ -942,6 +973,13 @@ + + + io.packagecloud.maven.wagon + maven-packagecloud-wagon + ${maven.packagecloud.wagon.version} + + diff --git a/src/main/scripts/sanity-check.groovy b/src/main/scripts/sanity-check.groovy index e1c9d48686..4447359a9c 100644 --- a/src/main/scripts/sanity-check.groovy +++ b/src/main/scripts/sanity-check.groovy @@ -1,5 +1,5 @@ @GrabResolver(name = 'rabbitmq-bintray', root = 'http://dl.bintray.com/rabbitmq/maven') -@GrabResolver(name = 'rabbitmq-bintray-milestones', root = 'http://dl.bintray.com/rabbitmq/maven-milestones') +@GrabResolver(name = 'rabbitmq-packagecloud-milestones', root = 'https://packagecloud.io/rabbitmq/maven-milestones/maven2') @Grab(group = 'com.rabbitmq', module = 'amqp-client', version = "${version}") @Grab(group = 'org.slf4j', module = 'slf4j-simple', version = '1.7.25') import com.rabbitmq.client.AMQP From 1a8ffed1383edecf9a329b1462f21554ae153d03 Mon Sep 17 00:00:00 2001 From: Casper Mout Date: Mon, 20 Aug 2018 13:26:38 +0200 Subject: [PATCH 0936/2114] Handle realTag = 0 in RecoveryAwareChannelN (cherry picked from commit 2e6bf274f04a06299a484daff3f666c00be15ffd) --- .../impl/recovery/RecoveryAwareChannelN.java | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java index d910da496c..faaa095bf6 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java @@ -84,21 +84,27 @@ private AMQImpl.Basic.Deliver offsetDeliveryTag(AMQImpl.Basic.Deliver method) { @Override public void basicAck(long deliveryTag, boolean multiple) throws IOException { long realTag = deliveryTag - activeDeliveryTagOffset; - // 0 tag means ack all when multiple is set - if (realTag > 0 || (multiple && realTag == 0)) { - transmit(new Basic.Ack(realTag, multiple)); - metricsCollector.basicAck(this, deliveryTag, multiple); + if(multiple && deliveryTag == 0) { + // 0 tag means ack all when multiple is set + realTag = 0; + } else if(realTag <= 0) { + return; } + transmit(new Basic.Ack(realTag, multiple)); + metricsCollector.basicAck(this, deliveryTag, multiple); } @Override public void basicNack(long deliveryTag, boolean multiple, boolean requeue) throws IOException { long realTag = deliveryTag - activeDeliveryTagOffset; - // 0 tag means nack all when multiple is set - if (realTag > 0 || (multiple && realTag == 0)) { - transmit(new Basic.Nack(realTag, multiple, requeue)); - metricsCollector.basicNack(this, deliveryTag); + if(multiple && deliveryTag == 0) { + // 0 tag means nack all when multiple is set + realTag = 0; + } else if(realTag <= 0) { + return; } + transmit(new Basic.Nack(realTag, multiple, requeue)); + metricsCollector.basicNack(this, deliveryTag); } @Override From d1f6e99d635d4f9fff3f99d9e0d519324df8ddf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 9 Oct 2018 15:51:57 +0200 Subject: [PATCH 0937/2114] Add Javadoc option on Java 11 to avoid 404 (cherry picked from commit 3c57eb9a3d37551fcd3adcaef03204b49cb5596d) --- pom.xml | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 411a697ef9..c21cf17b32 100644 --- a/pom.xml +++ b/pom.xml @@ -64,7 +64,7 @@ 3.1.0 2.21.0 - 3.0.0 + 3.0.1 2.5.3 2.3 3.0.2 @@ -177,6 +177,20 @@ + + + javadoc-no-module-dir-java-11 + + [11,) + + + --no-module-directories + + + + javadoc-no-module-dir-java-11 + + [11,) + + + --no-module-directories + + + + -Djdk.net.URLClassPath.disableClassPathURLCheck=true @@ -473,6 +478,11 @@ true + + -Djdk.net.URLClassPath.disableClassPathURLCheck=true From b2614e08b2440bff5c8f497c834e197cdb7c62a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 23 Nov 2018 11:43:47 +0100 Subject: [PATCH 0971/2114] Fix tests in CI environment (cherry picked from commit ae02f2c1e6fcc0f581af5e996cf6d9e78eca6ba7) --- pom.xml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pom.xml b/pom.xml index 79ff2f297a..618e24f9fb 100644 --- a/pom.xml +++ b/pom.xml @@ -437,6 +437,11 @@ **/ServerTests.* **/HATests.* + + -Djdk.net.URLClassPath.disableClassPathURLCheck=true @@ -473,6 +478,11 @@ true + + -Djdk.net.URLClassPath.disableClassPathURLCheck=true From f5601080a088e6c8e8b109be98b484ba559a25e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 27 Nov 2018 17:50:58 +0100 Subject: [PATCH 0972/2114] Record recoverable entities in RPC channel methods [#162201529] Fixes #425 --- .../impl/recovery/AutorecoveringChannel.java | 127 +++++++-- .../com/rabbitmq/client/test/ClientTests.java | 3 +- .../client/test/RpcTopologyRecordingTest.java | 242 ++++++++++++++++++ 3 files changed, 353 insertions(+), 19 deletions(-) create mode 100644 src/test/java/com/rabbitmq/client/test/RpcTopologyRecordingTest.java diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java index 402a6b82ea..10081fcf02 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java @@ -16,7 +16,9 @@ package com.rabbitmq.client.impl.recovery; import com.rabbitmq.client.*; -import com.rabbitmq.client.RecoverableChannel; +import com.rabbitmq.client.impl.AMQCommand; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.*; @@ -31,6 +33,9 @@ * @since 3.3.0 */ public class AutorecoveringChannel implements RecoverableChannel { + + private static final Logger LOGGER = LoggerFactory.getLogger(AutorecoveringChannel.class); + private volatile RecoveryAwareChannelN delegate; private volatile AutorecoveringConnection connection; private final List shutdownHooks = new CopyOnWriteArrayList(); @@ -235,12 +240,7 @@ public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, BuiltinExchangeT @Override public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, String type, boolean durable, boolean autoDelete, boolean internal, Map arguments) throws IOException { final AMQP.Exchange.DeclareOk ok = delegate.exchangeDeclare(exchange, type, durable, autoDelete, internal, arguments); - RecordedExchange x = new RecordedExchange(this, exchange). - type(type). - durable(durable). - autoDelete(autoDelete). - arguments(arguments); - recordExchange(exchange, x); + recordExchange(ok, exchange, type, durable, autoDelete, arguments); return ok; } @@ -331,15 +331,7 @@ public AMQP.Queue.DeclareOk queueDeclare() throws IOException { @Override public AMQP.Queue.DeclareOk queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map arguments) throws IOException { final AMQP.Queue.DeclareOk ok = delegate.queueDeclare(queue, durable, exclusive, autoDelete, arguments); - RecordedQueue q = new RecordedQueue(this, ok.getQueue()). - durable(durable). - exclusive(exclusive). - autoDelete(autoDelete). - arguments(arguments); - if (queue.equals(RecordedQueue.EMPTY_STRING)) { - q.serverNamed(true); - } - recordQueue(ok, q); + recordQueue(ok, queue, durable, exclusive, autoDelete, arguments); return ok; } @@ -714,7 +706,10 @@ public void asyncRpc(Method method) throws IOException { @Override public Command rpc(Method method) throws IOException { - return delegate.rpc(method); + recordOnRpcRequest(method); + AMQCommand response = delegate.rpc(method); + recordOnRpcResponse(response.getMethod(), method); + return response; } /** @@ -840,6 +835,18 @@ private boolean deleteRecordedExchangeBinding(String destination, String source, return this.connection.deleteRecordedExchangeBinding(this, destination, source, routingKey, arguments); } + private void recordQueue(AMQP.Queue.DeclareOk ok, String queue, boolean durable, boolean exclusive, boolean autoDelete, Map arguments) { + RecordedQueue q = new RecordedQueue(this, ok.getQueue()). + durable(durable). + exclusive(exclusive). + autoDelete(autoDelete). + arguments(arguments); + if (queue.equals(RecordedQueue.EMPTY_STRING)) { + q.serverNamed(true); + } + recordQueue(ok, q); + } + private void recordQueue(AMQP.Queue.DeclareOk ok, RecordedQueue q) { this.connection.recordQueue(ok, q); } @@ -852,6 +859,15 @@ private void deleteRecordedQueue(String queue) { this.connection.deleteRecordedQueue(queue); } + private void recordExchange(AMQP.Exchange.DeclareOk ok, String exchange, String type, boolean durable, boolean autoDelete, Map arguments) { + RecordedExchange x = new RecordedExchange(this, exchange). + type(type). + durable(durable). + autoDelete(autoDelete). + arguments(arguments); + recordExchange(exchange, x); + } + private void recordExchange(String exchange, RecordedExchange x) { this.connection.recordExchange(exchange, x); } @@ -898,7 +914,82 @@ void updateConsumerTag(String tag, String newTag) { @Override public CompletableFuture asyncCompletableRpc(Method method) throws IOException { - return this.delegate.asyncCompletableRpc(method); + recordOnRpcRequest(method); + CompletableFuture future = this.delegate.asyncCompletableRpc(method); + future.thenAccept(command -> { + if (command != null) { + recordOnRpcResponse(command.getMethod(), method); + } + }); + return future; + } + + private void recordOnRpcRequest(Method method) { + if (method instanceof AMQP.Queue.Delete) { + deleteRecordedQueue(((AMQP.Queue.Delete) method).getQueue()); + } else if (method instanceof AMQP.Exchange.Delete) { + deleteRecordedExchange(((AMQP.Exchange.Delete) method).getExchange()); + } else if (method instanceof AMQP.Queue.Unbind) { + AMQP.Queue.Unbind unbind = (AMQP.Queue.Unbind) method; + deleteRecordedQueueBinding( + unbind.getQueue(), unbind.getExchange(), + unbind.getRoutingKey(), unbind.getArguments() + ); + this.maybeDeleteRecordedAutoDeleteExchange(unbind.getExchange()); + } else if (method instanceof AMQP.Exchange.Unbind) { + AMQP.Exchange.Unbind unbind = (AMQP.Exchange.Unbind) method; + deleteRecordedExchangeBinding( + unbind.getDestination(), unbind.getSource(), + unbind.getRoutingKey(), unbind.getArguments() + ); + this.maybeDeleteRecordedAutoDeleteExchange(unbind.getSource()); + } + } + + private void recordOnRpcResponse(Method response, Method request) { + if (response instanceof AMQP.Queue.DeclareOk) { + if (request instanceof AMQP.Queue.Declare) { + AMQP.Queue.DeclareOk ok = (AMQP.Queue.DeclareOk) response; + AMQP.Queue.Declare declare = (AMQP.Queue.Declare) request; + recordQueue( + ok, declare.getQueue(), + declare.getDurable(), declare.getExclusive(), declare.getAutoDelete(), + declare.getArguments() + ); + } else { + LOGGER.warn("RPC response {} and RPC request {} not compatible, topology not recorded.", + response.getClass(), request.getClass()); + } + } else if (response instanceof AMQP.Exchange.DeclareOk) { + if (request instanceof AMQP.Exchange.Declare) { + AMQP.Exchange.DeclareOk ok = (AMQP.Exchange.DeclareOk) response; + AMQP.Exchange.Declare declare = (AMQP.Exchange.Declare) request; + recordExchange( + ok, declare.getExchange(), declare.getType(), + declare.getDurable(), declare.getAutoDelete(), + declare.getArguments() + ); + } else { + LOGGER.warn("RPC response {} and RPC request {} not compatible, topology not recorded.", + response.getClass(), request.getClass()); + } + } else if (response instanceof AMQP.Queue.BindOk) { + if (request instanceof AMQP.Queue.Bind) { + AMQP.Queue.Bind bind = (AMQP.Queue.Bind) request; + recordQueueBinding(bind.getQueue(), bind.getExchange(), bind.getRoutingKey(), bind.getArguments()); + } else { + LOGGER.warn("RPC response {} and RPC request {} not compatible, topology not recorded.", + response.getClass(), request.getClass()); + } + } else if (response instanceof AMQP.Exchange.BindOk) { + if (request instanceof AMQP.Exchange.Bind) { + AMQP.Exchange.Bind bind = (AMQP.Exchange.Bind) request; + recordExchangeBinding(bind.getDestination(), bind.getSource(), bind.getRoutingKey(), bind.getArguments()); + } else { + LOGGER.warn("RPC response {} and RPC request {} not compatible, topology not recorded.", + response.getClass(), request.getClass()); + } + } } @Override diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index 984ed83085..bf83d989e9 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -64,7 +64,8 @@ AddressTest.class, DefaultRetryHandlerTest.class, NioDeadlockOnConnectionClosing.class, - GeneratedClassesTest.class + GeneratedClassesTest.class, + RpcTopologyRecordingTest.class }) public class ClientTests { diff --git a/src/test/java/com/rabbitmq/client/test/RpcTopologyRecordingTest.java b/src/test/java/com/rabbitmq/client/test/RpcTopologyRecordingTest.java new file mode 100644 index 0000000000..a04baa4682 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/RpcTopologyRecordingTest.java @@ -0,0 +1,242 @@ +// Copyright (c) 2018-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.test; + +import com.rabbitmq.client.*; +import com.rabbitmq.client.impl.AMQImpl; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.io.IOException; +import java.util.UUID; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicReference; + +import static com.rabbitmq.client.test.TestUtils.closeAndWaitForRecovery; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +@RunWith(Parameterized.class) +public class RpcTopologyRecordingTest extends BrokerTestCase { + + @Parameterized.Parameter + public RpcCall rpcCall; + String exchange, queue, routingKey; + String exchange2, queue2, routingKey2; + + @Parameterized.Parameters + public static Object[] data() { + return new Object[]{ + (RpcCall) (channel, method) -> channel.asyncCompletableRpc(method).get(5, TimeUnit.SECONDS), + (RpcCall) (channel, method) -> channel.rpc(method) + }; + } + + @Override + protected ConnectionFactory newConnectionFactory() { + ConnectionFactory connectionFactory = super.newConnectionFactory(); + connectionFactory.setNetworkRecoveryInterval(2); + return connectionFactory; + } + + @Before + public void init() { + queue = UUID.randomUUID().toString(); + exchange = UUID.randomUUID().toString(); + routingKey = UUID.randomUUID().toString(); + queue2 = "e2e-" + UUID.randomUUID().toString(); + exchange2 = "e2e-" + UUID.randomUUID().toString(); + routingKey2 = "e2e-" + UUID.randomUUID().toString(); + } + + @After + public void tearDown() throws IOException { + channel.exchangeDelete(exchange); + channel.exchangeDelete(exchange2); + } + + @Test + public void topologyRecovery() throws Exception { + createTopology(); + + AtomicReference latch = new AtomicReference<>(new CountDownLatch(2)); + DeliverCallback countDown = (ctag, message) -> latch.get().countDown(); + channel.basicConsume(queue, countDown, consumerTag -> { + }); + channel.basicConsume(queue2, countDown, consumerTag -> { + }); + + channel.basicPublish(exchange, routingKey, null, "".getBytes()); + channel.basicPublish(exchange, routingKey2, null, "".getBytes()); + + assertTrue(latch.get().await(5, TimeUnit.SECONDS)); + + latch.set(new CountDownLatch(2)); + + closeAndWaitForRecovery((RecoverableConnection) connection); + + channel.basicPublish(exchange, routingKey, null, "".getBytes()); + channel.basicPublish(exchange, routingKey2, null, "".getBytes()); + assertTrue(latch.get().await(5, TimeUnit.SECONDS)); + } + + @Test + public void deletionAreProperlyRecorded() throws Exception { + createTopology(); + + AtomicReference latch = new AtomicReference<>(new CountDownLatch(2)); + DeliverCallback countDown = (ctag, message) -> latch.get().countDown(); + String ctag1 = channel.basicConsume(queue, countDown, consumerTag -> { + }); + String ctag2 = channel.basicConsume(queue2, countDown, consumerTag -> { + }); + + channel.basicPublish(exchange, routingKey, null, "".getBytes()); + channel.basicPublish(exchange, routingKey2, null, "".getBytes()); + + assertTrue(latch.get().await(5, TimeUnit.SECONDS)); + + channel.basicCancel(ctag1); + channel.basicCancel(ctag2); + + rpcCall.call(channel, new AMQImpl.Exchange.Delete.Builder().exchange(exchange).build()); + rpcCall.call(channel, new AMQImpl.Exchange.Delete.Builder().exchange(exchange2).build()); + rpcCall.call(channel, new AMQImpl.Queue.Delete.Builder().queue(queue).build()); + rpcCall.call(channel, new AMQImpl.Queue.Delete.Builder().queue(queue2).build()); + + + latch.set(new CountDownLatch(2)); + + closeAndWaitForRecovery((RecoverableConnection) connection); + + assertFalse(queueExists(queue)); + assertFalse(queueExists(queue2)); + assertFalse(exchangeExists(exchange)); + assertFalse(exchangeExists(exchange2)); + } + + boolean queueExists(String queue) throws TimeoutException { + try (Channel ch = connection.createChannel()) { + ch.queueDeclarePassive(queue); + return true; + } catch (IOException e) { + return false; + } + } + + boolean exchangeExists(String exchange) throws TimeoutException { + try (Channel ch = connection.createChannel()) { + ch.exchangeDeclarePassive(exchange); + return true; + } catch (IOException e) { + return false; + } + } + + @Test + public void bindingDeletionAreProperlyRecorded() throws Exception { + createTopology(); + + AtomicReference latch = new AtomicReference<>(new CountDownLatch(2)); + DeliverCallback countDown = (ctag, message) -> latch.get().countDown(); + channel.basicConsume(queue, countDown, consumerTag -> { + }); + channel.basicConsume(queue2, countDown, consumerTag -> { + }); + + channel.basicPublish(exchange, routingKey, null, "".getBytes()); + channel.basicPublish(exchange, routingKey2, null, "".getBytes()); + + assertTrue(latch.get().await(5, TimeUnit.SECONDS)); + + unbind(); + + latch.set(new CountDownLatch(2)); + + closeAndWaitForRecovery((RecoverableConnection) connection); + + channel.basicPublish(exchange, routingKey, null, "".getBytes()); + channel.basicPublish(exchange, routingKey2, null, "".getBytes()); + assertFalse(latch.get().await(2, TimeUnit.SECONDS)); + } + + private void createTopology() throws Exception { + createAndBind(exchange, queue, routingKey); + createAndBind(exchange2, queue2, routingKey2); + rpcCall.call(channel, new AMQImpl.Exchange.Bind.Builder() + .source(exchange) + .destination(exchange2) + .routingKey(routingKey2) + .arguments(null) + .build()); + } + + private void createAndBind(String e, String q, String rk) throws Exception { + rpcCall.call(channel, new AMQImpl.Queue.Declare.Builder() + .queue(q) + .durable(false) + .exclusive(true) + .autoDelete(false) + .arguments(null) + .build()); + rpcCall.call(channel, new AMQImpl.Exchange.Declare.Builder() + .exchange(e) + .type("direct") + .durable(false) + .autoDelete(false) + .arguments(null) + .build()); + rpcCall.call(channel, new AMQImpl.Queue.Bind.Builder() + .queue(q) + .exchange(e) + .routingKey(rk) + .arguments(null) + .build()); + } + + private void unbind() throws Exception { + rpcCall.call(channel, new AMQImpl.Queue.Unbind.Builder() + .exchange(exchange) + .queue(queue) + .routingKey(routingKey).build() + ); + + rpcCall.call(channel, new AMQImpl.Queue.Unbind.Builder() + .exchange(exchange2) + .queue(queue2) + .routingKey(routingKey2).build() + ); + + rpcCall.call(channel, new AMQImpl.Exchange.Unbind.Builder() + .source(exchange) + .destination(exchange2) + .routingKey(routingKey2).build() + ); + } + + @FunctionalInterface + interface RpcCall { + + void call(Channel channel, Method method) throws Exception; + + } + +} From c4ec981835267e6d9ea6b804b0b5a400e9f56735 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 28 Nov 2018 16:42:29 +0100 Subject: [PATCH 0973/2114] Fix test to run without broker in the background --- .../client/test/ConnectionFactoryTest.java | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java b/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java index 08b66c4c90..9a314d1769 100644 --- a/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java +++ b/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java @@ -60,7 +60,7 @@ protected AMQConnection createConnection(ConnectionParams params, FrameHandler f } @Override - protected synchronized FrameHandlerFactory createFrameHandlerFactory() throws IOException { + protected synchronized FrameHandlerFactory createFrameHandlerFactory() { return mock(FrameHandlerFactory.class); } }; @@ -87,6 +87,11 @@ protected AMQConnection createConnection(ConnectionParams params, FrameHandler f createCalled.set(true); return connection; } + + @Override + protected synchronized FrameHandlerFactory createFrameHandlerFactory() { + return mock(FrameHandlerFactory.class); + } }; connectionFactory.setCredentialsProvider(provider); connectionFactory.setAutomaticRecoveryEnabled(false); @@ -114,7 +119,14 @@ protected AddressResolver createAddressResolver(List
addresses) { addressResolver.set(super.createAddressResolver(addresses)); return addressResolver.get(); } + + @Override + protected synchronized FrameHandlerFactory createFrameHandlerFactory() { + return mock(FrameHandlerFactory.class); + } }; + // connection recovery makes the creation path more complex + connectionFactory.setAutomaticRecoveryEnabled(false); doNothing().when(connection).start(); connectionFactory.newConnection(); @@ -138,7 +150,14 @@ protected AddressResolver createAddressResolver(List
addresses) { addressResolver.set(super.createAddressResolver(addresses)); return addressResolver.get(); } + + @Override + protected synchronized FrameHandlerFactory createFrameHandlerFactory() { + return mock(FrameHandlerFactory.class); + } }; + // connection recovery makes the creation path more complex + connectionFactory.setAutomaticRecoveryEnabled(false); doNothing().when(connection).start(); connectionFactory.useSslProtocol(); From 7168133a0cde402d0d1fd81e009d2947b8c129f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 28 Nov 2018 16:42:29 +0100 Subject: [PATCH 0974/2114] Fix test to run without broker in the background (cherry picked from commit c4ec981835267e6d9ea6b804b0b5a400e9f56735) --- .../client/test/ConnectionFactoryTest.java | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java b/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java index 4cf56ae7b6..cccabd243e 100644 --- a/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java +++ b/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java @@ -62,7 +62,7 @@ protected AMQConnection createConnection(ConnectionParams params, FrameHandler f } @Override - protected synchronized FrameHandlerFactory createFrameHandlerFactory() throws IOException { + protected synchronized FrameHandlerFactory createFrameHandlerFactory() { return mock(FrameHandlerFactory.class); } }; @@ -89,6 +89,11 @@ protected AMQConnection createConnection(ConnectionParams params, FrameHandler f createCalled.set(true); return connection; } + + @Override + protected synchronized FrameHandlerFactory createFrameHandlerFactory() { + return mock(FrameHandlerFactory.class); + } }; connectionFactory.setCredentialsProvider(provider); connectionFactory.setAutomaticRecoveryEnabled(false); @@ -116,7 +121,14 @@ protected AddressResolver createAddressResolver(List
addresses) { addressResolver.set(super.createAddressResolver(addresses)); return addressResolver.get(); } + + @Override + protected synchronized FrameHandlerFactory createFrameHandlerFactory() { + return mock(FrameHandlerFactory.class); + } }; + // connection recovery makes the creation path more complex + connectionFactory.setAutomaticRecoveryEnabled(false); doNothing().when(connection).start(); connectionFactory.newConnection(); @@ -140,7 +152,14 @@ protected AddressResolver createAddressResolver(List
addresses) { addressResolver.set(super.createAddressResolver(addresses)); return addressResolver.get(); } + + @Override + protected synchronized FrameHandlerFactory createFrameHandlerFactory() { + return mock(FrameHandlerFactory.class); + } }; + // connection recovery makes the creation path more complex + connectionFactory.setAutomaticRecoveryEnabled(false); doNothing().when(connection).start(); connectionFactory.useSslProtocol(); From b47f17c4717993b342b46d6d2d5d7ffa54fd55d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 27 Nov 2018 17:50:58 +0100 Subject: [PATCH 0975/2114] Record recoverable entities in RPC channel methods [#162201529] Fixes #425 (cherry picked from commit f5601080a088e6c8e8b109be98b484ba559a25e8) --- .../impl/recovery/AutorecoveringChannel.java | 127 +++++++-- .../com/rabbitmq/client/test/ClientTests.java | 3 +- .../client/test/RpcTopologyRecordingTest.java | 242 ++++++++++++++++++ 3 files changed, 353 insertions(+), 19 deletions(-) create mode 100644 src/test/java/com/rabbitmq/client/test/RpcTopologyRecordingTest.java diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java index 402a6b82ea..10081fcf02 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java @@ -16,7 +16,9 @@ package com.rabbitmq.client.impl.recovery; import com.rabbitmq.client.*; -import com.rabbitmq.client.RecoverableChannel; +import com.rabbitmq.client.impl.AMQCommand; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.*; @@ -31,6 +33,9 @@ * @since 3.3.0 */ public class AutorecoveringChannel implements RecoverableChannel { + + private static final Logger LOGGER = LoggerFactory.getLogger(AutorecoveringChannel.class); + private volatile RecoveryAwareChannelN delegate; private volatile AutorecoveringConnection connection; private final List shutdownHooks = new CopyOnWriteArrayList(); @@ -235,12 +240,7 @@ public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, BuiltinExchangeT @Override public AMQP.Exchange.DeclareOk exchangeDeclare(String exchange, String type, boolean durable, boolean autoDelete, boolean internal, Map arguments) throws IOException { final AMQP.Exchange.DeclareOk ok = delegate.exchangeDeclare(exchange, type, durable, autoDelete, internal, arguments); - RecordedExchange x = new RecordedExchange(this, exchange). - type(type). - durable(durable). - autoDelete(autoDelete). - arguments(arguments); - recordExchange(exchange, x); + recordExchange(ok, exchange, type, durable, autoDelete, arguments); return ok; } @@ -331,15 +331,7 @@ public AMQP.Queue.DeclareOk queueDeclare() throws IOException { @Override public AMQP.Queue.DeclareOk queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map arguments) throws IOException { final AMQP.Queue.DeclareOk ok = delegate.queueDeclare(queue, durable, exclusive, autoDelete, arguments); - RecordedQueue q = new RecordedQueue(this, ok.getQueue()). - durable(durable). - exclusive(exclusive). - autoDelete(autoDelete). - arguments(arguments); - if (queue.equals(RecordedQueue.EMPTY_STRING)) { - q.serverNamed(true); - } - recordQueue(ok, q); + recordQueue(ok, queue, durable, exclusive, autoDelete, arguments); return ok; } @@ -714,7 +706,10 @@ public void asyncRpc(Method method) throws IOException { @Override public Command rpc(Method method) throws IOException { - return delegate.rpc(method); + recordOnRpcRequest(method); + AMQCommand response = delegate.rpc(method); + recordOnRpcResponse(response.getMethod(), method); + return response; } /** @@ -840,6 +835,18 @@ private boolean deleteRecordedExchangeBinding(String destination, String source, return this.connection.deleteRecordedExchangeBinding(this, destination, source, routingKey, arguments); } + private void recordQueue(AMQP.Queue.DeclareOk ok, String queue, boolean durable, boolean exclusive, boolean autoDelete, Map arguments) { + RecordedQueue q = new RecordedQueue(this, ok.getQueue()). + durable(durable). + exclusive(exclusive). + autoDelete(autoDelete). + arguments(arguments); + if (queue.equals(RecordedQueue.EMPTY_STRING)) { + q.serverNamed(true); + } + recordQueue(ok, q); + } + private void recordQueue(AMQP.Queue.DeclareOk ok, RecordedQueue q) { this.connection.recordQueue(ok, q); } @@ -852,6 +859,15 @@ private void deleteRecordedQueue(String queue) { this.connection.deleteRecordedQueue(queue); } + private void recordExchange(AMQP.Exchange.DeclareOk ok, String exchange, String type, boolean durable, boolean autoDelete, Map arguments) { + RecordedExchange x = new RecordedExchange(this, exchange). + type(type). + durable(durable). + autoDelete(autoDelete). + arguments(arguments); + recordExchange(exchange, x); + } + private void recordExchange(String exchange, RecordedExchange x) { this.connection.recordExchange(exchange, x); } @@ -898,7 +914,82 @@ void updateConsumerTag(String tag, String newTag) { @Override public CompletableFuture asyncCompletableRpc(Method method) throws IOException { - return this.delegate.asyncCompletableRpc(method); + recordOnRpcRequest(method); + CompletableFuture future = this.delegate.asyncCompletableRpc(method); + future.thenAccept(command -> { + if (command != null) { + recordOnRpcResponse(command.getMethod(), method); + } + }); + return future; + } + + private void recordOnRpcRequest(Method method) { + if (method instanceof AMQP.Queue.Delete) { + deleteRecordedQueue(((AMQP.Queue.Delete) method).getQueue()); + } else if (method instanceof AMQP.Exchange.Delete) { + deleteRecordedExchange(((AMQP.Exchange.Delete) method).getExchange()); + } else if (method instanceof AMQP.Queue.Unbind) { + AMQP.Queue.Unbind unbind = (AMQP.Queue.Unbind) method; + deleteRecordedQueueBinding( + unbind.getQueue(), unbind.getExchange(), + unbind.getRoutingKey(), unbind.getArguments() + ); + this.maybeDeleteRecordedAutoDeleteExchange(unbind.getExchange()); + } else if (method instanceof AMQP.Exchange.Unbind) { + AMQP.Exchange.Unbind unbind = (AMQP.Exchange.Unbind) method; + deleteRecordedExchangeBinding( + unbind.getDestination(), unbind.getSource(), + unbind.getRoutingKey(), unbind.getArguments() + ); + this.maybeDeleteRecordedAutoDeleteExchange(unbind.getSource()); + } + } + + private void recordOnRpcResponse(Method response, Method request) { + if (response instanceof AMQP.Queue.DeclareOk) { + if (request instanceof AMQP.Queue.Declare) { + AMQP.Queue.DeclareOk ok = (AMQP.Queue.DeclareOk) response; + AMQP.Queue.Declare declare = (AMQP.Queue.Declare) request; + recordQueue( + ok, declare.getQueue(), + declare.getDurable(), declare.getExclusive(), declare.getAutoDelete(), + declare.getArguments() + ); + } else { + LOGGER.warn("RPC response {} and RPC request {} not compatible, topology not recorded.", + response.getClass(), request.getClass()); + } + } else if (response instanceof AMQP.Exchange.DeclareOk) { + if (request instanceof AMQP.Exchange.Declare) { + AMQP.Exchange.DeclareOk ok = (AMQP.Exchange.DeclareOk) response; + AMQP.Exchange.Declare declare = (AMQP.Exchange.Declare) request; + recordExchange( + ok, declare.getExchange(), declare.getType(), + declare.getDurable(), declare.getAutoDelete(), + declare.getArguments() + ); + } else { + LOGGER.warn("RPC response {} and RPC request {} not compatible, topology not recorded.", + response.getClass(), request.getClass()); + } + } else if (response instanceof AMQP.Queue.BindOk) { + if (request instanceof AMQP.Queue.Bind) { + AMQP.Queue.Bind bind = (AMQP.Queue.Bind) request; + recordQueueBinding(bind.getQueue(), bind.getExchange(), bind.getRoutingKey(), bind.getArguments()); + } else { + LOGGER.warn("RPC response {} and RPC request {} not compatible, topology not recorded.", + response.getClass(), request.getClass()); + } + } else if (response instanceof AMQP.Exchange.BindOk) { + if (request instanceof AMQP.Exchange.Bind) { + AMQP.Exchange.Bind bind = (AMQP.Exchange.Bind) request; + recordExchangeBinding(bind.getDestination(), bind.getSource(), bind.getRoutingKey(), bind.getArguments()); + } else { + LOGGER.warn("RPC response {} and RPC request {} not compatible, topology not recorded.", + response.getClass(), request.getClass()); + } + } } @Override diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index 73a11f5af7..f16e2483c9 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -67,7 +67,8 @@ AddressTest.class, DefaultRetryHandlerTest.class, NioDeadlockOnConnectionClosing.class, - GeneratedClassesTest.class + GeneratedClassesTest.class, + RpcTopologyRecordingTest.class }) public class ClientTests { diff --git a/src/test/java/com/rabbitmq/client/test/RpcTopologyRecordingTest.java b/src/test/java/com/rabbitmq/client/test/RpcTopologyRecordingTest.java new file mode 100644 index 0000000000..a04baa4682 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/RpcTopologyRecordingTest.java @@ -0,0 +1,242 @@ +// Copyright (c) 2018-Present Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.test; + +import com.rabbitmq.client.*; +import com.rabbitmq.client.impl.AMQImpl; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.io.IOException; +import java.util.UUID; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicReference; + +import static com.rabbitmq.client.test.TestUtils.closeAndWaitForRecovery; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +@RunWith(Parameterized.class) +public class RpcTopologyRecordingTest extends BrokerTestCase { + + @Parameterized.Parameter + public RpcCall rpcCall; + String exchange, queue, routingKey; + String exchange2, queue2, routingKey2; + + @Parameterized.Parameters + public static Object[] data() { + return new Object[]{ + (RpcCall) (channel, method) -> channel.asyncCompletableRpc(method).get(5, TimeUnit.SECONDS), + (RpcCall) (channel, method) -> channel.rpc(method) + }; + } + + @Override + protected ConnectionFactory newConnectionFactory() { + ConnectionFactory connectionFactory = super.newConnectionFactory(); + connectionFactory.setNetworkRecoveryInterval(2); + return connectionFactory; + } + + @Before + public void init() { + queue = UUID.randomUUID().toString(); + exchange = UUID.randomUUID().toString(); + routingKey = UUID.randomUUID().toString(); + queue2 = "e2e-" + UUID.randomUUID().toString(); + exchange2 = "e2e-" + UUID.randomUUID().toString(); + routingKey2 = "e2e-" + UUID.randomUUID().toString(); + } + + @After + public void tearDown() throws IOException { + channel.exchangeDelete(exchange); + channel.exchangeDelete(exchange2); + } + + @Test + public void topologyRecovery() throws Exception { + createTopology(); + + AtomicReference latch = new AtomicReference<>(new CountDownLatch(2)); + DeliverCallback countDown = (ctag, message) -> latch.get().countDown(); + channel.basicConsume(queue, countDown, consumerTag -> { + }); + channel.basicConsume(queue2, countDown, consumerTag -> { + }); + + channel.basicPublish(exchange, routingKey, null, "".getBytes()); + channel.basicPublish(exchange, routingKey2, null, "".getBytes()); + + assertTrue(latch.get().await(5, TimeUnit.SECONDS)); + + latch.set(new CountDownLatch(2)); + + closeAndWaitForRecovery((RecoverableConnection) connection); + + channel.basicPublish(exchange, routingKey, null, "".getBytes()); + channel.basicPublish(exchange, routingKey2, null, "".getBytes()); + assertTrue(latch.get().await(5, TimeUnit.SECONDS)); + } + + @Test + public void deletionAreProperlyRecorded() throws Exception { + createTopology(); + + AtomicReference latch = new AtomicReference<>(new CountDownLatch(2)); + DeliverCallback countDown = (ctag, message) -> latch.get().countDown(); + String ctag1 = channel.basicConsume(queue, countDown, consumerTag -> { + }); + String ctag2 = channel.basicConsume(queue2, countDown, consumerTag -> { + }); + + channel.basicPublish(exchange, routingKey, null, "".getBytes()); + channel.basicPublish(exchange, routingKey2, null, "".getBytes()); + + assertTrue(latch.get().await(5, TimeUnit.SECONDS)); + + channel.basicCancel(ctag1); + channel.basicCancel(ctag2); + + rpcCall.call(channel, new AMQImpl.Exchange.Delete.Builder().exchange(exchange).build()); + rpcCall.call(channel, new AMQImpl.Exchange.Delete.Builder().exchange(exchange2).build()); + rpcCall.call(channel, new AMQImpl.Queue.Delete.Builder().queue(queue).build()); + rpcCall.call(channel, new AMQImpl.Queue.Delete.Builder().queue(queue2).build()); + + + latch.set(new CountDownLatch(2)); + + closeAndWaitForRecovery((RecoverableConnection) connection); + + assertFalse(queueExists(queue)); + assertFalse(queueExists(queue2)); + assertFalse(exchangeExists(exchange)); + assertFalse(exchangeExists(exchange2)); + } + + boolean queueExists(String queue) throws TimeoutException { + try (Channel ch = connection.createChannel()) { + ch.queueDeclarePassive(queue); + return true; + } catch (IOException e) { + return false; + } + } + + boolean exchangeExists(String exchange) throws TimeoutException { + try (Channel ch = connection.createChannel()) { + ch.exchangeDeclarePassive(exchange); + return true; + } catch (IOException e) { + return false; + } + } + + @Test + public void bindingDeletionAreProperlyRecorded() throws Exception { + createTopology(); + + AtomicReference latch = new AtomicReference<>(new CountDownLatch(2)); + DeliverCallback countDown = (ctag, message) -> latch.get().countDown(); + channel.basicConsume(queue, countDown, consumerTag -> { + }); + channel.basicConsume(queue2, countDown, consumerTag -> { + }); + + channel.basicPublish(exchange, routingKey, null, "".getBytes()); + channel.basicPublish(exchange, routingKey2, null, "".getBytes()); + + assertTrue(latch.get().await(5, TimeUnit.SECONDS)); + + unbind(); + + latch.set(new CountDownLatch(2)); + + closeAndWaitForRecovery((RecoverableConnection) connection); + + channel.basicPublish(exchange, routingKey, null, "".getBytes()); + channel.basicPublish(exchange, routingKey2, null, "".getBytes()); + assertFalse(latch.get().await(2, TimeUnit.SECONDS)); + } + + private void createTopology() throws Exception { + createAndBind(exchange, queue, routingKey); + createAndBind(exchange2, queue2, routingKey2); + rpcCall.call(channel, new AMQImpl.Exchange.Bind.Builder() + .source(exchange) + .destination(exchange2) + .routingKey(routingKey2) + .arguments(null) + .build()); + } + + private void createAndBind(String e, String q, String rk) throws Exception { + rpcCall.call(channel, new AMQImpl.Queue.Declare.Builder() + .queue(q) + .durable(false) + .exclusive(true) + .autoDelete(false) + .arguments(null) + .build()); + rpcCall.call(channel, new AMQImpl.Exchange.Declare.Builder() + .exchange(e) + .type("direct") + .durable(false) + .autoDelete(false) + .arguments(null) + .build()); + rpcCall.call(channel, new AMQImpl.Queue.Bind.Builder() + .queue(q) + .exchange(e) + .routingKey(rk) + .arguments(null) + .build()); + } + + private void unbind() throws Exception { + rpcCall.call(channel, new AMQImpl.Queue.Unbind.Builder() + .exchange(exchange) + .queue(queue) + .routingKey(routingKey).build() + ); + + rpcCall.call(channel, new AMQImpl.Queue.Unbind.Builder() + .exchange(exchange2) + .queue(queue2) + .routingKey(routingKey2).build() + ); + + rpcCall.call(channel, new AMQImpl.Exchange.Unbind.Builder() + .source(exchange) + .destination(exchange2) + .routingKey(routingKey2).build() + ); + } + + @FunctionalInterface + interface RpcCall { + + void call(Channel channel, Method method) throws Exception; + + } + +} From 666615eae8f5f65a3ef65740907a97974070ab74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 29 Nov 2018 14:18:53 +0100 Subject: [PATCH 0976/2114] Display client version in sanity check --- src/main/scripts/sanity-check.groovy | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/scripts/sanity-check.groovy b/src/main/scripts/sanity-check.groovy index def2a84b2b..12c5464d0c 100644 --- a/src/main/scripts/sanity-check.groovy +++ b/src/main/scripts/sanity-check.groovy @@ -7,13 +7,14 @@ import com.rabbitmq.client.Channel import com.rabbitmq.client.ConnectionFactory import com.rabbitmq.client.DefaultConsumer import com.rabbitmq.client.Envelope +import com.rabbitmq.client.impl.ClientVersion import org.slf4j.LoggerFactory import java.util.concurrent.CountDownLatch import java.util.concurrent.TimeUnit -def connection = new ConnectionFactory().newConnection() try { + def connection = new ConnectionFactory().newConnection() Channel ch = connection.createChannel() def queue = ch.queueDeclare().getQueue() CountDownLatch latch = new CountDownLatch(1); @@ -27,9 +28,9 @@ try { def received = latch.await(5, TimeUnit.SECONDS) if (!received) throw new IllegalStateException("Didn't receive message in 5 seconds") - LoggerFactory.getLogger("rabbitmq").info("Test succeeded") + LoggerFactory.getLogger("rabbitmq").info("Test succeeded with Java client {}", ClientVersion.VERSION) System.exit 0 } catch (Exception e) { - LoggerFactory.getLogger("rabbitmq").info("Test failed", e) + LoggerFactory.getLogger("rabbitmq").info("Test failed with Java client {}", ClientVersion.VERSION, e) System.exit 1 } From 1c3cf6af2ae24af93d97a2036d6e1e092d713d13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 4 Dec 2018 18:01:25 +0100 Subject: [PATCH 0977/2114] Fix some Sonar warnings --- pom.xml | 11 +++++++++++ .../java/com/rabbitmq/client/ConnectionFactory.java | 2 +- .../com/rabbitmq/client/impl/nio/FrameBuilder.java | 4 ++-- .../impl/nio/SocketChannelFrameHandlerFactory.java | 6 ++++-- .../client/impl/recovery/AutorecoveringChannel.java | 2 +- .../impl/recovery/AutorecoveringConnection.java | 2 +- src/main/java/com/rabbitmq/utility/BlockingCell.java | 2 +- 7 files changed, 21 insertions(+), 8 deletions(-) diff --git a/pom.xml b/pom.xml index 9a0ec3cf08..47f23e1c80 100644 --- a/pom.xml +++ b/pom.xml @@ -744,6 +744,17 @@ + + + + + org.sonarsource.scanner.maven + sonar-maven-plugin + 3.5.0.1254 + + + + diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 3679f6295c..9dd27a085f 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -1099,7 +1099,7 @@ public Connection newConnection(ExecutorService executor, AddressResolver addres if (isAutomaticRecoveryEnabled()) { // see com.rabbitmq.client.impl.recovery.RecoveryAwareAMQConnectionFactory#newConnection - AutorecoveringConnection conn = new AutorecoveringConnection(params, fhFactory, addressResolver, metricsCollector); + AutorecoveringConnection conn = new AutorecoveringConnection(params, fhFactory, addressResolver, metricsCollector); //NOSONAR conn.init(); return conn; diff --git a/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java b/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java index 56bbf28669..5bb867899f 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java @@ -80,7 +80,7 @@ public Frame readFrame() throws IOException { frameBuffer[0] = readFromBuffer(); } else if (bytesRead == 2) { // channel 2/2 - frameChannel = (frameBuffer[0] << 8) + (readFromBuffer() << 0); + frameChannel = (frameBuffer[0] << 8) + readFromBuffer(); } else if (bytesRead == 3) { // payload size 1/4 frameBuffer[0] = readFromBuffer(); @@ -92,7 +92,7 @@ public Frame readFrame() throws IOException { frameBuffer[2] = readFromBuffer(); } else if (bytesRead == 6) { // payload size 4/4 - int framePayloadSize = ((frameBuffer[0] << 24) + (frameBuffer[1] << 16) + (frameBuffer[2] << 8) + (readFromBuffer() << 0)); + int framePayloadSize = (frameBuffer[0] << 24) + (frameBuffer[1] << 16) + (frameBuffer[2] << 8) + readFromBuffer(); framePayload = new byte[framePayloadSize]; } else if (bytesRead >= PAYLOAD_OFFSET && bytesRead < framePayload.length + PAYLOAD_OFFSET) { framePayload[bytesRead - PAYLOAD_OFFSET] = (byte) readFromBuffer(); diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java index f900325ed4..cb4d544a33 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java @@ -78,7 +78,7 @@ public FrameHandler create(Address addr, String connectionName) throws IOExcepti } SocketAddress address = new InetSocketAddress(addr.getHost(), portNumber); - channel = SocketChannel.open(); + channel = SocketChannel.open(); //NOSONAR channel.configureBlocking(true); if(nioParams.getSocketChannelConfigurator() != null) { nioParams.getSocketChannelConfigurator().configure(channel); @@ -122,7 +122,9 @@ public FrameHandler create(Address addr, String connectionName) throws IOExcepti if(sslEngine != null && channel != null) { SslEngineHelper.close(channel, sslEngine); } - channel.close(); + if (channel != null) { + channel.close(); + } } catch(IOException closingException) { // ignore } diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java index 10081fcf02..1df7822f2c 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java @@ -761,7 +761,7 @@ public void automaticallyRecover(AutorecoveringConnection connection, Connection this.connection = connection; final RecoveryAwareChannelN newChannel = (RecoveryAwareChannelN) connDelegate.createChannel(this.getChannelNumber()); - if (newChannel == null) + if (newChannel == null) //NOSONAR throw new IOException("Failed to create new channel for channel number=" + this.getChannelNumber() + " during recovery"); newChannel.inheritOffsetFrom(defunctChannel); this.delegate = newChannel; diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index c200c8fd59..ae3659bbfb 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -163,7 +163,7 @@ public void init() throws IOException, TimeoutException { @Override public Channel createChannel() throws IOException { RecoveryAwareChannelN ch = (RecoveryAwareChannelN) delegate.createChannel(); - if (ch == null) { + if (ch == null) { //NOSONAR return null; } else { return this.wrapChannel(ch); diff --git a/src/main/java/com/rabbitmq/utility/BlockingCell.java b/src/main/java/com/rabbitmq/utility/BlockingCell.java index 2a7d6fb256..7fc8ec5641 100644 --- a/src/main/java/com/rabbitmq/utility/BlockingCell.java +++ b/src/main/java/com/rabbitmq/utility/BlockingCell.java @@ -28,7 +28,7 @@ public class BlockingCell { /** Will be null until a value is supplied, and possibly still then. */ private T _value; - private static final long NANOS_IN_MILLI = 1000 * 1000; + private static final long NANOS_IN_MILLI = 1000L * 1000L; private static final long INFINITY = -1; From 6c3e72d35d396730be75dd25039d2a2bf0b307c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 5 Dec 2018 09:11:00 +0100 Subject: [PATCH 0978/2114] Increase expiry epsilon in dead letter test --- .../com/rabbitmq/client/test/functional/DeadLetterExchange.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java index 56ef879fe3..cfaff5f47d 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java @@ -573,7 +573,7 @@ private void sleep(long millis) { publication time + TTL + latency */ private void checkPromptArrival(AccumulatingMessageConsumer c, int count, long latency) throws Exception { - long epsilon = TTL / 10; + long epsilon = TTL / 5; for (int i = 0; i < count; i++) { byte[] body = c.nextDelivery(TTL + TTL + latency + epsilon); assertNotNull("message #" + i + " did not expire", body); From 7343fd2b514efc90e2a009c84b7ddc405f0578f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 5 Dec 2018 09:11:00 +0100 Subject: [PATCH 0979/2114] Increase expiry epsilon in dead letter test (cherry picked from commit 6c3e72d35d396730be75dd25039d2a2bf0b307c4) --- .../com/rabbitmq/client/test/functional/DeadLetterExchange.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java index 56ef879fe3..cfaff5f47d 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java @@ -573,7 +573,7 @@ private void sleep(long millis) { publication time + TTL + latency */ private void checkPromptArrival(AccumulatingMessageConsumer c, int count, long latency) throws Exception { - long epsilon = TTL / 10; + long epsilon = TTL / 5; for (int i = 0; i < count; i++) { byte[] body = c.nextDelivery(TTL + TTL + latency + epsilon); assertNotNull("message #" + i + " did not expire", body); From 07b86cafc698eda8032e02a6880a4f558690f81b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 5 Dec 2018 09:38:40 +0100 Subject: [PATCH 0980/2114] Stop RpcServer when its thread is interrupted Fixes #428 --- .../java/com/rabbitmq/client/RpcServer.java | 5 +++- .../com/rabbitmq/client/test/RpcTest.java | 25 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/RpcServer.java b/src/main/java/com/rabbitmq/client/RpcServer.java index 581c2d8384..457e5f6679 100644 --- a/src/main/java/com/rabbitmq/client/RpcServer.java +++ b/src/main/java/com/rabbitmq/client/RpcServer.java @@ -96,7 +96,8 @@ protected RpcConsumer setupConsumer() * Public API - main server loop. Call this to begin processing * requests. Request processing will continue until the Channel * (or its underlying Connection) is shut down, or until - * terminateMainloop() is called. + * terminateMainloop() is called, or until the thread running the loop + * is interrupted. * * Note that if the mainloop is blocked waiting for a request, the * termination flag is not checked until a request is received, so @@ -114,6 +115,8 @@ public ShutdownSignalException mainloop() try { request = _consumer.nextDelivery(); } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + _mainloopRunning = false; continue; } processRequest(request); diff --git a/src/test/java/com/rabbitmq/client/test/RpcTest.java b/src/test/java/com/rabbitmq/client/test/RpcTest.java index b107711b0d..0c05f761e2 100644 --- a/src/test/java/com/rabbitmq/client/test/RpcTest.java +++ b/src/test/java/com/rabbitmq/client/test/RpcTest.java @@ -24,6 +24,8 @@ import com.rabbitmq.client.impl.recovery.RecordedQueue; import com.rabbitmq.client.impl.recovery.TopologyRecoveryFilter; import com.rabbitmq.tools.Host; +import org.awaitility.Awaitility; +import org.awaitility.Duration; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -37,6 +39,7 @@ import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; +import static org.awaitility.Awaitility.waitAtMost; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -281,6 +284,28 @@ public void handleRecoveryStarted(Recoverable recoverable) { } } + @Test public void interruptingServerThreadShouldStopIt() throws Exception { + rpcServer = new TestRpcServer(serverChannel, queue); + Thread serverThread = new Thread(() -> { + try { + rpcServer.mainloop(); + } catch (Exception e) { + // safe to ignore when loops ends/server is canceled + } + }); + serverThread.start(); + RpcClient client = new RpcClient(new RpcClientParams() + .channel(clientChannel).exchange("").routingKey(queue).timeout(1000)); + RpcClient.Response response = client.doCall(null, "hello".getBytes()); + assertEquals("*** hello ***", new String(response.getBody())); + + serverThread.interrupt(); + + waitAtMost(Duration.ONE_SECOND).until(() -> !serverThread.isAlive()) ; + + client.close(); + } + private static class TestRpcServer extends RpcServer { public TestRpcServer(Channel channel, String queueName) throws IOException { From c176ff96b3fdff1f46472fe533201c275682b04a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 5 Dec 2018 10:08:57 +0100 Subject: [PATCH 0981/2114] Fix some Sonar warnings --- src/main/java/com/rabbitmq/client/ConnectionFactory.java | 2 +- src/main/java/com/rabbitmq/client/impl/AMQChannel.java | 4 +++- src/main/java/com/rabbitmq/client/impl/WorkPool.java | 2 +- .../client/impl/nio/SocketChannelFrameHandlerFactory.java | 2 +- .../client/impl/nio/SocketChannelFrameHandlerState.java | 1 + .../java/com/rabbitmq/client/impl/nio/SslEngineHelper.java | 2 +- .../rabbitmq/client/impl/recovery/AutorecoveringChannel.java | 2 +- .../client/impl/recovery/AutorecoveringConnection.java | 4 ++-- 8 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 9dd27a085f..3679f6295c 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -1099,7 +1099,7 @@ public Connection newConnection(ExecutorService executor, AddressResolver addres if (isAutomaticRecoveryEnabled()) { // see com.rabbitmq.client.impl.recovery.RecoveryAwareAMQConnectionFactory#newConnection - AutorecoveringConnection conn = new AutorecoveringConnection(params, fhFactory, addressResolver, metricsCollector); //NOSONAR + AutorecoveringConnection conn = new AutorecoveringConnection(params, fhFactory, addressResolver, metricsCollector); conn.init(); return conn; diff --git a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java index b9810f67e5..985f89cf4d 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java @@ -440,7 +440,9 @@ public void quiescingTransmit(AMQCommand c) throws IOException { while (_blockContent) { try { _channelMutex.wait(); - } catch (InterruptedException ignored) {} + } catch (InterruptedException ignored) { + Thread.currentThread().interrupt(); + } // This is to catch a situation when the thread wakes up during // shutdown. Currently, no command that has content is allowed diff --git a/src/main/java/com/rabbitmq/client/impl/WorkPool.java b/src/main/java/com/rabbitmq/client/impl/WorkPool.java index ea2111b320..dfccd33acf 100644 --- a/src/main/java/com/rabbitmq/client/impl/WorkPool.java +++ b/src/main/java/com/rabbitmq/client/impl/WorkPool.java @@ -74,7 +74,7 @@ public WorkPool(final int queueingTimeout) { throw new WorkPoolFullException("Could not enqueue in work pool after " + queueingTimeout + " ms."); } } catch (InterruptedException e) { - Thread.currentThread(); + Thread.currentThread().interrupt(); } }; } else { diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java index cb4d544a33..3bf0953063 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java @@ -78,7 +78,7 @@ public FrameHandler create(Address addr, String connectionName) throws IOExcepti } SocketAddress address = new InetSocketAddress(addr.getHost(), portNumber); - channel = SocketChannel.open(); //NOSONAR + channel = SocketChannel.open(); channel.configureBlocking(true); if(nioParams.getSocketChannelConfigurator() != null) { nioParams.getSocketChannelConfigurator().configure(channel); diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java index 513280a72d..bea18489c7 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java @@ -137,6 +137,7 @@ private void sendWriteRequest(WriteRequest writeRequest) throws IOException { } } catch (InterruptedException e) { LOGGER.warn("Thread interrupted during enqueuing frame in write queue"); + Thread.currentThread().interrupt(); } } diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java index 7bfaa26d1e..c4b8a33c26 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java @@ -113,7 +113,7 @@ private static int retryRead(ReadableByteChannel channel, ByteBuffer buffer) thr try { Thread.sleep(100L); } catch (InterruptedException e) { - // ignore + Thread.currentThread().interrupt(); } read = NioHelper.read(channel, buffer); if(read > 0) { diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java index 1df7822f2c..10081fcf02 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java @@ -761,7 +761,7 @@ public void automaticallyRecover(AutorecoveringConnection connection, Connection this.connection = connection; final RecoveryAwareChannelN newChannel = (RecoveryAwareChannelN) connDelegate.createChannel(this.getChannelNumber()); - if (newChannel == null) //NOSONAR + if (newChannel == null) throw new IOException("Failed to create new channel for channel number=" + this.getChannelNumber() + " during recovery"); newChannel.inheritOffsetFrom(defunctChannel); this.delegate = newChannel; diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index ae3659bbfb..4c52fa52fb 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -163,7 +163,7 @@ public void init() throws IOException, TimeoutException { @Override public Channel createChannel() throws IOException { RecoveryAwareChannelN ch = (RecoveryAwareChannelN) delegate.createChannel(); - if (ch == null) { //NOSONAR + if (ch == null) { return null; } else { return this.wrapChannel(ch); @@ -559,7 +559,7 @@ public void removeConsumerRecoveryListener(ConsumerRecoveryListener listener) { } private synchronized void beginAutomaticRecovery() throws InterruptedException { - Thread.sleep(this.params.getRecoveryDelayHandler().getDelay(0)); + this.wait(this.params.getRecoveryDelayHandler().getDelay(0)); this.notifyRecoveryListenersStarted(); From 36d12f887c34f99afb19326458d0b25f50949cd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 6 Dec 2018 09:51:10 +0100 Subject: [PATCH 0982/2114] Fix some Sonar warnings --- .../java/com/rabbitmq/client/ConnectionFactory.java | 4 +++- .../rabbitmq/client/ConnectionFactoryConfigurator.java | 2 +- .../com/rabbitmq/client/SslEngineConfigurators.java | 4 ++-- src/main/java/com/rabbitmq/client/impl/AMQChannel.java | 5 +++-- .../java/com/rabbitmq/client/impl/ChannelManager.java | 10 ++++++++-- .../client/impl/ContentHeaderPropertyReader.java | 4 ++-- .../client/impl/ContentHeaderPropertyWriter.java | 4 ++-- .../impl/nio/SocketChannelFrameHandlerFactory.java | 5 ++++- .../client/impl/recovery/AutorecoveringChannel.java | 3 ++- .../client/impl/recovery/AutorecoveringConnection.java | 7 +++++-- src/main/java/com/rabbitmq/utility/Utility.java | 6 ++++-- 11 files changed, 36 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 3679f6295c..9a9ea410ac 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -1099,7 +1099,9 @@ public Connection newConnection(ExecutorService executor, AddressResolver addres if (isAutomaticRecoveryEnabled()) { // see com.rabbitmq.client.impl.recovery.RecoveryAwareAMQConnectionFactory#newConnection - AutorecoveringConnection conn = new AutorecoveringConnection(params, fhFactory, addressResolver, metricsCollector); + // No Sonar: no need to close this resource because we're the one that creates it + // and hands it over to the user + AutorecoveringConnection conn = new AutorecoveringConnection(params, fhFactory, addressResolver, metricsCollector); //NOSONAR conn.init(); return conn; diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java b/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java index 2052e4da1c..694b7626a8 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java @@ -54,7 +54,7 @@ public class ConnectionFactoryConfigurator { public static final String DEFAULT_PREFIX = "rabbitmq."; public static final String USERNAME = "username"; - public static final String PASSWORD = "password"; + public static final String PASSWORD = "password"; //NOSONAR public static final String VIRTUAL_HOST = "virtual.host"; public static final String HOST = "host"; public static final String PORT = "port"; diff --git a/src/main/java/com/rabbitmq/client/SslEngineConfigurators.java b/src/main/java/com/rabbitmq/client/SslEngineConfigurators.java index 119bb0314f..44c2e16f70 100644 --- a/src/main/java/com/rabbitmq/client/SslEngineConfigurators.java +++ b/src/main/java/com/rabbitmq/client/SslEngineConfigurators.java @@ -30,13 +30,13 @@ public abstract class SslEngineConfigurators { /** * Default {@link SslEngineConfigurator}, does nothing. */ - public static SslEngineConfigurator DEFAULT = sslEngine -> { + public static final SslEngineConfigurator DEFAULT = sslEngine -> { }; /** * {@link SslEngineConfigurator} that enables server hostname verification. */ - public static SslEngineConfigurator ENABLE_HOSTNAME_VERIFICATION = sslEngine -> { + public static final SslEngineConfigurator ENABLE_HOSTNAME_VERIFICATION = sslEngine -> { SSLParameters sslParameters = SocketConfigurators.enableHostnameVerification(sslEngine.getSSLParameters()); sslEngine.setSSLParameters(sslParameters); }; diff --git a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java index 985f89cf4d..3cdcf8c50f 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java @@ -68,7 +68,7 @@ public abstract class AMQChannel extends ShutdownNotifierComponent { private RpcWrapper _activeRpc = null; /** Whether transmission of content-bearing methods should be blocked */ - public volatile boolean _blockContent = false; + protected volatile boolean _blockContent = false; /** Timeout for RPC calls */ protected final int _rpcTimeout; @@ -218,8 +218,9 @@ private void doEnqueueRpc(Supplier rpcWrapperSupplier) { while (_activeRpc != null) { try { _channelMutex.wait(); - } catch (InterruptedException e) { + } catch (InterruptedException e) { //NOSONAR waitClearedInterruptStatus = true; + // No Sonar: we re-interrupt the thread later } } if (waitClearedInterruptStatus) { diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelManager.java b/src/main/java/com/rabbitmq/client/impl/ChannelManager.java index 53fedee158..73b78f71b4 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelManager.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelManager.java @@ -143,8 +143,14 @@ public void run() { for (CountDownLatch latch : sdSet) { try { int shutdownTimeout = ssWorkService.getShutdownTimeout(); - if (shutdownTimeout == 0) latch.await(); - else latch.await(shutdownTimeout, TimeUnit.MILLISECONDS); + if (shutdownTimeout == 0) { + latch.await(); + } else { + boolean completed = latch.await(shutdownTimeout, TimeUnit.MILLISECONDS); + if (!completed) { + LOGGER.warn("Consumer dispatcher for channel didn't shutdown after waiting for {} ms", shutdownTimeout); + } + } } catch (Throwable e) { /*ignored*/ } diff --git a/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java b/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java index 42e2d964ea..ca1a13411e 100644 --- a/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java +++ b/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java @@ -34,10 +34,10 @@ public class ContentHeaderPropertyReader { private final ValueReader in; /** Current field flag word */ - public int flagWord; + private int flagWord; /** Current flag position counter */ - public int bitCount; + private int bitCount; /** * Protected API - Constructs a reader from the given input stream diff --git a/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java b/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java index 1d22f9daa2..ad6211ab6d 100644 --- a/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java +++ b/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java @@ -33,10 +33,10 @@ public class ContentHeaderPropertyWriter { private final ValueWriter out; /** Current flags word being accumulated */ - public int flagWord; + private int flagWord; /** Position within current flags word */ - public int bitCount; + private int bitCount; /** * Constructs a fresh ContentHeaderPropertyWriter. diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java index 3bf0953063..c9e1ffb202 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java @@ -78,7 +78,10 @@ public FrameHandler create(Address addr, String connectionName) throws IOExcepti } SocketAddress address = new InetSocketAddress(addr.getHost(), portNumber); - channel = SocketChannel.open(); + // No Sonar: the channel is closed in case of error and it cannot + // be closed here because it's part of the state of the connection + // to be returned. + channel = SocketChannel.open(); //NOSONAR channel.configureBlocking(true); if(nioParams.getSocketChannelConfigurator() != null) { nioParams.getSocketChannelConfigurator().configure(channel); diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java index 10081fcf02..e74170d247 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java @@ -761,7 +761,8 @@ public void automaticallyRecover(AutorecoveringConnection connection, Connection this.connection = connection; final RecoveryAwareChannelN newChannel = (RecoveryAwareChannelN) connDelegate.createChannel(this.getChannelNumber()); - if (newChannel == null) + // No Sonar: the channel could be null + if (newChannel == null) //NOSONAR throw new IOException("Failed to create new channel for channel number=" + this.getChannelNumber() + " during recovery"); newChannel.inheritOffsetFrom(defunctChannel); this.delegate = newChannel; diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index 4c52fa52fb..bfd2336a5b 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -163,7 +163,8 @@ public void init() throws IOException, TimeoutException { @Override public Channel createChannel() throws IOException { RecoveryAwareChannelN ch = (RecoveryAwareChannelN) delegate.createChannel(); - if (ch == null) { + // No Sonar: the channel could be null + if (ch == null) { //NOSONAR return null; } else { return this.wrapChannel(ch); @@ -599,7 +600,9 @@ private RecoveryAwareAMQConnection recoverConnection() throws InterruptedExcepti while (!manuallyClosed) { try { attempts++; - RecoveryAwareAMQConnection newConn = this.cf.newConnection(); + // No Sonar: no need to close this resource because we're the one that creates it + // and hands it over to the user + RecoveryAwareAMQConnection newConn = this.cf.newConnection(); //NOSONAR synchronized(recoveryLock) { if (!manuallyClosed) { // This is the standard case. diff --git a/src/main/java/com/rabbitmq/utility/Utility.java b/src/main/java/com/rabbitmq/utility/Utility.java index 7de31cf895..23e4c56bf3 100644 --- a/src/main/java/com/rabbitmq/utility/Utility.java +++ b/src/main/java/com/rabbitmq/utility/Utility.java @@ -82,7 +82,8 @@ public static > T fixStackTrace(T throwab * @return ArrayList copy of the list */ public static List copy(final List list) { - synchronized (list) { + // No Sonar: this very list instance can be synchronized in other places of its owning class + synchronized (list) { //NOSONAR return new ArrayList(list); } } @@ -96,7 +97,8 @@ public static List copy(final List list) { * @return LinkedHashMap copy of the map */ public static Map copy(final Map map) { - synchronized (map) { + // No Sonar: this very map instance can be synchronized in other places of its owning class + synchronized (map) { //NOSONAR return new LinkedHashMap(map); } } From 57d4fff6ac2693819ab451c60fe4bf17ad71a773 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 6 Dec 2018 09:51:31 +0100 Subject: [PATCH 0983/2114] Make properties private in JSON RPC classes Accessors are now provided instead. Fixes #429 --- .../tools/jsonrpc/JsonRpcException.java | 25 ++++++++++++--- .../rabbitmq/tools/jsonrpc/JsonRpcServer.java | 12 +++---- .../tools/jsonrpc/ParameterDescription.java | 12 +++++-- .../tools/jsonrpc/ProcedureDescription.java | 24 +++++++++++--- .../tools/jsonrpc/ServiceDescription.java | 32 +++++++++++++++---- 5 files changed, 82 insertions(+), 23 deletions(-) diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java index fafb9457d0..7a58e5ff56 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java @@ -27,19 +27,19 @@ public class JsonRpcException extends Exception { /** * Usually the constant string, "JSONRPCError" */ - public String name; + private String name; /** * Error code */ - public int code; + private int code; /** * Error message */ - public String message; + private String message; /** * Error detail object - may not always be present or meaningful */ - public Object error; + private Object error; public JsonRpcException() { // no work needed in default no-arg constructor @@ -52,4 +52,21 @@ public JsonRpcException(String detailMessage, String name, int code, String mess this.message = message; this.error = error; } + + public String getName() { + return name; + } + + public int getCode() { + return code; + } + + @Override + public String getMessage() { + return message; + } + + public Object getError() { + return error; + } } diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java index ec22770e7f..e0b8373fd4 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java @@ -52,15 +52,11 @@ public class JsonRpcServer extends StringRpcServer { /** * Holds the JSON-RPC service description for this client. */ - public ServiceDescription serviceDescription; - /** - * The interface this server implements. - */ - public Class interfaceClass; + private ServiceDescription serviceDescription; /** * The instance backing this server. */ - public Object interfaceInstance; + private Object interfaceInstance; public JsonRpcServer(Channel channel, Class interfaceClass, @@ -119,7 +115,9 @@ public JsonRpcServer(Channel channel, } private void init(Class interfaceClass, Object interfaceInstance) { - this.interfaceClass = interfaceClass; + /** + * The interface this server implements. + */ this.interfaceInstance = interfaceInstance; this.serviceDescription = new ServiceDescription(interfaceClass); } diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/ParameterDescription.java b/src/main/java/com/rabbitmq/tools/jsonrpc/ParameterDescription.java index 4046c61602..c0fc274947 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/ParameterDescription.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/ParameterDescription.java @@ -26,12 +26,12 @@ */ public class ParameterDescription { /** The parameter name. */ - public String name; + private String name; /** * The parameter type - one of "bit", "num", "str", "arr", * "obj", "any" or "nil". */ - public String type; + private String type; public ParameterDescription() { // Nothing to do here. @@ -57,4 +57,12 @@ public static String lookup(Class c) { if (Collection.class.isAssignableFrom(c)) return "arr"; return "any"; } + + public String getName() { + return name; + } + + public String getType() { + return type; + } } diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java b/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java index 714db1da96..0f66a8406e 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java @@ -27,13 +27,13 @@ */ public class ProcedureDescription { /** Procedure name */ - public String name; + private String name; /** Human-readable procedure summary */ - public String summary; + private String summary; /** Human-readable instructions for how to get information on the procedure's operation */ - public String help; + private String help; /** True if this procedure is idempotent, that is, can be accessed via HTTP GET */ - public boolean idempotent; + private boolean idempotent; /** Descriptions of parameters for this procedure */ private ParameterDescription[] params; @@ -139,4 +139,20 @@ public int arity() { public ParameterDescription[] getParams() { return params; } + + public String getName() { + return name; + } + + public String getSummary() { + return summary; + } + + public String getHelp() { + return help; + } + + public boolean isIdempotent() { + return idempotent; + } } diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java b/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java index 4cb6d3bf66..6e0092049b 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java @@ -30,15 +30,15 @@ public class ServiceDescription { public static final String JSON_RPC_VERSION = "1.1"; /** The service name */ - public String name; + private String name; /** ID for the service */ - public String id; + private String id; /** Version of the service */ - public String version; + private String version; /** Human-readable summary for the service */ - public String summary; + private String summary; /** Human-readable instructions for how to get information on the service's operation */ - public String help; + private String help; /** Map from procedure name to {@link ProcedureDescription} */ private Map procedures; @@ -75,7 +75,7 @@ public void setProcs(Collection> p) { /** Private API - used during initialization */ private void addProcedure(ProcedureDescription proc) { - procedures.put(proc.name + "/" + proc.arity(), proc); + procedures.put(proc.getName() + "/" + proc.arity(), proc); } /** @@ -91,4 +91,24 @@ public ProcedureDescription getProcedure(String newname, int arity) { } return proc; } + + public String getName() { + return name; + } + + public String getId() { + return id; + } + + public String getVersion() { + return version; + } + + public String getSummary() { + return summary; + } + + public String getHelp() { + return help; + } } From 0168ce9ffab7a2884cbc2b11837a65724851f61e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 6 Dec 2018 11:20:43 +0100 Subject: [PATCH 0984/2114] Add setters to JSON RPC classes When appropriate. Some properties are accessed with reflection and making them private makes those reflection calls fail. References #429 --- .../tools/jsonrpc/JsonRpcException.java | 13 +++++++----- .../tools/jsonrpc/ParameterDescription.java | 8 ++++++++ .../tools/jsonrpc/ProcedureDescription.java | 16 +++++++++++++++ .../tools/jsonrpc/ServiceDescription.java | 20 +++++++++++++++++++ 4 files changed, 52 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java index 7a58e5ff56..18c0e93b84 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java @@ -27,22 +27,25 @@ public class JsonRpcException extends Exception { /** * Usually the constant string, "JSONRPCError" */ - private String name; + private final String name; /** * Error code */ - private int code; + private final int code; /** * Error message */ - private String message; + private final String message; /** * Error detail object - may not always be present or meaningful */ - private Object error; + private final Object error; public JsonRpcException() { - // no work needed in default no-arg constructor + this.name = null; + this.code = -1; + this.message = null; + this.error = null; } public JsonRpcException(String detailMessage, String name, int code, String message, Object error) { diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/ParameterDescription.java b/src/main/java/com/rabbitmq/tools/jsonrpc/ParameterDescription.java index c0fc274947..97fb9d0d01 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/ParameterDescription.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/ParameterDescription.java @@ -65,4 +65,12 @@ public String getName() { public String getType() { return type; } + + public void setName(String name) { + this.name = name; + } + + public void setType(String type) { + this.type = type; + } } diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java b/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java index 0f66a8406e..db637d1c38 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java @@ -155,4 +155,20 @@ public String getHelp() { public boolean isIdempotent() { return idempotent; } + + public void setName(String name) { + this.name = name; + } + + public void setSummary(String summary) { + this.summary = summary; + } + + public void setHelp(String help) { + this.help = help; + } + + public void setIdempotent(boolean idempotent) { + this.idempotent = idempotent; + } } diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java b/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java index 6e0092049b..a42a1b2f1d 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java @@ -111,4 +111,24 @@ public String getSummary() { public String getHelp() { return help; } + + public void setName(String name) { + this.name = name; + } + + public void setId(String id) { + this.id = id; + } + + public void setVersion(String version) { + this.version = version; + } + + public void setSummary(String summary) { + this.summary = summary; + } + + public void setHelp(String help) { + this.help = help; + } } From 2c96753eec36ca9ba8005ba0c6f56790e61df9ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 4 Dec 2018 18:01:25 +0100 Subject: [PATCH 0985/2114] Fix some Sonar warnings (cherry picked from commit 1c3cf6af2ae24af93d97a2036d6e1e092d713d13) --- pom.xml | 11 +++++++++++ .../java/com/rabbitmq/client/ConnectionFactory.java | 2 +- .../com/rabbitmq/client/impl/nio/FrameBuilder.java | 4 ++-- .../impl/nio/SocketChannelFrameHandlerFactory.java | 6 ++++-- .../client/impl/recovery/AutorecoveringChannel.java | 2 +- .../impl/recovery/AutorecoveringConnection.java | 2 +- src/main/java/com/rabbitmq/utility/BlockingCell.java | 2 +- 7 files changed, 21 insertions(+), 8 deletions(-) diff --git a/pom.xml b/pom.xml index 618e24f9fb..900f0ced38 100644 --- a/pom.xml +++ b/pom.xml @@ -744,6 +744,17 @@ + + + + + org.sonarsource.scanner.maven + sonar-maven-plugin + 3.5.0.1254 + + + + diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index e23325d18f..0d07297549 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -1099,7 +1099,7 @@ public Connection newConnection(ExecutorService executor, AddressResolver addres if (isAutomaticRecoveryEnabled()) { // see com.rabbitmq.client.impl.recovery.RecoveryAwareAMQConnectionFactory#newConnection - AutorecoveringConnection conn = new AutorecoveringConnection(params, fhFactory, addressResolver, metricsCollector); + AutorecoveringConnection conn = new AutorecoveringConnection(params, fhFactory, addressResolver, metricsCollector); //NOSONAR conn.init(); return conn; diff --git a/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java b/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java index 56bbf28669..5bb867899f 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java @@ -80,7 +80,7 @@ public Frame readFrame() throws IOException { frameBuffer[0] = readFromBuffer(); } else if (bytesRead == 2) { // channel 2/2 - frameChannel = (frameBuffer[0] << 8) + (readFromBuffer() << 0); + frameChannel = (frameBuffer[0] << 8) + readFromBuffer(); } else if (bytesRead == 3) { // payload size 1/4 frameBuffer[0] = readFromBuffer(); @@ -92,7 +92,7 @@ public Frame readFrame() throws IOException { frameBuffer[2] = readFromBuffer(); } else if (bytesRead == 6) { // payload size 4/4 - int framePayloadSize = ((frameBuffer[0] << 24) + (frameBuffer[1] << 16) + (frameBuffer[2] << 8) + (readFromBuffer() << 0)); + int framePayloadSize = (frameBuffer[0] << 24) + (frameBuffer[1] << 16) + (frameBuffer[2] << 8) + readFromBuffer(); framePayload = new byte[framePayloadSize]; } else if (bytesRead >= PAYLOAD_OFFSET && bytesRead < framePayload.length + PAYLOAD_OFFSET) { framePayload[bytesRead - PAYLOAD_OFFSET] = (byte) readFromBuffer(); diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java index f900325ed4..cb4d544a33 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java @@ -78,7 +78,7 @@ public FrameHandler create(Address addr, String connectionName) throws IOExcepti } SocketAddress address = new InetSocketAddress(addr.getHost(), portNumber); - channel = SocketChannel.open(); + channel = SocketChannel.open(); //NOSONAR channel.configureBlocking(true); if(nioParams.getSocketChannelConfigurator() != null) { nioParams.getSocketChannelConfigurator().configure(channel); @@ -122,7 +122,9 @@ public FrameHandler create(Address addr, String connectionName) throws IOExcepti if(sslEngine != null && channel != null) { SslEngineHelper.close(channel, sslEngine); } - channel.close(); + if (channel != null) { + channel.close(); + } } catch(IOException closingException) { // ignore } diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java index 10081fcf02..1df7822f2c 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java @@ -761,7 +761,7 @@ public void automaticallyRecover(AutorecoveringConnection connection, Connection this.connection = connection; final RecoveryAwareChannelN newChannel = (RecoveryAwareChannelN) connDelegate.createChannel(this.getChannelNumber()); - if (newChannel == null) + if (newChannel == null) //NOSONAR throw new IOException("Failed to create new channel for channel number=" + this.getChannelNumber() + " during recovery"); newChannel.inheritOffsetFrom(defunctChannel); this.delegate = newChannel; diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index c200c8fd59..ae3659bbfb 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -163,7 +163,7 @@ public void init() throws IOException, TimeoutException { @Override public Channel createChannel() throws IOException { RecoveryAwareChannelN ch = (RecoveryAwareChannelN) delegate.createChannel(); - if (ch == null) { + if (ch == null) { //NOSONAR return null; } else { return this.wrapChannel(ch); diff --git a/src/main/java/com/rabbitmq/utility/BlockingCell.java b/src/main/java/com/rabbitmq/utility/BlockingCell.java index 2a7d6fb256..7fc8ec5641 100644 --- a/src/main/java/com/rabbitmq/utility/BlockingCell.java +++ b/src/main/java/com/rabbitmq/utility/BlockingCell.java @@ -28,7 +28,7 @@ public class BlockingCell { /** Will be null until a value is supplied, and possibly still then. */ private T _value; - private static final long NANOS_IN_MILLI = 1000 * 1000; + private static final long NANOS_IN_MILLI = 1000L * 1000L; private static final long INFINITY = -1; From 18b15bb1c30add08e6f870dc6b3ff6d87f4f4542 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 5 Dec 2018 09:38:40 +0100 Subject: [PATCH 0986/2114] Stop RpcServer when its thread is interrupted Fixes #428 (cherry picked from commit 07b86cafc698eda8032e02a6880a4f558690f81b) --- .../java/com/rabbitmq/client/RpcServer.java | 5 +++- .../com/rabbitmq/client/test/RpcTest.java | 25 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/RpcServer.java b/src/main/java/com/rabbitmq/client/RpcServer.java index 581c2d8384..457e5f6679 100644 --- a/src/main/java/com/rabbitmq/client/RpcServer.java +++ b/src/main/java/com/rabbitmq/client/RpcServer.java @@ -96,7 +96,8 @@ protected RpcConsumer setupConsumer() * Public API - main server loop. Call this to begin processing * requests. Request processing will continue until the Channel * (or its underlying Connection) is shut down, or until - * terminateMainloop() is called. + * terminateMainloop() is called, or until the thread running the loop + * is interrupted. * * Note that if the mainloop is blocked waiting for a request, the * termination flag is not checked until a request is received, so @@ -114,6 +115,8 @@ public ShutdownSignalException mainloop() try { request = _consumer.nextDelivery(); } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + _mainloopRunning = false; continue; } processRequest(request); diff --git a/src/test/java/com/rabbitmq/client/test/RpcTest.java b/src/test/java/com/rabbitmq/client/test/RpcTest.java index b107711b0d..0c05f761e2 100644 --- a/src/test/java/com/rabbitmq/client/test/RpcTest.java +++ b/src/test/java/com/rabbitmq/client/test/RpcTest.java @@ -24,6 +24,8 @@ import com.rabbitmq.client.impl.recovery.RecordedQueue; import com.rabbitmq.client.impl.recovery.TopologyRecoveryFilter; import com.rabbitmq.tools.Host; +import org.awaitility.Awaitility; +import org.awaitility.Duration; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -37,6 +39,7 @@ import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; +import static org.awaitility.Awaitility.waitAtMost; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -281,6 +284,28 @@ public void handleRecoveryStarted(Recoverable recoverable) { } } + @Test public void interruptingServerThreadShouldStopIt() throws Exception { + rpcServer = new TestRpcServer(serverChannel, queue); + Thread serverThread = new Thread(() -> { + try { + rpcServer.mainloop(); + } catch (Exception e) { + // safe to ignore when loops ends/server is canceled + } + }); + serverThread.start(); + RpcClient client = new RpcClient(new RpcClientParams() + .channel(clientChannel).exchange("").routingKey(queue).timeout(1000)); + RpcClient.Response response = client.doCall(null, "hello".getBytes()); + assertEquals("*** hello ***", new String(response.getBody())); + + serverThread.interrupt(); + + waitAtMost(Duration.ONE_SECOND).until(() -> !serverThread.isAlive()) ; + + client.close(); + } + private static class TestRpcServer extends RpcServer { public TestRpcServer(Channel channel, String queueName) throws IOException { From 04badb406f455a5dd6e6bbe85966eafe190ddb97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 5 Dec 2018 10:08:57 +0100 Subject: [PATCH 0987/2114] Fix some Sonar warnings (cherry picked from commit c176ff96b3fdff1f46472fe533201c275682b04a) --- src/main/java/com/rabbitmq/client/ConnectionFactory.java | 2 +- src/main/java/com/rabbitmq/client/impl/AMQChannel.java | 4 +++- src/main/java/com/rabbitmq/client/impl/WorkPool.java | 2 +- .../client/impl/nio/SocketChannelFrameHandlerFactory.java | 2 +- .../client/impl/nio/SocketChannelFrameHandlerState.java | 1 + .../java/com/rabbitmq/client/impl/nio/SslEngineHelper.java | 2 +- .../rabbitmq/client/impl/recovery/AutorecoveringChannel.java | 2 +- .../client/impl/recovery/AutorecoveringConnection.java | 4 ++-- 8 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 0d07297549..e23325d18f 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -1099,7 +1099,7 @@ public Connection newConnection(ExecutorService executor, AddressResolver addres if (isAutomaticRecoveryEnabled()) { // see com.rabbitmq.client.impl.recovery.RecoveryAwareAMQConnectionFactory#newConnection - AutorecoveringConnection conn = new AutorecoveringConnection(params, fhFactory, addressResolver, metricsCollector); //NOSONAR + AutorecoveringConnection conn = new AutorecoveringConnection(params, fhFactory, addressResolver, metricsCollector); conn.init(); return conn; diff --git a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java index b9810f67e5..985f89cf4d 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java @@ -440,7 +440,9 @@ public void quiescingTransmit(AMQCommand c) throws IOException { while (_blockContent) { try { _channelMutex.wait(); - } catch (InterruptedException ignored) {} + } catch (InterruptedException ignored) { + Thread.currentThread().interrupt(); + } // This is to catch a situation when the thread wakes up during // shutdown. Currently, no command that has content is allowed diff --git a/src/main/java/com/rabbitmq/client/impl/WorkPool.java b/src/main/java/com/rabbitmq/client/impl/WorkPool.java index ea2111b320..dfccd33acf 100644 --- a/src/main/java/com/rabbitmq/client/impl/WorkPool.java +++ b/src/main/java/com/rabbitmq/client/impl/WorkPool.java @@ -74,7 +74,7 @@ public WorkPool(final int queueingTimeout) { throw new WorkPoolFullException("Could not enqueue in work pool after " + queueingTimeout + " ms."); } } catch (InterruptedException e) { - Thread.currentThread(); + Thread.currentThread().interrupt(); } }; } else { diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java index cb4d544a33..3bf0953063 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java @@ -78,7 +78,7 @@ public FrameHandler create(Address addr, String connectionName) throws IOExcepti } SocketAddress address = new InetSocketAddress(addr.getHost(), portNumber); - channel = SocketChannel.open(); //NOSONAR + channel = SocketChannel.open(); channel.configureBlocking(true); if(nioParams.getSocketChannelConfigurator() != null) { nioParams.getSocketChannelConfigurator().configure(channel); diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java index 513280a72d..bea18489c7 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java @@ -137,6 +137,7 @@ private void sendWriteRequest(WriteRequest writeRequest) throws IOException { } } catch (InterruptedException e) { LOGGER.warn("Thread interrupted during enqueuing frame in write queue"); + Thread.currentThread().interrupt(); } } diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java index 7bfaa26d1e..c4b8a33c26 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java @@ -113,7 +113,7 @@ private static int retryRead(ReadableByteChannel channel, ByteBuffer buffer) thr try { Thread.sleep(100L); } catch (InterruptedException e) { - // ignore + Thread.currentThread().interrupt(); } read = NioHelper.read(channel, buffer); if(read > 0) { diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java index 1df7822f2c..10081fcf02 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java @@ -761,7 +761,7 @@ public void automaticallyRecover(AutorecoveringConnection connection, Connection this.connection = connection; final RecoveryAwareChannelN newChannel = (RecoveryAwareChannelN) connDelegate.createChannel(this.getChannelNumber()); - if (newChannel == null) //NOSONAR + if (newChannel == null) throw new IOException("Failed to create new channel for channel number=" + this.getChannelNumber() + " during recovery"); newChannel.inheritOffsetFrom(defunctChannel); this.delegate = newChannel; diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index ae3659bbfb..4c52fa52fb 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -163,7 +163,7 @@ public void init() throws IOException, TimeoutException { @Override public Channel createChannel() throws IOException { RecoveryAwareChannelN ch = (RecoveryAwareChannelN) delegate.createChannel(); - if (ch == null) { //NOSONAR + if (ch == null) { return null; } else { return this.wrapChannel(ch); @@ -559,7 +559,7 @@ public void removeConsumerRecoveryListener(ConsumerRecoveryListener listener) { } private synchronized void beginAutomaticRecovery() throws InterruptedException { - Thread.sleep(this.params.getRecoveryDelayHandler().getDelay(0)); + this.wait(this.params.getRecoveryDelayHandler().getDelay(0)); this.notifyRecoveryListenersStarted(); From ced9e7a862e3d61016c3d480e9394cc8eb56ce75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 6 Dec 2018 09:51:10 +0100 Subject: [PATCH 0988/2114] Fix some Sonar warnings (cherry picked from commit 36d12f887c34f99afb19326458d0b25f50949cd0) --- .../java/com/rabbitmq/client/ConnectionFactory.java | 4 +++- .../rabbitmq/client/ConnectionFactoryConfigurator.java | 2 +- .../com/rabbitmq/client/SslEngineConfigurators.java | 4 ++-- src/main/java/com/rabbitmq/client/impl/AMQChannel.java | 5 +++-- .../java/com/rabbitmq/client/impl/ChannelManager.java | 10 ++++++++-- .../client/impl/ContentHeaderPropertyReader.java | 4 ++-- .../client/impl/ContentHeaderPropertyWriter.java | 4 ++-- .../impl/nio/SocketChannelFrameHandlerFactory.java | 5 ++++- .../client/impl/recovery/AutorecoveringChannel.java | 3 ++- .../client/impl/recovery/AutorecoveringConnection.java | 7 +++++-- src/main/java/com/rabbitmq/utility/Utility.java | 6 ++++-- 11 files changed, 36 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index e23325d18f..4dba1db7df 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -1099,7 +1099,9 @@ public Connection newConnection(ExecutorService executor, AddressResolver addres if (isAutomaticRecoveryEnabled()) { // see com.rabbitmq.client.impl.recovery.RecoveryAwareAMQConnectionFactory#newConnection - AutorecoveringConnection conn = new AutorecoveringConnection(params, fhFactory, addressResolver, metricsCollector); + // No Sonar: no need to close this resource because we're the one that creates it + // and hands it over to the user + AutorecoveringConnection conn = new AutorecoveringConnection(params, fhFactory, addressResolver, metricsCollector); //NOSONAR conn.init(); return conn; diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java b/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java index 2052e4da1c..694b7626a8 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java @@ -54,7 +54,7 @@ public class ConnectionFactoryConfigurator { public static final String DEFAULT_PREFIX = "rabbitmq."; public static final String USERNAME = "username"; - public static final String PASSWORD = "password"; + public static final String PASSWORD = "password"; //NOSONAR public static final String VIRTUAL_HOST = "virtual.host"; public static final String HOST = "host"; public static final String PORT = "port"; diff --git a/src/main/java/com/rabbitmq/client/SslEngineConfigurators.java b/src/main/java/com/rabbitmq/client/SslEngineConfigurators.java index 119bb0314f..44c2e16f70 100644 --- a/src/main/java/com/rabbitmq/client/SslEngineConfigurators.java +++ b/src/main/java/com/rabbitmq/client/SslEngineConfigurators.java @@ -30,13 +30,13 @@ public abstract class SslEngineConfigurators { /** * Default {@link SslEngineConfigurator}, does nothing. */ - public static SslEngineConfigurator DEFAULT = sslEngine -> { + public static final SslEngineConfigurator DEFAULT = sslEngine -> { }; /** * {@link SslEngineConfigurator} that enables server hostname verification. */ - public static SslEngineConfigurator ENABLE_HOSTNAME_VERIFICATION = sslEngine -> { + public static final SslEngineConfigurator ENABLE_HOSTNAME_VERIFICATION = sslEngine -> { SSLParameters sslParameters = SocketConfigurators.enableHostnameVerification(sslEngine.getSSLParameters()); sslEngine.setSSLParameters(sslParameters); }; diff --git a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java index 985f89cf4d..3cdcf8c50f 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java @@ -68,7 +68,7 @@ public abstract class AMQChannel extends ShutdownNotifierComponent { private RpcWrapper _activeRpc = null; /** Whether transmission of content-bearing methods should be blocked */ - public volatile boolean _blockContent = false; + protected volatile boolean _blockContent = false; /** Timeout for RPC calls */ protected final int _rpcTimeout; @@ -218,8 +218,9 @@ private void doEnqueueRpc(Supplier rpcWrapperSupplier) { while (_activeRpc != null) { try { _channelMutex.wait(); - } catch (InterruptedException e) { + } catch (InterruptedException e) { //NOSONAR waitClearedInterruptStatus = true; + // No Sonar: we re-interrupt the thread later } } if (waitClearedInterruptStatus) { diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelManager.java b/src/main/java/com/rabbitmq/client/impl/ChannelManager.java index 53fedee158..73b78f71b4 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelManager.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelManager.java @@ -143,8 +143,14 @@ public void run() { for (CountDownLatch latch : sdSet) { try { int shutdownTimeout = ssWorkService.getShutdownTimeout(); - if (shutdownTimeout == 0) latch.await(); - else latch.await(shutdownTimeout, TimeUnit.MILLISECONDS); + if (shutdownTimeout == 0) { + latch.await(); + } else { + boolean completed = latch.await(shutdownTimeout, TimeUnit.MILLISECONDS); + if (!completed) { + LOGGER.warn("Consumer dispatcher for channel didn't shutdown after waiting for {} ms", shutdownTimeout); + } + } } catch (Throwable e) { /*ignored*/ } diff --git a/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java b/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java index 42e2d964ea..ca1a13411e 100644 --- a/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java +++ b/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java @@ -34,10 +34,10 @@ public class ContentHeaderPropertyReader { private final ValueReader in; /** Current field flag word */ - public int flagWord; + private int flagWord; /** Current flag position counter */ - public int bitCount; + private int bitCount; /** * Protected API - Constructs a reader from the given input stream diff --git a/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java b/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java index 1d22f9daa2..ad6211ab6d 100644 --- a/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java +++ b/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java @@ -33,10 +33,10 @@ public class ContentHeaderPropertyWriter { private final ValueWriter out; /** Current flags word being accumulated */ - public int flagWord; + private int flagWord; /** Position within current flags word */ - public int bitCount; + private int bitCount; /** * Constructs a fresh ContentHeaderPropertyWriter. diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java index 3bf0953063..c9e1ffb202 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java @@ -78,7 +78,10 @@ public FrameHandler create(Address addr, String connectionName) throws IOExcepti } SocketAddress address = new InetSocketAddress(addr.getHost(), portNumber); - channel = SocketChannel.open(); + // No Sonar: the channel is closed in case of error and it cannot + // be closed here because it's part of the state of the connection + // to be returned. + channel = SocketChannel.open(); //NOSONAR channel.configureBlocking(true); if(nioParams.getSocketChannelConfigurator() != null) { nioParams.getSocketChannelConfigurator().configure(channel); diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java index 10081fcf02..e74170d247 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java @@ -761,7 +761,8 @@ public void automaticallyRecover(AutorecoveringConnection connection, Connection this.connection = connection; final RecoveryAwareChannelN newChannel = (RecoveryAwareChannelN) connDelegate.createChannel(this.getChannelNumber()); - if (newChannel == null) + // No Sonar: the channel could be null + if (newChannel == null) //NOSONAR throw new IOException("Failed to create new channel for channel number=" + this.getChannelNumber() + " during recovery"); newChannel.inheritOffsetFrom(defunctChannel); this.delegate = newChannel; diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index 4c52fa52fb..bfd2336a5b 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -163,7 +163,8 @@ public void init() throws IOException, TimeoutException { @Override public Channel createChannel() throws IOException { RecoveryAwareChannelN ch = (RecoveryAwareChannelN) delegate.createChannel(); - if (ch == null) { + // No Sonar: the channel could be null + if (ch == null) { //NOSONAR return null; } else { return this.wrapChannel(ch); @@ -599,7 +600,9 @@ private RecoveryAwareAMQConnection recoverConnection() throws InterruptedExcepti while (!manuallyClosed) { try { attempts++; - RecoveryAwareAMQConnection newConn = this.cf.newConnection(); + // No Sonar: no need to close this resource because we're the one that creates it + // and hands it over to the user + RecoveryAwareAMQConnection newConn = this.cf.newConnection(); //NOSONAR synchronized(recoveryLock) { if (!manuallyClosed) { // This is the standard case. diff --git a/src/main/java/com/rabbitmq/utility/Utility.java b/src/main/java/com/rabbitmq/utility/Utility.java index 62af79a5f8..d345717fc4 100644 --- a/src/main/java/com/rabbitmq/utility/Utility.java +++ b/src/main/java/com/rabbitmq/utility/Utility.java @@ -100,7 +100,8 @@ public static String makeStackTrace(Throwable throwable) { * @return ArrayList copy of the list */ public static List copy(final List list) { - synchronized (list) { + // No Sonar: this very list instance can be synchronized in other places of its owning class + synchronized (list) { //NOSONAR return new ArrayList(list); } } @@ -114,7 +115,8 @@ public static List copy(final List list) { * @return LinkedHashMap copy of the map */ public static Map copy(final Map map) { - synchronized (map) { + // No Sonar: this very map instance can be synchronized in other places of its owning class + synchronized (map) { //NOSONAR return new LinkedHashMap(map); } } From e730cd87603f30590d82a25cbc6f76c2a7cf884d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 6 Dec 2018 09:51:31 +0100 Subject: [PATCH 0989/2114] Make properties private in JSON RPC classes Accessors are now provided instead. Fixes #429 (cherry picked from commit 57d4fff6ac2693819ab451c60fe4bf17ad71a773) --- .../tools/jsonrpc/JsonRpcException.java | 25 ++++++++++++--- .../rabbitmq/tools/jsonrpc/JsonRpcServer.java | 12 +++---- .../tools/jsonrpc/ParameterDescription.java | 12 +++++-- .../tools/jsonrpc/ProcedureDescription.java | 24 +++++++++++--- .../tools/jsonrpc/ServiceDescription.java | 32 +++++++++++++++---- 5 files changed, 82 insertions(+), 23 deletions(-) diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java index fafb9457d0..7a58e5ff56 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java @@ -27,19 +27,19 @@ public class JsonRpcException extends Exception { /** * Usually the constant string, "JSONRPCError" */ - public String name; + private String name; /** * Error code */ - public int code; + private int code; /** * Error message */ - public String message; + private String message; /** * Error detail object - may not always be present or meaningful */ - public Object error; + private Object error; public JsonRpcException() { // no work needed in default no-arg constructor @@ -52,4 +52,21 @@ public JsonRpcException(String detailMessage, String name, int code, String mess this.message = message; this.error = error; } + + public String getName() { + return name; + } + + public int getCode() { + return code; + } + + @Override + public String getMessage() { + return message; + } + + public Object getError() { + return error; + } } diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java index 723664c3b5..61a3796647 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java @@ -52,15 +52,11 @@ public class JsonRpcServer extends StringRpcServer { /** * Holds the JSON-RPC service description for this client. */ - public ServiceDescription serviceDescription; - /** - * The interface this server implements. - */ - public Class interfaceClass; + private ServiceDescription serviceDescription; /** * The instance backing this server. */ - public Object interfaceInstance; + private Object interfaceInstance; public JsonRpcServer(Channel channel, Class interfaceClass, @@ -119,7 +115,9 @@ public JsonRpcServer(Channel channel, } private void init(Class interfaceClass, Object interfaceInstance) { - this.interfaceClass = interfaceClass; + /** + * The interface this server implements. + */ this.interfaceInstance = interfaceInstance; this.serviceDescription = new ServiceDescription(interfaceClass); } diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/ParameterDescription.java b/src/main/java/com/rabbitmq/tools/jsonrpc/ParameterDescription.java index 4046c61602..c0fc274947 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/ParameterDescription.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/ParameterDescription.java @@ -26,12 +26,12 @@ */ public class ParameterDescription { /** The parameter name. */ - public String name; + private String name; /** * The parameter type - one of "bit", "num", "str", "arr", * "obj", "any" or "nil". */ - public String type; + private String type; public ParameterDescription() { // Nothing to do here. @@ -57,4 +57,12 @@ public static String lookup(Class c) { if (Collection.class.isAssignableFrom(c)) return "arr"; return "any"; } + + public String getName() { + return name; + } + + public String getType() { + return type; + } } diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java b/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java index 714db1da96..0f66a8406e 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java @@ -27,13 +27,13 @@ */ public class ProcedureDescription { /** Procedure name */ - public String name; + private String name; /** Human-readable procedure summary */ - public String summary; + private String summary; /** Human-readable instructions for how to get information on the procedure's operation */ - public String help; + private String help; /** True if this procedure is idempotent, that is, can be accessed via HTTP GET */ - public boolean idempotent; + private boolean idempotent; /** Descriptions of parameters for this procedure */ private ParameterDescription[] params; @@ -139,4 +139,20 @@ public int arity() { public ParameterDescription[] getParams() { return params; } + + public String getName() { + return name; + } + + public String getSummary() { + return summary; + } + + public String getHelp() { + return help; + } + + public boolean isIdempotent() { + return idempotent; + } } diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java b/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java index 4cb6d3bf66..6e0092049b 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java @@ -30,15 +30,15 @@ public class ServiceDescription { public static final String JSON_RPC_VERSION = "1.1"; /** The service name */ - public String name; + private String name; /** ID for the service */ - public String id; + private String id; /** Version of the service */ - public String version; + private String version; /** Human-readable summary for the service */ - public String summary; + private String summary; /** Human-readable instructions for how to get information on the service's operation */ - public String help; + private String help; /** Map from procedure name to {@link ProcedureDescription} */ private Map procedures; @@ -75,7 +75,7 @@ public void setProcs(Collection> p) { /** Private API - used during initialization */ private void addProcedure(ProcedureDescription proc) { - procedures.put(proc.name + "/" + proc.arity(), proc); + procedures.put(proc.getName() + "/" + proc.arity(), proc); } /** @@ -91,4 +91,24 @@ public ProcedureDescription getProcedure(String newname, int arity) { } return proc; } + + public String getName() { + return name; + } + + public String getId() { + return id; + } + + public String getVersion() { + return version; + } + + public String getSummary() { + return summary; + } + + public String getHelp() { + return help; + } } From 906242239e7842eeeb1b6fe872aa753d54dad290 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 6 Dec 2018 11:20:43 +0100 Subject: [PATCH 0990/2114] Add setters to JSON RPC classes When appropriate. Some properties are accessed with reflection and making them private makes those reflection calls fail. References #429 (cherry picked from commit 0168ce9ffab7a2884cbc2b11837a65724851f61e) --- .../tools/jsonrpc/JsonRpcException.java | 13 +++++++----- .../tools/jsonrpc/ParameterDescription.java | 8 ++++++++ .../tools/jsonrpc/ProcedureDescription.java | 16 +++++++++++++++ .../tools/jsonrpc/ServiceDescription.java | 20 +++++++++++++++++++ 4 files changed, 52 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java index 7a58e5ff56..18c0e93b84 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java @@ -27,22 +27,25 @@ public class JsonRpcException extends Exception { /** * Usually the constant string, "JSONRPCError" */ - private String name; + private final String name; /** * Error code */ - private int code; + private final int code; /** * Error message */ - private String message; + private final String message; /** * Error detail object - may not always be present or meaningful */ - private Object error; + private final Object error; public JsonRpcException() { - // no work needed in default no-arg constructor + this.name = null; + this.code = -1; + this.message = null; + this.error = null; } public JsonRpcException(String detailMessage, String name, int code, String message, Object error) { diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/ParameterDescription.java b/src/main/java/com/rabbitmq/tools/jsonrpc/ParameterDescription.java index c0fc274947..97fb9d0d01 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/ParameterDescription.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/ParameterDescription.java @@ -65,4 +65,12 @@ public String getName() { public String getType() { return type; } + + public void setName(String name) { + this.name = name; + } + + public void setType(String type) { + this.type = type; + } } diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java b/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java index 0f66a8406e..db637d1c38 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java @@ -155,4 +155,20 @@ public String getHelp() { public boolean isIdempotent() { return idempotent; } + + public void setName(String name) { + this.name = name; + } + + public void setSummary(String summary) { + this.summary = summary; + } + + public void setHelp(String help) { + this.help = help; + } + + public void setIdempotent(boolean idempotent) { + this.idempotent = idempotent; + } } diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java b/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java index 6e0092049b..a42a1b2f1d 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java @@ -111,4 +111,24 @@ public String getSummary() { public String getHelp() { return help; } + + public void setName(String name) { + this.name = name; + } + + public void setId(String id) { + this.id = id; + } + + public void setVersion(String version) { + this.version = version; + } + + public void setSummary(String summary) { + this.summary = summary; + } + + public void setHelp(String help) { + this.help = help; + } } From 52588f239aac44584b7f37141f09d34b1dbbfec0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 6 Dec 2018 14:23:34 +0100 Subject: [PATCH 0991/2114] Use getter instead of property References #429 --- src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java index 23bb51764f..d23f56f0ff 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java @@ -262,7 +262,7 @@ public Object call(String[] args) Object[] actuals = new Object[arity]; for (int count = 0; count < params.length; count++) { - actuals[count] = coerce(args[count + 1], params[count].type); + actuals[count] = coerce(args[count + 1], params[count].getType()); } return call(method, actuals); From 018b3cd0cbb74d34e0c1364192d73a068168585d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 17 Dec 2018 16:08:31 +0100 Subject: [PATCH 0992/2114] Add Connection#openChannel to return Optional Fixes #431 --- .../java/com/rabbitmq/client/Connection.java | 43 ++++++ .../com/rabbitmq/client/test/ClientTests.java | 3 +- .../rabbitmq/client/test/ConnectionTest.java | 127 ++++++++++++++++++ 3 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 src/test/java/com/rabbitmq/client/test/ConnectionTest.java diff --git a/src/main/java/com/rabbitmq/client/Connection.java b/src/main/java/com/rabbitmq/client/Connection.java index be651e48ae..3bde680075 100644 --- a/src/main/java/com/rabbitmq/client/Connection.java +++ b/src/main/java/com/rabbitmq/client/Connection.java @@ -19,6 +19,7 @@ import java.io.IOException; import java.net.InetAddress; import java.util.Map; +import java.util.Optional; import java.util.concurrent.ExecutorService; /** @@ -117,6 +118,9 @@ public interface Connection extends ShutdownNotifier, Closeable { // rename to A * Create a new channel, using an internally allocated channel number. * If automatic connection recovery * is enabled, the channel returned by this method will be {@link Recoverable}. + *

+ * Use {@link #openChannel()} if you want to use an {@link Optional} to deal + * with a {@null} value. * * @return a new channel descriptor, or null if none is available * @throws IOException if an I/O problem is encountered @@ -125,12 +129,51 @@ public interface Connection extends ShutdownNotifier, Closeable { // rename to A /** * Create a new channel, using the specified channel number if possible. + *

+ * Use {@link #openChannel(int)} if you want to use an {@link Optional} to deal + * with a {@null} value. + * * @param channelNumber the channel number to allocate * @return a new channel descriptor, or null if this channel number is already in use * @throws IOException if an I/O problem is encountered */ Channel createChannel(int channelNumber) throws IOException; + /** + * Create a new channel wrapped in an {@link Optional}. + * The channel number is allocated internally. + *

+ * If automatic connection recovery + * is enabled, the channel returned by this method will be {@link Recoverable}. + *

+ * Use {@link #createChannel()} to return directly a {@link Channel} or {@code null}. + * + * @return an {@link Optional} containing the channel; + * never {@code null} but potentially empty if no channel is available + * @throws IOException if an I/O problem is encountered + * @see #createChannel() + * @since 5.6.0 + */ + default Optional openChannel() throws IOException { + return Optional.ofNullable(createChannel()); + } + + /** + * Create a new channel, using the specified channel number if possible. + *

+ * Use {@link #createChannel(int)} to return directly a {@link Channel} or {@code null}. + * + * @param channelNumber the channel number to allocate + * @return an {@link Optional} containing the channel, + * never {@code null} but potentially empty if this channel number is already in use + * @throws IOException if an I/O problem is encountered + * @see #createChannel(int) + * @since 5.6.0 + */ + default Optional openChannel(int channelNumber) throws IOException { + return Optional.ofNullable(createChannel(channelNumber)); + } + /** * Close this connection and all its channels * with the {@link com.rabbitmq.client.AMQP#REPLY_SUCCESS} close code diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index bf83d989e9..799cfd9126 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -65,7 +65,8 @@ DefaultRetryHandlerTest.class, NioDeadlockOnConnectionClosing.class, GeneratedClassesTest.class, - RpcTopologyRecordingTest.class + RpcTopologyRecordingTest.class, + ConnectionTest.class }) public class ClientTests { diff --git a/src/test/java/com/rabbitmq/client/test/ConnectionTest.java b/src/test/java/com/rabbitmq/client/test/ConnectionTest.java new file mode 100644 index 0000000000..36c1347b68 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/ConnectionTest.java @@ -0,0 +1,127 @@ +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.test; + +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.mockito.Mock; +import org.mockito.stubbing.OngoingStubbing; + +import java.io.IOException; +import java.util.NoSuchElementException; +import java.util.Optional; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +@RunWith(Parameterized.class) +public class ConnectionTest { + + @Parameterized.Parameter + public TestConfigurator configurator; + @Mock + Connection c = mock(Connection.class); + @Mock + Channel ch = mock(Channel.class); + + @Parameterized.Parameters + public static Object[] configurators() { + return new Object[]{new NotNumberedChannelCreationCallback(), new NumberedChannelCreationCallback()}; + } + + @Before + public void init() { + initMocks(this); + } + + @Test + public void openChannelWithNonNullChannelShouldReturnNonEmptyOptional() throws Exception { + configurator.mockAndWhenChannel(c).thenReturn(ch); + configurator.mockAndWhenOptional(c).thenCallRealMethod(); + Optional optional = configurator.open(c); + assertTrue(optional.isPresent()); + assertSame(ch, optional.get()); + } + + @Test(expected = NoSuchElementException.class) + public void openChannelWithNullChannelShouldReturnEmptyOptional() throws Exception { + configurator.mockAndWhenChannel(c).thenReturn(null); + configurator.mockAndWhenOptional(c).thenCallRealMethod(); + Optional optional = configurator.open(c); + assertFalse(optional.isPresent()); + optional.get(); + } + + @Test(expected = IOException.class) + public void openChannelShouldPropagateIoException() throws Exception { + configurator.mockAndWhenChannel(c).thenThrow(IOException.class); + configurator.mockAndWhenOptional(c).thenCallRealMethod(); + configurator.open(c); + } + + interface TestConfigurator { + + OngoingStubbing mockAndWhenChannel(Connection c) throws IOException; + + OngoingStubbing> mockAndWhenOptional(Connection c) throws IOException; + + Optional open(Connection c) throws IOException; + + } + + static class NotNumberedChannelCreationCallback implements TestConfigurator { + + @Override + public OngoingStubbing mockAndWhenChannel(Connection c) throws IOException { + return when(c.createChannel()); + } + + @Override + public OngoingStubbing> mockAndWhenOptional(Connection c) throws IOException { + return when(c.openChannel()); + } + + @Override + public Optional open(Connection c) throws IOException { + return c.openChannel(); + } + } + + static class NumberedChannelCreationCallback implements TestConfigurator { + + @Override + public OngoingStubbing mockAndWhenChannel(Connection c) throws IOException { + return when(c.createChannel(1)); + } + + @Override + public OngoingStubbing> mockAndWhenOptional(Connection c) throws IOException { + return when(c.openChannel(1)); + } + + @Override + public Optional open(Connection c) throws IOException { + return c.openChannel(1); + } + } + +} From 2642c7d4cf0a11591b23e19dfe4127c87de93f62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 17 Dec 2018 16:08:31 +0100 Subject: [PATCH 0993/2114] Add Connection#openChannel to return Optional Fixes #431 (cherry picked from commit 018b3cd0cbb74d34e0c1364192d73a068168585d) --- .../java/com/rabbitmq/client/Connection.java | 43 ++++++ .../com/rabbitmq/client/test/ClientTests.java | 3 +- .../rabbitmq/client/test/ConnectionTest.java | 127 ++++++++++++++++++ 3 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 src/test/java/com/rabbitmq/client/test/ConnectionTest.java diff --git a/src/main/java/com/rabbitmq/client/Connection.java b/src/main/java/com/rabbitmq/client/Connection.java index be651e48ae..3bde680075 100644 --- a/src/main/java/com/rabbitmq/client/Connection.java +++ b/src/main/java/com/rabbitmq/client/Connection.java @@ -19,6 +19,7 @@ import java.io.IOException; import java.net.InetAddress; import java.util.Map; +import java.util.Optional; import java.util.concurrent.ExecutorService; /** @@ -117,6 +118,9 @@ public interface Connection extends ShutdownNotifier, Closeable { // rename to A * Create a new channel, using an internally allocated channel number. * If automatic connection recovery * is enabled, the channel returned by this method will be {@link Recoverable}. + *

+ * Use {@link #openChannel()} if you want to use an {@link Optional} to deal + * with a {@null} value. * * @return a new channel descriptor, or null if none is available * @throws IOException if an I/O problem is encountered @@ -125,12 +129,51 @@ public interface Connection extends ShutdownNotifier, Closeable { // rename to A /** * Create a new channel, using the specified channel number if possible. + *

+ * Use {@link #openChannel(int)} if you want to use an {@link Optional} to deal + * with a {@null} value. + * * @param channelNumber the channel number to allocate * @return a new channel descriptor, or null if this channel number is already in use * @throws IOException if an I/O problem is encountered */ Channel createChannel(int channelNumber) throws IOException; + /** + * Create a new channel wrapped in an {@link Optional}. + * The channel number is allocated internally. + *

+ * If automatic connection recovery + * is enabled, the channel returned by this method will be {@link Recoverable}. + *

+ * Use {@link #createChannel()} to return directly a {@link Channel} or {@code null}. + * + * @return an {@link Optional} containing the channel; + * never {@code null} but potentially empty if no channel is available + * @throws IOException if an I/O problem is encountered + * @see #createChannel() + * @since 5.6.0 + */ + default Optional openChannel() throws IOException { + return Optional.ofNullable(createChannel()); + } + + /** + * Create a new channel, using the specified channel number if possible. + *

+ * Use {@link #createChannel(int)} to return directly a {@link Channel} or {@code null}. + * + * @param channelNumber the channel number to allocate + * @return an {@link Optional} containing the channel, + * never {@code null} but potentially empty if this channel number is already in use + * @throws IOException if an I/O problem is encountered + * @see #createChannel(int) + * @since 5.6.0 + */ + default Optional openChannel(int channelNumber) throws IOException { + return Optional.ofNullable(createChannel(channelNumber)); + } + /** * Close this connection and all its channels * with the {@link com.rabbitmq.client.AMQP#REPLY_SUCCESS} close code diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index f16e2483c9..998743d46b 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -68,7 +68,8 @@ DefaultRetryHandlerTest.class, NioDeadlockOnConnectionClosing.class, GeneratedClassesTest.class, - RpcTopologyRecordingTest.class + RpcTopologyRecordingTest.class, + ConnectionTest.class }) public class ClientTests { diff --git a/src/test/java/com/rabbitmq/client/test/ConnectionTest.java b/src/test/java/com/rabbitmq/client/test/ConnectionTest.java new file mode 100644 index 0000000000..36c1347b68 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/ConnectionTest.java @@ -0,0 +1,127 @@ +// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.test; + +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.mockito.Mock; +import org.mockito.stubbing.OngoingStubbing; + +import java.io.IOException; +import java.util.NoSuchElementException; +import java.util.Optional; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +@RunWith(Parameterized.class) +public class ConnectionTest { + + @Parameterized.Parameter + public TestConfigurator configurator; + @Mock + Connection c = mock(Connection.class); + @Mock + Channel ch = mock(Channel.class); + + @Parameterized.Parameters + public static Object[] configurators() { + return new Object[]{new NotNumberedChannelCreationCallback(), new NumberedChannelCreationCallback()}; + } + + @Before + public void init() { + initMocks(this); + } + + @Test + public void openChannelWithNonNullChannelShouldReturnNonEmptyOptional() throws Exception { + configurator.mockAndWhenChannel(c).thenReturn(ch); + configurator.mockAndWhenOptional(c).thenCallRealMethod(); + Optional optional = configurator.open(c); + assertTrue(optional.isPresent()); + assertSame(ch, optional.get()); + } + + @Test(expected = NoSuchElementException.class) + public void openChannelWithNullChannelShouldReturnEmptyOptional() throws Exception { + configurator.mockAndWhenChannel(c).thenReturn(null); + configurator.mockAndWhenOptional(c).thenCallRealMethod(); + Optional optional = configurator.open(c); + assertFalse(optional.isPresent()); + optional.get(); + } + + @Test(expected = IOException.class) + public void openChannelShouldPropagateIoException() throws Exception { + configurator.mockAndWhenChannel(c).thenThrow(IOException.class); + configurator.mockAndWhenOptional(c).thenCallRealMethod(); + configurator.open(c); + } + + interface TestConfigurator { + + OngoingStubbing mockAndWhenChannel(Connection c) throws IOException; + + OngoingStubbing> mockAndWhenOptional(Connection c) throws IOException; + + Optional open(Connection c) throws IOException; + + } + + static class NotNumberedChannelCreationCallback implements TestConfigurator { + + @Override + public OngoingStubbing mockAndWhenChannel(Connection c) throws IOException { + return when(c.createChannel()); + } + + @Override + public OngoingStubbing> mockAndWhenOptional(Connection c) throws IOException { + return when(c.openChannel()); + } + + @Override + public Optional open(Connection c) throws IOException { + return c.openChannel(); + } + } + + static class NumberedChannelCreationCallback implements TestConfigurator { + + @Override + public OngoingStubbing mockAndWhenChannel(Connection c) throws IOException { + return when(c.createChannel(1)); + } + + @Override + public OngoingStubbing> mockAndWhenOptional(Connection c) throws IOException { + return when(c.openChannel(1)); + } + + @Override + public Optional open(Connection c) throws IOException { + return c.openChannel(1); + } + } + +} From 3f25e9f13f838fcd1547e8d1d97ff5d931630d81 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Wed, 26 Dec 2018 07:35:55 -0500 Subject: [PATCH 0994/2114] Fix warnings in ClientVersion when amqp-client is relocated --- .../com/rabbitmq/client/impl/ClientVersion.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/ClientVersion.java b/src/main/java/com/rabbitmq/client/impl/ClientVersion.java index 15c6dc6e0a..66dc662b73 100644 --- a/src/main/java/com/rabbitmq/client/impl/ClientVersion.java +++ b/src/main/java/com/rabbitmq/client/impl/ClientVersion.java @@ -28,6 +28,11 @@ public class ClientVersion { private static final Logger LOGGER = LoggerFactory.getLogger(ClientVersion.class); + // We store the version property in an unusual way because relocating the package can rewrite the key in the property + // file, which results in spurious warnings being emitted at start-up. + private static final char[] VERSION_PROPERTY = new char[] {'c', 'o', 'm', '.', 'r', 'a', 'b', 'b', 'i', 't', 'm', 'q', '.', + 'c', 'l', 'i', 'e', 'n', 't', '.', 'v', 'e', 'r', 's', 'i', 'o', 'n'}; + public static final String VERSION; static { @@ -56,10 +61,12 @@ private static final String getVersionFromPropertyFile() throws Exception { inputStream.close(); } } - if (version.getProperty("com.rabbitmq.client.version") == null) { - throw new IllegalStateException("Coulnd't find version property in property file"); + String propertyName = new String(VERSION_PROPERTY); + String versionProperty = version.getProperty(propertyName); + if (versionProperty == null) { + throw new IllegalStateException("Couldn't find version property in property file"); } - return version.getProperty("com.rabbitmq.client.version"); + return versionProperty; } private static final String getVersionFromPackage() { From 4f692fe2e2c00cb0e00a2783edef011a8f9be66e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 2 Jan 2019 15:54:14 +0100 Subject: [PATCH 0995/2114] Add link to issue in comment References #436 --- src/main/java/com/rabbitmq/client/impl/ClientVersion.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/rabbitmq/client/impl/ClientVersion.java b/src/main/java/com/rabbitmq/client/impl/ClientVersion.java index 66dc662b73..dcda1072cd 100644 --- a/src/main/java/com/rabbitmq/client/impl/ClientVersion.java +++ b/src/main/java/com/rabbitmq/client/impl/ClientVersion.java @@ -30,6 +30,7 @@ public class ClientVersion { // We store the version property in an unusual way because relocating the package can rewrite the key in the property // file, which results in spurious warnings being emitted at start-up. + // see https://github.com/rabbitmq/rabbitmq-java-client/issues/436 private static final char[] VERSION_PROPERTY = new char[] {'c', 'o', 'm', '.', 'r', 'a', 'b', 'b', 'i', 't', 'm', 'q', '.', 'c', 'l', 'i', 'e', 'n', 't', '.', 'v', 'e', 'r', 's', 'i', 'o', 'n'}; From 9ef2cf8ece6b63a1010b54ebad996b823c55efbf Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Wed, 26 Dec 2018 07:35:55 -0500 Subject: [PATCH 0996/2114] Fix warnings in ClientVersion when amqp-client is relocated (cherry picked from commit 3f25e9f13f838fcd1547e8d1d97ff5d931630d81) --- .../com/rabbitmq/client/impl/ClientVersion.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/ClientVersion.java b/src/main/java/com/rabbitmq/client/impl/ClientVersion.java index 15c6dc6e0a..66dc662b73 100644 --- a/src/main/java/com/rabbitmq/client/impl/ClientVersion.java +++ b/src/main/java/com/rabbitmq/client/impl/ClientVersion.java @@ -28,6 +28,11 @@ public class ClientVersion { private static final Logger LOGGER = LoggerFactory.getLogger(ClientVersion.class); + // We store the version property in an unusual way because relocating the package can rewrite the key in the property + // file, which results in spurious warnings being emitted at start-up. + private static final char[] VERSION_PROPERTY = new char[] {'c', 'o', 'm', '.', 'r', 'a', 'b', 'b', 'i', 't', 'm', 'q', '.', + 'c', 'l', 'i', 'e', 'n', 't', '.', 'v', 'e', 'r', 's', 'i', 'o', 'n'}; + public static final String VERSION; static { @@ -56,10 +61,12 @@ private static final String getVersionFromPropertyFile() throws Exception { inputStream.close(); } } - if (version.getProperty("com.rabbitmq.client.version") == null) { - throw new IllegalStateException("Coulnd't find version property in property file"); + String propertyName = new String(VERSION_PROPERTY); + String versionProperty = version.getProperty(propertyName); + if (versionProperty == null) { + throw new IllegalStateException("Couldn't find version property in property file"); } - return version.getProperty("com.rabbitmq.client.version"); + return versionProperty; } private static final String getVersionFromPackage() { From 23ed9cde9b7974dc4f33e4356e568a97838ec754 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 2 Jan 2019 15:54:14 +0100 Subject: [PATCH 0997/2114] Add link to issue in comment References #436 (cherry picked from commit 4f692fe2e2c00cb0e00a2783edef011a8f9be66e) --- src/main/java/com/rabbitmq/client/impl/ClientVersion.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/rabbitmq/client/impl/ClientVersion.java b/src/main/java/com/rabbitmq/client/impl/ClientVersion.java index 66dc662b73..dcda1072cd 100644 --- a/src/main/java/com/rabbitmq/client/impl/ClientVersion.java +++ b/src/main/java/com/rabbitmq/client/impl/ClientVersion.java @@ -30,6 +30,7 @@ public class ClientVersion { // We store the version property in an unusual way because relocating the package can rewrite the key in the property // file, which results in spurious warnings being emitted at start-up. + // see https://github.com/rabbitmq/rabbitmq-java-client/issues/436 private static final char[] VERSION_PROPERTY = new char[] {'c', 'o', 'm', '.', 'r', 'a', 'b', 'b', 'i', 't', 'm', 'q', '.', 'c', 'l', 'i', 'e', 'n', 't', '.', 'v', 'e', 'r', 's', 'i', 'o', 'n'}; From cf65f5d1e9d29d4f959ad363a24513fb668bec4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 4 Jan 2019 14:29:02 +0100 Subject: [PATCH 0998/2114] Bump Maven to 3.6.0 --- .mvn/wrapper/maven-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index 6c8c0e080f..a3f9f18723 100755 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -1 +1 @@ -distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.4/apache-maven-3.5.4-bin.zip +distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip From 1a7ff5e9d58cbc8d66f4079a78ed21279c7d170b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 4 Jan 2019 14:29:02 +0100 Subject: [PATCH 0999/2114] Bump Maven to 3.6.0 (cherry picked from commit cf65f5d1e9d29d4f959ad363a24513fb668bec4b) --- .mvn/wrapper/maven-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index 6c8c0e080f..a3f9f18723 100755 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -1 +1 @@ -distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.4/apache-maven-3.5.4-bin.zip +distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip From c3caa3d7a6c51f21650da6f32f6b7a0e5ed991b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 7 Jan 2019 09:32:54 +0100 Subject: [PATCH 1000/2114] Remove performance test These tests are no longer used and do not belong here. They also depend on an old version of commons-cli with some bugs and vulnerabilities. Fixes #438 --- pom.xml | 7 - .../client/test/performance/CLIHelper.java | 81 ---- .../client/test/performance/QosScaling.java | 149 ------- .../test/performance/ScalabilityTest.java | 366 ------------------ .../test/performance/StressManagement.java | 116 ------ 5 files changed, 719 deletions(-) delete mode 100644 src/test/java/com/rabbitmq/client/test/performance/CLIHelper.java delete mode 100644 src/test/java/com/rabbitmq/client/test/performance/QosScaling.java delete mode 100644 src/test/java/com/rabbitmq/client/test/performance/ScalabilityTest.java delete mode 100644 src/test/java/com/rabbitmq/client/test/performance/StressManagement.java diff --git a/pom.xml b/pom.xml index 47f23e1c80..a64a0ea0b3 100644 --- a/pom.xml +++ b/pom.xml @@ -59,7 +59,6 @@ 1.0.2 2.9.6 1.2.3 - 1.1 4.12 3.1.0 2.21.0 @@ -705,12 +704,6 @@ ${jackson.version} true - - commons-cli - commons-cli - ${commons-cli.version} - test - junit junit diff --git a/src/test/java/com/rabbitmq/client/test/performance/CLIHelper.java b/src/test/java/com/rabbitmq/client/test/performance/CLIHelper.java deleted file mode 100644 index 7b316efd7d..0000000000 --- a/src/test/java/com/rabbitmq/client/test/performance/CLIHelper.java +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - - -package com.rabbitmq.client.test.performance; - -import java.util.Iterator; - -import org.apache.commons.cli.CommandLine; -import org.apache.commons.cli.CommandLineParser; -import org.apache.commons.cli.GnuParser; -import org.apache.commons.cli.HelpFormatter; -import org.apache.commons.cli.Option; -import org.apache.commons.cli.Options; -import org.apache.commons.cli.ParseException; - -/** - * Super class for handling repetative CLI stuff - */ -public class CLIHelper { - - private final Options options = new Options(); - - public static CLIHelper defaultHelper() { - Options opts = new Options(); - opts.addOption(new Option( "help", "print this message")); - opts.addOption(new Option("h", "host", true, "broker host")); - opts.addOption(new Option("p", "port", true, "broker port")); - return new CLIHelper(opts); - } - - public CLIHelper(Options opts) { - Iterator it = opts.getOptions().iterator(); - while (it.hasNext()) { - options.addOption((Option) it.next()); - } - } - - public void addOption(Option option) { - options.addOption(option); - } - - public CommandLine parseCommandLine(String [] args) { - CommandLineParser parser = new GnuParser(); - CommandLine commandLine = null; - try { - commandLine = parser.parse(options, args); - } - catch (ParseException e) { - printHelp(options); - throw new RuntimeException("Parsing failed. Reason: " + e.getMessage()); - } - - if (commandLine.hasOption("help")) { - printHelp(options); - return null; - } - return commandLine; - } - - public void printHelp(Options options) { - HelpFormatter formatter = new HelpFormatter(); - formatter.printHelp(getClass().getSimpleName(), options); - } - - public static int getOptionValue(CommandLine cmd, String s, int i) { - return Integer.parseInt(cmd.getOptionValue(s, i + "")); - } -} diff --git a/src/test/java/com/rabbitmq/client/test/performance/QosScaling.java b/src/test/java/com/rabbitmq/client/test/performance/QosScaling.java deleted file mode 100644 index 8e70d9f62b..0000000000 --- a/src/test/java/com/rabbitmq/client/test/performance/QosScaling.java +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - - -package com.rabbitmq.client.test.performance; - -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.ConnectionFactory; -import com.rabbitmq.client.QueueingConsumer; - -import com.rabbitmq.client.test.TestUtils; -import org.apache.commons.cli.CommandLine; -import org.apache.commons.cli.Option; - -import java.io.IOException; -import java.util.List; -import java.util.ArrayList; -import java.util.concurrent.TimeoutException; - -public class QosScaling { - - protected static class Parameters { - final String host; - final int port; - final int messageCount; - final int queueCount; - final int emptyCount; - - public static CommandLine parseCommandLine(String[] args) { - CLIHelper helper = CLIHelper.defaultHelper(); - helper.addOption(new Option("n", "messages", true, "number of messages to send")); - helper.addOption(new Option("q", "queues", true, "number of queues to route messages to")); - helper.addOption(new Option("e", "empty", true, "number of queues to leave empty")); - return helper.parseCommandLine(args); - } - - public Parameters(CommandLine cmd) { - host = cmd.getOptionValue("h", "localhost"); - port = CLIHelper.getOptionValue(cmd, "p", AMQP.PROTOCOL.PORT); - messageCount = CLIHelper.getOptionValue(cmd, "n", 2000); - queueCount = CLIHelper.getOptionValue(cmd, "q", 100); - emptyCount = CLIHelper.getOptionValue(cmd, "e", 0); - } - - public String toString() { - StringBuilder b = new StringBuilder(); - b.append("host=" + host); - b.append(",port=" + port); - b.append(",messages=" + messageCount); - b.append(",queues=" + queueCount); - b.append(",empty=" + emptyCount); - return b.toString(); - } - - } - - protected final Parameters params; - protected final ConnectionFactory connectionFactory = TestUtils.connectionFactory(); - protected Connection connection; - protected Channel channel; - - public QosScaling(Parameters p) { - params = p; - } - - protected List consume(QueueingConsumer c) throws IOException { - for (int i = 0; i < params.emptyCount; i++) { - String queue = channel.queueDeclare().getQueue(); - channel.basicConsume(queue, false, c); - } - List queues = new ArrayList(); - for (int i = 0; i < params.queueCount; i++) { - String queue = channel.queueDeclare().getQueue(); - channel.basicConsume(queue, false, c); - queues.add(queue); - } - return queues; - } - - protected void publish(List queues) throws IOException { - byte[] body = "".getBytes(); - int messagesPerQueue = params.messageCount / queues.size(); - for (String queue : queues) { - for (int i = 0; i < messagesPerQueue; i++) { - channel.basicPublish("", queue, null, body); - } - } - //ensure that all the messages have reached the queues - for (String queue : queues) { - channel.queueDeclarePassive(queue); - } - } - - protected long drain(QueueingConsumer c) throws IOException { - long start = System.nanoTime(); - try { - for (int i = 0; i < params.messageCount; i++) { - long tag = c.nextDelivery().getEnvelope().getDeliveryTag(); - channel.basicAck(tag, false); - } - } catch (InterruptedException e) { - IOException ioe = new IOException(); - ioe.initCause(e); - throw ioe; - } - long finish = System.nanoTime(); - return finish - start; - } - - public long run() throws IOException, TimeoutException { - connectionFactory.setHost(params.host); - connectionFactory.setPort(params.port); - connection = connectionFactory.newConnection(); - channel = connection.createChannel(); - channel.basicQos(1); - QueueingConsumer consumer = new QueueingConsumer(channel); - try { - publish(consume(consumer)); - return drain(consumer); - } finally { - connection.abort(); - } - } - - public static void main(String[] args) throws Exception { - CommandLine cmd = Parameters.parseCommandLine(args); - if (cmd == null) return; - Parameters params = new Parameters(cmd); - System.out.print(params.toString()); - QosScaling test = new QosScaling(params); - long result = test.run(); - System.out.println(" -> " + result / 1000000 + "ms"); - } - -} diff --git a/src/test/java/com/rabbitmq/client/test/performance/ScalabilityTest.java b/src/test/java/com/rabbitmq/client/test/performance/ScalabilityTest.java deleted file mode 100644 index 5445ffcb05..0000000000 --- a/src/test/java/com/rabbitmq/client/test/performance/ScalabilityTest.java +++ /dev/null @@ -1,366 +0,0 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - - -package com.rabbitmq.client.test.performance; - -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.PrintStream; -import java.text.DecimalFormat; -import java.text.NumberFormat; -import java.util.Random; -import java.util.Stack; -import java.util.UUID; -import java.util.Vector; -import java.util.concurrent.CountDownLatch; - -import org.apache.commons.cli.CommandLine; -import org.apache.commons.cli.Option; - -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.ConnectionFactory; -import com.rabbitmq.client.MessageProperties; -import com.rabbitmq.client.ReturnListener; - -/** - * This tests the scalability of the routing tables in two aspects: - * - * 1. The rate of creation and deletion for a fixed level of bindings - * per queue accross varying amounts of queues; - * - * 2. The rate of publishing n messages to an exchange with a fixed - * amount of bindings per queue accross varying amounts of queues. - */ -public class ScalabilityTest { - - private static class Parameters { - String host; - int port; - int messageCount; - int base, maxQueueExp, maxBindingExp, maxExp; - String filePrefix; - - } - - private abstract static class Measurements { - - protected final long[] times; - private final long start; - - public Measurements(final int count) { - times = new long[count]; - start = System.nanoTime(); - } - - public void addDataPoint(final int i) { - times[i] = System.nanoTime() - start; - } - - abstract public float[] analyse(final int base); - - protected static float[] calcOpTimes(final int base, final long[] t) { - float[] r = new float[t.length]; - for (int i = 0; i < t.length; i ++) { - final int amount = pow(base, i); - r[i] = t[i] / (float) amount / 1000; - } - - return r; - } - - } - - private static class CreationMeasurements extends Measurements { - - public CreationMeasurements(final int count) { - super(count); - } - - public float[] analyse(final int base) { - return calcOpTimes(base, times); - } - - } - - private static class DeletionMeasurements extends Measurements { - - public DeletionMeasurements(final int count) { - super(count); - } - - public float[] analyse(final int base) { - final long tmp[] = new long[times.length]; - final long totalTime = times[0]; - int i; - for (i = 0; i < times.length - 1; i++) { - tmp[i] = totalTime - times[i + 1]; - } - tmp[i] = totalTime; - - return calcOpTimes(base, tmp); - } - - } - - private static class Results { - - final float[][] creationTimes; - final float[][] deletionTimes; - final float[][] routingTimes; - - public Results(final int y) { - creationTimes = new float[y][]; - deletionTimes = new float[y][]; - routingTimes = new float[y][]; - } - - public void print(final int base, final String prefix) - throws IOException { - - PrintStream s; - s = open(prefix, "creation"); - print(s, base, creationTimes); - s.close(); - s = open(prefix, "deletion"); - print(s, base, deletionTimes); - s.close(); - s = open(prefix, "routing"); - print(s, base, transpose(routingTimes)); - s.close(); - } - - private static PrintStream open(final String prefix, - final String suffix) - throws IOException { - - return new PrintStream(new FileOutputStream(prefix + suffix + - ".dat")); - } - - private static void print(final PrintStream s, final int base, - final float[][] times) { - for (int y = 0; y < times.length; y++) { - s.println("# level " + pow(base, y)); - for (int x = 0; x < times[y].length; x++) { - s.println(pow(base, x) + " " + format.format(times[y][x])); - } - s.println(); - s.println(); - } - } - - private float[][] transpose(float[][] m) { - Vector> tmp = new Vector>(); - for (int i = 0; i < m[0].length; i++) { - tmp.addElement(new Vector()); - } - for (int i = 0; i < m.length; i++) { - for (int j = 0; j < m[i].length; j++) { - Vector v = tmp.get(j); - v.addElement(m[i][j]); - } - } - float[][] r = new float[tmp.size()][]; - for (int i = 0; i < tmp.size(); i++) { - Vector v = tmp.get(i); - float[] vr = new float[v.size()]; - for (int j = 0; j < v.size(); j++) { - vr[j] = v.get(j); - } - r[i] = vr; - } - return r; - } - } - - private static final NumberFormat format = new DecimalFormat("0.00"); - - private final Parameters params; - - public ScalabilityTest(Parameters p) { - params = p; - } - - public static void main(String[] args) throws Exception { - Parameters params = parseArgs(args); - if (params == null) return; - - ScalabilityTest test = new ScalabilityTest(params); - Results r = test.run(); - if (params.filePrefix != null) - r.print(params.base, params.filePrefix); - } - - - public Results run() throws Exception{ - Connection con = new ConnectionFactory(){{setHost(params.host); setPort(params.port);}}.newConnection(); - Channel channel = con.createChannel(); - - Results r = new Results(params.maxBindingExp); - - for (int y = 0; y < params.maxBindingExp; y++) { - - final int maxBindings = pow(params.base, y); - - String[] routingKeys = new String[maxBindings]; - for (int b = 0; b < maxBindings; b++) { - routingKeys[b] = UUID.randomUUID().toString(); - } - - Stack queues = new Stack(); - - int maxQueueExp = Math.min(params.maxQueueExp, params.maxExp - y); - - System.out.println("---------------------------------"); - System.out.println("| bindings = " + maxBindings + ", messages = " + params.messageCount); - - System.out.println("| Routing"); - - int q = 0; - - // create queues & bindings, time routing - Measurements creation = new CreationMeasurements(maxQueueExp); - float routingTimes[] = new float[maxQueueExp]; - for (int x = 0; x < maxQueueExp; x++) { - - final int maxQueues = pow(params.base, x); - - for (; q < maxQueues; q++) { - AMQP.Queue.DeclareOk ok = channel.queueDeclare(); - queues.push(ok.getQueue()); - for (int b = 0; b < maxBindings; b++) { - channel.queueBind(ok.getQueue(), "amq.direct", routingKeys[b]); - } - } - - creation.addDataPoint(x); - - float routingTime = timeRouting(channel, routingKeys); - routingTimes[x] = routingTime; - printTime(params.base, x, routingTime); - } - - r.routingTimes[y] = routingTimes; - float[] creationTimes = creation.analyse(params.base); - r.creationTimes[y] = creationTimes; - System.out.println("| Creating"); - printTimes(params.base, creationTimes); - - // delete queues & bindings - Measurements deletion = new DeletionMeasurements(maxQueueExp); - for (int x = maxQueueExp - 1; x >= 0; x--) { - - final int maxQueues = (x == 0) ? 0 : pow(params.base, x - 1); - - for (; q > maxQueues; q--) { - channel.queueDelete(queues.pop()); - } - - deletion.addDataPoint(x); - } - - float[] deletionTimes = deletion.analyse(params.base); - r.deletionTimes[y] = deletionTimes; - System.out.println("| Deleting"); - printTimes(params.base, deletionTimes); - } - - channel.close(); - con.close(); - - return r; - } - - private float timeRouting(Channel channel, String[] routingKeys) - throws IOException, InterruptedException { - - boolean mandatory = true; - boolean immdediate = true; - final CountDownLatch latch = new CountDownLatch(params.messageCount); - channel.addReturnListener(new ReturnListener() { - public void handleReturn(int replyCode, String replyText, - String exchange, String routingKey, - AMQP.BasicProperties properties, byte[] body) throws IOException { - latch.countDown(); - } - }); - - final long start = System.nanoTime(); - - // route some messages - Random r = new Random(); - int size = routingKeys.length; - for (int n = 0; n < params.messageCount; n ++) { - String key = routingKeys[r.nextInt(size)]; - channel.basicPublish("amq.direct", key, true, false, - MessageProperties.MINIMAL_BASIC, null); - } - - // wait for the returns to come back - latch.await(); - - // Compute the roundtrip time - final long finish = System.nanoTime(); - final long wallclock = finish - start; - return (params.messageCount == 0) ? (float)0.0 : wallclock / (float) params.messageCount / 1000; - } - - private static Parameters parseArgs(String [] args) { - CLIHelper helper = CLIHelper.defaultHelper(); - - helper.addOption(new Option("n", "messages", true, "number of messages to send")); - helper.addOption(new Option("b", "base", true, "base for exponential scaling")); - helper.addOption(new Option("x", "q-max-exp", true, "maximum queue count exponent")); - helper.addOption(new Option("y", "b-max-exp", true, "maximum per-queue binding count exponent")); - helper.addOption(new Option("c", "c-max-exp", true, "combined maximum exponent")); - helper.addOption(new Option("f", "file", true, "result files prefix; defaults to no file output")); - - CommandLine cmd = helper.parseCommandLine(args); - if (null == cmd) return null; - - Parameters params = new Parameters(); - params.host = cmd.getOptionValue("h", "0.0.0.0"); - params.port = CLIHelper.getOptionValue(cmd, "p", AMQP.PROTOCOL.PORT); - params.messageCount = CLIHelper.getOptionValue(cmd, "n", 100); - params.base = CLIHelper.getOptionValue(cmd, "b", 10); - params.maxQueueExp = CLIHelper.getOptionValue(cmd, "x", 4); - params.maxBindingExp = CLIHelper.getOptionValue(cmd, "y", 4); - params.maxExp = CLIHelper.getOptionValue(cmd, "c", Math.max(params.maxQueueExp, params.maxBindingExp)); - params.filePrefix = cmd.getOptionValue("f", null); - - return params; - } - - private static int pow(int x, int y) { - int r = 1; - for( int i = 0; i < y; i++ ) r *= x; - return r; - } - - private static void printTimes(int base, float[] times) { - for (int i = 0; i < times.length; i ++) { - printTime(base, i, times[i]); - } - } - - private static void printTime(int base, int exp, float v) { - System.out.println("| " + pow(base, exp) + - " -> " + format.format(v) + " us/op"); - } - -} diff --git a/src/test/java/com/rabbitmq/client/test/performance/StressManagement.java b/src/test/java/com/rabbitmq/client/test/performance/StressManagement.java deleted file mode 100644 index 32937c07ad..0000000000 --- a/src/test/java/com/rabbitmq/client/test/performance/StressManagement.java +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - -package com.rabbitmq.client.test.performance; - -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.ConnectionFactory; -import com.rabbitmq.client.MessageProperties; -import org.apache.commons.cli.CommandLine; -import org.apache.commons.cli.Option; - -import java.io.IOException; -import java.util.concurrent.TimeoutException; - -public class StressManagement { - protected static class Parameters { - final String host; - final int port; - final int queueCount; - final int channelCount; - - public static CommandLine parseCommandLine(String[] args) { - CLIHelper helper = CLIHelper.defaultHelper(); - helper.addOption(new Option("q", "queues", true, "number of queues")); - helper.addOption(new Option("c", "channels", true, "number of channels")); - return helper.parseCommandLine(args); - } - - public Parameters(CommandLine cmd) { - host = cmd.getOptionValue("h", "localhost"); - port = CLIHelper.getOptionValue(cmd, "p", AMQP.PROTOCOL.PORT); - queueCount = CLIHelper.getOptionValue(cmd, "q", 5000); - channelCount = CLIHelper.getOptionValue(cmd, "c", 100); - } - - public String toString() { - StringBuilder b = new StringBuilder(); - b.append("host=" + host); - b.append(",port=" + port); - b.append(",queues=" + queueCount); - b.append(",channels=" + channelCount); - return b.toString(); - } - - } - - protected final Parameters params; - protected final ConnectionFactory connectionFactory = - new ConnectionFactory(); - protected Connection connection; - protected Channel publishChannel; - protected Channel[] channels; - - public StressManagement(Parameters p) { - params = p; - } - - public long run() throws IOException, TimeoutException { - connectionFactory.setHost(params.host); - connectionFactory.setPort(params.port); - connection = connectionFactory.newConnection(); - publishChannel = connection.createChannel(); - - System.out.println("Declaring..."); - - channels = new Channel[params.channelCount]; - for (int i = 0; i < params.channelCount; i++) { - channels[i] = connection.createChannel(); - } - - for (int i = 0; i < params.queueCount; i++) { - publishChannel.queueDeclare("queue-" + i, false, true, false, null); - publishChannel.queueBind("queue-" + i, "amq.fanout", ""); - } - - System.out.println("Declaration complete, running..."); - - while (true) { - for (int i = 0; i < params.channelCount; i++) { - publishChannel.basicPublish("amq.fanout", "", MessageProperties.BASIC, "".getBytes()); - for (int j = 0; j < params.queueCount; j++) { - while (channels[i].basicGet("queue-" + j, true) == null) { - try { - Thread.sleep(10); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - } - } - } - } - - public static void main(String[] args) throws Exception { - CommandLine cmd = Parameters.parseCommandLine(args); - if (cmd == null) return; - Parameters params = new Parameters(cmd); - System.out.println(params.toString()); - StressManagement test = new StressManagement(params); - test.run(); - } -} From 5508d2cdb34e4b158b186a14054dda37a05f3d6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 7 Jan 2019 09:32:54 +0100 Subject: [PATCH 1001/2114] Remove performance test These tests are no longer used and do not belong here. They also depend on an old version of commons-cli with some bugs and vulnerabilities. Fixes #438 (cherry picked from commit c3caa3d7a6c51f21650da6f32f6b7a0e5ed991b5) --- pom.xml | 7 - .../client/test/performance/CLIHelper.java | 81 ---- .../client/test/performance/QosScaling.java | 149 ------- .../test/performance/ScalabilityTest.java | 366 ------------------ .../test/performance/StressManagement.java | 116 ------ 5 files changed, 719 deletions(-) delete mode 100644 src/test/java/com/rabbitmq/client/test/performance/CLIHelper.java delete mode 100644 src/test/java/com/rabbitmq/client/test/performance/QosScaling.java delete mode 100644 src/test/java/com/rabbitmq/client/test/performance/ScalabilityTest.java delete mode 100644 src/test/java/com/rabbitmq/client/test/performance/StressManagement.java diff --git a/pom.xml b/pom.xml index 900f0ced38..f43a4abace 100644 --- a/pom.xml +++ b/pom.xml @@ -59,7 +59,6 @@ 1.0.2 2.9.6 1.2.3 - 1.1 4.12 3.1.0 2.21.0 @@ -705,12 +704,6 @@ ${jackson.version} true - - commons-cli - commons-cli - ${commons-cli.version} - test - junit junit diff --git a/src/test/java/com/rabbitmq/client/test/performance/CLIHelper.java b/src/test/java/com/rabbitmq/client/test/performance/CLIHelper.java deleted file mode 100644 index 7b316efd7d..0000000000 --- a/src/test/java/com/rabbitmq/client/test/performance/CLIHelper.java +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - - -package com.rabbitmq.client.test.performance; - -import java.util.Iterator; - -import org.apache.commons.cli.CommandLine; -import org.apache.commons.cli.CommandLineParser; -import org.apache.commons.cli.GnuParser; -import org.apache.commons.cli.HelpFormatter; -import org.apache.commons.cli.Option; -import org.apache.commons.cli.Options; -import org.apache.commons.cli.ParseException; - -/** - * Super class for handling repetative CLI stuff - */ -public class CLIHelper { - - private final Options options = new Options(); - - public static CLIHelper defaultHelper() { - Options opts = new Options(); - opts.addOption(new Option( "help", "print this message")); - opts.addOption(new Option("h", "host", true, "broker host")); - opts.addOption(new Option("p", "port", true, "broker port")); - return new CLIHelper(opts); - } - - public CLIHelper(Options opts) { - Iterator it = opts.getOptions().iterator(); - while (it.hasNext()) { - options.addOption((Option) it.next()); - } - } - - public void addOption(Option option) { - options.addOption(option); - } - - public CommandLine parseCommandLine(String [] args) { - CommandLineParser parser = new GnuParser(); - CommandLine commandLine = null; - try { - commandLine = parser.parse(options, args); - } - catch (ParseException e) { - printHelp(options); - throw new RuntimeException("Parsing failed. Reason: " + e.getMessage()); - } - - if (commandLine.hasOption("help")) { - printHelp(options); - return null; - } - return commandLine; - } - - public void printHelp(Options options) { - HelpFormatter formatter = new HelpFormatter(); - formatter.printHelp(getClass().getSimpleName(), options); - } - - public static int getOptionValue(CommandLine cmd, String s, int i) { - return Integer.parseInt(cmd.getOptionValue(s, i + "")); - } -} diff --git a/src/test/java/com/rabbitmq/client/test/performance/QosScaling.java b/src/test/java/com/rabbitmq/client/test/performance/QosScaling.java deleted file mode 100644 index 8e70d9f62b..0000000000 --- a/src/test/java/com/rabbitmq/client/test/performance/QosScaling.java +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - - -package com.rabbitmq.client.test.performance; - -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.ConnectionFactory; -import com.rabbitmq.client.QueueingConsumer; - -import com.rabbitmq.client.test.TestUtils; -import org.apache.commons.cli.CommandLine; -import org.apache.commons.cli.Option; - -import java.io.IOException; -import java.util.List; -import java.util.ArrayList; -import java.util.concurrent.TimeoutException; - -public class QosScaling { - - protected static class Parameters { - final String host; - final int port; - final int messageCount; - final int queueCount; - final int emptyCount; - - public static CommandLine parseCommandLine(String[] args) { - CLIHelper helper = CLIHelper.defaultHelper(); - helper.addOption(new Option("n", "messages", true, "number of messages to send")); - helper.addOption(new Option("q", "queues", true, "number of queues to route messages to")); - helper.addOption(new Option("e", "empty", true, "number of queues to leave empty")); - return helper.parseCommandLine(args); - } - - public Parameters(CommandLine cmd) { - host = cmd.getOptionValue("h", "localhost"); - port = CLIHelper.getOptionValue(cmd, "p", AMQP.PROTOCOL.PORT); - messageCount = CLIHelper.getOptionValue(cmd, "n", 2000); - queueCount = CLIHelper.getOptionValue(cmd, "q", 100); - emptyCount = CLIHelper.getOptionValue(cmd, "e", 0); - } - - public String toString() { - StringBuilder b = new StringBuilder(); - b.append("host=" + host); - b.append(",port=" + port); - b.append(",messages=" + messageCount); - b.append(",queues=" + queueCount); - b.append(",empty=" + emptyCount); - return b.toString(); - } - - } - - protected final Parameters params; - protected final ConnectionFactory connectionFactory = TestUtils.connectionFactory(); - protected Connection connection; - protected Channel channel; - - public QosScaling(Parameters p) { - params = p; - } - - protected List consume(QueueingConsumer c) throws IOException { - for (int i = 0; i < params.emptyCount; i++) { - String queue = channel.queueDeclare().getQueue(); - channel.basicConsume(queue, false, c); - } - List queues = new ArrayList(); - for (int i = 0; i < params.queueCount; i++) { - String queue = channel.queueDeclare().getQueue(); - channel.basicConsume(queue, false, c); - queues.add(queue); - } - return queues; - } - - protected void publish(List queues) throws IOException { - byte[] body = "".getBytes(); - int messagesPerQueue = params.messageCount / queues.size(); - for (String queue : queues) { - for (int i = 0; i < messagesPerQueue; i++) { - channel.basicPublish("", queue, null, body); - } - } - //ensure that all the messages have reached the queues - for (String queue : queues) { - channel.queueDeclarePassive(queue); - } - } - - protected long drain(QueueingConsumer c) throws IOException { - long start = System.nanoTime(); - try { - for (int i = 0; i < params.messageCount; i++) { - long tag = c.nextDelivery().getEnvelope().getDeliveryTag(); - channel.basicAck(tag, false); - } - } catch (InterruptedException e) { - IOException ioe = new IOException(); - ioe.initCause(e); - throw ioe; - } - long finish = System.nanoTime(); - return finish - start; - } - - public long run() throws IOException, TimeoutException { - connectionFactory.setHost(params.host); - connectionFactory.setPort(params.port); - connection = connectionFactory.newConnection(); - channel = connection.createChannel(); - channel.basicQos(1); - QueueingConsumer consumer = new QueueingConsumer(channel); - try { - publish(consume(consumer)); - return drain(consumer); - } finally { - connection.abort(); - } - } - - public static void main(String[] args) throws Exception { - CommandLine cmd = Parameters.parseCommandLine(args); - if (cmd == null) return; - Parameters params = new Parameters(cmd); - System.out.print(params.toString()); - QosScaling test = new QosScaling(params); - long result = test.run(); - System.out.println(" -> " + result / 1000000 + "ms"); - } - -} diff --git a/src/test/java/com/rabbitmq/client/test/performance/ScalabilityTest.java b/src/test/java/com/rabbitmq/client/test/performance/ScalabilityTest.java deleted file mode 100644 index 5445ffcb05..0000000000 --- a/src/test/java/com/rabbitmq/client/test/performance/ScalabilityTest.java +++ /dev/null @@ -1,366 +0,0 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - - -package com.rabbitmq.client.test.performance; - -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.PrintStream; -import java.text.DecimalFormat; -import java.text.NumberFormat; -import java.util.Random; -import java.util.Stack; -import java.util.UUID; -import java.util.Vector; -import java.util.concurrent.CountDownLatch; - -import org.apache.commons.cli.CommandLine; -import org.apache.commons.cli.Option; - -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.ConnectionFactory; -import com.rabbitmq.client.MessageProperties; -import com.rabbitmq.client.ReturnListener; - -/** - * This tests the scalability of the routing tables in two aspects: - * - * 1. The rate of creation and deletion for a fixed level of bindings - * per queue accross varying amounts of queues; - * - * 2. The rate of publishing n messages to an exchange with a fixed - * amount of bindings per queue accross varying amounts of queues. - */ -public class ScalabilityTest { - - private static class Parameters { - String host; - int port; - int messageCount; - int base, maxQueueExp, maxBindingExp, maxExp; - String filePrefix; - - } - - private abstract static class Measurements { - - protected final long[] times; - private final long start; - - public Measurements(final int count) { - times = new long[count]; - start = System.nanoTime(); - } - - public void addDataPoint(final int i) { - times[i] = System.nanoTime() - start; - } - - abstract public float[] analyse(final int base); - - protected static float[] calcOpTimes(final int base, final long[] t) { - float[] r = new float[t.length]; - for (int i = 0; i < t.length; i ++) { - final int amount = pow(base, i); - r[i] = t[i] / (float) amount / 1000; - } - - return r; - } - - } - - private static class CreationMeasurements extends Measurements { - - public CreationMeasurements(final int count) { - super(count); - } - - public float[] analyse(final int base) { - return calcOpTimes(base, times); - } - - } - - private static class DeletionMeasurements extends Measurements { - - public DeletionMeasurements(final int count) { - super(count); - } - - public float[] analyse(final int base) { - final long tmp[] = new long[times.length]; - final long totalTime = times[0]; - int i; - for (i = 0; i < times.length - 1; i++) { - tmp[i] = totalTime - times[i + 1]; - } - tmp[i] = totalTime; - - return calcOpTimes(base, tmp); - } - - } - - private static class Results { - - final float[][] creationTimes; - final float[][] deletionTimes; - final float[][] routingTimes; - - public Results(final int y) { - creationTimes = new float[y][]; - deletionTimes = new float[y][]; - routingTimes = new float[y][]; - } - - public void print(final int base, final String prefix) - throws IOException { - - PrintStream s; - s = open(prefix, "creation"); - print(s, base, creationTimes); - s.close(); - s = open(prefix, "deletion"); - print(s, base, deletionTimes); - s.close(); - s = open(prefix, "routing"); - print(s, base, transpose(routingTimes)); - s.close(); - } - - private static PrintStream open(final String prefix, - final String suffix) - throws IOException { - - return new PrintStream(new FileOutputStream(prefix + suffix + - ".dat")); - } - - private static void print(final PrintStream s, final int base, - final float[][] times) { - for (int y = 0; y < times.length; y++) { - s.println("# level " + pow(base, y)); - for (int x = 0; x < times[y].length; x++) { - s.println(pow(base, x) + " " + format.format(times[y][x])); - } - s.println(); - s.println(); - } - } - - private float[][] transpose(float[][] m) { - Vector> tmp = new Vector>(); - for (int i = 0; i < m[0].length; i++) { - tmp.addElement(new Vector()); - } - for (int i = 0; i < m.length; i++) { - for (int j = 0; j < m[i].length; j++) { - Vector v = tmp.get(j); - v.addElement(m[i][j]); - } - } - float[][] r = new float[tmp.size()][]; - for (int i = 0; i < tmp.size(); i++) { - Vector v = tmp.get(i); - float[] vr = new float[v.size()]; - for (int j = 0; j < v.size(); j++) { - vr[j] = v.get(j); - } - r[i] = vr; - } - return r; - } - } - - private static final NumberFormat format = new DecimalFormat("0.00"); - - private final Parameters params; - - public ScalabilityTest(Parameters p) { - params = p; - } - - public static void main(String[] args) throws Exception { - Parameters params = parseArgs(args); - if (params == null) return; - - ScalabilityTest test = new ScalabilityTest(params); - Results r = test.run(); - if (params.filePrefix != null) - r.print(params.base, params.filePrefix); - } - - - public Results run() throws Exception{ - Connection con = new ConnectionFactory(){{setHost(params.host); setPort(params.port);}}.newConnection(); - Channel channel = con.createChannel(); - - Results r = new Results(params.maxBindingExp); - - for (int y = 0; y < params.maxBindingExp; y++) { - - final int maxBindings = pow(params.base, y); - - String[] routingKeys = new String[maxBindings]; - for (int b = 0; b < maxBindings; b++) { - routingKeys[b] = UUID.randomUUID().toString(); - } - - Stack queues = new Stack(); - - int maxQueueExp = Math.min(params.maxQueueExp, params.maxExp - y); - - System.out.println("---------------------------------"); - System.out.println("| bindings = " + maxBindings + ", messages = " + params.messageCount); - - System.out.println("| Routing"); - - int q = 0; - - // create queues & bindings, time routing - Measurements creation = new CreationMeasurements(maxQueueExp); - float routingTimes[] = new float[maxQueueExp]; - for (int x = 0; x < maxQueueExp; x++) { - - final int maxQueues = pow(params.base, x); - - for (; q < maxQueues; q++) { - AMQP.Queue.DeclareOk ok = channel.queueDeclare(); - queues.push(ok.getQueue()); - for (int b = 0; b < maxBindings; b++) { - channel.queueBind(ok.getQueue(), "amq.direct", routingKeys[b]); - } - } - - creation.addDataPoint(x); - - float routingTime = timeRouting(channel, routingKeys); - routingTimes[x] = routingTime; - printTime(params.base, x, routingTime); - } - - r.routingTimes[y] = routingTimes; - float[] creationTimes = creation.analyse(params.base); - r.creationTimes[y] = creationTimes; - System.out.println("| Creating"); - printTimes(params.base, creationTimes); - - // delete queues & bindings - Measurements deletion = new DeletionMeasurements(maxQueueExp); - for (int x = maxQueueExp - 1; x >= 0; x--) { - - final int maxQueues = (x == 0) ? 0 : pow(params.base, x - 1); - - for (; q > maxQueues; q--) { - channel.queueDelete(queues.pop()); - } - - deletion.addDataPoint(x); - } - - float[] deletionTimes = deletion.analyse(params.base); - r.deletionTimes[y] = deletionTimes; - System.out.println("| Deleting"); - printTimes(params.base, deletionTimes); - } - - channel.close(); - con.close(); - - return r; - } - - private float timeRouting(Channel channel, String[] routingKeys) - throws IOException, InterruptedException { - - boolean mandatory = true; - boolean immdediate = true; - final CountDownLatch latch = new CountDownLatch(params.messageCount); - channel.addReturnListener(new ReturnListener() { - public void handleReturn(int replyCode, String replyText, - String exchange, String routingKey, - AMQP.BasicProperties properties, byte[] body) throws IOException { - latch.countDown(); - } - }); - - final long start = System.nanoTime(); - - // route some messages - Random r = new Random(); - int size = routingKeys.length; - for (int n = 0; n < params.messageCount; n ++) { - String key = routingKeys[r.nextInt(size)]; - channel.basicPublish("amq.direct", key, true, false, - MessageProperties.MINIMAL_BASIC, null); - } - - // wait for the returns to come back - latch.await(); - - // Compute the roundtrip time - final long finish = System.nanoTime(); - final long wallclock = finish - start; - return (params.messageCount == 0) ? (float)0.0 : wallclock / (float) params.messageCount / 1000; - } - - private static Parameters parseArgs(String [] args) { - CLIHelper helper = CLIHelper.defaultHelper(); - - helper.addOption(new Option("n", "messages", true, "number of messages to send")); - helper.addOption(new Option("b", "base", true, "base for exponential scaling")); - helper.addOption(new Option("x", "q-max-exp", true, "maximum queue count exponent")); - helper.addOption(new Option("y", "b-max-exp", true, "maximum per-queue binding count exponent")); - helper.addOption(new Option("c", "c-max-exp", true, "combined maximum exponent")); - helper.addOption(new Option("f", "file", true, "result files prefix; defaults to no file output")); - - CommandLine cmd = helper.parseCommandLine(args); - if (null == cmd) return null; - - Parameters params = new Parameters(); - params.host = cmd.getOptionValue("h", "0.0.0.0"); - params.port = CLIHelper.getOptionValue(cmd, "p", AMQP.PROTOCOL.PORT); - params.messageCount = CLIHelper.getOptionValue(cmd, "n", 100); - params.base = CLIHelper.getOptionValue(cmd, "b", 10); - params.maxQueueExp = CLIHelper.getOptionValue(cmd, "x", 4); - params.maxBindingExp = CLIHelper.getOptionValue(cmd, "y", 4); - params.maxExp = CLIHelper.getOptionValue(cmd, "c", Math.max(params.maxQueueExp, params.maxBindingExp)); - params.filePrefix = cmd.getOptionValue("f", null); - - return params; - } - - private static int pow(int x, int y) { - int r = 1; - for( int i = 0; i < y; i++ ) r *= x; - return r; - } - - private static void printTimes(int base, float[] times) { - for (int i = 0; i < times.length; i ++) { - printTime(base, i, times[i]); - } - } - - private static void printTime(int base, int exp, float v) { - System.out.println("| " + pow(base, exp) + - " -> " + format.format(v) + " us/op"); - } - -} diff --git a/src/test/java/com/rabbitmq/client/test/performance/StressManagement.java b/src/test/java/com/rabbitmq/client/test/performance/StressManagement.java deleted file mode 100644 index 32937c07ad..0000000000 --- a/src/test/java/com/rabbitmq/client/test/performance/StressManagement.java +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - -package com.rabbitmq.client.test.performance; - -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.ConnectionFactory; -import com.rabbitmq.client.MessageProperties; -import org.apache.commons.cli.CommandLine; -import org.apache.commons.cli.Option; - -import java.io.IOException; -import java.util.concurrent.TimeoutException; - -public class StressManagement { - protected static class Parameters { - final String host; - final int port; - final int queueCount; - final int channelCount; - - public static CommandLine parseCommandLine(String[] args) { - CLIHelper helper = CLIHelper.defaultHelper(); - helper.addOption(new Option("q", "queues", true, "number of queues")); - helper.addOption(new Option("c", "channels", true, "number of channels")); - return helper.parseCommandLine(args); - } - - public Parameters(CommandLine cmd) { - host = cmd.getOptionValue("h", "localhost"); - port = CLIHelper.getOptionValue(cmd, "p", AMQP.PROTOCOL.PORT); - queueCount = CLIHelper.getOptionValue(cmd, "q", 5000); - channelCount = CLIHelper.getOptionValue(cmd, "c", 100); - } - - public String toString() { - StringBuilder b = new StringBuilder(); - b.append("host=" + host); - b.append(",port=" + port); - b.append(",queues=" + queueCount); - b.append(",channels=" + channelCount); - return b.toString(); - } - - } - - protected final Parameters params; - protected final ConnectionFactory connectionFactory = - new ConnectionFactory(); - protected Connection connection; - protected Channel publishChannel; - protected Channel[] channels; - - public StressManagement(Parameters p) { - params = p; - } - - public long run() throws IOException, TimeoutException { - connectionFactory.setHost(params.host); - connectionFactory.setPort(params.port); - connection = connectionFactory.newConnection(); - publishChannel = connection.createChannel(); - - System.out.println("Declaring..."); - - channels = new Channel[params.channelCount]; - for (int i = 0; i < params.channelCount; i++) { - channels[i] = connection.createChannel(); - } - - for (int i = 0; i < params.queueCount; i++) { - publishChannel.queueDeclare("queue-" + i, false, true, false, null); - publishChannel.queueBind("queue-" + i, "amq.fanout", ""); - } - - System.out.println("Declaration complete, running..."); - - while (true) { - for (int i = 0; i < params.channelCount; i++) { - publishChannel.basicPublish("amq.fanout", "", MessageProperties.BASIC, "".getBytes()); - for (int j = 0; j < params.queueCount; j++) { - while (channels[i].basicGet("queue-" + j, true) == null) { - try { - Thread.sleep(10); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - } - } - } - } - - public static void main(String[] args) throws Exception { - CommandLine cmd = Parameters.parseCommandLine(args); - if (cmd == null) return; - Parameters params = new Parameters(cmd); - System.out.println(params.toString()); - StressManagement test = new StressManagement(params); - test.run(); - } -} From 07a09aebeada69ed3fe123b5d8d021f6112ec141 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Sun, 13 Jan 2019 05:12:30 +0300 Subject: [PATCH 1002/2114] .travis.yml: sync Erlang and Elixir versions, require Erlang/OTP 20.3 --- .travis.yml | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000000..1e9e2a0485 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,57 @@ +# vim:sw=2:et: + +dist: xenial +sudo: false +language: erlang +notifications: + email: + recipients: + - alerts@rabbitmq.com + on_success: never + on_failure: always +addons: + apt: + packages: + - awscli +cache: + apt: true +env: + global: + - secure: Tu26VJ9BsXxL20xxwWk4cbCkZyqyxYmNpSSqco5r3FLeU5hk5Vkk+s2BareRvqKhKHFlvyxu8GwsKtajMvsieP6y5J99gSeub6fDOIskPz61bo0aKA9nbDuBFSG1Z5wgXx1XRo0yDatLxXCXe3FbThRsylG7XNjtRaru1/lwuVxfxPtBGQ1opvQX71sST3GYSPoBYR+JlcVpU+uDHMAzsP8J0m5rEpxcl821aTMk3iz90hBQMsoLTBmSQePPcNqOA/1OH75VfjuXR8JBXHvA9njrUBrsyxgHf2uOh3jAXdIrHZwZg/17+y7gNVqByfx/UpGb8XEpVkncg/cRyVIHMk7/gFCZkeVC1QkIN5+EPiGLF7u32x9QaT7Zqz57iLh3IJzED2dj12qWaeX8QypF1K1r5qq4pRrN6iEZx76stpZbyFT4XnExHRdzPuouy7yz1gDHF0HOxbNLowzc/jk7tuTp+qmDSR5tRvegAIH3TONegxXyB7smdbvdI6MCN5/GP2bGK7HiqYWCmTGHtJwgxBKc5XoV8ZjpXfKxG98WbK5RsSP1miRnmxSbxaV0Gai1hfFlanJFFxTA9584O+NVRXNNFMfnnt20Ts6OwoXTcJ/boIPjF5Mcm0eJ4nz4R18TArXE4B5S4pTk3eQkG1ACDigkYZ3fc6ws4cWrt8BZASI= + - secure: fNEx9OXi2UisiYu0FiHJpV9+vWLB9DIUAIKG24GfUHVgZqFQOInBf5fEYrjlVgm5zNezSBS3hFNHXd/EXJF8KNgbf6mI0z4h4RyyQY98N+78tWvINoIawEeYpgC6NTI52MdaCfV+fTVWhiL0uP7mqWhLmll2bKXIy6HA6I9PnmiQSloNe64vUPF+UsVZHzzeabK4DR2VdI3h+BGXzOY9FG8Kt2voiXOLd2RFpVeN86FDTp+uVZY/K9e/MsktoK+XaZZ4qMAgm6lB32LVkzl3KA9ki6y6BY7le1m2c90hxAtBJGWZptkMb+VL0Fem39nEBnLjE0a0vIddp32PLJQmv6eopMfLay5BIkwtkRwv3P0uCwYd0bgYQSHF/gdTCcK1nr7fMhkQveBh6vmnbhrca7OeQRHz08+jo6EquUgNQZKmTZPWXQn9lS9mU/0EDLJJhn4KhJezGw6DcAAqB0KqmQedxtHMUT87by7LzhINwKZnm4y5WKA/W/zLI6dNqvIgc5C6UJh0EVgxa13GRmrnGmttV1dtLRQhiMJCbJykaekjPMULUmli0RbFz7bSFqFqEUsF+wwovyD+Y6D8KGOJdvvEYPdPIFpRPnhGUvH86JzsFdVKNJBicGI9LpCtlXlWNRbQIQ8uV5ze2HhxSJhtM6e6dB4d9yzpp6a81uR77bk= + +otp_release: + - "20.3" + - "21.2" + +before_script: + - elixir --version + # The checkout made by Travis is a "detached HEAD" and branches + # information is missing. Our Erlang.mk's git_rmq fetch method relies + # on it, so we need to restore it. + # + # We simply fetch master and, if it exists, v3.7.x branches. A branch + # is created, pointing to the detached HEAD. + - | + git checkout -B "${TRAVIS_TAG:-${TRAVIS_BRANCH}}" + git remote add upstream https://github.com/$TRAVIS_REPO_SLUG.git + git fetch upstream v3.7.x:v3.7.x || : + git fetch upstream master:master || : + +script: + - make xref + - make tests + +after_failure: + - | + cd "$TRAVIS_BUILD_DIR" + if test -d logs && test "$AWS_ACCESS_KEY_ID" && test "$AWS_SECRET_ACCESS_KEY"; then + archive_name="$(basename "$TRAVIS_REPO_SLUG")-$TRAVIS_JOB_NUMBER" + + tar -c --transform "s/^logs/${archive_name}/" -f - logs | \ + xz > "${archive_name}.tar.xz" + + aws s3 cp "${archive_name}.tar.xz" s3://server-release-pipeline/travis-ci-logs/ \ + --region eu-west-1 \ + --acl public-read + fi From 618bdb841219bddd0a7b679b80269fc511f7e4a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 14 Jan 2019 17:47:08 +0100 Subject: [PATCH 1003/2114] Set current year in copyright --- src/main/java/com/rabbitmq/client/impl/AMQConnection.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index 25b18d0750..d65008d96a 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -35,7 +35,7 @@ import java.util.concurrent.atomic.AtomicBoolean; final class Copyright { - final static String COPYRIGHT="Copyright (c) 2007-2018 Pivotal Software, Inc."; + final static String COPYRIGHT="Copyright (c) 2007-2019 Pivotal Software, Inc."; final static String LICENSE="Licensed under the MPL. See http://www.rabbitmq.com/"; } From abcefaff0cc870f685485991e6b0756ff866d8df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 14 Jan 2019 17:47:08 +0100 Subject: [PATCH 1004/2114] Set current year in copyright (cherry picked from commit 618bdb841219bddd0a7b679b80269fc511f7e4a6) --- src/main/java/com/rabbitmq/client/impl/AMQConnection.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index 25b18d0750..d65008d96a 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -35,7 +35,7 @@ import java.util.concurrent.atomic.AtomicBoolean; final class Copyright { - final static String COPYRIGHT="Copyright (c) 2007-2018 Pivotal Software, Inc."; + final static String COPYRIGHT="Copyright (c) 2007-2019 Pivotal Software, Inc."; final static String LICENSE="Licensed under the MPL. See http://www.rabbitmq.com/"; } From 13c786d497bbad29fc3b23c7ce9735c786004da1 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Thu, 17 Jan 2019 18:50:07 +0300 Subject: [PATCH 1005/2114] Bump Jackson dependency to 2.9.8 Addresses a number of CVEs that affect versions from 2.9.0 through 2.9.7, inclusive. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a64a0ea0b3..fa15668cea 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,7 @@ 1.7.25 3.2.6 1.0.2 - 2.9.6 + 2.9.8 1.2.3 4.12 3.1.0 From eed81cb2023f04c2094b4a243b295b8c635a5607 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Thu, 17 Jan 2019 18:50:07 +0300 Subject: [PATCH 1006/2114] Bump Jackson dependency to 2.9.8 Addresses a number of CVEs that affect versions from 2.9.0 through 2.9.7, inclusive. (cherry picked from commit 13c786d497bbad29fc3b23c7ce9735c786004da1) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f43a4abace..e5d62dff82 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,7 @@ 1.7.25 3.2.6 1.0.2 - 2.9.6 + 2.9.8 1.2.3 4.12 3.1.0 From 08d7af39a9c1717cb16a49cbefdf2fc1d9f4198f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 18 Jan 2019 10:36:07 +0100 Subject: [PATCH 1007/2114] Add 5.5.3 and 4.9.3 in readme --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 5bb0b7a3c1..a10f1adce7 100644 --- a/README.md +++ b/README.md @@ -23,14 +23,14 @@ They require Java 8 or higher. com.rabbitmq amqp-client - 5.4.1 + 5.5.3 ``` ### Gradle ``` groovy -compile 'com.rabbitmq:amqp-client:5.4.1' +compile 'com.rabbitmq:amqp-client:5.5.3' ``` #### 4.x Series @@ -42,14 +42,14 @@ They require Java 6 or higher. com.rabbitmq amqp-client - 4.8.1 + 4.9.3 ``` ### Gradle ``` groovy -compile 'com.rabbitmq:amqp-client:4.8.1' +compile 'com.rabbitmq:amqp-client:4.9.3' ``` From 7865c1032f93e3a3761aa28ccb4dee99fc711e24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 22 Jan 2019 15:19:15 +0100 Subject: [PATCH 1008/2114] Fix Mockito test on Java 13 --- pom.xml | 4 ++-- .../com/rabbitmq/client/test/ConnectionTest.java | 7 ++++++- src/test/resources/log4j2-test.properties | 12 ++++++++++++ 3 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 src/test/resources/log4j2-test.properties diff --git a/pom.xml b/pom.xml index fa15668cea..c6142a46d6 100644 --- a/pom.xml +++ b/pom.xml @@ -60,8 +60,8 @@ 2.9.8 1.2.3 4.12 - 3.1.0 - 2.21.0 + 3.1.5 + 2.23.4 3.0.1 2.5.3 diff --git a/src/test/java/com/rabbitmq/client/test/ConnectionTest.java b/src/test/java/com/rabbitmq/client/test/ConnectionTest.java index 36c1347b68..85dc789130 100644 --- a/src/test/java/com/rabbitmq/client/test/ConnectionTest.java +++ b/src/test/java/com/rabbitmq/client/test/ConnectionTest.java @@ -39,7 +39,7 @@ public class ConnectionTest { @Parameterized.Parameter public TestConfigurator configurator; @Mock - Connection c = mock(Connection.class); + MyConnection c = mock(MyConnection.class); @Mock Channel ch = mock(Channel.class); @@ -124,4 +124,9 @@ public Optional open(Connection c) throws IOException { } } + // trick to make Mockito call the optional method defined in the interface + static abstract class MyConnection implements Connection { + + } + } diff --git a/src/test/resources/log4j2-test.properties b/src/test/resources/log4j2-test.properties new file mode 100644 index 0000000000..b7e0a68699 --- /dev/null +++ b/src/test/resources/log4j2-test.properties @@ -0,0 +1,12 @@ +status = error +dest = err +name = PropertiesConfig + +appender.console.type = Console +appender.console.name = STDOUT +appender.console.layout.type = PatternLayout +appender.console.layout.pattern = %m%n + +logger.com.rabbitmq.level = info +rootLogger.level = error +rootLogger.appenderRef.stdout.ref = STDOUT \ No newline at end of file From 46ef9bd756528a99403497f5b22dbe11b275f8db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 22 Jan 2019 15:21:08 +0100 Subject: [PATCH 1009/2114] Bump test dependencies --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index c6142a46d6..a4610b6156 100644 --- a/pom.xml +++ b/pom.xml @@ -73,8 +73,8 @@ 1.5 1.12 3.6.1 - 2.19.1 - 2.19.1 + 2.22.1 + 2.22.1 1.6 3.0.2 3.2.0 From b3ef95b0dcd57d7e42454ab5f41663818ca57f21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 22 Jan 2019 15:26:25 +0100 Subject: [PATCH 1010/2114] Bump Micrometer to 1.1.2 and Metrics to 4.0.5 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index a4610b6156..1756af45f4 100644 --- a/pom.xml +++ b/pom.xml @@ -55,8 +55,8 @@ UTF-8 1.7.25 - 3.2.6 - 1.0.2 + 4.0.5 + 1.1.2 2.9.8 1.2.3 4.12 From 16e3848807fee91af5ec8a78d6cefa455dabf0f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 22 Jan 2019 15:19:15 +0100 Subject: [PATCH 1011/2114] Fix Mockito test on Java 13 (cherry picked from commit 7865c1032f93e3a3761aa28ccb4dee99fc711e24) --- pom.xml | 4 ++-- .../com/rabbitmq/client/test/ConnectionTest.java | 7 ++++++- src/test/resources/log4j2-test.properties | 12 ++++++++++++ 3 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 src/test/resources/log4j2-test.properties diff --git a/pom.xml b/pom.xml index e5d62dff82..55e8367b79 100644 --- a/pom.xml +++ b/pom.xml @@ -60,8 +60,8 @@ 2.9.8 1.2.3 4.12 - 3.1.0 - 2.21.0 + 3.1.5 + 2.23.4 3.0.1 2.5.3 diff --git a/src/test/java/com/rabbitmq/client/test/ConnectionTest.java b/src/test/java/com/rabbitmq/client/test/ConnectionTest.java index 36c1347b68..85dc789130 100644 --- a/src/test/java/com/rabbitmq/client/test/ConnectionTest.java +++ b/src/test/java/com/rabbitmq/client/test/ConnectionTest.java @@ -39,7 +39,7 @@ public class ConnectionTest { @Parameterized.Parameter public TestConfigurator configurator; @Mock - Connection c = mock(Connection.class); + MyConnection c = mock(MyConnection.class); @Mock Channel ch = mock(Channel.class); @@ -124,4 +124,9 @@ public Optional open(Connection c) throws IOException { } } + // trick to make Mockito call the optional method defined in the interface + static abstract class MyConnection implements Connection { + + } + } diff --git a/src/test/resources/log4j2-test.properties b/src/test/resources/log4j2-test.properties new file mode 100644 index 0000000000..b7e0a68699 --- /dev/null +++ b/src/test/resources/log4j2-test.properties @@ -0,0 +1,12 @@ +status = error +dest = err +name = PropertiesConfig + +appender.console.type = Console +appender.console.name = STDOUT +appender.console.layout.type = PatternLayout +appender.console.layout.pattern = %m%n + +logger.com.rabbitmq.level = info +rootLogger.level = error +rootLogger.appenderRef.stdout.ref = STDOUT \ No newline at end of file From ef34291536e8f11582ff6b36afc63310e88af834 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 22 Jan 2019 15:21:08 +0100 Subject: [PATCH 1012/2114] Bump test dependencies (cherry picked from commit 46ef9bd756528a99403497f5b22dbe11b275f8db) --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 55e8367b79..b04ee5a37f 100644 --- a/pom.xml +++ b/pom.xml @@ -73,8 +73,8 @@ 1.5 1.12 3.6.1 - 2.19.1 - 2.19.1 + 2.22.1 + 2.22.1 1.6 3.0.2 3.2.0 From 5c602ee882abbffdc3ae3be5b2862570ff376900 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 22 Jan 2019 15:26:25 +0100 Subject: [PATCH 1013/2114] Bump Micrometer to 1.1.2 and Metrics to 4.0.5 (cherry picked from commit b3ef95b0dcd57d7e42454ab5f41663818ca57f21) --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index b04ee5a37f..6c442ddf64 100644 --- a/pom.xml +++ b/pom.xml @@ -55,8 +55,8 @@ UTF-8 1.7.25 - 3.2.6 - 1.0.2 + 4.0.5 + 1.1.2 2.9.8 1.2.3 4.12 From d7aad18013cdb37bba60675b6e4dc23cdce885e6 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Wed, 23 Jan 2019 09:57:05 +0000 Subject: [PATCH 1014/2114] [maven-release-plugin] prepare release v5.6.0.RC1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 6c442ddf64..320a029f0d 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.6.0-SNAPSHOT + 5.6.0.RC1 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v5.6.0.RC1 From 93d001a42567b5bacb79cacfb4c5b1477ff11be1 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Wed, 23 Jan 2019 09:57:12 +0000 Subject: [PATCH 1015/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 320a029f0d..6c442ddf64 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.6.0.RC1 + 5.6.0-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v5.6.0.RC1 + HEAD From 2f864fbcfa020bc7c25a79da653d5ee288eadddb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 23 Jan 2019 11:08:43 +0100 Subject: [PATCH 1016/2114] Set release version to 5.6.0.RC2 --- release-versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-versions.txt b/release-versions.txt index 5d615855c5..cd28c46dcd 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="5.6.0.RC1" +RELEASE_VERSION="5.6.0.RC2" DEVELOPMENT_VERSION="5.6.0-SNAPSHOT" From ca0835505861f0c0edc7c3588cbfd5b5bd69c19c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 25 Jan 2019 09:17:36 +0100 Subject: [PATCH 1017/2114] Set release version to 5.6.0 --- release-versions.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release-versions.txt b/release-versions.txt index cd28c46dcd..4058557c01 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="5.6.0.RC2" -DEVELOPMENT_VERSION="5.6.0-SNAPSHOT" +RELEASE_VERSION="5.6.0" +DEVELOPMENT_VERSION="5.6.1-SNAPSHOT" From b72aa53f2684c5034b0104e3402788c3b20bd68a Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Fri, 25 Jan 2019 08:19:50 +0000 Subject: [PATCH 1018/2114] [maven-release-plugin] prepare release v5.6.0 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 6c442ddf64..407c6c5593 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.6.0-SNAPSHOT + 5.6.0 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v5.6.0 From 152bf81438faf980070257316675651cc7a35aab Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Fri, 25 Jan 2019 08:19:55 +0000 Subject: [PATCH 1019/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 407c6c5593..8fa0ca4777 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.6.0 + 5.6.1-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v5.6.0 + HEAD From 385342459d4228803334ea22367df89f8ef8cbd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 25 Jan 2019 09:24:52 +0100 Subject: [PATCH 1020/2114] Set release version to 5.7.0.RC1 --- pom.xml | 2 +- release-versions.txt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 8fa0ca4777..e165d34bde 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.6.1-SNAPSHOT + 5.7.0-SNAPSHOT jar RabbitMQ Java Client diff --git a/release-versions.txt b/release-versions.txt index 4058557c01..94a66eae2b 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="5.6.0" -DEVELOPMENT_VERSION="5.6.1-SNAPSHOT" +RELEASE_VERSION="5.7.0.RC1" +DEVELOPMENT_VERSION="5.7.0-SNAPSHOT" From 7abd20c8bfa3be9182c1bc869f488e9eb0f90d14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 25 Jan 2019 09:55:41 +0100 Subject: [PATCH 1021/2114] Fix Javadoc Fix a broken reference to a method, add 8 to fix build on Java 11, replace package.html by package-info.java. --- pom.xml | 4 ++++ src/main/java/com/rabbitmq/client/RpcClientParams.java | 2 +- .../com/rabbitmq/client/impl/nio/package-info.java | 4 ++++ .../java/com/rabbitmq/client/impl/package-info.java | 4 ++++ src/main/java/com/rabbitmq/client/impl/package.html | 9 --------- .../rabbitmq/client/impl/recovery/package-info.java | 4 ++++ src/main/java/com/rabbitmq/client/package-info.java | 5 +++++ src/main/java/com/rabbitmq/client/package.html | 10 ---------- .../java/com/rabbitmq/tools/json/package-info.java | 4 ++++ src/main/java/com/rabbitmq/tools/json/package.html | 9 --------- .../java/com/rabbitmq/tools/jsonrpc/package-info.java | 4 ++++ src/main/java/com/rabbitmq/tools/jsonrpc/package.html | 9 --------- src/main/java/com/rabbitmq/tools/package-info.java | 4 ++++ src/main/java/com/rabbitmq/tools/package.html | 9 --------- src/main/java/com/rabbitmq/utility/package-info.java | 4 ++++ src/main/java/com/rabbitmq/utility/package.html | 9 --------- 16 files changed, 38 insertions(+), 56 deletions(-) create mode 100644 src/main/java/com/rabbitmq/client/impl/nio/package-info.java create mode 100644 src/main/java/com/rabbitmq/client/impl/package-info.java delete mode 100644 src/main/java/com/rabbitmq/client/impl/package.html create mode 100644 src/main/java/com/rabbitmq/client/impl/recovery/package-info.java create mode 100644 src/main/java/com/rabbitmq/client/package-info.java delete mode 100644 src/main/java/com/rabbitmq/client/package.html create mode 100644 src/main/java/com/rabbitmq/tools/json/package-info.java delete mode 100644 src/main/java/com/rabbitmq/tools/json/package.html create mode 100644 src/main/java/com/rabbitmq/tools/jsonrpc/package-info.java delete mode 100644 src/main/java/com/rabbitmq/tools/jsonrpc/package.html create mode 100644 src/main/java/com/rabbitmq/tools/package-info.java delete mode 100644 src/main/java/com/rabbitmq/tools/package.html create mode 100644 src/main/java/com/rabbitmq/utility/package-info.java delete mode 100644 src/main/java/com/rabbitmq/utility/package.html diff --git a/pom.xml b/pom.xml index 1756af45f4..be9de72033 100644 --- a/pom.xml +++ b/pom.xml @@ -504,6 +504,7 @@ ${javadoc.opts} ${javadoc.joption} true + 8 @@ -557,6 +558,7 @@ ${javadoc.opts} ${javadoc.joption} true + 8 @@ -611,6 +613,7 @@ ${javadoc.opts} ${javadoc.joption} true + 8 @@ -1001,6 +1004,7 @@ ${javadoc.opts} ${javadoc.joption} true + 8 diff --git a/src/main/java/com/rabbitmq/client/RpcClientParams.java b/src/main/java/com/rabbitmq/client/RpcClientParams.java index 0831ebb4b3..ce046a6cb6 100644 --- a/src/main/java/com/rabbitmq/client/RpcClientParams.java +++ b/src/main/java/com/rabbitmq/client/RpcClientParams.java @@ -146,7 +146,7 @@ public RpcClientParams timeout(int timeout) { * * @param useMandatory * @return - * @see #replyHandler(Function) + * @see #replyHandler(RpcClient.RpcClientReplyHandler) */ public RpcClientParams useMandatory(boolean useMandatory) { this.useMandatory = useMandatory; diff --git a/src/main/java/com/rabbitmq/client/impl/nio/package-info.java b/src/main/java/com/rabbitmq/client/impl/nio/package-info.java new file mode 100644 index 0000000000..9d6f23e3cb --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/nio/package-info.java @@ -0,0 +1,4 @@ +/** + * NIO network connector. + */ +package com.rabbitmq.client.impl.nio; \ No newline at end of file diff --git a/src/main/java/com/rabbitmq/client/impl/package-info.java b/src/main/java/com/rabbitmq/client/impl/package-info.java new file mode 100644 index 0000000000..4b22e82833 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/package-info.java @@ -0,0 +1,4 @@ +/** + * Implementations of interfaces specified in the client API, and their supporting classes. + */ +package com.rabbitmq.client.impl; \ No newline at end of file diff --git a/src/main/java/com/rabbitmq/client/impl/package.html b/src/main/java/com/rabbitmq/client/impl/package.html deleted file mode 100644 index 20ff0ce857..0000000000 --- a/src/main/java/com/rabbitmq/client/impl/package.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - - -Implementations of interfaces specified in the client API, and their supporting classes. - - - diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/package-info.java b/src/main/java/com/rabbitmq/client/impl/recovery/package-info.java new file mode 100644 index 0000000000..d1432bdcf6 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/recovery/package-info.java @@ -0,0 +1,4 @@ +/** + * Implementation of connection and topology recovery. + */ +package com.rabbitmq.client.impl.recovery; \ No newline at end of file diff --git a/src/main/java/com/rabbitmq/client/package-info.java b/src/main/java/com/rabbitmq/client/package-info.java new file mode 100644 index 0000000000..c231093c21 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/package-info.java @@ -0,0 +1,5 @@ +/** + * The client API proper: classes and interfaces representing the AMQP + * connections, channels, and wire-protocol framing descriptors. + */ +package com.rabbitmq.client; \ No newline at end of file diff --git a/src/main/java/com/rabbitmq/client/package.html b/src/main/java/com/rabbitmq/client/package.html deleted file mode 100644 index 3a190d8770..0000000000 --- a/src/main/java/com/rabbitmq/client/package.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - -The client API proper: classes and interfaces representing the AMQP -connections, channels, and wire-protocol framing descriptors. - - - diff --git a/src/main/java/com/rabbitmq/tools/json/package-info.java b/src/main/java/com/rabbitmq/tools/json/package-info.java new file mode 100644 index 0000000000..0a7d76e65f --- /dev/null +++ b/src/main/java/com/rabbitmq/tools/json/package-info.java @@ -0,0 +1,4 @@ +/** + * JSON reader/writer and utility classes. + */ +package com.rabbitmq.tools.json; \ No newline at end of file diff --git a/src/main/java/com/rabbitmq/tools/json/package.html b/src/main/java/com/rabbitmq/tools/json/package.html deleted file mode 100644 index 625fed317f..0000000000 --- a/src/main/java/com/rabbitmq/tools/json/package.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - - -JSON reader/writer and utility classes. - - - diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/package-info.java b/src/main/java/com/rabbitmq/tools/jsonrpc/package-info.java new file mode 100644 index 0000000000..4cc7826c55 --- /dev/null +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/package-info.java @@ -0,0 +1,4 @@ +/** + * JSON-RPC client and server classes for supporting JSON-RPC over an AMQP transport. + */ +package com.rabbitmq.tools.jsonrpc; \ No newline at end of file diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/package.html b/src/main/java/com/rabbitmq/tools/jsonrpc/package.html deleted file mode 100644 index 04a156cced..0000000000 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/package.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - - -JSON-RPC client and server classes for supporting JSON-RPC over an AMQP transport. - - - diff --git a/src/main/java/com/rabbitmq/tools/package-info.java b/src/main/java/com/rabbitmq/tools/package-info.java new file mode 100644 index 0000000000..2b8be98550 --- /dev/null +++ b/src/main/java/com/rabbitmq/tools/package-info.java @@ -0,0 +1,4 @@ +/** + * Non-core utilities and administration tools. + */ +package com.rabbitmq.tools; \ No newline at end of file diff --git a/src/main/java/com/rabbitmq/tools/package.html b/src/main/java/com/rabbitmq/tools/package.html deleted file mode 100644 index d9972631c5..0000000000 --- a/src/main/java/com/rabbitmq/tools/package.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - - -Non-core utilities and administration tools. - - - diff --git a/src/main/java/com/rabbitmq/utility/package-info.java b/src/main/java/com/rabbitmq/utility/package-info.java new file mode 100644 index 0000000000..9ae72725af --- /dev/null +++ b/src/main/java/com/rabbitmq/utility/package-info.java @@ -0,0 +1,4 @@ +/** + * Utility package of helper classes, mostly used in the implementation code. + */ +package com.rabbitmq.utility; \ No newline at end of file diff --git a/src/main/java/com/rabbitmq/utility/package.html b/src/main/java/com/rabbitmq/utility/package.html deleted file mode 100644 index 6a0ca1e0d0..0000000000 --- a/src/main/java/com/rabbitmq/utility/package.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - - -Utility package of helper classes, mostly used in the implementation code. - - - From 68d55d19fb1906e87b2aa3a82b88dc0b7140476b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 25 Jan 2019 09:55:41 +0100 Subject: [PATCH 1022/2114] Fix Javadoc Fix a broken reference to a method, add 8 to fix build on Java 11, replace package.html by package-info.java. (cherry picked from commit 7abd20c8bfa3be9182c1bc869f488e9eb0f90d14) --- pom.xml | 4 ++++ src/main/java/com/rabbitmq/client/RpcClientParams.java | 2 +- .../com/rabbitmq/client/impl/nio/package-info.java | 4 ++++ .../java/com/rabbitmq/client/impl/package-info.java | 4 ++++ src/main/java/com/rabbitmq/client/impl/package.html | 9 --------- .../rabbitmq/client/impl/recovery/package-info.java | 4 ++++ src/main/java/com/rabbitmq/client/package-info.java | 5 +++++ src/main/java/com/rabbitmq/client/package.html | 10 ---------- .../java/com/rabbitmq/tools/json/package-info.java | 4 ++++ src/main/java/com/rabbitmq/tools/json/package.html | 9 --------- .../java/com/rabbitmq/tools/jsonrpc/package-info.java | 4 ++++ src/main/java/com/rabbitmq/tools/jsonrpc/package.html | 9 --------- src/main/java/com/rabbitmq/tools/package-info.java | 4 ++++ src/main/java/com/rabbitmq/tools/package.html | 9 --------- src/main/java/com/rabbitmq/utility/package-info.java | 4 ++++ src/main/java/com/rabbitmq/utility/package.html | 9 --------- 16 files changed, 38 insertions(+), 56 deletions(-) create mode 100644 src/main/java/com/rabbitmq/client/impl/nio/package-info.java create mode 100644 src/main/java/com/rabbitmq/client/impl/package-info.java delete mode 100644 src/main/java/com/rabbitmq/client/impl/package.html create mode 100644 src/main/java/com/rabbitmq/client/impl/recovery/package-info.java create mode 100644 src/main/java/com/rabbitmq/client/package-info.java delete mode 100644 src/main/java/com/rabbitmq/client/package.html create mode 100644 src/main/java/com/rabbitmq/tools/json/package-info.java delete mode 100644 src/main/java/com/rabbitmq/tools/json/package.html create mode 100644 src/main/java/com/rabbitmq/tools/jsonrpc/package-info.java delete mode 100644 src/main/java/com/rabbitmq/tools/jsonrpc/package.html create mode 100644 src/main/java/com/rabbitmq/tools/package-info.java delete mode 100644 src/main/java/com/rabbitmq/tools/package.html create mode 100644 src/main/java/com/rabbitmq/utility/package-info.java delete mode 100644 src/main/java/com/rabbitmq/utility/package.html diff --git a/pom.xml b/pom.xml index e165d34bde..0fe97c7b4d 100644 --- a/pom.xml +++ b/pom.xml @@ -504,6 +504,7 @@ ${javadoc.opts} ${javadoc.joption} true + 8 @@ -557,6 +558,7 @@ ${javadoc.opts} ${javadoc.joption} true + 8 @@ -611,6 +613,7 @@ ${javadoc.opts} ${javadoc.joption} true + 8 @@ -1001,6 +1004,7 @@ ${javadoc.opts} ${javadoc.joption} true + 8 diff --git a/src/main/java/com/rabbitmq/client/RpcClientParams.java b/src/main/java/com/rabbitmq/client/RpcClientParams.java index 0831ebb4b3..ce046a6cb6 100644 --- a/src/main/java/com/rabbitmq/client/RpcClientParams.java +++ b/src/main/java/com/rabbitmq/client/RpcClientParams.java @@ -146,7 +146,7 @@ public RpcClientParams timeout(int timeout) { * * @param useMandatory * @return - * @see #replyHandler(Function) + * @see #replyHandler(RpcClient.RpcClientReplyHandler) */ public RpcClientParams useMandatory(boolean useMandatory) { this.useMandatory = useMandatory; diff --git a/src/main/java/com/rabbitmq/client/impl/nio/package-info.java b/src/main/java/com/rabbitmq/client/impl/nio/package-info.java new file mode 100644 index 0000000000..9d6f23e3cb --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/nio/package-info.java @@ -0,0 +1,4 @@ +/** + * NIO network connector. + */ +package com.rabbitmq.client.impl.nio; \ No newline at end of file diff --git a/src/main/java/com/rabbitmq/client/impl/package-info.java b/src/main/java/com/rabbitmq/client/impl/package-info.java new file mode 100644 index 0000000000..4b22e82833 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/package-info.java @@ -0,0 +1,4 @@ +/** + * Implementations of interfaces specified in the client API, and their supporting classes. + */ +package com.rabbitmq.client.impl; \ No newline at end of file diff --git a/src/main/java/com/rabbitmq/client/impl/package.html b/src/main/java/com/rabbitmq/client/impl/package.html deleted file mode 100644 index 20ff0ce857..0000000000 --- a/src/main/java/com/rabbitmq/client/impl/package.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - - -Implementations of interfaces specified in the client API, and their supporting classes. - - - diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/package-info.java b/src/main/java/com/rabbitmq/client/impl/recovery/package-info.java new file mode 100644 index 0000000000..d1432bdcf6 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/recovery/package-info.java @@ -0,0 +1,4 @@ +/** + * Implementation of connection and topology recovery. + */ +package com.rabbitmq.client.impl.recovery; \ No newline at end of file diff --git a/src/main/java/com/rabbitmq/client/package-info.java b/src/main/java/com/rabbitmq/client/package-info.java new file mode 100644 index 0000000000..c231093c21 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/package-info.java @@ -0,0 +1,5 @@ +/** + * The client API proper: classes and interfaces representing the AMQP + * connections, channels, and wire-protocol framing descriptors. + */ +package com.rabbitmq.client; \ No newline at end of file diff --git a/src/main/java/com/rabbitmq/client/package.html b/src/main/java/com/rabbitmq/client/package.html deleted file mode 100644 index 3a190d8770..0000000000 --- a/src/main/java/com/rabbitmq/client/package.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - -The client API proper: classes and interfaces representing the AMQP -connections, channels, and wire-protocol framing descriptors. - - - diff --git a/src/main/java/com/rabbitmq/tools/json/package-info.java b/src/main/java/com/rabbitmq/tools/json/package-info.java new file mode 100644 index 0000000000..0a7d76e65f --- /dev/null +++ b/src/main/java/com/rabbitmq/tools/json/package-info.java @@ -0,0 +1,4 @@ +/** + * JSON reader/writer and utility classes. + */ +package com.rabbitmq.tools.json; \ No newline at end of file diff --git a/src/main/java/com/rabbitmq/tools/json/package.html b/src/main/java/com/rabbitmq/tools/json/package.html deleted file mode 100644 index 625fed317f..0000000000 --- a/src/main/java/com/rabbitmq/tools/json/package.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - - -JSON reader/writer and utility classes. - - - diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/package-info.java b/src/main/java/com/rabbitmq/tools/jsonrpc/package-info.java new file mode 100644 index 0000000000..4cc7826c55 --- /dev/null +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/package-info.java @@ -0,0 +1,4 @@ +/** + * JSON-RPC client and server classes for supporting JSON-RPC over an AMQP transport. + */ +package com.rabbitmq.tools.jsonrpc; \ No newline at end of file diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/package.html b/src/main/java/com/rabbitmq/tools/jsonrpc/package.html deleted file mode 100644 index 04a156cced..0000000000 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/package.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - - -JSON-RPC client and server classes for supporting JSON-RPC over an AMQP transport. - - - diff --git a/src/main/java/com/rabbitmq/tools/package-info.java b/src/main/java/com/rabbitmq/tools/package-info.java new file mode 100644 index 0000000000..2b8be98550 --- /dev/null +++ b/src/main/java/com/rabbitmq/tools/package-info.java @@ -0,0 +1,4 @@ +/** + * Non-core utilities and administration tools. + */ +package com.rabbitmq.tools; \ No newline at end of file diff --git a/src/main/java/com/rabbitmq/tools/package.html b/src/main/java/com/rabbitmq/tools/package.html deleted file mode 100644 index d9972631c5..0000000000 --- a/src/main/java/com/rabbitmq/tools/package.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - - -Non-core utilities and administration tools. - - - diff --git a/src/main/java/com/rabbitmq/utility/package-info.java b/src/main/java/com/rabbitmq/utility/package-info.java new file mode 100644 index 0000000000..9ae72725af --- /dev/null +++ b/src/main/java/com/rabbitmq/utility/package-info.java @@ -0,0 +1,4 @@ +/** + * Utility package of helper classes, mostly used in the implementation code. + */ +package com.rabbitmq.utility; \ No newline at end of file diff --git a/src/main/java/com/rabbitmq/utility/package.html b/src/main/java/com/rabbitmq/utility/package.html deleted file mode 100644 index 6a0ca1e0d0..0000000000 --- a/src/main/java/com/rabbitmq/utility/package.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - - -Utility package of helper classes, mostly used in the implementation code. - - - From 7612b7cc5b2a7725d8a62cd2f3b8218e5e487f3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 25 Jan 2019 10:19:32 +0100 Subject: [PATCH 1023/2114] Update readme with 5.6.0 and 4.10.0 --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a10f1adce7..6bd933a167 100644 --- a/README.md +++ b/README.md @@ -23,14 +23,14 @@ They require Java 8 or higher. com.rabbitmq amqp-client - 5.5.3 + 5.6.0 ``` ### Gradle ``` groovy -compile 'com.rabbitmq:amqp-client:5.5.3' +compile 'com.rabbitmq:amqp-client:5.6.0' ``` #### 4.x Series @@ -42,14 +42,14 @@ They require Java 6 or higher. com.rabbitmq amqp-client - 4.9.3 + 4.10.0 ``` ### Gradle ``` groovy -compile 'com.rabbitmq:amqp-client:4.9.3' +compile 'com.rabbitmq:amqp-client:4.10.0' ``` From 7cc840078a35c2d73de0145c49fe553f2ca7595b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 11 Feb 2019 18:07:38 +0100 Subject: [PATCH 1024/2114] Improve logging for TLS connections [#163862785] Fixes #441 --- pom.xml | 7 + .../client/impl/SocketFrameHandler.java | 24 +- .../com/rabbitmq/client/impl/TlsUtils.java | 229 ++++++++++++++++++ .../nio/SocketChannelFrameHandlerFactory.java | 19 +- .../com/rabbitmq/client/test/ClientTests.java | 3 +- .../rabbitmq/client/test/TlsUtilsTest.java | 123 ++++++++++ .../rabbitmq/client/test/ssl/SSLTests.java | 3 +- .../client/test/ssl/TlsConnectionLogging.java | 71 ++++++ 8 files changed, 472 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/rabbitmq/client/impl/TlsUtils.java create mode 100644 src/test/java/com/rabbitmq/client/test/TlsUtilsTest.java create mode 100644 src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java diff --git a/pom.xml b/pom.xml index be9de72033..e8b006ed3a 100644 --- a/pom.xml +++ b/pom.xml @@ -62,6 +62,7 @@ 4.12 3.1.5 2.23.4 + 3.11.1 3.0.1 2.5.3 @@ -731,6 +732,12 @@ ${mockito.version} test + + org.assertj + assertj-core + ${assert4j.version} + test + org.hamcrest hamcrest-library diff --git a/src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java b/src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java index bbe76e0684..02cc9a2d2d 100644 --- a/src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java @@ -16,7 +16,11 @@ package com.rabbitmq.client.impl; import com.rabbitmq.client.AMQP; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import javax.net.ssl.SSLHandshakeException; +import javax.net.ssl.SSLSocket; import java.io.*; import java.net.InetAddress; import java.net.Socket; @@ -31,6 +35,9 @@ */ public class SocketFrameHandler implements FrameHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger(SocketFrameHandler.class); + /** The underlying socket */ private final Socket _socket; @@ -122,7 +129,12 @@ public void sendHeader(int major, int minor) throws IOException { _outputStream.write(1); _outputStream.write(major); _outputStream.write(minor); - _outputStream.flush(); + try { + _outputStream.flush(); + } catch (SSLHandshakeException e) { + LOGGER.error("TLS connection failed: {}", e.getMessage()); + throw e; + } } } @@ -144,13 +156,21 @@ public void sendHeader(int major, int minor, int revision) throws IOException { _outputStream.write(major); _outputStream.write(minor); _outputStream.write(revision); - _outputStream.flush(); + try { + _outputStream.flush(); + } catch (SSLHandshakeException e) { + LOGGER.error("TLS connection failed: {}", e.getMessage()); + throw e; + } } } @Override public void sendHeader() throws IOException { sendHeader(AMQP.PROTOCOL.MAJOR, AMQP.PROTOCOL.MINOR, AMQP.PROTOCOL.REVISION); + if (this._socket instanceof SSLSocket) { + TlsUtils.logPeerCertificateInfo(((SSLSocket) this._socket).getSession()); + } } @Override diff --git a/src/main/java/com/rabbitmq/client/impl/TlsUtils.java b/src/main/java/com/rabbitmq/client/impl/TlsUtils.java new file mode 100644 index 0000000000..b517e51d6c --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/TlsUtils.java @@ -0,0 +1,229 @@ +// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.net.ssl.SSLSession; +import java.security.cert.Certificate; +import java.security.cert.CertificateParsingException; +import java.security.cert.X509Certificate; +import java.util.*; +import java.util.function.BiFunction; +import java.util.stream.Collectors; + +/** + * Utility to extract information from X509 certificates. + * + * @since 5.7.0 + */ +public class TlsUtils { + + private static final Logger LOGGER = LoggerFactory.getLogger(TlsUtils.class); + private static final List KEY_USAGE = Collections.unmodifiableList(Arrays.asList( + "digitalSignature", "nonRepudiation", "keyEncipherment", + "dataEncipherment", "keyAgreement", "keyCertSign", + "cRLSign", "encipherOnly", "decipherOnly" + )); + private static final Map EXTENDED_KEY_USAGE = Collections.unmodifiableMap(new HashMap() {{ + put("1.3.6.1.5.5.7.3.1", "TLS Web server authentication"); + put("1.3.6.1.5.5.7.3.2", "TLS Web client authentication"); + put("1.3.6.1.5.5.7.3.3", "Signing of downloadable executable code"); + put("1.3.6.1.5.5.7.3.4", "E-mail protection"); + put("1.3.6.1.5.5.7.3.8", "Binding the hash of an object to a time from an agreed-upon time"); + }}); + private static String PARSING_ERROR = ""; + private static final Map> EXTENSIONS = Collections.unmodifiableMap( + new HashMap>() {{ + put("2.5.29.14", (v, c) -> "SubjectKeyIdentifier = " + octetStringHexDump(v)); + put("2.5.29.15", (v, c) -> "KeyUsage = " + keyUsageBitString(c.getKeyUsage(), v)); + put("2.5.29.16", (v, c) -> "PrivateKeyUsage = " + hexDump(0, v)); + put("2.5.29.17", (v, c) -> { + try { + return "SubjectAlternativeName = " + sans(c, "/"); + } catch (CertificateParsingException e) { + return "SubjectAlternativeName = " + PARSING_ERROR; + } + }); + put("2.5.29.18", (v, c) -> "IssuerAlternativeName = " + hexDump(0, v)); + put("2.5.29.19", (v, c) -> "BasicConstraints = " + basicConstraints(v)); + put("2.5.29.30", (v, c) -> "NameConstraints = " + hexDump(0, v)); + put("2.5.29.33", (v, c) -> "PolicyMappings = " + hexDump(0, v)); + put("2.5.29.35", (v, c) -> "AuthorityKeyIdentifier = " + authorityKeyIdentifier(v)); + put("2.5.29.36", (v, c) -> "PolicyConstraints = " + hexDump(0, v)); + put("2.5.29.37", (v, c) -> "ExtendedKeyUsage = " + extendedKeyUsage(v, c)); + }}); + + /** + * Log details on peer certificate and certification chain. + *

+ * The log level is debug. Common X509 extensions are displayed in a best-effort + * fashion, a hexadecimal dump is made for less commonly used extensions. + * + * @param session the {@link SSLSession} to extract the certificates from + */ + public static void logPeerCertificateInfo(SSLSession session) { + if (LOGGER.isDebugEnabled()) { + try { + Certificate[] peerCertificates = session.getPeerCertificates(); + if (peerCertificates != null && peerCertificates.length > 0) { + LOGGER.debug(peerCertificateInfo(peerCertificates[0], "Peer's leaf certificate")); + for (int i = 1; i < peerCertificates.length; i++) { + LOGGER.debug(peerCertificateInfo(peerCertificates[i], "Peer's certificate chain entry")); + } + } + } catch (Exception e) { + LOGGER.debug("Error while logging peer certificate info: {}", e.getMessage()); + } + } + } + + /** + * Get a string representation of certificate info. + * + * @param certificate the certificate to analyze + * @param prefix the line prefix + * @return information about the certificate + */ + public static String peerCertificateInfo(Certificate certificate, String prefix) { + X509Certificate c = (X509Certificate) certificate; + try { + return String.format("%s subject: %s, subject alternative names: %s, " + + "issuer: %s, not valid after: %s, X.509 usage extensions: %s", + prefix, c.getSubjectDN().getName(), sans(c, ","), c.getIssuerDN().getName(), + c.getNotAfter(), extensions(c)); + } catch (Exception e) { + return "Error while retrieving " + prefix + " certificate information"; + } + } + + private static String sans(X509Certificate c, String separator) throws CertificateParsingException { + return String.join(separator, Optional.ofNullable(c.getSubjectAlternativeNames()) + .orElse(new ArrayList<>()) + .stream() + .map(v -> v.toString()) + .collect(Collectors.toList())); + } + + /** + * Human-readable representation of an X509 certificate extension. + *

+ * Common extensions are supported in a best-effort fashion, less commonly + * used extensions are displayed as an hexadecimal dump. + *

+ * Extensions come encoded as a DER Octet String, which itself can contain + * other DER-encoded objects, making a comprehensive support in this utility + * impossible. + * + * @param oid extension OID + * @param derOctetString the extension value as a DER octet string + * @param certificate the certificate + * @return the OID and the value + * @see A Layman's Guide to a Subset of ASN.1, BER, and DER + * @see DER Encoding of ASN.1 Types + */ + public static String extensionPrettyPrint(String oid, byte[] derOctetString, X509Certificate certificate) { + try { + return EXTENSIONS.getOrDefault(oid, (v, c) -> oid + " = " + hexDump(0, derOctetString)) + .apply(derOctetString, certificate); + } catch (Exception e) { + return oid + " = " + PARSING_ERROR; + } + } + + private static String extensions(X509Certificate certificate) { + List extensions = new ArrayList<>(); + for (String oid : certificate.getCriticalExtensionOIDs()) { + extensions.add(extensionPrettyPrint(oid, certificate.getExtensionValue(oid), certificate) + " (critical)"); + } + for (String oid : certificate.getNonCriticalExtensionOIDs()) { + extensions.add(extensionPrettyPrint(oid, certificate.getExtensionValue(oid), certificate) + " (non-critical)"); + } + return String.join(", ", extensions); + } + + private static String octetStringHexDump(byte[] derOctetString) { + // this is an octet string in a octet string, [4 total_length 4 length ...] + if (derOctetString.length > 4 && derOctetString[0] == 4 && derOctetString[2] == 4) { + return hexDump(4, derOctetString); + } else { + return hexDump(0, derOctetString); + } + } + + private static String hexDump(int start, byte[] derOctetString) { + List hexs = new ArrayList<>(); + for (int i = start; i < derOctetString.length; i++) { + hexs.add(String.format("%02X", derOctetString[i])); + } + return String.join(":", hexs); + } + + private static String keyUsageBitString(boolean[] keyUsage, byte[] derOctetString) { + if (keyUsage != null) { + List usage = new ArrayList<>(); + for (int i = 0; i < keyUsage.length; i++) { + if (keyUsage[i]) { + usage.add(KEY_USAGE.get(i)); + } + } + return String.join("/", usage); + } else { + return hexDump(0, derOctetString); + } + } + + private static String basicConstraints(byte[] derOctetString) { + if (derOctetString.length == 4 && derOctetString[3] == 0) { + // e.g. 04:02:30:00 [octet_string length sequence size] + return "CA:FALSE"; + } else if (derOctetString.length >= 7 && derOctetString[2] == 48 && derOctetString[4] == 1) { + // e.g. 04:05:30:03:01:01:FF [octet_string length sequence boolean length boolean_value] + return "CA:" + (derOctetString[6] == 0 ? "FALSE" : "TRUE"); + } else { + return hexDump(0, derOctetString); + } + } + + private static String authorityKeyIdentifier(byte[] derOctetString) { + if (derOctetString.length == 26 && derOctetString[0] == 04) { + // e.g. 04:18:30:16:80:14:FB:D2:7C:63:DF:7F:D4:A4:8E:9A:20:43:F5:DC:75:6F:B6:D8:51:6F + // [octet_string length sequence ?? ?? key_length key] + return "keyid:" + hexDump(6, derOctetString); + } else { + return hexDump(0, derOctetString); + } + + } + + private static String extendedKeyUsage(byte[] derOctetString, X509Certificate certificate) { + List extendedKeyUsage = null; + try { + extendedKeyUsage = certificate.getExtendedKeyUsage(); + if (extendedKeyUsage == null) { + return hexDump(0, derOctetString); + } else { + return String.join("/", extendedKeyUsage.stream() + .map(oid -> EXTENDED_KEY_USAGE.getOrDefault(oid, oid)) + .collect(Collectors.toList())); + } + } catch (CertificateParsingException e) { + return PARSING_ERROR; + } + } + +} diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java index c9e1ffb202..784a5f80cd 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java @@ -20,10 +20,14 @@ import com.rabbitmq.client.SslContextFactory; import com.rabbitmq.client.impl.AbstractFrameHandlerFactory; import com.rabbitmq.client.impl.FrameHandler; +import com.rabbitmq.client.impl.TlsUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLException; +import javax.net.ssl.SSLHandshakeException; import java.io.IOException; import java.net.InetSocketAddress; import java.net.SocketAddress; @@ -39,6 +43,8 @@ */ public class SocketChannelFrameHandlerFactory extends AbstractFrameHandlerFactory { + private static final Logger LOGGER = LoggerFactory.getLogger(SocketChannelFrameHandler.class); + final NioParams nioParams; private final SslContextFactory sslContextFactory; @@ -91,10 +97,17 @@ public FrameHandler create(Address addr, String connectionName) throws IOExcepti if (ssl) { sslEngine.beginHandshake(); - boolean handshake = SslEngineHelper.doHandshake(channel, sslEngine); - if (!handshake) { - throw new SSLException("TLS handshake failed"); + try { + boolean handshake = SslEngineHelper.doHandshake(channel, sslEngine); + if (!handshake) { + LOGGER.error("TLS connection failed"); + throw new SSLException("TLS handshake failed"); + } + } catch (SSLHandshakeException e) { + LOGGER.error("TLS connection failed: {}", e.getMessage()); + throw e; } + TlsUtils.logPeerCertificateInfo(sslEngine.getSession()); } channel.configureBlocking(false); diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index 799cfd9126..dfae29e976 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -66,7 +66,8 @@ NioDeadlockOnConnectionClosing.class, GeneratedClassesTest.class, RpcTopologyRecordingTest.class, - ConnectionTest.class + ConnectionTest.class, + TlsUtilsTest.class }) public class ClientTests { diff --git a/src/test/java/com/rabbitmq/client/test/TlsUtilsTest.java b/src/test/java/com/rabbitmq/client/test/TlsUtilsTest.java new file mode 100644 index 0000000000..e632e47282 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/TlsUtilsTest.java @@ -0,0 +1,123 @@ +// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.test; + +import org.junit.Test; +import org.mockito.Mockito; + +import java.security.cert.CertificateParsingException; +import java.security.cert.X509Certificate; +import java.util.Arrays; + +import static com.rabbitmq.client.impl.TlsUtils.extensionPrettyPrint; +import static org.assertj.core.api.Assertions.assertThat; + +public class TlsUtilsTest { + + static final byte [] DOES_NOT_MATTER = new byte[0]; + + @Test + public void subjectKeyIdentifier() { + // https://www.alvestrand.no/objectid/2.5.29.14.html + byte[] derOctetString = new byte[]{ + 4, 22, 4, 20, -2, -87, -45, -120, 29, -126, -88, -17, 95, -39, -122, 23, 10, -62, -54, -82, 113, -121, -70, -121 + }; // 04:16:04:14:FE:A9:D3:88:1D:82:A8:EF:5F:D9:86:17:0A:C2:CA:AE:71:87:BA:87 + assertThat(extensionPrettyPrint("2.5.29.14", derOctetString, null)) + .isEqualTo("SubjectKeyIdentifier = FE:A9:D3:88:1D:82:A8:EF:5F:D9:86:17:0A:C2:CA:AE:71:87:BA:87"); + // change the 3rd byte to mimic it's not a octet string, the whole array should be then hex-dumped + derOctetString = new byte[]{ + 4, 22, 3, 20, -2, -87, -45, -120, 29, -126, -88, -17, 95, -39, -122, 23, 10, -62, -54, -82, 113, -121, -70, -121 + }; // 04:16:04:14:FE:A9:D3:88:1D:82:A8:EF:5F:D9:86:17:0A:C2:CA:AE:71:87:BA:87 + assertThat(extensionPrettyPrint("2.5.29.14", derOctetString, null)) + .isEqualTo("SubjectKeyIdentifier = 04:16:03:14:FE:A9:D3:88:1D:82:A8:EF:5F:D9:86:17:0A:C2:CA:AE:71:87:BA:87"); + } + + @Test public void keyUsage() { + // https://www.alvestrand.no/objectid/2.5.29.15.html + // http://javadoc.iaik.tugraz.at/iaik_jce/current/iaik/asn1/BIT_STRING.html + X509Certificate c = Mockito.mock(X509Certificate.class); + Mockito.when(c.getKeyUsage()) + .thenReturn(new boolean[] {true,false,true,false,false,false,false,false,false}) + .thenReturn(new boolean[] {false,false,false,false,false,true,true,false,false}) + .thenReturn(null); + assertThat(extensionPrettyPrint("2.5.29.15", DOES_NOT_MATTER, c)) + .isEqualTo("KeyUsage = digitalSignature/keyEncipherment"); + assertThat(extensionPrettyPrint("2.5.29.15", DOES_NOT_MATTER, c)) + .isEqualTo("KeyUsage = keyCertSign/cRLSign"); + // change the 3rd byte to mimic it's not a bit string, the whole array should be then hex-dumped + byte[] derOctetString = new byte[] { 4, 4, 3, 2, 1, 6}; // 04:04:03:02:01:06 => Certificate Sign, CRL Sign + assertThat(extensionPrettyPrint("2.5.29.15", derOctetString, c)) + .isEqualTo("KeyUsage = 04:04:03:02:01:06"); + } + + @Test public void basicConstraints() { + // https://www.alvestrand.no/objectid/2.5.29.19.html + byte [] derOctetString = new byte [] {0x04, 0x02, 0x30, 0x00}; + assertThat(extensionPrettyPrint("2.5.29.19", derOctetString, null)) + .isEqualTo("BasicConstraints = CA:FALSE"); + derOctetString = new byte [] {4, 5, 48, 3, 1, 1, -1}; // 04:05:30:03:01:01:FF + assertThat(extensionPrettyPrint("2.5.29.19", derOctetString, null)) + .isEqualTo("BasicConstraints = CA:TRUE"); + derOctetString = new byte [] {4, 5, 48, 3, 1, 1, 0}; // 04:05:30:03:01:01:00 + assertThat(extensionPrettyPrint("2.5.29.19", derOctetString, null)) + .isEqualTo("BasicConstraints = CA:FALSE"); + // change the 3rd to mimic it's not what the utils expects, the whole array should be hex-dump + derOctetString = new byte [] {4, 5, 4, 3, 1, 1, 0}; // 04:05:04:03:01:01:00 + assertThat(extensionPrettyPrint("2.5.29.19", derOctetString, null)) + .isEqualTo("BasicConstraints = 04:05:04:03:01:01:00"); + + } + + @Test public void authorityKeyIdentifier() { + // https://www.alvestrand.no/objectid/2.5.29.35.html + byte[] derOctetString = new byte[]{ + 4,24,48,22,-128,20,-5,-46,124,99,-33,127,-44,-92,-114,-102,32,67,-11,-36,117,111,-74,-40,81,111 + }; // 04:18:30:16:80:14:FB:D2:7C:63:DF:7F:D4:A4:8E:9A:20:43:F5:DC:75:6F:B6:D8:51:6F + assertThat(extensionPrettyPrint("2.5.29.35", derOctetString, null)) + .isEqualTo("AuthorityKeyIdentifier = keyid:FB:D2:7C:63:DF:7F:D4:A4:8E:9A:20:43:F5:DC:75:6F:B6:D8:51:6F"); + + // add a byte to mimic not-expected length, the whole array should be hex-dump + derOctetString = new byte[]{ + 4,24,48,22,-128,20,-5,-46,124,99,-33,127,-44,-92,-114,-102,32,67,-11,-36,117,111,-74,-40,81,111, -1 + }; // 04:18:30:16:80:14:FB:D2:7C:63:DF:7F:D4:A4:8E:9A:20:43:F5:DC:75:6F:B6:D8:51:6F + assertThat(extensionPrettyPrint("2.5.29.35", derOctetString, null)) + .isEqualTo("AuthorityKeyIdentifier = 04:18:30:16:80:14:FB:D2:7C:63:DF:7F:D4:A4:8E:9A:20:43:F5:DC:75:6F:B6:D8:51:6F:FF"); + } + + @Test public void extendedKeyUsage() throws CertificateParsingException { + // https://www.alvestrand.no/objectid/2.5.29.37.html + X509Certificate c = Mockito.mock(X509Certificate.class); + Mockito.when(c.getExtendedKeyUsage()) + .thenReturn(Arrays.asList("1.3.6.1.5.5.7.3.1")) + .thenReturn(Arrays.asList("1.3.6.1.5.5.7.3.1", "1.3.6.1.5.5.7.3.2")) + .thenReturn(Arrays.asList("1.3.6.1.5.5.7.3.unknown")) + .thenReturn(null) + .thenThrow(CertificateParsingException.class); + + assertThat(extensionPrettyPrint("2.5.29.37", DOES_NOT_MATTER, c)) + .isEqualTo("ExtendedKeyUsage = TLS Web server authentication"); + assertThat(extensionPrettyPrint("2.5.29.37", DOES_NOT_MATTER, c)) + .isEqualTo("ExtendedKeyUsage = TLS Web server authentication/TLS Web client authentication"); + assertThat(extensionPrettyPrint("2.5.29.37", DOES_NOT_MATTER, c)) + .isEqualTo("ExtendedKeyUsage = 1.3.6.1.5.5.7.3.unknown"); + byte [] derOctetString = new byte[] {0x04, 0x0C, 0x30, 0x0A, 0x06, 0x08, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01}; + assertThat(extensionPrettyPrint("2.5.29.37", derOctetString, c)) + .isEqualTo("ExtendedKeyUsage = 04:0C:30:0A:06:08:2B:06:01:05:05:07:03:01"); + assertThat(extensionPrettyPrint("2.5.29.37", DOES_NOT_MATTER, c)) + .isEqualTo("ExtendedKeyUsage = "); + } + +} diff --git a/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java index 679468a59f..88107b41fe 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java @@ -33,7 +33,8 @@ BadVerifiedConnection.class, ConnectionFactoryDefaultTlsVersion.class, NioTlsUnverifiedConnection.class, - HostnameVerification.class + HostnameVerification.class, + TlsConnectionLogging.class }) public class SSLTests { diff --git a/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java b/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java new file mode 100644 index 0000000000..12ec082a4d --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java @@ -0,0 +1,71 @@ +// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.test.ssl; + +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.impl.TlsUtils; +import com.rabbitmq.client.test.TestUtils; +import org.assertj.core.api.Assertions; +import org.junit.Test; + +import javax.net.ssl.*; +import java.security.cert.X509Certificate; +import java.util.concurrent.atomic.AtomicReference; + +import static org.junit.Assert.assertNotNull; + +public class TlsConnectionLogging { + + @Test + public void certificateInfoAreProperlyExtracted() throws Exception { + SSLContext sslContext = TestUtils.getSSLContext(); + sslContext.init(null, new TrustManager[]{new AlwaysTrustTrustManager()}, null); + ConnectionFactory connectionFactory = TestUtils.connectionFactory(); + connectionFactory.useSslProtocol(sslContext); + connectionFactory.useBlockingIo(); + AtomicReference socketCaptor = new AtomicReference<>(); + connectionFactory.setSocketConfigurator(socket -> socketCaptor.set((SSLSocket) socket)); + try (Connection ignored = connectionFactory.newConnection()) { + SSLSession session = socketCaptor.get().getSession(); + assertNotNull(session); + String info = TlsUtils.peerCertificateInfo(session.getPeerCertificates()[0], "some prefix"); + Assertions.assertThat(info).contains("some prefix") + .contains("CN=") + .contains("X.509 usage extensions") + .contains("KeyUsage"); + + } + } + + private static class AlwaysTrustTrustManager implements X509TrustManager { + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) { + + } + + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) { + + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } + } + +} From 434ee8b726a084ff858ffee469415d94c4aa057f Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Tue, 12 Feb 2019 00:36:10 -0500 Subject: [PATCH 1025/2114] spelling: concurrency --- src/main/java/com/rabbitmq/utility/IntAllocator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/utility/IntAllocator.java b/src/main/java/com/rabbitmq/utility/IntAllocator.java index b0f25075b7..6032a4dcc8 100644 --- a/src/main/java/com/rabbitmq/utility/IntAllocator.java +++ b/src/main/java/com/rabbitmq/utility/IntAllocator.java @@ -23,7 +23,7 @@ * {@link BitSet} representation of the free integers. *

* - *

Concurrecy Semantics:

+ *

Concurrency Semantics:

* This class is not thread safe. * *

Implementation notes:

From fe751963719d122567d31ac9014f839356023a56 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Tue, 12 Feb 2019 00:36:26 -0500 Subject: [PATCH 1026/2114] spelling: connection --- src/main/java/com/rabbitmq/client/impl/ChannelN.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java index 17bee9ffe7..aea0ee7a4b 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelN.java @@ -602,7 +602,7 @@ public AMQCommand transformReply(AMQCommand command) { boolean notify = false; try { // Synchronize the block below to avoid race conditions in case - // connnection wants to send Connection-CloseOK + // connection wants to send Connection-CloseOK synchronized (_channelMutex) { startProcessShutdownSignal(signal, !initiatedByApplication, true); quiescingRpc(reason, k); From 74a7b39295238400b5c7182c5cba06c6fb546cf1 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Tue, 12 Feb 2019 00:41:49 -0500 Subject: [PATCH 1027/2114] spelling: exchange --- .../rabbitmq/client/test/functional/AlternateExchange.java | 2 +- .../com/rabbitmq/client/test/functional/BindingLifecycle.java | 2 +- .../rabbitmq/client/test/server/DurableBindingLifecycle.java | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/AlternateExchange.java b/src/test/java/com/rabbitmq/client/test/functional/AlternateExchange.java index b408cffca0..242e95032b 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/AlternateExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/AlternateExchange.java @@ -96,7 +96,7 @@ public void handleReturn(int replyCode, * * @param name the name of the exchange to be created, and queue * to be bound - * @param ae the name of the alternate-exchage + * @param ae the name of the alternate-exchange */ protected void setupRouting(String name, String ae) throws IOException { Map args = new HashMap(); diff --git a/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java b/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java index 0090d40a45..363bfaebf1 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java +++ b/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java @@ -153,7 +153,7 @@ public class BindingLifecycle extends BindingLifecycleBase { * The unsubscribe should cause the queue to auto_delete, which in * turn should cause the exchange to auto_delete. * - * Then re-declare the queue again and try to rebind it to the same exhange. + * Then re-declare the queue again and try to rebind it to the same exchange. * * Because the exchange has been auto-deleted, the bind operation * should fail. diff --git a/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java b/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java index 4c4b6fd910..644c21d11a 100644 --- a/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java +++ b/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java @@ -85,9 +85,9 @@ private void restartPrimary() throws IOException, TimeoutException { /** * This tests whether the bindings attached to a durable exchange - * are correctly blown away when the exhange is nuked. + * are correctly blown away when the exchange is nuked. * - * This complements a unit test for testing non-durable exhanges. + * This complements a unit test for testing non-durable exchanges. * In that case, an exchange is deleted and you expect any * bindings hanging to it to be deleted as well. To verify this, * the exchange is deleted and then recreated. From a24af9c6c158c8f0a062e1505dbfb79adc012a1d Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Tue, 12 Feb 2019 00:42:02 -0500 Subject: [PATCH 1028/2114] spelling: execute --- src/main/java/com/rabbitmq/client/impl/AMQConnection.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index d65008d96a..48949b4ca4 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -851,7 +851,7 @@ public void handleConnectionClose(Command closeCommand) { SocketCloseWait scw = new SocketCloseWait(sse); // if shutdown executor is configured, use it. Otherwise - // execut socket close monitor the old fashioned way. + // execute socket close monitor the old fashioned way. // see rabbitmq/rabbitmq-java-client#91 if(shutdownExecutor != null) { shutdownExecutor.execute(scw); From 2cb02675e2cca0fcebc548d50d64fbc926ddbb12 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Tue, 12 Feb 2019 00:43:30 -0500 Subject: [PATCH 1029/2114] spelling: fulfill --- RUNNING_TESTS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RUNNING_TESTS.md b/RUNNING_TESTS.md index a449a0d099..a6da665d52 100644 --- a/RUNNING_TESTS.md +++ b/RUNNING_TESTS.md @@ -21,7 +21,7 @@ can control the running node. `./mvnw verify` will start those nodes with the appropriate configuration. -To easily fullfil all those requirements, you should use `make deps` to +To easily fulfill all those requirements, you should use `make deps` to fetch the dependencies in the `deps` directory. You then run Maven with the `deps.dir` property set like this: From 2f684a878bd521be00a98987f5837972865e16ea Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Tue, 12 Feb 2019 00:47:56 -0500 Subject: [PATCH 1030/2114] spelling: omitted --- src/main/java/com/rabbitmq/client/ConnectionFactory.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 9a9ea410ac..87aeb5e945 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -307,7 +307,7 @@ public void setVirtualHost(String virtualHost) { /** * Convenience method for setting the fields in an AMQP URI: host, * port, username, password and virtual host. If any part of the - * URI is ommited, the ConnectionFactory's corresponding variable + * URI is omitted, the ConnectionFactory's corresponding variable * is left unchanged. * @param uri is the AMQP URI containing the data */ @@ -366,7 +366,7 @@ public void setUri(URI uri) /** * Convenience method for setting the fields in an AMQP URI: host, * port, username, password and virtual host. If any part of the - * URI is ommited, the ConnectionFactory's corresponding variable + * URI is omitted, the ConnectionFactory's corresponding variable * is left unchanged. Note that not all valid AMQP URIs are * accepted; in particular, the hostname must be given if the * port, username or password are given, and escapes in the From a810eba969c41c068abc8b8fe4dddc34a1936ef0 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Tue, 12 Feb 2019 23:29:24 -0500 Subject: [PATCH 1031/2114] spelling: protocol --- src/main/java/com/rabbitmq/client/ConnectionFactory.java | 4 ++-- .../com/rabbitmq/client/test/SslContextFactoryTest.java | 2 +- .../client/test/ssl/ConnectionFactoryDefaultTlsVersion.java | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 87aeb5e945..cbc055bf99 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -674,7 +674,7 @@ public boolean isSSL(){ public void useSslProtocol() throws NoSuchAlgorithmException, KeyManagementException { - useSslProtocol(computeDefaultTlsProcotol(SSLContext.getDefault().getSupportedSSLParameters().getProtocols())); + useSslProtocol(computeDefaultTlsProtocol(SSLContext.getDefault().getSupportedSSLParameters().getProtocols())); } /** @@ -777,7 +777,7 @@ protected void enableHostnameVerificationForBlockingIo() { } } - public static String computeDefaultTlsProcotol(String[] supportedProtocols) { + public static String computeDefaultTlsProtocol(String[] supportedProtocols) { if(supportedProtocols != null) { for (String supportedProtocol : supportedProtocols) { if(PREFERRED_TLS_PROTOCOL.equalsIgnoreCase(supportedProtocol)) { diff --git a/src/test/java/com/rabbitmq/client/test/SslContextFactoryTest.java b/src/test/java/com/rabbitmq/client/test/SslContextFactoryTest.java index 68ed763cd0..ed930c111e 100644 --- a/src/test/java/com/rabbitmq/client/test/SslContextFactoryTest.java +++ b/src/test/java/com/rabbitmq/client/test/SslContextFactoryTest.java @@ -129,7 +129,7 @@ private SslContextFactory sslContextFactory() throws Exception { } private String tlsProtocol() throws NoSuchAlgorithmException { - return ConnectionFactory.computeDefaultTlsProcotol(SSLContext.getDefault().getSupportedSSLParameters().getProtocols()); + return ConnectionFactory.computeDefaultTlsProtocol(SSLContext.getDefault().getSupportedSSLParameters().getProtocols()); } private static class TrustNothingTrustManager implements X509TrustManager { diff --git a/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java b/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java index 095c2cbb49..9d6546572b 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java @@ -24,19 +24,19 @@ public class ConnectionFactoryDefaultTlsVersion { @Test public void defaultTlsVersionJdk16ShouldTakeFallback() { String [] supportedProtocols = {"SSLv2Hello", "SSLv3", "TLSv1"}; - String tlsProtocol = ConnectionFactory.computeDefaultTlsProcotol(supportedProtocols); + String tlsProtocol = ConnectionFactory.computeDefaultTlsProtocol(supportedProtocols); Assert.assertEquals("TLSv1",tlsProtocol); } @Test public void defaultTlsVersionJdk17ShouldTakePrefered() { String [] supportedProtocols = {"SSLv2Hello", "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2"}; - String tlsProtocol = ConnectionFactory.computeDefaultTlsProcotol(supportedProtocols); + String tlsProtocol = ConnectionFactory.computeDefaultTlsProtocol(supportedProtocols); Assert.assertEquals("TLSv1.2",tlsProtocol); } @Test public void defaultTlsVersionJdk18ShouldTakePrefered() { String [] supportedProtocols = {"SSLv2Hello", "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2"}; - String tlsProtocol = ConnectionFactory.computeDefaultTlsProcotol(supportedProtocols); + String tlsProtocol = ConnectionFactory.computeDefaultTlsProtocol(supportedProtocols); Assert.assertEquals("TLSv1.2",tlsProtocol); } From 8c8bdd30aafcd82c6fa76db32e7d2bcac35a975a Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Tue, 12 Feb 2019 23:30:18 -0500 Subject: [PATCH 1032/2114] spelling: receive --- .../com/rabbitmq/client/test/functional/BindingLifecycle.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java b/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java index 363bfaebf1..0223c4c878 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java +++ b/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java @@ -49,7 +49,7 @@ public class BindingLifecycle extends BindingLifecycleBase { Binding binding = setupExchangeBindings(false); channel.basicPublish(binding.x, binding.k, null, payload); - // Purge the queue, and test that we don't recieve a message + // Purge the queue, and test that we don't receive a message channel.queuePurge(binding.q); GetResponse response = channel.basicGet(binding.q, true); From 9658f446e8a2e6094ac0265581e2471a7720fb1d Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Tue, 12 Feb 2019 23:31:36 -0500 Subject: [PATCH 1033/2114] spelling: targeting --- .../java/com/rabbitmq/client/impl/MethodArgumentWriter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/impl/MethodArgumentWriter.java b/src/main/java/com/rabbitmq/client/impl/MethodArgumentWriter.java index 139f9eb5ea..db2005d32f 100644 --- a/src/main/java/com/rabbitmq/client/impl/MethodArgumentWriter.java +++ b/src/main/java/com/rabbitmq/client/impl/MethodArgumentWriter.java @@ -38,7 +38,7 @@ public class MethodArgumentWriter private int bitMask; /** - * Constructs a MethodArgumentWriter targetting the given DataOutputStream. + * Constructs a MethodArgumentWriter targeting the given DataOutputStream. */ public MethodArgumentWriter(ValueWriter out) { From cce132bfe822c61898a8532a58651e92a9b98565 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Tue, 12 Feb 2019 23:32:05 -0500 Subject: [PATCH 1034/2114] spelling: topology --- .../rabbitmq/client/impl/recovery/AutorecoveringConnection.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index bfd2336a5b..379961971c 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -681,7 +681,7 @@ private void recoverTopology(final ExecutorService executor) { recoverEntitiesAsynchronously(executor, Utility.copy(recordedBindings)); recoverEntitiesAsynchronously(executor, Utility.copy(consumers).values()); } catch (final Exception cause) { - final String message = "Caught an exception while recovering toplogy: " + cause.getMessage(); + final String message = "Caught an exception while recovering topology: " + cause.getMessage(); final TopologyRecoveryException e = new TopologyRecoveryException(message, cause); getExceptionHandler().handleTopologyRecoveryException(delegate, null, e); } From 9335d456400fd4e957733c952cef05a984da67d5 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Tue, 12 Feb 2019 00:36:10 -0500 Subject: [PATCH 1035/2114] spelling: concurrency (cherry picked from commit 434ee8b726a084ff858ffee469415d94c4aa057f) --- src/main/java/com/rabbitmq/utility/IntAllocator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/utility/IntAllocator.java b/src/main/java/com/rabbitmq/utility/IntAllocator.java index b0f25075b7..6032a4dcc8 100644 --- a/src/main/java/com/rabbitmq/utility/IntAllocator.java +++ b/src/main/java/com/rabbitmq/utility/IntAllocator.java @@ -23,7 +23,7 @@ * {@link BitSet} representation of the free integers. *

* - *

Concurrecy Semantics:

+ *

Concurrency Semantics:

* This class is not thread safe. * *

Implementation notes:

From 226b3323b404dd64063385804e32c11abce0a264 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Tue, 12 Feb 2019 00:36:26 -0500 Subject: [PATCH 1036/2114] spelling: connection (cherry picked from commit fe751963719d122567d31ac9014f839356023a56) --- src/main/java/com/rabbitmq/client/impl/ChannelN.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java index 17bee9ffe7..aea0ee7a4b 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelN.java @@ -602,7 +602,7 @@ public AMQCommand transformReply(AMQCommand command) { boolean notify = false; try { // Synchronize the block below to avoid race conditions in case - // connnection wants to send Connection-CloseOK + // connection wants to send Connection-CloseOK synchronized (_channelMutex) { startProcessShutdownSignal(signal, !initiatedByApplication, true); quiescingRpc(reason, k); From e597202213b500a04344bb75a56e0f06bd85de39 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Tue, 12 Feb 2019 00:41:49 -0500 Subject: [PATCH 1037/2114] spelling: exchange (cherry picked from commit 74a7b39295238400b5c7182c5cba06c6fb546cf1) --- .../rabbitmq/client/test/functional/AlternateExchange.java | 2 +- .../com/rabbitmq/client/test/functional/BindingLifecycle.java | 2 +- .../rabbitmq/client/test/server/DurableBindingLifecycle.java | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/AlternateExchange.java b/src/test/java/com/rabbitmq/client/test/functional/AlternateExchange.java index b408cffca0..242e95032b 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/AlternateExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/AlternateExchange.java @@ -96,7 +96,7 @@ public void handleReturn(int replyCode, * * @param name the name of the exchange to be created, and queue * to be bound - * @param ae the name of the alternate-exchage + * @param ae the name of the alternate-exchange */ protected void setupRouting(String name, String ae) throws IOException { Map args = new HashMap(); diff --git a/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java b/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java index 0090d40a45..363bfaebf1 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java +++ b/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java @@ -153,7 +153,7 @@ public class BindingLifecycle extends BindingLifecycleBase { * The unsubscribe should cause the queue to auto_delete, which in * turn should cause the exchange to auto_delete. * - * Then re-declare the queue again and try to rebind it to the same exhange. + * Then re-declare the queue again and try to rebind it to the same exchange. * * Because the exchange has been auto-deleted, the bind operation * should fail. diff --git a/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java b/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java index 4c4b6fd910..644c21d11a 100644 --- a/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java +++ b/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java @@ -85,9 +85,9 @@ private void restartPrimary() throws IOException, TimeoutException { /** * This tests whether the bindings attached to a durable exchange - * are correctly blown away when the exhange is nuked. + * are correctly blown away when the exchange is nuked. * - * This complements a unit test for testing non-durable exhanges. + * This complements a unit test for testing non-durable exchanges. * In that case, an exchange is deleted and you expect any * bindings hanging to it to be deleted as well. To verify this, * the exchange is deleted and then recreated. From 6568467fdb1cf9de92e417f3692902f45e83024e Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Tue, 12 Feb 2019 00:42:02 -0500 Subject: [PATCH 1038/2114] spelling: execute (cherry picked from commit a24af9c6c158c8f0a062e1505dbfb79adc012a1d) --- src/main/java/com/rabbitmq/client/impl/AMQConnection.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index d65008d96a..48949b4ca4 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -851,7 +851,7 @@ public void handleConnectionClose(Command closeCommand) { SocketCloseWait scw = new SocketCloseWait(sse); // if shutdown executor is configured, use it. Otherwise - // execut socket close monitor the old fashioned way. + // execute socket close monitor the old fashioned way. // see rabbitmq/rabbitmq-java-client#91 if(shutdownExecutor != null) { shutdownExecutor.execute(scw); From 03ec30edfbfb71ac3d9ec7a656b96f2c3e859fc8 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Tue, 12 Feb 2019 00:43:30 -0500 Subject: [PATCH 1039/2114] spelling: fulfill (cherry picked from commit 2cb02675e2cca0fcebc548d50d64fbc926ddbb12) --- RUNNING_TESTS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RUNNING_TESTS.md b/RUNNING_TESTS.md index a449a0d099..a6da665d52 100644 --- a/RUNNING_TESTS.md +++ b/RUNNING_TESTS.md @@ -21,7 +21,7 @@ can control the running node. `./mvnw verify` will start those nodes with the appropriate configuration. -To easily fullfil all those requirements, you should use `make deps` to +To easily fulfill all those requirements, you should use `make deps` to fetch the dependencies in the `deps` directory. You then run Maven with the `deps.dir` property set like this: From ebfd620a729cb6ce18c00d9cb5ff969aaeedb68f Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Tue, 12 Feb 2019 00:47:56 -0500 Subject: [PATCH 1040/2114] spelling: omitted (cherry picked from commit 2f684a878bd521be00a98987f5837972865e16ea) --- src/main/java/com/rabbitmq/client/ConnectionFactory.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 4dba1db7df..c5433571c7 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -307,7 +307,7 @@ public void setVirtualHost(String virtualHost) { /** * Convenience method for setting the fields in an AMQP URI: host, * port, username, password and virtual host. If any part of the - * URI is ommited, the ConnectionFactory's corresponding variable + * URI is omitted, the ConnectionFactory's corresponding variable * is left unchanged. * @param uri is the AMQP URI containing the data */ @@ -366,7 +366,7 @@ public void setUri(URI uri) /** * Convenience method for setting the fields in an AMQP URI: host, * port, username, password and virtual host. If any part of the - * URI is ommited, the ConnectionFactory's corresponding variable + * URI is omitted, the ConnectionFactory's corresponding variable * is left unchanged. Note that not all valid AMQP URIs are * accepted; in particular, the hostname must be given if the * port, username or password are given, and escapes in the From e4670da93e9118110ab166ea30659a68e4c9d7cb Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Tue, 12 Feb 2019 23:29:24 -0500 Subject: [PATCH 1041/2114] spelling: protocol (cherry picked from commit a810eba969c41c068abc8b8fe4dddc34a1936ef0) --- src/main/java/com/rabbitmq/client/ConnectionFactory.java | 4 ++-- .../com/rabbitmq/client/test/SslContextFactoryTest.java | 2 +- .../client/test/ssl/ConnectionFactoryDefaultTlsVersion.java | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index c5433571c7..12eccb007d 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -674,7 +674,7 @@ public boolean isSSL(){ public void useSslProtocol() throws NoSuchAlgorithmException, KeyManagementException { - useSslProtocol(computeDefaultTlsProcotol(SSLContext.getDefault().getSupportedSSLParameters().getProtocols())); + useSslProtocol(computeDefaultTlsProtocol(SSLContext.getDefault().getSupportedSSLParameters().getProtocols())); } /** @@ -777,7 +777,7 @@ protected void enableHostnameVerificationForBlockingIo() { } } - public static String computeDefaultTlsProcotol(String[] supportedProtocols) { + public static String computeDefaultTlsProtocol(String[] supportedProtocols) { if(supportedProtocols != null) { for (String supportedProtocol : supportedProtocols) { if(PREFERRED_TLS_PROTOCOL.equalsIgnoreCase(supportedProtocol)) { diff --git a/src/test/java/com/rabbitmq/client/test/SslContextFactoryTest.java b/src/test/java/com/rabbitmq/client/test/SslContextFactoryTest.java index 68ed763cd0..ed930c111e 100644 --- a/src/test/java/com/rabbitmq/client/test/SslContextFactoryTest.java +++ b/src/test/java/com/rabbitmq/client/test/SslContextFactoryTest.java @@ -129,7 +129,7 @@ private SslContextFactory sslContextFactory() throws Exception { } private String tlsProtocol() throws NoSuchAlgorithmException { - return ConnectionFactory.computeDefaultTlsProcotol(SSLContext.getDefault().getSupportedSSLParameters().getProtocols()); + return ConnectionFactory.computeDefaultTlsProtocol(SSLContext.getDefault().getSupportedSSLParameters().getProtocols()); } private static class TrustNothingTrustManager implements X509TrustManager { diff --git a/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java b/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java index 095c2cbb49..9d6546572b 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java @@ -24,19 +24,19 @@ public class ConnectionFactoryDefaultTlsVersion { @Test public void defaultTlsVersionJdk16ShouldTakeFallback() { String [] supportedProtocols = {"SSLv2Hello", "SSLv3", "TLSv1"}; - String tlsProtocol = ConnectionFactory.computeDefaultTlsProcotol(supportedProtocols); + String tlsProtocol = ConnectionFactory.computeDefaultTlsProtocol(supportedProtocols); Assert.assertEquals("TLSv1",tlsProtocol); } @Test public void defaultTlsVersionJdk17ShouldTakePrefered() { String [] supportedProtocols = {"SSLv2Hello", "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2"}; - String tlsProtocol = ConnectionFactory.computeDefaultTlsProcotol(supportedProtocols); + String tlsProtocol = ConnectionFactory.computeDefaultTlsProtocol(supportedProtocols); Assert.assertEquals("TLSv1.2",tlsProtocol); } @Test public void defaultTlsVersionJdk18ShouldTakePrefered() { String [] supportedProtocols = {"SSLv2Hello", "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2"}; - String tlsProtocol = ConnectionFactory.computeDefaultTlsProcotol(supportedProtocols); + String tlsProtocol = ConnectionFactory.computeDefaultTlsProtocol(supportedProtocols); Assert.assertEquals("TLSv1.2",tlsProtocol); } From d66c8e60ced1b7d47564e2bcf87bf9c37329286c Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Tue, 12 Feb 2019 23:30:18 -0500 Subject: [PATCH 1042/2114] spelling: receive (cherry picked from commit 8c8bdd30aafcd82c6fa76db32e7d2bcac35a975a) --- .../com/rabbitmq/client/test/functional/BindingLifecycle.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java b/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java index 363bfaebf1..0223c4c878 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java +++ b/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java @@ -49,7 +49,7 @@ public class BindingLifecycle extends BindingLifecycleBase { Binding binding = setupExchangeBindings(false); channel.basicPublish(binding.x, binding.k, null, payload); - // Purge the queue, and test that we don't recieve a message + // Purge the queue, and test that we don't receive a message channel.queuePurge(binding.q); GetResponse response = channel.basicGet(binding.q, true); From 6bb5fcb8ed21a2ce46a1c0e8f42369b33503ced3 Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Tue, 12 Feb 2019 23:31:36 -0500 Subject: [PATCH 1043/2114] spelling: targeting (cherry picked from commit 9658f446e8a2e6094ac0265581e2471a7720fb1d) --- .../java/com/rabbitmq/client/impl/MethodArgumentWriter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/impl/MethodArgumentWriter.java b/src/main/java/com/rabbitmq/client/impl/MethodArgumentWriter.java index 139f9eb5ea..db2005d32f 100644 --- a/src/main/java/com/rabbitmq/client/impl/MethodArgumentWriter.java +++ b/src/main/java/com/rabbitmq/client/impl/MethodArgumentWriter.java @@ -38,7 +38,7 @@ public class MethodArgumentWriter private int bitMask; /** - * Constructs a MethodArgumentWriter targetting the given DataOutputStream. + * Constructs a MethodArgumentWriter targeting the given DataOutputStream. */ public MethodArgumentWriter(ValueWriter out) { From 0cec53957204076038fbbf1afef25e0ce78c75fc Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Tue, 12 Feb 2019 23:32:05 -0500 Subject: [PATCH 1044/2114] spelling: topology (cherry picked from commit cce132bfe822c61898a8532a58651e92a9b98565) --- .../rabbitmq/client/impl/recovery/AutorecoveringConnection.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index bfd2336a5b..379961971c 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -681,7 +681,7 @@ private void recoverTopology(final ExecutorService executor) { recoverEntitiesAsynchronously(executor, Utility.copy(recordedBindings)); recoverEntitiesAsynchronously(executor, Utility.copy(consumers).values()); } catch (final Exception cause) { - final String message = "Caught an exception while recovering toplogy: " + cause.getMessage(); + final String message = "Caught an exception while recovering topology: " + cause.getMessage(); final TopologyRecoveryException e = new TopologyRecoveryException(message, cause); getExceptionHandler().handleTopologyRecoveryException(delegate, null, e); } From b8cb98bb4d42f38f764debe979213f0f3ef17178 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 11 Feb 2019 18:07:38 +0100 Subject: [PATCH 1045/2114] Improve logging for TLS connections [#163862785] Fixes #441 (cherry picked from commit 7cc840078a35c2d73de0145c49fe553f2ca7595b) --- pom.xml | 7 + .../client/impl/SocketFrameHandler.java | 24 +- .../com/rabbitmq/client/impl/TlsUtils.java | 229 ++++++++++++++++++ .../nio/SocketChannelFrameHandlerFactory.java | 19 +- .../com/rabbitmq/client/test/ClientTests.java | 3 +- .../rabbitmq/client/test/TlsUtilsTest.java | 123 ++++++++++ .../rabbitmq/client/test/ssl/SSLTests.java | 3 +- .../client/test/ssl/TlsConnectionLogging.java | 71 ++++++ 8 files changed, 472 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/rabbitmq/client/impl/TlsUtils.java create mode 100644 src/test/java/com/rabbitmq/client/test/TlsUtilsTest.java create mode 100644 src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java diff --git a/pom.xml b/pom.xml index 0fe97c7b4d..b4b6cd3d46 100644 --- a/pom.xml +++ b/pom.xml @@ -62,6 +62,7 @@ 4.12 3.1.5 2.23.4 + 3.11.1 3.0.1 2.5.3 @@ -731,6 +732,12 @@ ${mockito.version} test + + org.assertj + assertj-core + ${assert4j.version} + test + org.hamcrest hamcrest-library diff --git a/src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java b/src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java index bbe76e0684..02cc9a2d2d 100644 --- a/src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java @@ -16,7 +16,11 @@ package com.rabbitmq.client.impl; import com.rabbitmq.client.AMQP; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import javax.net.ssl.SSLHandshakeException; +import javax.net.ssl.SSLSocket; import java.io.*; import java.net.InetAddress; import java.net.Socket; @@ -31,6 +35,9 @@ */ public class SocketFrameHandler implements FrameHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger(SocketFrameHandler.class); + /** The underlying socket */ private final Socket _socket; @@ -122,7 +129,12 @@ public void sendHeader(int major, int minor) throws IOException { _outputStream.write(1); _outputStream.write(major); _outputStream.write(minor); - _outputStream.flush(); + try { + _outputStream.flush(); + } catch (SSLHandshakeException e) { + LOGGER.error("TLS connection failed: {}", e.getMessage()); + throw e; + } } } @@ -144,13 +156,21 @@ public void sendHeader(int major, int minor, int revision) throws IOException { _outputStream.write(major); _outputStream.write(minor); _outputStream.write(revision); - _outputStream.flush(); + try { + _outputStream.flush(); + } catch (SSLHandshakeException e) { + LOGGER.error("TLS connection failed: {}", e.getMessage()); + throw e; + } } } @Override public void sendHeader() throws IOException { sendHeader(AMQP.PROTOCOL.MAJOR, AMQP.PROTOCOL.MINOR, AMQP.PROTOCOL.REVISION); + if (this._socket instanceof SSLSocket) { + TlsUtils.logPeerCertificateInfo(((SSLSocket) this._socket).getSession()); + } } @Override diff --git a/src/main/java/com/rabbitmq/client/impl/TlsUtils.java b/src/main/java/com/rabbitmq/client/impl/TlsUtils.java new file mode 100644 index 0000000000..b517e51d6c --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/TlsUtils.java @@ -0,0 +1,229 @@ +// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.net.ssl.SSLSession; +import java.security.cert.Certificate; +import java.security.cert.CertificateParsingException; +import java.security.cert.X509Certificate; +import java.util.*; +import java.util.function.BiFunction; +import java.util.stream.Collectors; + +/** + * Utility to extract information from X509 certificates. + * + * @since 5.7.0 + */ +public class TlsUtils { + + private static final Logger LOGGER = LoggerFactory.getLogger(TlsUtils.class); + private static final List KEY_USAGE = Collections.unmodifiableList(Arrays.asList( + "digitalSignature", "nonRepudiation", "keyEncipherment", + "dataEncipherment", "keyAgreement", "keyCertSign", + "cRLSign", "encipherOnly", "decipherOnly" + )); + private static final Map EXTENDED_KEY_USAGE = Collections.unmodifiableMap(new HashMap() {{ + put("1.3.6.1.5.5.7.3.1", "TLS Web server authentication"); + put("1.3.6.1.5.5.7.3.2", "TLS Web client authentication"); + put("1.3.6.1.5.5.7.3.3", "Signing of downloadable executable code"); + put("1.3.6.1.5.5.7.3.4", "E-mail protection"); + put("1.3.6.1.5.5.7.3.8", "Binding the hash of an object to a time from an agreed-upon time"); + }}); + private static String PARSING_ERROR = ""; + private static final Map> EXTENSIONS = Collections.unmodifiableMap( + new HashMap>() {{ + put("2.5.29.14", (v, c) -> "SubjectKeyIdentifier = " + octetStringHexDump(v)); + put("2.5.29.15", (v, c) -> "KeyUsage = " + keyUsageBitString(c.getKeyUsage(), v)); + put("2.5.29.16", (v, c) -> "PrivateKeyUsage = " + hexDump(0, v)); + put("2.5.29.17", (v, c) -> { + try { + return "SubjectAlternativeName = " + sans(c, "/"); + } catch (CertificateParsingException e) { + return "SubjectAlternativeName = " + PARSING_ERROR; + } + }); + put("2.5.29.18", (v, c) -> "IssuerAlternativeName = " + hexDump(0, v)); + put("2.5.29.19", (v, c) -> "BasicConstraints = " + basicConstraints(v)); + put("2.5.29.30", (v, c) -> "NameConstraints = " + hexDump(0, v)); + put("2.5.29.33", (v, c) -> "PolicyMappings = " + hexDump(0, v)); + put("2.5.29.35", (v, c) -> "AuthorityKeyIdentifier = " + authorityKeyIdentifier(v)); + put("2.5.29.36", (v, c) -> "PolicyConstraints = " + hexDump(0, v)); + put("2.5.29.37", (v, c) -> "ExtendedKeyUsage = " + extendedKeyUsage(v, c)); + }}); + + /** + * Log details on peer certificate and certification chain. + *

+ * The log level is debug. Common X509 extensions are displayed in a best-effort + * fashion, a hexadecimal dump is made for less commonly used extensions. + * + * @param session the {@link SSLSession} to extract the certificates from + */ + public static void logPeerCertificateInfo(SSLSession session) { + if (LOGGER.isDebugEnabled()) { + try { + Certificate[] peerCertificates = session.getPeerCertificates(); + if (peerCertificates != null && peerCertificates.length > 0) { + LOGGER.debug(peerCertificateInfo(peerCertificates[0], "Peer's leaf certificate")); + for (int i = 1; i < peerCertificates.length; i++) { + LOGGER.debug(peerCertificateInfo(peerCertificates[i], "Peer's certificate chain entry")); + } + } + } catch (Exception e) { + LOGGER.debug("Error while logging peer certificate info: {}", e.getMessage()); + } + } + } + + /** + * Get a string representation of certificate info. + * + * @param certificate the certificate to analyze + * @param prefix the line prefix + * @return information about the certificate + */ + public static String peerCertificateInfo(Certificate certificate, String prefix) { + X509Certificate c = (X509Certificate) certificate; + try { + return String.format("%s subject: %s, subject alternative names: %s, " + + "issuer: %s, not valid after: %s, X.509 usage extensions: %s", + prefix, c.getSubjectDN().getName(), sans(c, ","), c.getIssuerDN().getName(), + c.getNotAfter(), extensions(c)); + } catch (Exception e) { + return "Error while retrieving " + prefix + " certificate information"; + } + } + + private static String sans(X509Certificate c, String separator) throws CertificateParsingException { + return String.join(separator, Optional.ofNullable(c.getSubjectAlternativeNames()) + .orElse(new ArrayList<>()) + .stream() + .map(v -> v.toString()) + .collect(Collectors.toList())); + } + + /** + * Human-readable representation of an X509 certificate extension. + *

+ * Common extensions are supported in a best-effort fashion, less commonly + * used extensions are displayed as an hexadecimal dump. + *

+ * Extensions come encoded as a DER Octet String, which itself can contain + * other DER-encoded objects, making a comprehensive support in this utility + * impossible. + * + * @param oid extension OID + * @param derOctetString the extension value as a DER octet string + * @param certificate the certificate + * @return the OID and the value + * @see A Layman's Guide to a Subset of ASN.1, BER, and DER + * @see DER Encoding of ASN.1 Types + */ + public static String extensionPrettyPrint(String oid, byte[] derOctetString, X509Certificate certificate) { + try { + return EXTENSIONS.getOrDefault(oid, (v, c) -> oid + " = " + hexDump(0, derOctetString)) + .apply(derOctetString, certificate); + } catch (Exception e) { + return oid + " = " + PARSING_ERROR; + } + } + + private static String extensions(X509Certificate certificate) { + List extensions = new ArrayList<>(); + for (String oid : certificate.getCriticalExtensionOIDs()) { + extensions.add(extensionPrettyPrint(oid, certificate.getExtensionValue(oid), certificate) + " (critical)"); + } + for (String oid : certificate.getNonCriticalExtensionOIDs()) { + extensions.add(extensionPrettyPrint(oid, certificate.getExtensionValue(oid), certificate) + " (non-critical)"); + } + return String.join(", ", extensions); + } + + private static String octetStringHexDump(byte[] derOctetString) { + // this is an octet string in a octet string, [4 total_length 4 length ...] + if (derOctetString.length > 4 && derOctetString[0] == 4 && derOctetString[2] == 4) { + return hexDump(4, derOctetString); + } else { + return hexDump(0, derOctetString); + } + } + + private static String hexDump(int start, byte[] derOctetString) { + List hexs = new ArrayList<>(); + for (int i = start; i < derOctetString.length; i++) { + hexs.add(String.format("%02X", derOctetString[i])); + } + return String.join(":", hexs); + } + + private static String keyUsageBitString(boolean[] keyUsage, byte[] derOctetString) { + if (keyUsage != null) { + List usage = new ArrayList<>(); + for (int i = 0; i < keyUsage.length; i++) { + if (keyUsage[i]) { + usage.add(KEY_USAGE.get(i)); + } + } + return String.join("/", usage); + } else { + return hexDump(0, derOctetString); + } + } + + private static String basicConstraints(byte[] derOctetString) { + if (derOctetString.length == 4 && derOctetString[3] == 0) { + // e.g. 04:02:30:00 [octet_string length sequence size] + return "CA:FALSE"; + } else if (derOctetString.length >= 7 && derOctetString[2] == 48 && derOctetString[4] == 1) { + // e.g. 04:05:30:03:01:01:FF [octet_string length sequence boolean length boolean_value] + return "CA:" + (derOctetString[6] == 0 ? "FALSE" : "TRUE"); + } else { + return hexDump(0, derOctetString); + } + } + + private static String authorityKeyIdentifier(byte[] derOctetString) { + if (derOctetString.length == 26 && derOctetString[0] == 04) { + // e.g. 04:18:30:16:80:14:FB:D2:7C:63:DF:7F:D4:A4:8E:9A:20:43:F5:DC:75:6F:B6:D8:51:6F + // [octet_string length sequence ?? ?? key_length key] + return "keyid:" + hexDump(6, derOctetString); + } else { + return hexDump(0, derOctetString); + } + + } + + private static String extendedKeyUsage(byte[] derOctetString, X509Certificate certificate) { + List extendedKeyUsage = null; + try { + extendedKeyUsage = certificate.getExtendedKeyUsage(); + if (extendedKeyUsage == null) { + return hexDump(0, derOctetString); + } else { + return String.join("/", extendedKeyUsage.stream() + .map(oid -> EXTENDED_KEY_USAGE.getOrDefault(oid, oid)) + .collect(Collectors.toList())); + } + } catch (CertificateParsingException e) { + return PARSING_ERROR; + } + } + +} diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java index c9e1ffb202..784a5f80cd 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java @@ -20,10 +20,14 @@ import com.rabbitmq.client.SslContextFactory; import com.rabbitmq.client.impl.AbstractFrameHandlerFactory; import com.rabbitmq.client.impl.FrameHandler; +import com.rabbitmq.client.impl.TlsUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLException; +import javax.net.ssl.SSLHandshakeException; import java.io.IOException; import java.net.InetSocketAddress; import java.net.SocketAddress; @@ -39,6 +43,8 @@ */ public class SocketChannelFrameHandlerFactory extends AbstractFrameHandlerFactory { + private static final Logger LOGGER = LoggerFactory.getLogger(SocketChannelFrameHandler.class); + final NioParams nioParams; private final SslContextFactory sslContextFactory; @@ -91,10 +97,17 @@ public FrameHandler create(Address addr, String connectionName) throws IOExcepti if (ssl) { sslEngine.beginHandshake(); - boolean handshake = SslEngineHelper.doHandshake(channel, sslEngine); - if (!handshake) { - throw new SSLException("TLS handshake failed"); + try { + boolean handshake = SslEngineHelper.doHandshake(channel, sslEngine); + if (!handshake) { + LOGGER.error("TLS connection failed"); + throw new SSLException("TLS handshake failed"); + } + } catch (SSLHandshakeException e) { + LOGGER.error("TLS connection failed: {}", e.getMessage()); + throw e; } + TlsUtils.logPeerCertificateInfo(sslEngine.getSession()); } channel.configureBlocking(false); diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index 998743d46b..0db46be963 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -69,7 +69,8 @@ NioDeadlockOnConnectionClosing.class, GeneratedClassesTest.class, RpcTopologyRecordingTest.class, - ConnectionTest.class + ConnectionTest.class, + TlsUtilsTest.class }) public class ClientTests { diff --git a/src/test/java/com/rabbitmq/client/test/TlsUtilsTest.java b/src/test/java/com/rabbitmq/client/test/TlsUtilsTest.java new file mode 100644 index 0000000000..e632e47282 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/TlsUtilsTest.java @@ -0,0 +1,123 @@ +// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.test; + +import org.junit.Test; +import org.mockito.Mockito; + +import java.security.cert.CertificateParsingException; +import java.security.cert.X509Certificate; +import java.util.Arrays; + +import static com.rabbitmq.client.impl.TlsUtils.extensionPrettyPrint; +import static org.assertj.core.api.Assertions.assertThat; + +public class TlsUtilsTest { + + static final byte [] DOES_NOT_MATTER = new byte[0]; + + @Test + public void subjectKeyIdentifier() { + // https://www.alvestrand.no/objectid/2.5.29.14.html + byte[] derOctetString = new byte[]{ + 4, 22, 4, 20, -2, -87, -45, -120, 29, -126, -88, -17, 95, -39, -122, 23, 10, -62, -54, -82, 113, -121, -70, -121 + }; // 04:16:04:14:FE:A9:D3:88:1D:82:A8:EF:5F:D9:86:17:0A:C2:CA:AE:71:87:BA:87 + assertThat(extensionPrettyPrint("2.5.29.14", derOctetString, null)) + .isEqualTo("SubjectKeyIdentifier = FE:A9:D3:88:1D:82:A8:EF:5F:D9:86:17:0A:C2:CA:AE:71:87:BA:87"); + // change the 3rd byte to mimic it's not a octet string, the whole array should be then hex-dumped + derOctetString = new byte[]{ + 4, 22, 3, 20, -2, -87, -45, -120, 29, -126, -88, -17, 95, -39, -122, 23, 10, -62, -54, -82, 113, -121, -70, -121 + }; // 04:16:04:14:FE:A9:D3:88:1D:82:A8:EF:5F:D9:86:17:0A:C2:CA:AE:71:87:BA:87 + assertThat(extensionPrettyPrint("2.5.29.14", derOctetString, null)) + .isEqualTo("SubjectKeyIdentifier = 04:16:03:14:FE:A9:D3:88:1D:82:A8:EF:5F:D9:86:17:0A:C2:CA:AE:71:87:BA:87"); + } + + @Test public void keyUsage() { + // https://www.alvestrand.no/objectid/2.5.29.15.html + // http://javadoc.iaik.tugraz.at/iaik_jce/current/iaik/asn1/BIT_STRING.html + X509Certificate c = Mockito.mock(X509Certificate.class); + Mockito.when(c.getKeyUsage()) + .thenReturn(new boolean[] {true,false,true,false,false,false,false,false,false}) + .thenReturn(new boolean[] {false,false,false,false,false,true,true,false,false}) + .thenReturn(null); + assertThat(extensionPrettyPrint("2.5.29.15", DOES_NOT_MATTER, c)) + .isEqualTo("KeyUsage = digitalSignature/keyEncipherment"); + assertThat(extensionPrettyPrint("2.5.29.15", DOES_NOT_MATTER, c)) + .isEqualTo("KeyUsage = keyCertSign/cRLSign"); + // change the 3rd byte to mimic it's not a bit string, the whole array should be then hex-dumped + byte[] derOctetString = new byte[] { 4, 4, 3, 2, 1, 6}; // 04:04:03:02:01:06 => Certificate Sign, CRL Sign + assertThat(extensionPrettyPrint("2.5.29.15", derOctetString, c)) + .isEqualTo("KeyUsage = 04:04:03:02:01:06"); + } + + @Test public void basicConstraints() { + // https://www.alvestrand.no/objectid/2.5.29.19.html + byte [] derOctetString = new byte [] {0x04, 0x02, 0x30, 0x00}; + assertThat(extensionPrettyPrint("2.5.29.19", derOctetString, null)) + .isEqualTo("BasicConstraints = CA:FALSE"); + derOctetString = new byte [] {4, 5, 48, 3, 1, 1, -1}; // 04:05:30:03:01:01:FF + assertThat(extensionPrettyPrint("2.5.29.19", derOctetString, null)) + .isEqualTo("BasicConstraints = CA:TRUE"); + derOctetString = new byte [] {4, 5, 48, 3, 1, 1, 0}; // 04:05:30:03:01:01:00 + assertThat(extensionPrettyPrint("2.5.29.19", derOctetString, null)) + .isEqualTo("BasicConstraints = CA:FALSE"); + // change the 3rd to mimic it's not what the utils expects, the whole array should be hex-dump + derOctetString = new byte [] {4, 5, 4, 3, 1, 1, 0}; // 04:05:04:03:01:01:00 + assertThat(extensionPrettyPrint("2.5.29.19", derOctetString, null)) + .isEqualTo("BasicConstraints = 04:05:04:03:01:01:00"); + + } + + @Test public void authorityKeyIdentifier() { + // https://www.alvestrand.no/objectid/2.5.29.35.html + byte[] derOctetString = new byte[]{ + 4,24,48,22,-128,20,-5,-46,124,99,-33,127,-44,-92,-114,-102,32,67,-11,-36,117,111,-74,-40,81,111 + }; // 04:18:30:16:80:14:FB:D2:7C:63:DF:7F:D4:A4:8E:9A:20:43:F5:DC:75:6F:B6:D8:51:6F + assertThat(extensionPrettyPrint("2.5.29.35", derOctetString, null)) + .isEqualTo("AuthorityKeyIdentifier = keyid:FB:D2:7C:63:DF:7F:D4:A4:8E:9A:20:43:F5:DC:75:6F:B6:D8:51:6F"); + + // add a byte to mimic not-expected length, the whole array should be hex-dump + derOctetString = new byte[]{ + 4,24,48,22,-128,20,-5,-46,124,99,-33,127,-44,-92,-114,-102,32,67,-11,-36,117,111,-74,-40,81,111, -1 + }; // 04:18:30:16:80:14:FB:D2:7C:63:DF:7F:D4:A4:8E:9A:20:43:F5:DC:75:6F:B6:D8:51:6F + assertThat(extensionPrettyPrint("2.5.29.35", derOctetString, null)) + .isEqualTo("AuthorityKeyIdentifier = 04:18:30:16:80:14:FB:D2:7C:63:DF:7F:D4:A4:8E:9A:20:43:F5:DC:75:6F:B6:D8:51:6F:FF"); + } + + @Test public void extendedKeyUsage() throws CertificateParsingException { + // https://www.alvestrand.no/objectid/2.5.29.37.html + X509Certificate c = Mockito.mock(X509Certificate.class); + Mockito.when(c.getExtendedKeyUsage()) + .thenReturn(Arrays.asList("1.3.6.1.5.5.7.3.1")) + .thenReturn(Arrays.asList("1.3.6.1.5.5.7.3.1", "1.3.6.1.5.5.7.3.2")) + .thenReturn(Arrays.asList("1.3.6.1.5.5.7.3.unknown")) + .thenReturn(null) + .thenThrow(CertificateParsingException.class); + + assertThat(extensionPrettyPrint("2.5.29.37", DOES_NOT_MATTER, c)) + .isEqualTo("ExtendedKeyUsage = TLS Web server authentication"); + assertThat(extensionPrettyPrint("2.5.29.37", DOES_NOT_MATTER, c)) + .isEqualTo("ExtendedKeyUsage = TLS Web server authentication/TLS Web client authentication"); + assertThat(extensionPrettyPrint("2.5.29.37", DOES_NOT_MATTER, c)) + .isEqualTo("ExtendedKeyUsage = 1.3.6.1.5.5.7.3.unknown"); + byte [] derOctetString = new byte[] {0x04, 0x0C, 0x30, 0x0A, 0x06, 0x08, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01}; + assertThat(extensionPrettyPrint("2.5.29.37", derOctetString, c)) + .isEqualTo("ExtendedKeyUsage = 04:0C:30:0A:06:08:2B:06:01:05:05:07:03:01"); + assertThat(extensionPrettyPrint("2.5.29.37", DOES_NOT_MATTER, c)) + .isEqualTo("ExtendedKeyUsage = "); + } + +} diff --git a/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java index 679468a59f..88107b41fe 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java @@ -33,7 +33,8 @@ BadVerifiedConnection.class, ConnectionFactoryDefaultTlsVersion.class, NioTlsUnverifiedConnection.class, - HostnameVerification.class + HostnameVerification.class, + TlsConnectionLogging.class }) public class SSLTests { diff --git a/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java b/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java new file mode 100644 index 0000000000..12ec082a4d --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java @@ -0,0 +1,71 @@ +// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.test.ssl; + +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.impl.TlsUtils; +import com.rabbitmq.client.test.TestUtils; +import org.assertj.core.api.Assertions; +import org.junit.Test; + +import javax.net.ssl.*; +import java.security.cert.X509Certificate; +import java.util.concurrent.atomic.AtomicReference; + +import static org.junit.Assert.assertNotNull; + +public class TlsConnectionLogging { + + @Test + public void certificateInfoAreProperlyExtracted() throws Exception { + SSLContext sslContext = TestUtils.getSSLContext(); + sslContext.init(null, new TrustManager[]{new AlwaysTrustTrustManager()}, null); + ConnectionFactory connectionFactory = TestUtils.connectionFactory(); + connectionFactory.useSslProtocol(sslContext); + connectionFactory.useBlockingIo(); + AtomicReference socketCaptor = new AtomicReference<>(); + connectionFactory.setSocketConfigurator(socket -> socketCaptor.set((SSLSocket) socket)); + try (Connection ignored = connectionFactory.newConnection()) { + SSLSession session = socketCaptor.get().getSession(); + assertNotNull(session); + String info = TlsUtils.peerCertificateInfo(session.getPeerCertificates()[0], "some prefix"); + Assertions.assertThat(info).contains("some prefix") + .contains("CN=") + .contains("X.509 usage extensions") + .contains("KeyUsage"); + + } + } + + private static class AlwaysTrustTrustManager implements X509TrustManager { + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) { + + } + + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) { + + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } + } + +} From 106bade4917e47e39f334786836dfbd10674c5e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 13 Feb 2019 10:59:38 +0100 Subject: [PATCH 1046/2114] Add NIO test case for TLS connection info logging [#163862785] References #441 --- .../client/test/ssl/TlsConnectionLogging.java | 39 +++++++++++++++++-- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java b/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java index 12ec082a4d..363d749dde 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java @@ -18,29 +18,60 @@ import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.impl.TlsUtils; +import com.rabbitmq.client.impl.nio.NioParams; import com.rabbitmq.client.test.TestUtils; import org.assertj.core.api.Assertions; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; import javax.net.ssl.*; import java.security.cert.X509Certificate; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; +import java.util.function.Supplier; import static org.junit.Assert.assertNotNull; +@RunWith(Parameterized.class) public class TlsConnectionLogging { + @Parameterized.Parameter + public Function> configurer; + + @Parameterized.Parameters + public static Object[] data() { + return new Object[]{blockingIo(), nio()}; + } + + public static Function> blockingIo() { + return connectionFactory -> { + connectionFactory.useBlockingIo(); + AtomicReference socketCaptor = new AtomicReference<>(); + connectionFactory.setSocketConfigurator(socket -> socketCaptor.set((SSLSocket) socket)); + return () -> socketCaptor.get().getSession(); + }; + } + + public static Function> nio() { + return connectionFactory -> { + connectionFactory.useNio(); + AtomicReference sslEngineCaptor = new AtomicReference<>(); + connectionFactory.setNioParams(new NioParams() + .setSslEngineConfigurator(sslEngine -> sslEngineCaptor.set(sslEngine))); + return () -> sslEngineCaptor.get().getSession(); + }; + } + @Test public void certificateInfoAreProperlyExtracted() throws Exception { SSLContext sslContext = TestUtils.getSSLContext(); sslContext.init(null, new TrustManager[]{new AlwaysTrustTrustManager()}, null); ConnectionFactory connectionFactory = TestUtils.connectionFactory(); connectionFactory.useSslProtocol(sslContext); - connectionFactory.useBlockingIo(); - AtomicReference socketCaptor = new AtomicReference<>(); - connectionFactory.setSocketConfigurator(socket -> socketCaptor.set((SSLSocket) socket)); + Supplier sslSessionSupplier = configurer.apply(connectionFactory); try (Connection ignored = connectionFactory.newConnection()) { - SSLSession session = socketCaptor.get().getSession(); + SSLSession session = sslSessionSupplier.get(); assertNotNull(session); String info = TlsUtils.peerCertificateInfo(session.getPeerCertificates()[0], "some prefix"); Assertions.assertThat(info).contains("some prefix") From ebb82edd848e270a7133ac9b771b24b933da7d42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 13 Feb 2019 10:59:38 +0100 Subject: [PATCH 1047/2114] Add NIO test case for TLS connection info logging [#163862785] References #441 (cherry picked from commit 106bade4917e47e39f334786836dfbd10674c5e7) --- .../client/test/ssl/TlsConnectionLogging.java | 39 +++++++++++++++++-- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java b/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java index 12ec082a4d..363d749dde 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java @@ -18,29 +18,60 @@ import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.impl.TlsUtils; +import com.rabbitmq.client.impl.nio.NioParams; import com.rabbitmq.client.test.TestUtils; import org.assertj.core.api.Assertions; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; import javax.net.ssl.*; import java.security.cert.X509Certificate; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; +import java.util.function.Supplier; import static org.junit.Assert.assertNotNull; +@RunWith(Parameterized.class) public class TlsConnectionLogging { + @Parameterized.Parameter + public Function> configurer; + + @Parameterized.Parameters + public static Object[] data() { + return new Object[]{blockingIo(), nio()}; + } + + public static Function> blockingIo() { + return connectionFactory -> { + connectionFactory.useBlockingIo(); + AtomicReference socketCaptor = new AtomicReference<>(); + connectionFactory.setSocketConfigurator(socket -> socketCaptor.set((SSLSocket) socket)); + return () -> socketCaptor.get().getSession(); + }; + } + + public static Function> nio() { + return connectionFactory -> { + connectionFactory.useNio(); + AtomicReference sslEngineCaptor = new AtomicReference<>(); + connectionFactory.setNioParams(new NioParams() + .setSslEngineConfigurator(sslEngine -> sslEngineCaptor.set(sslEngine))); + return () -> sslEngineCaptor.get().getSession(); + }; + } + @Test public void certificateInfoAreProperlyExtracted() throws Exception { SSLContext sslContext = TestUtils.getSSLContext(); sslContext.init(null, new TrustManager[]{new AlwaysTrustTrustManager()}, null); ConnectionFactory connectionFactory = TestUtils.connectionFactory(); connectionFactory.useSslProtocol(sslContext); - connectionFactory.useBlockingIo(); - AtomicReference socketCaptor = new AtomicReference<>(); - connectionFactory.setSocketConfigurator(socket -> socketCaptor.set((SSLSocket) socket)); + Supplier sslSessionSupplier = configurer.apply(connectionFactory); try (Connection ignored = connectionFactory.newConnection()) { - SSLSession session = socketCaptor.get().getSession(); + SSLSession session = sslSessionSupplier.get(); assertNotNull(session); String info = TlsUtils.peerCertificateInfo(session.getPeerCertificates()[0], "some prefix"); Assertions.assertThat(info).contains("some prefix") From f3a50edb95381f91894a19eeb2b4d1758bfa58be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 13 Feb 2019 11:03:54 +0100 Subject: [PATCH 1048/2114] Fix test with NioParams correct usage for this branch --- .../com/rabbitmq/client/test/ssl/TlsConnectionLogging.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java b/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java index 363d749dde..6eb865ea41 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java @@ -57,8 +57,9 @@ public static Function> nio() { return connectionFactory -> { connectionFactory.useNio(); AtomicReference sslEngineCaptor = new AtomicReference<>(); - connectionFactory.setNioParams(new NioParams() - .setSslEngineConfigurator(sslEngine -> sslEngineCaptor.set(sslEngine))); + NioParams nioParams = new NioParams(); + nioParams.setSslEngineConfigurator(sslEngine -> sslEngineCaptor.set(sslEngine)); + connectionFactory.setNioParams(nioParams); return () -> sslEngineCaptor.get().getSession(); }; } From 0c25c3c5023a664812477128354da717b4018af9 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Thu, 28 Feb 2019 16:02:23 +0300 Subject: [PATCH 1049/2114] Squash a few IDEA warnings in AMQChannel --- .../com/rabbitmq/client/impl/AMQChannel.java | 58 +++++++++---------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java index 3cdcf8c50f..b3ba519da8 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java @@ -46,14 +46,14 @@ public abstract class AMQChannel extends ShutdownNotifierComponent { private static final Logger LOGGER = LoggerFactory.getLogger(AMQChannel.class); - protected static final int NO_RPC_TIMEOUT = 0; + static final int NO_RPC_TIMEOUT = 0; /** * Protected; used instead of synchronizing on the channel itself, * so that clients can themselves use the channel to synchronize * on. */ - protected final Object _channelMutex = new Object(); + final Object _channelMutex = new Object(); /** The connection this channel is associated with. */ private final AMQConnection _connection; @@ -68,10 +68,10 @@ public abstract class AMQChannel extends ShutdownNotifierComponent { private RpcWrapper _activeRpc = null; /** Whether transmission of content-bearing methods should be blocked */ - protected volatile boolean _blockContent = false; + volatile boolean _blockContent = false; /** Timeout for RPC calls */ - protected final int _rpcTimeout; + final int _rpcTimeout; private final boolean _checkRpcResponseType; @@ -107,7 +107,7 @@ public int getChannelNumber() { * @param frame the incoming frame * @throws IOException if an error is encountered */ - public void handleFrame(Frame frame) throws IOException { + void handleFrame(Frame frame) throws IOException { AMQCommand command = _command; if (command.handleFrame(frame)) { // a complete command has rolled off the assembly line _command = new AMQCommand(); // prepare for the next one @@ -126,9 +126,7 @@ public static IOException wrap(ShutdownSignalException ex) { } public static IOException wrap(ShutdownSignalException ex, String message) { - IOException ioe = new IOException(message); - ioe.initCause(ex); - return ioe; + return new IOException(message, ex); } /** @@ -148,7 +146,7 @@ public AMQCommand exnWrappingRpc(Method m) } } - public CompletableFuture exnWrappingAsyncRpc(Method m) + CompletableFuture exnWrappingAsyncRpc(Method m) throws IOException { try { @@ -167,7 +165,7 @@ public CompletableFuture exnWrappingAsyncRpc(Method m) * @throws IOException if there's any problem * * @param command the incoming command - * @throws IOException + * @throws IOException when operation is interrupted by an I/O exception */ public void handleCompleteInboundCommand(AMQCommand command) throws IOException { // First, offer the command to the asynchronous-command @@ -208,7 +206,7 @@ public void enqueueRpc(RpcContinuation k) doEnqueueRpc(() -> new RpcContinuationRpcWrapper(k)); } - public void enqueueAsyncRpc(Method method, CompletableFuture future) { + private void enqueueAsyncRpc(Method method, CompletableFuture future) { doEnqueueRpc(() -> new CompletableFutureRpcWrapper(method, future)); } @@ -230,7 +228,7 @@ private void doEnqueueRpc(Supplier rpcWrapperSupplier) { } } - public boolean isOutstandingRpc() + boolean isOutstandingRpc() { synchronized (_channelMutex) { return (_activeRpc != null); @@ -251,7 +249,7 @@ protected void markRpcFinished() { // no-op } - public void ensureIsOpen() + private void ensureIsOpen() throws AlreadyClosedException { if (!isOpen()) { @@ -308,7 +306,7 @@ private void cleanRpcChannelState() { } /** Cleans RPC channel state after a timeout and wraps the TimeoutException in a ChannelContinuationTimeoutException */ - protected ChannelContinuationTimeoutException wrapTimeoutException(final Method m, final TimeoutException e) { + ChannelContinuationTimeoutException wrapTimeoutException(final Method m, final TimeoutException e) { cleanRpcChannelState(); return new ChannelContinuationTimeoutException(e, this, this._channelNumber, m); } @@ -343,7 +341,7 @@ public void rpc(Method m, RpcContinuation k) } } - public void quiescingRpc(Method m, RpcContinuation k) + void quiescingRpc(Method m, RpcContinuation k) throws IOException { synchronized (_channelMutex) { @@ -352,7 +350,7 @@ public void quiescingRpc(Method m, RpcContinuation k) } } - public void asyncRpc(Method m, CompletableFuture future) + private void asyncRpc(Method m, CompletableFuture future) throws IOException { synchronized (_channelMutex) { @@ -361,7 +359,7 @@ public void asyncRpc(Method m, CompletableFuture future) } } - public void quiescingAsyncRpc(Method m, CompletableFuture future) + private void quiescingAsyncRpc(Method m, CompletableFuture future) throws IOException { synchronized (_channelMutex) { @@ -409,33 +407,33 @@ public void processShutdownSignal(ShutdownSignalException signal, } } - public void notifyOutstandingRpc(ShutdownSignalException signal) { + void notifyOutstandingRpc(ShutdownSignalException signal) { RpcWrapper k = nextOutstandingRpc(); if (k != null) { k.shutdown(signal); } } - public void transmit(Method m) throws IOException { + protected void transmit(Method m) throws IOException { synchronized (_channelMutex) { transmit(new AMQCommand(m)); } } - public void transmit(AMQCommand c) throws IOException { + void transmit(AMQCommand c) throws IOException { synchronized (_channelMutex) { ensureIsOpen(); quiescingTransmit(c); } } - public void quiescingTransmit(Method m) throws IOException { + void quiescingTransmit(Method m) throws IOException { synchronized (_channelMutex) { quiescingTransmit(new AMQCommand(m)); } } - public void quiescingTransmit(AMQCommand c) throws IOException { + private void quiescingTransmit(AMQCommand c) throws IOException { synchronized (_channelMutex) { if (c.getMethod().hasContent()) { while (_blockContent) { @@ -468,16 +466,16 @@ public interface RpcContinuation { } public static abstract class BlockingRpcContinuation implements RpcContinuation { - public final BlockingValueOrException _blocker = - new BlockingValueOrException(); + final BlockingValueOrException _blocker = + new BlockingValueOrException<>(); protected final Method request; - public BlockingRpcContinuation() { + BlockingRpcContinuation() { request = null; } - public BlockingRpcContinuation(final Method request) { + BlockingRpcContinuation(final Method request) { this.request = request; } @@ -496,7 +494,7 @@ public T getReply() throws ShutdownSignalException return _blocker.uninterruptibleGetValue(); } - public T getReply(int timeout) + T getReply(int timeout) throws ShutdownSignalException, TimeoutException { return _blocker.uninterruptibleGetValue(timeout); @@ -509,7 +507,7 @@ public boolean canHandleReply(AMQCommand command) { public abstract T transformReply(AMQCommand command); - public static boolean isResponseCompatibleWithRequest(Method request, Method response) { + static boolean isResponseCompatibleWithRequest(Method request, Method response) { // make a best effort attempt to ensure the reply was intended for this rpc request // Ideally each rpc request would tag an id on it that could be returned and referenced on its reply. // But because that would be a very large undertaking to add passively this logic at least protects against ClassCastExceptions @@ -570,11 +568,11 @@ public static class SimpleBlockingRpcContinuation extends BlockingRpcContinuation { - public SimpleBlockingRpcContinuation() { + SimpleBlockingRpcContinuation() { super(); } - public SimpleBlockingRpcContinuation(final Method method) { + SimpleBlockingRpcContinuation(final Method method) { super(method); } From dae7b13849a929d653c9bec62d782914e6644f8c Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Thu, 28 Feb 2019 16:23:21 +0300 Subject: [PATCH 1050/2114] Update a few tests to explicitly delete queues Due to changes in [1] argument mismatch that involves the exclusive property can report a different channel exception (406 LOCKED). Since it has nothing to do with dead-lettering, switching to cleaning up queues manually and relying on their non-durability e.g. between CI runs is sufficient. Spotted by @acogoluegnes. 1. https://github.com/rabbitmq/rabbitmq-server/commit/bd46898b5923c92873f4b9ff0c3ac9df3cb0a1aa --- .../client/test/functional/DeadLetterExchange.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java index cfaff5f47d..e76e866bd2 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java @@ -29,13 +29,13 @@ public class DeadLetterExchange extends BrokerTestCase { public static final String DLX = "dead.letter.exchange"; - public static final String DLX_ARG = "x-dead-letter-exchange"; - public static final String DLX_RK_ARG = "x-dead-letter-routing-key"; + private static final String DLX_ARG = "x-dead-letter-exchange"; + private static final String DLX_RK_ARG = "x-dead-letter-routing-key"; public static final String TEST_QUEUE_NAME = "test.queue.dead.letter"; public static final String DLQ = "queue.dlq"; - public static final String DLQ2 = "queue.dlq2"; + private static final String DLQ2 = "queue.dlq2"; public static final int MSG_COUNT = 10; - public static final int TTL = 1000; + private static final int TTL = 1000; @Override protected void createResources() throws IOException { @@ -48,6 +48,7 @@ protected void createResources() throws IOException { @Override protected void releaseResources() throws IOException { channel.exchangeDelete(DLX); + channel.queueDelete(TEST_QUEUE_NAME); } @Test public void declareQueueWithExistingDeadLetterExchange() @@ -614,7 +615,7 @@ private void declareQueue(String queue, Object deadLetterExchange, if (deadLetterRoutingKey != null) { args.put(DLX_RK_ARG, deadLetterRoutingKey); } - channel.queueDeclare(queue, false, true, false, args); + channel.queueDeclare(queue, false, false, false, args); } private void publishN(int n) throws IOException { From 8fa6760f1b37abfa2b8dda9fa6a40b022dacc1bb Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Thu, 28 Feb 2019 16:29:48 +0300 Subject: [PATCH 1051/2114] Squash a few more IDEA warnings --- .../test/functional/DeadLetterExchange.java | 227 ++++++++---------- 1 file changed, 100 insertions(+), 127 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java index e76e866bd2..f78bd7a264 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java @@ -77,9 +77,7 @@ protected void releaseResources() throws IOException { declareQueue(TEST_QUEUE_NAME, DLX, "routing_key", null); } - @Test public void declareQueueWithInvalidDeadLetterExchangeArg() - throws IOException - { + @Test public void declareQueueWithInvalidDeadLetterExchangeArg() { try { declareQueue(133); fail("x-dead-letter-exchange must be a valid exchange name"); @@ -101,9 +99,7 @@ protected void releaseResources() throws IOException { } } - @Test public void declareQueueWithInvalidDeadLetterRoutingKeyArg() - throws IOException - { + @Test public void declareQueueWithInvalidDeadLetterRoutingKeyArg() { try { declareQueue("foo", "amq.direct", 144, null); fail("x-dead-letter-routing-key must be a string"); @@ -125,11 +121,9 @@ protected void releaseResources() throws IOException { } } - @Test public void declareQueueWithRoutingKeyButNoDeadLetterExchange() - throws IOException - { + @Test public void declareQueueWithRoutingKeyButNoDeadLetterExchange() { try { - Map args = new HashMap(); + Map args = new HashMap<>(); args.put(DLX_RK_ARG, "foo"); channel.queueDeclare(randomQueueName(), false, true, false, args); @@ -139,11 +133,10 @@ protected void releaseResources() throws IOException { } } - @Test public void redeclareQueueWithRoutingKeyButNoDeadLetterExchange() - throws IOException, InterruptedException { + @Test public void redeclareQueueWithRoutingKeyButNoDeadLetterExchange() { try { String queueName = randomQueueName(); - Map args = new HashMap(); + Map args = new HashMap<>(); channel.queueDeclare(queueName, false, true, false, args); args.put(DLX_RK_ARG, "foo"); @@ -165,7 +158,7 @@ protected void releaseResources() throws IOException { } @Test public void deadLetterQueueTTLPromptExpiry() throws Exception { - Map args = new HashMap(); + Map args = new HashMap<>(); args.put("x-message-ttl", TTL); declareQueue(TEST_QUEUE_NAME, DLX, null, args); channel.queueBind(TEST_QUEUE_NAME, "amq.direct", "test"); @@ -205,7 +198,7 @@ protected void releaseResources() throws IOException { publishAt(start); basicGet(TEST_QUEUE_NAME); // publish a 2nd message and immediately fetch it in ack mode - publishAt(start + TTL * 1 / 2); + publishAt(start + TTL / 2); GetResponse r = channel.basicGet(TEST_QUEUE_NAME, false); // publish a 3rd message publishAt(start + TTL * 3 / 4); @@ -250,20 +243,17 @@ protected void releaseResources() throws IOException { // the DLQ *AND* should remain there, not getting removed after a subsequent // wait time > 100ms sleep(500); - consumeN(DLQ, 1, new WithResponse() { - @SuppressWarnings("unchecked") - public void process(GetResponse getResponse) { - assertNull(getResponse.getProps().getExpiration()); - Map headers = getResponse.getProps().getHeaders(); - assertNotNull(headers); - ArrayList death = (ArrayList)headers.get("x-death"); - assertNotNull(death); - assertDeathReason(death, 0, TEST_QUEUE_NAME, "expired"); - final Map deathHeader = - (Map)death.get(0); - assertEquals("100", deathHeader.get("original-expiration").toString()); - } - }); + consumeN(DLQ, 1, getResponse -> { + assertNull(getResponse.getProps().getExpiration()); + Map headers = getResponse.getProps().getHeaders(); + assertNotNull(headers); + ArrayList death = (ArrayList)headers.get("x-death"); + assertNotNull(death); + assertDeathReason(death, 0, TEST_QUEUE_NAME, "expired"); + final Map deathHeader = + (Map)death.get(0); + assertEquals("100", deathHeader.get("original-expiration").toString()); + }); } @Test public void deadLetterOnReject() throws Exception { @@ -315,23 +305,20 @@ public void process(GetResponse getResponse) { // There should now be two copies of each message on DLQ2: one // with one set of death headers, and another with two sets. - consumeN(DLQ2, MSG_COUNT*2, new WithResponse() { - @SuppressWarnings("unchecked") - public void process(GetResponse getResponse) { - Map headers = getResponse.getProps().getHeaders(); - assertNotNull(headers); - ArrayList death = (ArrayList)headers.get("x-death"); - assertNotNull(death); - if (death.size() == 1) { - assertDeathReason(death, 0, TEST_QUEUE_NAME, "expired"); - } else if (death.size() == 2) { - assertDeathReason(death, 0, DLQ, "expired"); - assertDeathReason(death, 1, TEST_QUEUE_NAME, "expired"); - } else { - fail("message was dead-lettered more times than expected"); - } - } - }); + consumeN(DLQ2, MSG_COUNT*2, getResponse -> { + Map headers = getResponse.getProps().getHeaders(); + assertNotNull(headers); + ArrayList death = (ArrayList)headers.get("x-death"); + assertNotNull(death); + if (death.size() == 1) { + assertDeathReason(death, 0, TEST_QUEUE_NAME, "expired"); + } else if (death.size() == 2) { + assertDeathReason(death, 0, DLQ, "expired"); + assertDeathReason(death, 1, TEST_QUEUE_NAME, "expired"); + } else { + fail("message was dead-lettered more times than expected"); + } + }); } @Test public void deadLetterSelf() throws Exception { @@ -379,9 +366,9 @@ public void handleDelivery(String consumerTag, Envelope envelope, channel.queueBind(DLQ, DLX, "test"); channel.queueBind(DLQ2, DLX, "test-other"); - Map headers = new HashMap(); - headers.put("CC", Arrays.asList("foo")); - headers.put("BCC", Arrays.asList("bar")); + Map headers = new HashMap<>(); + headers.put("CC", Collections.singletonList("foo")); + headers.put("BCC", Collections.singletonList("bar")); publishN(MSG_COUNT, (new AMQP.BasicProperties.Builder()) .headers(headers) @@ -390,27 +377,24 @@ public void handleDelivery(String consumerTag, Envelope envelope, sleep(100); consumeN(DLQ, 0, WithResponse.NULL); - consumeN(DLQ2, MSG_COUNT, new WithResponse() { - @SuppressWarnings("unchecked") - public void process(GetResponse getResponse) { - Map headers = getResponse.getProps().getHeaders(); - assertNotNull(headers); - assertNull(headers.get("CC")); - assertNull(headers.get("BCC")); - - ArrayList death = (ArrayList)headers.get("x-death"); - assertNotNull(death); - assertEquals(1, death.size()); - assertDeathReason(death, 0, TEST_QUEUE_NAME, - "expired", "amq.direct", - Arrays.asList("test", "foo")); - } - }); + consumeN(DLQ2, MSG_COUNT, getResponse -> { + Map headers1 = getResponse.getProps().getHeaders(); + assertNotNull(headers1); + assertNull(headers1.get("CC")); + assertNull(headers1.get("BCC")); + + ArrayList death = (ArrayList) headers1.get("x-death"); + assertNotNull(death); + assertEquals(1, death.size()); + assertDeathReason(death, 0, TEST_QUEUE_NAME, + "expired", "amq.direct", + Arrays.asList("test", "foo")); + }); } @SuppressWarnings("unchecked") @Test public void republish() throws Exception { - Map args = new HashMap(); + Map args = new HashMap<>(); args.put("x-message-ttl", 100); declareQueue(TEST_QUEUE_NAME, DLX, null, args); channel.queueBind(TEST_QUEUE_NAME, "amq.direct", "test"); @@ -430,10 +414,10 @@ public void process(GetResponse getResponse) { assertNotNull(death); assertEquals(1, death.size()); assertDeathReason(death, 0, TEST_QUEUE_NAME, "expired", "amq.direct", - Arrays.asList("test")); + Collections.singletonList("test")); // Make queue zero length - args = new HashMap(); + args = new HashMap<>(); args.put("x-max-length", 0); channel.queueDelete(TEST_QUEUE_NAME); declareQueue(TEST_QUEUE_NAME, DLX, null, args); @@ -457,9 +441,9 @@ public void process(GetResponse getResponse) { assertNotNull(death); assertEquals(2, death.size()); assertDeathReason(death, 0, TEST_QUEUE_NAME, "maxlen", "amq.direct", - Arrays.asList("test")); + Collections.singletonList("test")); assertDeathReason(death, 1, TEST_QUEUE_NAME, "expired", "amq.direct", - Arrays.asList("test")); + Collections.singletonList("test")); //Set invalid headers headers.put("x-death", "[I, am, not, array]"); @@ -478,26 +462,24 @@ public void process(GetResponse getResponse) { assertNotNull(death); assertEquals(1, death.size()); assertDeathReason(death, 0, TEST_QUEUE_NAME, "maxlen", "amq.direct", - Arrays.asList("test")); - - } - - public void rejectionTest(final boolean useNack) throws Exception { - deadLetterTest(new Callable() { - public Void call() throws Exception { - for (int x = 0; x < MSG_COUNT; x++) { - GetResponse getResponse = - channel.basicGet(TEST_QUEUE_NAME, false); - long tag = getResponse.getEnvelope().getDeliveryTag(); - if (useNack) { - channel.basicNack(tag, false, false); - } else { - channel.basicReject(tag, false); - } - } - return null; + Collections.singletonList("test")); + + } + + private void rejectionTest(final boolean useNack) throws Exception { + deadLetterTest((Callable) () -> { + for (int x = 0; x < MSG_COUNT; x++) { + GetResponse getResponse = + channel.basicGet(TEST_QUEUE_NAME, false); + long tag = getResponse.getEnvelope().getDeliveryTag(); + if (useNack) { + channel.basicNack(tag, false, false); + } else { + channel.basicReject(tag, false); } - }, null, "rejected"); + } + return null; + }, null, "rejected"); } private void deadLetterTest(final Runnable deathTrigger, @@ -505,12 +487,10 @@ private void deadLetterTest(final Runnable deathTrigger, String reason) throws Exception { - deadLetterTest(new Callable() { - public Object call() throws Exception { - deathTrigger.run(); - return null; - } - }, queueDeclareArgs, reason); + deadLetterTest(() -> { + deathTrigger.run(); + return null; + }, queueDeclareArgs, reason); } private void deadLetterTest(Callable deathTrigger, @@ -531,35 +511,30 @@ private void deadLetterTest(Callable deathTrigger, } public static void consume(final Channel channel, final String reason) throws IOException { - consumeN(channel, DLQ, MSG_COUNT, new WithResponse() { - @SuppressWarnings("unchecked") - public void process(GetResponse getResponse) { - Map headers = getResponse.getProps().getHeaders(); - assertNotNull(headers); - ArrayList death = (ArrayList) headers.get("x-death"); - assertNotNull(death); - // the following assertions shouldn't be checked on version lower than 3.7 - // as the headers are new in 3.7 - // see https://github.com/rabbitmq/rabbitmq-server/issues/1332 - if(TestUtils.isVersion37orLater(channel.getConnection())) { - assertNotNull(headers.get("x-first-death-queue")); - assertNotNull(headers.get("x-first-death-reason")); - assertNotNull(headers.get("x-first-death-exchange")); - } - assertEquals(1, death.size()); - assertDeathReason(death, 0, TEST_QUEUE_NAME, reason, - "amq.direct", - Arrays.asList("test")); + consumeN(channel, DLQ, MSG_COUNT, getResponse -> { + Map headers = getResponse.getProps().getHeaders(); + assertNotNull(headers); + ArrayList death = (ArrayList) headers.get("x-death"); + assertNotNull(death); + // the following assertions shouldn't be checked on version lower than 3.7 + // as the headers are new in 3.7 + // see https://github.com/rabbitmq/rabbitmq-server/issues/1332 + if(TestUtils.isVersion37orLater(channel.getConnection())) { + assertNotNull(headers.get("x-first-death-queue")); + assertNotNull(headers.get("x-first-death-reason")); + assertNotNull(headers.get("x-first-death-exchange")); } + assertEquals(1, death.size()); + assertDeathReason(death, 0, TEST_QUEUE_NAME, reason, + "amq.direct", + Collections.singletonList("test")); }); } private void ttlTest(final long ttl) throws Exception { Map args = new HashMap(); args.put("x-message-ttl", ttl); - deadLetterTest(new Runnable() { - public void run() { sleep(ttl + 1500); } - }, args, "expired"); + deadLetterTest(() -> sleep(ttl + 1500), args, "expired"); } private void sleep(long millis) { @@ -604,7 +579,7 @@ private void declareQueue(String queue, Object deadLetterExchange, throws IOException { if (args == null) { - args = new HashMap(); + args = new HashMap<>(); } if (ttl > 0){ @@ -674,7 +649,7 @@ private static void assertDeathReason(List death, int num, (Map)death.get(num); assertEquals(exchange, deathHeader.get("exchange").toString()); - List deathRKs = new ArrayList(); + List deathRKs = new ArrayList<>(); for (Object rk : (ArrayList)deathHeader.get("routing-keys")) { deathRKs.add(rk.toString()); } @@ -694,13 +669,11 @@ private static void assertDeathReason(List death, int num, assertEquals(reason, deathHeader.get("reason").toString()); } - private static interface WithResponse { - static final WithResponse NULL = new WithResponse() { - public void process(GetResponse getResponse) { - } - }; + private interface WithResponse { + WithResponse NULL = getResponse -> { + }; - public void process(GetResponse response); + void process(GetResponse response); } private static String randomQueueName() { @@ -709,9 +682,9 @@ private static String randomQueueName() { class AccumulatingMessageConsumer extends DefaultConsumer { - BlockingQueue messages = new LinkedBlockingQueue(); + BlockingQueue messages = new LinkedBlockingQueue<>(); - public AccumulatingMessageConsumer(Channel channel) { + AccumulatingMessageConsumer(Channel channel) { super(channel); } From 6a6b26c309aa77f6050eeeef088f75ddefe9a9e3 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Thu, 28 Feb 2019 17:01:11 +0300 Subject: [PATCH 1052/2114] AMQConnection: squash a few more IDEA warnings --- .../rabbitmq/client/impl/AMQConnection.java | 41 ++++++++----------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index 48949b4ca4..5f059edff9 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -50,7 +50,7 @@ public class AMQConnection extends ShutdownNotifierComponent implements Connecti private static final Logger LOGGER = LoggerFactory.getLogger(AMQConnection.class); // we want socket write and channel shutdown timeouts to kick in after // the heartbeat one, so we use a value of 105% of the effective heartbeat timeout - public static final double CHANNEL_SHUTDOWN_TIMEOUT_MULTIPLIER = 1.05; + static final double CHANNEL_SHUTDOWN_TIMEOUT_MULTIPLIER = 1.05; private final ExecutorService consumerWorkServiceExecutor; private final ScheduledExecutorService heartbeatExecutor; @@ -60,7 +60,7 @@ public class AMQConnection extends ShutdownNotifierComponent implements Connecti private String id; private final List recoveryCanBeginListeners = - Collections.synchronizedList(new ArrayList()); + Collections.synchronizedList(new ArrayList<>()); private final ErrorOnWriteListener errorOnWriteListener; @@ -77,14 +77,14 @@ public class AMQConnection extends ShutdownNotifierComponent implements Connecti * @see Connection#getClientProperties */ public static Map defaultClientProperties() { - Map props = new HashMap(); + Map props = new HashMap<>(); props.put("product", LongStringHelper.asLongString("RabbitMQ")); props.put("version", LongStringHelper.asLongString(ClientVersion.VERSION)); props.put("platform", LongStringHelper.asLongString("Java")); props.put("copyright", LongStringHelper.asLongString(Copyright.COPYRIGHT)); props.put("information", LongStringHelper.asLongString(Copyright.LICENSE)); - Map capabilities = new HashMap(); + Map capabilities = new HashMap<>(); capabilities.put("publisher_confirms", true); capabilities.put("exchange_exchange_bindings", true); capabilities.put("basic.nack", true); @@ -117,7 +117,7 @@ public static Map defaultClientProperties() { /** Object used for blocking main application thread when doing all the necessary * connection shutdown operations */ - private final BlockingCell _appContinuation = new BlockingCell(); + private final BlockingCell _appContinuation = new BlockingCell<>(); /** Flag indicating whether the client received Connection.Close message from the broker */ private volatile boolean _brokerInitiatedShutdown; @@ -137,7 +137,7 @@ public static Map defaultClientProperties() { private final int handshakeTimeout; private final int shutdownTimeout; private final CredentialsProvider credentialsProvider; - private final Collection blockedListeners = new CopyOnWriteArrayList(); + private final Collection blockedListeners = new CopyOnWriteArrayList<>(); protected final MetricsCollector metricsCollector; private final int channelRpcTimeout; private final boolean channelShouldCheckRpcResponseType; @@ -157,10 +157,10 @@ public static Map defaultClientProperties() { private volatile Map _serverProperties; /** - * Protected API - respond, in the driver thread, to a ShutdownSignal. + * Protected API - respond, in the main I/O loop thread, to a ShutdownSignal. * @param channel the channel to disconnect */ - public final void disconnectChannel(ChannelN channel) { + final void disconnectChannel(ChannelN channel) { ChannelManager cm = _channelManager; if (cm != null) cm.releaseChannelNumber(channel); @@ -367,15 +367,12 @@ public void start() throw new PossibleAuthenticationFailureException(e); } } while (connTune == null); - } catch (TimeoutException te) { + } catch (TimeoutException | IOException te) { _frameHandler.close(); throw te; } catch (ShutdownSignalException sse) { _frameHandler.close(); throw AMQChannel.wrap(sse); - } catch(IOException ioe) { - _frameHandler.close(); - throw ioe; } try { @@ -509,7 +506,7 @@ public ThreadFactory getThreadFactory() { @Override public Map getClientProperties() { - return new HashMap(_clientProperties); + return new HashMap<>(_clientProperties); } @Override @@ -560,7 +557,7 @@ public Channel createChannel() throws IOException { /** * Public API - sends a frame directly to the broker. */ - public void writeFrame(Frame f) throws IOException { + void writeFrame(Frame f) throws IOException { _frameHandler.writeFrame(f); _heartbeatSender.signalActivity(); } @@ -755,6 +752,7 @@ public void addRecoveryCanBeginListener(RecoveryCanBeginListener fn) { this.recoveryCanBeginListeners.add(fn); } + @SuppressWarnings("unused") public void removeRecoveryCanBeginListener(RecoveryCanBeginListener fn) { this.recoveryCanBeginListeners.remove(fn); } @@ -842,7 +840,7 @@ public boolean processControlCommand(Command c) throws IOException } } - public void handleConnectionClose(Command closeCommand) { + private void handleConnectionClose(Command closeCommand) { ShutdownSignalException sse = shutdown(closeCommand.getMethod(), false, null, _inConnectionNegotiation); try { _channel0.quiescingTransmit(new AMQP.Connection.CloseOk.Builder().build()); @@ -863,13 +861,13 @@ public void handleConnectionClose(Command closeCommand) { } } - // same as ConnectionFactory.DEFAULT_SHUTDOWN_TIMEOUT - private static long SOCKET_CLOSE_TIMEOUT = 10000; - private class SocketCloseWait implements Runnable { + // same as ConnectionFactory.DEFAULT_SHUTDOWN_TIMEOUT + private long SOCKET_CLOSE_TIMEOUT = 10000; + private final ShutdownSignalException cause; - public SocketCloseWait(ShutdownSignalException sse) { + SocketCloseWait(ShutdownSignalException sse) { cause = sse; } @@ -1055,12 +1053,9 @@ public AMQCommand transformReply(AMQCommand command) { sse.initCause(cause); throw sse; } - } catch (ShutdownSignalException sse) { + } catch (ShutdownSignalException | IOException sse) { if (!abort) throw sse; - } catch (IOException ioe) { - if (!abort) - throw ioe; } finally { if(sync) _frameHandler.close(); } From ba0434e0bb44ffafc1302c0bb9d8390cc5a51c3c Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Thu, 28 Feb 2019 16:23:21 +0300 Subject: [PATCH 1053/2114] Update a few tests to explicitly delete queues Due to changes in [1] argument mismatch that involves the exclusive property can report a different channel exception (406 LOCKED). Since it has nothing to do with dead-lettering, switching to cleaning up queues manually and relying on their non-durability e.g. between CI runs is sufficient. Spotted by @acogoluegnes. 1. https://github.com/rabbitmq/rabbitmq-server/commit/bd46898b5923c92873f4b9ff0c3ac9df3cb0a1aa (cherry picked from commit dae7b13849a929d653c9bec62d782914e6644f8c) --- .../client/test/functional/DeadLetterExchange.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java index cfaff5f47d..e76e866bd2 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java @@ -29,13 +29,13 @@ public class DeadLetterExchange extends BrokerTestCase { public static final String DLX = "dead.letter.exchange"; - public static final String DLX_ARG = "x-dead-letter-exchange"; - public static final String DLX_RK_ARG = "x-dead-letter-routing-key"; + private static final String DLX_ARG = "x-dead-letter-exchange"; + private static final String DLX_RK_ARG = "x-dead-letter-routing-key"; public static final String TEST_QUEUE_NAME = "test.queue.dead.letter"; public static final String DLQ = "queue.dlq"; - public static final String DLQ2 = "queue.dlq2"; + private static final String DLQ2 = "queue.dlq2"; public static final int MSG_COUNT = 10; - public static final int TTL = 1000; + private static final int TTL = 1000; @Override protected void createResources() throws IOException { @@ -48,6 +48,7 @@ protected void createResources() throws IOException { @Override protected void releaseResources() throws IOException { channel.exchangeDelete(DLX); + channel.queueDelete(TEST_QUEUE_NAME); } @Test public void declareQueueWithExistingDeadLetterExchange() @@ -614,7 +615,7 @@ private void declareQueue(String queue, Object deadLetterExchange, if (deadLetterRoutingKey != null) { args.put(DLX_RK_ARG, deadLetterRoutingKey); } - channel.queueDeclare(queue, false, true, false, args); + channel.queueDeclare(queue, false, false, false, args); } private void publishN(int n) throws IOException { From b6c5f8aaa0d5b03ca6e2c3039b35a9738f005b46 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Thu, 28 Feb 2019 16:29:48 +0300 Subject: [PATCH 1054/2114] Squash a few more IDEA warnings (cherry picked from commit 8fa6760f1b37abfa2b8dda9fa6a40b022dacc1bb) --- .../test/functional/DeadLetterExchange.java | 227 ++++++++---------- 1 file changed, 100 insertions(+), 127 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java index e76e866bd2..f78bd7a264 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java @@ -77,9 +77,7 @@ protected void releaseResources() throws IOException { declareQueue(TEST_QUEUE_NAME, DLX, "routing_key", null); } - @Test public void declareQueueWithInvalidDeadLetterExchangeArg() - throws IOException - { + @Test public void declareQueueWithInvalidDeadLetterExchangeArg() { try { declareQueue(133); fail("x-dead-letter-exchange must be a valid exchange name"); @@ -101,9 +99,7 @@ protected void releaseResources() throws IOException { } } - @Test public void declareQueueWithInvalidDeadLetterRoutingKeyArg() - throws IOException - { + @Test public void declareQueueWithInvalidDeadLetterRoutingKeyArg() { try { declareQueue("foo", "amq.direct", 144, null); fail("x-dead-letter-routing-key must be a string"); @@ -125,11 +121,9 @@ protected void releaseResources() throws IOException { } } - @Test public void declareQueueWithRoutingKeyButNoDeadLetterExchange() - throws IOException - { + @Test public void declareQueueWithRoutingKeyButNoDeadLetterExchange() { try { - Map args = new HashMap(); + Map args = new HashMap<>(); args.put(DLX_RK_ARG, "foo"); channel.queueDeclare(randomQueueName(), false, true, false, args); @@ -139,11 +133,10 @@ protected void releaseResources() throws IOException { } } - @Test public void redeclareQueueWithRoutingKeyButNoDeadLetterExchange() - throws IOException, InterruptedException { + @Test public void redeclareQueueWithRoutingKeyButNoDeadLetterExchange() { try { String queueName = randomQueueName(); - Map args = new HashMap(); + Map args = new HashMap<>(); channel.queueDeclare(queueName, false, true, false, args); args.put(DLX_RK_ARG, "foo"); @@ -165,7 +158,7 @@ protected void releaseResources() throws IOException { } @Test public void deadLetterQueueTTLPromptExpiry() throws Exception { - Map args = new HashMap(); + Map args = new HashMap<>(); args.put("x-message-ttl", TTL); declareQueue(TEST_QUEUE_NAME, DLX, null, args); channel.queueBind(TEST_QUEUE_NAME, "amq.direct", "test"); @@ -205,7 +198,7 @@ protected void releaseResources() throws IOException { publishAt(start); basicGet(TEST_QUEUE_NAME); // publish a 2nd message and immediately fetch it in ack mode - publishAt(start + TTL * 1 / 2); + publishAt(start + TTL / 2); GetResponse r = channel.basicGet(TEST_QUEUE_NAME, false); // publish a 3rd message publishAt(start + TTL * 3 / 4); @@ -250,20 +243,17 @@ protected void releaseResources() throws IOException { // the DLQ *AND* should remain there, not getting removed after a subsequent // wait time > 100ms sleep(500); - consumeN(DLQ, 1, new WithResponse() { - @SuppressWarnings("unchecked") - public void process(GetResponse getResponse) { - assertNull(getResponse.getProps().getExpiration()); - Map headers = getResponse.getProps().getHeaders(); - assertNotNull(headers); - ArrayList death = (ArrayList)headers.get("x-death"); - assertNotNull(death); - assertDeathReason(death, 0, TEST_QUEUE_NAME, "expired"); - final Map deathHeader = - (Map)death.get(0); - assertEquals("100", deathHeader.get("original-expiration").toString()); - } - }); + consumeN(DLQ, 1, getResponse -> { + assertNull(getResponse.getProps().getExpiration()); + Map headers = getResponse.getProps().getHeaders(); + assertNotNull(headers); + ArrayList death = (ArrayList)headers.get("x-death"); + assertNotNull(death); + assertDeathReason(death, 0, TEST_QUEUE_NAME, "expired"); + final Map deathHeader = + (Map)death.get(0); + assertEquals("100", deathHeader.get("original-expiration").toString()); + }); } @Test public void deadLetterOnReject() throws Exception { @@ -315,23 +305,20 @@ public void process(GetResponse getResponse) { // There should now be two copies of each message on DLQ2: one // with one set of death headers, and another with two sets. - consumeN(DLQ2, MSG_COUNT*2, new WithResponse() { - @SuppressWarnings("unchecked") - public void process(GetResponse getResponse) { - Map headers = getResponse.getProps().getHeaders(); - assertNotNull(headers); - ArrayList death = (ArrayList)headers.get("x-death"); - assertNotNull(death); - if (death.size() == 1) { - assertDeathReason(death, 0, TEST_QUEUE_NAME, "expired"); - } else if (death.size() == 2) { - assertDeathReason(death, 0, DLQ, "expired"); - assertDeathReason(death, 1, TEST_QUEUE_NAME, "expired"); - } else { - fail("message was dead-lettered more times than expected"); - } - } - }); + consumeN(DLQ2, MSG_COUNT*2, getResponse -> { + Map headers = getResponse.getProps().getHeaders(); + assertNotNull(headers); + ArrayList death = (ArrayList)headers.get("x-death"); + assertNotNull(death); + if (death.size() == 1) { + assertDeathReason(death, 0, TEST_QUEUE_NAME, "expired"); + } else if (death.size() == 2) { + assertDeathReason(death, 0, DLQ, "expired"); + assertDeathReason(death, 1, TEST_QUEUE_NAME, "expired"); + } else { + fail("message was dead-lettered more times than expected"); + } + }); } @Test public void deadLetterSelf() throws Exception { @@ -379,9 +366,9 @@ public void handleDelivery(String consumerTag, Envelope envelope, channel.queueBind(DLQ, DLX, "test"); channel.queueBind(DLQ2, DLX, "test-other"); - Map headers = new HashMap(); - headers.put("CC", Arrays.asList("foo")); - headers.put("BCC", Arrays.asList("bar")); + Map headers = new HashMap<>(); + headers.put("CC", Collections.singletonList("foo")); + headers.put("BCC", Collections.singletonList("bar")); publishN(MSG_COUNT, (new AMQP.BasicProperties.Builder()) .headers(headers) @@ -390,27 +377,24 @@ public void handleDelivery(String consumerTag, Envelope envelope, sleep(100); consumeN(DLQ, 0, WithResponse.NULL); - consumeN(DLQ2, MSG_COUNT, new WithResponse() { - @SuppressWarnings("unchecked") - public void process(GetResponse getResponse) { - Map headers = getResponse.getProps().getHeaders(); - assertNotNull(headers); - assertNull(headers.get("CC")); - assertNull(headers.get("BCC")); - - ArrayList death = (ArrayList)headers.get("x-death"); - assertNotNull(death); - assertEquals(1, death.size()); - assertDeathReason(death, 0, TEST_QUEUE_NAME, - "expired", "amq.direct", - Arrays.asList("test", "foo")); - } - }); + consumeN(DLQ2, MSG_COUNT, getResponse -> { + Map headers1 = getResponse.getProps().getHeaders(); + assertNotNull(headers1); + assertNull(headers1.get("CC")); + assertNull(headers1.get("BCC")); + + ArrayList death = (ArrayList) headers1.get("x-death"); + assertNotNull(death); + assertEquals(1, death.size()); + assertDeathReason(death, 0, TEST_QUEUE_NAME, + "expired", "amq.direct", + Arrays.asList("test", "foo")); + }); } @SuppressWarnings("unchecked") @Test public void republish() throws Exception { - Map args = new HashMap(); + Map args = new HashMap<>(); args.put("x-message-ttl", 100); declareQueue(TEST_QUEUE_NAME, DLX, null, args); channel.queueBind(TEST_QUEUE_NAME, "amq.direct", "test"); @@ -430,10 +414,10 @@ public void process(GetResponse getResponse) { assertNotNull(death); assertEquals(1, death.size()); assertDeathReason(death, 0, TEST_QUEUE_NAME, "expired", "amq.direct", - Arrays.asList("test")); + Collections.singletonList("test")); // Make queue zero length - args = new HashMap(); + args = new HashMap<>(); args.put("x-max-length", 0); channel.queueDelete(TEST_QUEUE_NAME); declareQueue(TEST_QUEUE_NAME, DLX, null, args); @@ -457,9 +441,9 @@ public void process(GetResponse getResponse) { assertNotNull(death); assertEquals(2, death.size()); assertDeathReason(death, 0, TEST_QUEUE_NAME, "maxlen", "amq.direct", - Arrays.asList("test")); + Collections.singletonList("test")); assertDeathReason(death, 1, TEST_QUEUE_NAME, "expired", "amq.direct", - Arrays.asList("test")); + Collections.singletonList("test")); //Set invalid headers headers.put("x-death", "[I, am, not, array]"); @@ -478,26 +462,24 @@ public void process(GetResponse getResponse) { assertNotNull(death); assertEquals(1, death.size()); assertDeathReason(death, 0, TEST_QUEUE_NAME, "maxlen", "amq.direct", - Arrays.asList("test")); - - } - - public void rejectionTest(final boolean useNack) throws Exception { - deadLetterTest(new Callable() { - public Void call() throws Exception { - for (int x = 0; x < MSG_COUNT; x++) { - GetResponse getResponse = - channel.basicGet(TEST_QUEUE_NAME, false); - long tag = getResponse.getEnvelope().getDeliveryTag(); - if (useNack) { - channel.basicNack(tag, false, false); - } else { - channel.basicReject(tag, false); - } - } - return null; + Collections.singletonList("test")); + + } + + private void rejectionTest(final boolean useNack) throws Exception { + deadLetterTest((Callable) () -> { + for (int x = 0; x < MSG_COUNT; x++) { + GetResponse getResponse = + channel.basicGet(TEST_QUEUE_NAME, false); + long tag = getResponse.getEnvelope().getDeliveryTag(); + if (useNack) { + channel.basicNack(tag, false, false); + } else { + channel.basicReject(tag, false); } - }, null, "rejected"); + } + return null; + }, null, "rejected"); } private void deadLetterTest(final Runnable deathTrigger, @@ -505,12 +487,10 @@ private void deadLetterTest(final Runnable deathTrigger, String reason) throws Exception { - deadLetterTest(new Callable() { - public Object call() throws Exception { - deathTrigger.run(); - return null; - } - }, queueDeclareArgs, reason); + deadLetterTest(() -> { + deathTrigger.run(); + return null; + }, queueDeclareArgs, reason); } private void deadLetterTest(Callable deathTrigger, @@ -531,35 +511,30 @@ private void deadLetterTest(Callable deathTrigger, } public static void consume(final Channel channel, final String reason) throws IOException { - consumeN(channel, DLQ, MSG_COUNT, new WithResponse() { - @SuppressWarnings("unchecked") - public void process(GetResponse getResponse) { - Map headers = getResponse.getProps().getHeaders(); - assertNotNull(headers); - ArrayList death = (ArrayList) headers.get("x-death"); - assertNotNull(death); - // the following assertions shouldn't be checked on version lower than 3.7 - // as the headers are new in 3.7 - // see https://github.com/rabbitmq/rabbitmq-server/issues/1332 - if(TestUtils.isVersion37orLater(channel.getConnection())) { - assertNotNull(headers.get("x-first-death-queue")); - assertNotNull(headers.get("x-first-death-reason")); - assertNotNull(headers.get("x-first-death-exchange")); - } - assertEquals(1, death.size()); - assertDeathReason(death, 0, TEST_QUEUE_NAME, reason, - "amq.direct", - Arrays.asList("test")); + consumeN(channel, DLQ, MSG_COUNT, getResponse -> { + Map headers = getResponse.getProps().getHeaders(); + assertNotNull(headers); + ArrayList death = (ArrayList) headers.get("x-death"); + assertNotNull(death); + // the following assertions shouldn't be checked on version lower than 3.7 + // as the headers are new in 3.7 + // see https://github.com/rabbitmq/rabbitmq-server/issues/1332 + if(TestUtils.isVersion37orLater(channel.getConnection())) { + assertNotNull(headers.get("x-first-death-queue")); + assertNotNull(headers.get("x-first-death-reason")); + assertNotNull(headers.get("x-first-death-exchange")); } + assertEquals(1, death.size()); + assertDeathReason(death, 0, TEST_QUEUE_NAME, reason, + "amq.direct", + Collections.singletonList("test")); }); } private void ttlTest(final long ttl) throws Exception { Map args = new HashMap(); args.put("x-message-ttl", ttl); - deadLetterTest(new Runnable() { - public void run() { sleep(ttl + 1500); } - }, args, "expired"); + deadLetterTest(() -> sleep(ttl + 1500), args, "expired"); } private void sleep(long millis) { @@ -604,7 +579,7 @@ private void declareQueue(String queue, Object deadLetterExchange, throws IOException { if (args == null) { - args = new HashMap(); + args = new HashMap<>(); } if (ttl > 0){ @@ -674,7 +649,7 @@ private static void assertDeathReason(List death, int num, (Map)death.get(num); assertEquals(exchange, deathHeader.get("exchange").toString()); - List deathRKs = new ArrayList(); + List deathRKs = new ArrayList<>(); for (Object rk : (ArrayList)deathHeader.get("routing-keys")) { deathRKs.add(rk.toString()); } @@ -694,13 +669,11 @@ private static void assertDeathReason(List death, int num, assertEquals(reason, deathHeader.get("reason").toString()); } - private static interface WithResponse { - static final WithResponse NULL = new WithResponse() { - public void process(GetResponse getResponse) { - } - }; + private interface WithResponse { + WithResponse NULL = getResponse -> { + }; - public void process(GetResponse response); + void process(GetResponse response); } private static String randomQueueName() { @@ -709,9 +682,9 @@ private static String randomQueueName() { class AccumulatingMessageConsumer extends DefaultConsumer { - BlockingQueue messages = new LinkedBlockingQueue(); + BlockingQueue messages = new LinkedBlockingQueue<>(); - public AccumulatingMessageConsumer(Channel channel) { + AccumulatingMessageConsumer(Channel channel) { super(channel); } From 75042ec95794ac264426ff165c7d2abc0451aa69 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Thu, 28 Feb 2019 18:30:46 +0300 Subject: [PATCH 1055/2114] Update more tests to explicitly delete queues See dae7b13849a929d653c9bec62d782914e6644f8c for background. --- .../client/test/functional/CcRoutes.java | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java b/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java index 8d0136419c..942d4d2f66 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java +++ b/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java @@ -39,30 +39,38 @@ public class CcRoutes extends BrokerTestCase { static private final String[] queues = new String[]{"queue1", "queue2", "queue3"}; - protected final String exDirect = "direct_cc_exchange"; - protected final String exTopic = "topic_cc_exchange"; - protected BasicProperties.Builder propsBuilder; + private final String exDirect = "direct_cc_exchange"; + private final String exTopic = "topic_cc_exchange"; + private BasicProperties.Builder propsBuilder; protected Map headers; - protected List ccList; - protected List bccList; + private List ccList; + private List bccList; @Override public void setUp() throws IOException, TimeoutException { super.setUp(); propsBuilder = new BasicProperties.Builder(); - headers = new HashMap(); - ccList = new ArrayList(); - bccList = new ArrayList(); + headers = new HashMap<>(); + ccList = new ArrayList<>(); + bccList = new ArrayList<>(); } @Override protected void createResources() throws IOException, TimeoutException { super.createResources(); for (String q : queues) { - channel.queueDeclare(q, false, true, true, null); + channel.queueDeclare(q, false, false, true, null); } channel.exchangeDeclare(exDirect, "direct", false, true, null); channel.exchangeDeclare(exTopic, "topic", false, true, null); } + @Override + protected void releaseResources() throws IOException { + super.releaseResources(); + for (String q : queues) { + channel.queueDelete(q); + } + } + @Test public void ccList() throws IOException { ccList.add("queue2"); ccList.add("queue3"); From 3242f7a3fff74f22c766528c2b16ddba869af3f8 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Thu, 28 Feb 2019 18:30:46 +0300 Subject: [PATCH 1056/2114] Update more tests to explicitly delete queues See dae7b13849a929d653c9bec62d782914e6644f8c for background. (cherry picked from commit 75042ec95794ac264426ff165c7d2abc0451aa69) --- .../client/test/functional/CcRoutes.java | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java b/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java index 8d0136419c..942d4d2f66 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java +++ b/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java @@ -39,30 +39,38 @@ public class CcRoutes extends BrokerTestCase { static private final String[] queues = new String[]{"queue1", "queue2", "queue3"}; - protected final String exDirect = "direct_cc_exchange"; - protected final String exTopic = "topic_cc_exchange"; - protected BasicProperties.Builder propsBuilder; + private final String exDirect = "direct_cc_exchange"; + private final String exTopic = "topic_cc_exchange"; + private BasicProperties.Builder propsBuilder; protected Map headers; - protected List ccList; - protected List bccList; + private List ccList; + private List bccList; @Override public void setUp() throws IOException, TimeoutException { super.setUp(); propsBuilder = new BasicProperties.Builder(); - headers = new HashMap(); - ccList = new ArrayList(); - bccList = new ArrayList(); + headers = new HashMap<>(); + ccList = new ArrayList<>(); + bccList = new ArrayList<>(); } @Override protected void createResources() throws IOException, TimeoutException { super.createResources(); for (String q : queues) { - channel.queueDeclare(q, false, true, true, null); + channel.queueDeclare(q, false, false, true, null); } channel.exchangeDeclare(exDirect, "direct", false, true, null); channel.exchangeDeclare(exTopic, "topic", false, true, null); } + @Override + protected void releaseResources() throws IOException { + super.releaseResources(); + for (String q : queues) { + channel.queueDelete(q); + } + } + @Test public void ccList() throws IOException { ccList.add("queue2"); ccList.add("queue3"); From ca7eb02789c45814715d61c181791d82e9b93731 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Thu, 28 Feb 2019 21:10:37 +0300 Subject: [PATCH 1057/2114] Squash more warnings --- .../rabbitmq/client/SocketConfigurators.java | 18 +++++++++--------- .../rabbitmq/client/impl/ClientVersion.java | 6 +++--- .../client/impl/MethodArgumentWriter.java | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/SocketConfigurators.java b/src/main/java/com/rabbitmq/client/SocketConfigurators.java index 551ad95ca9..f738fe166d 100644 --- a/src/main/java/com/rabbitmq/client/SocketConfigurators.java +++ b/src/main/java/com/rabbitmq/client/SocketConfigurators.java @@ -49,7 +49,7 @@ public abstract class SocketConfigurators { } }; - static final SSLParameters enableHostnameVerification(SSLParameters sslParameters) { + static SSLParameters enableHostnameVerification(SSLParameters sslParameters) { if (sslParameters == null) { sslParameters = new SSLParameters(); } @@ -62,7 +62,7 @@ static final SSLParameters enableHostnameVerification(SSLParameters sslParameter /** * The default {@link SocketConfigurator} that disables Nagle's algorithm. * - * @return + * @return Default configurator: only disables Nagle's algirithm */ public static SocketConfigurator defaultConfigurator() { return DEFAULT; @@ -71,7 +71,7 @@ public static SocketConfigurator defaultConfigurator() { /** * {@link SocketConfigurator} that disables Nagle's algorithm. * - * @return + * @return A composable configurator that diasbles Nagle's algirithm */ public static SocketConfigurator disableNagleAlgorithm() { return DISABLE_NAGLE_ALGORITHM; @@ -80,7 +80,7 @@ public static SocketConfigurator disableNagleAlgorithm() { /** * {@link SocketConfigurator} that enable server hostname verification for TLS connections. * - * @return + * @return A composable configurator that enables peer hostname verification */ public static SocketConfigurator enableHostnameVerification() { return ENABLE_HOSTNAME_VERIFICATION; @@ -103,7 +103,7 @@ public static class Builder { /** * Set default configuration. * - * @return + * @return this */ public Builder defaultConfigurator() { configurator = configurator.andThen(DEFAULT); @@ -113,7 +113,7 @@ public Builder defaultConfigurator() { /** * Disable Nagle's Algorithm. * - * @return + * @return this */ public Builder disableNagleAlgorithm() { configurator = configurator.andThen(DISABLE_NAGLE_ALGORITHM); @@ -123,7 +123,7 @@ public Builder disableNagleAlgorithm() { /** * Enable server hostname verification for TLS connections. * - * @return + * @return this */ public Builder enableHostnameVerification() { configurator = configurator.andThen(ENABLE_HOSTNAME_VERIFICATION); @@ -134,7 +134,7 @@ public Builder enableHostnameVerification() { * Add an extra configuration step. * * @param extraConfiguration - * @return + * @return this */ public Builder add(SocketConfigurator extraConfiguration) { configurator = configurator.andThen(extraConfiguration); @@ -144,7 +144,7 @@ public Builder add(SocketConfigurator extraConfiguration) { /** * Return the configured {@link SocketConfigurator}. * - * @return + * @return the final configurator */ public SocketConfigurator build() { return configurator; diff --git a/src/main/java/com/rabbitmq/client/impl/ClientVersion.java b/src/main/java/com/rabbitmq/client/impl/ClientVersion.java index dcda1072cd..771c71d135 100644 --- a/src/main/java/com/rabbitmq/client/impl/ClientVersion.java +++ b/src/main/java/com/rabbitmq/client/impl/ClientVersion.java @@ -52,7 +52,7 @@ public class ClientVersion { VERSION = version; } - private static final String getVersionFromPropertyFile() throws Exception { + private static String getVersionFromPropertyFile() throws Exception { InputStream inputStream = ClientVersion.class.getClassLoader().getResourceAsStream("rabbitmq-amqp-client.properties"); Properties version = new Properties(); try { @@ -70,14 +70,14 @@ private static final String getVersionFromPropertyFile() throws Exception { return versionProperty; } - private static final String getVersionFromPackage() { + private static String getVersionFromPackage() { if (ClientVersion.class.getPackage().getImplementationVersion() == null) { throw new IllegalStateException("Couldn't get version with Package#getImplementationVersion"); } return ClientVersion.class.getPackage().getImplementationVersion(); } - private static final String getDefaultVersion() { + private static String getDefaultVersion() { return "0.0.0"; } } diff --git a/src/main/java/com/rabbitmq/client/impl/MethodArgumentWriter.java b/src/main/java/com/rabbitmq/client/impl/MethodArgumentWriter.java index db2005d32f..35ad76ab17 100644 --- a/src/main/java/com/rabbitmq/client/impl/MethodArgumentWriter.java +++ b/src/main/java/com/rabbitmq/client/impl/MethodArgumentWriter.java @@ -57,7 +57,7 @@ private void resetBitAccumulator() { * Private API - called when we may be transitioning from encoding * a group of bits to encoding a non-bit value. */ - private final void bitflush() + private void bitflush() throws IOException { if (needBitFlush) { From abb67a75c1614d54e071f6f1de01b85b5cc871eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 1 Mar 2019 10:11:20 +0100 Subject: [PATCH 1058/2114] Change queue names between test methods To avoid collisions on slow environments like CI. --- .../client/test/functional/CcRoutes.java | 68 +++++++++++-------- 1 file changed, 41 insertions(+), 27 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java b/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java index 942d4d2f66..7e02faae15 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java +++ b/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java @@ -22,12 +22,10 @@ import static org.junit.Assert.fail; import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.concurrent.TimeoutException; +import java.util.stream.Collectors; +import java.util.stream.IntStream; import org.junit.Test; @@ -38,7 +36,7 @@ public class CcRoutes extends BrokerTestCase { - static private final String[] queues = new String[]{"queue1", "queue2", "queue3"}; + private String[] queues; private final String exDirect = "direct_cc_exchange"; private final String exTopic = "topic_cc_exchange"; private BasicProperties.Builder propsBuilder; @@ -56,6 +54,10 @@ public class CcRoutes extends BrokerTestCase { @Override protected void createResources() throws IOException, TimeoutException { super.createResources(); + queues = IntStream.range(1, 4) + .mapToObj(index -> CcRoutes.class.getSimpleName() + "." + UUID.randomUUID().toString()) + .collect(Collectors.toList()) + .toArray(new String[]{}); for (String q : queues) { channel.queueDeclare(q, false, false, true, null); } @@ -72,58 +74,58 @@ protected void releaseResources() throws IOException { } @Test public void ccList() throws IOException { - ccList.add("queue2"); - ccList.add("queue3"); - headerPublish("", "queue1", ccList, null); - expect(new String []{"queue1", "queue2", "queue3"}, true); + ccList.add(queue2()); + ccList.add(queue3()); + headerPublish("", queue1(), ccList, null); + expect(new String []{queue1(), queue2(), queue3()}, true); } @Test public void ccIgnoreEmptyAndInvalidRoutes() throws IOException { bccList.add("frob"); - headerPublish("", "queue1", ccList, bccList); - expect(new String []{"queue1"}, true); + headerPublish("", queue1(), ccList, bccList); + expect(new String []{queue1()}, true); } @Test public void bcc() throws IOException { - bccList.add("queue2"); - headerPublish("", "queue1", null, bccList); - expect(new String []{"queue1", "queue2"}, false); + bccList.add(queue2()); + headerPublish("", queue1(), null, bccList); + expect(new String []{queue1(), queue2()}, false); } @Test public void noDuplicates() throws IOException { - ccList.add("queue1"); - ccList.add("queue1"); - bccList.add("queue1"); - headerPublish("", "queue1", ccList, bccList); - expect(new String[] {"queue1"}, true); + ccList.add(queue1()); + ccList.add(queue1()); + bccList.add(queue1()); + headerPublish("", queue1(), ccList, bccList); + expect(new String[] {queue1()}, true); } @Test public void directExchangeWithoutBindings() throws IOException { - ccList.add("queue1"); - headerPublish(exDirect, "queue2", ccList, null); + ccList.add(queue1()); + headerPublish(exDirect, queue2(), ccList, null); expect(new String[] {}, true); } @Test public void topicExchange() throws IOException { ccList.add("routing_key"); - channel.queueBind("queue2", exTopic, "routing_key"); + channel.queueBind(queue2(), exTopic, "routing_key"); headerPublish(exTopic, "", ccList, null); - expect(new String[] {"queue2"}, true); + expect(new String[] {queue2()}, true); } @Test public void boundExchanges() throws IOException { ccList.add("routing_key1"); bccList.add("routing_key2"); channel.exchangeBind(exTopic, exDirect, "routing_key1"); - channel.queueBind("queue2", exTopic, "routing_key2"); + channel.queueBind(queue2(), exTopic, "routing_key2"); headerPublish(exDirect, "", ccList, bccList); - expect(new String[] {"queue2"}, true); + expect(new String[] {queue2()}, true); } @Test public void nonArray() throws IOException { headers.put("CC", 0); propsBuilder.headers(headers); - channel.basicPublish("", "queue1", propsBuilder.build(), new byte[0]); + channel.basicPublish("", queue1(), propsBuilder.build(), new byte[0]); try { expect(new String[] {}, false); fail(); @@ -161,4 +163,16 @@ private void expect(String[] expectedQueues, boolean usedCc) throws IOException } } } + + String queue1() { + return queues[0]; + } + + String queue2() { + return queues[1]; + } + + String queue3() { + return queues[2]; + } } From 082c2f9c79306cab174a23431cb41f54f6932c86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 1 Mar 2019 10:11:20 +0100 Subject: [PATCH 1059/2114] Change queue names between test methods To avoid collisions on slow environments like CI. (cherry picked from commit abb67a75c1614d54e071f6f1de01b85b5cc871eb) --- .../client/test/functional/CcRoutes.java | 68 +++++++++++-------- 1 file changed, 41 insertions(+), 27 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java b/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java index 942d4d2f66..7e02faae15 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java +++ b/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java @@ -22,12 +22,10 @@ import static org.junit.Assert.fail; import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.concurrent.TimeoutException; +import java.util.stream.Collectors; +import java.util.stream.IntStream; import org.junit.Test; @@ -38,7 +36,7 @@ public class CcRoutes extends BrokerTestCase { - static private final String[] queues = new String[]{"queue1", "queue2", "queue3"}; + private String[] queues; private final String exDirect = "direct_cc_exchange"; private final String exTopic = "topic_cc_exchange"; private BasicProperties.Builder propsBuilder; @@ -56,6 +54,10 @@ public class CcRoutes extends BrokerTestCase { @Override protected void createResources() throws IOException, TimeoutException { super.createResources(); + queues = IntStream.range(1, 4) + .mapToObj(index -> CcRoutes.class.getSimpleName() + "." + UUID.randomUUID().toString()) + .collect(Collectors.toList()) + .toArray(new String[]{}); for (String q : queues) { channel.queueDeclare(q, false, false, true, null); } @@ -72,58 +74,58 @@ protected void releaseResources() throws IOException { } @Test public void ccList() throws IOException { - ccList.add("queue2"); - ccList.add("queue3"); - headerPublish("", "queue1", ccList, null); - expect(new String []{"queue1", "queue2", "queue3"}, true); + ccList.add(queue2()); + ccList.add(queue3()); + headerPublish("", queue1(), ccList, null); + expect(new String []{queue1(), queue2(), queue3()}, true); } @Test public void ccIgnoreEmptyAndInvalidRoutes() throws IOException { bccList.add("frob"); - headerPublish("", "queue1", ccList, bccList); - expect(new String []{"queue1"}, true); + headerPublish("", queue1(), ccList, bccList); + expect(new String []{queue1()}, true); } @Test public void bcc() throws IOException { - bccList.add("queue2"); - headerPublish("", "queue1", null, bccList); - expect(new String []{"queue1", "queue2"}, false); + bccList.add(queue2()); + headerPublish("", queue1(), null, bccList); + expect(new String []{queue1(), queue2()}, false); } @Test public void noDuplicates() throws IOException { - ccList.add("queue1"); - ccList.add("queue1"); - bccList.add("queue1"); - headerPublish("", "queue1", ccList, bccList); - expect(new String[] {"queue1"}, true); + ccList.add(queue1()); + ccList.add(queue1()); + bccList.add(queue1()); + headerPublish("", queue1(), ccList, bccList); + expect(new String[] {queue1()}, true); } @Test public void directExchangeWithoutBindings() throws IOException { - ccList.add("queue1"); - headerPublish(exDirect, "queue2", ccList, null); + ccList.add(queue1()); + headerPublish(exDirect, queue2(), ccList, null); expect(new String[] {}, true); } @Test public void topicExchange() throws IOException { ccList.add("routing_key"); - channel.queueBind("queue2", exTopic, "routing_key"); + channel.queueBind(queue2(), exTopic, "routing_key"); headerPublish(exTopic, "", ccList, null); - expect(new String[] {"queue2"}, true); + expect(new String[] {queue2()}, true); } @Test public void boundExchanges() throws IOException { ccList.add("routing_key1"); bccList.add("routing_key2"); channel.exchangeBind(exTopic, exDirect, "routing_key1"); - channel.queueBind("queue2", exTopic, "routing_key2"); + channel.queueBind(queue2(), exTopic, "routing_key2"); headerPublish(exDirect, "", ccList, bccList); - expect(new String[] {"queue2"}, true); + expect(new String[] {queue2()}, true); } @Test public void nonArray() throws IOException { headers.put("CC", 0); propsBuilder.headers(headers); - channel.basicPublish("", "queue1", propsBuilder.build(), new byte[0]); + channel.basicPublish("", queue1(), propsBuilder.build(), new byte[0]); try { expect(new String[] {}, false); fail(); @@ -161,4 +163,16 @@ private void expect(String[] expectedQueues, boolean usedCc) throws IOException } } } + + String queue1() { + return queues[0]; + } + + String queue2() { + return queues[1]; + } + + String queue3() { + return queues[2]; + } } From b70076045c9e671cc46d2c44df2b373b8740b81b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 8 Mar 2019 15:29:53 +0100 Subject: [PATCH 1060/2114] Use https --- src/main/scripts/sanity-check.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scripts/sanity-check.groovy b/src/main/scripts/sanity-check.groovy index 12c5464d0c..073650a360 100644 --- a/src/main/scripts/sanity-check.groovy +++ b/src/main/scripts/sanity-check.groovy @@ -1,4 +1,4 @@ -@GrabResolver(name = 'rabbitmq-bintray', root = 'http://dl.bintray.com/rabbitmq/maven') +@GrabResolver(name = 'rabbitmq-bintray', root = 'https://dl.bintray.com/rabbitmq/maven') @GrabResolver(name = 'rabbitmq-packagecloud-milestones', root = 'https://packagecloud.io/rabbitmq/maven-milestones/maven2') @Grab(group = 'com.rabbitmq', module = 'amqp-client', version = '${version}') @Grab(group = 'org.slf4j', module = 'slf4j-simple', version = '1.7.25') From ad3809c3ca3a188eb74bf3d5b69ffb4cda0d8996 Mon Sep 17 00:00:00 2001 From: Spring Operator Date: Tue, 12 Mar 2019 08:27:56 -0500 Subject: [PATCH 1061/2114] URL Cleanup This commit updates URLs to prefer the https protocol. Redirects are not followed to avoid accidentally expanding intentionally shortened URLs (i.e. if using a URL shortener). # Fixed URLs ## Fixed Success These URLs were switched to an https URL with a 2xx status. While the status was successful, your review is still recommended. * http://www.apache.org/licenses/LICENSE-2.0 migrated to: https://www.apache.org/licenses/LICENSE-2.0 ([https](https://www.apache.org/licenses/LICENSE-2.0) result 200). * http://www.apache.org/licenses/LICENSE-2.0.html migrated to: https://www.apache.org/licenses/LICENSE-2.0.html ([https](https://www.apache.org/licenses/LICENSE-2.0.html) result 200). * http://www.gnu.org/licenses/gpl-2.0.txt migrated to: https://www.gnu.org/licenses/gpl-2.0.txt ([https](https://www.gnu.org/licenses/gpl-2.0.txt) result 200). * http://www.rabbitmq.com migrated to: https://www.rabbitmq.com ([https](https://www.rabbitmq.com) result 200). * http://www.mozilla.org/MPL/MPL-1.1.txt migrated to: https://www.mozilla.org/MPL/MPL-1.1.txt ([https](https://www.mozilla.org/MPL/MPL-1.1.txt) result 301). # Ignored These URLs were intentionally ignored. * http://maven.apache.org/POM/4.0.0 * http://maven.apache.org/xsd/maven-4.0.0.xsd * http://www.w3.org/2001/XMLSchema-instance --- mvnw | 2 +- mvnw.cmd | 2 +- pom.xml | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/mvnw b/mvnw index e96ccd5fbb..4e574d9a02 100755 --- a/mvnw +++ b/mvnw @@ -8,7 +8,7 @@ # "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 +# https://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 diff --git a/mvnw.cmd b/mvnw.cmd index 4f0b068a03..23ab056e29 100755 --- a/mvnw.cmd +++ b/mvnw.cmd @@ -7,7 +7,7 @@ @REM "License"); you may not use this file except in compliance @REM with the License. You may obtain a copy of the License at @REM -@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM https://www.apache.org/licenses/LICENSE-2.0 @REM @REM Unless required by applicable law or agreed to in writing, @REM software distributed under the License is distributed on an diff --git a/pom.xml b/pom.xml index e8b006ed3a..6221fd2780 100644 --- a/pom.xml +++ b/pom.xml @@ -9,22 +9,22 @@ RabbitMQ Java Client The RabbitMQ Java client library allows Java applications to interface with RabbitMQ. - http://www.rabbitmq.com + https://www.rabbitmq.com ASL 2.0 - http://www.apache.org/licenses/LICENSE-2.0.html + https://www.apache.org/licenses/LICENSE-2.0.html repo GPL v2 - http://www.gnu.org/licenses/gpl-2.0.txt + https://www.gnu.org/licenses/gpl-2.0.txt repo MPL 1.1 - http://www.mozilla.org/MPL/MPL-1.1.txt + https://www.mozilla.org/MPL/MPL-1.1.txt repo @@ -47,7 +47,7 @@ Pivotal Software, Inc. - http://www.rabbitmq.com + https://www.rabbitmq.com From 74a93623c3cbbd2ecb5b8054643e4a359b60a306 Mon Sep 17 00:00:00 2001 From: Spring Operator Date: Tue, 12 Mar 2019 08:27:56 -0500 Subject: [PATCH 1062/2114] URL Cleanup This commit updates URLs to prefer the https protocol. Redirects are not followed to avoid accidentally expanding intentionally shortened URLs (i.e. if using a URL shortener). # Fixed URLs ## Fixed Success These URLs were switched to an https URL with a 2xx status. While the status was successful, your review is still recommended. * http://www.apache.org/licenses/LICENSE-2.0 migrated to: https://www.apache.org/licenses/LICENSE-2.0 ([https](https://www.apache.org/licenses/LICENSE-2.0) result 200). * http://www.apache.org/licenses/LICENSE-2.0.html migrated to: https://www.apache.org/licenses/LICENSE-2.0.html ([https](https://www.apache.org/licenses/LICENSE-2.0.html) result 200). * http://www.gnu.org/licenses/gpl-2.0.txt migrated to: https://www.gnu.org/licenses/gpl-2.0.txt ([https](https://www.gnu.org/licenses/gpl-2.0.txt) result 200). * http://www.rabbitmq.com migrated to: https://www.rabbitmq.com ([https](https://www.rabbitmq.com) result 200). * http://www.mozilla.org/MPL/MPL-1.1.txt migrated to: https://www.mozilla.org/MPL/MPL-1.1.txt ([https](https://www.mozilla.org/MPL/MPL-1.1.txt) result 301). # Ignored These URLs were intentionally ignored. * http://maven.apache.org/POM/4.0.0 * http://maven.apache.org/xsd/maven-4.0.0.xsd * http://www.w3.org/2001/XMLSchema-instance (cherry picked from commit ad3809c3ca3a188eb74bf3d5b69ffb4cda0d8996) --- mvnw | 2 +- mvnw.cmd | 2 +- pom.xml | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/mvnw b/mvnw index e96ccd5fbb..4e574d9a02 100755 --- a/mvnw +++ b/mvnw @@ -8,7 +8,7 @@ # "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 +# https://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 diff --git a/mvnw.cmd b/mvnw.cmd index 4f0b068a03..23ab056e29 100755 --- a/mvnw.cmd +++ b/mvnw.cmd @@ -7,7 +7,7 @@ @REM "License"); you may not use this file except in compliance @REM with the License. You may obtain a copy of the License at @REM -@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM https://www.apache.org/licenses/LICENSE-2.0 @REM @REM Unless required by applicable law or agreed to in writing, @REM software distributed under the License is distributed on an diff --git a/pom.xml b/pom.xml index b4b6cd3d46..7ee17b23e7 100644 --- a/pom.xml +++ b/pom.xml @@ -9,22 +9,22 @@ RabbitMQ Java Client The RabbitMQ Java client library allows Java applications to interface with RabbitMQ. - http://www.rabbitmq.com + https://www.rabbitmq.com ASL 2.0 - http://www.apache.org/licenses/LICENSE-2.0.html + https://www.apache.org/licenses/LICENSE-2.0.html repo GPL v2 - http://www.gnu.org/licenses/gpl-2.0.txt + https://www.gnu.org/licenses/gpl-2.0.txt repo MPL 1.1 - http://www.mozilla.org/MPL/MPL-1.1.txt + https://www.mozilla.org/MPL/MPL-1.1.txt repo @@ -47,7 +47,7 @@ Pivotal Software, Inc. - http://www.rabbitmq.com + https://www.rabbitmq.com From 4473aa119dbf9a94515704759c7f392fd2c74ad9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 15 Mar 2019 09:44:46 +0100 Subject: [PATCH 1063/2114] Add logs during tests --- src/test/resources/logback-test.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml index ee88f442c2..596182704c 100644 --- a/src/test/resources/logback-test.xml +++ b/src/test/resources/logback-test.xml @@ -5,6 +5,8 @@ + + From 1bd2ea4508e6206fc84faa81c8158a276446b8f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 15 Mar 2019 09:49:27 +0100 Subject: [PATCH 1064/2114] Squash a few warnings in tests --- .../client/test/functional/DeadLetterExchange.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java index f78bd7a264..12e96cf4b8 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java @@ -230,6 +230,7 @@ protected void releaseResources() throws IOException { consumeN(DLQ, MSG_COUNT, WithResponse.NULL); } + @SuppressWarnings("unchecked") @Test public void deadLetterPerMessageTTLRemoved() throws Exception { declareQueue(TEST_QUEUE_NAME, DLX, null, null, 1); channel.queueBind(TEST_QUEUE_NAME, "amq.direct", "test"); @@ -247,11 +248,10 @@ protected void releaseResources() throws IOException { assertNull(getResponse.getProps().getExpiration()); Map headers = getResponse.getProps().getHeaders(); assertNotNull(headers); - ArrayList death = (ArrayList)headers.get("x-death"); + ArrayList death = (ArrayList) headers.get("x-death"); assertNotNull(death); assertDeathReason(death, 0, TEST_QUEUE_NAME, "expired"); - final Map deathHeader = - (Map)death.get(0); + final Map deathHeader = (Map) death.get(0); assertEquals("100", deathHeader.get("original-expiration").toString()); }); } @@ -287,6 +287,7 @@ protected void releaseResources() throws IOException { publishN(MSG_COUNT); } + @SuppressWarnings("unchecked") @Test public void deadLetterTwice() throws Exception { declareQueue(TEST_QUEUE_NAME, DLX, null, null, 1); @@ -308,7 +309,7 @@ protected void releaseResources() throws IOException { consumeN(DLQ2, MSG_COUNT*2, getResponse -> { Map headers = getResponse.getProps().getHeaders(); assertNotNull(headers); - ArrayList death = (ArrayList)headers.get("x-death"); + ArrayList death = (ArrayList) headers.get("x-death"); assertNotNull(death); if (death.size() == 1) { assertDeathReason(death, 0, TEST_QUEUE_NAME, "expired"); @@ -357,6 +358,7 @@ public void handleDelivery(String consumerTag, Envelope envelope, assertTrue(latch.await(10, TimeUnit.SECONDS)); } + @SuppressWarnings("unchecked") @Test public void deadLetterNewRK() throws Exception { declareQueue(TEST_QUEUE_NAME, DLX, "test-other", null, 1); @@ -510,6 +512,7 @@ private void deadLetterTest(Callable deathTrigger, consume(channel, reason); } + @SuppressWarnings("unchecked") public static void consume(final Channel channel, final String reason) throws IOException { consumeN(channel, DLQ, MSG_COUNT, getResponse -> { Map headers = getResponse.getProps().getHeaders(); From 69f3d3ca4cfe309230d094de9a7e80fb891a870f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 15 Mar 2019 09:49:27 +0100 Subject: [PATCH 1065/2114] Squash a few warnings in tests (cherry picked from commit 1bd2ea4508e6206fc84faa81c8158a276446b8f5) --- .../client/test/functional/DeadLetterExchange.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java index f78bd7a264..12e96cf4b8 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java @@ -230,6 +230,7 @@ protected void releaseResources() throws IOException { consumeN(DLQ, MSG_COUNT, WithResponse.NULL); } + @SuppressWarnings("unchecked") @Test public void deadLetterPerMessageTTLRemoved() throws Exception { declareQueue(TEST_QUEUE_NAME, DLX, null, null, 1); channel.queueBind(TEST_QUEUE_NAME, "amq.direct", "test"); @@ -247,11 +248,10 @@ protected void releaseResources() throws IOException { assertNull(getResponse.getProps().getExpiration()); Map headers = getResponse.getProps().getHeaders(); assertNotNull(headers); - ArrayList death = (ArrayList)headers.get("x-death"); + ArrayList death = (ArrayList) headers.get("x-death"); assertNotNull(death); assertDeathReason(death, 0, TEST_QUEUE_NAME, "expired"); - final Map deathHeader = - (Map)death.get(0); + final Map deathHeader = (Map) death.get(0); assertEquals("100", deathHeader.get("original-expiration").toString()); }); } @@ -287,6 +287,7 @@ protected void releaseResources() throws IOException { publishN(MSG_COUNT); } + @SuppressWarnings("unchecked") @Test public void deadLetterTwice() throws Exception { declareQueue(TEST_QUEUE_NAME, DLX, null, null, 1); @@ -308,7 +309,7 @@ protected void releaseResources() throws IOException { consumeN(DLQ2, MSG_COUNT*2, getResponse -> { Map headers = getResponse.getProps().getHeaders(); assertNotNull(headers); - ArrayList death = (ArrayList)headers.get("x-death"); + ArrayList death = (ArrayList) headers.get("x-death"); assertNotNull(death); if (death.size() == 1) { assertDeathReason(death, 0, TEST_QUEUE_NAME, "expired"); @@ -357,6 +358,7 @@ public void handleDelivery(String consumerTag, Envelope envelope, assertTrue(latch.await(10, TimeUnit.SECONDS)); } + @SuppressWarnings("unchecked") @Test public void deadLetterNewRK() throws Exception { declareQueue(TEST_QUEUE_NAME, DLX, "test-other", null, 1); @@ -510,6 +512,7 @@ private void deadLetterTest(Callable deathTrigger, consume(channel, reason); } + @SuppressWarnings("unchecked") public static void consume(final Channel channel, final String reason) throws IOException { consumeN(channel, DLQ, MSG_COUNT, getResponse -> { Map headers = getResponse.getProps().getHeaders(); From 329156821f7b5e023e1d422558503bfb03c3ba34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 15 Mar 2019 15:30:05 +0100 Subject: [PATCH 1066/2114] Track connections left open in tests --- .../client/test/AMQConnectionTest.java | 4 +-- .../client/test/BrokenFramesTest.java | 4 +-- .../rabbitmq/client/test/BrokerTestCase.java | 3 -- .../ChannelAsyncCompletableFutureTest.java | 13 +++---- .../ChannelRpcTimeoutIntegrationTest.java | 4 +-- .../client/test/ConnectionFactoryTest.java | 1 + ...RecoveryAwareAMQConnectionFactoryTest.java | 1 - .../client/test/RpcTopologyRecordingTest.java | 12 +++---- .../com/rabbitmq/client/test/TestUtils.java | 6 ++++ .../test/functional/ConnectionOpen.java | 3 +- .../client/test/functional/Heartbeat.java | 17 ++++----- .../test/functional/UnexpectedFrames.java | 3 +- .../client/test/functional/UserIDHeader.java | 13 ++++--- .../client/test/server/BlockedConnection.java | 13 +++++-- .../test/server/ChannelLimitNegotiation.java | 10 ++++-- src/test/java/com/rabbitmq/tools/Host.java | 36 ++++++++++++++----- 16 files changed, 90 insertions(+), 53 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java b/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java index ae8bc1e258..ece2e42e05 100644 --- a/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java +++ b/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java @@ -51,14 +51,14 @@ public class AMQConnectionTest { private ConnectionFactory factory; private MyExceptionHandler exceptionHandler; - @Before public void setUp() throws Exception { + @Before public void setUp() { _mockFrameHandler = new MockFrameHandler(); factory = TestUtils.connectionFactory(); exceptionHandler = new MyExceptionHandler(); factory.setExceptionHandler(exceptionHandler); } - @After public void tearDown() throws Exception { + @After public void tearDown() { factory = null; _mockFrameHandler = null; } diff --git a/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java b/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java index 1b499e9057..b9853a6731 100644 --- a/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java +++ b/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java @@ -42,12 +42,12 @@ public class BrokenFramesTest { private MyFrameHandler myFrameHandler; private ConnectionFactory factory; - @Before public void setUp() throws Exception { + @Before public void setUp() { myFrameHandler = new MyFrameHandler(); factory = TestUtils.connectionFactory(); } - @After public void tearDown() throws Exception { + @After public void tearDown() { factory = null; myFrameHandler = null; } diff --git a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java index 1a00ca8c1b..2608c0ca2e 100644 --- a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java +++ b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java @@ -20,7 +20,6 @@ import com.rabbitmq.client.impl.nio.NioParams; import com.rabbitmq.tools.Host; import org.junit.After; -import org.junit.Assume; import org.junit.Before; import org.junit.Rule; import org.junit.rules.TestRule; @@ -32,7 +31,6 @@ import javax.net.ssl.SSLContext; import java.io.IOException; import java.security.NoSuchAlgorithmException; -import java.util.Arrays; import java.util.Map; import java.util.UUID; import java.util.concurrent.TimeoutException; @@ -184,7 +182,6 @@ public void checkShutdownSignal(int expectedCode, ShutdownSignalException sse) { Method method = sse.getReason(); channel = null; if (sse.isHardError()) { - connection = null; AMQP.Connection.Close closeMethod = (AMQP.Connection.Close) method; assertEquals(expectedCode, closeMethod.getReplyCode()); } else { diff --git a/src/test/java/com/rabbitmq/client/test/ChannelAsyncCompletableFutureTest.java b/src/test/java/com/rabbitmq/client/test/ChannelAsyncCompletableFutureTest.java index c94e17a7b0..c6e51f777f 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelAsyncCompletableFutureTest.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelAsyncCompletableFutureTest.java @@ -25,10 +25,7 @@ import java.io.IOException; import java.util.UUID; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; +import java.util.concurrent.*; import static org.junit.Assert.assertTrue; @@ -39,13 +36,17 @@ public class ChannelAsyncCompletableFutureTest extends BrokerTestCase { String queue; String exchange; - @Before public void init() { + @Override + protected void createResources() throws IOException, TimeoutException { + super.createResources(); executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); queue = UUID.randomUUID().toString(); exchange = UUID.randomUUID().toString(); } - @After public void tearDown() throws IOException { + @Override + protected void releaseResources() throws IOException { + super.releaseResources(); executor.shutdownNow(); channel.queueDelete(queue); channel.exchangeDelete(exchange); diff --git a/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java b/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java index f880f617da..875d608d96 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java @@ -37,12 +37,12 @@ public class ChannelRpcTimeoutIntegrationTest { ConnectionFactory factory; @Before - public void setUp() throws Exception { + public void setUp() { factory = TestUtils.connectionFactory(); } @After - public void tearDown() throws Exception { + public void tearDown() { factory = null; } diff --git a/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java b/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java index 9a314d1769..5ccb855fd4 100644 --- a/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java +++ b/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java @@ -27,6 +27,7 @@ import com.rabbitmq.client.impl.CredentialsProvider; import com.rabbitmq.client.impl.FrameHandler; import com.rabbitmq.client.impl.FrameHandlerFactory; +import org.junit.AfterClass; import org.junit.Test; import java.io.IOException; diff --git a/src/test/java/com/rabbitmq/client/test/RecoveryAwareAMQConnectionFactoryTest.java b/src/test/java/com/rabbitmq/client/test/RecoveryAwareAMQConnectionFactoryTest.java index 8f8354b2db..704c252bc0 100644 --- a/src/test/java/com/rabbitmq/client/test/RecoveryAwareAMQConnectionFactoryTest.java +++ b/src/test/java/com/rabbitmq/client/test/RecoveryAwareAMQConnectionFactoryTest.java @@ -28,7 +28,6 @@ import java.io.IOException; import java.util.Arrays; -import java.util.List; import java.util.Queue; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.TimeoutException; diff --git a/src/test/java/com/rabbitmq/client/test/RpcTopologyRecordingTest.java b/src/test/java/com/rabbitmq/client/test/RpcTopologyRecordingTest.java index a04baa4682..47c56b9953 100644 --- a/src/test/java/com/rabbitmq/client/test/RpcTopologyRecordingTest.java +++ b/src/test/java/com/rabbitmq/client/test/RpcTopologyRecordingTest.java @@ -17,8 +17,6 @@ import com.rabbitmq.client.*; import com.rabbitmq.client.impl.AMQImpl; -import org.junit.After; -import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -57,8 +55,9 @@ protected ConnectionFactory newConnectionFactory() { return connectionFactory; } - @Before - public void init() { + @Override + protected void createResources() throws IOException, TimeoutException { + super.createResources(); queue = UUID.randomUUID().toString(); exchange = UUID.randomUUID().toString(); routingKey = UUID.randomUUID().toString(); @@ -67,8 +66,9 @@ public void init() { routingKey2 = "e2e-" + UUID.randomUUID().toString(); } - @After - public void tearDown() throws IOException { + @Override + protected void releaseResources() throws IOException { + super.releaseResources(); channel.exchangeDelete(exchange); channel.exchangeDelete(exchange2); } diff --git a/src/test/java/com/rabbitmq/client/test/TestUtils.java b/src/test/java/com/rabbitmq/client/test/TestUtils.java index b6cb834773..adc5ffb759 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtils.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtils.java @@ -67,6 +67,12 @@ public static void close(Connection connection) { } } + public static void abort(Connection connection) { + if (connection != null) { + connection.abort(); + } + } + public static SSLContext getSSLContext() throws NoSuchAlgorithmException { SSLContext c = null; diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionOpen.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionOpen.java index 5f4f1e88c6..91b6f18ba9 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionOpen.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionOpen.java @@ -43,13 +43,12 @@ */ public class ConnectionOpen { @Test public void correctProtocolHeader() throws IOException { - ConnectionFactory factory = TestUtils.connectionFactory(); SocketFrameHandler fh = new SocketFrameHandler(SocketFactory.getDefault().createSocket("localhost", AMQP.PROTOCOL.PORT)); fh.sendHeader(); AMQCommand command = new AMQCommand(); while (!command.handleFrame(fh.readFrame())) { } Method m = command.getMethod(); - // System.out.println(m.getClass()); + assertTrue("First command must be Connection.start", m instanceof AMQP.Connection.Start); AMQP.Connection.Start start = (AMQP.Connection.Start) m; diff --git a/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java b/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java index fe0f904103..14c58c60a0 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java @@ -16,6 +16,7 @@ package com.rabbitmq.client.test.functional; +import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; import com.rabbitmq.client.test.BrokerTestCase; import org.junit.Test; @@ -26,19 +27,19 @@ public class Heartbeat extends BrokerTestCase { - public Heartbeat() - { - super(); - connectionFactory.setRequestedHeartbeat(1); + @Override + protected ConnectionFactory newConnectionFactory() { + ConnectionFactory cf = super.newConnectionFactory(); + cf.setRequestedHeartbeat(1); + return cf; } - @Test public void heartbeat() - throws IOException, InterruptedException - { + @Test + public void heartbeat() throws InterruptedException { assertEquals(1, connection.getHeartbeat()); Thread.sleep(3100); assertTrue(connection.isOpen()); - ((AutorecoveringConnection)connection).getDelegate().setHeartbeat(0); + ((AutorecoveringConnection) connection).getDelegate().setHeartbeat(0); assertEquals(0, connection.getHeartbeat()); Thread.sleep(3100); assertFalse(connection.isOpen()); diff --git a/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java b/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java index 698d8a8952..2599a7663c 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java +++ b/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java @@ -17,7 +17,6 @@ import com.rabbitmq.client.AMQP; import com.rabbitmq.client.ConnectionFactory; -import com.rabbitmq.client.DefaultSocketConfigurator; import com.rabbitmq.client.SocketConfigurators; import com.rabbitmq.client.impl.*; import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; @@ -35,7 +34,7 @@ public class UnexpectedFrames extends BrokerTestCase { private interface Confuser { - public Frame confuse(Frame frame) throws IOException; + Frame confuse(Frame frame) throws IOException; } private static class ConfusedFrameHandler extends SocketFrameHandler { diff --git a/src/test/java/com/rabbitmq/client/test/functional/UserIDHeader.java b/src/test/java/com/rabbitmq/client/test/functional/UserIDHeader.java index e31bb64bb1..7d64fee7a7 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/UserIDHeader.java +++ b/src/test/java/com/rabbitmq/client/test/functional/UserIDHeader.java @@ -20,6 +20,8 @@ import java.io.IOException; import java.util.concurrent.TimeoutException; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; import org.junit.Test; import com.rabbitmq.client.AMQP; @@ -48,17 +50,18 @@ public class UserIDHeader extends BrokerTestCase { @Test public void impersonatedUserId() throws IOException, TimeoutException { Host.rabbitmqctl("set_user_tags guest administrator impersonator"); - connection = null; - channel = null; - setUp(); - try { - publish(BAD); + try (Connection c = connectionFactory.newConnection()){ + publish(BAD, c.createChannel()); } finally { Host.rabbitmqctl("set_user_tags guest administrator"); } } private void publish(AMQP.BasicProperties properties) throws IOException { + publish(properties, this.channel); + } + + private void publish(AMQP.BasicProperties properties, Channel channel) throws IOException { channel.basicPublish("amq.fanout", "", properties, "".getBytes()); channel.queueDeclare(); // To flush the channel } diff --git a/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java b/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java index 1c75628ec7..61a84ae731 100644 --- a/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java @@ -50,7 +50,12 @@ protected void releaseResources() throws IOException { block(); publish(connection); - assertTrue(latch.await(10, TimeUnit.SECONDS)); + try { + assertTrue(latch.await(10, TimeUnit.SECONDS)); + } finally { + TestUtils.abort(connection); + } + } // this test first triggers an alarm, then opens a @@ -62,7 +67,11 @@ protected void releaseResources() throws IOException { Connection connection = connection(latch); publish(connection); - assertTrue(latch.await(10, TimeUnit.SECONDS)); + try { + assertTrue(latch.await(10, TimeUnit.SECONDS)); + } finally { + TestUtils.abort(connection); + } } private Connection connection(final CountDownLatch latch) throws IOException, TimeoutException { diff --git a/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java b/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java index 6111e2660e..f6500b0677 100644 --- a/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java +++ b/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java @@ -42,6 +42,7 @@ import com.rabbitmq.tools.Host; public class ChannelLimitNegotiation extends BrokerTestCase { + class SpecialConnection extends AMQConnection { private final int channelMax; @@ -68,8 +69,9 @@ protected int negotiateChannelMax(int requestedChannelMax, int serverMax) { ConnectionFactory cf = TestUtils.connectionFactory(); cf.setRequestedChannelMax(n); - Connection conn = cf.newConnection(); - assertEquals(n, conn.getChannelMax()); + try (Connection conn = cf.newConnection()) { + assertEquals(n, conn.getChannelMax()); + } } @Test public void channelMaxGreaterThanServerValue() throws Exception { @@ -91,10 +93,11 @@ protected int negotiateChannelMax(int requestedChannelMax, int serverMax) { @Test public void openingTooManyChannels() throws Exception { int n = 48; + Connection conn = null; try { Host.rabbitmqctl("eval 'application:set_env(rabbit, channel_max, " + n + ").'"); ConnectionFactory cf = TestUtils.connectionFactory(); - Connection conn = cf.newConnection(); + conn = cf.newConnection(); assertEquals(n, conn.getChannelMax()); for (int i = 1; i <= n; i++) { @@ -118,6 +121,7 @@ public void shutdownCompleted(ShutdownSignalException cause) { } catch (IOException e) { checkShutdownSignal(530, e); } finally { + TestUtils.abort(conn); Host.rabbitmqctl("eval 'application:set_env(rabbit, channel_max, 0).'"); } } diff --git a/src/test/java/com/rabbitmq/tools/Host.java b/src/test/java/com/rabbitmq/tools/Host.java index 564d8f217c..0c9e7dbbf1 100644 --- a/src/test/java/com/rabbitmq/tools/Host.java +++ b/src/test/java/com/rabbitmq/tools/Host.java @@ -22,6 +22,7 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import com.rabbitmq.client.Connection; @@ -222,10 +223,12 @@ public static void closeConnection(NetworkConnection c) throws IOException { public static class ConnectionInfo { private final String pid; private final int peerPort; + private final String clientProperties; - public ConnectionInfo(String pid, int peerPort) { + public ConnectionInfo(String pid, int peerPort, String clientProperties) { this.pid = pid; this.peerPort = peerPort; + this.clientProperties = clientProperties; } public String getPid() { @@ -235,10 +238,23 @@ public String getPid() { public int getPeerPort() { return peerPort; } + + public String getClientProperties() { + return clientProperties; + } + + @Override + public String toString() { + return "ConnectionInfo{" + + "pid='" + pid + '\'' + + ", peerPort=" + peerPort + + ", clientProperties='" + clientProperties + '\'' + + '}'; + } } public static List listConnections() throws IOException { - String output = capture(rabbitmqctl("list_connections -q pid peer_port").getInputStream()); + String output = capture(rabbitmqctl("list_connections -q pid peer_port client_properties").getInputStream()); // output (header line presence depends on broker version): // pid peer_port // 58713 @@ -246,13 +262,15 @@ public static List listConnections() throws IOException { ArrayList result = new ArrayList(); for (String line : allLines) { - // line: 58713 - String[] columns = line.split("\t"); - // can be also header line, so ignoring NumberFormatException - try { - result.add(new ConnectionInfo(columns[0], Integer.valueOf(columns[1]))); - } catch (NumberFormatException e) { - // OK + if (line != null && !line.trim().isEmpty()) { + // line: 58713 + String[] columns = line.split("\t"); + // can be also header line, so ignoring NumberFormatException + try { + result.add(new ConnectionInfo(columns[0], Integer.valueOf(columns[1]), columns[2])); + } catch (NumberFormatException e) { + // OK + } } } return result; From b0a599c9137303088a3229aff222f2c413f095f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 15 Mar 2019 15:30:05 +0100 Subject: [PATCH 1067/2114] Track connections left open in tests (cherry picked from commit 329156821f7b5e023e1d422558503bfb03c3ba34) Conflicts: src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java --- .../client/test/AMQConnectionTest.java | 4 +-- .../client/test/BrokenFramesTest.java | 4 +-- .../rabbitmq/client/test/BrokerTestCase.java | 3 -- .../ChannelAsyncCompletableFutureTest.java | 13 +++---- .../ChannelRpcTimeoutIntegrationTest.java | 4 +-- .../client/test/ConnectionFactoryTest.java | 2 -- ...RecoveryAwareAMQConnectionFactoryTest.java | 1 - .../client/test/RpcTopologyRecordingTest.java | 12 +++---- .../com/rabbitmq/client/test/TestUtils.java | 6 ++++ .../test/functional/ConnectionOpen.java | 3 +- .../client/test/functional/Heartbeat.java | 17 ++++----- .../test/functional/UnexpectedFrames.java | 3 +- .../client/test/functional/UserIDHeader.java | 13 ++++--- .../client/test/server/BlockedConnection.java | 13 +++++-- .../test/server/ChannelLimitNegotiation.java | 10 ++++-- src/test/java/com/rabbitmq/tools/Host.java | 36 ++++++++++++++----- 16 files changed, 89 insertions(+), 55 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java b/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java index ae8bc1e258..ece2e42e05 100644 --- a/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java +++ b/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java @@ -51,14 +51,14 @@ public class AMQConnectionTest { private ConnectionFactory factory; private MyExceptionHandler exceptionHandler; - @Before public void setUp() throws Exception { + @Before public void setUp() { _mockFrameHandler = new MockFrameHandler(); factory = TestUtils.connectionFactory(); exceptionHandler = new MyExceptionHandler(); factory.setExceptionHandler(exceptionHandler); } - @After public void tearDown() throws Exception { + @After public void tearDown() { factory = null; _mockFrameHandler = null; } diff --git a/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java b/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java index 1b499e9057..b9853a6731 100644 --- a/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java +++ b/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java @@ -42,12 +42,12 @@ public class BrokenFramesTest { private MyFrameHandler myFrameHandler; private ConnectionFactory factory; - @Before public void setUp() throws Exception { + @Before public void setUp() { myFrameHandler = new MyFrameHandler(); factory = TestUtils.connectionFactory(); } - @After public void tearDown() throws Exception { + @After public void tearDown() { factory = null; myFrameHandler = null; } diff --git a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java index 1a00ca8c1b..2608c0ca2e 100644 --- a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java +++ b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java @@ -20,7 +20,6 @@ import com.rabbitmq.client.impl.nio.NioParams; import com.rabbitmq.tools.Host; import org.junit.After; -import org.junit.Assume; import org.junit.Before; import org.junit.Rule; import org.junit.rules.TestRule; @@ -32,7 +31,6 @@ import javax.net.ssl.SSLContext; import java.io.IOException; import java.security.NoSuchAlgorithmException; -import java.util.Arrays; import java.util.Map; import java.util.UUID; import java.util.concurrent.TimeoutException; @@ -184,7 +182,6 @@ public void checkShutdownSignal(int expectedCode, ShutdownSignalException sse) { Method method = sse.getReason(); channel = null; if (sse.isHardError()) { - connection = null; AMQP.Connection.Close closeMethod = (AMQP.Connection.Close) method; assertEquals(expectedCode, closeMethod.getReplyCode()); } else { diff --git a/src/test/java/com/rabbitmq/client/test/ChannelAsyncCompletableFutureTest.java b/src/test/java/com/rabbitmq/client/test/ChannelAsyncCompletableFutureTest.java index c94e17a7b0..c6e51f777f 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelAsyncCompletableFutureTest.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelAsyncCompletableFutureTest.java @@ -25,10 +25,7 @@ import java.io.IOException; import java.util.UUID; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; +import java.util.concurrent.*; import static org.junit.Assert.assertTrue; @@ -39,13 +36,17 @@ public class ChannelAsyncCompletableFutureTest extends BrokerTestCase { String queue; String exchange; - @Before public void init() { + @Override + protected void createResources() throws IOException, TimeoutException { + super.createResources(); executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); queue = UUID.randomUUID().toString(); exchange = UUID.randomUUID().toString(); } - @After public void tearDown() throws IOException { + @Override + protected void releaseResources() throws IOException { + super.releaseResources(); executor.shutdownNow(); channel.queueDelete(queue); channel.exchangeDelete(exchange); diff --git a/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java b/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java index f880f617da..875d608d96 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java @@ -37,12 +37,12 @@ public class ChannelRpcTimeoutIntegrationTest { ConnectionFactory factory; @Before - public void setUp() throws Exception { + public void setUp() { factory = TestUtils.connectionFactory(); } @After - public void tearDown() throws Exception { + public void tearDown() { factory = null; } diff --git a/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java b/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java index cccabd243e..adca51336a 100644 --- a/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java +++ b/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java @@ -27,8 +27,6 @@ import com.rabbitmq.client.impl.CredentialsProvider; import com.rabbitmq.client.impl.FrameHandler; import com.rabbitmq.client.impl.FrameHandlerFactory; -import org.hamcrest.Matchers; -import org.junit.Assert; import org.junit.Test; import java.io.IOException; diff --git a/src/test/java/com/rabbitmq/client/test/RecoveryAwareAMQConnectionFactoryTest.java b/src/test/java/com/rabbitmq/client/test/RecoveryAwareAMQConnectionFactoryTest.java index 8f8354b2db..704c252bc0 100644 --- a/src/test/java/com/rabbitmq/client/test/RecoveryAwareAMQConnectionFactoryTest.java +++ b/src/test/java/com/rabbitmq/client/test/RecoveryAwareAMQConnectionFactoryTest.java @@ -28,7 +28,6 @@ import java.io.IOException; import java.util.Arrays; -import java.util.List; import java.util.Queue; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.TimeoutException; diff --git a/src/test/java/com/rabbitmq/client/test/RpcTopologyRecordingTest.java b/src/test/java/com/rabbitmq/client/test/RpcTopologyRecordingTest.java index a04baa4682..47c56b9953 100644 --- a/src/test/java/com/rabbitmq/client/test/RpcTopologyRecordingTest.java +++ b/src/test/java/com/rabbitmq/client/test/RpcTopologyRecordingTest.java @@ -17,8 +17,6 @@ import com.rabbitmq.client.*; import com.rabbitmq.client.impl.AMQImpl; -import org.junit.After; -import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -57,8 +55,9 @@ protected ConnectionFactory newConnectionFactory() { return connectionFactory; } - @Before - public void init() { + @Override + protected void createResources() throws IOException, TimeoutException { + super.createResources(); queue = UUID.randomUUID().toString(); exchange = UUID.randomUUID().toString(); routingKey = UUID.randomUUID().toString(); @@ -67,8 +66,9 @@ public void init() { routingKey2 = "e2e-" + UUID.randomUUID().toString(); } - @After - public void tearDown() throws IOException { + @Override + protected void releaseResources() throws IOException { + super.releaseResources(); channel.exchangeDelete(exchange); channel.exchangeDelete(exchange2); } diff --git a/src/test/java/com/rabbitmq/client/test/TestUtils.java b/src/test/java/com/rabbitmq/client/test/TestUtils.java index b6cb834773..adc5ffb759 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtils.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtils.java @@ -67,6 +67,12 @@ public static void close(Connection connection) { } } + public static void abort(Connection connection) { + if (connection != null) { + connection.abort(); + } + } + public static SSLContext getSSLContext() throws NoSuchAlgorithmException { SSLContext c = null; diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionOpen.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionOpen.java index 5f4f1e88c6..91b6f18ba9 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionOpen.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionOpen.java @@ -43,13 +43,12 @@ */ public class ConnectionOpen { @Test public void correctProtocolHeader() throws IOException { - ConnectionFactory factory = TestUtils.connectionFactory(); SocketFrameHandler fh = new SocketFrameHandler(SocketFactory.getDefault().createSocket("localhost", AMQP.PROTOCOL.PORT)); fh.sendHeader(); AMQCommand command = new AMQCommand(); while (!command.handleFrame(fh.readFrame())) { } Method m = command.getMethod(); - // System.out.println(m.getClass()); + assertTrue("First command must be Connection.start", m instanceof AMQP.Connection.Start); AMQP.Connection.Start start = (AMQP.Connection.Start) m; diff --git a/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java b/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java index fe0f904103..14c58c60a0 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java @@ -16,6 +16,7 @@ package com.rabbitmq.client.test.functional; +import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; import com.rabbitmq.client.test.BrokerTestCase; import org.junit.Test; @@ -26,19 +27,19 @@ public class Heartbeat extends BrokerTestCase { - public Heartbeat() - { - super(); - connectionFactory.setRequestedHeartbeat(1); + @Override + protected ConnectionFactory newConnectionFactory() { + ConnectionFactory cf = super.newConnectionFactory(); + cf.setRequestedHeartbeat(1); + return cf; } - @Test public void heartbeat() - throws IOException, InterruptedException - { + @Test + public void heartbeat() throws InterruptedException { assertEquals(1, connection.getHeartbeat()); Thread.sleep(3100); assertTrue(connection.isOpen()); - ((AutorecoveringConnection)connection).getDelegate().setHeartbeat(0); + ((AutorecoveringConnection) connection).getDelegate().setHeartbeat(0); assertEquals(0, connection.getHeartbeat()); Thread.sleep(3100); assertFalse(connection.isOpen()); diff --git a/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java b/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java index 698d8a8952..2599a7663c 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java +++ b/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java @@ -17,7 +17,6 @@ import com.rabbitmq.client.AMQP; import com.rabbitmq.client.ConnectionFactory; -import com.rabbitmq.client.DefaultSocketConfigurator; import com.rabbitmq.client.SocketConfigurators; import com.rabbitmq.client.impl.*; import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; @@ -35,7 +34,7 @@ public class UnexpectedFrames extends BrokerTestCase { private interface Confuser { - public Frame confuse(Frame frame) throws IOException; + Frame confuse(Frame frame) throws IOException; } private static class ConfusedFrameHandler extends SocketFrameHandler { diff --git a/src/test/java/com/rabbitmq/client/test/functional/UserIDHeader.java b/src/test/java/com/rabbitmq/client/test/functional/UserIDHeader.java index e31bb64bb1..7d64fee7a7 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/UserIDHeader.java +++ b/src/test/java/com/rabbitmq/client/test/functional/UserIDHeader.java @@ -20,6 +20,8 @@ import java.io.IOException; import java.util.concurrent.TimeoutException; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; import org.junit.Test; import com.rabbitmq.client.AMQP; @@ -48,17 +50,18 @@ public class UserIDHeader extends BrokerTestCase { @Test public void impersonatedUserId() throws IOException, TimeoutException { Host.rabbitmqctl("set_user_tags guest administrator impersonator"); - connection = null; - channel = null; - setUp(); - try { - publish(BAD); + try (Connection c = connectionFactory.newConnection()){ + publish(BAD, c.createChannel()); } finally { Host.rabbitmqctl("set_user_tags guest administrator"); } } private void publish(AMQP.BasicProperties properties) throws IOException { + publish(properties, this.channel); + } + + private void publish(AMQP.BasicProperties properties, Channel channel) throws IOException { channel.basicPublish("amq.fanout", "", properties, "".getBytes()); channel.queueDeclare(); // To flush the channel } diff --git a/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java b/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java index 1c75628ec7..61a84ae731 100644 --- a/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java @@ -50,7 +50,12 @@ protected void releaseResources() throws IOException { block(); publish(connection); - assertTrue(latch.await(10, TimeUnit.SECONDS)); + try { + assertTrue(latch.await(10, TimeUnit.SECONDS)); + } finally { + TestUtils.abort(connection); + } + } // this test first triggers an alarm, then opens a @@ -62,7 +67,11 @@ protected void releaseResources() throws IOException { Connection connection = connection(latch); publish(connection); - assertTrue(latch.await(10, TimeUnit.SECONDS)); + try { + assertTrue(latch.await(10, TimeUnit.SECONDS)); + } finally { + TestUtils.abort(connection); + } } private Connection connection(final CountDownLatch latch) throws IOException, TimeoutException { diff --git a/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java b/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java index 6111e2660e..f6500b0677 100644 --- a/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java +++ b/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java @@ -42,6 +42,7 @@ import com.rabbitmq.tools.Host; public class ChannelLimitNegotiation extends BrokerTestCase { + class SpecialConnection extends AMQConnection { private final int channelMax; @@ -68,8 +69,9 @@ protected int negotiateChannelMax(int requestedChannelMax, int serverMax) { ConnectionFactory cf = TestUtils.connectionFactory(); cf.setRequestedChannelMax(n); - Connection conn = cf.newConnection(); - assertEquals(n, conn.getChannelMax()); + try (Connection conn = cf.newConnection()) { + assertEquals(n, conn.getChannelMax()); + } } @Test public void channelMaxGreaterThanServerValue() throws Exception { @@ -91,10 +93,11 @@ protected int negotiateChannelMax(int requestedChannelMax, int serverMax) { @Test public void openingTooManyChannels() throws Exception { int n = 48; + Connection conn = null; try { Host.rabbitmqctl("eval 'application:set_env(rabbit, channel_max, " + n + ").'"); ConnectionFactory cf = TestUtils.connectionFactory(); - Connection conn = cf.newConnection(); + conn = cf.newConnection(); assertEquals(n, conn.getChannelMax()); for (int i = 1; i <= n; i++) { @@ -118,6 +121,7 @@ public void shutdownCompleted(ShutdownSignalException cause) { } catch (IOException e) { checkShutdownSignal(530, e); } finally { + TestUtils.abort(conn); Host.rabbitmqctl("eval 'application:set_env(rabbit, channel_max, 0).'"); } } diff --git a/src/test/java/com/rabbitmq/tools/Host.java b/src/test/java/com/rabbitmq/tools/Host.java index 564d8f217c..0c9e7dbbf1 100644 --- a/src/test/java/com/rabbitmq/tools/Host.java +++ b/src/test/java/com/rabbitmq/tools/Host.java @@ -22,6 +22,7 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import com.rabbitmq.client.Connection; @@ -222,10 +223,12 @@ public static void closeConnection(NetworkConnection c) throws IOException { public static class ConnectionInfo { private final String pid; private final int peerPort; + private final String clientProperties; - public ConnectionInfo(String pid, int peerPort) { + public ConnectionInfo(String pid, int peerPort, String clientProperties) { this.pid = pid; this.peerPort = peerPort; + this.clientProperties = clientProperties; } public String getPid() { @@ -235,10 +238,23 @@ public String getPid() { public int getPeerPort() { return peerPort; } + + public String getClientProperties() { + return clientProperties; + } + + @Override + public String toString() { + return "ConnectionInfo{" + + "pid='" + pid + '\'' + + ", peerPort=" + peerPort + + ", clientProperties='" + clientProperties + '\'' + + '}'; + } } public static List listConnections() throws IOException { - String output = capture(rabbitmqctl("list_connections -q pid peer_port").getInputStream()); + String output = capture(rabbitmqctl("list_connections -q pid peer_port client_properties").getInputStream()); // output (header line presence depends on broker version): // pid peer_port // 58713 @@ -246,13 +262,15 @@ public static List listConnections() throws IOException { ArrayList result = new ArrayList(); for (String line : allLines) { - // line: 58713 - String[] columns = line.split("\t"); - // can be also header line, so ignoring NumberFormatException - try { - result.add(new ConnectionInfo(columns[0], Integer.valueOf(columns[1]))); - } catch (NumberFormatException e) { - // OK + if (line != null && !line.trim().isEmpty()) { + // line: 58713 + String[] columns = line.split("\t"); + // can be also header line, so ignoring NumberFormatException + try { + result.add(new ConnectionInfo(columns[0], Integer.valueOf(columns[1]), columns[2])); + } catch (NumberFormatException e) { + // OK + } } } return result; From 4c95c600cf9ed05993c53cff7028b610d4785f96 Mon Sep 17 00:00:00 2001 From: Spring Operator Date: Fri, 15 Mar 2019 21:11:26 -0500 Subject: [PATCH 1068/2114] URL Cleanup This commit updates URLs to prefer the https protocol. Redirects are not followed to avoid accidentally expanding intentionally shortened URLs (i.e. if using a URL shortener). # Fixed URLs ## Fixed Success These URLs were switched to an https URL with a 2xx status. While the status was successful, your review is still recommended. * http://maven.apache.org/xsd/maven-4.0.0.xsd with 1 occurrences migrated to: https://maven.apache.org/xsd/maven-4.0.0.xsd ([https](https://maven.apache.org/xsd/maven-4.0.0.xsd) result 200). # Ignored These URLs were intentionally ignored. * http://maven.apache.org/POM/4.0.0 with 2 occurrences * http://www.w3.org/2001/XMLSchema-instance with 1 occurrences --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7ee17b23e7..4da58c9d4f 100644 --- a/pom.xml +++ b/pom.xml @@ -1,5 +1,5 @@ - + 4.0.0 com.rabbitmq From ac46ed2585891e86b62bd2c61a731ef59c1b5974 Mon Sep 17 00:00:00 2001 From: Spring Operator Date: Tue, 19 Mar 2019 20:09:21 -0500 Subject: [PATCH 1069/2114] URL Cleanup This commit updates URLs to prefer the https protocol. Redirects are not followed to avoid accidentally expanding intentionally shortened URLs (i.e. if using a URL shortener). # Fixed URLs ## Fixed Success These URLs were switched to an https URL with a 2xx status. While the status was successful, your review is still recommended. * http://maven.apache.org/xsd/maven-4.0.0.xsd with 1 occurrences migrated to: https://maven.apache.org/xsd/maven-4.0.0.xsd ([https](https://maven.apache.org/xsd/maven-4.0.0.xsd) result 200). # Ignored These URLs were intentionally ignored. * http://maven.apache.org/POM/4.0.0 with 2 occurrences * http://www.w3.org/2001/XMLSchema-instance with 1 occurrences --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6221fd2780..9f8206a753 100644 --- a/pom.xml +++ b/pom.xml @@ -1,5 +1,5 @@ - + 4.0.0 com.rabbitmq From dc71205446d4a3955f50d30514ed689925fa0fe5 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 20 Mar 2019 10:33:15 +0300 Subject: [PATCH 1070/2114] Travis: use Erlang 21.3, Elixir 1.8.1 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 1e9e2a0485..4bf2802d96 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,7 +22,7 @@ env: otp_release: - "20.3" - - "21.2" + - "21.3" before_script: - elixir --version From 55d1d89f54116c70bc3971e5d4e9d3dc917aa33a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 20 Mar 2019 09:02:24 +0100 Subject: [PATCH 1071/2114] Remove some logging in tests --- src/test/resources/logback-test.xml | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml index 596182704c..ee88f442c2 100644 --- a/src/test/resources/logback-test.xml +++ b/src/test/resources/logback-test.xml @@ -5,8 +5,6 @@ - - From 489ebacc85cd0cd49aa3b6ec97e962009028c528 Mon Sep 17 00:00:00 2001 From: Spring Operator Date: Wed, 20 Mar 2019 03:16:18 -0500 Subject: [PATCH 1072/2114] URL Cleanup This commit updates URLs to prefer the https protocol. Redirects are not followed to avoid accidentally expanding intentionally shortened URLs (i.e. if using a URL shortener). # HTTP URLs that Could Not Be Fixed These URLs were unable to be fixed. Please review them to see if they can be manually resolved. * http://javadoc.iaik.tugraz.at/iaik_jce/current/iaik/asn1/BIT_STRING.html (200) with 1 occurrences could not be migrated: ([https](https://javadoc.iaik.tugraz.at/iaik_jce/current/iaik/asn1/BIT_STRING.html) result NotSslRecordException). * http://luca.ntop.org/Teaching/Appunti/asn1.html (200) with 1 occurrences could not be migrated: ([https](https://luca.ntop.org/Teaching/Appunti/asn1.html) result SSLHandshakeException). # Fixed URLs ## Fixed Success These URLs were switched to an https URL with a 2xx status. While the status was successful, your review is still recommended. * http://github.com/rabbitmq/ with 1 occurrences migrated to: https://github.com/rabbitmq/ ([https](https://github.com/rabbitmq/) result 200). * http://search.maven.org/ with 1 occurrences migrated to: https://search.maven.org/ ([https](https://search.maven.org/) result 200). * http://stackoverflow.com/questions/6701948/efficient-way-to-compare-version-strings-in-java with 1 occurrences migrated to: https://stackoverflow.com/questions/6701948/efficient-way-to-compare-version-strings-in-java ([https](https://stackoverflow.com/questions/6701948/efficient-way-to-compare-version-strings-in-java) result 200). * http://www.amqp.org/ with 1 occurrences migrated to: https://www.amqp.org/ ([https](https://www.amqp.org/) result 200). * http://www.apple.com/DTDs/PropertyList-1.0.dtd with 1 occurrences migrated to: https://www.apple.com/DTDs/PropertyList-1.0.dtd ([https](https://www.apple.com/DTDs/PropertyList-1.0.dtd) result 200). * http://www.json.org/ with 1 occurrences migrated to: https://www.json.org/ ([https](https://www.json.org/) result 200). * http://json-rpc.org (302) with 1 occurrences migrated to: https://www.jsonrpc.org/ ([https](https://json-rpc.org) result 200). * http://www.rabbitmq.com with 1 occurrences migrated to: https://www.rabbitmq.com ([https](https://www.rabbitmq.com) result 200). * http://www.rabbitmq.com/ with 1 occurrences migrated to: https://www.rabbitmq.com/ ([https](https://www.rabbitmq.com/) result 200). * http://www.rabbitmq.com/alarms.html with 6 occurrences migrated to: https://www.rabbitmq.com/alarms.html ([https](https://www.rabbitmq.com/alarms.html) result 200). * http://www.rabbitmq.com/api-guide.html with 33 occurrences migrated to: https://www.rabbitmq.com/api-guide.html ([https](https://www.rabbitmq.com/api-guide.html) result 200). * http://www.rabbitmq.com/build-java-client.html with 1 occurrences migrated to: https://www.rabbitmq.com/build-java-client.html ([https](https://www.rabbitmq.com/build-java-client.html) result 200). * http://www.rabbitmq.com/confirms.html with 1 occurrences migrated to: https://www.rabbitmq.com/confirms.html ([https](https://www.rabbitmq.com/confirms.html) result 200). * http://www.rabbitmq.com/getstarted.html with 2 occurrences migrated to: https://www.rabbitmq.com/getstarted.html ([https](https://www.rabbitmq.com/getstarted.html) result 200). * http://www.rabbitmq.com/specification.html with 1 occurrences migrated to: https://www.rabbitmq.com/specification.html ([https](https://www.rabbitmq.com/specification.html) result 200). * http://contributor-covenant.org with 1 occurrences migrated to: https://contributor-covenant.org ([https](https://contributor-covenant.org) result 301). * http://contributor-covenant.org/version/1/3/0/ with 1 occurrences migrated to: https://contributor-covenant.org/version/1/3/0/ ([https](https://contributor-covenant.org/version/1/3/0/) result 301). * http://rabbitmq.com/heartbeats.html with 1 occurrences migrated to: https://rabbitmq.com/heartbeats.html ([https](https://rabbitmq.com/heartbeats.html) result 301). * http://www.mozilla.org/MPL/ with 1 occurrences migrated to: https://www.mozilla.org/MPL/ ([https](https://www.mozilla.org/MPL/) result 301). * http://creativecommons.org/licenses/publicdomain with 1 occurrences migrated to: https://creativecommons.org/licenses/publicdomain ([https](https://creativecommons.org/licenses/publicdomain) result 302). --- CODE_OF_CONDUCT.md | 4 +- LICENSE-MPL-RabbitMQ | 2 +- README.in | 2 +- README.md | 6 +- doc/channels/worktransition.graffle | 2 +- .../java/com/rabbitmq/client/Channel.java | 22 +++---- .../java/com/rabbitmq/client/Connection.java | 6 +- .../rabbitmq/client/ConnectionFactory.java | 58 +++++++++---------- src/main/java/com/rabbitmq/client/Method.java | 2 +- .../rabbitmq/client/impl/AMQConnection.java | 2 +- .../impl/VariableLinkedBlockingQueue.java | 2 +- .../rabbitmq/tools/jsonrpc/JsonRpcClient.java | 4 +- .../com/rabbitmq/client/test/AmqpUriTest.java | 2 +- .../com/rabbitmq/client/test/TestUtils.java | 2 +- 14 files changed, 58 insertions(+), 58 deletions(-) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 1f6ef1c576..08697906fd 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -40,5 +40,5 @@ appropriate to the circumstances. Maintainers are obligated to maintain confiden with regard to the reporter of an incident. This Code of Conduct is adapted from the -[Contributor Covenant](http://contributor-covenant.org), version 1.3.0, available at -[contributor-covenant.org/version/1/3/0/](http://contributor-covenant.org/version/1/3/0/) +[Contributor Covenant](https://contributor-covenant.org), version 1.3.0, available at +[contributor-covenant.org/version/1/3/0/](https://contributor-covenant.org/version/1/3/0/) diff --git a/LICENSE-MPL-RabbitMQ b/LICENSE-MPL-RabbitMQ index 02ee669400..b237a959b0 100644 --- a/LICENSE-MPL-RabbitMQ +++ b/LICENSE-MPL-RabbitMQ @@ -437,7 +437,7 @@ EXHIBIT A -Mozilla Public License. ``The contents of this file are subject to the Mozilla Public License Version 1.1 (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.mozilla.org/MPL/ + https://www.mozilla.org/MPL/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the diff --git a/README.in b/README.in index e9ccd32f24..c00367a7ab 100644 --- a/README.in +++ b/README.in @@ -1,4 +1,4 @@ -Please see http://www.rabbitmq.com/build-java-client.html for build +Please see https://www.rabbitmq.com/build-java-client.html for build instructions. For your convenience, a text copy of these instructions is available diff --git a/README.md b/README.md index 6bd933a167..18bc738950 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ # RabbitMQ Java Client -This repository contains source code of the [RabbitMQ Java client](http://www.rabbitmq.com/api-guide.html). -The client is maintained by the [RabbitMQ team at Pivotal](http://github.com/rabbitmq/). +This repository contains source code of the [RabbitMQ Java client](https://www.rabbitmq.com/api-guide.html). +The client is maintained by the [RabbitMQ team at Pivotal](https://github.com/rabbitmq/). ## Dependency (Maven Artifact) -Maven artifacts are [released to Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3Acom.rabbitmq%20a%3Aamqp-client) +Maven artifacts are [released to Maven Central](https://search.maven.org/#search%7Cga%7C1%7Cg%3Acom.rabbitmq%20a%3Aamqp-client) via [RabbitMQ Maven repository on Bintray](https://bintray.com/rabbitmq/maven). There's also a [Maven repository with milestone releases](https://bintray.com/rabbitmq/maven-milestones). [Snapshots are available](https://oss.sonatype.org/content/repositories/snapshots/com/rabbitmq/amqp-client/) as well. diff --git a/doc/channels/worktransition.graffle b/doc/channels/worktransition.graffle index a8c2d6ce8e..a1feddfa7f 100644 --- a/doc/channels/worktransition.graffle +++ b/doc/channels/worktransition.graffle @@ -1,5 +1,5 @@ - + ActiveLayerIndex diff --git a/src/main/java/com/rabbitmq/client/Channel.java b/src/main/java/com/rabbitmq/client/Channel.java index 6279bf881f..c4312e041a 100644 --- a/src/main/java/com/rabbitmq/client/Channel.java +++ b/src/main/java/com/rabbitmq/client/Channel.java @@ -32,11 +32,11 @@ * this interface are part of the public API. * *

Tutorials

- * RabbitMQ tutorials demonstrate how + * RabbitMQ tutorials demonstrate how * key methods of this interface are used. * *

User Guide

- * See Java Client User Guide. + * See Java Client User Guide. * *

Concurrency Considerations

*

@@ -47,13 +47,13 @@ * multiple threads. While some operations on channels are safe to invoke * concurrently, some are not and will result in incorrect frame interleaving * on the wire. Sharing channels between threads will also interfere with - * Publisher Confirms. + * Publisher Confirms. * * As such, applications need to use a {@link Channel} per thread. *

* - * @see RabbitMQ tutorials - * @see RabbitMQ Java Client User Guide + * @see RabbitMQ tutorials + * @see RabbitMQ Java Client User Guide */ public interface Channel extends ShutdownNotifier, AutoCloseable { /** @@ -243,10 +243,10 @@ public interface Channel extends ShutdownNotifier, AutoCloseable { * protocol exception, which closes the channel. * * Invocations of Channel#basicPublish will eventually block if a - * resource-driven alarm is in effect. + * resource-driven alarm is in effect. * * @see com.rabbitmq.client.AMQP.Basic.Publish - * @see Resource-driven alarms + * @see Resource-driven alarms * @param exchange the exchange to publish the message to * @param routingKey the routing key * @param props other properties for the message - routing headers etc @@ -259,10 +259,10 @@ public interface Channel extends ShutdownNotifier, AutoCloseable { * Publish a message. * * Invocations of Channel#basicPublish will eventually block if a - * resource-driven alarm is in effect. + * resource-driven alarm is in effect. * * @see com.rabbitmq.client.AMQP.Basic.Publish - * @see Resource-driven alarms + * @see Resource-driven alarms * @param exchange the exchange to publish the message to * @param routingKey the routing key * @param mandatory true if the 'mandatory' flag is to be set @@ -280,10 +280,10 @@ void basicPublish(String exchange, String routingKey, boolean mandatory, BasicPr * protocol exception, which closes the channel. * * Invocations of Channel#basicPublish will eventually block if a - * resource-driven alarm is in effect. + * resource-driven alarm is in effect. * * @see com.rabbitmq.client.AMQP.Basic.Publish - * @see Resource-driven alarms + * @see Resource-driven alarms * @param exchange the exchange to publish the message to * @param routingKey the routing key * @param mandatory true if the 'mandatory' flag is to be set diff --git a/src/main/java/com/rabbitmq/client/Connection.java b/src/main/java/com/rabbitmq/client/Connection.java index 3bde680075..2b1c9281ee 100644 --- a/src/main/java/com/rabbitmq/client/Connection.java +++ b/src/main/java/com/rabbitmq/client/Connection.java @@ -23,7 +23,7 @@ import java.util.concurrent.ExecutorService; /** - * Public API: Interface to an AMQ connection. See the see the spec for details. + * Public API: Interface to an AMQ connection. See the see the spec for details. *

* To connect to a broker, fill in a {@link ConnectionFactory} and use a {@link ConnectionFactory} as follows: * @@ -116,7 +116,7 @@ public interface Connection extends ShutdownNotifier, Closeable { // rename to A /** * Create a new channel, using an internally allocated channel number. - * If automatic connection recovery + * If automatic connection recovery * is enabled, the channel returned by this method will be {@link Recoverable}. *

* Use {@link #openChannel()} if you want to use an {@link Optional} to deal @@ -143,7 +143,7 @@ public interface Connection extends ShutdownNotifier, Closeable { // rename to A * Create a new channel wrapped in an {@link Optional}. * The channel number is allocated internally. *

- * If automatic connection recovery + * If automatic connection recovery * is enabled, the channel returned by this method will be {@link Recoverable}. *

* Use {@link #createChannel()} to return directly a {@link Channel} or {@code null}. diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index cbc055bf99..06037b6e24 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -493,7 +493,7 @@ public int getShutdownTimeout() { * If server heartbeat timeout is configured to a non-zero value, this method can only be used * to lower the value; otherwise any value provided by the client will be used. * @param requestedHeartbeat the initially requested heartbeat timeout, in seconds; zero for none - * @see RabbitMQ Heartbeats Guide + * @see RabbitMQ Heartbeats Guide */ public void setRequestedHeartbeat(int requestedHeartbeat) { this.requestedHeartbeat = requestedHeartbeat; @@ -789,19 +789,19 @@ public static String computeDefaultTlsProtocol(String[] supportedProtocols) { } /** - * Returns true if automatic connection recovery + * Returns true if automatic connection recovery * is enabled, false otherwise * @return true if automatic connection recovery is enabled, false otherwise - * @see Automatic Recovery + * @see Automatic Recovery */ public boolean isAutomaticRecoveryEnabled() { return automaticRecovery; } /** - * Enables or disables automatic connection recovery. + * Enables or disables automatic connection recovery. * @param automaticRecovery if true, enables connection recovery - * @see Automatic Recovery + * @see Automatic Recovery */ public void setAutomaticRecoveryEnabled(boolean automaticRecovery) { this.automaticRecovery = automaticRecovery; @@ -810,7 +810,7 @@ public void setAutomaticRecoveryEnabled(boolean automaticRecovery) { /** * Returns true if topology recovery is enabled, false otherwise * @return true if topology recovery is enabled, false otherwise - * @see Automatic Recovery + * @see Automatic Recovery */ public boolean isTopologyRecoveryEnabled() { return topologyRecovery; @@ -819,7 +819,7 @@ public boolean isTopologyRecoveryEnabled() { /** * Enables or disables topology recovery * @param topologyRecovery if true, enables topology recovery - * @see Automatic Recovery + * @see Automatic Recovery */ public void setTopologyRecoveryEnabled(boolean topologyRecovery) { this.topologyRecovery = topologyRecovery; @@ -873,7 +873,7 @@ protected synchronized FrameHandlerFactory createFrameHandlerFactory() throws IO * Create a new broker connection, picking the first available address from * the list. * - * If automatic connection recovery + * If automatic connection recovery * is enabled, the connection returned by this method will be {@link Recoverable}. Future * reconnection attempts will pick a random accessible address from the provided list. * @@ -889,14 +889,14 @@ public Connection newConnection(Address[] addrs) throws IOException, TimeoutExce * Create a new broker connection, picking the first available address from * the list provided by the {@link AddressResolver}. * - * If automatic connection recovery + * If automatic connection recovery * is enabled, the connection returned by this method will be {@link Recoverable}. Future * reconnection attempts will pick a random accessible address provided by the {@link AddressResolver}. * * @param addressResolver discovery service to list potential addresses (hostname/port pairs) to connect to * @return an interface to the connection * @throws IOException if it encounters a problem - * @see Automatic Recovery + * @see Automatic Recovery */ public Connection newConnection(AddressResolver addressResolver) throws IOException, TimeoutException { return newConnection(this.sharedExecutor, addressResolver, null); @@ -907,7 +907,7 @@ public Connection newConnection(AddressResolver addressResolver) throws IOExcept * Create a new broker connection with a client-provided name, picking the first available address from * the list. * - * If automatic connection recovery + * If automatic connection recovery * is enabled, the connection returned by this method will be {@link Recoverable}. Future * reconnection attempts will pick a random accessible address from the provided list. * @@ -928,7 +928,7 @@ public Connection newConnection(Address[] addrs, String clientProvidedName) thro * Create a new broker connection, picking the first available address from * the list. * - * If automatic connection recovery + * If automatic connection recovery * is enabled, the connection returned by this method will be {@link Recoverable}. Future * reconnection attempts will pick a random accessible address from the provided list. * @@ -944,7 +944,7 @@ public Connection newConnection(List

addrs) throws IOException, Timeout * Create a new broker connection with a client-provided name, picking the first available address from * the list. * - * If automatic connection recovery + * If automatic connection recovery * is enabled, the connection returned by this method will be {@link Recoverable}. Future * reconnection attempts will pick a random accessible address from the provided list. * @@ -965,7 +965,7 @@ public Connection newConnection(List
addrs, String clientProvidedName) * Create a new broker connection, picking the first available address from * the list. * - * If automatic connection recovery + * If automatic connection recovery * is enabled, the connection returned by this method will be {@link Recoverable}. Future * reconnection attempts will pick a random accessible address from the provided list. * @@ -973,7 +973,7 @@ public Connection newConnection(List
addrs, String clientProvidedName) * @param addrs an array of known broker addresses (hostname/port pairs) to try in order * @return an interface to the connection * @throws java.io.IOException if it encounters a problem - * @see Automatic Recovery + * @see Automatic Recovery */ public Connection newConnection(ExecutorService executor, Address[] addrs) throws IOException, TimeoutException { return newConnection(executor, Arrays.asList(addrs), null); @@ -984,7 +984,7 @@ public Connection newConnection(ExecutorService executor, Address[] addrs) throw * Create a new broker connection with a client-provided name, picking the first available address from * the list. * - * If automatic connection recovery + * If automatic connection recovery * is enabled, the connection returned by this method will be {@link Recoverable}. Future * reconnection attempts will pick a random accessible address from the provided list. * @@ -997,7 +997,7 @@ public Connection newConnection(ExecutorService executor, Address[] addrs) throw * This value is supposed to be human-readable. * @return an interface to the connection * @throws java.io.IOException if it encounters a problem - * @see Automatic Recovery + * @see Automatic Recovery */ public Connection newConnection(ExecutorService executor, Address[] addrs, String clientProvidedName) throws IOException, TimeoutException { return newConnection(executor, Arrays.asList(addrs), clientProvidedName); @@ -1007,7 +1007,7 @@ public Connection newConnection(ExecutorService executor, Address[] addrs, Strin * Create a new broker connection, picking the first available address from * the list. * - * If automatic connection recovery + * If automatic connection recovery * is enabled, the connection returned by this method will be {@link Recoverable}. Future * reconnection attempts will pick a random accessible address from the provided list. * @@ -1015,7 +1015,7 @@ public Connection newConnection(ExecutorService executor, Address[] addrs, Strin * @param addrs a List of known broker addrs (hostname/port pairs) to try in order * @return an interface to the connection * @throws java.io.IOException if it encounters a problem - * @see Automatic Recovery + * @see Automatic Recovery */ public Connection newConnection(ExecutorService executor, List
addrs) throws IOException, TimeoutException { return newConnection(executor, addrs, null); @@ -1025,7 +1025,7 @@ public Connection newConnection(ExecutorService executor, List
addrs) t * Create a new broker connection, picking the first available address from * the list provided by the {@link AddressResolver}. * - * If automatic connection recovery + * If automatic connection recovery * is enabled, the connection returned by this method will be {@link Recoverable}. Future * reconnection attempts will pick a random accessible address provided by the {@link AddressResolver}. * @@ -1033,7 +1033,7 @@ public Connection newConnection(ExecutorService executor, List
addrs) t * @param addressResolver discovery service to list potential addresses (hostname/port pairs) to connect to * @return an interface to the connection * @throws java.io.IOException if it encounters a problem - * @see Automatic Recovery + * @see Automatic Recovery */ public Connection newConnection(ExecutorService executor, AddressResolver addressResolver) throws IOException, TimeoutException { return newConnection(executor, addressResolver, null); @@ -1043,7 +1043,7 @@ public Connection newConnection(ExecutorService executor, AddressResolver addres * Create a new broker connection with a client-provided name, picking the first available address from * the list. * - * If automatic connection recovery + * If automatic connection recovery * is enabled, the connection returned by this method will be {@link Recoverable}. Future * reconnection attempts will pick a random accessible address from the provided list. * @@ -1056,7 +1056,7 @@ public Connection newConnection(ExecutorService executor, AddressResolver addres * This value is supposed to be human-readable. * @return an interface to the connection * @throws java.io.IOException if it encounters a problem - * @see Automatic Recovery + * @see Automatic Recovery */ public Connection newConnection(ExecutorService executor, List
addrs, String clientProvidedName) throws IOException, TimeoutException { @@ -1067,7 +1067,7 @@ public Connection newConnection(ExecutorService executor, List
addrs, S * Create a new broker connection with a client-provided name, picking the first available address from * the list provided by the {@link AddressResolver}. * - * If automatic connection recovery + * If automatic connection recovery * is enabled, the connection returned by this method will be {@link Recoverable}. Future * reconnection attempts will pick a random accessible address provided by the {@link AddressResolver}. * @@ -1080,7 +1080,7 @@ public Connection newConnection(ExecutorService executor, List
addrs, S * This value is supposed to be human-readable. * @return an interface to the connection * @throws java.io.IOException if it encounters a problem - * @see Automatic Recovery + * @see Automatic Recovery */ public Connection newConnection(ExecutorService executor, AddressResolver addressResolver, String clientProvidedName) throws IOException, TimeoutException { @@ -1171,7 +1171,7 @@ protected AMQConnection createConnection(ConnectionParams params, FrameHandler f /** * Create a new broker connection. * - * If automatic connection recovery + * If automatic connection recovery * is enabled, the connection returned by this method will be {@link Recoverable}. Reconnection * attempts will always use the address configured on {@link ConnectionFactory}. * @@ -1185,7 +1185,7 @@ public Connection newConnection() throws IOException, TimeoutException { /** * Create a new broker connection. * - * If automatic connection recovery + * If automatic connection recovery * is enabled, the connection returned by this method will be {@link Recoverable}. Reconnection * attempts will always use the address configured on {@link ConnectionFactory}. * @@ -1201,7 +1201,7 @@ public Connection newConnection(String connectionName) throws IOException, Timeo /** * Create a new broker connection. * - * If automatic connection recovery + * If automatic connection recovery * is enabled, the connection returned by this method will be {@link Recoverable}. Reconnection * attempts will always use the address configured on {@link ConnectionFactory}. * @@ -1216,7 +1216,7 @@ public Connection newConnection(ExecutorService executor) throws IOException, Ti /** * Create a new broker connection. * - * If automatic connection recovery + * If automatic connection recovery * is enabled, the connection returned by this method will be {@link Recoverable}. Reconnection * attempts will always use the address configured on {@link ConnectionFactory}. * diff --git a/src/main/java/com/rabbitmq/client/Method.java b/src/main/java/com/rabbitmq/client/Method.java index 46afe1f459..393f64cc1b 100644 --- a/src/main/java/com/rabbitmq/client/Method.java +++ b/src/main/java/com/rabbitmq/client/Method.java @@ -18,7 +18,7 @@ /** * Public interface to objects representing an AMQP 0-9-1 method - * @see http://www.rabbitmq.com/specification.html. + * @see https://www.rabbitmq.com/specification.html. */ public interface Method { diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index 5f059edff9..80ea32bb3d 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -36,7 +36,7 @@ final class Copyright { final static String COPYRIGHT="Copyright (c) 2007-2019 Pivotal Software, Inc."; - final static String LICENSE="Licensed under the MPL. See http://www.rabbitmq.com/"; + final static String LICENSE="Licensed under the MPL. See https://www.rabbitmq.com/"; } /** diff --git a/src/main/java/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java b/src/main/java/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java index 3447b07e34..33b4303294 100644 --- a/src/main/java/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java +++ b/src/main/java/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java @@ -21,7 +21,7 @@ /* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at - * http://creativecommons.org/licenses/publicdomain + * https://creativecommons.org/licenses/publicdomain */ package com.rabbitmq.client.impl; diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java index 514e4d9843..88f3939fef 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java @@ -31,8 +31,8 @@ import java.util.concurrent.TimeoutException; /** - * JSON-RPC is a lightweight - * RPC mechanism using JSON + * JSON-RPC is a lightweight + * RPC mechanism using JSON * as a data language for request and reply messages. It is * rapidly becoming a standard in web development, where it is * used to make RPC requests over HTTP. RabbitMQ provides an diff --git a/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java b/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java index c99dc3eb7b..11cd5bf248 100644 --- a/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java +++ b/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java @@ -63,7 +63,7 @@ public class AmqpUriTest extends BrokerTestCase "user", "pass", "[::1]", 100, "/"); /* Various failure cases */ - parseFail("http://www.rabbitmq.com"); + parseFail("https://www.rabbitmq.com"); parseFail("amqp://foo[::1]"); parseFail("amqp://foo:[::1]"); parseFail("amqp://[::1]foo"); diff --git a/src/test/java/com/rabbitmq/client/test/TestUtils.java b/src/test/java/com/rabbitmq/client/test/TestUtils.java index adc5ffb759..b385c73fde 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtils.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtils.java @@ -221,7 +221,7 @@ private static void wait(CountDownLatch latch) throws InterruptedException { } /** - * http://stackoverflow.com/questions/6701948/efficient-way-to-compare-version-strings-in-java + * https://stackoverflow.com/questions/6701948/efficient-way-to-compare-version-strings-in-java */ static int versionCompare(String str1, String str2) { String[] vals1 = str1.split("\\."); From f2a61d71e1cf2286f661ed449372ed4dd30e6eea Mon Sep 17 00:00:00 2001 From: Spring Operator Date: Wed, 20 Mar 2019 03:16:18 -0500 Subject: [PATCH 1073/2114] URL Cleanup This commit updates URLs to prefer the https protocol. Redirects are not followed to avoid accidentally expanding intentionally shortened URLs (i.e. if using a URL shortener). # HTTP URLs that Could Not Be Fixed These URLs were unable to be fixed. Please review them to see if they can be manually resolved. * http://javadoc.iaik.tugraz.at/iaik_jce/current/iaik/asn1/BIT_STRING.html (200) with 1 occurrences could not be migrated: ([https](https://javadoc.iaik.tugraz.at/iaik_jce/current/iaik/asn1/BIT_STRING.html) result NotSslRecordException). * http://luca.ntop.org/Teaching/Appunti/asn1.html (200) with 1 occurrences could not be migrated: ([https](https://luca.ntop.org/Teaching/Appunti/asn1.html) result SSLHandshakeException). # Fixed URLs ## Fixed Success These URLs were switched to an https URL with a 2xx status. While the status was successful, your review is still recommended. * http://github.com/rabbitmq/ with 1 occurrences migrated to: https://github.com/rabbitmq/ ([https](https://github.com/rabbitmq/) result 200). * http://search.maven.org/ with 1 occurrences migrated to: https://search.maven.org/ ([https](https://search.maven.org/) result 200). * http://stackoverflow.com/questions/6701948/efficient-way-to-compare-version-strings-in-java with 1 occurrences migrated to: https://stackoverflow.com/questions/6701948/efficient-way-to-compare-version-strings-in-java ([https](https://stackoverflow.com/questions/6701948/efficient-way-to-compare-version-strings-in-java) result 200). * http://www.amqp.org/ with 1 occurrences migrated to: https://www.amqp.org/ ([https](https://www.amqp.org/) result 200). * http://www.apple.com/DTDs/PropertyList-1.0.dtd with 1 occurrences migrated to: https://www.apple.com/DTDs/PropertyList-1.0.dtd ([https](https://www.apple.com/DTDs/PropertyList-1.0.dtd) result 200). * http://www.json.org/ with 1 occurrences migrated to: https://www.json.org/ ([https](https://www.json.org/) result 200). * http://json-rpc.org (302) with 1 occurrences migrated to: https://www.jsonrpc.org/ ([https](https://json-rpc.org) result 200). * http://www.rabbitmq.com with 1 occurrences migrated to: https://www.rabbitmq.com ([https](https://www.rabbitmq.com) result 200). * http://www.rabbitmq.com/ with 1 occurrences migrated to: https://www.rabbitmq.com/ ([https](https://www.rabbitmq.com/) result 200). * http://www.rabbitmq.com/alarms.html with 6 occurrences migrated to: https://www.rabbitmq.com/alarms.html ([https](https://www.rabbitmq.com/alarms.html) result 200). * http://www.rabbitmq.com/api-guide.html with 33 occurrences migrated to: https://www.rabbitmq.com/api-guide.html ([https](https://www.rabbitmq.com/api-guide.html) result 200). * http://www.rabbitmq.com/build-java-client.html with 1 occurrences migrated to: https://www.rabbitmq.com/build-java-client.html ([https](https://www.rabbitmq.com/build-java-client.html) result 200). * http://www.rabbitmq.com/confirms.html with 1 occurrences migrated to: https://www.rabbitmq.com/confirms.html ([https](https://www.rabbitmq.com/confirms.html) result 200). * http://www.rabbitmq.com/getstarted.html with 2 occurrences migrated to: https://www.rabbitmq.com/getstarted.html ([https](https://www.rabbitmq.com/getstarted.html) result 200). * http://www.rabbitmq.com/specification.html with 1 occurrences migrated to: https://www.rabbitmq.com/specification.html ([https](https://www.rabbitmq.com/specification.html) result 200). * http://contributor-covenant.org with 1 occurrences migrated to: https://contributor-covenant.org ([https](https://contributor-covenant.org) result 301). * http://contributor-covenant.org/version/1/3/0/ with 1 occurrences migrated to: https://contributor-covenant.org/version/1/3/0/ ([https](https://contributor-covenant.org/version/1/3/0/) result 301). * http://rabbitmq.com/heartbeats.html with 1 occurrences migrated to: https://rabbitmq.com/heartbeats.html ([https](https://rabbitmq.com/heartbeats.html) result 301). * http://www.mozilla.org/MPL/ with 1 occurrences migrated to: https://www.mozilla.org/MPL/ ([https](https://www.mozilla.org/MPL/) result 301). * http://creativecommons.org/licenses/publicdomain with 1 occurrences migrated to: https://creativecommons.org/licenses/publicdomain ([https](https://creativecommons.org/licenses/publicdomain) result 302). (cherry picked from commit 489ebacc85cd0cd49aa3b6ec97e962009028c528) --- CODE_OF_CONDUCT.md | 4 +- LICENSE-MPL-RabbitMQ | 2 +- README.in | 2 +- README.md | 6 +- doc/channels/worktransition.graffle | 2 +- .../java/com/rabbitmq/client/Channel.java | 22 +++---- .../java/com/rabbitmq/client/Connection.java | 6 +- .../rabbitmq/client/ConnectionFactory.java | 58 +++++++++---------- src/main/java/com/rabbitmq/client/Method.java | 2 +- .../rabbitmq/client/impl/AMQConnection.java | 2 +- .../impl/VariableLinkedBlockingQueue.java | 2 +- .../rabbitmq/tools/jsonrpc/JsonRpcClient.java | 4 +- .../com/rabbitmq/client/test/AmqpUriTest.java | 2 +- .../com/rabbitmq/client/test/TestUtils.java | 2 +- 14 files changed, 58 insertions(+), 58 deletions(-) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 1f6ef1c576..08697906fd 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -40,5 +40,5 @@ appropriate to the circumstances. Maintainers are obligated to maintain confiden with regard to the reporter of an incident. This Code of Conduct is adapted from the -[Contributor Covenant](http://contributor-covenant.org), version 1.3.0, available at -[contributor-covenant.org/version/1/3/0/](http://contributor-covenant.org/version/1/3/0/) +[Contributor Covenant](https://contributor-covenant.org), version 1.3.0, available at +[contributor-covenant.org/version/1/3/0/](https://contributor-covenant.org/version/1/3/0/) diff --git a/LICENSE-MPL-RabbitMQ b/LICENSE-MPL-RabbitMQ index 02ee669400..b237a959b0 100644 --- a/LICENSE-MPL-RabbitMQ +++ b/LICENSE-MPL-RabbitMQ @@ -437,7 +437,7 @@ EXHIBIT A -Mozilla Public License. ``The contents of this file are subject to the Mozilla Public License Version 1.1 (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.mozilla.org/MPL/ + https://www.mozilla.org/MPL/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the diff --git a/README.in b/README.in index e9ccd32f24..c00367a7ab 100644 --- a/README.in +++ b/README.in @@ -1,4 +1,4 @@ -Please see http://www.rabbitmq.com/build-java-client.html for build +Please see https://www.rabbitmq.com/build-java-client.html for build instructions. For your convenience, a text copy of these instructions is available diff --git a/README.md b/README.md index 47e7ae1d06..103c73d08d 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ # RabbitMQ Java Client -This repository contains source code of the [RabbitMQ Java client](http://www.rabbitmq.com/api-guide.html). -The client is maintained by the [RabbitMQ team at Pivotal](http://github.com/rabbitmq/). +This repository contains source code of the [RabbitMQ Java client](https://www.rabbitmq.com/api-guide.html). +The client is maintained by the [RabbitMQ team at Pivotal](https://github.com/rabbitmq/). ## Dependency (Maven Artifact) -Maven artifacts are [released to Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3Acom.rabbitmq%20a%3Aamqp-client) +Maven artifacts are [released to Maven Central](https://search.maven.org/#search%7Cga%7C1%7Cg%3Acom.rabbitmq%20a%3Aamqp-client) via [RabbitMQ Maven repository on Bintray](https://bintray.com/rabbitmq/maven). There's also a [Maven repository with milestone releases](https://bintray.com/rabbitmq/maven-milestones). [Snapshots are available](https://oss.sonatype.org/content/repositories/snapshots/com/rabbitmq/amqp-client/) as well. diff --git a/doc/channels/worktransition.graffle b/doc/channels/worktransition.graffle index a8c2d6ce8e..a1feddfa7f 100644 --- a/doc/channels/worktransition.graffle +++ b/doc/channels/worktransition.graffle @@ -1,5 +1,5 @@ - + ActiveLayerIndex diff --git a/src/main/java/com/rabbitmq/client/Channel.java b/src/main/java/com/rabbitmq/client/Channel.java index 6279bf881f..c4312e041a 100644 --- a/src/main/java/com/rabbitmq/client/Channel.java +++ b/src/main/java/com/rabbitmq/client/Channel.java @@ -32,11 +32,11 @@ * this interface are part of the public API. * *

Tutorials

- * RabbitMQ tutorials demonstrate how + * RabbitMQ tutorials demonstrate how * key methods of this interface are used. * *

User Guide

- * See Java Client User Guide. + * See Java Client User Guide. * *

Concurrency Considerations

*

@@ -47,13 +47,13 @@ * multiple threads. While some operations on channels are safe to invoke * concurrently, some are not and will result in incorrect frame interleaving * on the wire. Sharing channels between threads will also interfere with - * Publisher Confirms. + * Publisher Confirms. * * As such, applications need to use a {@link Channel} per thread. *

* - * @see RabbitMQ tutorials - * @see RabbitMQ Java Client User Guide + * @see RabbitMQ tutorials + * @see RabbitMQ Java Client User Guide */ public interface Channel extends ShutdownNotifier, AutoCloseable { /** @@ -243,10 +243,10 @@ public interface Channel extends ShutdownNotifier, AutoCloseable { * protocol exception, which closes the channel. * * Invocations of Channel#basicPublish will eventually block if a - * resource-driven alarm is in effect. + * resource-driven alarm is in effect. * * @see com.rabbitmq.client.AMQP.Basic.Publish - * @see Resource-driven alarms + * @see Resource-driven alarms * @param exchange the exchange to publish the message to * @param routingKey the routing key * @param props other properties for the message - routing headers etc @@ -259,10 +259,10 @@ public interface Channel extends ShutdownNotifier, AutoCloseable { * Publish a message. * * Invocations of Channel#basicPublish will eventually block if a - * resource-driven alarm is in effect. + * resource-driven alarm is in effect. * * @see com.rabbitmq.client.AMQP.Basic.Publish - * @see Resource-driven alarms + * @see Resource-driven alarms * @param exchange the exchange to publish the message to * @param routingKey the routing key * @param mandatory true if the 'mandatory' flag is to be set @@ -280,10 +280,10 @@ void basicPublish(String exchange, String routingKey, boolean mandatory, BasicPr * protocol exception, which closes the channel. * * Invocations of Channel#basicPublish will eventually block if a - * resource-driven alarm is in effect. + * resource-driven alarm is in effect. * * @see com.rabbitmq.client.AMQP.Basic.Publish - * @see Resource-driven alarms + * @see Resource-driven alarms * @param exchange the exchange to publish the message to * @param routingKey the routing key * @param mandatory true if the 'mandatory' flag is to be set diff --git a/src/main/java/com/rabbitmq/client/Connection.java b/src/main/java/com/rabbitmq/client/Connection.java index 3bde680075..2b1c9281ee 100644 --- a/src/main/java/com/rabbitmq/client/Connection.java +++ b/src/main/java/com/rabbitmq/client/Connection.java @@ -23,7 +23,7 @@ import java.util.concurrent.ExecutorService; /** - * Public API: Interface to an AMQ connection. See the see the spec for details. + * Public API: Interface to an AMQ connection. See the see the spec for details. *

* To connect to a broker, fill in a {@link ConnectionFactory} and use a {@link ConnectionFactory} as follows: * @@ -116,7 +116,7 @@ public interface Connection extends ShutdownNotifier, Closeable { // rename to A /** * Create a new channel, using an internally allocated channel number. - * If automatic connection recovery + * If automatic connection recovery * is enabled, the channel returned by this method will be {@link Recoverable}. *

* Use {@link #openChannel()} if you want to use an {@link Optional} to deal @@ -143,7 +143,7 @@ public interface Connection extends ShutdownNotifier, Closeable { // rename to A * Create a new channel wrapped in an {@link Optional}. * The channel number is allocated internally. *

- * If automatic connection recovery + * If automatic connection recovery * is enabled, the channel returned by this method will be {@link Recoverable}. *

* Use {@link #createChannel()} to return directly a {@link Channel} or {@code null}. diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 12eccb007d..547422de83 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -493,7 +493,7 @@ public int getShutdownTimeout() { * If server heartbeat timeout is configured to a non-zero value, this method can only be used * to lower the value; otherwise any value provided by the client will be used. * @param requestedHeartbeat the initially requested heartbeat timeout, in seconds; zero for none - * @see RabbitMQ Heartbeats Guide + * @see RabbitMQ Heartbeats Guide */ public void setRequestedHeartbeat(int requestedHeartbeat) { this.requestedHeartbeat = requestedHeartbeat; @@ -789,19 +789,19 @@ public static String computeDefaultTlsProtocol(String[] supportedProtocols) { } /** - * Returns true if automatic connection recovery + * Returns true if automatic connection recovery * is enabled, false otherwise * @return true if automatic connection recovery is enabled, false otherwise - * @see Automatic Recovery + * @see Automatic Recovery */ public boolean isAutomaticRecoveryEnabled() { return automaticRecovery; } /** - * Enables or disables automatic connection recovery. + * Enables or disables automatic connection recovery. * @param automaticRecovery if true, enables connection recovery - * @see Automatic Recovery + * @see Automatic Recovery */ public void setAutomaticRecoveryEnabled(boolean automaticRecovery) { this.automaticRecovery = automaticRecovery; @@ -810,7 +810,7 @@ public void setAutomaticRecoveryEnabled(boolean automaticRecovery) { /** * Returns true if topology recovery is enabled, false otherwise * @return true if topology recovery is enabled, false otherwise - * @see Automatic Recovery + * @see Automatic Recovery */ public boolean isTopologyRecoveryEnabled() { return topologyRecovery; @@ -819,7 +819,7 @@ public boolean isTopologyRecoveryEnabled() { /** * Enables or disables topology recovery * @param topologyRecovery if true, enables topology recovery - * @see Automatic Recovery + * @see Automatic Recovery */ public void setTopologyRecoveryEnabled(boolean topologyRecovery) { this.topologyRecovery = topologyRecovery; @@ -873,7 +873,7 @@ protected synchronized FrameHandlerFactory createFrameHandlerFactory() throws IO * Create a new broker connection, picking the first available address from * the list. * - * If automatic connection recovery + * If automatic connection recovery * is enabled, the connection returned by this method will be {@link Recoverable}. Future * reconnection attempts will pick a random accessible address from the provided list. * @@ -889,14 +889,14 @@ public Connection newConnection(Address[] addrs) throws IOException, TimeoutExce * Create a new broker connection, picking the first available address from * the list provided by the {@link AddressResolver}. * - * If automatic connection recovery + * If automatic connection recovery * is enabled, the connection returned by this method will be {@link Recoverable}. Future * reconnection attempts will pick a random accessible address provided by the {@link AddressResolver}. * * @param addressResolver discovery service to list potential addresses (hostname/port pairs) to connect to * @return an interface to the connection * @throws IOException if it encounters a problem - * @see Automatic Recovery + * @see Automatic Recovery */ public Connection newConnection(AddressResolver addressResolver) throws IOException, TimeoutException { return newConnection(this.sharedExecutor, addressResolver, null); @@ -907,7 +907,7 @@ public Connection newConnection(AddressResolver addressResolver) throws IOExcept * Create a new broker connection with a client-provided name, picking the first available address from * the list. * - * If automatic connection recovery + * If automatic connection recovery * is enabled, the connection returned by this method will be {@link Recoverable}. Future * reconnection attempts will pick a random accessible address from the provided list. * @@ -928,7 +928,7 @@ public Connection newConnection(Address[] addrs, String clientProvidedName) thro * Create a new broker connection, picking the first available address from * the list. * - * If automatic connection recovery + * If automatic connection recovery * is enabled, the connection returned by this method will be {@link Recoverable}. Future * reconnection attempts will pick a random accessible address from the provided list. * @@ -944,7 +944,7 @@ public Connection newConnection(List

addrs) throws IOException, Timeout * Create a new broker connection with a client-provided name, picking the first available address from * the list. * - * If automatic connection recovery + * If automatic connection recovery * is enabled, the connection returned by this method will be {@link Recoverable}. Future * reconnection attempts will pick a random accessible address from the provided list. * @@ -965,7 +965,7 @@ public Connection newConnection(List
addrs, String clientProvidedName) * Create a new broker connection, picking the first available address from * the list. * - * If automatic connection recovery + * If automatic connection recovery * is enabled, the connection returned by this method will be {@link Recoverable}. Future * reconnection attempts will pick a random accessible address from the provided list. * @@ -973,7 +973,7 @@ public Connection newConnection(List
addrs, String clientProvidedName) * @param addrs an array of known broker addresses (hostname/port pairs) to try in order * @return an interface to the connection * @throws java.io.IOException if it encounters a problem - * @see Automatic Recovery + * @see Automatic Recovery */ public Connection newConnection(ExecutorService executor, Address[] addrs) throws IOException, TimeoutException { return newConnection(executor, Arrays.asList(addrs), null); @@ -984,7 +984,7 @@ public Connection newConnection(ExecutorService executor, Address[] addrs) throw * Create a new broker connection with a client-provided name, picking the first available address from * the list. * - * If automatic connection recovery + * If automatic connection recovery * is enabled, the connection returned by this method will be {@link Recoverable}. Future * reconnection attempts will pick a random accessible address from the provided list. * @@ -997,7 +997,7 @@ public Connection newConnection(ExecutorService executor, Address[] addrs) throw * This value is supposed to be human-readable. * @return an interface to the connection * @throws java.io.IOException if it encounters a problem - * @see Automatic Recovery + * @see Automatic Recovery */ public Connection newConnection(ExecutorService executor, Address[] addrs, String clientProvidedName) throws IOException, TimeoutException { return newConnection(executor, Arrays.asList(addrs), clientProvidedName); @@ -1007,7 +1007,7 @@ public Connection newConnection(ExecutorService executor, Address[] addrs, Strin * Create a new broker connection, picking the first available address from * the list. * - * If automatic connection recovery + * If automatic connection recovery * is enabled, the connection returned by this method will be {@link Recoverable}. Future * reconnection attempts will pick a random accessible address from the provided list. * @@ -1015,7 +1015,7 @@ public Connection newConnection(ExecutorService executor, Address[] addrs, Strin * @param addrs a List of known broker addrs (hostname/port pairs) to try in order * @return an interface to the connection * @throws java.io.IOException if it encounters a problem - * @see Automatic Recovery + * @see Automatic Recovery */ public Connection newConnection(ExecutorService executor, List
addrs) throws IOException, TimeoutException { return newConnection(executor, addrs, null); @@ -1025,7 +1025,7 @@ public Connection newConnection(ExecutorService executor, List
addrs) t * Create a new broker connection, picking the first available address from * the list provided by the {@link AddressResolver}. * - * If automatic connection recovery + * If automatic connection recovery * is enabled, the connection returned by this method will be {@link Recoverable}. Future * reconnection attempts will pick a random accessible address provided by the {@link AddressResolver}. * @@ -1033,7 +1033,7 @@ public Connection newConnection(ExecutorService executor, List
addrs) t * @param addressResolver discovery service to list potential addresses (hostname/port pairs) to connect to * @return an interface to the connection * @throws java.io.IOException if it encounters a problem - * @see Automatic Recovery + * @see Automatic Recovery */ public Connection newConnection(ExecutorService executor, AddressResolver addressResolver) throws IOException, TimeoutException { return newConnection(executor, addressResolver, null); @@ -1043,7 +1043,7 @@ public Connection newConnection(ExecutorService executor, AddressResolver addres * Create a new broker connection with a client-provided name, picking the first available address from * the list. * - * If automatic connection recovery + * If automatic connection recovery * is enabled, the connection returned by this method will be {@link Recoverable}. Future * reconnection attempts will pick a random accessible address from the provided list. * @@ -1056,7 +1056,7 @@ public Connection newConnection(ExecutorService executor, AddressResolver addres * This value is supposed to be human-readable. * @return an interface to the connection * @throws java.io.IOException if it encounters a problem - * @see Automatic Recovery + * @see Automatic Recovery */ public Connection newConnection(ExecutorService executor, List
addrs, String clientProvidedName) throws IOException, TimeoutException { @@ -1067,7 +1067,7 @@ public Connection newConnection(ExecutorService executor, List
addrs, S * Create a new broker connection with a client-provided name, picking the first available address from * the list provided by the {@link AddressResolver}. * - * If automatic connection recovery + * If automatic connection recovery * is enabled, the connection returned by this method will be {@link Recoverable}. Future * reconnection attempts will pick a random accessible address provided by the {@link AddressResolver}. * @@ -1080,7 +1080,7 @@ public Connection newConnection(ExecutorService executor, List
addrs, S * This value is supposed to be human-readable. * @return an interface to the connection * @throws java.io.IOException if it encounters a problem - * @see Automatic Recovery + * @see Automatic Recovery */ public Connection newConnection(ExecutorService executor, AddressResolver addressResolver, String clientProvidedName) throws IOException, TimeoutException { @@ -1171,7 +1171,7 @@ protected AMQConnection createConnection(ConnectionParams params, FrameHandler f /** * Create a new broker connection. * - * If automatic connection recovery + * If automatic connection recovery * is enabled, the connection returned by this method will be {@link Recoverable}. Reconnection * attempts will always use the address configured on {@link ConnectionFactory}. * @@ -1185,7 +1185,7 @@ public Connection newConnection() throws IOException, TimeoutException { /** * Create a new broker connection. * - * If automatic connection recovery + * If automatic connection recovery * is enabled, the connection returned by this method will be {@link Recoverable}. Reconnection * attempts will always use the address configured on {@link ConnectionFactory}. * @@ -1201,7 +1201,7 @@ public Connection newConnection(String connectionName) throws IOException, Timeo /** * Create a new broker connection. * - * If automatic connection recovery + * If automatic connection recovery * is enabled, the connection returned by this method will be {@link Recoverable}. Reconnection * attempts will always use the address configured on {@link ConnectionFactory}. * @@ -1216,7 +1216,7 @@ public Connection newConnection(ExecutorService executor) throws IOException, Ti /** * Create a new broker connection. * - * If automatic connection recovery + * If automatic connection recovery * is enabled, the connection returned by this method will be {@link Recoverable}. Reconnection * attempts will always use the address configured on {@link ConnectionFactory}. * diff --git a/src/main/java/com/rabbitmq/client/Method.java b/src/main/java/com/rabbitmq/client/Method.java index 46afe1f459..393f64cc1b 100644 --- a/src/main/java/com/rabbitmq/client/Method.java +++ b/src/main/java/com/rabbitmq/client/Method.java @@ -18,7 +18,7 @@ /** * Public interface to objects representing an AMQP 0-9-1 method - * @see http://www.rabbitmq.com/specification.html. + * @see https://www.rabbitmq.com/specification.html. */ public interface Method { diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index 48949b4ca4..e5a40ceee1 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -36,7 +36,7 @@ final class Copyright { final static String COPYRIGHT="Copyright (c) 2007-2019 Pivotal Software, Inc."; - final static String LICENSE="Licensed under the MPL. See http://www.rabbitmq.com/"; + final static String LICENSE="Licensed under the MPL. See https://www.rabbitmq.com/"; } /** diff --git a/src/main/java/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java b/src/main/java/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java index 3447b07e34..33b4303294 100644 --- a/src/main/java/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java +++ b/src/main/java/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java @@ -21,7 +21,7 @@ /* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at - * http://creativecommons.org/licenses/publicdomain + * https://creativecommons.org/licenses/publicdomain */ package com.rabbitmq.client.impl; diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java index d23f56f0ff..870eadd843 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java @@ -32,8 +32,8 @@ import java.util.concurrent.TimeoutException; /** - * JSON-RPC is a lightweight - * RPC mechanism using JSON + * JSON-RPC is a lightweight + * RPC mechanism using JSON * as a data language for request and reply messages. It is * rapidly becoming a standard in web development, where it is * used to make RPC requests over HTTP. RabbitMQ provides an diff --git a/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java b/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java index c99dc3eb7b..11cd5bf248 100644 --- a/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java +++ b/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java @@ -63,7 +63,7 @@ public class AmqpUriTest extends BrokerTestCase "user", "pass", "[::1]", 100, "/"); /* Various failure cases */ - parseFail("http://www.rabbitmq.com"); + parseFail("https://www.rabbitmq.com"); parseFail("amqp://foo[::1]"); parseFail("amqp://foo:[::1]"); parseFail("amqp://[::1]foo"); diff --git a/src/test/java/com/rabbitmq/client/test/TestUtils.java b/src/test/java/com/rabbitmq/client/test/TestUtils.java index adc5ffb759..b385c73fde 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtils.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtils.java @@ -221,7 +221,7 @@ private static void wait(CountDownLatch latch) throws InterruptedException { } /** - * http://stackoverflow.com/questions/6701948/efficient-way-to-compare-version-strings-in-java + * https://stackoverflow.com/questions/6701948/efficient-way-to-compare-version-strings-in-java */ static int versionCompare(String str1, String str2) { String[] vals1 = str1.split("\\."); From eab59eb2d99226171d4e056887e1413f8368a093 Mon Sep 17 00:00:00 2001 From: Spring Operator Date: Thu, 21 Mar 2019 03:06:22 -0500 Subject: [PATCH 1074/2114] URL Cleanup This commit updates URLs to prefer the https protocol. Redirects are not followed to avoid accidentally expanding intentionally shortened URLs (i.e. if using a URL shortener). # Fixed URLs ## Fixed Success These URLs were switched to an https URL with a 2xx status. While the status was successful, your review is still recommended. * [ ] http://www.apache.org/licenses/ with 1 occurrences migrated to: https://www.apache.org/licenses/ ([https](https://www.apache.org/licenses/) result 200). * [ ] http://www.apache.org/licenses/LICENSE-2.0 with 3 occurrences migrated to: https://www.apache.org/licenses/LICENSE-2.0 ([https](https://www.apache.org/licenses/LICENSE-2.0) result 200). --- LICENSE-APACHE2 | 4 ++-- src/main/java/com/rabbitmq/tools/json/JSONReader.java | 2 +- src/main/java/com/rabbitmq/tools/json/JSONWriter.java | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/LICENSE-APACHE2 b/LICENSE-APACHE2 index d645695673..62589edd12 100644 --- a/LICENSE-APACHE2 +++ b/LICENSE-APACHE2 @@ -1,7 +1,7 @@ Apache License Version 2.0, January 2004 - http://www.apache.org/licenses/ + https://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION @@ -193,7 +193,7 @@ 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 + https://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, diff --git a/src/main/java/com/rabbitmq/tools/json/JSONReader.java b/src/main/java/com/rabbitmq/tools/json/JSONReader.java index 14c690e6e2..5bd332c7bd 100644 --- a/src/main/java/com/rabbitmq/tools/json/JSONReader.java +++ b/src/main/java/com/rabbitmq/tools/json/JSONReader.java @@ -21,7 +21,7 @@ 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 + https://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, diff --git a/src/main/java/com/rabbitmq/tools/json/JSONWriter.java b/src/main/java/com/rabbitmq/tools/json/JSONWriter.java index 7101598040..ec05322c34 100644 --- a/src/main/java/com/rabbitmq/tools/json/JSONWriter.java +++ b/src/main/java/com/rabbitmq/tools/json/JSONWriter.java @@ -21,7 +21,7 @@ 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 + https://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, From ac8e3506444c591663587f5ad370756feea00a6f Mon Sep 17 00:00:00 2001 From: Spring Operator Date: Thu, 21 Mar 2019 03:06:51 -0500 Subject: [PATCH 1075/2114] URL Cleanup This commit updates URLs to prefer the https protocol. Redirects are not followed to avoid accidentally expanding intentionally shortened URLs (i.e. if using a URL shortener). # Fixed URLs ## Fixed Success These URLs were switched to an https URL with a 2xx status. While the status was successful, your review is still recommended. * [ ] http://www.apache.org/licenses/ with 1 occurrences migrated to: https://www.apache.org/licenses/ ([https](https://www.apache.org/licenses/) result 200). * [ ] http://www.apache.org/licenses/LICENSE-2.0 with 1 occurrences migrated to: https://www.apache.org/licenses/LICENSE-2.0 ([https](https://www.apache.org/licenses/LICENSE-2.0) result 200). --- LICENSE-APACHE2 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/LICENSE-APACHE2 b/LICENSE-APACHE2 index d645695673..62589edd12 100644 --- a/LICENSE-APACHE2 +++ b/LICENSE-APACHE2 @@ -1,7 +1,7 @@ Apache License Version 2.0, January 2004 - http://www.apache.org/licenses/ + https://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION @@ -193,7 +193,7 @@ 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 + https://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, From be13273f885a3078354879c36a3969f7e749358c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 22 Mar 2019 10:36:14 +0100 Subject: [PATCH 1076/2114] Log warning when receiving basic.cancel for unknown consumer Fixes #525 --- .../com/rabbitmq/client/impl/ChannelN.java | 2 + .../rabbitmq/client/test/ChannelNTest.java | 51 +++++++++++++++++++ .../com/rabbitmq/client/test/ClientTests.java | 3 +- 3 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 src/test/java/com/rabbitmq/client/test/ChannelNTest.java diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java index aea0ee7a4b..43b8c4d823 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelN.java @@ -402,6 +402,8 @@ private void releaseChannel() { consumerTag, "handleCancel"); } + } else { + LOGGER.warn("Could not cancel consumer with unknown tag {}", consumerTag); } return true; } else { diff --git a/src/test/java/com/rabbitmq/client/test/ChannelNTest.java b/src/test/java/com/rabbitmq/client/test/ChannelNTest.java new file mode 100644 index 0000000000..93ec20f15b --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/ChannelNTest.java @@ -0,0 +1,51 @@ +// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.test; + +import com.rabbitmq.client.Method; +import com.rabbitmq.client.impl.*; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +public class ChannelNTest { + + ConsumerWorkService consumerWorkService; + ExecutorService executorService; + + @Before public void init() { + executorService = Executors.newSingleThreadExecutor(); + consumerWorkService = new ConsumerWorkService(executorService, null, 1000, 1000); + } + + @After public void tearDown() { + consumerWorkService.shutdown(); + executorService.shutdownNow(); + } + + @Test + public void cancelUnknownConsumerDoesNotThrowException() throws Exception { + AMQConnection connection = Mockito.mock(AMQConnection.class); + ChannelN channel = new ChannelN(connection, 1, consumerWorkService); + Method method = new AMQImpl.Basic.Cancel.Builder().consumerTag("does-not-exist").build(); + channel.processAsync(new AMQCommand(method)); + } + +} diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index dfae29e976..d5fb3251ab 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -67,7 +67,8 @@ GeneratedClassesTest.class, RpcTopologyRecordingTest.class, ConnectionTest.class, - TlsUtilsTest.class + TlsUtilsTest.class, + ChannelNTest.class }) public class ClientTests { From 261ffff32465b7710e2305d469b2bb5f6cb930ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 22 Mar 2019 10:40:51 +0100 Subject: [PATCH 1077/2114] Add test for Channel#basicCancel with unknown consumer tag References #525, #528 --- .../com/rabbitmq/client/test/ChannelNTest.java | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/ChannelNTest.java b/src/test/java/com/rabbitmq/client/test/ChannelNTest.java index 93ec20f15b..f6e85e686e 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelNTest.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelNTest.java @@ -22,6 +22,7 @@ import org.junit.Test; import org.mockito.Mockito; +import java.io.IOException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -30,22 +31,31 @@ public class ChannelNTest { ConsumerWorkService consumerWorkService; ExecutorService executorService; - @Before public void init() { + @Before + public void init() { executorService = Executors.newSingleThreadExecutor(); consumerWorkService = new ConsumerWorkService(executorService, null, 1000, 1000); } - @After public void tearDown() { + @After + public void tearDown() { consumerWorkService.shutdown(); executorService.shutdownNow(); } @Test - public void cancelUnknownConsumerDoesNotThrowException() throws Exception { + public void serverBasicCancelForUnknownConsumerDoesNotThrowException() throws Exception { AMQConnection connection = Mockito.mock(AMQConnection.class); ChannelN channel = new ChannelN(connection, 1, consumerWorkService); Method method = new AMQImpl.Basic.Cancel.Builder().consumerTag("does-not-exist").build(); channel.processAsync(new AMQCommand(method)); } + @Test(expected = IOException.class) + public void callingBasicCancelForUnknownConsumerThrowsException() throws Exception { + AMQConnection connection = Mockito.mock(AMQConnection.class); + ChannelN channel = new ChannelN(connection, 1, consumerWorkService); + channel.basicCancel("does-not-exist"); + } + } From af0943fcf3e3a28f40ee85a432c10e5ce82cc8b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 22 Mar 2019 10:55:25 +0100 Subject: [PATCH 1078/2114] Log warning when calling Channel#basicCancel with unknown tag Fixes #528 --- src/main/java/com/rabbitmq/client/Channel.java | 15 +++++++-------- .../java/com/rabbitmq/client/impl/ChannelN.java | 6 ++++-- .../com/rabbitmq/client/test/ChannelNTest.java | 5 ++--- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/Channel.java b/src/main/java/com/rabbitmq/client/Channel.java index c4312e041a..51e50d8917 100644 --- a/src/main/java/com/rabbitmq/client/Channel.java +++ b/src/main/java/com/rabbitmq/client/Channel.java @@ -15,18 +15,14 @@ package com.rabbitmq.client; +import com.rabbitmq.client.AMQP.BasicProperties; +import com.rabbitmq.client.AMQP.*; + import java.io.IOException; import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeoutException; -import com.rabbitmq.client.AMQP.BasicProperties; -import com.rabbitmq.client.AMQP.Exchange; -import com.rabbitmq.client.AMQP.Queue; -import com.rabbitmq.client.AMQP.Tx; -import com.rabbitmq.client.AMQP.Basic; -import com.rabbitmq.client.AMQP.Confirm; - /** * Interface to a channel. All non-deprecated methods of * this interface are part of the public API. @@ -1220,8 +1216,11 @@ void basicNack(long deliveryTag, boolean multiple, boolean requeue) /** * Cancel a consumer. Calls the consumer's {@link Consumer#handleCancelOk} * method. + *

+ * A consumer tag that does not match any consumer is ignored. + * * @param consumerTag a client- or server-generated consumer tag to establish context - * @throws IOException if an error is encountered, or if the consumerTag is unknown + * @throws IOException if an error is encountered * @see com.rabbitmq.client.AMQP.Basic.Cancel * @see com.rabbitmq.client.AMQP.Basic.CancelOk */ diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java index 43b8c4d823..25311062fb 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelN.java @@ -1468,8 +1468,10 @@ public void basicCancel(final String consumerTag) throws IOException { final Consumer originalConsumer = _consumers.get(consumerTag); - if (originalConsumer == null) - throw new IOException("Unknown consumerTag"); + if (originalConsumer == null) { + LOGGER.warn("Tried to cancel consumer with unknown tag {}", consumerTag); + return; + } final Method m = new Basic.Cancel(consumerTag, false); BlockingRpcContinuation k = new BlockingRpcContinuation(m) { diff --git a/src/test/java/com/rabbitmq/client/test/ChannelNTest.java b/src/test/java/com/rabbitmq/client/test/ChannelNTest.java index f6e85e686e..6f9056174f 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelNTest.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelNTest.java @@ -22,7 +22,6 @@ import org.junit.Test; import org.mockito.Mockito; -import java.io.IOException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -51,8 +50,8 @@ public void serverBasicCancelForUnknownConsumerDoesNotThrowException() throws Ex channel.processAsync(new AMQCommand(method)); } - @Test(expected = IOException.class) - public void callingBasicCancelForUnknownConsumerThrowsException() throws Exception { + @Test + public void callingBasicCancelForUnknownConsumerDoesNotThrowException() throws Exception { AMQConnection connection = Mockito.mock(AMQConnection.class); ChannelN channel = new ChannelN(connection, 1, consumerWorkService); channel.basicCancel("does-not-exist"); From ad6968621409f31bb6967c324a82e90f2daba93a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 22 Mar 2019 11:28:24 +0100 Subject: [PATCH 1079/2114] Add comment to explain decision tree References #525 --- src/main/java/com/rabbitmq/client/impl/ChannelN.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java index 43b8c4d823..5ab12bda20 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelN.java @@ -386,6 +386,10 @@ private void releaseChannel() { Basic.Cancel m = (Basic.Cancel)method; String consumerTag = m.getConsumerTag(); Consumer callback = _consumers.remove(consumerTag); + // Not finding any matching consumer isn't necessarily an indication of an issue anywhere. + // Sometimes there's a natural race condition between consumer management on the server and client ends. + // E.g. Channel#basicCancel called just before a basic.cancel for the same consumer tag is received. + // See https://github.com/rabbitmq/rabbitmq-java-client/issues/525 if (callback == null) { callback = defaultConsumer; } From 6081628163669bac39456c9fcf1dbc3c6692786d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 22 Mar 2019 10:36:14 +0100 Subject: [PATCH 1080/2114] Log warning when receiving basic.cancel for unknown consumer Fixes #525 (cherry picked from commit be13273f885a3078354879c36a3969f7e749358c) --- .../com/rabbitmq/client/impl/ChannelN.java | 2 + .../rabbitmq/client/test/ChannelNTest.java | 51 +++++++++++++++++++ .../com/rabbitmq/client/test/ClientTests.java | 3 +- 3 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 src/test/java/com/rabbitmq/client/test/ChannelNTest.java diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java index aea0ee7a4b..43b8c4d823 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelN.java @@ -402,6 +402,8 @@ private void releaseChannel() { consumerTag, "handleCancel"); } + } else { + LOGGER.warn("Could not cancel consumer with unknown tag {}", consumerTag); } return true; } else { diff --git a/src/test/java/com/rabbitmq/client/test/ChannelNTest.java b/src/test/java/com/rabbitmq/client/test/ChannelNTest.java new file mode 100644 index 0000000000..93ec20f15b --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/ChannelNTest.java @@ -0,0 +1,51 @@ +// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.test; + +import com.rabbitmq.client.Method; +import com.rabbitmq.client.impl.*; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +public class ChannelNTest { + + ConsumerWorkService consumerWorkService; + ExecutorService executorService; + + @Before public void init() { + executorService = Executors.newSingleThreadExecutor(); + consumerWorkService = new ConsumerWorkService(executorService, null, 1000, 1000); + } + + @After public void tearDown() { + consumerWorkService.shutdown(); + executorService.shutdownNow(); + } + + @Test + public void cancelUnknownConsumerDoesNotThrowException() throws Exception { + AMQConnection connection = Mockito.mock(AMQConnection.class); + ChannelN channel = new ChannelN(connection, 1, consumerWorkService); + Method method = new AMQImpl.Basic.Cancel.Builder().consumerTag("does-not-exist").build(); + channel.processAsync(new AMQCommand(method)); + } + +} diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index 0db46be963..4f4cb156eb 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -70,7 +70,8 @@ GeneratedClassesTest.class, RpcTopologyRecordingTest.class, ConnectionTest.class, - TlsUtilsTest.class + TlsUtilsTest.class, + ChannelNTest.class }) public class ClientTests { From 365dd22a51a79ed40e7f45742a4eb71ecbfd44e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 22 Mar 2019 10:40:51 +0100 Subject: [PATCH 1081/2114] Add test for Channel#basicCancel with unknown consumer tag References #525, #528 (cherry picked from commit 261ffff32465b7710e2305d469b2bb5f6cb930ea) --- .../com/rabbitmq/client/test/ChannelNTest.java | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/ChannelNTest.java b/src/test/java/com/rabbitmq/client/test/ChannelNTest.java index 93ec20f15b..f6e85e686e 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelNTest.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelNTest.java @@ -22,6 +22,7 @@ import org.junit.Test; import org.mockito.Mockito; +import java.io.IOException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -30,22 +31,31 @@ public class ChannelNTest { ConsumerWorkService consumerWorkService; ExecutorService executorService; - @Before public void init() { + @Before + public void init() { executorService = Executors.newSingleThreadExecutor(); consumerWorkService = new ConsumerWorkService(executorService, null, 1000, 1000); } - @After public void tearDown() { + @After + public void tearDown() { consumerWorkService.shutdown(); executorService.shutdownNow(); } @Test - public void cancelUnknownConsumerDoesNotThrowException() throws Exception { + public void serverBasicCancelForUnknownConsumerDoesNotThrowException() throws Exception { AMQConnection connection = Mockito.mock(AMQConnection.class); ChannelN channel = new ChannelN(connection, 1, consumerWorkService); Method method = new AMQImpl.Basic.Cancel.Builder().consumerTag("does-not-exist").build(); channel.processAsync(new AMQCommand(method)); } + @Test(expected = IOException.class) + public void callingBasicCancelForUnknownConsumerThrowsException() throws Exception { + AMQConnection connection = Mockito.mock(AMQConnection.class); + ChannelN channel = new ChannelN(connection, 1, consumerWorkService); + channel.basicCancel("does-not-exist"); + } + } From e49f66d6f0fad816feb33012a95d059cfdab2c20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 22 Mar 2019 11:28:24 +0100 Subject: [PATCH 1082/2114] Add comment to explain decision tree References #525 (cherry picked from commit ad6968621409f31bb6967c324a82e90f2daba93a) --- src/main/java/com/rabbitmq/client/impl/ChannelN.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java index 43b8c4d823..5ab12bda20 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelN.java @@ -386,6 +386,10 @@ private void releaseChannel() { Basic.Cancel m = (Basic.Cancel)method; String consumerTag = m.getConsumerTag(); Consumer callback = _consumers.remove(consumerTag); + // Not finding any matching consumer isn't necessarily an indication of an issue anywhere. + // Sometimes there's a natural race condition between consumer management on the server and client ends. + // E.g. Channel#basicCancel called just before a basic.cancel for the same consumer tag is received. + // See https://github.com/rabbitmq/rabbitmq-java-client/issues/525 if (callback == null) { callback = defaultConsumer; } From 28f507aff3acf285776b036632eb99291d553efe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 1 Apr 2019 14:09:50 +0200 Subject: [PATCH 1083/2114] Handle multiple publisher confirms in metrics This is follow-up to #354. Fixes #372 --- .../com/rabbitmq/client/MetricsCollector.java | 2 +- .../rabbitmq/client/NoOpMetricsCollector.java | 2 +- .../client/impl/AbstractMetricsCollector.java | 51 +++++++----- .../com/rabbitmq/client/impl/ChannelN.java | 8 +- .../client/test/MetricsCollectorTest.java | 77 +++++++++++++++---- 5 files changed, 102 insertions(+), 38 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/MetricsCollector.java b/src/main/java/com/rabbitmq/client/MetricsCollector.java index 101948e6b9..09315f8cb0 100644 --- a/src/main/java/com/rabbitmq/client/MetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/MetricsCollector.java @@ -34,7 +34,7 @@ public interface MetricsCollector { void closeChannel(Channel channel); - void basicPublish(Channel channel); + void basicPublish(Channel channel, long deliveryTag); void basicPublishFailure(Channel channel, Throwable cause); diff --git a/src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java b/src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java index 30e0d83402..04df2ea595 100644 --- a/src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java @@ -66,7 +66,7 @@ public void basicCancel(Channel channel, String consumerTag) { } @Override - public void basicPublish(Channel channel) { + public void basicPublish(Channel channel, long deliveryTag) { } diff --git a/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java index 99a5b7a138..b6647f13d4 100644 --- a/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java @@ -24,6 +24,7 @@ import java.util.concurrent.ConcurrentMap; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; +import java.util.function.Function; /** * Base class for {@link MetricsCollector}. @@ -44,6 +45,14 @@ public abstract class AbstractMetricsCollector implements MetricsCollector { private final Runnable markRejectedMessageAction = () -> markRejectedMessage(); + private final Runnable markMessagePublishAcknowledgedAction = () -> markMessagePublishAcknowledged(); + + private final Runnable markMessagePublishNotAcknowledgedAction = () -> markMessagePublishNotAcknowledged(); + + private static final Function> GET_UNACKED_DTAGS = channelState -> channelState.unackedMessageDeliveryTags; + + private static final Function> GET_UNCONFIRMED_DTAGS = channelState -> channelState.unconfirmedMessageDeliveryTags; + @Override public void newConnection(final Connection connection) { try { @@ -94,8 +103,17 @@ public void closeChannel(Channel channel) { } @Override - public void basicPublish(Channel channel) { + public void basicPublish(Channel channel, long deliveryTag) { try { + if (deliveryTag != 0) { + ChannelState channelState = channelState(channel); + channelState.lock.lock(); + try { + channelState(channel).unconfirmedMessageDeliveryTags.add(deliveryTag); + } finally { + channelState.lock.unlock(); + } + } markPublishedMessage(); } catch(Exception e) { LOGGER.info("Error while computing metrics in basicPublish: " + e.getMessage()); @@ -113,26 +131,19 @@ public void basicPublishFailure(Channel channel, Throwable cause) { @Override public void basicPublishAck(Channel channel, long deliveryTag, boolean multiple) { - if (multiple) { - // this is a naive approach, as it does not handle multiple nacks - return; - } try { - markMessagePublishAcknowledged(); - } catch(Exception e) { + updateChannelStateAfterAckReject(channel, deliveryTag, multiple, GET_UNCONFIRMED_DTAGS, markMessagePublishAcknowledgedAction); + } catch (Exception e) { + e.printStackTrace(); LOGGER.info("Error while computing metrics in basicPublishAck: " + e.getMessage()); } } @Override public void basicPublishNack(Channel channel, long deliveryTag, boolean multiple) { - if (multiple) { - // this is a naive approach, as it does not handle multiple nacks - return; - } try { - markMessagePublishNotAcknowledged(); - } catch(Exception e) { + updateChannelStateAfterAckReject(channel, deliveryTag, multiple, GET_UNCONFIRMED_DTAGS, markMessagePublishNotAcknowledgedAction); + } catch (Exception e) { LOGGER.info("Error while computing metrics in basicPublishNack: " + e.getMessage()); } } @@ -217,7 +228,7 @@ public void consumedMessage(Channel channel, long deliveryTag, String consumerTa @Override public void basicAck(Channel channel, long deliveryTag, boolean multiple) { try { - updateChannelStateAfterAckReject(channel, deliveryTag, multiple, markAcknowledgedMessageAction); + updateChannelStateAfterAckReject(channel, deliveryTag, multiple, GET_UNACKED_DTAGS, markAcknowledgedMessageAction); } catch(Exception e) { LOGGER.info("Error while computing metrics in basicAck: " + e.getMessage()); } @@ -226,7 +237,7 @@ public void basicAck(Channel channel, long deliveryTag, boolean multiple) { @Override public void basicNack(Channel channel, long deliveryTag) { try { - updateChannelStateAfterAckReject(channel, deliveryTag, true, markRejectedMessageAction); + updateChannelStateAfterAckReject(channel, deliveryTag, true, GET_UNACKED_DTAGS, markRejectedMessageAction); } catch(Exception e) { LOGGER.info("Error while computing metrics in basicNack: " + e.getMessage()); } @@ -235,18 +246,19 @@ public void basicNack(Channel channel, long deliveryTag) { @Override public void basicReject(Channel channel, long deliveryTag) { try { - updateChannelStateAfterAckReject(channel, deliveryTag, false, markRejectedMessageAction); + updateChannelStateAfterAckReject(channel, deliveryTag, false, GET_UNACKED_DTAGS, markRejectedMessageAction); } catch(Exception e) { LOGGER.info("Error while computing metrics in basicReject: " + e.getMessage()); } } - private void updateChannelStateAfterAckReject(Channel channel, long deliveryTag, boolean multiple, Runnable action) { + private void updateChannelStateAfterAckReject(Channel channel, long deliveryTag, boolean multiple, + Function> dtags, Runnable action) { ChannelState channelState = channelState(channel); channelState.lock.lock(); try { if(multiple) { - Iterator iterator = channelState.unackedMessageDeliveryTags.iterator(); + Iterator iterator = dtags.apply(channelState).iterator(); while(iterator.hasNext()) { long messageDeliveryTag = iterator.next(); if(messageDeliveryTag <= deliveryTag) { @@ -255,7 +267,7 @@ private void updateChannelStateAfterAckReject(Channel channel, long deliveryTag, } } } else { - if (channelState.unackedMessageDeliveryTags.remove(deliveryTag)) { + if (dtags.apply(channelState).remove(deliveryTag)) { action.run(); } } @@ -329,6 +341,7 @@ private static class ChannelState { final Set unackedMessageDeliveryTags = new HashSet(); final Set consumersWithManualAck = new HashSet(); + final Set unconfirmedMessageDeliveryTags = new HashSet<>(); final Channel channel; diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java index 19bb7e0882..38d7d8e551 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelN.java @@ -692,9 +692,13 @@ public void basicPublish(String exchange, String routingKey, BasicProperties props, byte[] body) throws IOException { + final long deliveryTag; if (nextPublishSeqNo > 0) { - unconfirmedSet.add(getNextPublishSeqNo()); + deliveryTag = getNextPublishSeqNo(); + unconfirmedSet.add(deliveryTag); nextPublishSeqNo++; + } else { + deliveryTag = 0; } if (props == null) { props = MessageProperties.MINIMAL_BASIC; @@ -712,7 +716,7 @@ public void basicPublish(String exchange, String routingKey, metricsCollector.basicPublishFailure(this, e); throw e; } - metricsCollector.basicPublish(this); + metricsCollector.basicPublish(this, deliveryTag); } /** Public API - {@inheritDoc} */ diff --git a/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java b/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java index 74f85ac668..9b2c8604dc 100644 --- a/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java +++ b/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java @@ -132,7 +132,7 @@ public void basicGetAndAck() { assertThat(failedToPublishMessages(metrics), is(1L)); assertThat(publishedMessages(metrics), is(0L)); - metrics.basicPublish(channel); + metrics.basicPublish(channel, 0L); assertThat(failedToPublishMessages(metrics), is(1L)); assertThat(publishedMessages(metrics), is(1L)); @@ -140,7 +140,7 @@ public void basicGetAndAck() { assertThat(failedToPublishMessages(metrics), is(2L)); assertThat(publishedMessages(metrics), is(1L)); - metrics.basicPublish(channel); + metrics.basicPublish(channel, 0L); assertThat(failedToPublishMessages(metrics), is(2L)); assertThat(publishedMessages(metrics), is(2L)); @@ -150,43 +150,90 @@ public void basicGetAndAck() { } @Test public void publishingAcknowledgements() { - long anyDeliveryTag = 123L; AbstractMetricsCollector metrics = factory.create(); + Connection connection = mock(Connection.class); + when(connection.getId()).thenReturn("connection-1"); Channel channel = mock(Channel.class); + when(channel.getConnection()).thenReturn(connection); + when(channel.getChannelNumber()).thenReturn(1); + + metrics.newConnection(connection); + metrics.newChannel(channel); + // begins with no messages acknowledged assertThat(publishAck(metrics), is(0L)); // first acknowledgement gets tracked - metrics.basicPublishAck(channel, anyDeliveryTag, false); + metrics.basicPublish(channel, 1); + metrics.basicPublishAck(channel, 1, false); assertThat(publishAck(metrics), is(1L)); // second acknowledgement gets tracked - metrics.basicPublishAck(channel, anyDeliveryTag, false); + metrics.basicPublish(channel, 2); + metrics.basicPublishAck(channel, 2, false); assertThat(publishAck(metrics), is(2L)); - // multiple deliveries aren't tracked - metrics.basicPublishAck(channel, anyDeliveryTag, true); + + // this is idempotent + metrics.basicPublishAck(channel, 2, false); assertThat(publishAck(metrics), is(2L)); + + // multi-ack + metrics.basicPublish(channel, 3); + metrics.basicPublish(channel, 4); + metrics.basicPublish(channel, 5); + // ack-ing in the middle + metrics.basicPublishAck(channel, 4, false); + assertThat(publishAck(metrics), is(3L)); + // ack-ing several at once + metrics.basicPublishAck(channel, 5, true); + assertThat(publishAck(metrics), is(5L)); + + // ack-ing non existent doesn't affect metrics + metrics.basicPublishAck(channel, 123, true); + assertThat(publishAck(metrics), is(5L)); + // cleaning stale state doesn't affect the metric metrics.cleanStaleState(); - assertThat(publishAck(metrics), is(2L)); + assertThat(publishAck(metrics), is(5L)); } @Test public void publishingNotAcknowledgements() { - long anyDeliveryTag = 123L; AbstractMetricsCollector metrics = factory.create(); + Connection connection = mock(Connection.class); + when(connection.getId()).thenReturn("connection-1"); Channel channel = mock(Channel.class); + when(channel.getConnection()).thenReturn(connection); + when(channel.getChannelNumber()).thenReturn(1); + + metrics.newConnection(connection); + metrics.newChannel(channel); // begins with no messages not-acknowledged assertThat(publishNack(metrics), is(0L)); // first not-acknowledgement gets tracked - metrics.basicPublishNack(channel, anyDeliveryTag, false); + metrics.basicPublish(channel, 1); + metrics.basicPublishNack(channel, 1, false); assertThat(publishNack(metrics), is(1L)); // second not-acknowledgement gets tracked - metrics.basicPublishNack(channel, anyDeliveryTag, false); - assertThat(publishNack(metrics), is(2L)); - // multiple deliveries aren't tracked - metrics.basicPublishNack(channel, anyDeliveryTag, true); + metrics.basicPublish(channel, 2); + metrics.basicPublishNack(channel, 2, false); assertThat(publishNack(metrics), is(2L)); + + // multi-nack + metrics.basicPublish(channel, 3); + metrics.basicPublish(channel, 4); + metrics.basicPublish(channel, 5); + // ack-ing in the middle + metrics.basicPublishNack(channel, 4, false); + assertThat(publishNack(metrics), is(3L)); + // ack-ing several at once + metrics.basicPublishNack(channel, 5, true); + assertThat(publishNack(metrics), is(5L)); + + // ack-ing non existent doesn't affect metrics + metrics.basicPublishNack(channel, 123, true); + assertThat(publishNack(metrics), is(5L)); + // cleaning stale state doesn't affect the metric metrics.cleanStaleState(); - assertThat(publishNack(metrics), is(2L)); + assertThat(publishNack(metrics), is(5L)); } @Test public void publishingUnrouted() { From c06008605a4b718c5298ed8377dfb9e2e90dddf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 2 Apr 2019 14:18:47 +0200 Subject: [PATCH 1084/2114] Bump dependencies Fixes #607 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 9f8206a753..f30ff57419 100644 --- a/pom.xml +++ b/pom.xml @@ -54,9 +54,9 @@ UTF-8 UTF-8 - 1.7.25 + 1.7.26 4.0.5 - 1.1.2 + 1.1.3 2.9.8 1.2.3 4.12 From 941575654686a30418ce56e611087df5c11c4573 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 2 Apr 2019 14:23:06 +0200 Subject: [PATCH 1085/2114] Bump test dependencies --- pom.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index f30ff57419..edc514cc0b 100644 --- a/pom.xml +++ b/pom.xml @@ -60,9 +60,9 @@ 2.9.8 1.2.3 4.12 - 3.1.5 - 2.23.4 - 3.11.1 + 3.1.6 + 2.25.1 + 3.12.2 3.0.1 2.5.3 @@ -735,7 +735,7 @@ org.assertj assertj-core - ${assert4j.version} + ${assertj.version} test From 953d255e4728b222e3f3fbc88b8db8a541d82933 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 2 Apr 2019 14:18:47 +0200 Subject: [PATCH 1086/2114] Bump dependencies Fixes #607 (cherry picked from commit c06008605a4b718c5298ed8377dfb9e2e90dddf6) --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 4da58c9d4f..0e9f1e2ddd 100644 --- a/pom.xml +++ b/pom.xml @@ -54,9 +54,9 @@ UTF-8 UTF-8 - 1.7.25 + 1.7.26 4.0.5 - 1.1.2 + 1.1.3 2.9.8 1.2.3 4.12 From bb8f6edf2f4c7fc3d9c805b91c32e59a58782e0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 2 Apr 2019 14:23:06 +0200 Subject: [PATCH 1087/2114] Bump test dependencies (cherry picked from commit 941575654686a30418ce56e611087df5c11c4573) --- pom.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 0e9f1e2ddd..d731fe61c8 100644 --- a/pom.xml +++ b/pom.xml @@ -60,9 +60,9 @@ 2.9.8 1.2.3 4.12 - 3.1.5 - 2.23.4 - 3.11.1 + 3.1.6 + 2.25.1 + 3.12.2 3.0.1 2.5.3 @@ -735,7 +735,7 @@ org.assertj assertj-core - ${assert4j.version} + ${assertj.version} test From e79ed4d7491bc541e15c3e548ed77181778ff0b8 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Tue, 2 Apr 2019 14:00:30 +0000 Subject: [PATCH 1088/2114] [maven-release-plugin] prepare release v5.7.0.RC1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index d731fe61c8..73ca672d08 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.7.0-SNAPSHOT + 5.7.0.RC1 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v5.7.0.RC1 From 9f2dffec12bcebcc41dc0d2a6d996df04661143a Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Tue, 2 Apr 2019 14:00:37 +0000 Subject: [PATCH 1089/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 73ca672d08..d731fe61c8 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.7.0.RC1 + 5.7.0-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v5.7.0.RC1 + HEAD From 1928ce86a7c7da761003af4ee8fed89237b18938 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 5 Apr 2019 10:19:26 +0200 Subject: [PATCH 1090/2114] Set release version to 5.7.0 --- release-versions.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release-versions.txt b/release-versions.txt index 94a66eae2b..3d73cfa347 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="5.7.0.RC1" -DEVELOPMENT_VERSION="5.7.0-SNAPSHOT" +RELEASE_VERSION="5.7.0" +DEVELOPMENT_VERSION="5.8.0-SNAPSHOT" From 57aa724ddd15ac376576894bd869d04b49e62451 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Fri, 5 Apr 2019 08:27:53 +0000 Subject: [PATCH 1091/2114] [maven-release-plugin] prepare release v5.7.0 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index d731fe61c8..539a45bc9c 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.7.0-SNAPSHOT + 5.7.0 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v5.7.0 From 01f1900c2951a8001144efcc23b03c88bff7a8ae Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Fri, 5 Apr 2019 08:27:59 +0000 Subject: [PATCH 1092/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 539a45bc9c..6db1d486d2 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.7.0 + 5.8.0-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v5.7.0 + HEAD From 172cac87ac4504409fe788b27e88bff839e343ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 15 Apr 2019 09:06:51 +0200 Subject: [PATCH 1093/2114] Bump versions in readme --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 18bc738950..ce5b90fc10 100644 --- a/README.md +++ b/README.md @@ -23,14 +23,14 @@ They require Java 8 or higher. com.rabbitmq amqp-client - 5.6.0 + 5.7.0 ``` ### Gradle ``` groovy -compile 'com.rabbitmq:amqp-client:5.6.0' +compile 'com.rabbitmq:amqp-client:5.7.0' ``` #### 4.x Series @@ -42,14 +42,14 @@ They require Java 6 or higher. com.rabbitmq amqp-client - 4.10.0 + 4.11.0 ``` ### Gradle ``` groovy -compile 'com.rabbitmq:amqp-client:4.10.0' +compile 'com.rabbitmq:amqp-client:4.11.0' ``` From 924617e7fea7f92d9b035fdebd1acd454275ee18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 24 Apr 2019 11:30:47 +0200 Subject: [PATCH 1094/2114] Bump Maven to 3.6.1 --- .mvn/wrapper/maven-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index a3f9f18723..a3ba20ec52 100755 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -1 +1 @@ -distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip +distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.6.1/apache-maven-3.6.1-bin.zip From 9ef2462c9c4ba9b9e9c66a977380ed6eb3f48a7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 24 Apr 2019 11:30:47 +0200 Subject: [PATCH 1095/2114] Bump Maven to 3.6.1 (cherry picked from commit 924617e7fea7f92d9b035fdebd1acd454275ee18) --- .mvn/wrapper/maven-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index a3f9f18723..a3ba20ec52 100755 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -1 +1 @@ -distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip +distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.6.1/apache-maven-3.6.1-bin.zip From d6a188ccec01d01e1f846f69b49d12baa51b6c31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 24 Apr 2019 11:32:30 +0200 Subject: [PATCH 1096/2114] Set release version to 5.8.0.RC1 --- release-versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-versions.txt b/release-versions.txt index 3d73cfa347..34cae24ccc 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="5.7.0" +RELEASE_VERSION="5.8.0.RC1" DEVELOPMENT_VERSION="5.8.0-SNAPSHOT" From 41635af2eccfb4b8c8616aa7e5423c774d38e579 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 14 May 2019 11:49:49 +0200 Subject: [PATCH 1097/2114] Use rabbitmqctl to command secondary node Not make. --- .../client/test/functional/ClusteredTestBase.java | 9 +++++++-- .../client/test/server/DurableBindingLifecycle.java | 10 ++-------- src/test/java/com/rabbitmq/tools/Host.java | 6 +++++- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java b/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java index c198db8bd0..6d1b430cf9 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java @@ -124,10 +124,15 @@ public void closeConnection() throws IOException { } protected void stopSecondary() throws IOException { - Host.invokeMakeTarget("stop-rabbit-on-node RABBITMQ_NODENAME=\'" + Host.nodenameB() + "\'"); + Host.executeCommand(Host.rabbitmqctlCommand() + + " -n \'" + Host.nodenameB() + "\'" + + " stop_app"); } protected void startSecondary() throws IOException { - Host.invokeMakeTarget("start-rabbit-on-node RABBITMQ_NODENAME=\'" + Host.nodenameB() + "\'"); + Host.executeCommand(Host.rabbitmqctlCommand() + + " -n \'" + Host.nodenameB() + "\'" + + " start_app"); + Host.tryConnectFor(10_000, Host.node_portB() == null ? 5673 : Integer.valueOf(Host.node_portB())); } } diff --git a/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java b/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java index 644c21d11a..388a3ce7a5 100644 --- a/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java +++ b/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java @@ -26,7 +26,6 @@ import com.rabbitmq.client.GetResponse; import com.rabbitmq.client.test.functional.BindingLifecycleBase; -import com.rabbitmq.tools.Host; /** * This tests whether bindings are created and nuked properly. @@ -47,13 +46,8 @@ protected void restart() throws IOException, TimeoutException { alternateConnection = null; alternateChannel = null; - Host.invokeMakeTarget( - "stop-node" + - " start-background-broker" + - " RABBITMQ_NODENAME=\'" + Host.nodenameB() + "\'" + - " RABBITMQ_NODE_PORT=" + Host.node_portB() + - " RABBITMQ_CONFIG_FILE=\'" + Host.config_fileB() + "\'" - ); + stopSecondary(); + startSecondary(); } restartPrimary(); } diff --git a/src/test/java/com/rabbitmq/tools/Host.java b/src/test/java/com/rabbitmq/tools/Host.java index 0c9e7dbbf1..c30ec7fc6f 100644 --- a/src/test/java/com/rabbitmq/tools/Host.java +++ b/src/test/java/com/rabbitmq/tools/Host.java @@ -22,7 +22,6 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import com.rabbitmq.client.Connection; @@ -142,6 +141,10 @@ public static void stopRabbitOnNode() throws IOException { } public static void tryConnectFor(int timeoutInMs) throws IOException { + tryConnectFor(timeoutInMs, node_portA() == null ? 5672 : Integer.valueOf(node_portA())); + } + + public static void tryConnectFor(int timeoutInMs, int port) throws IOException { int waitTime = 100; int totalWaitTime = 0; while (totalWaitTime <= timeoutInMs) { @@ -152,6 +155,7 @@ public static void tryConnectFor(int timeoutInMs) throws IOException { } totalWaitTime += waitTime; ConnectionFactory connectionFactory = TestUtils.connectionFactory(); + connectionFactory.setPort(port); try (Connection ignored = connectionFactory.newConnection()) { return; From 58d5892db98074151925be1472e155abcc565dd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 14 May 2019 12:49:00 +0200 Subject: [PATCH 1098/2114] Lower log level for tests --- src/test/resources/logback-test.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml index ee88f442c2..4bd2e37606 100644 --- a/src/test/resources/logback-test.xml +++ b/src/test/resources/logback-test.xml @@ -5,7 +5,7 @@ - + \ No newline at end of file From 8c523097feee7be0ad99082f8f6c3ccaf9ef8b05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 14 May 2019 13:33:38 +0200 Subject: [PATCH 1099/2114] Disable hanging test Need more investigation. --- src/test/java/com/rabbitmq/client/test/server/ServerTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/client/test/server/ServerTests.java b/src/test/java/com/rabbitmq/client/test/server/ServerTests.java index bf8631a4b8..5028d9cd3c 100644 --- a/src/test/java/com/rabbitmq/client/test/server/ServerTests.java +++ b/src/test/java/com/rabbitmq/client/test/server/ServerTests.java @@ -26,7 +26,7 @@ Permissions.class, DurableBindingLifecycle.class, DeadLetterExchangeDurable.class, - EffectVisibilityCrossNodeTest.class, + //EffectVisibilityCrossNodeTest.class, ExclusiveQueueDurability.class, AbsentQueue.class, AlternateExchangeEquivalence.class, From 54ed4207ad989cd3f2ad4a771e6568efbcc9f100 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 14 May 2019 11:49:49 +0200 Subject: [PATCH 1100/2114] Use rabbitmqctl to command secondary node Not make. (cherry picked from commit 41635af2eccfb4b8c8616aa7e5423c774d38e579) --- .../client/test/functional/ClusteredTestBase.java | 9 +++++++-- .../client/test/server/DurableBindingLifecycle.java | 10 ++-------- src/test/java/com/rabbitmq/tools/Host.java | 6 +++++- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java b/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java index c198db8bd0..6d1b430cf9 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java @@ -124,10 +124,15 @@ public void closeConnection() throws IOException { } protected void stopSecondary() throws IOException { - Host.invokeMakeTarget("stop-rabbit-on-node RABBITMQ_NODENAME=\'" + Host.nodenameB() + "\'"); + Host.executeCommand(Host.rabbitmqctlCommand() + + " -n \'" + Host.nodenameB() + "\'" + + " stop_app"); } protected void startSecondary() throws IOException { - Host.invokeMakeTarget("start-rabbit-on-node RABBITMQ_NODENAME=\'" + Host.nodenameB() + "\'"); + Host.executeCommand(Host.rabbitmqctlCommand() + + " -n \'" + Host.nodenameB() + "\'" + + " start_app"); + Host.tryConnectFor(10_000, Host.node_portB() == null ? 5673 : Integer.valueOf(Host.node_portB())); } } diff --git a/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java b/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java index 644c21d11a..388a3ce7a5 100644 --- a/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java +++ b/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java @@ -26,7 +26,6 @@ import com.rabbitmq.client.GetResponse; import com.rabbitmq.client.test.functional.BindingLifecycleBase; -import com.rabbitmq.tools.Host; /** * This tests whether bindings are created and nuked properly. @@ -47,13 +46,8 @@ protected void restart() throws IOException, TimeoutException { alternateConnection = null; alternateChannel = null; - Host.invokeMakeTarget( - "stop-node" + - " start-background-broker" + - " RABBITMQ_NODENAME=\'" + Host.nodenameB() + "\'" + - " RABBITMQ_NODE_PORT=" + Host.node_portB() + - " RABBITMQ_CONFIG_FILE=\'" + Host.config_fileB() + "\'" - ); + stopSecondary(); + startSecondary(); } restartPrimary(); } diff --git a/src/test/java/com/rabbitmq/tools/Host.java b/src/test/java/com/rabbitmq/tools/Host.java index 0c9e7dbbf1..c30ec7fc6f 100644 --- a/src/test/java/com/rabbitmq/tools/Host.java +++ b/src/test/java/com/rabbitmq/tools/Host.java @@ -22,7 +22,6 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import com.rabbitmq.client.Connection; @@ -142,6 +141,10 @@ public static void stopRabbitOnNode() throws IOException { } public static void tryConnectFor(int timeoutInMs) throws IOException { + tryConnectFor(timeoutInMs, node_portA() == null ? 5672 : Integer.valueOf(node_portA())); + } + + public static void tryConnectFor(int timeoutInMs, int port) throws IOException { int waitTime = 100; int totalWaitTime = 0; while (totalWaitTime <= timeoutInMs) { @@ -152,6 +155,7 @@ public static void tryConnectFor(int timeoutInMs) throws IOException { } totalWaitTime += waitTime; ConnectionFactory connectionFactory = TestUtils.connectionFactory(); + connectionFactory.setPort(port); try (Connection ignored = connectionFactory.newConnection()) { return; From 346f6f2ee5751479288b3465ee5c148eb8f67011 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 14 May 2019 12:49:00 +0200 Subject: [PATCH 1101/2114] Lower log level for tests (cherry picked from commit 58d5892db98074151925be1472e155abcc565dd6) --- src/test/resources/logback-test.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml index ee88f442c2..4bd2e37606 100644 --- a/src/test/resources/logback-test.xml +++ b/src/test/resources/logback-test.xml @@ -5,7 +5,7 @@ - + \ No newline at end of file From 87723e7c75bd34bbf02c53c9877a62b60f661722 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 14 May 2019 13:33:38 +0200 Subject: [PATCH 1102/2114] Disable hanging test Need more investigation. (cherry picked from commit 8c523097feee7be0ad99082f8f6c3ccaf9ef8b05) --- src/test/java/com/rabbitmq/client/test/server/ServerTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/client/test/server/ServerTests.java b/src/test/java/com/rabbitmq/client/test/server/ServerTests.java index bf8631a4b8..5028d9cd3c 100644 --- a/src/test/java/com/rabbitmq/client/test/server/ServerTests.java +++ b/src/test/java/com/rabbitmq/client/test/server/ServerTests.java @@ -26,7 +26,7 @@ Permissions.class, DurableBindingLifecycle.class, DeadLetterExchangeDurable.class, - EffectVisibilityCrossNodeTest.class, + //EffectVisibilityCrossNodeTest.class, ExclusiveQueueDurability.class, AbsentQueue.class, AlternateExchangeEquivalence.class, From 16524854f5fced9db810b3ddc17f7b1a048717aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 15 May 2019 09:55:32 +0200 Subject: [PATCH 1103/2114] Temporarily disable test Fails on 3.8, disable it until the fix is in the next alpha. --- .../com/rabbitmq/client/test/functional/FunctionalTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java b/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java index fb48f29585..1e28fa27ba 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java +++ b/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java @@ -40,7 +40,7 @@ NoRequeueOnCancel.class, Bug20004Test.class, ExchangeDeleteIfUnused.class, - QosTests.class, + //QosTests.class, AlternateExchange.class, ExchangeExchangeBindings.class, ExchangeExchangeBindingsAutoDelete.class, From 7b6b7af20f41449f0725bd797a197f80ef5b9a7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 15 May 2019 10:48:16 +0200 Subject: [PATCH 1104/2114] Fix and re-enable hanging test The test could hang because a connection was in flow control and a queue purge operation was stuck. The test now uses different connections to publish and purge and use publisher confirms. Publisher confirms seems necessary because the test was expecting the exact number of published messages was purged from the queue. It's maybe expecting too much considering publishing is asynchronous. Publisher confirms should make the test more reliable. --- .../server/EffectVisibilityCrossNodeTest.java | 22 ++++++++++++++----- .../client/test/server/ServerTests.java | 2 +- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java b/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java index 78b2291781..7c7c369cce 100644 --- a/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java +++ b/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java @@ -18,7 +18,11 @@ import static org.junit.Assert.assertEquals; import java.io.IOException; +import java.util.concurrent.TimeoutException; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.test.TestUtils; import org.junit.Test; import com.rabbitmq.client.test.functional.ClusteredTestBase; @@ -29,19 +33,25 @@ */ public class EffectVisibilityCrossNodeTest extends ClusteredTestBase { private final String[] queues = new String[QUEUES]; + private Connection purgeConnection; @Override - protected void createResources() throws IOException { + protected void createResources() throws IOException, TimeoutException { for (int i = 0; i < queues.length ; i++) { queues[i] = alternateChannel.queueDeclare("", false, false, true, null).getQueue(); alternateChannel.queueBind(queues[i], "amq.fanout", ""); } + this.purgeConnection = TestUtils.connectionFactory().newConnection(); } @Override protected void releaseResources() throws IOException { - for (int i = 0; i < queues.length ; i++) { - alternateChannel.queueDelete(queues[i]); + try { + for (int i = 0; i < queues.length ; i++) { + alternateChannel.queueDelete(queues[i]); + } + } finally { + TestUtils.close(this.purgeConnection); } } @@ -52,13 +62,15 @@ protected void releaseResources() throws IOException { private static final byte[] msg = "".getBytes(); @Test public void effectVisibility() throws Exception { - + Channel purgeChannel = this.purgeConnection.createChannel(); + channel.confirmSelect(); for (int i = 0; i < BATCHES; i++) { for (int j = 0; j < MESSAGES_PER_BATCH; j++) { channel.basicPublish("amq.fanout", "", null, msg); } + channel.waitForConfirmsOrDie(10_000); for (int j = 0; j < queues.length ; j++) { - assertEquals(MESSAGES_PER_BATCH, channel.queuePurge(queues[j]).getMessageCount()); + assertEquals(MESSAGES_PER_BATCH, purgeChannel.queuePurge(queues[j]).getMessageCount()); } } } diff --git a/src/test/java/com/rabbitmq/client/test/server/ServerTests.java b/src/test/java/com/rabbitmq/client/test/server/ServerTests.java index 5028d9cd3c..bf8631a4b8 100644 --- a/src/test/java/com/rabbitmq/client/test/server/ServerTests.java +++ b/src/test/java/com/rabbitmq/client/test/server/ServerTests.java @@ -26,7 +26,7 @@ Permissions.class, DurableBindingLifecycle.class, DeadLetterExchangeDurable.class, - //EffectVisibilityCrossNodeTest.class, + EffectVisibilityCrossNodeTest.class, ExclusiveQueueDurability.class, AbsentQueue.class, AlternateExchangeEquivalence.class, From 999d673dc1dfc1bbfa8d69e0f8aa88c09b1e8ebf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 15 May 2019 11:36:20 +0200 Subject: [PATCH 1105/2114] Increase publisher confirm timeout in test --- .../client/test/server/EffectVisibilityCrossNodeTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java b/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java index 7c7c369cce..3cce62d5dc 100644 --- a/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java +++ b/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java @@ -68,7 +68,7 @@ protected void releaseResources() throws IOException { for (int j = 0; j < MESSAGES_PER_BATCH; j++) { channel.basicPublish("amq.fanout", "", null, msg); } - channel.waitForConfirmsOrDie(10_000); + channel.waitForConfirmsOrDie(60_000); for (int j = 0; j < queues.length ; j++) { assertEquals(MESSAGES_PER_BATCH, purgeChannel.queuePurge(queues[j]).getMessageCount()); } From ed0a3b0a995896dbed6bdad7be009141223c1e48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 15 May 2019 12:55:37 +0200 Subject: [PATCH 1106/2114] Revert "Increase publisher confirm timeout in test" This reverts commit 999d673dc1dfc1bbfa8d69e0f8aa88c09b1e8ebf. --- .../client/test/server/EffectVisibilityCrossNodeTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java b/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java index 3cce62d5dc..7c7c369cce 100644 --- a/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java +++ b/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java @@ -68,7 +68,7 @@ protected void releaseResources() throws IOException { for (int j = 0; j < MESSAGES_PER_BATCH; j++) { channel.basicPublish("amq.fanout", "", null, msg); } - channel.waitForConfirmsOrDie(60_000); + channel.waitForConfirmsOrDie(10_000); for (int j = 0; j < queues.length ; j++) { assertEquals(MESSAGES_PER_BATCH, purgeChannel.queuePurge(queues[j]).getMessageCount()); } From e45884039a03590c658d754231fe1a538f9dc9a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 15 May 2019 12:55:46 +0200 Subject: [PATCH 1107/2114] Revert "Fix and re-enable hanging test" This reverts commit 7b6b7af20f41449f0725bd797a197f80ef5b9a7c. --- .../server/EffectVisibilityCrossNodeTest.java | 22 +++++-------------- .../client/test/server/ServerTests.java | 2 +- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java b/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java index 7c7c369cce..78b2291781 100644 --- a/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java +++ b/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java @@ -18,11 +18,7 @@ import static org.junit.Assert.assertEquals; import java.io.IOException; -import java.util.concurrent.TimeoutException; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.test.TestUtils; import org.junit.Test; import com.rabbitmq.client.test.functional.ClusteredTestBase; @@ -33,25 +29,19 @@ */ public class EffectVisibilityCrossNodeTest extends ClusteredTestBase { private final String[] queues = new String[QUEUES]; - private Connection purgeConnection; @Override - protected void createResources() throws IOException, TimeoutException { + protected void createResources() throws IOException { for (int i = 0; i < queues.length ; i++) { queues[i] = alternateChannel.queueDeclare("", false, false, true, null).getQueue(); alternateChannel.queueBind(queues[i], "amq.fanout", ""); } - this.purgeConnection = TestUtils.connectionFactory().newConnection(); } @Override protected void releaseResources() throws IOException { - try { - for (int i = 0; i < queues.length ; i++) { - alternateChannel.queueDelete(queues[i]); - } - } finally { - TestUtils.close(this.purgeConnection); + for (int i = 0; i < queues.length ; i++) { + alternateChannel.queueDelete(queues[i]); } } @@ -62,15 +52,13 @@ protected void releaseResources() throws IOException { private static final byte[] msg = "".getBytes(); @Test public void effectVisibility() throws Exception { - Channel purgeChannel = this.purgeConnection.createChannel(); - channel.confirmSelect(); + for (int i = 0; i < BATCHES; i++) { for (int j = 0; j < MESSAGES_PER_BATCH; j++) { channel.basicPublish("amq.fanout", "", null, msg); } - channel.waitForConfirmsOrDie(10_000); for (int j = 0; j < queues.length ; j++) { - assertEquals(MESSAGES_PER_BATCH, purgeChannel.queuePurge(queues[j]).getMessageCount()); + assertEquals(MESSAGES_PER_BATCH, channel.queuePurge(queues[j]).getMessageCount()); } } } diff --git a/src/test/java/com/rabbitmq/client/test/server/ServerTests.java b/src/test/java/com/rabbitmq/client/test/server/ServerTests.java index bf8631a4b8..5028d9cd3c 100644 --- a/src/test/java/com/rabbitmq/client/test/server/ServerTests.java +++ b/src/test/java/com/rabbitmq/client/test/server/ServerTests.java @@ -26,7 +26,7 @@ Permissions.class, DurableBindingLifecycle.class, DeadLetterExchangeDurable.class, - EffectVisibilityCrossNodeTest.class, + //EffectVisibilityCrossNodeTest.class, ExclusiveQueueDurability.class, AbsentQueue.class, AlternateExchangeEquivalence.class, From 838cc5500eb1f1d25ef5591bbeb6d23455244d46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 15 May 2019 13:03:14 +0200 Subject: [PATCH 1108/2114] Fix hanging test Make it less harsh and execute it in dedicated thread to avoid hanging. --- .../server/EffectVisibilityCrossNodeTest.java | 31 +++++++++++++------ .../client/test/server/ServerTests.java | 2 +- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java b/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java index 78b2291781..cea5f368a1 100644 --- a/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java +++ b/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java @@ -18,6 +18,7 @@ import static org.junit.Assert.assertEquals; import java.io.IOException; +import java.util.concurrent.*; import org.junit.Test; @@ -46,20 +47,30 @@ protected void releaseResources() throws IOException { } private static final int QUEUES = 5; - private static final int BATCHES = 500; - private static final int MESSAGES_PER_BATCH = 10; + private static final int BATCHES = 100; + private static final int MESSAGES_PER_BATCH = 5; private static final byte[] msg = "".getBytes(); @Test public void effectVisibility() throws Exception { - - for (int i = 0; i < BATCHES; i++) { - for (int j = 0; j < MESSAGES_PER_BATCH; j++) { - channel.basicPublish("amq.fanout", "", null, msg); - } - for (int j = 0; j < queues.length ; j++) { - assertEquals(MESSAGES_PER_BATCH, channel.queuePurge(queues[j]).getMessageCount()); - } + ExecutorService executorService = Executors.newSingleThreadExecutor(); + try { + Future task = executorService.submit(() -> { + for (int i = 0; i < BATCHES; i++) { + Thread.sleep(10); // to avoid flow control for the connection + for (int j = 0; j < MESSAGES_PER_BATCH; j++) { + channel.basicPublish("amq.fanout", "", null, msg); + } + for (int j = 0; j < queues.length; j++) { + assertEquals(MESSAGES_PER_BATCH, channel.queuePurge(queues[j]).getMessageCount()); + } + } + return null; + }); + task.get(1, TimeUnit.MINUTES); + } finally { + executorService.shutdownNow(); + executorService.awaitTermination(1, TimeUnit.SECONDS); } } } diff --git a/src/test/java/com/rabbitmq/client/test/server/ServerTests.java b/src/test/java/com/rabbitmq/client/test/server/ServerTests.java index 5028d9cd3c..bf8631a4b8 100644 --- a/src/test/java/com/rabbitmq/client/test/server/ServerTests.java +++ b/src/test/java/com/rabbitmq/client/test/server/ServerTests.java @@ -26,7 +26,7 @@ Permissions.class, DurableBindingLifecycle.class, DeadLetterExchangeDurable.class, - //EffectVisibilityCrossNodeTest.class, + EffectVisibilityCrossNodeTest.class, ExclusiveQueueDurability.class, AbsentQueue.class, AlternateExchangeEquivalence.class, From 97ebf216cb32707c559876e6a5511c6f51d025f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 15 May 2019 13:03:14 +0200 Subject: [PATCH 1109/2114] Fix hanging test Make it less harsh and execute it in dedicated thread to avoid hanging. (cherry picked from commit 838cc5500eb1f1d25ef5591bbeb6d23455244d46) --- .../server/EffectVisibilityCrossNodeTest.java | 31 +++++++++++++------ .../client/test/server/ServerTests.java | 2 +- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java b/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java index 78b2291781..cea5f368a1 100644 --- a/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java +++ b/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java @@ -18,6 +18,7 @@ import static org.junit.Assert.assertEquals; import java.io.IOException; +import java.util.concurrent.*; import org.junit.Test; @@ -46,20 +47,30 @@ protected void releaseResources() throws IOException { } private static final int QUEUES = 5; - private static final int BATCHES = 500; - private static final int MESSAGES_PER_BATCH = 10; + private static final int BATCHES = 100; + private static final int MESSAGES_PER_BATCH = 5; private static final byte[] msg = "".getBytes(); @Test public void effectVisibility() throws Exception { - - for (int i = 0; i < BATCHES; i++) { - for (int j = 0; j < MESSAGES_PER_BATCH; j++) { - channel.basicPublish("amq.fanout", "", null, msg); - } - for (int j = 0; j < queues.length ; j++) { - assertEquals(MESSAGES_PER_BATCH, channel.queuePurge(queues[j]).getMessageCount()); - } + ExecutorService executorService = Executors.newSingleThreadExecutor(); + try { + Future task = executorService.submit(() -> { + for (int i = 0; i < BATCHES; i++) { + Thread.sleep(10); // to avoid flow control for the connection + for (int j = 0; j < MESSAGES_PER_BATCH; j++) { + channel.basicPublish("amq.fanout", "", null, msg); + } + for (int j = 0; j < queues.length; j++) { + assertEquals(MESSAGES_PER_BATCH, channel.queuePurge(queues[j]).getMessageCount()); + } + } + return null; + }); + task.get(1, TimeUnit.MINUTES); + } finally { + executorService.shutdownNow(); + executorService.awaitTermination(1, TimeUnit.SECONDS); } } } diff --git a/src/test/java/com/rabbitmq/client/test/server/ServerTests.java b/src/test/java/com/rabbitmq/client/test/server/ServerTests.java index 5028d9cd3c..bf8631a4b8 100644 --- a/src/test/java/com/rabbitmq/client/test/server/ServerTests.java +++ b/src/test/java/com/rabbitmq/client/test/server/ServerTests.java @@ -26,7 +26,7 @@ Permissions.class, DurableBindingLifecycle.class, DeadLetterExchangeDurable.class, - //EffectVisibilityCrossNodeTest.class, + EffectVisibilityCrossNodeTest.class, ExclusiveQueueDurability.class, AbsentQueue.class, AlternateExchangeEquivalence.class, From bd385248f8771ea5a7c11bedca8f05bed83c126f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 16 May 2019 10:31:26 +0200 Subject: [PATCH 1110/2114] Handle exception in NIO loop to avoid abrupt termination Fixes #611 --- src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java b/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java index 44f438cf58..e153e721c8 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java @@ -115,7 +115,14 @@ public void run() { registration = registrationIterator.next(); registrationIterator.remove(); int operations = registration.operations; - registration.state.getChannel().register(selector, operations, registration.state); + try { + if (registration.state.getChannel().isOpen()) { + registration.state.getChannel().register(selector, operations, registration.state); + } + } catch (Exception e) { + // can happen if the channel has been closed since the operation has been enqueued + LOGGER.info("Error while registering socket channel for read: {}", e.getMessage()); + } } if (select > 0) { From 8188914543578b7279cd656c1070e20da85655a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 16 May 2019 10:31:26 +0200 Subject: [PATCH 1111/2114] Handle exception in NIO loop to avoid abrupt termination Fixes #611 (cherry picked from commit bd385248f8771ea5a7c11bedca8f05bed83c126f) --- src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java b/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java index 44f438cf58..e153e721c8 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java @@ -115,7 +115,14 @@ public void run() { registration = registrationIterator.next(); registrationIterator.remove(); int operations = registration.operations; - registration.state.getChannel().register(selector, operations, registration.state); + try { + if (registration.state.getChannel().isOpen()) { + registration.state.getChannel().register(selector, operations, registration.state); + } + } catch (Exception e) { + // can happen if the channel has been closed since the operation has been enqueued + LOGGER.info("Error while registering socket channel for read: {}", e.getMessage()); + } } if (select > 0) { From 44c3ca20ddff2096d6062ce7d8acdf588d76a9f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 23 May 2019 16:46:16 +0100 Subject: [PATCH 1112/2114] Increase TTL in dead lettering tests Those fail sometimes on CI, increasing TTL can help on slow-ish environment. --- .../com/rabbitmq/client/test/functional/DeadLetterExchange.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java index 12e96cf4b8..6a7f97725e 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java @@ -35,7 +35,7 @@ public class DeadLetterExchange extends BrokerTestCase { public static final String DLQ = "queue.dlq"; private static final String DLQ2 = "queue.dlq2"; public static final int MSG_COUNT = 10; - private static final int TTL = 1000; + private static final int TTL = 2000; @Override protected void createResources() throws IOException { From 767a19bdb798ad8d5a747edc562a9c1be55c9fb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 23 May 2019 16:55:32 +0100 Subject: [PATCH 1113/2114] Bump Jackson to 2.9.9 Fixes #612 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index edc514cc0b..cff83e31d3 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,7 @@ 1.7.26 4.0.5 1.1.3 - 2.9.8 + 2.9.9 1.2.3 4.12 3.1.6 From e3c68c3fba3fd4ec7780a80dc5c26b6ebfaa58c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 23 May 2019 16:46:16 +0100 Subject: [PATCH 1114/2114] Increase TTL in dead lettering tests Those fail sometimes on CI, increasing TTL can help on slow-ish environment. (cherry picked from commit 44c3ca20ddff2096d6062ce7d8acdf588d76a9f1) --- .../com/rabbitmq/client/test/functional/DeadLetterExchange.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java index 12e96cf4b8..6a7f97725e 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java @@ -35,7 +35,7 @@ public class DeadLetterExchange extends BrokerTestCase { public static final String DLQ = "queue.dlq"; private static final String DLQ2 = "queue.dlq2"; public static final int MSG_COUNT = 10; - private static final int TTL = 1000; + private static final int TTL = 2000; @Override protected void createResources() throws IOException { From 23525b6f88d8d37bf630ed41f03164d0e8264156 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 23 May 2019 16:55:32 +0100 Subject: [PATCH 1115/2114] Bump Jackson to 2.9.9 Fixes #612 (cherry picked from commit 767a19bdb798ad8d5a747edc562a9c1be55c9fb0) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6db1d486d2..1d4fc3a7be 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,7 @@ 1.7.26 4.0.5 1.1.3 - 2.9.8 + 2.9.9 1.2.3 4.12 3.1.6 From 7eef0387ff8a7a32087073846898a82aae707a71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 27 May 2019 13:11:31 +0200 Subject: [PATCH 1116/2114] Bump versions in readme --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index ce5b90fc10..f3424e87e3 100644 --- a/README.md +++ b/README.md @@ -23,14 +23,14 @@ They require Java 8 or higher. com.rabbitmq amqp-client - 5.7.0 + 5.7.1 ``` ### Gradle ``` groovy -compile 'com.rabbitmq:amqp-client:5.7.0' +compile 'com.rabbitmq:amqp-client:5.7.1' ``` #### 4.x Series @@ -42,14 +42,14 @@ They require Java 6 or higher. com.rabbitmq amqp-client - 4.11.0 + 4.11.1 ``` ### Gradle ``` groovy -compile 'com.rabbitmq:amqp-client:4.11.0' +compile 'com.rabbitmq:amqp-client:4.11.1' ``` From d00d84fefd6f948972c05a8e658735bb5389a4cc Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Sun, 16 Jun 2019 22:58:01 +0300 Subject: [PATCH 1117/2114] Correct JavaDoc for a couple of methods Fixes #615. --- src/main/java/com/rabbitmq/client/Channel.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/Channel.java b/src/main/java/com/rabbitmq/client/Channel.java index 51e50d8917..f38d5e5f53 100644 --- a/src/main/java/com/rabbitmq/client/Channel.java +++ b/src/main/java/com/rabbitmq/client/Channel.java @@ -1346,7 +1346,7 @@ void basicNack(long deliveryTag, boolean multiple, boolean requeue) /** * Returns the number of messages in a queue ready to be delivered * to consumers. This method assumes the queue exists. If it doesn't, - * an exception will be closed with an exception. + * the channels will be closed with an exception. * @param queue the name of the queue * @return the number of messages in ready state * @throws IOException Problem transmitting method. @@ -1356,7 +1356,7 @@ void basicNack(long deliveryTag, boolean multiple, boolean requeue) /** * Returns the number of consumers on a queue. * This method assumes the queue exists. If it doesn't, - * an exception will be closed with an exception. + * the channel will be closed with an exception. * @param queue the name of the queue * @return the number of consumers * @throws IOException Problem transmitting method. From 4191a84a8c5591e03e21fd219b519ad6399b1ac6 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Sun, 16 Jun 2019 22:58:01 +0300 Subject: [PATCH 1118/2114] Correct JavaDoc for a couple of methods Fixes #615. (cherry picked from commit d00d84fefd6f948972c05a8e658735bb5389a4cc) --- src/main/java/com/rabbitmq/client/Channel.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/Channel.java b/src/main/java/com/rabbitmq/client/Channel.java index c4312e041a..b1daa31100 100644 --- a/src/main/java/com/rabbitmq/client/Channel.java +++ b/src/main/java/com/rabbitmq/client/Channel.java @@ -1347,7 +1347,7 @@ void basicNack(long deliveryTag, boolean multiple, boolean requeue) /** * Returns the number of messages in a queue ready to be delivered * to consumers. This method assumes the queue exists. If it doesn't, - * an exception will be closed with an exception. + * the channels will be closed with an exception. * @param queue the name of the queue * @return the number of messages in ready state * @throws IOException Problem transmitting method. @@ -1357,7 +1357,7 @@ void basicNack(long deliveryTag, boolean multiple, boolean requeue) /** * Returns the number of consumers on a queue. * This method assumes the queue exists. If it doesn't, - * an exception will be closed with an exception. + * the channel will be closed with an exception. * @param queue the name of the queue * @return the number of consumers * @throws IOException Problem transmitting method. From 4251459c7c397efb066e3c38d21ce122836a7794 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 21 Jun 2019 16:11:31 +0200 Subject: [PATCH 1119/2114] Add OAuth 2 credentials provider and refresh service WIP. --- pom.xml | 7 + .../rabbitmq/client/ConnectionFactory.java | 17 +- .../rabbitmq/client/impl/AMQConnection.java | 33 ++ .../client/impl/ConnectionParams.java | 10 + .../client/impl/CredentialsProvider.java | 55 +++- .../impl/CredentialsRefreshService.java | 73 +++++ .../impl/DefaultCredentialsProvider.java | 15 + .../DefaultCredentialsRefreshService.java | 307 ++++++++++++++++++ ...ntCredentialsGrantCredentialsProvider.java | 233 +++++++++++++ .../impl/OAuthTokenManagementException.java | 27 ++ .../client/RefreshCredentialsTest.java | 81 +++++ .../DefaultCredentialsRefreshServiceTest.java | 181 +++++++++++ ...edentialsGrantCredentialsProviderTest.java | 190 +++++++++++ .../com/rabbitmq/client/test/ClientTests.java | 9 +- .../com/rabbitmq/client/test/TestUtils.java | 9 + 15 files changed, 1235 insertions(+), 12 deletions(-) create mode 100644 src/main/java/com/rabbitmq/client/impl/CredentialsRefreshService.java create mode 100644 src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java create mode 100644 src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java create mode 100644 src/main/java/com/rabbitmq/client/impl/OAuthTokenManagementException.java create mode 100644 src/test/java/com/rabbitmq/client/RefreshCredentialsTest.java create mode 100644 src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java create mode 100644 src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java diff --git a/pom.xml b/pom.xml index cff83e31d3..628e74de92 100644 --- a/pom.xml +++ b/pom.xml @@ -63,6 +63,7 @@ 3.1.6 2.25.1 3.12.2 + 9.4.19.v20190610 3.0.1 2.5.3 @@ -744,6 +745,12 @@ 1.3 test + + org.eclipse.jetty + jetty-servlet + ${jetty.version} + test + diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 06037b6e24..4f8948ae5b 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -15,15 +15,7 @@ package com.rabbitmq.client; -import com.rabbitmq.client.impl.AMQConnection; -import com.rabbitmq.client.impl.ConnectionParams; -import com.rabbitmq.client.impl.CredentialsProvider; -import com.rabbitmq.client.impl.DefaultCredentialsProvider; -import com.rabbitmq.client.impl.DefaultExceptionHandler; -import com.rabbitmq.client.impl.ErrorOnWriteListener; -import com.rabbitmq.client.impl.FrameHandler; -import com.rabbitmq.client.impl.FrameHandlerFactory; -import com.rabbitmq.client.impl.SocketFrameHandlerFactory; +import com.rabbitmq.client.impl.*; import com.rabbitmq.client.impl.nio.NioParams; import com.rabbitmq.client.impl.nio.SocketChannelFrameHandlerFactory; import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; @@ -209,6 +201,8 @@ public class ConnectionFactory implements Cloneable { */ private TrafficListener trafficListener = TrafficListener.NO_OP; + private CredentialsRefreshService credentialsRefreshService; + /** @return the default host to use for connections */ public String getHost() { return host; @@ -854,6 +848,10 @@ public MetricsCollector getMetricsCollector() { return metricsCollector; } + public void setCredentialsRefreshService(CredentialsRefreshService credentialsRefreshService) { + this.credentialsRefreshService = credentialsRefreshService; + } + protected synchronized FrameHandlerFactory createFrameHandlerFactory() throws IOException { if(nio) { if(this.frameHandlerFactory == null) { @@ -1161,6 +1159,7 @@ public ConnectionParams params(ExecutorService consumerWorkServiceExecutor) { result.setConnectionRecoveryTriggeringCondition(connectionRecoveryTriggeringCondition); result.setTopologyRecoveryRetryHandler(topologyRecoveryRetryHandler); result.setTrafficListener(trafficListener); + result.setCredentialsRefreshService(credentialsRefreshService); return result; } diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index 80ea32bb3d..95d55c011f 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -142,6 +142,7 @@ public static Map defaultClientProperties() { private final int channelRpcTimeout; private final boolean channelShouldCheckRpcResponseType; private final TrafficListener trafficListener; + private final CredentialsRefreshService credentialsRefreshService; /* State modified after start - all volatile */ @@ -239,6 +240,9 @@ public AMQConnection(ConnectionParams params, FrameHandler frameHandler, Metrics this.channelShouldCheckRpcResponseType = params.channelShouldCheckRpcResponseType(); this.trafficListener = params.getTrafficListener() == null ? TrafficListener.NO_OP : params.getTrafficListener(); + + this.credentialsRefreshService = params.getCredentialsRefreshService(); + this._channel0 = new AMQChannel(this, 0) { @Override public boolean processAsync(Command c) throws IOException { return getConnection().processControlCommand(c); @@ -336,6 +340,15 @@ public void start() String username = credentialsProvider.getUsername(); String password = credentialsProvider.getPassword(); + + if (credentialsProvider.getExpiration() != null) { + if (this.credentialsRefreshService.needRefresh(credentialsProvider.getExpiration())) { + credentialsProvider.refresh(); + username = credentialsProvider.getUsername(); + password = credentialsProvider.getPassword(); + } + } + LongString challenge = null; LongString response = sm.handleChallenge(null, username, password); @@ -410,6 +423,26 @@ public void start() throw AMQChannel.wrap(sse); } + if (this.credentialsProvider.getExpiration() != null) { + String registrationId = this.credentialsRefreshService.register(credentialsProvider, () -> { + // return false if connection is closed, so refresh service can get rid of this registration + if (!isOpen()) { + return false; + } + if (this._inConnectionNegotiation) { + // this should not happen + return true; + } + String refreshedPassword = credentialsProvider.getPassword(); + + // TODO send password to server with update-secret extension, using channel 0 + + return true; + }); + + addShutdownListener(sse -> this.credentialsRefreshService.unregister(this.credentialsProvider, registrationId)); + } + // We can now respond to errors having finished tailoring the connection this._inConnectionNegotiation = false; } diff --git a/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java b/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java index 849905e2a8..57a028783b 100644 --- a/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java +++ b/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java @@ -60,6 +60,8 @@ public class ConnectionParams { private TrafficListener trafficListener; + private CredentialsRefreshService credentialsRefreshService; + public ConnectionParams() {} public CredentialsProvider getCredentialsProvider() { @@ -277,4 +279,12 @@ public void setTrafficListener(TrafficListener trafficListener) { public TrafficListener getTrafficListener() { return trafficListener; } + + public void setCredentialsRefreshService(CredentialsRefreshService credentialsRefreshService) { + this.credentialsRefreshService = credentialsRefreshService; + } + + public CredentialsRefreshService getCredentialsRefreshService() { + return credentialsRefreshService; + } } diff --git a/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java index 1b1c308cd6..a7db53f8c3 100644 --- a/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java @@ -1,16 +1,67 @@ +// Copyright (c) 2018-2019 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.impl; +import java.util.Date; + /** * Provider interface for establishing credentials for connecting to the broker. Especially useful - * for situations where credentials might change before a recovery takes place or where it is + * for situations where credentials might expire or change before a recovery takes place or where it is * convenient to plug in an outside custom implementation. * - * @since 4.5.0 + * @see CredentialsRefreshService + * @since 5.2.0 */ public interface CredentialsProvider { + /** + * Username to use for authentication + * + * @return username + */ String getUsername(); + /** + * Password/secret/token to use for authentication + * + * @return password/secret/token + */ String getPassword(); + /** + * The expiration date of the credentials, if any. + *

+ * If credentials do not expire, must return null. Default + * behavior is to return null, assuming credentials never + * expire. + * + * @return credentials expiration date + */ + default Date getExpiration() { + // no expiration by default + return null; + } + + /** + * Instructs the provider to refresh or renew credentials. + *

+ * Default behavior is no-op. + */ + default void refresh() { + // no need to refresh anything by default + } + } \ No newline at end of file diff --git a/src/main/java/com/rabbitmq/client/impl/CredentialsRefreshService.java b/src/main/java/com/rabbitmq/client/impl/CredentialsRefreshService.java new file mode 100644 index 0000000000..536c0dc0e0 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/CredentialsRefreshService.java @@ -0,0 +1,73 @@ +// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl; + +import java.util.Date; +import java.util.concurrent.Callable; + +/** + * Provider interface to refresh credentials when appropriate + * and perform an operation once the credentials have been + * renewed. In the context of RabbitMQ, the operation consists + * in calling the update.secret AMQP extension + * to provide new valid credentials before the current ones + * expire. + *

+ * New connections are registered and implementations must perform + * credentials renewal when appropriate. Implementations + * must call a registered callback once credentials are renewed. + * + * @see CredentialsProvider + * @see DefaultCredentialsRefreshService + */ +public interface CredentialsRefreshService { + + /** + * Register a new entity that needs credentials renewal. + *

+ * The registered callback must return true if the action was + * performed correctly, throw an exception if something goes wrong, + * and return false if it became stale and wants to be unregistered. + *

+ * Implementations are free to automatically unregister an entity whose + * callback has failed a given number of times. + * + * @param credentialsProvider the credentials provider + * @param refreshAction the action to perform after credentials renewal + * @return a tracking ID for the registration + */ + String register(CredentialsProvider credentialsProvider, Callable refreshAction); + + /** + * Unregister the entity with the given registration ID. + *

+ * Its state is cleaned up and its registered callback will not be + * called again. + * + * @param credentialsProvider the credentials provider + * @param registrationId the registration ID + */ + void unregister(CredentialsProvider credentialsProvider, String registrationId); + + /** + * Provide a hint about whether credentials should be renewed. + * + * @param expiration + * @return true if credentials should be renewed, false otherwise + */ + boolean needRefresh(Date expiration); + +} diff --git a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java index f743a14618..20cbbe3acc 100644 --- a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java @@ -1,3 +1,18 @@ +// Copyright (c) 2018-2019 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.impl; /** diff --git a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java new file mode 100644 index 0000000000..091948bb82 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java @@ -0,0 +1,307 @@ +// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.time.Duration; +import java.util.Date; +import java.util.Iterator; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; +import java.util.function.Supplier; + +/** + * Scheduling-based implementation of {@link CredentialsRefreshService}. + *

+ * This implementation keeps track of entities (typically AMQP connections) that need + * to renew credentials. Token renewal is scheduled based on token expiration, using + * a Function refreshDelayStrategy. Once credentials + * for a {@link CredentialsProvider} have been renewed, the callback registered + * by each entity/connection is performed. This callback typically propagates + * the new credentials in the entity state, e.g. sending the new password to the + * broker for AMQP connections. + */ +public class DefaultCredentialsRefreshService implements CredentialsRefreshService { + + private static final Logger LOGGER = LoggerFactory.getLogger(DefaultCredentialsRefreshService.class); + + private final ScheduledExecutorService scheduler; + + private final ConcurrentMap credentialsProviderStates = new ConcurrentHashMap<>(); + + private final boolean privateScheduler; + + private final Function refreshDelayStrategy; + + private final Function needRefreshStrategy; + + public DefaultCredentialsRefreshService(ScheduledExecutorService scheduler, Function refreshDelayStrategy, Function needRefreshStrategy) { + this.refreshDelayStrategy = refreshDelayStrategy; + this.needRefreshStrategy = needRefreshStrategy; + if (scheduler == null) { + this.scheduler = Executors.newScheduledThreadPool(1); + privateScheduler = true; + } else { + this.scheduler = scheduler; + privateScheduler = false; + } + } + + /** + * Delay before refresh is TTL - specified duration. + *

+ * E.g. if TTL is 60 seconds and specified duration is 20 seconds, refresh will + * be scheduled in 60 - 20 = 40 seconds. + * + * @param duration + * @return + */ + public static Function fixedDelayBeforeExpirationRefreshDelayStrategy(Duration duration) { + return new FixedDelayBeforeExpirationRefreshDelayStrategy(duration.toMillis()); + } + + /** + * Advise to refresh credentials if TTL <= limit. + * + * @param limitBeforeExpiration + * @return + */ + public static Function fixedTimeNeedRefreshStrategy(Duration limitBeforeExpiration) { + return new FixedTimeNeedRefreshStrategy(limitBeforeExpiration.toMillis()); + } + + // TODO add a delay refresh strategy that bases the time on a percentage of the TTL, use it as default with 80% TTL + + private static Runnable refresh(ScheduledExecutorService scheduler, CredentialsProviderState credentialsProviderState, + Function refreshDelayStrategy) { + return () -> { + LOGGER.debug("Refreshing token"); + credentialsProviderState.refresh(); + + Date expirationAfterRefresh = credentialsProviderState.credentialsProvider.getExpiration(); + long newDelay = refreshDelayStrategy.apply(expirationAfterRefresh); + + LOGGER.debug("Scheduling refresh in {} milliseconds", newDelay); + + ScheduledFuture scheduledFuture = scheduler.schedule(refresh(scheduler, credentialsProviderState, refreshDelayStrategy), newDelay, TimeUnit.MILLISECONDS); + credentialsProviderState.refreshTask.set(scheduledFuture); + }; + } + + @Override + public String register(CredentialsProvider credentialsProvider, Callable refreshAction) { + String registrationId = UUID.randomUUID().toString(); + LOGGER.debug("New registration {}", registrationId); + + Registration registration = new Registration(registrationId, refreshAction); + CredentialsProviderState credentialsProviderState = credentialsProviderStates.computeIfAbsent( + credentialsProvider, + credentialsProviderKey -> new CredentialsProviderState(credentialsProviderKey) + ); + + credentialsProviderState.add(registration); + + credentialsProviderState.maybeSetRefreshTask(() -> { + Date expiration = credentialsProvider.getExpiration(); + long delay = refreshDelayStrategy.apply(expiration); + LOGGER.debug("Scheduling refresh in {} milliseconds", delay); + return scheduler.schedule(refresh(scheduler, credentialsProviderState, refreshDelayStrategy), delay, TimeUnit.MILLISECONDS); + }); + + return registrationId; + } + + @Override + public void unregister(CredentialsProvider credentialsProvider, String registrationId) { + CredentialsProviderState credentialsProviderState = this.credentialsProviderStates.get(credentialsProvider); + if (credentialsProviderState != null) { + credentialsProviderState.unregister(registrationId); + } + } + + @Override + public boolean needRefresh(Date expiration) { + return this.needRefreshStrategy.apply(expiration); + } + + public void close() { + if (privateScheduler) { + scheduler.shutdownNow(); + } + } + + private static class FixedTimeNeedRefreshStrategy implements Function { + + private final long limitBeforeExpiration; + + private FixedTimeNeedRefreshStrategy(long limitBeforeExpiration) { + this.limitBeforeExpiration = limitBeforeExpiration; + } + + @Override + public Boolean apply(Date expiration) { + long ttl = expiration.getTime() - new Date().getTime(); + return ttl <= limitBeforeExpiration; + } + } + + private static class FixedDelayBeforeExpirationRefreshDelayStrategy implements Function { + + private final long delay; + + private FixedDelayBeforeExpirationRefreshDelayStrategy(long delay) { + this.delay = delay; + } + + @Override + public Long apply(Date expiration) { + long ttl = expiration.getTime() - new Date().getTime(); + long refreshTimeBeforeExpiration = ttl - delay; + if (refreshTimeBeforeExpiration < 0) { + return ttl; + } else { + return refreshTimeBeforeExpiration; + } + } + } + + static class Registration { + + private final Callable refreshAction; + + private final AtomicInteger errorHistory = new AtomicInteger(0); + + private final String id; + + Registration(String id, Callable refreshAction) { + this.refreshAction = refreshAction; + this.id = id; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Registration that = (Registration) o; + + return id.equals(that.id); + } + + @Override + public int hashCode() { + return id.hashCode(); + } + } + + /** + * State and refresh behavior for a {@link CredentialsProvider} and + * its registered entities. + */ + static class CredentialsProviderState { + + private final CredentialsProvider credentialsProvider; + + private final Map registrations = new ConcurrentHashMap<>(); + + private final AtomicReference> refreshTask = new AtomicReference<>(); + + private final AtomicBoolean refreshTaskSet = new AtomicBoolean(false); + + CredentialsProviderState(CredentialsProvider credentialsProvider) { + this.credentialsProvider = credentialsProvider; + } + + void add(Registration registration) { + this.registrations.put(registration.id, registration); + } + + void maybeSetRefreshTask(Supplier> scheduledFutureSupplier) { + if (refreshTaskSet.compareAndSet(false, true)) { + refreshTask.set(scheduledFutureSupplier.get()); + } + } + + void refresh() { + // FIXME check whether thread has been cancelled or not before refresh() and registratAction.call() + + // FIXME protect this call, or at least log some error + this.credentialsProvider.refresh(); + + Iterator iterator = registrations.values().iterator(); + while (iterator.hasNext()) { + Registration registration = iterator.next(); + // FIXME set a timeout on the call? (needs a separate thread) + try { + boolean refreshed = registration.refreshAction.call(); + if (!refreshed) { + LOGGER.debug("Registration did not refresh token"); + iterator.remove(); + } + registration.errorHistory.set(0); + } catch (Exception e) { + LOGGER.warn("Error while trying to refresh a connection token", e); + registration.errorHistory.incrementAndGet(); + if (registration.errorHistory.get() >= 5) { + registrations.remove(registration.id); + } + } + } + } + + void unregister(String registrationId) { + this.registrations.remove(registrationId); + } + } + + public static class DefaultCredentialsRefreshServiceBuilder { + + + private ScheduledExecutorService scheduler; + + private Function refreshDelayStrategy = fixedDelayBeforeExpirationRefreshDelayStrategy(Duration.ofSeconds(60)); + + private Function needRefreshStrategy = fixedTimeNeedRefreshStrategy(Duration.ofSeconds(60)); + + public DefaultCredentialsRefreshServiceBuilder scheduler(ScheduledThreadPoolExecutor scheduler) { + this.scheduler = scheduler; + return this; + } + + public DefaultCredentialsRefreshServiceBuilder refreshDelayStrategy(Function refreshDelayStrategy) { + this.refreshDelayStrategy = refreshDelayStrategy; + return this; + } + + public DefaultCredentialsRefreshServiceBuilder needRefreshStrategy(Function needRefreshStrategy) { + this.needRefreshStrategy = needRefreshStrategy; + return this; + } + + public DefaultCredentialsRefreshService build() { + return new DefaultCredentialsRefreshService(scheduler, refreshDelayStrategy, needRefreshStrategy); + } + + } + +} diff --git a/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java new file mode 100644 index 0000000000..ca3fb5c8a3 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java @@ -0,0 +1,233 @@ +// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + + +public class OAuth2ClientCredentialsGrantCredentialsProvider implements CredentialsProvider { + + private static final Logger LOGGER = LoggerFactory.getLogger(OAuth2ClientCredentialsGrantCredentialsProvider.class); + + private static final String UTF_8_CHARSET = "UTF-8"; + private final String serverUri; // should be renamed to tokenEndpointUri? + private final String clientId; + private final String clientSecret; + private final String grantType; + // UAA specific, to distinguish between different users + private final String username, password; + + private final ObjectMapper objectMapper = new ObjectMapper(); + + private final String id; + + private final AtomicReference token = new AtomicReference<>(); + + private final Lock refreshLock = new ReentrantLock(); + private final AtomicReference latch = new AtomicReference<>(); + private AtomicBoolean refreshInProcess = new AtomicBoolean(false); + + public OAuth2ClientCredentialsGrantCredentialsProvider(String serverUri, String clientId, String clientSecret, String grantType, String username, String password) { + this.serverUri = serverUri; + this.clientId = clientId; + this.clientSecret = clientSecret; + this.grantType = grantType; + this.username = username; + this.password = password; + this.id = UUID.randomUUID().toString(); + } + + private static StringBuilder encode(StringBuilder builder, String name, String value) throws UnsupportedEncodingException { + if (value != null) { + if (builder.length() > 0) { + builder.append("&"); + } + builder.append(URLEncoder.encode(name, UTF_8_CHARSET)) + .append("=") + .append(URLEncoder.encode(value, UTF_8_CHARSET)); + } + return builder; + } + + private static String basicAuthentication(String username, String password) { + String credentials = username + ":" + password; + byte[] credentialsAsBytes = credentials.getBytes(StandardCharsets.ISO_8859_1); + byte[] encodedBytes = Base64.getEncoder().encode(credentialsAsBytes); + String encodedCredentials = new String(encodedBytes, StandardCharsets.ISO_8859_1); + return "Basic " + encodedCredentials; + } + + @Override + public String getUsername() { + return ""; + } + + @Override + public String getPassword() { + if (token.get() == null) { + refresh(); + } + return token.get().getAccess(); + } + + @Override + public Date getExpiration() { + if (token.get() == null) { + refresh(); + } + return token.get().getExpiration(); + } + + protected Token parseToken(String response) { + try { + Map map = objectMapper.readValue(response, Map.class); + int expiresIn = ((Number) map.get("expires_in")).intValue(); + Calendar calendar = Calendar.getInstance(); + calendar.add(Calendar.SECOND, expiresIn); + return new Token(map.get("access_token").toString(), calendar.getTime()); + } catch (IOException e) { + throw new OAuthTokenManagementException("Error while parsing OAuth 2 token", e); + } + } + + @Override + public void refresh() { + // refresh should happen at once. Other calls wait for the refresh to finish and move on. + if (refreshLock.tryLock()) { + LOGGER.debug("Refreshing token"); + try { + latch.set(new CountDownLatch(1)); + refreshInProcess.set(true); + token.set(retrieveToken()); + LOGGER.debug("Token refreshed"); + } finally { + latch.get().countDown(); + refreshInProcess.set(false); + refreshLock.unlock(); + } + } else { + try { + LOGGER.debug("Waiting for token refresh to be finished"); + while (!refreshInProcess.get()) { + Thread.sleep(10); + } + latch.get().await(); + LOGGER.debug("Done waiting for token refresh"); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + } + + protected Token retrieveToken() { + // FIXME handle TLS specific settings + try { + StringBuilder urlParameters = new StringBuilder(); + encode(urlParameters, "grant_type", grantType); + encode(urlParameters, "username", username); + encode(urlParameters, "password", password); + byte[] postData = urlParameters.toString().getBytes(StandardCharsets.UTF_8); + int postDataLength = postData.length; + URL url = new URL(serverUri); + // FIXME close connection? + // FIXME set timeout on request + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setDoOutput(true); + conn.setInstanceFollowRedirects(false); + conn.setRequestMethod("POST"); + conn.setRequestProperty("authorization", basicAuthentication(clientId, clientSecret)); + conn.setRequestProperty("content-type", "application/x-www-form-urlencoded"); + conn.setRequestProperty("charset", UTF_8_CHARSET); + conn.setRequestProperty("accept", "application/json"); + conn.setRequestProperty("content-length", Integer.toString(postDataLength)); + conn.setUseCaches(false); + try (DataOutputStream wr = new DataOutputStream(conn.getOutputStream())) { + wr.write(postData); + } + int responseCode = conn.getResponseCode(); + if (responseCode != 200) { + throw new OAuthTokenManagementException( + "HTTP request for token retrieval did not " + + "return 200 response code: " + responseCode + ); + } + + StringBuffer content = new StringBuffer(); + try (BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()))) { + String inputLine; + while ((inputLine = in.readLine()) != null) { + content.append(inputLine); + } + } + + // FIXME check result is json + + + return parseToken(content.toString()); + } catch (IOException e) { + throw new OAuthTokenManagementException("Error while retrieving OAuth 2 token", e); + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + OAuth2ClientCredentialsGrantCredentialsProvider that = (OAuth2ClientCredentialsGrantCredentialsProvider) o; + + return id.equals(that.id); + } + + @Override + public int hashCode() { + return id.hashCode(); + } + + public static class Token { + + private final String access; + + private final Date expiration; + + public Token(String access, Date expiration) { + this.access = access; + this.expiration = expiration; + } + + public Date getExpiration() { + return expiration; + } + + public String getAccess() { + return access; + } + } +} diff --git a/src/main/java/com/rabbitmq/client/impl/OAuthTokenManagementException.java b/src/main/java/com/rabbitmq/client/impl/OAuthTokenManagementException.java new file mode 100644 index 0000000000..62db5e07a5 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/OAuthTokenManagementException.java @@ -0,0 +1,27 @@ +// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl; + +public class OAuthTokenManagementException extends RuntimeException { + + public OAuthTokenManagementException(String message, Throwable cause) { + super(message, cause); + } + + public OAuthTokenManagementException(String message) { + super(message); + } +} diff --git a/src/test/java/com/rabbitmq/client/RefreshCredentialsTest.java b/src/test/java/com/rabbitmq/client/RefreshCredentialsTest.java new file mode 100644 index 0000000000..41fe348e28 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/RefreshCredentialsTest.java @@ -0,0 +1,81 @@ +// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client; + +import com.rabbitmq.client.impl.DefaultCredentialsRefreshService; +import com.rabbitmq.client.impl.OAuth2ClientCredentialsGrantCredentialsProvider; +import com.rabbitmq.client.test.TestUtils; +import org.junit.Before; +import org.junit.Test; + +import java.time.Duration; +import java.util.Calendar; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import static org.assertj.core.api.Assertions.assertThat; + +public class RefreshCredentialsTest { + + DefaultCredentialsRefreshService refreshService; + + @Before + public void tearDown() { + if (refreshService != null) { + refreshService.close(); + } + } + + @Test + public void connectionAndRefreshCredentials() throws Exception { + ConnectionFactory cf = TestUtils.connectionFactory(); + CountDownLatch latch = new CountDownLatch(5); + // OAuth server is actually not used in this test, default RabbitMQ authentication backend is + OAuth2ClientCredentialsGrantCredentialsProvider provider = new OAuth2ClientCredentialsGrantCredentialsProvider( + "http://localhost:8080/uaa/oauth/token/", + "rabbit_client", "rabbit_secret", + "password", // UAA-specific, standard is client_credentials + "rabbit_super", "rabbit_super" // UAA-specific, to distinguish between RabbitMQ users + ) { + @Override + protected Token retrieveToken() { + latch.countDown(); + Calendar calendar = Calendar.getInstance(); + calendar.add(Calendar.SECOND, 2); + return new Token("guest", calendar.getTime()); + } + + @Override + public String getUsername() { + return "guest"; + } + }; + cf.setCredentialsProvider(provider); + refreshService = new DefaultCredentialsRefreshService.DefaultCredentialsRefreshServiceBuilder() + .refreshDelayStrategy(DefaultCredentialsRefreshService.fixedDelayBeforeExpirationRefreshDelayStrategy(Duration.ofSeconds(1))) + .needRefreshStrategy(expiration -> false) + .build(); + cf.setCredentialsRefreshService(refreshService); + + try (Connection c = cf.newConnection()) { + Channel ch = c.createChannel(); + String queue = ch.queueDeclare().getQueue(); + TestUtils.sendAndConsumeMessage("", queue, queue, c); + assertThat(latch.await(10, TimeUnit.SECONDS)).isTrue(); + } + } + +} diff --git a/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java b/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java new file mode 100644 index 0000000000..66e59ba866 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java @@ -0,0 +1,181 @@ +// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl; + +import org.junit.After; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.stubbing.Answer; + +import java.time.Duration; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.IntStream; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.*; + +@RunWith(MockitoJUnitRunner.class) +public class DefaultCredentialsRefreshServiceTest { + + @Mock + Callable refreshAction; + + @Mock + CredentialsProvider credentialsProvider; + + DefaultCredentialsRefreshService refreshService; + + @After + public void tearDown() { + if (refreshService != null) { + refreshService.close(); + } + } + + @Test + public void scheduling() throws Exception { + refreshService = new DefaultCredentialsRefreshService.DefaultCredentialsRefreshServiceBuilder() + .refreshDelayStrategy(DefaultCredentialsRefreshService.fixedDelayBeforeExpirationRefreshDelayStrategy(Duration.ofSeconds(2))) + .build(); + + AtomicInteger passwordSequence = new AtomicInteger(0); + when(credentialsProvider.getPassword()).thenAnswer( + (Answer) invocation -> "password-" + passwordSequence.get()); + when(credentialsProvider.getExpiration()).thenAnswer((Answer) invocation -> { + Calendar calendar = Calendar.getInstance(); + calendar.add(Calendar.SECOND, 5); + return calendar.getTime(); + }); + doAnswer(invocation -> { + passwordSequence.incrementAndGet(); + return null; + }).when(credentialsProvider).refresh(); + + List passwords = new CopyOnWriteArrayList<>(); + CountDownLatch latch = new CountDownLatch(2 * 2); + refreshAction = () -> { + passwords.add(credentialsProvider.getPassword()); + latch.countDown(); + return true; + }; + refreshService.register(credentialsProvider, refreshAction); + refreshService.register(credentialsProvider, refreshAction); + assertThat(latch.await(10, TimeUnit.SECONDS)).isTrue(); + assertThat(passwords).hasSize(4).containsExactlyInAnyOrder("password-1", "password-2", "password-1", "password-2"); + + AtomicInteger passwordSequence2 = new AtomicInteger(0); + CredentialsProvider credentialsProvider2 = mock(CredentialsProvider.class); + when(credentialsProvider2.getPassword()).thenAnswer((Answer) invocation -> "password2-" + passwordSequence2.get()); + when(credentialsProvider2.getExpiration()).thenAnswer((Answer) invocation -> { + Calendar calendar = Calendar.getInstance(); + calendar.add(Calendar.SECOND, 4); + return calendar.getTime(); + }); + doAnswer(invocation -> { + passwordSequence2.incrementAndGet(); + return null; + }).when(credentialsProvider2).refresh(); + + + List passwords2 = new CopyOnWriteArrayList<>(); + CountDownLatch latch2 = new CountDownLatch(2 * 1); + refreshAction = () -> { + passwords2.add(credentialsProvider2.getPassword()); + latch2.countDown(); + return true; + }; + + refreshService.register(credentialsProvider2, refreshAction); + + assertThat(latch2.await(10, TimeUnit.SECONDS)).isTrue(); + assertThat(passwords2).hasSize(2).containsExactlyInAnyOrder( + "password2-1", "password2-2" + ); + assertThat(passwords).hasSizeGreaterThan(4); + + + } + + @Test + public void refreshActionIsCorrectlyRegisteredCalledAndCanceled() throws Exception { + DefaultCredentialsRefreshService.CredentialsProviderState state = new DefaultCredentialsRefreshService.CredentialsProviderState( + credentialsProvider + ); + when(refreshAction.call()).thenReturn(true); + state.add(new DefaultCredentialsRefreshService.Registration("1", refreshAction)); + + state.refresh(); + verify(credentialsProvider, times(1)).refresh(); + verify(refreshAction, times(1)).call(); + + state.refresh(); + verify(credentialsProvider, times(2)).refresh(); + verify(refreshAction, times(2)).call(); + + state.unregister("1"); + state.refresh(); + verify(credentialsProvider, times(3)).refresh(); + verify(refreshAction, times(2)).call(); + } + + @Test + public void refreshActionIsRemovedIfItReturnsFalse() throws Exception { + DefaultCredentialsRefreshService.CredentialsProviderState state = new DefaultCredentialsRefreshService.CredentialsProviderState( + credentialsProvider + ); + when(refreshAction.call()).thenReturn(false); + state.add(new DefaultCredentialsRefreshService.Registration("1", refreshAction)); + + state.refresh(); + verify(credentialsProvider, times(1)).refresh(); + verify(refreshAction, times(1)).call(); + + state.refresh(); + verify(credentialsProvider, times(2)).refresh(); + verify(refreshAction, times(1)).call(); + } + + @Test + public void refreshActionIsRemovedIfItErrorsTooMuch() throws Exception { + DefaultCredentialsRefreshService.CredentialsProviderState state = new DefaultCredentialsRefreshService.CredentialsProviderState( + credentialsProvider + ); + when(refreshAction.call()).thenThrow(RuntimeException.class); + state.add(new DefaultCredentialsRefreshService.Registration("1", refreshAction)); + + int callsCountBeforeCancellation = 5; + IntStream.range(0, callsCountBeforeCancellation).forEach(i -> { + state.refresh(); + }); + + verify(credentialsProvider, times(callsCountBeforeCancellation)).refresh(); + verify(refreshAction, times(callsCountBeforeCancellation)).call(); + + state.refresh(); + verify(credentialsProvider, times(callsCountBeforeCancellation + 1)).refresh(); + verify(refreshAction, times(callsCountBeforeCancellation)).call(); + } + +} diff --git a/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java b/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java new file mode 100644 index 0000000000..6e1908fee2 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java @@ -0,0 +1,190 @@ +// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl; + +import com.rabbitmq.client.test.TestUtils; +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.server.handler.AbstractHandler; +import org.eclipse.jetty.server.handler.ContextHandler; +import org.junit.After; +import org.junit.Test; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Calendar; +import java.util.Date; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.IntStream; + +import static org.assertj.core.api.Assertions.assertThat; + +public class OAuth2ClientCredentialsGrantCredentialsProviderTest { + + Server server; + + @After + public void tearDown() throws Exception { + if (server != null) { + server.stop(); + } + } + + @Test + public void getToken() throws Exception { + Server server = new Server(); + ServerConnector connector = new ServerConnector(server); + int port = TestUtils.randomNetworkPort(); + connector.setPort(port); + server.setConnectors(new Connector[]{connector}); + + AtomicReference httpMethod = new AtomicReference<>(); + AtomicReference contentType = new AtomicReference<>(); + AtomicReference authorization = new AtomicReference<>(); + AtomicReference accept = new AtomicReference<>(); + AtomicReference accessToken = new AtomicReference<>(); + + int expiresIn = 60; + + ContextHandler context = new ContextHandler(); + context.setContextPath("/uaa/oauth/token/"); + context.setHandler(new AbstractHandler() { + + @Override + public void handle(String s, Request request, HttpServletRequest httpServletRequest, HttpServletResponse response) + throws IOException { + + httpMethod.set(request.getMethod()); + contentType.set(request.getContentType()); + authorization.set(request.getHeader("authorization")); + accept.set(request.getHeader("accept")); + + accessToken.set(UUID.randomUUID().toString()); + String json = sampleJsonToken(accessToken.get(), expiresIn); + + response.setStatus(HttpServletResponse.SC_OK); + response.setContentLength(json.length()); + response.setContentType("application/json"); + + response.getWriter().print(json); + + request.setHandled(true); + + } + }); + + server.setHandler(context); + + server.setStopTimeout(1000); + server.start(); + + OAuth2ClientCredentialsGrantCredentialsProvider provider = new OAuth2ClientCredentialsGrantCredentialsProvider( + "http://localhost:" + port + "/uaa/oauth/token/", + "rabbit_client", "rabbit_secret", + "password", // UAA-specific, standard is client_credentials + "rabbit_super", "rabbit_super" // UAA-specific, to distinguish between RabbitMQ users + ); + + String password = provider.getPassword(); + + assertThat(password).isEqualTo(accessToken.get()); + assertThat(provider.getExpiration()).isBetween(offsetNow(expiresIn - 10), offsetNow(expiresIn + 10)); + + assertThat(httpMethod).hasValue("POST"); + assertThat(contentType).hasValue("application/x-www-form-urlencoded"); + assertThat(authorization).hasValue("Basic cmFiYml0X2NsaWVudDpyYWJiaXRfc2VjcmV0"); + assertThat(accept).hasValue("application/json"); + } + + @Test + public void refresh() throws Exception { + AtomicInteger retrieveTokenCallCount = new AtomicInteger(0); + OAuth2ClientCredentialsGrantCredentialsProvider provider = new OAuth2ClientCredentialsGrantCredentialsProvider( + "http://localhost:8080/uaa/oauth/token/", + "rabbit_client", "rabbit_secret", + "password", // UAA-specific, standard is client_credentials + "rabbit_super", "rabbit_super" // UAA-specific, to distinguish between RabbitMQ users + ) { + @Override + protected Token retrieveToken() { + retrieveTokenCallCount.incrementAndGet(); + try { + Thread.sleep(2000L); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + return new Token(UUID.randomUUID().toString(), new Date()); + } + }; + + Set passwords = ConcurrentHashMap.newKeySet(); + CountDownLatch latch = new CountDownLatch(5); + IntStream.range(0, 5).forEach(i -> new Thread(() -> { + passwords.add(provider.getPassword()); + latch.countDown(); + }).start()); + + assertThat(latch.await(10, TimeUnit.SECONDS)).isTrue(); + + assertThat(retrieveTokenCallCount).hasValue(1); + assertThat(passwords).hasSize(1); + } + + @Test + public void parseToken() { + OAuth2ClientCredentialsGrantCredentialsProvider provider = new OAuth2ClientCredentialsGrantCredentialsProvider( + "http://localhost:8080/uaa/oauth/token", + "rabbit_client", "rabbit_secret", + "password", // UAA-specific, standard is client_credentials + "rabbit_super", "rabbit_super" // UAA-specific, to distinguish between RabbitMQ users + ); + + String accessToken = "18c1b1dfdda04382a8bcc14d077b71dd"; + int expiresIn = 43199; + String response = sampleJsonToken(accessToken, expiresIn); + + OAuth2ClientCredentialsGrantCredentialsProvider.Token token = provider.parseToken(response); + assertThat(token.getAccess()).isEqualTo("18c1b1dfdda04382a8bcc14d077b71dd"); + assertThat(token.getExpiration()).isBetween(offsetNow(expiresIn - 10), offsetNow(expiresIn + 1)); + } + + Date offsetNow(int seconds) { + Calendar calendar = Calendar.getInstance(); + calendar.add(Calendar.SECOND, seconds); + return calendar.getTime(); + } + + String sampleJsonToken(String accessToken, int expiresIn) { + String json = "{\n" + + " \"access_token\" : \"{accessToken}\",\n" + + " \"token_type\" : \"bearer\",\n" + + " \"expires_in\" : {expiresIn},\n" + + " \"scope\" : \"clients.read emails.write scim.userids password.write idps.write notifications.write oauth.login scim.write critical_notifications.write\",\n" + + " \"jti\" : \"18c1b1dfdda04382a8bcc14d077b71dd\"\n" + + "}"; + return json.replace("{accessToken}", accessToken).replace("{expiresIn}", expiresIn + ""); + } + +} diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index d5fb3251ab..0d4db0f8b2 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -17,6 +17,10 @@ package com.rabbitmq.client.test; import com.rabbitmq.client.JacksonJsonRpcTest; +import com.rabbitmq.client.RefreshCredentialsTest; +import com.rabbitmq.client.impl.DefaultCredentialsRefreshServiceTest; +import com.rabbitmq.client.impl.OAuth2ClientCredentialsGrantCredentialsProvider; +import com.rabbitmq.client.impl.OAuth2ClientCredentialsGrantCredentialsProviderTest; import com.rabbitmq.utility.IntAllocatorTests; import org.junit.runner.RunWith; import org.junit.runners.Suite; @@ -68,7 +72,10 @@ RpcTopologyRecordingTest.class, ConnectionTest.class, TlsUtilsTest.class, - ChannelNTest.class + ChannelNTest.class, + DefaultCredentialsRefreshServiceTest.class, + OAuth2ClientCredentialsGrantCredentialsProviderTest.class, + RefreshCredentialsTest.class }) public class ClientTests { diff --git a/src/test/java/com/rabbitmq/client/test/TestUtils.java b/src/test/java/com/rabbitmq/client/test/TestUtils.java index b385c73fde..21b1f542ad 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtils.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtils.java @@ -32,6 +32,7 @@ import javax.net.ssl.SSLContext; import java.io.IOException; +import java.net.ServerSocket; import java.security.NoSuchAlgorithmException; import java.util.Arrays; import java.util.Collection; @@ -240,4 +241,12 @@ static int versionCompare(String str1, String str2) { // e.g. "1.2.3" = "1.2.3" or "1.2.3" < "1.2.3.4" return Integer.signum(vals1.length - vals2.length); } + + public static int randomNetworkPort() throws IOException { + ServerSocket socket = new ServerSocket(); + socket.bind(null); + int port = socket.getLocalPort(); + socket.close(); + return port; + } } From 5752e55404c771aa73f12df9b440fdb38e78ce11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 24 Jun 2019 14:16:26 +0200 Subject: [PATCH 1120/2114] Create RefreshProtectedCredentialsProvider class To protect from several actual token retrievals to happen at the same time. This class is used in the OAuth 2 client credentials grant provider. Add also a builder to make the OAuth 2 provider easier to configure, add TLS settings and a test. --- pom.xml | 7 + ...ntCredentialsGrantCredentialsProvider.java | 186 +++++++++++------- .../RefreshProtectedCredentialsProvider.java | 113 +++++++++++ .../DefaultCredentialsRefreshServiceTest.java | 4 +- ...edentialsGrantCredentialsProviderTest.java | 176 ++++++++++++----- ...freshProtectedCredentialsProviderTest.java | 90 +++++++++ .../com/rabbitmq/client/test/ClientTests.java | 4 +- .../{ => test}/RefreshCredentialsTest.java | 45 +++-- 8 files changed, 493 insertions(+), 132 deletions(-) create mode 100644 src/main/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProvider.java create mode 100644 src/test/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProviderTest.java rename src/test/java/com/rabbitmq/client/{ => test}/RefreshCredentialsTest.java (69%) diff --git a/pom.xml b/pom.xml index 628e74de92..714c3e5672 100644 --- a/pom.xml +++ b/pom.xml @@ -64,6 +64,7 @@ 2.25.1 3.12.2 9.4.19.v20190610 + 1.61 3.0.1 2.5.3 @@ -751,6 +752,12 @@ ${jetty.version} test + + org.bouncycastle + bcpkix-jdk15on + ${bouncycastle.version} + test + diff --git a/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java index ca3fb5c8a3..0338fcedd6 100644 --- a/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java @@ -16,51 +16,60 @@ package com.rabbitmq.client.impl; import com.fasterxml.jackson.databind.ObjectMapper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLSocketFactory; import java.io.*; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.util.*; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - -public class OAuth2ClientCredentialsGrantCredentialsProvider implements CredentialsProvider { - - private static final Logger LOGGER = LoggerFactory.getLogger(OAuth2ClientCredentialsGrantCredentialsProvider.class); +/** + * + * @see RefreshProtectedCredentialsProvider + */ +public class OAuth2ClientCredentialsGrantCredentialsProvider extends RefreshProtectedCredentialsProvider { private static final String UTF_8_CHARSET = "UTF-8"; - private final String serverUri; // should be renamed to tokenEndpointUri? + private final String tokenEndpointUri; private final String clientId; private final String clientSecret; private final String grantType; - // UAA specific, to distinguish between different users - private final String username, password; + + private final Map parameters; private final ObjectMapper objectMapper = new ObjectMapper(); private final String id; - private final AtomicReference token = new AtomicReference<>(); + private final HostnameVerifier hostnameVerifier; + private final SSLSocketFactory sslSocketFactory; + + public OAuth2ClientCredentialsGrantCredentialsProvider(String tokenEndpointUri, String clientId, String clientSecret, String grantType) { + this(tokenEndpointUri, clientId, clientSecret, grantType, new HashMap<>()); + } + + public OAuth2ClientCredentialsGrantCredentialsProvider(String tokenEndpointUri, String clientId, String clientSecret, String grantType, + HostnameVerifier hostnameVerifier, SSLSocketFactory sslSocketFactory) { + this(tokenEndpointUri, clientId, clientSecret, grantType, new HashMap<>(), hostnameVerifier, sslSocketFactory); + } - private final Lock refreshLock = new ReentrantLock(); - private final AtomicReference latch = new AtomicReference<>(); - private AtomicBoolean refreshInProcess = new AtomicBoolean(false); + public OAuth2ClientCredentialsGrantCredentialsProvider(String tokenEndpointUri, String clientId, String clientSecret, String grantType, Map parameters) { + this(tokenEndpointUri, clientId, clientSecret, grantType, parameters, null, null); + } - public OAuth2ClientCredentialsGrantCredentialsProvider(String serverUri, String clientId, String clientSecret, String grantType, String username, String password) { - this.serverUri = serverUri; + public OAuth2ClientCredentialsGrantCredentialsProvider(String tokenEndpointUri, String clientId, String clientSecret, String grantType, Map parameters, + HostnameVerifier hostnameVerifier, SSLSocketFactory sslSocketFactory) { + this.tokenEndpointUri = tokenEndpointUri; this.clientId = clientId; this.clientSecret = clientSecret; this.grantType = grantType; - this.username = username; - this.password = password; + this.parameters = Collections.unmodifiableMap(new HashMap<>(parameters)); + this.hostnameVerifier = hostnameVerifier; + this.sslSocketFactory = sslSocketFactory; this.id = UUID.randomUUID().toString(); } @@ -90,19 +99,8 @@ public String getUsername() { } @Override - public String getPassword() { - if (token.get() == null) { - refresh(); - } - return token.get().getAccess(); - } - - @Override - public Date getExpiration() { - if (token.get() == null) { - refresh(); - } - return token.get().getExpiration(); + protected String usernameFromToken(Token token) { + return ""; } protected Token parseToken(String response) { @@ -118,47 +116,21 @@ protected Token parseToken(String response) { } @Override - public void refresh() { - // refresh should happen at once. Other calls wait for the refresh to finish and move on. - if (refreshLock.tryLock()) { - LOGGER.debug("Refreshing token"); - try { - latch.set(new CountDownLatch(1)); - refreshInProcess.set(true); - token.set(retrieveToken()); - LOGGER.debug("Token refreshed"); - } finally { - latch.get().countDown(); - refreshInProcess.set(false); - refreshLock.unlock(); - } - } else { - try { - LOGGER.debug("Waiting for token refresh to be finished"); - while (!refreshInProcess.get()) { - Thread.sleep(10); - } - latch.get().await(); - LOGGER.debug("Done waiting for token refresh"); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - } - protected Token retrieveToken() { - // FIXME handle TLS specific settings try { StringBuilder urlParameters = new StringBuilder(); encode(urlParameters, "grant_type", grantType); - encode(urlParameters, "username", username); - encode(urlParameters, "password", password); + for (Map.Entry parameter : parameters.entrySet()) { + encode(urlParameters, parameter.getKey(), parameter.getValue()); + } byte[] postData = urlParameters.toString().getBytes(StandardCharsets.UTF_8); int postDataLength = postData.length; - URL url = new URL(serverUri); + URL url = new URL(tokenEndpointUri); + // FIXME close connection? // FIXME set timeout on request HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setDoOutput(true); conn.setInstanceFollowRedirects(false); conn.setRequestMethod("POST"); @@ -168,6 +140,9 @@ protected Token retrieveToken() { conn.setRequestProperty("accept", "application/json"); conn.setRequestProperty("content-length", Integer.toString(postDataLength)); conn.setUseCaches(false); + + configureHttpConnection(conn); + try (DataOutputStream wr = new DataOutputStream(conn.getOutputStream())) { wr.write(postData); } @@ -196,6 +171,28 @@ protected Token retrieveToken() { } } + @Override + protected String passwordFromToken(Token token) { + return token.getAccess(); + } + + @Override + protected Date expirationFromToken(Token token) { + return token.getExpiration(); + } + + protected void configureHttpConnection(HttpURLConnection connection) { + if (connection instanceof HttpsURLConnection) { + HttpsURLConnection securedConnection = (HttpsURLConnection) connection; + if (this.hostnameVerifier != null) { + securedConnection.setHostnameVerifier(this.hostnameVerifier); + } + if (this.sslSocketFactory != null) { + securedConnection.setSSLSocketFactory(this.sslSocketFactory); + } + } + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -230,4 +227,59 @@ public String getAccess() { return access; } } + + public static class OAuth2ClientCredentialsGrantCredentialsProviderBuilder { + + private final Map parameters = new HashMap<>(); + private String tokenEndpointUri; + private String clientId; + private String clientSecret; + private String grantType = "client_credentials"; + private HostnameVerifier hostnameVerifier; + + private SSLSocketFactory sslSocketFactory; + + public OAuth2ClientCredentialsGrantCredentialsProviderBuilder tokenEndpointUri(String tokenEndpointUri) { + this.tokenEndpointUri = tokenEndpointUri; + return this; + } + + public OAuth2ClientCredentialsGrantCredentialsProviderBuilder clientId(String clientId) { + this.clientId = clientId; + return this; + } + + public OAuth2ClientCredentialsGrantCredentialsProviderBuilder clientSecret(String clientSecret) { + this.clientSecret = clientSecret; + return this; + } + + public OAuth2ClientCredentialsGrantCredentialsProviderBuilder grantType(String grantType) { + this.grantType = grantType; + return this; + } + + public OAuth2ClientCredentialsGrantCredentialsProviderBuilder parameter(String name, String value) { + this.parameters.put(name, value); + return this; + } + + public OAuth2ClientCredentialsGrantCredentialsProviderBuilder setHostnameVerifier(HostnameVerifier hostnameVerifier) { + this.hostnameVerifier = hostnameVerifier; + return this; + } + + public OAuth2ClientCredentialsGrantCredentialsProviderBuilder setSslSocketFactory(SSLSocketFactory sslSocketFactory) { + this.sslSocketFactory = sslSocketFactory; + return this; + } + + public OAuth2ClientCredentialsGrantCredentialsProvider build() { + return new OAuth2ClientCredentialsGrantCredentialsProvider( + tokenEndpointUri, clientId, clientSecret, grantType, parameters, + hostnameVerifier, sslSocketFactory + ); + } + + } } diff --git a/src/main/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProvider.java new file mode 100644 index 0000000000..7bca427205 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProvider.java @@ -0,0 +1,113 @@ +// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Date; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +/** + * An abstract {@link CredentialsProvider} that does not let token refresh happen concurrently. + *

+ * A token is usually long-lived (several minutes or more), can be re-used inside the same application, + * and refreshing it is a costly operation. This base class lets a first call to {@link #refresh()} + * pass and block concurrent calls until the first call is over. Concurrent calls are then unblocked and + * can benefit from the refresh. This avoids unnecessary refresh operations to happen if a token + * is already being renewed. + *

+ * Subclasses need to provide the actual token retrieval (whether is a first retrieval or a renewal is + * a implementation detail) and how to extract information (username, password, expiration date) from the retrieved + * token. + * + * @param the type of token (usually specified by the subclass) + */ +public abstract class RefreshProtectedCredentialsProvider implements CredentialsProvider { + + private static final Logger LOGGER = LoggerFactory.getLogger(RefreshProtectedCredentialsProvider.class); + + private final AtomicReference token = new AtomicReference<>(); + + private final Lock refreshLock = new ReentrantLock(); + private final AtomicReference latch = new AtomicReference<>(); + private AtomicBoolean refreshInProcess = new AtomicBoolean(false); + + @Override + public String getUsername() { + if (token.get() == null) { + refresh(); + } + return usernameFromToken(token.get()); + } + + @Override + public String getPassword() { + if (token.get() == null) { + refresh(); + } + return passwordFromToken(token.get()); + } + + @Override + public Date getExpiration() { + if (token.get() == null) { + refresh(); + } + return expirationFromToken(token.get()); + } + + @Override + public void refresh() { + // refresh should happen at once. Other calls wait for the refresh to finish and move on. + if (refreshLock.tryLock()) { + LOGGER.debug("Refreshing token"); + try { + latch.set(new CountDownLatch(1)); + refreshInProcess.set(true); + token.set(retrieveToken()); + LOGGER.debug("Token refreshed"); + } finally { + latch.get().countDown(); + refreshInProcess.set(false); + refreshLock.unlock(); + } + } else { + try { + LOGGER.debug("Waiting for token refresh to be finished"); + while (!refreshInProcess.get()) { + Thread.sleep(10); + } + latch.get().await(); + LOGGER.debug("Done waiting for token refresh"); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + } + + protected abstract T retrieveToken(); + + protected abstract String usernameFromToken(T token); + + protected abstract String passwordFromToken(T token); + + protected abstract Date expirationFromToken(T token); +} diff --git a/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java b/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java index 66e59ba866..56e5bd9a89 100644 --- a/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java +++ b/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java @@ -166,9 +166,7 @@ public void refreshActionIsRemovedIfItErrorsTooMuch() throws Exception { state.add(new DefaultCredentialsRefreshService.Registration("1", refreshAction)); int callsCountBeforeCancellation = 5; - IntStream.range(0, callsCountBeforeCancellation).forEach(i -> { - state.refresh(); - }); + IntStream.range(0, callsCountBeforeCancellation).forEach(i -> state.refresh()); verify(credentialsProvider, times(callsCountBeforeCancellation)).refresh(); verify(refreshAction, times(callsCountBeforeCancellation)).call(); diff --git a/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java b/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java index 6e1908fee2..662b24235c 100644 --- a/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java +++ b/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java @@ -16,28 +16,39 @@ package com.rabbitmq.client.impl; import com.rabbitmq.client.test.TestUtils; -import org.eclipse.jetty.server.Connector; -import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; +import org.bouncycastle.asn1.x500.X500NameBuilder; +import org.bouncycastle.asn1.x500.style.BCStyle; +import org.bouncycastle.cert.X509CertificateHolder; +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; +import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder; +import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; +import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.server.*; import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.server.handler.ContextHandler; +import org.eclipse.jetty.util.ssl.SslContextFactory; import org.junit.After; import org.junit.Test; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManagerFactory; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.KeyStore; +import java.security.SecureRandom; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.Calendar; import java.util.Date; -import java.util.Set; +import java.util.Map; import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; -import java.util.stream.IntStream; import static org.assertj.core.api.Assertions.assertThat; @@ -65,23 +76,26 @@ public void getToken() throws Exception { AtomicReference authorization = new AtomicReference<>(); AtomicReference accept = new AtomicReference<>(); AtomicReference accessToken = new AtomicReference<>(); + AtomicReference> httpParameters = new AtomicReference<>(); int expiresIn = 60; ContextHandler context = new ContextHandler(); - context.setContextPath("/uaa/oauth/token/"); + context.setContextPath("/uaa/oauth/token"); context.setHandler(new AbstractHandler() { @Override public void handle(String s, Request request, HttpServletRequest httpServletRequest, HttpServletResponse response) throws IOException { - httpMethod.set(request.getMethod()); contentType.set(request.getContentType()); authorization.set(request.getHeader("authorization")); accept.set(request.getHeader("accept")); accessToken.set(UUID.randomUUID().toString()); + + httpParameters.set(request.getParameterMap()); + String json = sampleJsonToken(accessToken.get(), expiresIn); response.setStatus(HttpServletResponse.SC_OK); @@ -91,7 +105,6 @@ public void handle(String s, Request request, HttpServletRequest httpServletRequ response.getWriter().print(json); request.setHandled(true); - } }); @@ -100,12 +113,13 @@ public void handle(String s, Request request, HttpServletRequest httpServletRequ server.setStopTimeout(1000); server.start(); - OAuth2ClientCredentialsGrantCredentialsProvider provider = new OAuth2ClientCredentialsGrantCredentialsProvider( - "http://localhost:" + port + "/uaa/oauth/token/", - "rabbit_client", "rabbit_secret", - "password", // UAA-specific, standard is client_credentials - "rabbit_super", "rabbit_super" // UAA-specific, to distinguish between RabbitMQ users - ); + OAuth2ClientCredentialsGrantCredentialsProvider provider = new OAuth2ClientCredentialsGrantCredentialsProvider.OAuth2ClientCredentialsGrantCredentialsProviderBuilder() + .tokenEndpointUri("http://localhost:" + port + "/uaa/oauth/token/") + .clientId("rabbit_client").clientSecret("rabbit_secret") + .grantType("password") + .parameter("username", "rabbit_super") + .parameter("password", "rabbit_super") + .build(); String password = provider.getPassword(); @@ -116,49 +130,59 @@ public void handle(String s, Request request, HttpServletRequest httpServletRequ assertThat(contentType).hasValue("application/x-www-form-urlencoded"); assertThat(authorization).hasValue("Basic cmFiYml0X2NsaWVudDpyYWJiaXRfc2VjcmV0"); assertThat(accept).hasValue("application/json"); + Map parameters = httpParameters.get(); + assertThat(parameters).isNotNull().hasSize(3).containsKeys("grant_type", "username", "password") + .hasEntrySatisfying("grant_type", v -> assertThat(v).hasSize(1).contains("password")) + .hasEntrySatisfying("username", v -> assertThat(v).hasSize(1).contains("rabbit_super")) + .hasEntrySatisfying("password", v -> assertThat(v).hasSize(1).contains("rabbit_super")); } @Test - public void refresh() throws Exception { - AtomicInteger retrieveTokenCallCount = new AtomicInteger(0); - OAuth2ClientCredentialsGrantCredentialsProvider provider = new OAuth2ClientCredentialsGrantCredentialsProvider( - "http://localhost:8080/uaa/oauth/token/", - "rabbit_client", "rabbit_secret", - "password", // UAA-specific, standard is client_credentials - "rabbit_super", "rabbit_super" // UAA-specific, to distinguish between RabbitMQ users - ) { + public void tls() throws Exception { + int port = TestUtils.randomNetworkPort(); + + String accessToken = UUID.randomUUID().toString(); + int expiresIn = 60; + + AbstractHandler httpHandler = new AbstractHandler() { @Override - protected Token retrieveToken() { - retrieveTokenCallCount.incrementAndGet(); - try { - Thread.sleep(2000L); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - return new Token(UUID.randomUUID().toString(), new Date()); + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException { + String json = sampleJsonToken(accessToken, expiresIn); + + response.setStatus(HttpServletResponse.SC_OK); + response.setContentLength(json.length()); + response.setContentType("application/json"); + + response.getWriter().print(json); + + baseRequest.setHandled(true); } }; - Set passwords = ConcurrentHashMap.newKeySet(); - CountDownLatch latch = new CountDownLatch(5); - IntStream.range(0, 5).forEach(i -> new Thread(() -> { - passwords.add(provider.getPassword()); - latch.countDown(); - }).start()); + KeyStore keyStore = startHttpsServer(port, httpHandler); - assertThat(latch.await(10, TimeUnit.SECONDS)).isTrue(); + TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); + tmf.init(keyStore); + SSLContext sslContext = SSLContext.getInstance("TLSv1.2"); + sslContext.init(null, tmf.getTrustManagers(), null); - assertThat(retrieveTokenCallCount).hasValue(1); - assertThat(passwords).hasSize(1); + OAuth2ClientCredentialsGrantCredentialsProvider provider = new OAuth2ClientCredentialsGrantCredentialsProvider.OAuth2ClientCredentialsGrantCredentialsProviderBuilder() + .tokenEndpointUri("https://localhost:" + port + "/uaa/oauth/token/") + .clientId("rabbit_client").clientSecret("rabbit_secret") + .setSslSocketFactory(sslContext.getSocketFactory()) + .build(); + + String password = provider.getPassword(); + assertThat(password).isEqualTo(accessToken); + assertThat(provider.getExpiration()).isBetween(offsetNow(expiresIn - 10), offsetNow(expiresIn + 10)); } @Test public void parseToken() { OAuth2ClientCredentialsGrantCredentialsProvider provider = new OAuth2ClientCredentialsGrantCredentialsProvider( - "http://localhost:8080/uaa/oauth/token", + "http://localhost:8080/uaa/oauth/token/", "rabbit_client", "rabbit_secret", - "password", // UAA-specific, standard is client_credentials - "rabbit_super", "rabbit_super" // UAA-specific, to distinguish between RabbitMQ users + "client_credentials" ); String accessToken = "18c1b1dfdda04382a8bcc14d077b71dd"; @@ -187,4 +211,62 @@ String sampleJsonToken(String accessToken, int expiresIn) { return json.replace("{accessToken}", accessToken).replace("{expiresIn}", expiresIn + ""); } + KeyStore startHttpsServer(int port, Handler handler) throws Exception { + KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + String keyStorePassword = "password"; + keyStore.load(null, keyStorePassword.toCharArray()); + + KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); + kpg.initialize(2048); + KeyPair kp = kpg.generateKeyPair(); + + JcaX509v3CertificateBuilder certificateBuilder = new JcaX509v3CertificateBuilder( + new X500NameBuilder().addRDN(BCStyle.CN, "localhost").build(), + BigInteger.valueOf(new SecureRandom().nextInt()), + Date.from(Instant.now().minus(10, ChronoUnit.DAYS)), + Date.from(Instant.now().plus(10, ChronoUnit.DAYS)), + new X500NameBuilder().addRDN(BCStyle.CN, "localhost").build(), + kp.getPublic() + ); + + X509CertificateHolder certificateHolder = certificateBuilder.build(new JcaContentSignerBuilder("SHA256WithRSAEncryption") + .build(kp.getPrivate())); + + X509Certificate certificate = new JcaX509CertificateConverter().getCertificate(certificateHolder); + + keyStore.setKeyEntry("default", kp.getPrivate(), keyStorePassword.toCharArray(), new Certificate[]{certificate}); + + server = new Server(); + SslContextFactory sslContextFactory = new SslContextFactory.Server(); + sslContextFactory.setKeyStore(keyStore); + sslContextFactory.setKeyStorePassword(keyStorePassword); + + HttpConfiguration httpsConfiguration = new HttpConfiguration(); + httpsConfiguration.setSecureScheme("https"); + httpsConfiguration.setSecurePort(port); + httpsConfiguration.setOutputBufferSize(32768); + + SecureRequestCustomizer src = new SecureRequestCustomizer(); + src.setStsMaxAge(2000); + src.setStsIncludeSubDomains(true); + httpsConfiguration.addCustomizer(src); + + ServerConnector https = new ServerConnector(server, + new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()), + new HttpConnectionFactory(httpsConfiguration)); + https.setPort(port); + https.setIdleTimeout(500000); + + server.setConnectors(new Connector[]{https}); + + ContextHandler context = new ContextHandler(); + context.setContextPath("/uaa/oauth/token"); + context.setHandler(handler); + + server.setHandler(context); + + server.start(); + return keyStore; + } + } diff --git a/src/test/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProviderTest.java b/src/test/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProviderTest.java new file mode 100644 index 0000000000..5c15cd7400 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProviderTest.java @@ -0,0 +1,90 @@ +// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl; + +import org.junit.Test; + +import java.util.Date; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.IntStream; + +import static org.assertj.core.api.Assertions.assertThat; + +public class RefreshProtectedCredentialsProviderTest { + + @Test + public void refresh() throws Exception { + AtomicInteger retrieveTokenCallCount = new AtomicInteger(0); + + RefreshProtectedCredentialsProvider credentialsProvider = new RefreshProtectedCredentialsProvider() { + + @Override + protected TestToken retrieveToken() { + retrieveTokenCallCount.incrementAndGet(); + try { + Thread.sleep(2000L); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + return new TestToken(UUID.randomUUID().toString(), new Date()); + } + + @Override + protected String usernameFromToken(TestToken token) { + return ""; + } + + @Override + protected String passwordFromToken(TestToken token) { + return token.secret; + } + + @Override + protected Date expirationFromToken(TestToken token) { + return token.expiration; + } + }; + + Set passwords = ConcurrentHashMap.newKeySet(); + CountDownLatch latch = new CountDownLatch(5); + IntStream.range(0, 5).forEach(i -> new Thread(() -> { + passwords.add(credentialsProvider.getPassword()); + latch.countDown(); + }).start()); + + assertThat(latch.await(10, TimeUnit.SECONDS)).isTrue(); + + assertThat(retrieveTokenCallCount).hasValue(1); + assertThat(passwords).hasSize(1); + } + + private static class TestToken { + + final String secret; + final Date expiration; + + TestToken(String secret, Date expiration) { + this.secret = secret; + this.expiration = expiration; + } + } + +} diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index 0d4db0f8b2..40cf11d71b 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -17,10 +17,9 @@ package com.rabbitmq.client.test; import com.rabbitmq.client.JacksonJsonRpcTest; -import com.rabbitmq.client.RefreshCredentialsTest; import com.rabbitmq.client.impl.DefaultCredentialsRefreshServiceTest; -import com.rabbitmq.client.impl.OAuth2ClientCredentialsGrantCredentialsProvider; import com.rabbitmq.client.impl.OAuth2ClientCredentialsGrantCredentialsProviderTest; +import com.rabbitmq.client.impl.RefreshProtectedCredentialsProviderTest; import com.rabbitmq.utility.IntAllocatorTests; import org.junit.runner.RunWith; import org.junit.runners.Suite; @@ -73,6 +72,7 @@ ConnectionTest.class, TlsUtilsTest.class, ChannelNTest.class, + RefreshProtectedCredentialsProviderTest.class, DefaultCredentialsRefreshServiceTest.class, OAuth2ClientCredentialsGrantCredentialsProviderTest.class, RefreshCredentialsTest.class diff --git a/src/test/java/com/rabbitmq/client/RefreshCredentialsTest.java b/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java similarity index 69% rename from src/test/java/com/rabbitmq/client/RefreshCredentialsTest.java rename to src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java index 41fe348e28..fa455b7744 100644 --- a/src/test/java/com/rabbitmq/client/RefreshCredentialsTest.java +++ b/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java @@ -13,16 +13,19 @@ // If you have any questions regarding licensing, please contact us at // info@rabbitmq.com. -package com.rabbitmq.client; +package com.rabbitmq.client.test; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.impl.DefaultCredentialsRefreshService; -import com.rabbitmq.client.impl.OAuth2ClientCredentialsGrantCredentialsProvider; -import com.rabbitmq.client.test.TestUtils; +import com.rabbitmq.client.impl.RefreshProtectedCredentialsProvider; import org.junit.Before; import org.junit.Test; import java.time.Duration; import java.util.Calendar; +import java.util.Date; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -43,26 +46,31 @@ public void tearDown() { public void connectionAndRefreshCredentials() throws Exception { ConnectionFactory cf = TestUtils.connectionFactory(); CountDownLatch latch = new CountDownLatch(5); - // OAuth server is actually not used in this test, default RabbitMQ authentication backend is - OAuth2ClientCredentialsGrantCredentialsProvider provider = new OAuth2ClientCredentialsGrantCredentialsProvider( - "http://localhost:8080/uaa/oauth/token/", - "rabbit_client", "rabbit_secret", - "password", // UAA-specific, standard is client_credentials - "rabbit_super", "rabbit_super" // UAA-specific, to distinguish between RabbitMQ users - ) { + RefreshProtectedCredentialsProvider provider = new RefreshProtectedCredentialsProvider() { @Override - protected Token retrieveToken() { + protected TestToken retrieveToken() { latch.countDown(); Calendar calendar = Calendar.getInstance(); calendar.add(Calendar.SECOND, 2); - return new Token("guest", calendar.getTime()); + return new TestToken("guest", calendar.getTime()); } @Override - public String getUsername() { + protected String usernameFromToken(TestToken token) { return "guest"; } + + @Override + protected String passwordFromToken(TestToken token) { + return token.secret; + } + + @Override + protected Date expirationFromToken(TestToken token) { + return token.expiration; + } }; + cf.setCredentialsProvider(provider); refreshService = new DefaultCredentialsRefreshService.DefaultCredentialsRefreshServiceBuilder() .refreshDelayStrategy(DefaultCredentialsRefreshService.fixedDelayBeforeExpirationRefreshDelayStrategy(Duration.ofSeconds(1))) @@ -78,4 +86,15 @@ public String getUsername() { } } + private static class TestToken { + + final String secret; + final Date expiration; + + TestToken(String secret, Date expiration) { + this.secret = secret; + this.expiration = expiration; + } + } + } From 32a4daf3aba4821c94803611455e0f9cebaf5384 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 24 Jun 2019 15:53:03 +0200 Subject: [PATCH 1121/2114] Refine OAuth 2 client credentials provider Make it more configurable, set last critical parameters for HTTP request, document it. --- ...ntCredentialsGrantCredentialsProvider.java | 116 ++++++++++++++---- src/test/resources/logback-test.xml | 4 + 2 files changed, 93 insertions(+), 27 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java index 0338fcedd6..7e9efea3d1 100644 --- a/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java @@ -26,10 +26,31 @@ import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.util.*; +import java.util.function.Consumer; /** + * A {@link CredentialsProvider} that performs an + * OAuth 2 Client Credentials flow + * to retrieve a token. + *

+ * The provider has different parameters to set, e.g. the token endpoint URI of the OAuth server to + * request, the client ID, the client secret, the grant type, etc. The {@link OAuth2ClientCredentialsGrantCredentialsProviderBuilder} + * class is the preferred way to create an instance of the provider. + *

+ * The implementation uses the JDK {@link HttpURLConnection} API to request the OAuth server. This can + * be easily changed by overriding the {@link #retrieveToken()} method. + *

+ * This class expects a JSON document as a response and needs Jackson + * to deserialize the response into a {@link Token}. This can be changed by overriding the {@link #parseToken(String)} + * method. + *

+ * TLS is supported by providing a HTTPS URI and setting the {@link HostnameVerifier} and {@link SSLSocketFactory}. + *

+ * If more customization is needed, a {@link #connectionConfigurator} callback can be provided to configure + * the connection. * * @see RefreshProtectedCredentialsProvider + * @see CredentialsRefreshService */ public class OAuth2ClientCredentialsGrantCredentialsProvider extends RefreshProtectedCredentialsProvider { @@ -48,21 +69,34 @@ public class OAuth2ClientCredentialsGrantCredentialsProvider extends RefreshProt private final HostnameVerifier hostnameVerifier; private final SSLSocketFactory sslSocketFactory; + private final Consumer connectionConfigurator; + public OAuth2ClientCredentialsGrantCredentialsProvider(String tokenEndpointUri, String clientId, String clientSecret, String grantType) { this(tokenEndpointUri, clientId, clientSecret, grantType, new HashMap<>()); } + public OAuth2ClientCredentialsGrantCredentialsProvider(String tokenEndpointUri, String clientId, String clientSecret, String grantType, Map parameters) { + this(tokenEndpointUri, clientId, clientSecret, grantType, parameters, null, null, null); + } + + public OAuth2ClientCredentialsGrantCredentialsProvider(String tokenEndpointUri, String clientId, String clientSecret, String grantType, Map parameters, + Consumer connectionConfigurator) { + this(tokenEndpointUri, clientId, clientSecret, grantType, parameters, null, null, connectionConfigurator); + } + public OAuth2ClientCredentialsGrantCredentialsProvider(String tokenEndpointUri, String clientId, String clientSecret, String grantType, HostnameVerifier hostnameVerifier, SSLSocketFactory sslSocketFactory) { - this(tokenEndpointUri, clientId, clientSecret, grantType, new HashMap<>(), hostnameVerifier, sslSocketFactory); + this(tokenEndpointUri, clientId, clientSecret, grantType, new HashMap<>(), hostnameVerifier, sslSocketFactory, null); } - public OAuth2ClientCredentialsGrantCredentialsProvider(String tokenEndpointUri, String clientId, String clientSecret, String grantType, Map parameters) { - this(tokenEndpointUri, clientId, clientSecret, grantType, parameters, null, null); + public OAuth2ClientCredentialsGrantCredentialsProvider(String tokenEndpointUri, String clientId, String clientSecret, String grantType, Map parameters, + HostnameVerifier hostnameVerifier, SSLSocketFactory sslSocketFactory) { + this(tokenEndpointUri, clientId, clientSecret, grantType, parameters, hostnameVerifier, sslSocketFactory, null); } public OAuth2ClientCredentialsGrantCredentialsProvider(String tokenEndpointUri, String clientId, String clientSecret, String grantType, Map parameters, - HostnameVerifier hostnameVerifier, SSLSocketFactory sslSocketFactory) { + HostnameVerifier hostnameVerifier, SSLSocketFactory sslSocketFactory, + Consumer connectionConfigurator) { this.tokenEndpointUri = tokenEndpointUri; this.clientId = clientId; this.clientSecret = clientSecret; @@ -70,6 +104,8 @@ public OAuth2ClientCredentialsGrantCredentialsProvider(String tokenEndpointUri, this.parameters = Collections.unmodifiableMap(new HashMap<>(parameters)); this.hostnameVerifier = hostnameVerifier; this.sslSocketFactory = sslSocketFactory; + this.connectionConfigurator = connectionConfigurator == null ? c -> { + } : connectionConfigurator; this.id = UUID.randomUUID().toString(); } @@ -127,8 +163,6 @@ protected Token retrieveToken() { int postDataLength = postData.length; URL url = new URL(tokenEndpointUri); - // FIXME close connection? - // FIXME set timeout on request HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setDoOutput(true); @@ -140,37 +174,52 @@ protected Token retrieveToken() { conn.setRequestProperty("accept", "application/json"); conn.setRequestProperty("content-length", Integer.toString(postDataLength)); conn.setUseCaches(false); + conn.setConnectTimeout(60_000); + conn.setReadTimeout(60_000); - configureHttpConnection(conn); + configureConnection(conn); try (DataOutputStream wr = new DataOutputStream(conn.getOutputStream())) { wr.write(postData); } - int responseCode = conn.getResponseCode(); - if (responseCode != 200) { - throw new OAuthTokenManagementException( - "HTTP request for token retrieval did not " + - "return 200 response code: " + responseCode - ); - } - - StringBuffer content = new StringBuffer(); - try (BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()))) { - String inputLine; - while ((inputLine = in.readLine()) != null) { - content.append(inputLine); - } - } - - // FIXME check result is json + checkResponseCode(conn.getResponseCode()); + checkContentType(conn.getHeaderField("content-type")); - return parseToken(content.toString()); + return parseToken(extractResponseBody(conn.getInputStream())); } catch (IOException e) { throw new OAuthTokenManagementException("Error while retrieving OAuth 2 token", e); } } + protected void checkContentType(String headerField) throws OAuthTokenManagementException { + if (headerField == null || !headerField.toLowerCase().contains("json")) { + throw new OAuthTokenManagementException( + "HTTP request for token retrieval is not JSON: " + headerField + ); + } + } + + protected void checkResponseCode(int responseCode) throws OAuthTokenManagementException { + if (responseCode != 200) { + throw new OAuthTokenManagementException( + "HTTP request for token retrieval did not " + + "return 200 response code: " + responseCode + ); + } + } + + protected String extractResponseBody(InputStream inputStream) throws IOException { + StringBuffer content = new StringBuffer(); + try (BufferedReader in = new BufferedReader(new InputStreamReader(inputStream))) { + String inputLine; + while ((inputLine = in.readLine()) != null) { + content.append(inputLine); + } + } + return content.toString(); + } + @Override protected String passwordFromToken(Token token) { return token.getAccess(); @@ -181,7 +230,12 @@ protected Date expirationFromToken(Token token) { return token.getExpiration(); } - protected void configureHttpConnection(HttpURLConnection connection) { + protected void configureConnection(HttpURLConnection connection) { + this.connectionConfigurator.accept(connection); + this.configureConnectionForHttps(connection); + } + + protected void configureConnectionForHttps(HttpURLConnection connection) { if (connection instanceof HttpsURLConnection) { HttpsURLConnection securedConnection = (HttpsURLConnection) connection; if (this.hostnameVerifier != null) { @@ -239,6 +293,8 @@ public static class OAuth2ClientCredentialsGrantCredentialsProviderBuilder { private SSLSocketFactory sslSocketFactory; + private Consumer connectionConfigurator; + public OAuth2ClientCredentialsGrantCredentialsProviderBuilder tokenEndpointUri(String tokenEndpointUri) { this.tokenEndpointUri = tokenEndpointUri; return this; @@ -274,10 +330,16 @@ public OAuth2ClientCredentialsGrantCredentialsProviderBuilder setSslSocketFactor return this; } + public OAuth2ClientCredentialsGrantCredentialsProviderBuilder setConnectionConfigurator(Consumer connectionConfigurator) { + this.connectionConfigurator = connectionConfigurator; + return this; + } + public OAuth2ClientCredentialsGrantCredentialsProvider build() { return new OAuth2ClientCredentialsGrantCredentialsProvider( tokenEndpointUri, clientId, clientSecret, grantType, parameters, - hostnameVerifier, sslSocketFactory + hostnameVerifier, sslSocketFactory, + connectionConfigurator ); } diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml index 4bd2e37606..143b351b50 100644 --- a/src/test/resources/logback-test.xml +++ b/src/test/resources/logback-test.xml @@ -5,6 +5,10 @@ + + + + From 6277348afb6a23d9c0db1bdc0a26a6a8ee0eb77b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 24 Jun 2019 17:55:57 +0200 Subject: [PATCH 1122/2114] Use Duration to track token expiration Easier to work with than a Date. --- .../rabbitmq/client/impl/AMQConnection.java | 8 +-- .../client/impl/CredentialsProvider.java | 9 ++-- .../impl/CredentialsRefreshService.java | 6 +-- .../DefaultCredentialsRefreshService.java | 51 +++++++++---------- ...ntCredentialsGrantCredentialsProvider.java | 39 +++++++++----- .../RefreshProtectedCredentialsProvider.java | 12 ++--- .../DefaultCredentialsRefreshServiceTest.java | 14 +---- ...edentialsGrantCredentialsProviderTest.java | 14 ++--- ...freshProtectedCredentialsProviderTest.java | 12 ++--- .../client/test/RefreshCredentialsTest.java | 26 ++++++---- 10 files changed, 95 insertions(+), 96 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index 95d55c011f..5d834a052f 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2019 Pivotal Software, Inc. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 @@ -341,8 +341,8 @@ public void start() String username = credentialsProvider.getUsername(); String password = credentialsProvider.getPassword(); - if (credentialsProvider.getExpiration() != null) { - if (this.credentialsRefreshService.needRefresh(credentialsProvider.getExpiration())) { + if (credentialsProvider.getTimeBeforeExpiration() != null) { + if (this.credentialsRefreshService.needRefresh(credentialsProvider.getTimeBeforeExpiration())) { credentialsProvider.refresh(); username = credentialsProvider.getUsername(); password = credentialsProvider.getPassword(); @@ -423,7 +423,7 @@ public void start() throw AMQChannel.wrap(sse); } - if (this.credentialsProvider.getExpiration() != null) { + if (this.credentialsProvider.getTimeBeforeExpiration() != null) { String registrationId = this.credentialsRefreshService.register(credentialsProvider, () -> { // return false if connection is closed, so refresh service can get rid of this registration if (!isOpen()) { diff --git a/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java index a7db53f8c3..e4f6bda06a 100644 --- a/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java @@ -15,7 +15,7 @@ package com.rabbitmq.client.impl; -import java.util.Date; +import java.time.Duration; /** * Provider interface for establishing credentials for connecting to the broker. Especially useful @@ -42,16 +42,15 @@ public interface CredentialsProvider { String getPassword(); /** - * The expiration date of the credentials, if any. + * The time before the credentials expire, if they do expire. *

* If credentials do not expire, must return null. Default * behavior is to return null, assuming credentials never * expire. * - * @return credentials expiration date + * @return time before expiration */ - default Date getExpiration() { - // no expiration by default + default Duration getTimeBeforeExpiration() { return null; } diff --git a/src/main/java/com/rabbitmq/client/impl/CredentialsRefreshService.java b/src/main/java/com/rabbitmq/client/impl/CredentialsRefreshService.java index 536c0dc0e0..2e6065336e 100644 --- a/src/main/java/com/rabbitmq/client/impl/CredentialsRefreshService.java +++ b/src/main/java/com/rabbitmq/client/impl/CredentialsRefreshService.java @@ -15,7 +15,7 @@ package com.rabbitmq.client.impl; -import java.util.Date; +import java.time.Duration; import java.util.concurrent.Callable; /** @@ -65,9 +65,9 @@ public interface CredentialsRefreshService { /** * Provide a hint about whether credentials should be renewed. * - * @param expiration + * @param timeBeforeExpiration * @return true if credentials should be renewed, false otherwise */ - boolean needRefresh(Date expiration); + boolean needRefresh(Duration timeBeforeExpiration); } diff --git a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java index 091948bb82..ec083b5895 100644 --- a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java +++ b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java @@ -19,7 +19,6 @@ import org.slf4j.LoggerFactory; import java.time.Duration; -import java.util.Date; import java.util.Iterator; import java.util.Map; import java.util.UUID; @@ -35,7 +34,7 @@ *

* This implementation keeps track of entities (typically AMQP connections) that need * to renew credentials. Token renewal is scheduled based on token expiration, using - * a Function refreshDelayStrategy. Once credentials + * a Function refreshDelayStrategy. Once credentials * for a {@link CredentialsProvider} have been renewed, the callback registered * by each entity/connection is performed. This callback typically propagates * the new credentials in the entity state, e.g. sending the new password to the @@ -51,11 +50,11 @@ public class DefaultCredentialsRefreshService implements CredentialsRefreshServi private final boolean privateScheduler; - private final Function refreshDelayStrategy; + private final Function refreshDelayStrategy; - private final Function needRefreshStrategy; + private final Function needRefreshStrategy; - public DefaultCredentialsRefreshService(ScheduledExecutorService scheduler, Function refreshDelayStrategy, Function needRefreshStrategy) { + public DefaultCredentialsRefreshService(ScheduledExecutorService scheduler, Function refreshDelayStrategy, Function needRefreshStrategy) { this.refreshDelayStrategy = refreshDelayStrategy; this.needRefreshStrategy = needRefreshStrategy; if (scheduler == null) { @@ -76,7 +75,7 @@ public DefaultCredentialsRefreshService(ScheduledExecutorService scheduler, Func * @param duration * @return */ - public static Function fixedDelayBeforeExpirationRefreshDelayStrategy(Duration duration) { + public static Function fixedDelayBeforeExpirationRefreshDelayStrategy(Duration duration) { return new FixedDelayBeforeExpirationRefreshDelayStrategy(duration.toMillis()); } @@ -86,20 +85,21 @@ public static Function fixedDelayBeforeExpirationRefreshDelayStrateg * @param limitBeforeExpiration * @return */ - public static Function fixedTimeNeedRefreshStrategy(Duration limitBeforeExpiration) { + public static Function fixedTimeNeedRefreshStrategy(Duration limitBeforeExpiration) { return new FixedTimeNeedRefreshStrategy(limitBeforeExpiration.toMillis()); } // TODO add a delay refresh strategy that bases the time on a percentage of the TTL, use it as default with 80% TTL private static Runnable refresh(ScheduledExecutorService scheduler, CredentialsProviderState credentialsProviderState, - Function refreshDelayStrategy) { + Function refreshDelayStrategy) { return () -> { LOGGER.debug("Refreshing token"); credentialsProviderState.refresh(); - Date expirationAfterRefresh = credentialsProviderState.credentialsProvider.getExpiration(); - long newDelay = refreshDelayStrategy.apply(expirationAfterRefresh); + Duration timeBeforeExpiration = credentialsProviderState.credentialsProvider.getTimeBeforeExpiration(); + + long newDelay = refreshDelayStrategy.apply(timeBeforeExpiration); LOGGER.debug("Scheduling refresh in {} milliseconds", newDelay); @@ -122,8 +122,7 @@ public String register(CredentialsProvider credentialsProvider, Callable { - Date expiration = credentialsProvider.getExpiration(); - long delay = refreshDelayStrategy.apply(expiration); + long delay = refreshDelayStrategy.apply(credentialsProvider.getTimeBeforeExpiration()); LOGGER.debug("Scheduling refresh in {} milliseconds", delay); return scheduler.schedule(refresh(scheduler, credentialsProviderState, refreshDelayStrategy), delay, TimeUnit.MILLISECONDS); }); @@ -140,8 +139,8 @@ public void unregister(CredentialsProvider credentialsProvider, String registrat } @Override - public boolean needRefresh(Date expiration) { - return this.needRefreshStrategy.apply(expiration); + public boolean needRefresh(Duration timeBeforeExpiration) { + return this.needRefreshStrategy.apply(timeBeforeExpiration); } public void close() { @@ -150,7 +149,7 @@ public void close() { } } - private static class FixedTimeNeedRefreshStrategy implements Function { + private static class FixedTimeNeedRefreshStrategy implements Function { private final long limitBeforeExpiration; @@ -159,13 +158,12 @@ private FixedTimeNeedRefreshStrategy(long limitBeforeExpiration) { } @Override - public Boolean apply(Date expiration) { - long ttl = expiration.getTime() - new Date().getTime(); - return ttl <= limitBeforeExpiration; + public Boolean apply(Duration timeBeforeExpiration) { + return timeBeforeExpiration.toMillis() <= limitBeforeExpiration; } } - private static class FixedDelayBeforeExpirationRefreshDelayStrategy implements Function { + private static class FixedDelayBeforeExpirationRefreshDelayStrategy implements Function { private final long delay; @@ -174,11 +172,10 @@ private FixedDelayBeforeExpirationRefreshDelayStrategy(long delay) { } @Override - public Long apply(Date expiration) { - long ttl = expiration.getTime() - new Date().getTime(); - long refreshTimeBeforeExpiration = ttl - delay; + public Long apply(Duration timeBeforeExpiration) { + long refreshTimeBeforeExpiration = timeBeforeExpiration.toMillis() - delay; if (refreshTimeBeforeExpiration < 0) { - return ttl; + return timeBeforeExpiration.toMillis(); } else { return refreshTimeBeforeExpiration; } @@ -279,21 +276,21 @@ public static class DefaultCredentialsRefreshServiceBuilder { private ScheduledExecutorService scheduler; - private Function refreshDelayStrategy = fixedDelayBeforeExpirationRefreshDelayStrategy(Duration.ofSeconds(60)); + private Function refreshDelayStrategy = fixedDelayBeforeExpirationRefreshDelayStrategy(Duration.ofSeconds(60)); - private Function needRefreshStrategy = fixedTimeNeedRefreshStrategy(Duration.ofSeconds(60)); + private Function needRefreshStrategy = fixedTimeNeedRefreshStrategy(Duration.ofSeconds(60)); public DefaultCredentialsRefreshServiceBuilder scheduler(ScheduledThreadPoolExecutor scheduler) { this.scheduler = scheduler; return this; } - public DefaultCredentialsRefreshServiceBuilder refreshDelayStrategy(Function refreshDelayStrategy) { + public DefaultCredentialsRefreshServiceBuilder refreshDelayStrategy(Function refreshDelayStrategy) { this.refreshDelayStrategy = refreshDelayStrategy; return this; } - public DefaultCredentialsRefreshServiceBuilder needRefreshStrategy(Function needRefreshStrategy) { + public DefaultCredentialsRefreshServiceBuilder needRefreshStrategy(Function needRefreshStrategy) { this.needRefreshStrategy = needRefreshStrategy; return this; } diff --git a/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java index 7e9efea3d1..21d6961ac5 100644 --- a/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java @@ -25,6 +25,9 @@ import java.net.URL; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.*; import java.util.function.Consumer; @@ -143,9 +146,8 @@ protected Token parseToken(String response) { try { Map map = objectMapper.readValue(response, Map.class); int expiresIn = ((Number) map.get("expires_in")).intValue(); - Calendar calendar = Calendar.getInstance(); - calendar.add(Calendar.SECOND, expiresIn); - return new Token(map.get("access_token").toString(), calendar.getTime()); + Instant receivedAt = Instant.now(); + return new Token(map.get("access_token").toString(), expiresIn, receivedAt); } catch (IOException e) { throw new OAuthTokenManagementException("Error while parsing OAuth 2 token", e); } @@ -226,8 +228,8 @@ protected String passwordFromToken(Token token) { } @Override - protected Date expirationFromToken(Token token) { - return token.getExpiration(); + protected Duration timeBeforeExpiration(Token token) { + return token.getTimeBeforeExpiration(); } protected void configureConnection(HttpURLConnection connection) { @@ -266,20 +268,33 @@ public static class Token { private final String access; - private final Date expiration; + private final int expiresIn; - public Token(String access, Date expiration) { - this.access = access; - this.expiration = expiration; - } + private final Instant receivedAt; - public Date getExpiration() { - return expiration; + public Token(String access, int expiresIn, Instant receivedAt) { + this.access = access; + this.expiresIn = expiresIn; + this.receivedAt = receivedAt; } public String getAccess() { return access; } + + public int getExpiresIn() { + return expiresIn; + } + + public Instant getReceivedAt() { + return receivedAt; + } + + public Duration getTimeBeforeExpiration() { + Instant now = Instant.now(); + long age = receivedAt.until(now, ChronoUnit.SECONDS); + return Duration.ofSeconds(expiresIn - age); + } } public static class OAuth2ClientCredentialsGrantCredentialsProviderBuilder { diff --git a/src/main/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProvider.java index 7bca427205..21f6bc9780 100644 --- a/src/main/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProvider.java @@ -18,7 +18,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.Date; +import java.time.Duration; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; @@ -35,8 +35,8 @@ * is already being renewed. *

* Subclasses need to provide the actual token retrieval (whether is a first retrieval or a renewal is - * a implementation detail) and how to extract information (username, password, expiration date) from the retrieved - * token. + * a implementation detail) and how to extract information (username, password, time before expiration) + * from the retrieved token. * * @param the type of token (usually specified by the subclass) */ @@ -67,11 +67,11 @@ public String getPassword() { } @Override - public Date getExpiration() { + public Duration getTimeBeforeExpiration() { if (token.get() == null) { refresh(); } - return expirationFromToken(token.get()); + return timeBeforeExpiration(token.get()); } @Override @@ -109,5 +109,5 @@ public void refresh() { protected abstract String passwordFromToken(T token); - protected abstract Date expirationFromToken(T token); + protected abstract Duration timeBeforeExpiration(T token); } diff --git a/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java b/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java index 56e5bd9a89..576612db54 100644 --- a/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java +++ b/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java @@ -23,8 +23,6 @@ import org.mockito.stubbing.Answer; import java.time.Duration; -import java.util.Calendar; -import java.util.Date; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.CopyOnWriteArrayList; @@ -63,11 +61,7 @@ public void scheduling() throws Exception { AtomicInteger passwordSequence = new AtomicInteger(0); when(credentialsProvider.getPassword()).thenAnswer( (Answer) invocation -> "password-" + passwordSequence.get()); - when(credentialsProvider.getExpiration()).thenAnswer((Answer) invocation -> { - Calendar calendar = Calendar.getInstance(); - calendar.add(Calendar.SECOND, 5); - return calendar.getTime(); - }); + when(credentialsProvider.getTimeBeforeExpiration()).thenAnswer((Answer) invocation -> Duration.ofSeconds(5)); doAnswer(invocation -> { passwordSequence.incrementAndGet(); return null; @@ -88,11 +82,7 @@ public void scheduling() throws Exception { AtomicInteger passwordSequence2 = new AtomicInteger(0); CredentialsProvider credentialsProvider2 = mock(CredentialsProvider.class); when(credentialsProvider2.getPassword()).thenAnswer((Answer) invocation -> "password2-" + passwordSequence2.get()); - when(credentialsProvider2.getExpiration()).thenAnswer((Answer) invocation -> { - Calendar calendar = Calendar.getInstance(); - calendar.add(Calendar.SECOND, 4); - return calendar.getTime(); - }); + when(credentialsProvider2.getTimeBeforeExpiration()).thenAnswer((Answer) invocation -> Duration.ofSeconds(4)); doAnswer(invocation -> { passwordSequence2.incrementAndGet(); return null; diff --git a/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java b/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java index 662b24235c..2cd19ee828 100644 --- a/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java +++ b/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java @@ -42,9 +42,9 @@ import java.security.SecureRandom; import java.security.cert.Certificate; import java.security.cert.X509Certificate; +import java.time.Duration; import java.time.Instant; import java.time.temporal.ChronoUnit; -import java.util.Calendar; import java.util.Date; import java.util.Map; import java.util.UUID; @@ -124,7 +124,7 @@ public void handle(String s, Request request, HttpServletRequest httpServletRequ String password = provider.getPassword(); assertThat(password).isEqualTo(accessToken.get()); - assertThat(provider.getExpiration()).isBetween(offsetNow(expiresIn - 10), offsetNow(expiresIn + 10)); + assertThat(provider.getTimeBeforeExpiration()).isBetween(Duration.ofSeconds(expiresIn - 10), Duration.ofSeconds(expiresIn + 10)); assertThat(httpMethod).hasValue("POST"); assertThat(contentType).hasValue("application/x-www-form-urlencoded"); @@ -174,7 +174,7 @@ public void handle(String target, Request baseRequest, HttpServletRequest reques String password = provider.getPassword(); assertThat(password).isEqualTo(accessToken); - assertThat(provider.getExpiration()).isBetween(offsetNow(expiresIn - 10), offsetNow(expiresIn + 10)); + assertThat(provider.getTimeBeforeExpiration()).isBetween(Duration.ofSeconds(expiresIn - 10), Duration.ofSeconds(expiresIn + 10)); } @Test @@ -191,13 +191,7 @@ public void parseToken() { OAuth2ClientCredentialsGrantCredentialsProvider.Token token = provider.parseToken(response); assertThat(token.getAccess()).isEqualTo("18c1b1dfdda04382a8bcc14d077b71dd"); - assertThat(token.getExpiration()).isBetween(offsetNow(expiresIn - 10), offsetNow(expiresIn + 1)); - } - - Date offsetNow(int seconds) { - Calendar calendar = Calendar.getInstance(); - calendar.add(Calendar.SECOND, seconds); - return calendar.getTime(); + assertThat(token.getTimeBeforeExpiration()).isBetween(Duration.ofSeconds(expiresIn - 10), Duration.ofSeconds(expiresIn + 1)); } String sampleJsonToken(String accessToken, int expiresIn) { diff --git a/src/test/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProviderTest.java b/src/test/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProviderTest.java index 5c15cd7400..a96c757e59 100644 --- a/src/test/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProviderTest.java +++ b/src/test/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProviderTest.java @@ -17,7 +17,7 @@ import org.junit.Test; -import java.util.Date; +import java.time.Duration; import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; @@ -44,7 +44,7 @@ protected TestToken retrieveToken() { } catch (InterruptedException e) { throw new RuntimeException(e); } - return new TestToken(UUID.randomUUID().toString(), new Date()); + return new TestToken(UUID.randomUUID().toString()); } @Override @@ -58,8 +58,8 @@ protected String passwordFromToken(TestToken token) { } @Override - protected Date expirationFromToken(TestToken token) { - return token.expiration; + protected Duration timeBeforeExpiration(TestToken token) { + return Duration.ofSeconds(1); } }; @@ -79,11 +79,9 @@ protected Date expirationFromToken(TestToken token) { private static class TestToken { final String secret; - final Date expiration; - TestToken(String secret, Date expiration) { + TestToken(String secret) { this.secret = secret; - this.expiration = expiration; } } diff --git a/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java b/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java index fa455b7744..0870d4d92b 100644 --- a/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java +++ b/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java @@ -24,8 +24,8 @@ import org.junit.Test; import java.time.Duration; -import java.util.Calendar; -import java.util.Date; +import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -50,9 +50,7 @@ public void connectionAndRefreshCredentials() throws Exception { @Override protected TestToken retrieveToken() { latch.countDown(); - Calendar calendar = Calendar.getInstance(); - calendar.add(Calendar.SECOND, 2); - return new TestToken("guest", calendar.getTime()); + return new TestToken("guest", 2, Instant.now()); } @Override @@ -66,8 +64,8 @@ protected String passwordFromToken(TestToken token) { } @Override - protected Date expirationFromToken(TestToken token) { - return token.expiration; + protected Duration timeBeforeExpiration(TestToken token) { + return token.getTimeBeforeExpiration(); } }; @@ -89,11 +87,19 @@ protected Date expirationFromToken(TestToken token) { private static class TestToken { final String secret; - final Date expiration; + final int expiresIn; + final Instant receivedAt; - TestToken(String secret, Date expiration) { + TestToken(String secret, int expiresIn, Instant receivedAt) { this.secret = secret; - this.expiration = expiration; + this.expiresIn = expiresIn; + this.receivedAt = receivedAt; + } + + public Duration getTimeBeforeExpiration() { + Instant now = Instant.now(); + long age = receivedAt.until(now, ChronoUnit.SECONDS); + return Duration.ofSeconds(expiresIn - age); } } From 97c8700390eb199ca895b729c98a515c1474f673 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 25 Jun 2019 10:53:22 +0200 Subject: [PATCH 1123/2114] Add ratio-based token refresh delay strategy --- .../DefaultCredentialsRefreshService.java | 93 +++++++++++++------ .../DefaultCredentialsRefreshServiceTest.java | 40 ++++++-- 2 files changed, 98 insertions(+), 35 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java index ec083b5895..ed081017ae 100644 --- a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java +++ b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java @@ -50,11 +50,11 @@ public class DefaultCredentialsRefreshService implements CredentialsRefreshServi private final boolean privateScheduler; - private final Function refreshDelayStrategy; + private final Function refreshDelayStrategy; private final Function needRefreshStrategy; - public DefaultCredentialsRefreshService(ScheduledExecutorService scheduler, Function refreshDelayStrategy, Function needRefreshStrategy) { + public DefaultCredentialsRefreshService(ScheduledExecutorService scheduler, Function refreshDelayStrategy, Function needRefreshStrategy) { this.refreshDelayStrategy = refreshDelayStrategy; this.needRefreshStrategy = needRefreshStrategy; if (scheduler == null) { @@ -67,43 +67,57 @@ public DefaultCredentialsRefreshService(ScheduledExecutorService scheduler, Func } /** - * Delay before refresh is TTL - specified duration. + * Delay before refresh is a ratio of the time before expiration. *

- * E.g. if TTL is 60 seconds and specified duration is 20 seconds, refresh will + * E.g. if time before expiration is 60 seconds and specified ratio is 0.8, refresh will + * be scheduled in 60 x 0.8 = 48 seconds. + * + * @param ratio + * @return the delay before refreshing + */ + public static Function ratioRefreshDelayStrategy(double ratio) { + return new RatioRefreshDelayStrategy(ratio); + } + + /** + * Delay before refresh is time before expiration - specified duration. + *

+ * E.g. if time before expiration is 60 seconds and specified duration is 20 seconds, refresh will * be scheduled in 60 - 20 = 40 seconds. * * @param duration - * @return + * @return the delay before refreshing */ - public static Function fixedDelayBeforeExpirationRefreshDelayStrategy(Duration duration) { - return new FixedDelayBeforeExpirationRefreshDelayStrategy(duration.toMillis()); + public static Function fixedDelayBeforeExpirationRefreshDelayStrategy(Duration duration) { + return new FixedDelayBeforeExpirationRefreshDelayStrategy(duration); } /** * Advise to refresh credentials if TTL <= limit. * * @param limitBeforeExpiration - * @return + * @return true if credentials should be refreshed, false otherwise */ public static Function fixedTimeNeedRefreshStrategy(Duration limitBeforeExpiration) { return new FixedTimeNeedRefreshStrategy(limitBeforeExpiration.toMillis()); } - // TODO add a delay refresh strategy that bases the time on a percentage of the TTL, use it as default with 80% TTL - private static Runnable refresh(ScheduledExecutorService scheduler, CredentialsProviderState credentialsProviderState, - Function refreshDelayStrategy) { + Function refreshDelayStrategy) { return () -> { LOGGER.debug("Refreshing token"); credentialsProviderState.refresh(); Duration timeBeforeExpiration = credentialsProviderState.credentialsProvider.getTimeBeforeExpiration(); + Duration newDelay = refreshDelayStrategy.apply(timeBeforeExpiration); - long newDelay = refreshDelayStrategy.apply(timeBeforeExpiration); + LOGGER.debug("Scheduling refresh in {} seconds", newDelay.getSeconds()); - LOGGER.debug("Scheduling refresh in {} milliseconds", newDelay); - - ScheduledFuture scheduledFuture = scheduler.schedule(refresh(scheduler, credentialsProviderState, refreshDelayStrategy), newDelay, TimeUnit.MILLISECONDS); + ScheduledFuture scheduledFuture = scheduler.schedule( + refresh(scheduler, credentialsProviderState, refreshDelayStrategy), + newDelay.getSeconds(), + TimeUnit.SECONDS + ); credentialsProviderState.refreshTask.set(scheduledFuture); }; } @@ -122,9 +136,13 @@ public String register(CredentialsProvider credentialsProvider, Callable { - long delay = refreshDelayStrategy.apply(credentialsProvider.getTimeBeforeExpiration()); - LOGGER.debug("Scheduling refresh in {} milliseconds", delay); - return scheduler.schedule(refresh(scheduler, credentialsProviderState, refreshDelayStrategy), delay, TimeUnit.MILLISECONDS); + Duration delay = refreshDelayStrategy.apply(credentialsProvider.getTimeBeforeExpiration()); + LOGGER.debug("Scheduling refresh in {} seconds", delay.getSeconds()); + return scheduler.schedule( + refresh(scheduler, credentialsProviderState, refreshDelayStrategy), + delay.getSeconds(), + TimeUnit.SECONDS + ); }); return registrationId; @@ -163,25 +181,42 @@ public Boolean apply(Duration timeBeforeExpiration) { } } - private static class FixedDelayBeforeExpirationRefreshDelayStrategy implements Function { + private static class FixedDelayBeforeExpirationRefreshDelayStrategy implements Function { - private final long delay; + private final Duration delay; - private FixedDelayBeforeExpirationRefreshDelayStrategy(long delay) { + private FixedDelayBeforeExpirationRefreshDelayStrategy(Duration delay) { this.delay = delay; } @Override - public Long apply(Duration timeBeforeExpiration) { - long refreshTimeBeforeExpiration = timeBeforeExpiration.toMillis() - delay; - if (refreshTimeBeforeExpiration < 0) { - return timeBeforeExpiration.toMillis(); + public Duration apply(Duration timeBeforeExpiration) { + Duration refreshTimeBeforeExpiration = timeBeforeExpiration.minus(delay); + if (refreshTimeBeforeExpiration.isNegative()) { + return timeBeforeExpiration; } else { return refreshTimeBeforeExpiration; } } } + private static class RatioRefreshDelayStrategy implements Function { + + private final double ratio; + + private RatioRefreshDelayStrategy(double ratio) { + if (ratio < 0 || ratio > 1) { + throw new IllegalArgumentException("Ratio should be > 0 and <= 1: " + ratio); + } + this.ratio = ratio; + } + + @Override + public Duration apply(Duration duration) { + return Duration.ofSeconds((long) ((double) duration.getSeconds() * ratio)); + } + } + static class Registration { private final Callable refreshAction; @@ -240,7 +275,7 @@ void maybeSetRefreshTask(Supplier> scheduledFutureSupplier) { } void refresh() { - // FIXME check whether thread has been cancelled or not before refresh() and registratAction.call() + // FIXME check whether thread has been cancelled or not before refresh() and refreshAction.call() // FIXME protect this call, or at least log some error this.credentialsProvider.refresh(); @@ -276,16 +311,16 @@ public static class DefaultCredentialsRefreshServiceBuilder { private ScheduledExecutorService scheduler; - private Function refreshDelayStrategy = fixedDelayBeforeExpirationRefreshDelayStrategy(Duration.ofSeconds(60)); + private Function refreshDelayStrategy = ratioRefreshDelayStrategy(0.8); - private Function needRefreshStrategy = fixedTimeNeedRefreshStrategy(Duration.ofSeconds(60)); + private Function needRefreshStrategy = ttl -> false; public DefaultCredentialsRefreshServiceBuilder scheduler(ScheduledThreadPoolExecutor scheduler) { this.scheduler = scheduler; return this; } - public DefaultCredentialsRefreshServiceBuilder refreshDelayStrategy(Function refreshDelayStrategy) { + public DefaultCredentialsRefreshServiceBuilder refreshDelayStrategy(Function refreshDelayStrategy) { this.refreshDelayStrategy = refreshDelayStrategy; return this; } diff --git a/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java b/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java index 576612db54..2229c34d52 100644 --- a/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java +++ b/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java @@ -29,8 +29,12 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Function; import java.util.stream.IntStream; +import static com.rabbitmq.client.impl.DefaultCredentialsRefreshService.fixedDelayBeforeExpirationRefreshDelayStrategy; +import static com.rabbitmq.client.impl.DefaultCredentialsRefreshService.fixedTimeNeedRefreshStrategy; +import static java.time.Duration.ofSeconds; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.*; @@ -55,13 +59,13 @@ public void tearDown() { @Test public void scheduling() throws Exception { refreshService = new DefaultCredentialsRefreshService.DefaultCredentialsRefreshServiceBuilder() - .refreshDelayStrategy(DefaultCredentialsRefreshService.fixedDelayBeforeExpirationRefreshDelayStrategy(Duration.ofSeconds(2))) + .refreshDelayStrategy(fixedDelayBeforeExpirationRefreshDelayStrategy(ofSeconds(2))) .build(); AtomicInteger passwordSequence = new AtomicInteger(0); when(credentialsProvider.getPassword()).thenAnswer( (Answer) invocation -> "password-" + passwordSequence.get()); - when(credentialsProvider.getTimeBeforeExpiration()).thenAnswer((Answer) invocation -> Duration.ofSeconds(5)); + when(credentialsProvider.getTimeBeforeExpiration()).thenAnswer((Answer) invocation -> ofSeconds(5)); doAnswer(invocation -> { passwordSequence.incrementAndGet(); return null; @@ -82,13 +86,12 @@ public void scheduling() throws Exception { AtomicInteger passwordSequence2 = new AtomicInteger(0); CredentialsProvider credentialsProvider2 = mock(CredentialsProvider.class); when(credentialsProvider2.getPassword()).thenAnswer((Answer) invocation -> "password2-" + passwordSequence2.get()); - when(credentialsProvider2.getTimeBeforeExpiration()).thenAnswer((Answer) invocation -> Duration.ofSeconds(4)); + when(credentialsProvider2.getTimeBeforeExpiration()).thenAnswer((Answer) invocation -> ofSeconds(4)); doAnswer(invocation -> { passwordSequence2.incrementAndGet(); return null; }).when(credentialsProvider2).refresh(); - List passwords2 = new CopyOnWriteArrayList<>(); CountDownLatch latch2 = new CountDownLatch(2 * 1); refreshAction = () -> { @@ -104,8 +107,6 @@ public void scheduling() throws Exception { "password2-1", "password2-2" ); assertThat(passwords).hasSizeGreaterThan(4); - - } @Test @@ -166,4 +167,31 @@ public void refreshActionIsRemovedIfItErrorsTooMuch() throws Exception { verify(refreshAction, times(callsCountBeforeCancellation)).call(); } + @Test + public void fixedDelayBeforeExpirationRefreshDelayStrategyTest() { + Function delayStrategy = fixedDelayBeforeExpirationRefreshDelayStrategy(ofSeconds(20)); + assertThat(delayStrategy.apply(ofSeconds(60))).as("refresh delay is TTL - fixed delay").isEqualTo(ofSeconds(40)); + assertThat(delayStrategy.apply(ofSeconds(10))).as("refresh delay is TTL if TTL < fixed delay").isEqualTo(ofSeconds(10)); + } + + @Test + public void fixedTimeNeedRefreshStrategyTest() { + Function refreshStrategy = fixedTimeNeedRefreshStrategy(ofSeconds(20)); + assertThat(refreshStrategy.apply(ofSeconds(60))).isFalse(); + assertThat(refreshStrategy.apply(ofSeconds(20))).isTrue(); + assertThat(refreshStrategy.apply(ofSeconds(19))).isTrue(); + assertThat(refreshStrategy.apply(ofSeconds(10))).isTrue(); + } + + @Test + public void ratioRefreshDelayStrategyTest() { + Function delayStrategy = DefaultCredentialsRefreshService.ratioRefreshDelayStrategy(0.8); + assertThat(delayStrategy.apply(ofSeconds(60))).isEqualTo(ofSeconds(48)); + assertThat(delayStrategy.apply(ofSeconds(30))).isEqualTo(ofSeconds(24)); + assertThat(delayStrategy.apply(ofSeconds(10))).isEqualTo(ofSeconds(8)); + assertThat(delayStrategy.apply(ofSeconds(5))).isEqualTo(ofSeconds(4)); + assertThat(delayStrategy.apply(ofSeconds(2))).isEqualTo(ofSeconds(1)); + assertThat(delayStrategy.apply(ofSeconds(1))).isEqualTo(ofSeconds(0)); + } + } From 443a5896191edbf5652841856f9f534d38665496 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 25 Jun 2019 11:52:23 +0200 Subject: [PATCH 1124/2114] Handle thread interruption in credentials refresh service --- .../DefaultCredentialsRefreshService.java | 35 ++++++++++-- .../DefaultCredentialsRefreshServiceTest.java | 57 +++++++++++++++++++ 2 files changed, 88 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java index ed081017ae..032a94c779 100644 --- a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java +++ b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java @@ -275,13 +275,38 @@ void maybeSetRefreshTask(Supplier> scheduledFutureSupplier) { } void refresh() { - // FIXME check whether thread has been cancelled or not before refresh() and refreshAction.call() + if (Thread.currentThread().isInterrupted()) { + return; + } - // FIXME protect this call, or at least log some error - this.credentialsProvider.refresh(); + int attemptCount = 0; + boolean refreshSucceeded = false; + while (attemptCount < 3) { + LOGGER.debug("Refreshing token for credentials provider {}", credentialsProvider); + try { + this.credentialsProvider.refresh(); + LOGGER.debug("Token refreshed for credentials provider {}", credentialsProvider); + refreshSucceeded = true; + break; + } catch (Exception e) { + LOGGER.warn("Error while trying to refresh token: {}", e.getMessage()); + } + attemptCount++; + try { + Thread.sleep(1000L); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return; + } + } + + if (!refreshSucceeded) { + LOGGER.warn("Token refresh failed after retry, aborting callbacks"); + return; + } Iterator iterator = registrations.values().iterator(); - while (iterator.hasNext()) { + while (iterator.hasNext() && !Thread.currentThread().isInterrupted()) { Registration registration = iterator.next(); // FIXME set a timeout on the call? (needs a separate thread) try { @@ -291,6 +316,8 @@ void refresh() { iterator.remove(); } registration.errorHistory.set(0); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); } catch (Exception e) { LOGGER.warn("Error while trying to refresh a connection token", e); registration.errorHistory.incrementAndGet(); diff --git a/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java b/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java index 2229c34d52..5a1518610d 100644 --- a/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java +++ b/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java @@ -167,6 +167,63 @@ public void refreshActionIsRemovedIfItErrorsTooMuch() throws Exception { verify(refreshAction, times(callsCountBeforeCancellation)).call(); } + @Test + public void errorInRefreshShouldBeRetried() throws Exception { + DefaultCredentialsRefreshService.CredentialsProviderState state = new DefaultCredentialsRefreshService.CredentialsProviderState( + credentialsProvider + ); + doThrow(RuntimeException.class).doThrow(RuntimeException.class) + .doNothing().when(credentialsProvider).refresh(); + + when(refreshAction.call()).thenReturn(true); + + state.add(new DefaultCredentialsRefreshService.Registration("1", refreshAction)); + + state.refresh(); + + verify(credentialsProvider, times(3)).refresh(); + verify(refreshAction, times(1)).call(); + } + + @Test + public void callbacksAreNotCalledWhenRetryOnRefreshIsExhausted() throws Exception { + DefaultCredentialsRefreshService.CredentialsProviderState state = new DefaultCredentialsRefreshService.CredentialsProviderState( + credentialsProvider + ); + doThrow(RuntimeException.class).when(credentialsProvider).refresh(); + + state.add(new DefaultCredentialsRefreshService.Registration("1", refreshAction)); + + state.refresh(); + + verify(credentialsProvider, times(3)).refresh(); + verify(refreshAction, times(0)).call(); + } + + @Test + public void refreshCanBeInterrupted() throws Exception { + DefaultCredentialsRefreshService.CredentialsProviderState state = new DefaultCredentialsRefreshService.CredentialsProviderState( + credentialsProvider + ); + + AtomicInteger callbackCount = new AtomicInteger(10); + when(refreshAction.call()).thenAnswer(invocation -> { + callbackCount.decrementAndGet(); + Thread.sleep(1000L); + return true; + }); + + IntStream.range(0, callbackCount.get()).forEach(i -> state.add(new DefaultCredentialsRefreshService.Registration(i + "", refreshAction))); + + Thread refreshThread = new Thread(() -> state.refresh()); + refreshThread.start(); + Thread.sleep(1000L); + refreshThread.interrupt(); + refreshThread.join(5000); + assertThat(refreshThread.isAlive()).isFalse(); + assertThat(callbackCount).hasValueGreaterThan(1); // not all the callbacks were called, because thread has been cancelled + } + @Test public void fixedDelayBeforeExpirationRefreshDelayStrategyTest() { Function delayStrategy = fixedDelayBeforeExpirationRefreshDelayStrategy(ofSeconds(20)); From fe58bd6c1e399e30bcf8c55fa807bf2e739dd76a Mon Sep 17 00:00:00 2001 From: Changlin Li Date: Thu, 27 Jun 2019 23:03:49 -0400 Subject: [PATCH 1125/2114] Change # of bits ValueWriter checks for BigDecimal Move from 32 to 31 because bitLength ignores the sign bit. --- src/main/java/com/rabbitmq/client/impl/ValueWriter.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/impl/ValueWriter.java b/src/main/java/com/rabbitmq/client/impl/ValueWriter.java index 28d516dec4..ab65b95aeb 100644 --- a/src/main/java/com/rabbitmq/client/impl/ValueWriter.java +++ b/src/main/java/com/rabbitmq/client/impl/ValueWriter.java @@ -145,7 +145,9 @@ else if(value instanceof BigDecimal) { BigDecimal decimal = (BigDecimal)value; writeOctet(decimal.scale()); BigInteger unscaled = decimal.unscaledValue(); - if(unscaled.bitLength() > 32) /*Integer.SIZE in Java 1.5*/ + // We use 31 instead of 32 because bitLength ignores the sign bit, + // so e.g. new BigDecimal(Integer.MAX_VALUE) comes out to 31 bits. + if(unscaled.bitLength() > 31) /*Integer.SIZE in Java 1.5*/ throw new IllegalArgumentException ("BigDecimal too large to be encoded"); writeLong(decimal.unscaledValue().intValue()); From a4c5a1a23461a0335a3c10a473a64d1b4e7a9240 Mon Sep 17 00:00:00 2001 From: Changlin Li Date: Thu, 27 Jun 2019 23:21:37 -0400 Subject: [PATCH 1126/2114] Add basic test case for fixing 617 --- .../rabbitmq/client/impl/ValueWriterTest.java | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java diff --git a/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java b/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java new file mode 100644 index 0000000000..a0052939fb --- /dev/null +++ b/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java @@ -0,0 +1,30 @@ +package com.rabbitmq.client.impl; + +import org.junit.Test; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.math.BigDecimal; +import java.util.ArrayDeque; +import java.util.Queue; + +public class ValueWriterTest { + @Test(expected = IllegalArgumentException.class) public void writingOverlyLargeBigDecimalShouldFail() throws IOException { + Queue queue = new ArrayDeque<>(); + + OutputStream outputStream = new OutputStream() { + @Override + public void write(int b) { + queue.add((byte) b); + } + }; + + DataOutputStream dataOutputStream = new DataOutputStream(outputStream); + + ValueWriter valueWriter = new ValueWriter(dataOutputStream); + + valueWriter.writeFieldValue(new BigDecimal(Integer.MAX_VALUE).add(new BigDecimal(1))); + + } +} From ecb31ba94e8d03cea3f18dadf408e6cf2cb13129 Mon Sep 17 00:00:00 2001 From: Changlin Li Date: Fri, 28 Jun 2019 01:21:25 -0400 Subject: [PATCH 1127/2114] Add additional fix for not checking scale The scale of a BigDecimal must also be checked because it must be a signed octet --- .../com/rabbitmq/client/impl/ValueWriter.java | 6 +++++ .../rabbitmq/client/impl/ValueWriterTest.java | 22 ++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/impl/ValueWriter.java b/src/main/java/com/rabbitmq/client/impl/ValueWriter.java index ab65b95aeb..2510172a95 100644 --- a/src/main/java/com/rabbitmq/client/impl/ValueWriter.java +++ b/src/main/java/com/rabbitmq/client/impl/ValueWriter.java @@ -143,6 +143,12 @@ else if(value instanceof Integer) { else if(value instanceof BigDecimal) { writeOctet('D'); BigDecimal decimal = (BigDecimal)value; + // The scale must be an unsigned octet, therefore its values must + // be between 0 and 255 + if(decimal.scale() > 255 || decimal.scale() < 0) + throw new IllegalArgumentException + ("BigDecimal has too large of a scale to be encoded. " + + "The scale was: " + decimal.scale()); writeOctet(decimal.scale()); BigInteger unscaled = decimal.unscaledValue(); // We use 31 instead of 32 because bitLength ignores the sign bit, diff --git a/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java b/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java index a0052939fb..743a2cd043 100644 --- a/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java +++ b/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java @@ -6,11 +6,13 @@ import java.io.IOException; import java.io.OutputStream; import java.math.BigDecimal; +import java.math.BigInteger; import java.util.ArrayDeque; import java.util.Queue; public class ValueWriterTest { - @Test(expected = IllegalArgumentException.class) public void writingOverlyLargeBigDecimalShouldFail() throws IOException { + @Test(expected = IllegalArgumentException.class) public void writingOverlyLargeBigDecimalShouldFail() + throws IOException { Queue queue = new ArrayDeque<>(); OutputStream outputStream = new OutputStream() { @@ -27,4 +29,22 @@ public void write(int b) { valueWriter.writeFieldValue(new BigDecimal(Integer.MAX_VALUE).add(new BigDecimal(1))); } + + @Test(expected = IllegalArgumentException.class) public void writingOverlyLargeScaleInBigDecimalShouldFail() + throws IOException { + Queue queue = new ArrayDeque<>(); + + OutputStream outputStream = new OutputStream() { + @Override + public void write(int b) { + queue.add((byte) b); + } + }; + + DataOutputStream dataOutputStream = new DataOutputStream(outputStream); + + ValueWriter valueWriter = new ValueWriter(dataOutputStream); + + valueWriter.writeFieldValue(new BigDecimal(BigInteger.ONE, 500)); + } } From 26e20c74cf247f13c9f58fa2e534f78365a7e142 Mon Sep 17 00:00:00 2001 From: Changlin Li Date: Fri, 28 Jun 2019 02:34:35 -0400 Subject: [PATCH 1128/2114] Remove redundant queues from tests They're not actually used at all during the test --- src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java b/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java index 743a2cd043..681919103d 100644 --- a/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java +++ b/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java @@ -7,18 +7,14 @@ import java.io.OutputStream; import java.math.BigDecimal; import java.math.BigInteger; -import java.util.ArrayDeque; -import java.util.Queue; public class ValueWriterTest { @Test(expected = IllegalArgumentException.class) public void writingOverlyLargeBigDecimalShouldFail() throws IOException { - Queue queue = new ArrayDeque<>(); OutputStream outputStream = new OutputStream() { @Override public void write(int b) { - queue.add((byte) b); } }; @@ -32,12 +28,10 @@ public void write(int b) { @Test(expected = IllegalArgumentException.class) public void writingOverlyLargeScaleInBigDecimalShouldFail() throws IOException { - Queue queue = new ArrayDeque<>(); OutputStream outputStream = new OutputStream() { @Override public void write(int b) { - queue.add((byte) b); } }; From 02284ea050e5f9326f0cc362bcdcbae911ae7f20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 28 Jun 2019 10:25:09 +0200 Subject: [PATCH 1129/2114] Add a test to write/read BigDecimal References #617 --- .../com/rabbitmq/client/impl/ValueReader.java | 5 ++- .../com/rabbitmq/client/impl/ValueWriter.java | 2 +- .../rabbitmq/client/impl/ValueWriterTest.java | 44 ++++++++++++++++--- .../com/rabbitmq/client/test/ClientTests.java | 4 +- 4 files changed, 44 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/ValueReader.java b/src/main/java/com/rabbitmq/client/impl/ValueReader.java index 8cc639891b..8a9e860443 100644 --- a/src/main/java/com/rabbitmq/client/impl/ValueReader.java +++ b/src/main/java/com/rabbitmq/client/impl/ValueReader.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2019 Pivotal Software, Inc. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 @@ -153,7 +153,8 @@ private static Map readTable(DataInputStream in) return table; } - private static Object readFieldValue(DataInputStream in) + // package protected for testing + static Object readFieldValue(DataInputStream in) throws IOException { Object value = null; switch(in.readUnsignedByte()) { diff --git a/src/main/java/com/rabbitmq/client/impl/ValueWriter.java b/src/main/java/com/rabbitmq/client/impl/ValueWriter.java index 2510172a95..947c6a326d 100644 --- a/src/main/java/com/rabbitmq/client/impl/ValueWriter.java +++ b/src/main/java/com/rabbitmq/client/impl/ValueWriter.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2019 Pivotal Software, Inc. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java b/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java index 681919103d..76cbd0d6df 100644 --- a/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java +++ b/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java @@ -1,16 +1,33 @@ +// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.impl; import org.junit.Test; -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.OutputStream; +import java.io.*; import java.math.BigDecimal; import java.math.BigInteger; +import static org.assertj.core.api.Assertions.assertThat; + public class ValueWriterTest { - @Test(expected = IllegalArgumentException.class) public void writingOverlyLargeBigDecimalShouldFail() - throws IOException { + + @Test(expected = IllegalArgumentException.class) + public void writingOverlyLargeBigDecimalShouldFail() + throws IOException { OutputStream outputStream = new OutputStream() { @Override @@ -26,8 +43,9 @@ public void write(int b) { } - @Test(expected = IllegalArgumentException.class) public void writingOverlyLargeScaleInBigDecimalShouldFail() - throws IOException { + @Test(expected = IllegalArgumentException.class) + public void writingOverlyLargeScaleInBigDecimalShouldFail() + throws IOException { OutputStream outputStream = new OutputStream() { @Override @@ -41,4 +59,16 @@ public void write(int b) { valueWriter.writeFieldValue(new BigDecimal(BigInteger.ONE, 500)); } + + @Test + public void bigDecimalWrittenAndReadMatches() throws IOException { + BigDecimal value = new BigDecimal(BigInteger.valueOf(56), 3); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + DataOutputStream dataOutputStream = new DataOutputStream(outputStream); + ValueWriter valueWriter = new ValueWriter(dataOutputStream); + valueWriter.writeFieldValue(value); + + BigDecimal read = (BigDecimal) ValueReader.readFieldValue(new DataInputStream(new ByteArrayInputStream(outputStream.toByteArray()))); + assertThat(read).isEqualTo(value); + } } diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index d5fb3251ab..7d0a2ef64f 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -17,6 +17,7 @@ package com.rabbitmq.client.test; import com.rabbitmq.client.JacksonJsonRpcTest; +import com.rabbitmq.client.impl.ValueWriterTest; import com.rabbitmq.utility.IntAllocatorTests; import org.junit.runner.RunWith; import org.junit.runners.Suite; @@ -68,7 +69,8 @@ RpcTopologyRecordingTest.class, ConnectionTest.class, TlsUtilsTest.class, - ChannelNTest.class + ChannelNTest.class, + ValueWriterTest.class }) public class ClientTests { From 904c5b4c998573d5c0bafa7c0bbdc9ec75a64c32 Mon Sep 17 00:00:00 2001 From: Changlin Li Date: Thu, 27 Jun 2019 23:03:49 -0400 Subject: [PATCH 1130/2114] Change # of bits ValueWriter checks for BigDecimal Move from 32 to 31 because bitLength ignores the sign bit. (cherry picked from commit fe58bd6c1e399e30bcf8c55fa807bf2e739dd76a) --- src/main/java/com/rabbitmq/client/impl/ValueWriter.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/impl/ValueWriter.java b/src/main/java/com/rabbitmq/client/impl/ValueWriter.java index 28d516dec4..ab65b95aeb 100644 --- a/src/main/java/com/rabbitmq/client/impl/ValueWriter.java +++ b/src/main/java/com/rabbitmq/client/impl/ValueWriter.java @@ -145,7 +145,9 @@ else if(value instanceof BigDecimal) { BigDecimal decimal = (BigDecimal)value; writeOctet(decimal.scale()); BigInteger unscaled = decimal.unscaledValue(); - if(unscaled.bitLength() > 32) /*Integer.SIZE in Java 1.5*/ + // We use 31 instead of 32 because bitLength ignores the sign bit, + // so e.g. new BigDecimal(Integer.MAX_VALUE) comes out to 31 bits. + if(unscaled.bitLength() > 31) /*Integer.SIZE in Java 1.5*/ throw new IllegalArgumentException ("BigDecimal too large to be encoded"); writeLong(decimal.unscaledValue().intValue()); From e3ceed7430996e404c57b114632b7d8d85a3903f Mon Sep 17 00:00:00 2001 From: Changlin Li Date: Thu, 27 Jun 2019 23:21:37 -0400 Subject: [PATCH 1131/2114] Add basic test case for fixing 617 (cherry picked from commit a4c5a1a23461a0335a3c10a473a64d1b4e7a9240) --- .../rabbitmq/client/impl/ValueWriterTest.java | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java diff --git a/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java b/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java new file mode 100644 index 0000000000..a0052939fb --- /dev/null +++ b/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java @@ -0,0 +1,30 @@ +package com.rabbitmq.client.impl; + +import org.junit.Test; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.math.BigDecimal; +import java.util.ArrayDeque; +import java.util.Queue; + +public class ValueWriterTest { + @Test(expected = IllegalArgumentException.class) public void writingOverlyLargeBigDecimalShouldFail() throws IOException { + Queue queue = new ArrayDeque<>(); + + OutputStream outputStream = new OutputStream() { + @Override + public void write(int b) { + queue.add((byte) b); + } + }; + + DataOutputStream dataOutputStream = new DataOutputStream(outputStream); + + ValueWriter valueWriter = new ValueWriter(dataOutputStream); + + valueWriter.writeFieldValue(new BigDecimal(Integer.MAX_VALUE).add(new BigDecimal(1))); + + } +} From e26c85879158992148d8f5a5ea0709125211b18c Mon Sep 17 00:00:00 2001 From: Changlin Li Date: Fri, 28 Jun 2019 01:21:25 -0400 Subject: [PATCH 1132/2114] Add additional fix for not checking scale The scale of a BigDecimal must also be checked because it must be a signed octet (cherry picked from commit ecb31ba94e8d03cea3f18dadf408e6cf2cb13129) --- .../com/rabbitmq/client/impl/ValueWriter.java | 6 +++++ .../rabbitmq/client/impl/ValueWriterTest.java | 22 ++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/impl/ValueWriter.java b/src/main/java/com/rabbitmq/client/impl/ValueWriter.java index ab65b95aeb..2510172a95 100644 --- a/src/main/java/com/rabbitmq/client/impl/ValueWriter.java +++ b/src/main/java/com/rabbitmq/client/impl/ValueWriter.java @@ -143,6 +143,12 @@ else if(value instanceof Integer) { else if(value instanceof BigDecimal) { writeOctet('D'); BigDecimal decimal = (BigDecimal)value; + // The scale must be an unsigned octet, therefore its values must + // be between 0 and 255 + if(decimal.scale() > 255 || decimal.scale() < 0) + throw new IllegalArgumentException + ("BigDecimal has too large of a scale to be encoded. " + + "The scale was: " + decimal.scale()); writeOctet(decimal.scale()); BigInteger unscaled = decimal.unscaledValue(); // We use 31 instead of 32 because bitLength ignores the sign bit, diff --git a/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java b/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java index a0052939fb..743a2cd043 100644 --- a/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java +++ b/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java @@ -6,11 +6,13 @@ import java.io.IOException; import java.io.OutputStream; import java.math.BigDecimal; +import java.math.BigInteger; import java.util.ArrayDeque; import java.util.Queue; public class ValueWriterTest { - @Test(expected = IllegalArgumentException.class) public void writingOverlyLargeBigDecimalShouldFail() throws IOException { + @Test(expected = IllegalArgumentException.class) public void writingOverlyLargeBigDecimalShouldFail() + throws IOException { Queue queue = new ArrayDeque<>(); OutputStream outputStream = new OutputStream() { @@ -27,4 +29,22 @@ public void write(int b) { valueWriter.writeFieldValue(new BigDecimal(Integer.MAX_VALUE).add(new BigDecimal(1))); } + + @Test(expected = IllegalArgumentException.class) public void writingOverlyLargeScaleInBigDecimalShouldFail() + throws IOException { + Queue queue = new ArrayDeque<>(); + + OutputStream outputStream = new OutputStream() { + @Override + public void write(int b) { + queue.add((byte) b); + } + }; + + DataOutputStream dataOutputStream = new DataOutputStream(outputStream); + + ValueWriter valueWriter = new ValueWriter(dataOutputStream); + + valueWriter.writeFieldValue(new BigDecimal(BigInteger.ONE, 500)); + } } From 693503ad985a0214d44a1be10ca09e233694f3ef Mon Sep 17 00:00:00 2001 From: Changlin Li Date: Fri, 28 Jun 2019 02:34:35 -0400 Subject: [PATCH 1133/2114] Remove redundant queues from tests They're not actually used at all during the test (cherry picked from commit 26e20c74cf247f13c9f58fa2e534f78365a7e142) --- src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java b/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java index 743a2cd043..681919103d 100644 --- a/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java +++ b/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java @@ -7,18 +7,14 @@ import java.io.OutputStream; import java.math.BigDecimal; import java.math.BigInteger; -import java.util.ArrayDeque; -import java.util.Queue; public class ValueWriterTest { @Test(expected = IllegalArgumentException.class) public void writingOverlyLargeBigDecimalShouldFail() throws IOException { - Queue queue = new ArrayDeque<>(); OutputStream outputStream = new OutputStream() { @Override public void write(int b) { - queue.add((byte) b); } }; @@ -32,12 +28,10 @@ public void write(int b) { @Test(expected = IllegalArgumentException.class) public void writingOverlyLargeScaleInBigDecimalShouldFail() throws IOException { - Queue queue = new ArrayDeque<>(); OutputStream outputStream = new OutputStream() { @Override public void write(int b) { - queue.add((byte) b); } }; From 2671fff53b14d54b1f8a63e205480dfa10b24d30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 28 Jun 2019 10:25:09 +0200 Subject: [PATCH 1134/2114] Add a test to write/read BigDecimal References #617 (cherry picked from commit 02284ea050e5f9326f0cc362bcdcbae911ae7f20) Conflicts: src/test/java/com/rabbitmq/client/test/ClientTests.java --- .../com/rabbitmq/client/impl/ValueReader.java | 5 ++- .../com/rabbitmq/client/impl/ValueWriter.java | 2 +- .../rabbitmq/client/impl/ValueWriterTest.java | 44 ++++++++++++++++--- .../com/rabbitmq/client/test/ClientTests.java | 4 +- 4 files changed, 44 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/ValueReader.java b/src/main/java/com/rabbitmq/client/impl/ValueReader.java index 8cc639891b..8a9e860443 100644 --- a/src/main/java/com/rabbitmq/client/impl/ValueReader.java +++ b/src/main/java/com/rabbitmq/client/impl/ValueReader.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2019 Pivotal Software, Inc. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 @@ -153,7 +153,8 @@ private static Map readTable(DataInputStream in) return table; } - private static Object readFieldValue(DataInputStream in) + // package protected for testing + static Object readFieldValue(DataInputStream in) throws IOException { Object value = null; switch(in.readUnsignedByte()) { diff --git a/src/main/java/com/rabbitmq/client/impl/ValueWriter.java b/src/main/java/com/rabbitmq/client/impl/ValueWriter.java index 2510172a95..947c6a326d 100644 --- a/src/main/java/com/rabbitmq/client/impl/ValueWriter.java +++ b/src/main/java/com/rabbitmq/client/impl/ValueWriter.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2019 Pivotal Software, Inc. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java b/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java index 681919103d..76cbd0d6df 100644 --- a/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java +++ b/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java @@ -1,16 +1,33 @@ +// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.impl; import org.junit.Test; -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.OutputStream; +import java.io.*; import java.math.BigDecimal; import java.math.BigInteger; +import static org.assertj.core.api.Assertions.assertThat; + public class ValueWriterTest { - @Test(expected = IllegalArgumentException.class) public void writingOverlyLargeBigDecimalShouldFail() - throws IOException { + + @Test(expected = IllegalArgumentException.class) + public void writingOverlyLargeBigDecimalShouldFail() + throws IOException { OutputStream outputStream = new OutputStream() { @Override @@ -26,8 +43,9 @@ public void write(int b) { } - @Test(expected = IllegalArgumentException.class) public void writingOverlyLargeScaleInBigDecimalShouldFail() - throws IOException { + @Test(expected = IllegalArgumentException.class) + public void writingOverlyLargeScaleInBigDecimalShouldFail() + throws IOException { OutputStream outputStream = new OutputStream() { @Override @@ -41,4 +59,16 @@ public void write(int b) { valueWriter.writeFieldValue(new BigDecimal(BigInteger.ONE, 500)); } + + @Test + public void bigDecimalWrittenAndReadMatches() throws IOException { + BigDecimal value = new BigDecimal(BigInteger.valueOf(56), 3); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + DataOutputStream dataOutputStream = new DataOutputStream(outputStream); + ValueWriter valueWriter = new ValueWriter(dataOutputStream); + valueWriter.writeFieldValue(value); + + BigDecimal read = (BigDecimal) ValueReader.readFieldValue(new DataInputStream(new ByteArrayInputStream(outputStream.toByteArray()))); + assertThat(read).isEqualTo(value); + } } diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index 4f4cb156eb..db5c7cd179 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -18,6 +18,7 @@ import com.rabbitmq.client.JacksonJsonRpcTest; import com.rabbitmq.client.DefaultJsonRpcTest; +import com.rabbitmq.client.impl.ValueWriterTest; import com.rabbitmq.utility.IntAllocatorTests; import org.junit.runner.RunWith; import org.junit.runners.Suite; @@ -71,7 +72,8 @@ RpcTopologyRecordingTest.class, ConnectionTest.class, TlsUtilsTest.class, - ChannelNTest.class + ChannelNTest.class, + ValueWriterTest.class }) public class ClientTests { From 4f90abd9602e4bc1d1fdc809696b2e542afa68ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 28 Jun 2019 13:49:30 +0200 Subject: [PATCH 1135/2114] Fix comment in BigDecimal serialization References #617 --- src/main/java/com/rabbitmq/client/impl/ValueWriter.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/ValueWriter.java b/src/main/java/com/rabbitmq/client/impl/ValueWriter.java index 947c6a326d..0c997d1545 100644 --- a/src/main/java/com/rabbitmq/client/impl/ValueWriter.java +++ b/src/main/java/com/rabbitmq/client/impl/ValueWriter.java @@ -151,9 +151,9 @@ else if(value instanceof BigDecimal) { "The scale was: " + decimal.scale()); writeOctet(decimal.scale()); BigInteger unscaled = decimal.unscaledValue(); - // We use 31 instead of 32 because bitLength ignores the sign bit, + // We use 31 instead of 32 (Integer.SIZE) because bitLength ignores the sign bit, // so e.g. new BigDecimal(Integer.MAX_VALUE) comes out to 31 bits. - if(unscaled.bitLength() > 31) /*Integer.SIZE in Java 1.5*/ + if(unscaled.bitLength() > 31) throw new IllegalArgumentException ("BigDecimal too large to be encoded"); writeLong(decimal.unscaledValue().intValue()); From 8ad972629e75217fa33f11e00c9cf3ffab4c267b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 28 Jun 2019 13:49:30 +0200 Subject: [PATCH 1136/2114] Fix comment in BigDecimal serialization References #617 (cherry picked from commit 4f90abd9602e4bc1d1fdc809696b2e542afa68ae) --- src/main/java/com/rabbitmq/client/impl/ValueWriter.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/ValueWriter.java b/src/main/java/com/rabbitmq/client/impl/ValueWriter.java index 947c6a326d..0c997d1545 100644 --- a/src/main/java/com/rabbitmq/client/impl/ValueWriter.java +++ b/src/main/java/com/rabbitmq/client/impl/ValueWriter.java @@ -151,9 +151,9 @@ else if(value instanceof BigDecimal) { "The scale was: " + decimal.scale()); writeOctet(decimal.scale()); BigInteger unscaled = decimal.unscaledValue(); - // We use 31 instead of 32 because bitLength ignores the sign bit, + // We use 31 instead of 32 (Integer.SIZE) because bitLength ignores the sign bit, // so e.g. new BigDecimal(Integer.MAX_VALUE) comes out to 31 bits. - if(unscaled.bitLength() > 31) /*Integer.SIZE in Java 1.5*/ + if(unscaled.bitLength() > 31) throw new IllegalArgumentException ("BigDecimal too large to be encoded"); writeLong(decimal.unscaledValue().intValue()); From 0024b6a1070e074992aa495c2e3dee972f1e4cdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 1 Jul 2019 14:30:19 +0200 Subject: [PATCH 1137/2114] Bump Micrometer and Metrics Fixes #619 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index cff83e31d3..f13e1d173b 100644 --- a/pom.xml +++ b/pom.xml @@ -55,8 +55,8 @@ UTF-8 1.7.26 - 4.0.5 - 1.1.3 + 4.1.0 + 1.2.0 2.9.9 1.2.3 4.12 From b872a46ec79a9b929246432314b53aa11db70ed8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 1 Jul 2019 14:33:28 +0200 Subject: [PATCH 1138/2114] Bump Mockito --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f13e1d173b..8cea12c61d 100644 --- a/pom.xml +++ b/pom.xml @@ -61,7 +61,7 @@ 1.2.3 4.12 3.1.6 - 2.25.1 + 2.28.2 3.12.2 3.0.1 From d5b0c4e55128f1286d1adb6cde94e6e926425169 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 1 Jul 2019 14:30:19 +0200 Subject: [PATCH 1139/2114] Bump Micrometer and Metrics Fixes #619 (cherry picked from commit 0024b6a1070e074992aa495c2e3dee972f1e4cdc) --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 1d4fc3a7be..b7f13a526c 100644 --- a/pom.xml +++ b/pom.xml @@ -55,8 +55,8 @@ UTF-8 1.7.26 - 4.0.5 - 1.1.3 + 4.1.0 + 1.2.0 2.9.9 1.2.3 4.12 From c5725eaa06b9f0eea60816612458c0d82b7643fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 1 Jul 2019 14:33:28 +0200 Subject: [PATCH 1140/2114] Bump Mockito (cherry picked from commit b872a46ec79a9b929246432314b53aa11db70ed8) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b7f13a526c..c28cd1042f 100644 --- a/pom.xml +++ b/pom.xml @@ -61,7 +61,7 @@ 1.2.3 4.12 3.1.6 - 2.25.1 + 2.28.2 3.12.2 3.0.1 From 6d275bfe2af1d71c3aa8e571c0f9ec2df25e1c1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 3 Jul 2019 10:53:11 +0200 Subject: [PATCH 1141/2114] Mention 5.7.2 and 4.11.2 in readme --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index f3424e87e3..cb414953b5 100644 --- a/README.md +++ b/README.md @@ -23,14 +23,14 @@ They require Java 8 or higher. com.rabbitmq amqp-client - 5.7.1 + 5.7.2 ``` ### Gradle ``` groovy -compile 'com.rabbitmq:amqp-client:5.7.1' +compile 'com.rabbitmq:amqp-client:5.7.2' ``` #### 4.x Series @@ -42,14 +42,14 @@ They require Java 6 or higher. com.rabbitmq amqp-client - 4.11.1 + 4.11.2 ``` ### Gradle ``` groovy -compile 'com.rabbitmq:amqp-client:4.11.1' +compile 'com.rabbitmq:amqp-client:4.11.2' ``` From 136b3ea7232356ad98e94b3f57d34e267c2cebeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 4 Jul 2019 12:01:17 +0200 Subject: [PATCH 1142/2114] Send update.secret extension when scheduled [#167029587] --- .../rabbitmq/client/impl/AMQConnection.java | 6 +- .../DefaultCredentialsRefreshServiceTest.java | 57 +++++++++++- .../client/test/RefreshCredentialsTest.java | 4 + .../com/rabbitmq/client/test/TestUtils.java | 93 +++++++++++++------ .../rabbitmq/client/test/TestUtilsTest.java | 19 ++++ 5 files changed, 147 insertions(+), 32 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index 5d834a052f..eac4553647 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -435,8 +435,10 @@ public void start() } String refreshedPassword = credentialsProvider.getPassword(); - // TODO send password to server with update-secret extension, using channel 0 - + AMQImpl.Connection.UpdateSecret updateSecret = new AMQImpl.Connection.UpdateSecret( + LongStringHelper.asLongString(refreshedPassword), "Refresh scheduled by client" + ); + _channel0.rpc(updateSecret); return true; }); diff --git a/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java b/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java index 5a1518610d..0fa8e7ca72 100644 --- a/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java +++ b/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java @@ -15,6 +15,10 @@ package com.rabbitmq.client.impl; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.test.TestUtils; import org.junit.After; import org.junit.Test; import org.junit.runner.RunWith; @@ -22,6 +26,7 @@ import org.mockito.junit.MockitoJUnitRunner; import org.mockito.stubbing.Answer; +import java.io.IOException; import java.time.Duration; import java.util.List; import java.util.concurrent.Callable; @@ -32,8 +37,7 @@ import java.util.function.Function; import java.util.stream.IntStream; -import static com.rabbitmq.client.impl.DefaultCredentialsRefreshService.fixedDelayBeforeExpirationRefreshDelayStrategy; -import static com.rabbitmq.client.impl.DefaultCredentialsRefreshService.fixedTimeNeedRefreshStrategy; +import static com.rabbitmq.client.impl.DefaultCredentialsRefreshService.*; import static java.time.Duration.ofSeconds; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.*; @@ -56,6 +60,55 @@ public void tearDown() { } } + @Test public void renew() { + ConnectionFactory cf = new ConnectionFactory(); + OAuth2ClientCredentialsGrantCredentialsProvider provider = new OAuth2ClientCredentialsGrantCredentialsProvider.OAuth2ClientCredentialsGrantCredentialsProviderBuilder() + .tokenEndpointUri("http://localhost:" + 8080 + "/uaa/oauth/token") + .clientId("rabbit_client").clientSecret("rabbit_secret") + .grantType("password") + .parameter("username", "rabbit_super") + .parameter("password", "rabbit_super") + .build(); + cf.setCredentialsProvider(provider); + + + } + + @Test public void connect() throws Exception { + ConnectionFactory cf = new ConnectionFactory(); + OAuth2ClientCredentialsGrantCredentialsProvider provider = new OAuth2ClientCredentialsGrantCredentialsProvider.OAuth2ClientCredentialsGrantCredentialsProviderBuilder() + .tokenEndpointUri("http://localhost:" + 8080 + "/uaa/oauth/token") + .clientId("rabbit_client").clientSecret("rabbit_secret") + .grantType("password") + .parameter("username", "rabbit_super") + .parameter("password", "rabbit_super") + .build(); + cf.setCredentialsProvider(provider); + refreshService = new DefaultCredentialsRefreshService.DefaultCredentialsRefreshServiceBuilder() +// .refreshDelayStrategy(ttl -> Duration.ofSeconds(60)) + .refreshDelayStrategy(ratioRefreshDelayStrategy(0.8)) + .needRefreshStrategy(expiration -> false) + .build(); + cf.setCredentialsRefreshService(refreshService); + try (Connection c = cf.newConnection()) { + + while (true) { + try { + Channel ch = c.createChannel(); + String queue = ch.queueDeclare().getQueue(); + TestUtils.sendAndConsumeMessage("", queue, queue, c); + System.out.println("Message sent and consumed"); + ch.close(); + } catch (IOException e) { + System.out.println(e.getCause().getMessage()); + } + Thread.sleep(10_000L); + } + } + + + } + @Test public void scheduling() throws Exception { refreshService = new DefaultCredentialsRefreshService.DefaultCredentialsRefreshServiceBuilder() diff --git a/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java b/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java index 0870d4d92b..963adc7964 100644 --- a/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java +++ b/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java @@ -21,7 +21,9 @@ import com.rabbitmq.client.impl.DefaultCredentialsRefreshService; import com.rabbitmq.client.impl.RefreshProtectedCredentialsProvider; import org.junit.Before; +import org.junit.ClassRule; import org.junit.Test; +import org.junit.rules.TestRule; import java.time.Duration; import java.time.Instant; @@ -33,6 +35,8 @@ public class RefreshCredentialsTest { + @ClassRule + public static TestRule brokerVersionTestRule = TestUtils.atLeast38(); DefaultCredentialsRefreshService refreshService; @Before diff --git a/src/test/java/com/rabbitmq/client/test/TestUtils.java b/src/test/java/com/rabbitmq/client/test/TestUtils.java index 21b1f542ad..e2890ab4bc 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtils.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtils.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2019 Pivotal Software, Inc. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 @@ -15,19 +15,14 @@ package com.rabbitmq.client.test; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.ConnectionFactory; -import com.rabbitmq.client.DefaultConsumer; -import com.rabbitmq.client.Envelope; -import com.rabbitmq.client.Recoverable; -import com.rabbitmq.client.RecoverableConnection; -import com.rabbitmq.client.RecoveryListener; -import com.rabbitmq.client.ShutdownSignalException; +import com.rabbitmq.client.*; import com.rabbitmq.client.impl.NetworkConnection; import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; import com.rabbitmq.tools.Host; +import org.junit.AssumptionViolatedException; +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; import org.slf4j.LoggerFactory; import javax.net.ssl.SSLContext; @@ -46,7 +41,7 @@ public class TestUtils { - public static final boolean USE_NIO = System.getProperty("use.nio") == null ? false : true; + public static final boolean USE_NIO = System.getProperty("use.nio") != null; public static ConnectionFactory connectionFactory() { ConnectionFactory connectionFactory = new ConnectionFactory(); @@ -79,7 +74,7 @@ public static SSLContext getSSLContext() throws NoSuchAlgorithmException { // pick the first protocol available, preferring TLSv1.2, then TLSv1, // falling back to SSLv3 if running on an ancient/crippled JDK - for(String proto : Arrays.asList("TLSv1.2", "TLSv1", "SSLv3")) { + for (String proto : Arrays.asList("TLSv1.2", "TLSv1", "SSLv3")) { try { c = SSLContext.getInstance(proto); return c; @@ -90,31 +85,49 @@ public static SSLContext getSSLContext() throws NoSuchAlgorithmException { throw new NoSuchAlgorithmException(); } + public static TestRule atLeast38() { + return new BrokerVersionTestRule("3.8.0"); + } + public static boolean isVersion37orLater(Connection connection) { + return atLeastVersion("3.7.0", connection); + } + + public static boolean isVersion38orLater(Connection connection) { + return atLeastVersion("3.8.0", connection); + } + + private static boolean atLeastVersion(String expectedVersion, Connection connection) { String currentVersion = null; try { - currentVersion = connection.getServerProperties().get("version").toString(); - // versions built from source: 3.7.0+rc.1.4.gedc5d96 - if (currentVersion.contains("+")) { - currentVersion = currentVersion.substring(0, currentVersion.indexOf("+")); - } - // alpha (snapshot) versions: 3.7.0~alpha.449-1 - if (currentVersion.contains("~")) { - currentVersion = currentVersion.substring(0, currentVersion.indexOf("~")); - } - // alpha (snapshot) versions: 3.7.1-alpha.40 - if (currentVersion.contains("-")) { - currentVersion = currentVersion.substring(0, currentVersion.indexOf("-")); - } - return "0.0.0".equals(currentVersion) || versionCompare(currentVersion, "3.7.0") >= 0; + currentVersion = currentVersion( + connection.getServerProperties().get("version").toString() + ); + return "0.0.0".equals(currentVersion) || versionCompare(currentVersion, expectedVersion) >= 0; } catch (RuntimeException e) { LoggerFactory.getLogger(TestUtils.class).warn("Unable to parse broker version {}", currentVersion, e); throw e; } } + private static String currentVersion(String currentVersion) { + // versions built from source: 3.7.0+rc.1.4.gedc5d96 + if (currentVersion.contains("+")) { + currentVersion = currentVersion.substring(0, currentVersion.indexOf("+")); + } + // alpha (snapshot) versions: 3.7.0~alpha.449-1 + if (currentVersion.contains("~")) { + currentVersion = currentVersion.substring(0, currentVersion.indexOf("~")); + } + // alpha (snapshot) versions: 3.7.1-alpha.40 + if (currentVersion.contains("-")) { + currentVersion = currentVersion.substring(0, currentVersion.indexOf("-")); + } + return currentVersion; + } + public static boolean sendAndConsumeMessage(String exchange, String routingKey, String queue, Connection c) - throws IOException, TimeoutException, InterruptedException { + throws IOException, TimeoutException, InterruptedException { Channel ch = c.createChannel(); try { ch.confirmSelect(); @@ -249,4 +262,28 @@ public static int randomNetworkPort() throws IOException { socket.close(); return port; } + + private static class BrokerVersionTestRule implements TestRule { + + private final String version; + + public BrokerVersionTestRule(String version) { + this.version = version; + } + + @Override + public Statement apply(Statement base, Description description) { + return new Statement() { + @Override + public void evaluate() throws Throwable { + try (Connection c = TestUtils.connectionFactory().newConnection()) { + if (!TestUtils.atLeastVersion(version, c)) { + throw new AssumptionViolatedException("Broker version < " + version + ", skipping."); + } + } + base.evaluate(); + } + }; + } + } } diff --git a/src/test/java/com/rabbitmq/client/test/TestUtilsTest.java b/src/test/java/com/rabbitmq/client/test/TestUtilsTest.java index 379196a6d0..00374f3a4e 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtilsTest.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtilsTest.java @@ -43,4 +43,23 @@ public void isVersion37orLater() { serverProperties.put("version", "3.7.1-alpha.40"); assertThat(TestUtils.isVersion37orLater(connection), is(true)); } + + @Test + public void isVersion38orLater() { + Map serverProperties = new HashMap<>(); + Connection connection = mock(Connection.class); + when(connection.getServerProperties()).thenReturn(serverProperties); + + serverProperties.put("version", "3.7.0+rc.1.4.gedc5d96"); + assertThat(TestUtils.isVersion38orLater(connection), is(false)); + + serverProperties.put("version", "3.7.0~alpha.449-1"); + assertThat(TestUtils.isVersion38orLater(connection), is(false)); + + serverProperties.put("version", "3.7.1-alpha.40"); + assertThat(TestUtils.isVersion38orLater(connection), is(false)); + + serverProperties.put("version", "3.8.0+beta.4.38.g33a7f97"); + assertThat(TestUtils.isVersion38orLater(connection), is(true)); + } } From 7b50067c9a23412a7a156acf9d1dfe7fb45db778 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 4 Jul 2019 14:32:34 +0200 Subject: [PATCH 1143/2114] Remove some OAuth 2 integration tests They were supposed to be manual tests. --- .../DefaultCredentialsRefreshServiceTest.java | 57 +------------------ 1 file changed, 2 insertions(+), 55 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java b/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java index 0fa8e7ca72..5a1518610d 100644 --- a/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java +++ b/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java @@ -15,10 +15,6 @@ package com.rabbitmq.client.impl; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.ConnectionFactory; -import com.rabbitmq.client.test.TestUtils; import org.junit.After; import org.junit.Test; import org.junit.runner.RunWith; @@ -26,7 +22,6 @@ import org.mockito.junit.MockitoJUnitRunner; import org.mockito.stubbing.Answer; -import java.io.IOException; import java.time.Duration; import java.util.List; import java.util.concurrent.Callable; @@ -37,7 +32,8 @@ import java.util.function.Function; import java.util.stream.IntStream; -import static com.rabbitmq.client.impl.DefaultCredentialsRefreshService.*; +import static com.rabbitmq.client.impl.DefaultCredentialsRefreshService.fixedDelayBeforeExpirationRefreshDelayStrategy; +import static com.rabbitmq.client.impl.DefaultCredentialsRefreshService.fixedTimeNeedRefreshStrategy; import static java.time.Duration.ofSeconds; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.*; @@ -60,55 +56,6 @@ public void tearDown() { } } - @Test public void renew() { - ConnectionFactory cf = new ConnectionFactory(); - OAuth2ClientCredentialsGrantCredentialsProvider provider = new OAuth2ClientCredentialsGrantCredentialsProvider.OAuth2ClientCredentialsGrantCredentialsProviderBuilder() - .tokenEndpointUri("http://localhost:" + 8080 + "/uaa/oauth/token") - .clientId("rabbit_client").clientSecret("rabbit_secret") - .grantType("password") - .parameter("username", "rabbit_super") - .parameter("password", "rabbit_super") - .build(); - cf.setCredentialsProvider(provider); - - - } - - @Test public void connect() throws Exception { - ConnectionFactory cf = new ConnectionFactory(); - OAuth2ClientCredentialsGrantCredentialsProvider provider = new OAuth2ClientCredentialsGrantCredentialsProvider.OAuth2ClientCredentialsGrantCredentialsProviderBuilder() - .tokenEndpointUri("http://localhost:" + 8080 + "/uaa/oauth/token") - .clientId("rabbit_client").clientSecret("rabbit_secret") - .grantType("password") - .parameter("username", "rabbit_super") - .parameter("password", "rabbit_super") - .build(); - cf.setCredentialsProvider(provider); - refreshService = new DefaultCredentialsRefreshService.DefaultCredentialsRefreshServiceBuilder() -// .refreshDelayStrategy(ttl -> Duration.ofSeconds(60)) - .refreshDelayStrategy(ratioRefreshDelayStrategy(0.8)) - .needRefreshStrategy(expiration -> false) - .build(); - cf.setCredentialsRefreshService(refreshService); - try (Connection c = cf.newConnection()) { - - while (true) { - try { - Channel ch = c.createChannel(); - String queue = ch.queueDeclare().getQueue(); - TestUtils.sendAndConsumeMessage("", queue, queue, c); - System.out.println("Message sent and consumed"); - ch.close(); - } catch (IOException e) { - System.out.println(e.getCause().getMessage()); - } - Thread.sleep(10_000L); - } - } - - - } - @Test public void scheduling() throws Exception { refreshService = new DefaultCredentialsRefreshService.DefaultCredentialsRefreshServiceBuilder() From 77951bc2a5a8dad2488c5a3ffb41c99b5208f570 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 4 Jul 2019 17:52:26 +0200 Subject: [PATCH 1144/2114] Handle credentials refresh error [#167029587] --- .../rabbitmq/client/impl/AMQConnection.java | 21 ++- .../AMQConnectionRefreshCredentialsTest.java | 173 ++++++++++++++++++ .../com/rabbitmq/client/test/ClientTests.java | 6 +- 3 files changed, 190 insertions(+), 10 deletions(-) create mode 100644 src/test/java/com/rabbitmq/client/impl/AMQConnectionRefreshCredentialsTest.java diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index eac4553647..b8f2256502 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -243,11 +243,7 @@ public AMQConnection(ConnectionParams params, FrameHandler frameHandler, Metrics this.credentialsRefreshService = params.getCredentialsRefreshService(); - this._channel0 = new AMQChannel(this, 0) { - @Override public boolean processAsync(Command c) throws IOException { - return getConnection().processControlCommand(c); - } - }; + this._channel0 = createChannel0(); this._channelManager = null; @@ -262,6 +258,14 @@ public AMQConnection(ConnectionParams params, FrameHandler frameHandler, Metrics this.workPoolTimeout = params.getWorkPoolTimeout(); } + AMQChannel createChannel0() { + return new AMQChannel(this, 0) { + @Override public boolean processAsync(Command c) throws IOException { + return getConnection().processControlCommand(c); + } + }; + } + private void initializeConsumerWorkService() { this._workService = new ConsumerWorkService(consumerWorkServiceExecutor, threadFactory, workPoolTimeout, shutdownTimeout); } @@ -438,7 +442,12 @@ public void start() AMQImpl.Connection.UpdateSecret updateSecret = new AMQImpl.Connection.UpdateSecret( LongStringHelper.asLongString(refreshedPassword), "Refresh scheduled by client" ); - _channel0.rpc(updateSecret); + try { + _channel0.rpc(updateSecret); + } catch (ShutdownSignalException e) { + LOGGER.warn("Error while trying to update secret: {}. Connection has been closed.", e.getMessage()); + return false; + } return true; }); diff --git a/src/test/java/com/rabbitmq/client/impl/AMQConnectionRefreshCredentialsTest.java b/src/test/java/com/rabbitmq/client/impl/AMQConnectionRefreshCredentialsTest.java new file mode 100644 index 0000000000..d0978e1e61 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/impl/AMQConnectionRefreshCredentialsTest.java @@ -0,0 +1,173 @@ +// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl; + +import com.rabbitmq.client.Method; +import com.rabbitmq.client.*; +import com.rabbitmq.client.test.TestUtils; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.rules.TestRule; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import java.io.IOException; +import java.time.Duration; +import java.util.UUID; +import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.*; + +@RunWith(MockitoJUnitRunner.class) +public class AMQConnectionRefreshCredentialsTest { + + @ClassRule + public static TestRule brokerVersionTestRule = TestUtils.atLeast38(); + + @Mock + CredentialsProvider credentialsProvider; + + @Mock + CredentialsRefreshService refreshService; + + private static ConnectionFactory connectionFactoryThatSendsGarbageAfterUpdateSecret() { + ConnectionFactory cf = new ConnectionFactory() { + @Override + protected AMQConnection createConnection(ConnectionParams params, FrameHandler frameHandler, MetricsCollector metricsCollector) { + return new AMQConnection(params, frameHandler, metricsCollector) { + + @Override + AMQChannel createChannel0() { + return new AMQChannel(this, 0) { + @Override + public boolean processAsync(Command c) throws IOException { + return getConnection().processControlCommand(c); + } + + @Override + public AMQCommand rpc(Method m) throws IOException, ShutdownSignalException { + if (m instanceof AMQImpl.Connection.UpdateSecret) { + super.rpc(m); + return super.rpc(new AMQImpl.Connection.UpdateSecret(LongStringHelper.asLongString(""), "Refresh scheduled by client") { + @Override + public int protocolMethodId() { + return 255; + } + }); + } else { + return super.rpc(m); + } + + } + }; + + } + }; + } + }; + cf.setAutomaticRecoveryEnabled(false); + if (TestUtils.USE_NIO) { + cf.useNio(); + } + return cf; + } + + @Test + @SuppressWarnings("unchecked") + public void connectionIsUnregisteredFromRefreshServiceWhenClosed() throws Exception { + when(credentialsProvider.getUsername()).thenReturn("guest"); + when(credentialsProvider.getPassword()).thenReturn("guest"); + when(credentialsProvider.getTimeBeforeExpiration()).thenReturn(Duration.ofSeconds(10)); + + ConnectionFactory cf = TestUtils.connectionFactory(); + cf.setCredentialsProvider(credentialsProvider); + + String registrationId = UUID.randomUUID().toString(); + CountDownLatch unregisteredLatch = new CountDownLatch(1); + + AtomicReference> refreshTokenCallable = new AtomicReference<>(); + when(refreshService.register(eq(credentialsProvider), any(Callable.class))).thenAnswer(invocation -> { + refreshTokenCallable.set(invocation.getArgument(1)); + return registrationId; + }); + doAnswer(invocation -> { + unregisteredLatch.countDown(); + return null; + }).when(refreshService).unregister(credentialsProvider, registrationId); + + cf.setCredentialsRefreshService(refreshService); + + verify(refreshService, never()).register(any(CredentialsProvider.class), any(Callable.class)); + try (Connection c = cf.newConnection()) { + verify(refreshService, times(1)).register(eq(credentialsProvider), any(Callable.class)); + Channel ch = c.createChannel(); + String queue = ch.queueDeclare().getQueue(); + TestUtils.sendAndConsumeMessage("", queue, queue, c); + verify(refreshService, never()).unregister(any(CredentialsProvider.class), anyString()); + // calling refresh + assertThat(refreshTokenCallable.get().call()).isTrue(); + } + verify(refreshService, times(1)).register(eq(credentialsProvider), any(Callable.class)); + assertThat(unregisteredLatch.await(5, TimeUnit.SECONDS)).isTrue(); + verify(refreshService, times(1)).unregister(credentialsProvider, registrationId); + } + + @Test + @SuppressWarnings("unchecked") + public void connectionIsUnregisteredFromRefreshServiceIfUpdateSecretFails() throws Exception { + when(credentialsProvider.getUsername()).thenReturn("guest"); + when(credentialsProvider.getPassword()).thenReturn("guest"); + when(credentialsProvider.getTimeBeforeExpiration()).thenReturn(Duration.ofSeconds(10)); + + ConnectionFactory cf = connectionFactoryThatSendsGarbageAfterUpdateSecret(); + cf.setCredentialsProvider(credentialsProvider); + + String registrationId = UUID.randomUUID().toString(); + CountDownLatch unregisteredLatch = new CountDownLatch(1); + AtomicReference> refreshTokenCallable = new AtomicReference<>(); + when(refreshService.register(eq(credentialsProvider), any(Callable.class))).thenAnswer(invocation -> { + refreshTokenCallable.set(invocation.getArgument(1)); + return registrationId; + }); + doAnswer(invocation -> { + unregisteredLatch.countDown(); + return null; + }).when(refreshService).unregister(credentialsProvider, registrationId); + + cf.setCredentialsRefreshService(refreshService); + + Connection c = cf.newConnection(); + verify(refreshService, times(1)).register(eq(credentialsProvider), any(Callable.class)); + Channel ch = c.createChannel(); + String queue = ch.queueDeclare().getQueue(); + TestUtils.sendAndConsumeMessage("", queue, queue, c); + verify(refreshService, never()).unregister(any(CredentialsProvider.class), anyString()); + + verify(refreshService, never()).unregister(any(CredentialsProvider.class), anyString()); + // calling refresh, this sends garbage and should make the broker close the connection + assertThat(refreshTokenCallable.get().call()).isFalse(); + assertThat(unregisteredLatch.await(5, TimeUnit.SECONDS)).isTrue(); + verify(refreshService, times(1)).unregister(credentialsProvider, registrationId); + assertThat(c.isOpen()).isFalse(); + } +} diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index 78d4f10c65..34e9436c3d 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -17,10 +17,7 @@ package com.rabbitmq.client.test; import com.rabbitmq.client.JacksonJsonRpcTest; -import com.rabbitmq.client.impl.DefaultCredentialsRefreshServiceTest; -import com.rabbitmq.client.impl.OAuth2ClientCredentialsGrantCredentialsProviderTest; -import com.rabbitmq.client.impl.RefreshProtectedCredentialsProviderTest; -import com.rabbitmq.client.impl.ValueWriterTest; +import com.rabbitmq.client.impl.*; import com.rabbitmq.utility.IntAllocatorTests; import org.junit.runner.RunWith; @@ -78,6 +75,7 @@ DefaultCredentialsRefreshServiceTest.class, OAuth2ClientCredentialsGrantCredentialsProviderTest.class, RefreshCredentialsTest.class, + AMQConnectionRefreshCredentialsTest.class, ValueWriterTest.class }) public class ClientTests { From 1c7b21c5f5f5f93e4ae5884269b5702c2ae38558 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 5 Jul 2019 10:47:45 +0200 Subject: [PATCH 1145/2114] Document credentials refresh service [#167029587] --- .../rabbitmq/client/ConnectionFactory.java | 28 +++++++++++-------- .../rabbitmq/client/impl/AMQConnection.java | 3 ++ 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 4f8948ae5b..ebbdae3890 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -32,17 +32,8 @@ import java.net.URLDecoder; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.TimeoutException; +import java.util.*; +import java.util.concurrent.*; import java.util.function.Predicate; import static java.util.concurrent.TimeUnit.MINUTES; @@ -848,6 +839,21 @@ public MetricsCollector getMetricsCollector() { return metricsCollector; } + /** + * Set a {@link CredentialsRefreshService} instance to handle credentials refresh if appropriate. + *

+ * Each created connection will register to the refresh service to send an AMQP update.secret + * frame when credentials are about to expire. This is the refresh service responsibility to schedule + * credentials refresh and udpate.secret frame sending, based on the information provided + * by the {@link CredentialsProvider}. + *

+ * Note the {@link CredentialsRefreshService} is used only when the {@link CredentialsProvider} + * signals credentials can expire, by returning a non-null value from {@link CredentialsProvider#getTimeBeforeExpiration()}. + * + * @param credentialsRefreshService the refresh service to use + * @see #setCredentialsProvider(CredentialsProvider) + * @see DefaultCredentialsRefreshService + */ public void setCredentialsRefreshService(CredentialsRefreshService credentialsRefreshService) { this.credentialsRefreshService = credentialsRefreshService; } diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index b8f2256502..09d8d53203 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -346,6 +346,9 @@ public void start() String password = credentialsProvider.getPassword(); if (credentialsProvider.getTimeBeforeExpiration() != null) { + if (this.credentialsRefreshService == null) { + throw new IllegalStateException("Credentials can expire, a credentials refresh service should be set"); + } if (this.credentialsRefreshService.needRefresh(credentialsProvider.getTimeBeforeExpiration())) { credentialsProvider.refresh(); username = credentialsProvider.getUsername(); From 7dc7170ce0562cce0891f2f62f9c1258cfc52074 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 8 Jul 2019 15:01:51 +0200 Subject: [PATCH 1146/2114] Rename CredentialsRefreshService#needRefresh to isApproachingExpiration [#167029587] --- .../rabbitmq/client/impl/AMQConnection.java | 2 +- .../impl/CredentialsRefreshService.java | 8 ++- .../DefaultCredentialsRefreshService.java | 72 ++++++++++++++----- .../DefaultCredentialsRefreshServiceTest.java | 6 +- .../client/test/RefreshCredentialsTest.java | 2 +- 5 files changed, 66 insertions(+), 24 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index 09d8d53203..027d380acb 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -349,7 +349,7 @@ public void start() if (this.credentialsRefreshService == null) { throw new IllegalStateException("Credentials can expire, a credentials refresh service should be set"); } - if (this.credentialsRefreshService.needRefresh(credentialsProvider.getTimeBeforeExpiration())) { + if (this.credentialsRefreshService.isApproachingExpiration(credentialsProvider.getTimeBeforeExpiration())) { credentialsProvider.refresh(); username = credentialsProvider.getUsername(); password = credentialsProvider.getPassword(); diff --git a/src/main/java/com/rabbitmq/client/impl/CredentialsRefreshService.java b/src/main/java/com/rabbitmq/client/impl/CredentialsRefreshService.java index 2e6065336e..675fa8fe1b 100644 --- a/src/main/java/com/rabbitmq/client/impl/CredentialsRefreshService.java +++ b/src/main/java/com/rabbitmq/client/impl/CredentialsRefreshService.java @@ -63,11 +63,15 @@ public interface CredentialsRefreshService { void unregister(CredentialsProvider credentialsProvider, String registrationId); /** - * Provide a hint about whether credentials should be renewed. + * Provide a hint about whether credentials should be renewed now or not before attempting to connect. + *

+ * This can avoid a connection to use almost expired credentials if this connection + * is created just before credentials are refreshed in the background, but does not + * benefit from the refresh. * * @param timeBeforeExpiration * @return true if credentials should be renewed, false otherwise */ - boolean needRefresh(Duration timeBeforeExpiration); + boolean isApproachingExpiration(Duration timeBeforeExpiration); } diff --git a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java index 032a94c779..39d6db1fda 100644 --- a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java +++ b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java @@ -44,19 +44,57 @@ public class DefaultCredentialsRefreshService implements CredentialsRefreshServi private static final Logger LOGGER = LoggerFactory.getLogger(DefaultCredentialsRefreshService.class); + /** + * Scheduler used to schedule credentials refresh. + *

+ * Default is a single-threaded scheduler, which should be enough for most scenarios, assuming + * that credentials expire after a few minutes or hours. This default scheduler + * is automatically disposed of when the {@link DefaultCredentialsRefreshService} is closed. + *

+ * If an external scheduler is passed in, it is the developer's responsibility to + * close it. + */ private final ScheduledExecutorService scheduler; private final ConcurrentMap credentialsProviderStates = new ConcurrentHashMap<>(); private final boolean privateScheduler; + /** + * Strategy to schedule credentials refresh after credentials retrieval. + *

+ * Typical strategies schedule refresh after a ratio of the time before expiration + * (e.g. 80 % of the time before expiration) or after a fixed time before + * expiration (e.g. 20 seconds before credentials expire). + * + * @see #ratioRefreshDelayStrategy(double) + * @see #fixedDelayBeforeExpirationRefreshDelayStrategy(Duration) + */ private final Function refreshDelayStrategy; - private final Function needRefreshStrategy; + /** + * Strategy to provide a hint about whether credentials should be renewed now or not before attempting to connect. + *

+ * This can avoid a connection to use almost expired credentials if this connection + * is created just before credentials are refreshed in the background, but does not + * benefit from the refresh. + *

+ * Note setting such a strategy may require knowledge of the credentials validity and must be consistent + * with the {@link #refreshDelayStrategy} chosen. For example, for a validity of 60 minutes and + * a {@link #refreshDelayStrategy} that instructs to refresh 10 minutes before credentials expire, this + * strategy could hint that credentials that expire in 11 minutes or less (1 minute before a refresh is actually + * scheduled) should be refreshed, which would trigger an early refresh. + *

+ * The default strategy always return false. + */ + private final Function approachingExpirationStrategy; - public DefaultCredentialsRefreshService(ScheduledExecutorService scheduler, Function refreshDelayStrategy, Function needRefreshStrategy) { + public DefaultCredentialsRefreshService(ScheduledExecutorService scheduler, Function refreshDelayStrategy, Function approachingExpirationStrategy) { + if (refreshDelayStrategy == null) { + throw new IllegalArgumentException("Refresh delay strategy can not be null"); + } this.refreshDelayStrategy = refreshDelayStrategy; - this.needRefreshStrategy = needRefreshStrategy; + this.approachingExpirationStrategy = approachingExpirationStrategy == null ? duration -> false : approachingExpirationStrategy; if (scheduler == null) { this.scheduler = Executors.newScheduledThreadPool(1); privateScheduler = true; @@ -69,8 +107,8 @@ public DefaultCredentialsRefreshService(ScheduledExecutorService scheduler, Func /** * Delay before refresh is a ratio of the time before expiration. *

- * E.g. if time before expiration is 60 seconds and specified ratio is 0.8, refresh will - * be scheduled in 60 x 0.8 = 48 seconds. + * E.g. if time before expiration is 60 minutes and specified ratio is 0.8, refresh will + * be scheduled in 60 x 0.8 = 48 minutes. * * @param ratio * @return the delay before refreshing @@ -82,8 +120,8 @@ public static Function ratioRefreshDelayStrategy(double rati /** * Delay before refresh is time before expiration - specified duration. *

- * E.g. if time before expiration is 60 seconds and specified duration is 20 seconds, refresh will - * be scheduled in 60 - 20 = 40 seconds. + * E.g. if time before expiration is 60 minutes and specified duration is 10 minutes, refresh will + * be scheduled in 60 - 10 = 50 minutes. * * @param duration * @return the delay before refreshing @@ -98,8 +136,8 @@ public static Function fixedDelayBeforeExpirationRefreshDela * @param limitBeforeExpiration * @return true if credentials should be refreshed, false otherwise */ - public static Function fixedTimeNeedRefreshStrategy(Duration limitBeforeExpiration) { - return new FixedTimeNeedRefreshStrategy(limitBeforeExpiration.toMillis()); + public static Function fixedTimeApproachingExpirationStrategy(Duration limitBeforeExpiration) { + return new FixedTimeApproachingExpirationStrategy(limitBeforeExpiration.toMillis()); } private static Runnable refresh(ScheduledExecutorService scheduler, CredentialsProviderState credentialsProviderState, @@ -157,8 +195,8 @@ public void unregister(CredentialsProvider credentialsProvider, String registrat } @Override - public boolean needRefresh(Duration timeBeforeExpiration) { - return this.needRefreshStrategy.apply(timeBeforeExpiration); + public boolean isApproachingExpiration(Duration timeBeforeExpiration) { + return this.approachingExpirationStrategy.apply(timeBeforeExpiration); } public void close() { @@ -167,11 +205,11 @@ public void close() { } } - private static class FixedTimeNeedRefreshStrategy implements Function { + private static class FixedTimeApproachingExpirationStrategy implements Function { private final long limitBeforeExpiration; - private FixedTimeNeedRefreshStrategy(long limitBeforeExpiration) { + private FixedTimeApproachingExpirationStrategy(long limitBeforeExpiration) { this.limitBeforeExpiration = limitBeforeExpiration; } @@ -340,7 +378,7 @@ public static class DefaultCredentialsRefreshServiceBuilder { private Function refreshDelayStrategy = ratioRefreshDelayStrategy(0.8); - private Function needRefreshStrategy = ttl -> false; + private Function approachingExpirationStrategy = ttl -> false; public DefaultCredentialsRefreshServiceBuilder scheduler(ScheduledThreadPoolExecutor scheduler) { this.scheduler = scheduler; @@ -352,13 +390,13 @@ public DefaultCredentialsRefreshServiceBuilder refreshDelayStrategy(Function needRefreshStrategy) { - this.needRefreshStrategy = needRefreshStrategy; + public DefaultCredentialsRefreshServiceBuilder approachingExpirationStrategy(Function approachingExpirationStrategy) { + this.approachingExpirationStrategy = approachingExpirationStrategy; return this; } public DefaultCredentialsRefreshService build() { - return new DefaultCredentialsRefreshService(scheduler, refreshDelayStrategy, needRefreshStrategy); + return new DefaultCredentialsRefreshService(scheduler, refreshDelayStrategy, approachingExpirationStrategy); } } diff --git a/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java b/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java index 5a1518610d..7009319b9c 100644 --- a/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java +++ b/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java @@ -33,7 +33,7 @@ import java.util.stream.IntStream; import static com.rabbitmq.client.impl.DefaultCredentialsRefreshService.fixedDelayBeforeExpirationRefreshDelayStrategy; -import static com.rabbitmq.client.impl.DefaultCredentialsRefreshService.fixedTimeNeedRefreshStrategy; +import static com.rabbitmq.client.impl.DefaultCredentialsRefreshService.fixedTimeApproachingExpirationStrategy; import static java.time.Duration.ofSeconds; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.*; @@ -232,8 +232,8 @@ public void fixedDelayBeforeExpirationRefreshDelayStrategyTest() { } @Test - public void fixedTimeNeedRefreshStrategyTest() { - Function refreshStrategy = fixedTimeNeedRefreshStrategy(ofSeconds(20)); + public void fixedTimeApproachingExpirationStrategyTest() { + Function refreshStrategy = fixedTimeApproachingExpirationStrategy(ofSeconds(20)); assertThat(refreshStrategy.apply(ofSeconds(60))).isFalse(); assertThat(refreshStrategy.apply(ofSeconds(20))).isTrue(); assertThat(refreshStrategy.apply(ofSeconds(19))).isTrue(); diff --git a/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java b/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java index 963adc7964..defa0c4b4f 100644 --- a/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java +++ b/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java @@ -76,7 +76,7 @@ protected Duration timeBeforeExpiration(TestToken token) { cf.setCredentialsProvider(provider); refreshService = new DefaultCredentialsRefreshService.DefaultCredentialsRefreshServiceBuilder() .refreshDelayStrategy(DefaultCredentialsRefreshService.fixedDelayBeforeExpirationRefreshDelayStrategy(Duration.ofSeconds(1))) - .needRefreshStrategy(expiration -> false) + .approachingExpirationStrategy(expiration -> false) .build(); cf.setCredentialsRefreshService(refreshService); From 09f5320787594d64ee5cf6a79d9f488f90feefa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 8 Jul 2019 17:25:26 +0200 Subject: [PATCH 1147/2114] Document OAuth 2 credentials provider [#167029587] --- ...ntCredentialsGrantCredentialsProvider.java | 275 ++++++++++++++++-- ...edentialsGrantCredentialsProviderTest.java | 2 +- 2 files changed, 257 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java index 21d6961ac5..090bcfa675 100644 --- a/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java @@ -16,21 +16,24 @@ package com.rabbitmq.client.impl; import com.fasterxml.jackson.databind.ObjectMapper; +import com.rabbitmq.client.TrustEverythingTrustManager; -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.*; import java.io.*; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; import java.time.Duration; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.*; import java.util.function.Consumer; +import static com.rabbitmq.client.ConnectionFactory.computeDefaultTlsProtocol; + /** * A {@link CredentialsProvider} that performs an * OAuth 2 Client Credentials flow @@ -47,13 +50,17 @@ * to deserialize the response into a {@link Token}. This can be changed by overriding the {@link #parseToken(String)} * method. *

- * TLS is supported by providing a HTTPS URI and setting the {@link HostnameVerifier} and {@link SSLSocketFactory}. + * TLS is supported by providing a HTTPS URI and setting a {@link SSLContext}. See + * {@link OAuth2ClientCredentialsGrantCredentialsProviderBuilder#tls()} for more information. + * Applications in production should always use HTTPS to retrieve tokens. *

* If more customization is needed, a {@link #connectionConfigurator} callback can be provided to configure * the connection. * * @see RefreshProtectedCredentialsProvider * @see CredentialsRefreshService + * @see OAuth2ClientCredentialsGrantCredentialsProviderBuilder + * @see OAuth2ClientCredentialsGrantCredentialsProviderBuilder#tls() */ public class OAuth2ClientCredentialsGrantCredentialsProvider extends RefreshProtectedCredentialsProvider { @@ -74,29 +81,89 @@ public class OAuth2ClientCredentialsGrantCredentialsProvider extends RefreshProt private final Consumer connectionConfigurator; + /** + * Use {@link OAuth2ClientCredentialsGrantCredentialsProviderBuilder} to create an instance. + * + * @param tokenEndpointUri + * @param clientId + * @param clientSecret + * @param grantType + */ public OAuth2ClientCredentialsGrantCredentialsProvider(String tokenEndpointUri, String clientId, String clientSecret, String grantType) { this(tokenEndpointUri, clientId, clientSecret, grantType, new HashMap<>()); } + /** + * Use {@link OAuth2ClientCredentialsGrantCredentialsProviderBuilder} to create an instance. + * + * @param tokenEndpointUri + * @param clientId + * @param clientSecret + * @param grantType + * @param parameters + */ public OAuth2ClientCredentialsGrantCredentialsProvider(String tokenEndpointUri, String clientId, String clientSecret, String grantType, Map parameters) { this(tokenEndpointUri, clientId, clientSecret, grantType, parameters, null, null, null); } + /** + * Use {@link OAuth2ClientCredentialsGrantCredentialsProviderBuilder} to create an instance. + * + * @param tokenEndpointUri + * @param clientId + * @param clientSecret + * @param grantType + * @param parameters + * @param connectionConfigurator + */ public OAuth2ClientCredentialsGrantCredentialsProvider(String tokenEndpointUri, String clientId, String clientSecret, String grantType, Map parameters, Consumer connectionConfigurator) { this(tokenEndpointUri, clientId, clientSecret, grantType, parameters, null, null, connectionConfigurator); } + /** + * Use {@link OAuth2ClientCredentialsGrantCredentialsProviderBuilder} to create an instance. + * + * @param tokenEndpointUri + * @param clientId + * @param clientSecret + * @param grantType + * @param hostnameVerifier + * @param sslSocketFactory + */ public OAuth2ClientCredentialsGrantCredentialsProvider(String tokenEndpointUri, String clientId, String clientSecret, String grantType, HostnameVerifier hostnameVerifier, SSLSocketFactory sslSocketFactory) { this(tokenEndpointUri, clientId, clientSecret, grantType, new HashMap<>(), hostnameVerifier, sslSocketFactory, null); } + /** + * Use {@link OAuth2ClientCredentialsGrantCredentialsProviderBuilder} to create an instance. + * + * @param tokenEndpointUri + * @param clientId + * @param clientSecret + * @param grantType + * @param parameters + * @param hostnameVerifier + * @param sslSocketFactory + */ public OAuth2ClientCredentialsGrantCredentialsProvider(String tokenEndpointUri, String clientId, String clientSecret, String grantType, Map parameters, HostnameVerifier hostnameVerifier, SSLSocketFactory sslSocketFactory) { this(tokenEndpointUri, clientId, clientSecret, grantType, parameters, hostnameVerifier, sslSocketFactory, null); } + /** + * Use {@link OAuth2ClientCredentialsGrantCredentialsProviderBuilder} to create an instance. + * + * @param tokenEndpointUri + * @param clientId + * @param clientSecret + * @param grantType + * @param parameters + * @param hostnameVerifier + * @param sslSocketFactory + * @param connectionConfigurator + */ public OAuth2ClientCredentialsGrantCredentialsProvider(String tokenEndpointUri, String clientId, String clientSecret, String grantType, Map parameters, HostnameVerifier hostnameVerifier, SSLSocketFactory sslSocketFactory, Consumer connectionConfigurator) { @@ -117,13 +184,17 @@ private static StringBuilder encode(StringBuilder builder, String name, String v if (builder.length() > 0) { builder.append("&"); } - builder.append(URLEncoder.encode(name, UTF_8_CHARSET)) + builder.append(encode(name, UTF_8_CHARSET)) .append("=") - .append(URLEncoder.encode(value, UTF_8_CHARSET)); + .append(encode(value, UTF_8_CHARSET)); } return builder; } + private static String encode(String value, String charset) throws UnsupportedEncodingException { + return URLEncoder.encode(value, charset); + } + private static String basicAuthentication(String username, String password) { String credentials = username + ":" + password; byte[] credentialsAsBytes = credentials.getBytes(StandardCharsets.ISO_8859_1); @@ -297,6 +368,9 @@ public Duration getTimeBeforeExpiration() { } } + /** + * Helper to create {@link OAuth2ClientCredentialsGrantCredentialsProvider} instances. + */ public static class OAuth2ClientCredentialsGrantCredentialsProviderBuilder { private final Map parameters = new HashMap<>(); @@ -304,59 +378,222 @@ public static class OAuth2ClientCredentialsGrantCredentialsProviderBuilder { private String clientId; private String clientSecret; private String grantType = "client_credentials"; - private HostnameVerifier hostnameVerifier; - - private SSLSocketFactory sslSocketFactory; private Consumer connectionConfigurator; + private TlsConfiguration tlsConfiguration = new TlsConfiguration(this); + + /** + * Set the URI to request to get the token. + * + * @param tokenEndpointUri + * @return this builder instance + */ public OAuth2ClientCredentialsGrantCredentialsProviderBuilder tokenEndpointUri(String tokenEndpointUri) { this.tokenEndpointUri = tokenEndpointUri; return this; } + /** + * Set the OAuth 2 client ID + *

+ * The client ID usually identifies the application that requests a token. + * + * @param clientId + * @return this builder instance + */ public OAuth2ClientCredentialsGrantCredentialsProviderBuilder clientId(String clientId) { this.clientId = clientId; return this; } + /** + * Set the secret (password) to use to get a token. + * + * @param clientSecret + * @return this builder instance + */ public OAuth2ClientCredentialsGrantCredentialsProviderBuilder clientSecret(String clientSecret) { this.clientSecret = clientSecret; return this; } + /** + * Set the grant type to use when requesting the token. + *

+ * The default is client_credentials, but some OAuth 2 servers can use + * non-standard grant types to request tokens with extra-information. + * + * @param grantType + * @return this builder instance + */ public OAuth2ClientCredentialsGrantCredentialsProviderBuilder grantType(String grantType) { this.grantType = grantType; return this; } + /** + * Extra parameters to pass in the request. + *

+ * These parameters can be used by the OAuth 2 server to narrow down the identify of the user. + * + * @param name + * @param value + * @return this builder instance + */ public OAuth2ClientCredentialsGrantCredentialsProviderBuilder parameter(String name, String value) { this.parameters.put(name, value); return this; } - public OAuth2ClientCredentialsGrantCredentialsProviderBuilder setHostnameVerifier(HostnameVerifier hostnameVerifier) { + /** + * A hook to configure the {@link HttpURLConnection} before the request is sent. + *

+ * Can be used to configuration settings like timeouts. + * + * @param connectionConfigurator + * @return this builder instance + */ + public OAuth2ClientCredentialsGrantCredentialsProviderBuilder connectionConfigurator(Consumer connectionConfigurator) { + this.connectionConfigurator = connectionConfigurator; + return this; + } + + /** + * Get access to the TLS configuration to get the token on HTTPS. + *

+ * It is recommended that applications in production use HTTPS and configure it properly + * to perform token retrieval. Not doing so could result in sensitive data + * transiting in clear on the network. + *

+ * You can "exit" the TLS configuration and come back to the builder by + * calling {@link TlsConfiguration#builder()}. + * + * @return the TLS configuration for this builder. + * @see TlsConfiguration + * @see TlsConfiguration#builder() + */ + public TlsConfiguration tls() { + return this.tlsConfiguration; + } + + /** + * Create the {@link OAuth2ClientCredentialsGrantCredentialsProvider} instance. + * + * @return + */ + public OAuth2ClientCredentialsGrantCredentialsProvider build() { + return new OAuth2ClientCredentialsGrantCredentialsProvider( + tokenEndpointUri, clientId, clientSecret, grantType, parameters, + tlsConfiguration.hostnameVerifier, tlsConfiguration.sslSocketFactory(), + connectionConfigurator + ); + } + + } + + /** + * TLS configuration for a {@link OAuth2ClientCredentialsGrantCredentialsProvider}. + *

+ * Use it from {@link OAuth2ClientCredentialsGrantCredentialsProviderBuilder#tls()}. + */ + public static class TlsConfiguration { + + private final OAuth2ClientCredentialsGrantCredentialsProviderBuilder builder; + + private HostnameVerifier hostnameVerifier; + + private SSLSocketFactory sslSocketFactory; + + private SSLContext sslContext; + + public TlsConfiguration(OAuth2ClientCredentialsGrantCredentialsProviderBuilder builder) { + this.builder = builder; + } + + /** + * Set the hostname verifier. + *

+ * {@link HttpsURLConnection} sets a default hostname verifier, so + * setting a custom one is only needed for specific cases. + * + * @param hostnameVerifier + * @return this TLS configuration instance + * @see HostnameVerifier + */ + public TlsConfiguration hostnameVerifier(HostnameVerifier hostnameVerifier) { this.hostnameVerifier = hostnameVerifier; return this; } - public OAuth2ClientCredentialsGrantCredentialsProviderBuilder setSslSocketFactory(SSLSocketFactory sslSocketFactory) { + /** + * Set the {@link SSLSocketFactory} to use in the {@link HttpsURLConnection}. + *

+ * The {@link SSLSocketFactory} supersedes the {@link SSLContext} value if both are set up. + * + * @param sslSocketFactory + * @return this TLS configuration instance + */ + public TlsConfiguration sslSocketFactory(SSLSocketFactory sslSocketFactory) { this.sslSocketFactory = sslSocketFactory; return this; } - public OAuth2ClientCredentialsGrantCredentialsProviderBuilder setConnectionConfigurator(Consumer connectionConfigurator) { - this.connectionConfigurator = connectionConfigurator; + /** + * Set the {@link SSLContext} to use to create the {@link SSLSocketFactory} for the {@link HttpsURLConnection}. + *

+ * This is the preferred way to configure TLS version to use, trusted servers, etc. + *

+ * Note the {@link SSLContext} is not used if the {@link SSLSocketFactory} is set. + * + * @param sslContext + * @return this TLS configuration instances + */ + public TlsConfiguration sslContext(SSLContext sslContext) { + this.sslContext = sslContext; return this; } - public OAuth2ClientCredentialsGrantCredentialsProvider build() { - return new OAuth2ClientCredentialsGrantCredentialsProvider( - tokenEndpointUri, clientId, clientSecret, grantType, parameters, - hostnameVerifier, sslSocketFactory, - connectionConfigurator - ); + /** + * Set up a non-secured environment, useful for development and testing. + *

+ * With this configuration, all servers are trusted. + * + * DO NOT USE this in production. + * + * @return a TLS configuration that trusts all servers + */ + public TlsConfiguration dev() { + try { + SSLContext sslContext = SSLContext.getInstance(computeDefaultTlsProtocol( + SSLContext.getDefault().getSupportedSSLParameters().getProtocols() + )); + sslContext.init(null, new TrustManager[]{new TrustEverythingTrustManager()}, null); + this.sslContext = sslContext; + } catch (NoSuchAlgorithmException | KeyManagementException e) { + throw new OAuthTokenManagementException("Error while creating TLS context for development configuration", e); + } + return this; + } + + /** + * Go back to the builder to configure non-TLS settings. + * + * @return the wrapping builder + */ + public OAuth2ClientCredentialsGrantCredentialsProviderBuilder builder() { + return builder; + } + + private SSLSocketFactory sslSocketFactory() { + if (this.sslSocketFactory != null) { + return this.sslSocketFactory; + } else if (this.sslContext != null) { + return this.sslContext.getSocketFactory(); + } + return null; } } + } diff --git a/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java b/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java index 2cd19ee828..e1d1c5abbf 100644 --- a/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java +++ b/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java @@ -169,7 +169,7 @@ public void handle(String target, Request baseRequest, HttpServletRequest reques OAuth2ClientCredentialsGrantCredentialsProvider provider = new OAuth2ClientCredentialsGrantCredentialsProvider.OAuth2ClientCredentialsGrantCredentialsProviderBuilder() .tokenEndpointUri("https://localhost:" + port + "/uaa/oauth/token/") .clientId("rabbit_client").clientSecret("rabbit_secret") - .setSslSocketFactory(sslContext.getSocketFactory()) + .tls().sslContext(sslContext).builder() .build(); String password = provider.getPassword(); From a9e8e733572ed9acea116bd76cba0926e368b70e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 8 Jul 2019 17:47:03 +0200 Subject: [PATCH 1148/2114] Document DefaultCredentialsRefreshService [#167029587] --- .../DefaultCredentialsRefreshService.java | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java index 39d6db1fda..d74d749a0d 100644 --- a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java +++ b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java @@ -39,6 +39,8 @@ * by each entity/connection is performed. This callback typically propagates * the new credentials in the entity state, e.g. sending the new password to the * broker for AMQP connections. + *

+ * Instances are preferably created with {@link DefaultCredentialsRefreshServiceBuilder}. */ public class DefaultCredentialsRefreshService implements CredentialsRefreshService { @@ -89,6 +91,13 @@ public class DefaultCredentialsRefreshService implements CredentialsRefreshServi */ private final Function approachingExpirationStrategy; + /** + * Constructor. Consider using {@link DefaultCredentialsRefreshServiceBuilder} to create instances. + * + * @param scheduler + * @param refreshDelayStrategy + * @param approachingExpirationStrategy + */ public DefaultCredentialsRefreshService(ScheduledExecutorService scheduler, Function refreshDelayStrategy, Function approachingExpirationStrategy) { if (refreshDelayStrategy == null) { throw new IllegalArgumentException("Refresh delay strategy can not be null"); @@ -371,6 +380,9 @@ void unregister(String registrationId) { } } + /** + * Builder to create instances of {@link DefaultCredentialsRefreshServiceBuilder}. + */ public static class DefaultCredentialsRefreshServiceBuilder { @@ -385,16 +397,43 @@ public DefaultCredentialsRefreshServiceBuilder scheduler(ScheduledThreadPoolExec return this; } + /** + * Set the strategy to schedule credentials refresh after credentials retrieval. + *

+ * Default is a 80 % ratio-based strategy (refresh is scheduled after 80 % of the time + * before expiration, e.g. 48 minutes for a token with a validity of 60 minutes, that + * is refresh will be scheduled 12 minutes before the token actually expires). + * + * @param refreshDelayStrategy + * @return this builder instance + * @see DefaultCredentialsRefreshService#refreshDelayStrategy + * @see DefaultCredentialsRefreshService#ratioRefreshDelayStrategy(double) + */ public DefaultCredentialsRefreshServiceBuilder refreshDelayStrategy(Function refreshDelayStrategy) { this.refreshDelayStrategy = refreshDelayStrategy; return this; } + /** + * Set the strategy to trigger an early refresh before attempting to connect. + *

+ * Default is to never advise to refresh before connecting. + * + * @param approachingExpirationStrategy + * @return this builder instances + * @see DefaultCredentialsRefreshService#approachingExpirationStrategy + * @see CredentialsRefreshService#isApproachingExpiration(Duration) + */ public DefaultCredentialsRefreshServiceBuilder approachingExpirationStrategy(Function approachingExpirationStrategy) { this.approachingExpirationStrategy = approachingExpirationStrategy; return this; } + /** + * Create the {@link DefaultCredentialsRefreshService} instance. + * + * @return + */ public DefaultCredentialsRefreshService build() { return new DefaultCredentialsRefreshService(scheduler, refreshDelayStrategy, approachingExpirationStrategy); } From 851735de206c43872d0d099cfa6a8ff030ef5f11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 16 Jul 2019 10:27:35 +0200 Subject: [PATCH 1149/2114] Set log level to info for tests --- src/test/resources/logback-test.xml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml index 143b351b50..4bd2e37606 100644 --- a/src/test/resources/logback-test.xml +++ b/src/test/resources/logback-test.xml @@ -5,10 +5,6 @@ - - - - From ebddf5b43180e56e3077c439828dd2b53da91397 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 23 Jul 2019 11:04:11 +0200 Subject: [PATCH 1150/2114] Bump Jackson to 2.9.9.1 To address https://nvd.nist.gov/vuln/detail/CVE-2019-12814. Jackson is an optional dependency, necessary only when using JSON RPC. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a934277387..4347e68d84 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,7 @@ 1.7.26 4.1.0 1.2.0 - 2.9.9 + 2.9.9.1 1.2.3 4.12 3.1.6 From 9786a9e15ae590a63129f929abfb80eb21b40f38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 23 Jul 2019 11:06:01 +0200 Subject: [PATCH 1151/2114] Bump Mockito to 3.0.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4347e68d84..646ace9766 100644 --- a/pom.xml +++ b/pom.xml @@ -61,7 +61,7 @@ 1.2.3 4.12 3.1.6 - 2.28.2 + 3.0.0 3.12.2 9.4.19.v20190610 1.61 From ad6a703b40bf0e177180bb4ddf63c32d71485115 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 23 Jul 2019 11:04:11 +0200 Subject: [PATCH 1152/2114] Bump Jackson to 2.9.9.1 To address https://nvd.nist.gov/vuln/detail/CVE-2019-12814. Jackson is an optional dependency, necessary only when using JSON RPC. (cherry picked from commit ebddf5b43180e56e3077c439828dd2b53da91397) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c28cd1042f..2df45fc73d 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,7 @@ 1.7.26 4.1.0 1.2.0 - 2.9.9 + 2.9.9.1 1.2.3 4.12 3.1.6 From 969c0a71bc49d4f1ad49aebf33eaf81b33b8bae9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 23 Jul 2019 11:06:01 +0200 Subject: [PATCH 1153/2114] Bump Mockito to 3.0.0 (cherry picked from commit 9786a9e15ae590a63129f929abfb80eb21b40f38) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2df45fc73d..c242146ae0 100644 --- a/pom.xml +++ b/pom.xml @@ -61,7 +61,7 @@ 1.2.3 4.12 3.1.6 - 2.28.2 + 3.0.0 3.12.2 3.0.1 From cfdae67d9aee1c5bd105a78196baa0ae55a2bd39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 23 Jul 2019 15:59:49 +0200 Subject: [PATCH 1154/2114] Mention dependency management in JacksonJsonRpcMapper --- .../tools/jsonrpc/JacksonJsonRpcMapper.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java index 2b8b349b70..7a5d77337b 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2019 Pivotal Software, Inc. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 @@ -15,11 +15,7 @@ package com.rabbitmq.tools.jsonrpc; -import com.fasterxml.jackson.core.JsonFactory; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.core.JsonToken; -import com.fasterxml.jackson.core.TreeNode; +import com.fasterxml.jackson.core.*; import com.fasterxml.jackson.databind.MappingJsonFactory; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ValueNode; @@ -34,7 +30,14 @@ /** * {@link JsonRpcMapper} based on Jackson. - * Uses the streaming and databind modules. + *

+ * Uses the streaming and databind modules. You need to add the appropriate dependency + * to the classpath if you want to use this class, as the RabbitMQ Java client + * library does not pull Jackson automatically when using a dependency management + * tool like Maven or Gradle. + *

+ * Make sure to use the latest version of the Jackson library, as the version used in the + * RabbitMQ Java client can be a little bit behind. * * @see JsonRpcMapper * @since 5.4.0 From 5d9573c9993aefbae1bfde0a85a05db5e68ae9d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 23 Jul 2019 15:59:49 +0200 Subject: [PATCH 1155/2114] Mention dependency management in JacksonJsonRpcMapper (cherry picked from commit cfdae67d9aee1c5bd105a78196baa0ae55a2bd39) --- .../tools/jsonrpc/JacksonJsonRpcMapper.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java index 2b8b349b70..7a5d77337b 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2019 Pivotal Software, Inc. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 @@ -15,11 +15,7 @@ package com.rabbitmq.tools.jsonrpc; -import com.fasterxml.jackson.core.JsonFactory; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.core.JsonToken; -import com.fasterxml.jackson.core.TreeNode; +import com.fasterxml.jackson.core.*; import com.fasterxml.jackson.databind.MappingJsonFactory; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ValueNode; @@ -34,7 +30,14 @@ /** * {@link JsonRpcMapper} based on Jackson. - * Uses the streaming and databind modules. + *

+ * Uses the streaming and databind modules. You need to add the appropriate dependency + * to the classpath if you want to use this class, as the RabbitMQ Java client + * library does not pull Jackson automatically when using a dependency management + * tool like Maven or Gradle. + *

+ * Make sure to use the latest version of the Jackson library, as the version used in the + * RabbitMQ Java client can be a little bit behind. * * @see JsonRpcMapper * @since 5.4.0 From 9269ff67e9141935d315684a5f340ba6a3224df5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 13 Aug 2019 09:13:07 +0200 Subject: [PATCH 1156/2114] Bump Jackson to 2.9.9.3 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 646ace9766..542e6bdf4e 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,7 @@ 1.7.26 4.1.0 1.2.0 - 2.9.9.1 + 2.9.9.3 1.2.3 4.12 3.1.6 From 374d89fa4f5d604ecf775e014c77e0fe68d3eddf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 13 Aug 2019 09:13:07 +0200 Subject: [PATCH 1157/2114] Bump Jackson to 2.9.9.3 (cherry picked from commit 9269ff67e9141935d315684a5f340ba6a3224df5) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c242146ae0..f4b6319cb5 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,7 @@ 1.7.26 4.1.0 1.2.0 - 2.9.9.1 + 2.9.9.3 1.2.3 4.12 3.1.6 From e8c4adb0cc9b84935c3360e5d6baf81a788679f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 13 Aug 2019 09:23:10 +0200 Subject: [PATCH 1158/2114] Mention 5.7.3 and 4.11.3 in readme --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index cb414953b5..9bcd1593d9 100644 --- a/README.md +++ b/README.md @@ -23,14 +23,14 @@ They require Java 8 or higher. com.rabbitmq amqp-client - 5.7.2 + 5.7.3 ``` ### Gradle ``` groovy -compile 'com.rabbitmq:amqp-client:5.7.2' +compile 'com.rabbitmq:amqp-client:5.7.3' ``` #### 4.x Series @@ -42,14 +42,14 @@ They require Java 6 or higher. com.rabbitmq amqp-client - 4.11.2 + 4.11.3 ``` ### Gradle ``` groovy -compile 'com.rabbitmq:amqp-client:4.11.2' +compile 'com.rabbitmq:amqp-client:4.11.3' ``` From af44bfbf9f62259850011f5abff08975802557d4 Mon Sep 17 00:00:00 2001 From: Andrey Somov Date: Fri, 23 Aug 2019 00:16:59 +0300 Subject: [PATCH 1159/2114] Make instance variables in Frame private --- .../rabbitmq/client/impl/AMQConnection.java | 6 +++--- .../client/impl/CommandAssembler.java | 6 +++--- .../java/com/rabbitmq/client/impl/Frame.java | 13 +++++++++--- .../client/impl/nio/FrameBuilder.java | 2 +- .../client/test/BrokenFramesTest.java | 4 ++-- .../client/test/FrameBuilderTest.java | 12 +++++------ .../test/functional/UnexpectedFrames.java | 20 +++++++++---------- 7 files changed, 35 insertions(+), 28 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index 027d380acb..944a1a0a25 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -689,10 +689,10 @@ public boolean hasBrokerInitiatedShutdown() { private void readFrame(Frame frame) throws IOException { if (frame != null) { _missedHeartbeats = 0; - if (frame.type == AMQP.FRAME_HEARTBEAT) { + if (frame.getType() == AMQP.FRAME_HEARTBEAT) { // Ignore it: we've already just reset the heartbeat counter. } else { - if (frame.channel == 0) { // the special channel + if (frame.getChannel() == 0) { // the special channel _channel0.handleFrame(frame); } else { if (isOpen()) { @@ -705,7 +705,7 @@ private void readFrame(Frame frame) throws IOException { if (cm != null) { ChannelN channel; try { - channel = cm.getChannel(frame.channel); + channel = cm.getChannel(frame.getChannel()); } catch(UnknownChannelException e) { // this can happen if channel has been closed, // but there was e.g. an in-flight delivery. diff --git a/src/main/java/com/rabbitmq/client/impl/CommandAssembler.java b/src/main/java/com/rabbitmq/client/impl/CommandAssembler.java index da65cef8f2..0dbf1a25cd 100644 --- a/src/main/java/com/rabbitmq/client/impl/CommandAssembler.java +++ b/src/main/java/com/rabbitmq/client/impl/CommandAssembler.java @@ -88,7 +88,7 @@ private void updateContentBodyState() { } private void consumeMethodFrame(Frame f) throws IOException { - if (f.type == AMQP.FRAME_METHOD) { + if (f.getType() == AMQP.FRAME_METHOD) { this.method = AMQImpl.readMethodFrom(f.getInputStream()); this.state = this.method.hasContent() ? CAState.EXPECTING_CONTENT_HEADER : CAState.COMPLETE; } else { @@ -97,7 +97,7 @@ private void consumeMethodFrame(Frame f) throws IOException { } private void consumeHeaderFrame(Frame f) throws IOException { - if (f.type == AMQP.FRAME_HEADER) { + if (f.getType() == AMQP.FRAME_HEADER) { this.contentHeader = AMQImpl.readContentHeaderFrom(f.getInputStream()); this.remainingBodyBytes = this.contentHeader.getBodySize(); updateContentBodyState(); @@ -107,7 +107,7 @@ private void consumeHeaderFrame(Frame f) throws IOException { } private void consumeBodyFrame(Frame f) { - if (f.type == AMQP.FRAME_BODY) { + if (f.getType() == AMQP.FRAME_BODY) { byte[] fragment = f.getPayload(); this.remainingBodyBytes -= fragment.length; updateContentBodyState(); diff --git a/src/main/java/com/rabbitmq/client/impl/Frame.java b/src/main/java/com/rabbitmq/client/impl/Frame.java index a5fd59e454..39a12d5eb6 100644 --- a/src/main/java/com/rabbitmq/client/impl/Frame.java +++ b/src/main/java/com/rabbitmq/client/impl/Frame.java @@ -29,14 +29,13 @@ /** * Represents an AMQP wire-protocol frame, with frame type, channel number, and payload bytes. - * TODO: make state private */ public class Frame { /** Frame type code */ - public final int type; + private final int type; /** Frame channel number, 0-65535 */ - public final int channel; + private final int channel; /** Frame payload bytes (for inbound frames) */ private final byte[] payload; @@ -345,4 +344,12 @@ private static int shortStrSize(String str) { return str.getBytes("utf-8").length + 1; } + + public int getType() { + return type; + } + + public int getChannel() { + return channel; + } } diff --git a/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java b/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java index 5bb867899f..770bca63b6 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java @@ -59,7 +59,7 @@ public FrameBuilder(ReadableByteChannel channel, ByteBuffer buffer) { /** * Read a frame from the network. - * This method returns null f a frame could not have been fully built from + * This method returns null if a frame could not have been fully built from * the network. The client must then retry later (typically * when the channel notifies it has something to read). * diff --git a/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java b/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java index b9853a6731..6073c4b9f0 100644 --- a/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java +++ b/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java @@ -62,7 +62,7 @@ public class BrokenFramesTest { } catch (IOException e) { UnexpectedFrameError unexpectedFrameError = findUnexpectedFrameError(e); assertNotNull(unexpectedFrameError); - assertEquals(AMQP.FRAME_HEADER, unexpectedFrameError.getReceivedFrame().type); + assertEquals(AMQP.FRAME_HEADER, unexpectedFrameError.getReceivedFrame().getType()); assertEquals(AMQP.FRAME_METHOD, unexpectedFrameError.getExpectedFrameType()); return; } @@ -88,7 +88,7 @@ public class BrokenFramesTest { } catch (IOException e) { UnexpectedFrameError unexpectedFrameError = findUnexpectedFrameError(e); assertNotNull(unexpectedFrameError); - assertEquals(AMQP.FRAME_BODY, unexpectedFrameError.getReceivedFrame().type); + assertEquals(AMQP.FRAME_BODY, unexpectedFrameError.getReceivedFrame().getType()); assertEquals(AMQP.FRAME_HEADER, unexpectedFrameError.getExpectedFrameType()); return; } diff --git a/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java b/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java index ce71a779a7..3ed9f8596e 100644 --- a/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java +++ b/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java @@ -53,8 +53,8 @@ public void buildFrameInOneGo() throws IOException { builder = new FrameBuilder(channel, buffer); Frame frame = builder.readFrame(); assertThat(frame, notNullValue()); - assertThat(frame.type, is(1)); - assertThat(frame.channel, is(0)); + assertThat(frame.getType(), is(1)); + assertThat(frame.getChannel(), is(0)); assertThat(frame.getPayload().length, is(3)); } @@ -74,8 +74,8 @@ public void buildFramesInOneGo() throws IOException { Frame frame; while ((frame = builder.readFrame()) != null) { assertThat(frame, notNullValue()); - assertThat(frame.type, is(1)); - assertThat(frame.channel, is(0)); + assertThat(frame.getType(), is(1)); + assertThat(frame.getChannel(), is(0)); assertThat(frame.getPayload().length, is(3)); frameCount++; } @@ -95,8 +95,8 @@ public void buildFrameInSeveralCalls() throws IOException { frame = builder.readFrame(); assertThat(frame, notNullValue()); - assertThat(frame.type, is(1)); - assertThat(frame.channel, is(0)); + assertThat(frame.getType(), is(1)); + assertThat(frame.getChannel(), is(0)); assertThat(frame.getPayload().length, is(3)); } diff --git a/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java b/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java index 2599a7663c..80c5bce1e9 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java +++ b/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java @@ -101,7 +101,7 @@ public UnexpectedFrames() { @Test public void missingHeader() throws IOException { expectUnexpectedFrameError(new Confuser() { public Frame confuse(Frame frame) { - if (frame.type == AMQP.FRAME_HEADER) { + if (frame.getType() == AMQP.FRAME_HEADER) { return null; } return frame; @@ -112,11 +112,11 @@ public Frame confuse(Frame frame) { @Test public void missingMethod() throws IOException { expectUnexpectedFrameError(new Confuser() { public Frame confuse(Frame frame) { - if (frame.type == AMQP.FRAME_METHOD) { + if (frame.getType() == AMQP.FRAME_METHOD) { // We can't just skip the method as that will lead us to // send 0 bytes and hang waiting for a response. return new Frame(AMQP.FRAME_HEADER, - frame.channel, frame.getPayload()); + frame.getChannel(), frame.getPayload()); } return frame; } @@ -126,7 +126,7 @@ public Frame confuse(Frame frame) { @Test public void missingBody() throws IOException { expectUnexpectedFrameError(new Confuser() { public Frame confuse(Frame frame) { - if (frame.type == AMQP.FRAME_BODY) { + if (frame.getType() == AMQP.FRAME_BODY) { return null; } return frame; @@ -137,10 +137,10 @@ public Frame confuse(Frame frame) { @Test public void wrongClassInHeader() throws IOException { expectUnexpectedFrameError(new Confuser() { public Frame confuse(Frame frame) { - if (frame.type == AMQP.FRAME_HEADER) { + if (frame.getType() == AMQP.FRAME_HEADER) { byte[] payload = frame.getPayload(); Frame confusedFrame = new Frame(AMQP.FRAME_HEADER, - frame.channel, payload); + frame.getChannel(), payload); // First two bytes = class ID, must match class ID from // method. payload[0] = 12; @@ -155,8 +155,8 @@ public Frame confuse(Frame frame) { @Test public void heartbeatOnChannel() throws IOException { expectUnexpectedFrameError(new Confuser() { public Frame confuse(Frame frame) { - if (frame.type == AMQP.FRAME_METHOD) { - return new Frame(AMQP.FRAME_HEARTBEAT, frame.channel); + if (frame.getType() == AMQP.FRAME_METHOD) { + return new Frame(AMQP.FRAME_HEARTBEAT, frame.getChannel()); } return frame; } @@ -166,8 +166,8 @@ public Frame confuse(Frame frame) { @Test public void unknownFrameType() throws IOException { expectError(AMQP.FRAME_ERROR, new Confuser() { public Frame confuse(Frame frame) { - if (frame.type == AMQP.FRAME_METHOD) { - return new Frame(0, frame.channel, + if (frame.getType() == AMQP.FRAME_METHOD) { + return new Frame(0, frame.getChannel(), "1234567890\0001234567890".getBytes()); } return frame; From b41d37997f52a301dc64d608d1fb102f18fc8b0b Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Thu, 29 Aug 2019 18:02:56 +0300 Subject: [PATCH 1160/2114] Merge pull request #623 from rabbitmq/rabbitmq-java-client-622-for-4.x Sanitise peer certificate values we log (cherry picked from commit af217ec157ec08b5148fd47257ae4bfa30011ea1) --- src/main/java/com/rabbitmq/client/impl/TlsUtils.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/TlsUtils.java b/src/main/java/com/rabbitmq/client/impl/TlsUtils.java index b517e51d6c..938c1ad9d4 100644 --- a/src/main/java/com/rabbitmq/client/impl/TlsUtils.java +++ b/src/main/java/com/rabbitmq/client/impl/TlsUtils.java @@ -104,8 +104,8 @@ public static String peerCertificateInfo(Certificate certificate, String prefix) try { return String.format("%s subject: %s, subject alternative names: %s, " + "issuer: %s, not valid after: %s, X.509 usage extensions: %s", - prefix, c.getSubjectDN().getName(), sans(c, ","), c.getIssuerDN().getName(), - c.getNotAfter(), extensions(c)); + stripCRLF(prefix), stripCRLF(c.getSubjectDN().getName()), stripCRLF(sans(c, ",")), stripCRLF(c.getIssuerDN().getName()), + c.getNotAfter(), stripCRLF(extensions(c))); } catch (Exception e) { return "Error while retrieving " + prefix + " certificate information"; } @@ -145,6 +145,14 @@ public static String extensionPrettyPrint(String oid, byte[] derOctetString, X50 } } + /** + * Strips carriage return (CR) and line feed (LF) characters to mitigate CWE-117. + * @return sanitised string value + */ + public static String stripCRLF(String value) { + return value.replaceAll("\r", "").replaceAll("\n", ""); + } + private static String extensions(X509Certificate certificate) { List extensions = new ArrayList<>(); for (String oid : certificate.getCriticalExtensionOIDs()) { From 93f677cc1f5259fa5824dc725a14a7bfdbe9d765 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Thu, 29 Aug 2019 18:02:56 +0300 Subject: [PATCH 1161/2114] Merge pull request #623 from rabbitmq/rabbitmq-java-client-622-for-4.x Sanitise peer certificate values we log (cherry picked from commit af217ec157ec08b5148fd47257ae4bfa30011ea1) --- src/main/java/com/rabbitmq/client/impl/TlsUtils.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/TlsUtils.java b/src/main/java/com/rabbitmq/client/impl/TlsUtils.java index b517e51d6c..938c1ad9d4 100644 --- a/src/main/java/com/rabbitmq/client/impl/TlsUtils.java +++ b/src/main/java/com/rabbitmq/client/impl/TlsUtils.java @@ -104,8 +104,8 @@ public static String peerCertificateInfo(Certificate certificate, String prefix) try { return String.format("%s subject: %s, subject alternative names: %s, " + "issuer: %s, not valid after: %s, X.509 usage extensions: %s", - prefix, c.getSubjectDN().getName(), sans(c, ","), c.getIssuerDN().getName(), - c.getNotAfter(), extensions(c)); + stripCRLF(prefix), stripCRLF(c.getSubjectDN().getName()), stripCRLF(sans(c, ",")), stripCRLF(c.getIssuerDN().getName()), + c.getNotAfter(), stripCRLF(extensions(c))); } catch (Exception e) { return "Error while retrieving " + prefix + " certificate information"; } @@ -145,6 +145,14 @@ public static String extensionPrettyPrint(String oid, byte[] derOctetString, X50 } } + /** + * Strips carriage return (CR) and line feed (LF) characters to mitigate CWE-117. + * @return sanitised string value + */ + public static String stripCRLF(String value) { + return value.replaceAll("\r", "").replaceAll("\n", ""); + } + private static String extensions(X509Certificate certificate) { List extensions = new ArrayList<>(); for (String oid : certificate.getCriticalExtensionOIDs()) { From c737a939466647c43f5b544e8696cf0f19b2ae37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 12 Sep 2019 09:50:13 +0200 Subject: [PATCH 1162/2114] Bump dependencies References #625 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 542e6bdf4e..d70784d4c3 100644 --- a/pom.xml +++ b/pom.xml @@ -54,9 +54,9 @@ UTF-8 UTF-8 - 1.7.26 + 1.7.28 4.1.0 - 1.2.0 + 1.2.1 2.9.9.3 1.2.3 4.12 From d0e1a0863f8916c41755ba06a1d55043254fb908 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 12 Sep 2019 10:09:32 +0200 Subject: [PATCH 1163/2114] Bump test and build dependencies --- pom.xml | 16 ++++----- .../com/rabbitmq/client/test/JavaNioTest.java | 35 +++++++++++-------- .../com/rabbitmq/client/test/RpcTest.java | 7 ++-- .../client/test/functional/Metrics.java | 6 ++-- 4 files changed, 34 insertions(+), 30 deletions(-) diff --git a/pom.xml b/pom.xml index d70784d4c3..a0ad962936 100644 --- a/pom.xml +++ b/pom.xml @@ -60,13 +60,13 @@ 2.9.9.3 1.2.3 4.12 - 3.1.6 + 4.0.1 3.0.0 - 3.12.2 - 9.4.19.v20190610 - 1.61 + 3.13.2 + 9.4.20.v20190813 + 1.63 - 3.0.1 + 3.1.1 2.5.3 2.3 3.0.2 @@ -75,9 +75,9 @@ 2.4.8 1.5 1.12 - 3.6.1 - 2.22.1 - 2.22.1 + 3.8.1 + 2.22.2 + 2.22.2 1.6 3.0.2 3.2.0 diff --git a/src/test/java/com/rabbitmq/client/test/JavaNioTest.java b/src/test/java/com/rabbitmq/client/test/JavaNioTest.java index 2b80277590..0d143e86e8 100644 --- a/src/test/java/com/rabbitmq/client/test/JavaNioTest.java +++ b/src/test/java/com/rabbitmq/client/test/JavaNioTest.java @@ -4,6 +4,7 @@ import com.rabbitmq.client.impl.nio.BlockingQueueNioQueue; import com.rabbitmq.client.impl.nio.DefaultByteBufferFactory; import com.rabbitmq.client.impl.nio.NioParams; +import org.assertj.core.api.Condition; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -14,10 +15,8 @@ import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicInteger; -import static org.hamcrest.Matchers.hasSize; -import static org.hamcrest.Matchers.isOneOf; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; /** @@ -125,19 +124,21 @@ public void shutdownCompleted(ShutdownSignalException cause) { public void nioLoopCleaning() throws Exception { ConnectionFactory connectionFactory = new ConnectionFactory(); connectionFactory.useNio(); - for(int i = 0; i < 10; i++) { + for (int i = 0; i < 10; i++) { Connection connection = connectionFactory.newConnection(); connection.abort(); } } - @Test public void messageSize() throws Exception { + @Test + public void messageSize() throws Exception { for (int i = 0; i < 50; i++) { sendAndVerifyMessage(testConnection, 76390); } } - @Test public void byteBufferFactory() throws Exception { + @Test + public void byteBufferFactory() throws Exception { ConnectionFactory cf = new ConnectionFactory(); cf.useNio(); int baseCapacity = 32768; @@ -155,12 +156,15 @@ public void nioLoopCleaning() throws Exception { sendAndVerifyMessage(c, 100); } - assertThat(byteBuffers, hasSize(2)); - assertThat(byteBuffers.get(0).capacity(), isOneOf(nioParams.getReadByteBufferSize(), nioParams.getWriteByteBufferSize())); - assertThat(byteBuffers.get(1).capacity(), isOneOf(nioParams.getReadByteBufferSize(), nioParams.getWriteByteBufferSize())); + assertThat(byteBuffers).hasSize(2); + Condition condition = new Condition<>(c -> c == nioParams.getReadByteBufferSize() || + c == nioParams.getWriteByteBufferSize(), "capacity set by factory"); + assertThat(byteBuffers.get(0).capacity()).is(condition); + assertThat(byteBuffers.get(1).capacity()).is(condition); } - @Test public void directByteBuffers() throws Exception { + @Test + public void directByteBuffers() throws Exception { ConnectionFactory cf = new ConnectionFactory(); cf.useNio(); cf.setNioParams(new NioParams().setByteBufferFactory(new DefaultByteBufferFactory(capacity -> ByteBuffer.allocateDirect(capacity)))); @@ -169,15 +173,16 @@ public void nioLoopCleaning() throws Exception { } } - @Test public void customWriteQueue() throws Exception { + @Test + public void customWriteQueue() throws Exception { ConnectionFactory cf = new ConnectionFactory(); cf.useNio(); AtomicInteger count = new AtomicInteger(0); cf.setNioParams(new NioParams().setWriteQueueFactory(ctx -> { count.incrementAndGet(); return new BlockingQueueNioQueue( - new LinkedBlockingQueue<>(ctx.getNioParams().getWriteQueueCapacity()), - ctx.getNioParams().getWriteEnqueuingTimeoutInMs() + new LinkedBlockingQueue<>(ctx.getNioParams().getWriteQueueCapacity()), + ctx.getNioParams().getWriteEnqueuingTimeoutInMs() ); })); try (Connection c = cf.newConnection()) { @@ -193,7 +198,7 @@ private void sendAndVerifyMessage(Connection connection, int size) throws Except } private Connection basicGetBasicConsume(ConnectionFactory connectionFactory, String queue, final CountDownLatch latch) - throws IOException, TimeoutException { + throws IOException, TimeoutException { Connection connection = connectionFactory.newConnection(); Channel channel = connection.createChannel(); channel.queueDeclare(queue, false, false, false, null); @@ -213,7 +218,7 @@ public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProp } private boolean basicGetBasicConsume(Connection connection, String queue, final CountDownLatch latch, int msgSize) - throws Exception { + throws Exception { Channel channel = connection.createChannel(); channel.queueDeclare(queue, false, false, false, null); channel.queuePurge(queue); diff --git a/src/test/java/com/rabbitmq/client/test/RpcTest.java b/src/test/java/com/rabbitmq/client/test/RpcTest.java index 0c05f761e2..66251738d3 100644 --- a/src/test/java/com/rabbitmq/client/test/RpcTest.java +++ b/src/test/java/com/rabbitmq/client/test/RpcTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2017-2019 Pivotal Software, Inc. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 @@ -24,13 +24,12 @@ import com.rabbitmq.client.impl.recovery.RecordedQueue; import com.rabbitmq.client.impl.recovery.TopologyRecoveryFilter; import com.rabbitmq.tools.Host; -import org.awaitility.Awaitility; -import org.awaitility.Duration; import org.junit.After; import org.junit.Before; import org.junit.Test; import java.io.IOException; +import java.time.Duration; import java.util.HashMap; import java.util.Map; import java.util.UUID; @@ -301,7 +300,7 @@ public void handleRecoveryStarted(Recoverable recoverable) { serverThread.interrupt(); - waitAtMost(Duration.ONE_SECOND).until(() -> !serverThread.isAlive()) ; + waitAtMost(Duration.ofSeconds(1)).until(() -> !serverThread.isAlive()) ; client.close(); } diff --git a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java index 783d9e197f..94d76bfe2d 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2019 Pivotal Software, Inc. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 @@ -30,13 +30,13 @@ import com.rabbitmq.client.test.BrokerTestCase; import com.rabbitmq.client.test.TestUtils; import com.rabbitmq.tools.Host; -import org.awaitility.Duration; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import java.io.IOException; import java.lang.reflect.Field; +import java.time.Duration; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -637,7 +637,7 @@ private void sendMessage(Channel channel) throws IOException { } private Duration timeout() { - return new Duration(10, TimeUnit.SECONDS); + return Duration.ofSeconds(10); } private static class MultipleAckConsumer extends DefaultConsumer { From 67f991284a6040f41d2fe8be973ab15347f2bef0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 21 Jun 2019 16:11:31 +0200 Subject: [PATCH 1164/2114] Add OAuth 2 credentials provider and refresh service WIP. (cherry picked from commit 4251459c7c397efb066e3c38d21ce122836a7794) Conflicts: src/test/java/com/rabbitmq/client/test/ClientTests.java --- pom.xml | 7 + .../rabbitmq/client/ConnectionFactory.java | 17 +- .../rabbitmq/client/impl/AMQConnection.java | 33 ++ .../client/impl/ConnectionParams.java | 10 + .../client/impl/CredentialsProvider.java | 55 +++- .../impl/CredentialsRefreshService.java | 73 +++++ .../impl/DefaultCredentialsProvider.java | 15 + .../DefaultCredentialsRefreshService.java | 307 ++++++++++++++++++ ...ntCredentialsGrantCredentialsProvider.java | 233 +++++++++++++ .../impl/OAuthTokenManagementException.java | 27 ++ .../client/RefreshCredentialsTest.java | 81 +++++ .../DefaultCredentialsRefreshServiceTest.java | 181 +++++++++++ ...edentialsGrantCredentialsProviderTest.java | 190 +++++++++++ .../com/rabbitmq/client/test/ClientTests.java | 8 +- .../com/rabbitmq/client/test/TestUtils.java | 9 + 15 files changed, 1234 insertions(+), 12 deletions(-) create mode 100644 src/main/java/com/rabbitmq/client/impl/CredentialsRefreshService.java create mode 100644 src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java create mode 100644 src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java create mode 100644 src/main/java/com/rabbitmq/client/impl/OAuthTokenManagementException.java create mode 100644 src/test/java/com/rabbitmq/client/RefreshCredentialsTest.java create mode 100644 src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java create mode 100644 src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java diff --git a/pom.xml b/pom.xml index f4b6319cb5..d4523675c8 100644 --- a/pom.xml +++ b/pom.xml @@ -63,6 +63,7 @@ 3.1.6 3.0.0 3.12.2 + 9.4.19.v20190610 3.0.1 2.5.3 @@ -744,6 +745,12 @@ 1.3 test + + org.eclipse.jetty + jetty-servlet + ${jetty.version} + test + diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 547422de83..0047d55245 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -15,15 +15,7 @@ package com.rabbitmq.client; -import com.rabbitmq.client.impl.AMQConnection; -import com.rabbitmq.client.impl.ConnectionParams; -import com.rabbitmq.client.impl.CredentialsProvider; -import com.rabbitmq.client.impl.DefaultCredentialsProvider; -import com.rabbitmq.client.impl.DefaultExceptionHandler; -import com.rabbitmq.client.impl.ErrorOnWriteListener; -import com.rabbitmq.client.impl.FrameHandler; -import com.rabbitmq.client.impl.FrameHandlerFactory; -import com.rabbitmq.client.impl.SocketFrameHandlerFactory; +import com.rabbitmq.client.impl.*; import com.rabbitmq.client.impl.nio.NioParams; import com.rabbitmq.client.impl.nio.SocketChannelFrameHandlerFactory; import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; @@ -209,6 +201,8 @@ public class ConnectionFactory implements Cloneable { */ private TrafficListener trafficListener = TrafficListener.NO_OP; + private CredentialsRefreshService credentialsRefreshService; + /** @return the default host to use for connections */ public String getHost() { return host; @@ -854,6 +848,10 @@ public MetricsCollector getMetricsCollector() { return metricsCollector; } + public void setCredentialsRefreshService(CredentialsRefreshService credentialsRefreshService) { + this.credentialsRefreshService = credentialsRefreshService; + } + protected synchronized FrameHandlerFactory createFrameHandlerFactory() throws IOException { if(nio) { if(this.frameHandlerFactory == null) { @@ -1161,6 +1159,7 @@ public ConnectionParams params(ExecutorService consumerWorkServiceExecutor) { result.setConnectionRecoveryTriggeringCondition(connectionRecoveryTriggeringCondition); result.setTopologyRecoveryRetryHandler(topologyRecoveryRetryHandler); result.setTrafficListener(trafficListener); + result.setCredentialsRefreshService(credentialsRefreshService); return result; } diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index e5a40ceee1..67c2c29afe 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -142,6 +142,7 @@ public static Map defaultClientProperties() { private final int channelRpcTimeout; private final boolean channelShouldCheckRpcResponseType; private final TrafficListener trafficListener; + private final CredentialsRefreshService credentialsRefreshService; /* State modified after start - all volatile */ @@ -239,6 +240,9 @@ public AMQConnection(ConnectionParams params, FrameHandler frameHandler, Metrics this.channelShouldCheckRpcResponseType = params.channelShouldCheckRpcResponseType(); this.trafficListener = params.getTrafficListener() == null ? TrafficListener.NO_OP : params.getTrafficListener(); + + this.credentialsRefreshService = params.getCredentialsRefreshService(); + this._channel0 = new AMQChannel(this, 0) { @Override public boolean processAsync(Command c) throws IOException { return getConnection().processControlCommand(c); @@ -336,6 +340,15 @@ public void start() String username = credentialsProvider.getUsername(); String password = credentialsProvider.getPassword(); + + if (credentialsProvider.getExpiration() != null) { + if (this.credentialsRefreshService.needRefresh(credentialsProvider.getExpiration())) { + credentialsProvider.refresh(); + username = credentialsProvider.getUsername(); + password = credentialsProvider.getPassword(); + } + } + LongString challenge = null; LongString response = sm.handleChallenge(null, username, password); @@ -413,6 +426,26 @@ public void start() throw AMQChannel.wrap(sse); } + if (this.credentialsProvider.getExpiration() != null) { + String registrationId = this.credentialsRefreshService.register(credentialsProvider, () -> { + // return false if connection is closed, so refresh service can get rid of this registration + if (!isOpen()) { + return false; + } + if (this._inConnectionNegotiation) { + // this should not happen + return true; + } + String refreshedPassword = credentialsProvider.getPassword(); + + // TODO send password to server with update-secret extension, using channel 0 + + return true; + }); + + addShutdownListener(sse -> this.credentialsRefreshService.unregister(this.credentialsProvider, registrationId)); + } + // We can now respond to errors having finished tailoring the connection this._inConnectionNegotiation = false; } diff --git a/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java b/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java index 849905e2a8..57a028783b 100644 --- a/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java +++ b/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java @@ -60,6 +60,8 @@ public class ConnectionParams { private TrafficListener trafficListener; + private CredentialsRefreshService credentialsRefreshService; + public ConnectionParams() {} public CredentialsProvider getCredentialsProvider() { @@ -277,4 +279,12 @@ public void setTrafficListener(TrafficListener trafficListener) { public TrafficListener getTrafficListener() { return trafficListener; } + + public void setCredentialsRefreshService(CredentialsRefreshService credentialsRefreshService) { + this.credentialsRefreshService = credentialsRefreshService; + } + + public CredentialsRefreshService getCredentialsRefreshService() { + return credentialsRefreshService; + } } diff --git a/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java index 1b1c308cd6..a7db53f8c3 100644 --- a/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java @@ -1,16 +1,67 @@ +// Copyright (c) 2018-2019 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.impl; +import java.util.Date; + /** * Provider interface for establishing credentials for connecting to the broker. Especially useful - * for situations where credentials might change before a recovery takes place or where it is + * for situations where credentials might expire or change before a recovery takes place or where it is * convenient to plug in an outside custom implementation. * - * @since 4.5.0 + * @see CredentialsRefreshService + * @since 5.2.0 */ public interface CredentialsProvider { + /** + * Username to use for authentication + * + * @return username + */ String getUsername(); + /** + * Password/secret/token to use for authentication + * + * @return password/secret/token + */ String getPassword(); + /** + * The expiration date of the credentials, if any. + *

+ * If credentials do not expire, must return null. Default + * behavior is to return null, assuming credentials never + * expire. + * + * @return credentials expiration date + */ + default Date getExpiration() { + // no expiration by default + return null; + } + + /** + * Instructs the provider to refresh or renew credentials. + *

+ * Default behavior is no-op. + */ + default void refresh() { + // no need to refresh anything by default + } + } \ No newline at end of file diff --git a/src/main/java/com/rabbitmq/client/impl/CredentialsRefreshService.java b/src/main/java/com/rabbitmq/client/impl/CredentialsRefreshService.java new file mode 100644 index 0000000000..536c0dc0e0 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/CredentialsRefreshService.java @@ -0,0 +1,73 @@ +// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl; + +import java.util.Date; +import java.util.concurrent.Callable; + +/** + * Provider interface to refresh credentials when appropriate + * and perform an operation once the credentials have been + * renewed. In the context of RabbitMQ, the operation consists + * in calling the update.secret AMQP extension + * to provide new valid credentials before the current ones + * expire. + *

+ * New connections are registered and implementations must perform + * credentials renewal when appropriate. Implementations + * must call a registered callback once credentials are renewed. + * + * @see CredentialsProvider + * @see DefaultCredentialsRefreshService + */ +public interface CredentialsRefreshService { + + /** + * Register a new entity that needs credentials renewal. + *

+ * The registered callback must return true if the action was + * performed correctly, throw an exception if something goes wrong, + * and return false if it became stale and wants to be unregistered. + *

+ * Implementations are free to automatically unregister an entity whose + * callback has failed a given number of times. + * + * @param credentialsProvider the credentials provider + * @param refreshAction the action to perform after credentials renewal + * @return a tracking ID for the registration + */ + String register(CredentialsProvider credentialsProvider, Callable refreshAction); + + /** + * Unregister the entity with the given registration ID. + *

+ * Its state is cleaned up and its registered callback will not be + * called again. + * + * @param credentialsProvider the credentials provider + * @param registrationId the registration ID + */ + void unregister(CredentialsProvider credentialsProvider, String registrationId); + + /** + * Provide a hint about whether credentials should be renewed. + * + * @param expiration + * @return true if credentials should be renewed, false otherwise + */ + boolean needRefresh(Date expiration); + +} diff --git a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java index f743a14618..20cbbe3acc 100644 --- a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java @@ -1,3 +1,18 @@ +// Copyright (c) 2018-2019 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.impl; /** diff --git a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java new file mode 100644 index 0000000000..091948bb82 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java @@ -0,0 +1,307 @@ +// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.time.Duration; +import java.util.Date; +import java.util.Iterator; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; +import java.util.function.Supplier; + +/** + * Scheduling-based implementation of {@link CredentialsRefreshService}. + *

+ * This implementation keeps track of entities (typically AMQP connections) that need + * to renew credentials. Token renewal is scheduled based on token expiration, using + * a Function refreshDelayStrategy. Once credentials + * for a {@link CredentialsProvider} have been renewed, the callback registered + * by each entity/connection is performed. This callback typically propagates + * the new credentials in the entity state, e.g. sending the new password to the + * broker for AMQP connections. + */ +public class DefaultCredentialsRefreshService implements CredentialsRefreshService { + + private static final Logger LOGGER = LoggerFactory.getLogger(DefaultCredentialsRefreshService.class); + + private final ScheduledExecutorService scheduler; + + private final ConcurrentMap credentialsProviderStates = new ConcurrentHashMap<>(); + + private final boolean privateScheduler; + + private final Function refreshDelayStrategy; + + private final Function needRefreshStrategy; + + public DefaultCredentialsRefreshService(ScheduledExecutorService scheduler, Function refreshDelayStrategy, Function needRefreshStrategy) { + this.refreshDelayStrategy = refreshDelayStrategy; + this.needRefreshStrategy = needRefreshStrategy; + if (scheduler == null) { + this.scheduler = Executors.newScheduledThreadPool(1); + privateScheduler = true; + } else { + this.scheduler = scheduler; + privateScheduler = false; + } + } + + /** + * Delay before refresh is TTL - specified duration. + *

+ * E.g. if TTL is 60 seconds and specified duration is 20 seconds, refresh will + * be scheduled in 60 - 20 = 40 seconds. + * + * @param duration + * @return + */ + public static Function fixedDelayBeforeExpirationRefreshDelayStrategy(Duration duration) { + return new FixedDelayBeforeExpirationRefreshDelayStrategy(duration.toMillis()); + } + + /** + * Advise to refresh credentials if TTL <= limit. + * + * @param limitBeforeExpiration + * @return + */ + public static Function fixedTimeNeedRefreshStrategy(Duration limitBeforeExpiration) { + return new FixedTimeNeedRefreshStrategy(limitBeforeExpiration.toMillis()); + } + + // TODO add a delay refresh strategy that bases the time on a percentage of the TTL, use it as default with 80% TTL + + private static Runnable refresh(ScheduledExecutorService scheduler, CredentialsProviderState credentialsProviderState, + Function refreshDelayStrategy) { + return () -> { + LOGGER.debug("Refreshing token"); + credentialsProviderState.refresh(); + + Date expirationAfterRefresh = credentialsProviderState.credentialsProvider.getExpiration(); + long newDelay = refreshDelayStrategy.apply(expirationAfterRefresh); + + LOGGER.debug("Scheduling refresh in {} milliseconds", newDelay); + + ScheduledFuture scheduledFuture = scheduler.schedule(refresh(scheduler, credentialsProviderState, refreshDelayStrategy), newDelay, TimeUnit.MILLISECONDS); + credentialsProviderState.refreshTask.set(scheduledFuture); + }; + } + + @Override + public String register(CredentialsProvider credentialsProvider, Callable refreshAction) { + String registrationId = UUID.randomUUID().toString(); + LOGGER.debug("New registration {}", registrationId); + + Registration registration = new Registration(registrationId, refreshAction); + CredentialsProviderState credentialsProviderState = credentialsProviderStates.computeIfAbsent( + credentialsProvider, + credentialsProviderKey -> new CredentialsProviderState(credentialsProviderKey) + ); + + credentialsProviderState.add(registration); + + credentialsProviderState.maybeSetRefreshTask(() -> { + Date expiration = credentialsProvider.getExpiration(); + long delay = refreshDelayStrategy.apply(expiration); + LOGGER.debug("Scheduling refresh in {} milliseconds", delay); + return scheduler.schedule(refresh(scheduler, credentialsProviderState, refreshDelayStrategy), delay, TimeUnit.MILLISECONDS); + }); + + return registrationId; + } + + @Override + public void unregister(CredentialsProvider credentialsProvider, String registrationId) { + CredentialsProviderState credentialsProviderState = this.credentialsProviderStates.get(credentialsProvider); + if (credentialsProviderState != null) { + credentialsProviderState.unregister(registrationId); + } + } + + @Override + public boolean needRefresh(Date expiration) { + return this.needRefreshStrategy.apply(expiration); + } + + public void close() { + if (privateScheduler) { + scheduler.shutdownNow(); + } + } + + private static class FixedTimeNeedRefreshStrategy implements Function { + + private final long limitBeforeExpiration; + + private FixedTimeNeedRefreshStrategy(long limitBeforeExpiration) { + this.limitBeforeExpiration = limitBeforeExpiration; + } + + @Override + public Boolean apply(Date expiration) { + long ttl = expiration.getTime() - new Date().getTime(); + return ttl <= limitBeforeExpiration; + } + } + + private static class FixedDelayBeforeExpirationRefreshDelayStrategy implements Function { + + private final long delay; + + private FixedDelayBeforeExpirationRefreshDelayStrategy(long delay) { + this.delay = delay; + } + + @Override + public Long apply(Date expiration) { + long ttl = expiration.getTime() - new Date().getTime(); + long refreshTimeBeforeExpiration = ttl - delay; + if (refreshTimeBeforeExpiration < 0) { + return ttl; + } else { + return refreshTimeBeforeExpiration; + } + } + } + + static class Registration { + + private final Callable refreshAction; + + private final AtomicInteger errorHistory = new AtomicInteger(0); + + private final String id; + + Registration(String id, Callable refreshAction) { + this.refreshAction = refreshAction; + this.id = id; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Registration that = (Registration) o; + + return id.equals(that.id); + } + + @Override + public int hashCode() { + return id.hashCode(); + } + } + + /** + * State and refresh behavior for a {@link CredentialsProvider} and + * its registered entities. + */ + static class CredentialsProviderState { + + private final CredentialsProvider credentialsProvider; + + private final Map registrations = new ConcurrentHashMap<>(); + + private final AtomicReference> refreshTask = new AtomicReference<>(); + + private final AtomicBoolean refreshTaskSet = new AtomicBoolean(false); + + CredentialsProviderState(CredentialsProvider credentialsProvider) { + this.credentialsProvider = credentialsProvider; + } + + void add(Registration registration) { + this.registrations.put(registration.id, registration); + } + + void maybeSetRefreshTask(Supplier> scheduledFutureSupplier) { + if (refreshTaskSet.compareAndSet(false, true)) { + refreshTask.set(scheduledFutureSupplier.get()); + } + } + + void refresh() { + // FIXME check whether thread has been cancelled or not before refresh() and registratAction.call() + + // FIXME protect this call, or at least log some error + this.credentialsProvider.refresh(); + + Iterator iterator = registrations.values().iterator(); + while (iterator.hasNext()) { + Registration registration = iterator.next(); + // FIXME set a timeout on the call? (needs a separate thread) + try { + boolean refreshed = registration.refreshAction.call(); + if (!refreshed) { + LOGGER.debug("Registration did not refresh token"); + iterator.remove(); + } + registration.errorHistory.set(0); + } catch (Exception e) { + LOGGER.warn("Error while trying to refresh a connection token", e); + registration.errorHistory.incrementAndGet(); + if (registration.errorHistory.get() >= 5) { + registrations.remove(registration.id); + } + } + } + } + + void unregister(String registrationId) { + this.registrations.remove(registrationId); + } + } + + public static class DefaultCredentialsRefreshServiceBuilder { + + + private ScheduledExecutorService scheduler; + + private Function refreshDelayStrategy = fixedDelayBeforeExpirationRefreshDelayStrategy(Duration.ofSeconds(60)); + + private Function needRefreshStrategy = fixedTimeNeedRefreshStrategy(Duration.ofSeconds(60)); + + public DefaultCredentialsRefreshServiceBuilder scheduler(ScheduledThreadPoolExecutor scheduler) { + this.scheduler = scheduler; + return this; + } + + public DefaultCredentialsRefreshServiceBuilder refreshDelayStrategy(Function refreshDelayStrategy) { + this.refreshDelayStrategy = refreshDelayStrategy; + return this; + } + + public DefaultCredentialsRefreshServiceBuilder needRefreshStrategy(Function needRefreshStrategy) { + this.needRefreshStrategy = needRefreshStrategy; + return this; + } + + public DefaultCredentialsRefreshService build() { + return new DefaultCredentialsRefreshService(scheduler, refreshDelayStrategy, needRefreshStrategy); + } + + } + +} diff --git a/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java new file mode 100644 index 0000000000..ca3fb5c8a3 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java @@ -0,0 +1,233 @@ +// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + + +public class OAuth2ClientCredentialsGrantCredentialsProvider implements CredentialsProvider { + + private static final Logger LOGGER = LoggerFactory.getLogger(OAuth2ClientCredentialsGrantCredentialsProvider.class); + + private static final String UTF_8_CHARSET = "UTF-8"; + private final String serverUri; // should be renamed to tokenEndpointUri? + private final String clientId; + private final String clientSecret; + private final String grantType; + // UAA specific, to distinguish between different users + private final String username, password; + + private final ObjectMapper objectMapper = new ObjectMapper(); + + private final String id; + + private final AtomicReference token = new AtomicReference<>(); + + private final Lock refreshLock = new ReentrantLock(); + private final AtomicReference latch = new AtomicReference<>(); + private AtomicBoolean refreshInProcess = new AtomicBoolean(false); + + public OAuth2ClientCredentialsGrantCredentialsProvider(String serverUri, String clientId, String clientSecret, String grantType, String username, String password) { + this.serverUri = serverUri; + this.clientId = clientId; + this.clientSecret = clientSecret; + this.grantType = grantType; + this.username = username; + this.password = password; + this.id = UUID.randomUUID().toString(); + } + + private static StringBuilder encode(StringBuilder builder, String name, String value) throws UnsupportedEncodingException { + if (value != null) { + if (builder.length() > 0) { + builder.append("&"); + } + builder.append(URLEncoder.encode(name, UTF_8_CHARSET)) + .append("=") + .append(URLEncoder.encode(value, UTF_8_CHARSET)); + } + return builder; + } + + private static String basicAuthentication(String username, String password) { + String credentials = username + ":" + password; + byte[] credentialsAsBytes = credentials.getBytes(StandardCharsets.ISO_8859_1); + byte[] encodedBytes = Base64.getEncoder().encode(credentialsAsBytes); + String encodedCredentials = new String(encodedBytes, StandardCharsets.ISO_8859_1); + return "Basic " + encodedCredentials; + } + + @Override + public String getUsername() { + return ""; + } + + @Override + public String getPassword() { + if (token.get() == null) { + refresh(); + } + return token.get().getAccess(); + } + + @Override + public Date getExpiration() { + if (token.get() == null) { + refresh(); + } + return token.get().getExpiration(); + } + + protected Token parseToken(String response) { + try { + Map map = objectMapper.readValue(response, Map.class); + int expiresIn = ((Number) map.get("expires_in")).intValue(); + Calendar calendar = Calendar.getInstance(); + calendar.add(Calendar.SECOND, expiresIn); + return new Token(map.get("access_token").toString(), calendar.getTime()); + } catch (IOException e) { + throw new OAuthTokenManagementException("Error while parsing OAuth 2 token", e); + } + } + + @Override + public void refresh() { + // refresh should happen at once. Other calls wait for the refresh to finish and move on. + if (refreshLock.tryLock()) { + LOGGER.debug("Refreshing token"); + try { + latch.set(new CountDownLatch(1)); + refreshInProcess.set(true); + token.set(retrieveToken()); + LOGGER.debug("Token refreshed"); + } finally { + latch.get().countDown(); + refreshInProcess.set(false); + refreshLock.unlock(); + } + } else { + try { + LOGGER.debug("Waiting for token refresh to be finished"); + while (!refreshInProcess.get()) { + Thread.sleep(10); + } + latch.get().await(); + LOGGER.debug("Done waiting for token refresh"); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + } + + protected Token retrieveToken() { + // FIXME handle TLS specific settings + try { + StringBuilder urlParameters = new StringBuilder(); + encode(urlParameters, "grant_type", grantType); + encode(urlParameters, "username", username); + encode(urlParameters, "password", password); + byte[] postData = urlParameters.toString().getBytes(StandardCharsets.UTF_8); + int postDataLength = postData.length; + URL url = new URL(serverUri); + // FIXME close connection? + // FIXME set timeout on request + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setDoOutput(true); + conn.setInstanceFollowRedirects(false); + conn.setRequestMethod("POST"); + conn.setRequestProperty("authorization", basicAuthentication(clientId, clientSecret)); + conn.setRequestProperty("content-type", "application/x-www-form-urlencoded"); + conn.setRequestProperty("charset", UTF_8_CHARSET); + conn.setRequestProperty("accept", "application/json"); + conn.setRequestProperty("content-length", Integer.toString(postDataLength)); + conn.setUseCaches(false); + try (DataOutputStream wr = new DataOutputStream(conn.getOutputStream())) { + wr.write(postData); + } + int responseCode = conn.getResponseCode(); + if (responseCode != 200) { + throw new OAuthTokenManagementException( + "HTTP request for token retrieval did not " + + "return 200 response code: " + responseCode + ); + } + + StringBuffer content = new StringBuffer(); + try (BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()))) { + String inputLine; + while ((inputLine = in.readLine()) != null) { + content.append(inputLine); + } + } + + // FIXME check result is json + + + return parseToken(content.toString()); + } catch (IOException e) { + throw new OAuthTokenManagementException("Error while retrieving OAuth 2 token", e); + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + OAuth2ClientCredentialsGrantCredentialsProvider that = (OAuth2ClientCredentialsGrantCredentialsProvider) o; + + return id.equals(that.id); + } + + @Override + public int hashCode() { + return id.hashCode(); + } + + public static class Token { + + private final String access; + + private final Date expiration; + + public Token(String access, Date expiration) { + this.access = access; + this.expiration = expiration; + } + + public Date getExpiration() { + return expiration; + } + + public String getAccess() { + return access; + } + } +} diff --git a/src/main/java/com/rabbitmq/client/impl/OAuthTokenManagementException.java b/src/main/java/com/rabbitmq/client/impl/OAuthTokenManagementException.java new file mode 100644 index 0000000000..62db5e07a5 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/OAuthTokenManagementException.java @@ -0,0 +1,27 @@ +// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl; + +public class OAuthTokenManagementException extends RuntimeException { + + public OAuthTokenManagementException(String message, Throwable cause) { + super(message, cause); + } + + public OAuthTokenManagementException(String message) { + super(message); + } +} diff --git a/src/test/java/com/rabbitmq/client/RefreshCredentialsTest.java b/src/test/java/com/rabbitmq/client/RefreshCredentialsTest.java new file mode 100644 index 0000000000..41fe348e28 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/RefreshCredentialsTest.java @@ -0,0 +1,81 @@ +// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client; + +import com.rabbitmq.client.impl.DefaultCredentialsRefreshService; +import com.rabbitmq.client.impl.OAuth2ClientCredentialsGrantCredentialsProvider; +import com.rabbitmq.client.test.TestUtils; +import org.junit.Before; +import org.junit.Test; + +import java.time.Duration; +import java.util.Calendar; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import static org.assertj.core.api.Assertions.assertThat; + +public class RefreshCredentialsTest { + + DefaultCredentialsRefreshService refreshService; + + @Before + public void tearDown() { + if (refreshService != null) { + refreshService.close(); + } + } + + @Test + public void connectionAndRefreshCredentials() throws Exception { + ConnectionFactory cf = TestUtils.connectionFactory(); + CountDownLatch latch = new CountDownLatch(5); + // OAuth server is actually not used in this test, default RabbitMQ authentication backend is + OAuth2ClientCredentialsGrantCredentialsProvider provider = new OAuth2ClientCredentialsGrantCredentialsProvider( + "http://localhost:8080/uaa/oauth/token/", + "rabbit_client", "rabbit_secret", + "password", // UAA-specific, standard is client_credentials + "rabbit_super", "rabbit_super" // UAA-specific, to distinguish between RabbitMQ users + ) { + @Override + protected Token retrieveToken() { + latch.countDown(); + Calendar calendar = Calendar.getInstance(); + calendar.add(Calendar.SECOND, 2); + return new Token("guest", calendar.getTime()); + } + + @Override + public String getUsername() { + return "guest"; + } + }; + cf.setCredentialsProvider(provider); + refreshService = new DefaultCredentialsRefreshService.DefaultCredentialsRefreshServiceBuilder() + .refreshDelayStrategy(DefaultCredentialsRefreshService.fixedDelayBeforeExpirationRefreshDelayStrategy(Duration.ofSeconds(1))) + .needRefreshStrategy(expiration -> false) + .build(); + cf.setCredentialsRefreshService(refreshService); + + try (Connection c = cf.newConnection()) { + Channel ch = c.createChannel(); + String queue = ch.queueDeclare().getQueue(); + TestUtils.sendAndConsumeMessage("", queue, queue, c); + assertThat(latch.await(10, TimeUnit.SECONDS)).isTrue(); + } + } + +} diff --git a/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java b/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java new file mode 100644 index 0000000000..66e59ba866 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java @@ -0,0 +1,181 @@ +// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl; + +import org.junit.After; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.stubbing.Answer; + +import java.time.Duration; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.IntStream; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.*; + +@RunWith(MockitoJUnitRunner.class) +public class DefaultCredentialsRefreshServiceTest { + + @Mock + Callable refreshAction; + + @Mock + CredentialsProvider credentialsProvider; + + DefaultCredentialsRefreshService refreshService; + + @After + public void tearDown() { + if (refreshService != null) { + refreshService.close(); + } + } + + @Test + public void scheduling() throws Exception { + refreshService = new DefaultCredentialsRefreshService.DefaultCredentialsRefreshServiceBuilder() + .refreshDelayStrategy(DefaultCredentialsRefreshService.fixedDelayBeforeExpirationRefreshDelayStrategy(Duration.ofSeconds(2))) + .build(); + + AtomicInteger passwordSequence = new AtomicInteger(0); + when(credentialsProvider.getPassword()).thenAnswer( + (Answer) invocation -> "password-" + passwordSequence.get()); + when(credentialsProvider.getExpiration()).thenAnswer((Answer) invocation -> { + Calendar calendar = Calendar.getInstance(); + calendar.add(Calendar.SECOND, 5); + return calendar.getTime(); + }); + doAnswer(invocation -> { + passwordSequence.incrementAndGet(); + return null; + }).when(credentialsProvider).refresh(); + + List passwords = new CopyOnWriteArrayList<>(); + CountDownLatch latch = new CountDownLatch(2 * 2); + refreshAction = () -> { + passwords.add(credentialsProvider.getPassword()); + latch.countDown(); + return true; + }; + refreshService.register(credentialsProvider, refreshAction); + refreshService.register(credentialsProvider, refreshAction); + assertThat(latch.await(10, TimeUnit.SECONDS)).isTrue(); + assertThat(passwords).hasSize(4).containsExactlyInAnyOrder("password-1", "password-2", "password-1", "password-2"); + + AtomicInteger passwordSequence2 = new AtomicInteger(0); + CredentialsProvider credentialsProvider2 = mock(CredentialsProvider.class); + when(credentialsProvider2.getPassword()).thenAnswer((Answer) invocation -> "password2-" + passwordSequence2.get()); + when(credentialsProvider2.getExpiration()).thenAnswer((Answer) invocation -> { + Calendar calendar = Calendar.getInstance(); + calendar.add(Calendar.SECOND, 4); + return calendar.getTime(); + }); + doAnswer(invocation -> { + passwordSequence2.incrementAndGet(); + return null; + }).when(credentialsProvider2).refresh(); + + + List passwords2 = new CopyOnWriteArrayList<>(); + CountDownLatch latch2 = new CountDownLatch(2 * 1); + refreshAction = () -> { + passwords2.add(credentialsProvider2.getPassword()); + latch2.countDown(); + return true; + }; + + refreshService.register(credentialsProvider2, refreshAction); + + assertThat(latch2.await(10, TimeUnit.SECONDS)).isTrue(); + assertThat(passwords2).hasSize(2).containsExactlyInAnyOrder( + "password2-1", "password2-2" + ); + assertThat(passwords).hasSizeGreaterThan(4); + + + } + + @Test + public void refreshActionIsCorrectlyRegisteredCalledAndCanceled() throws Exception { + DefaultCredentialsRefreshService.CredentialsProviderState state = new DefaultCredentialsRefreshService.CredentialsProviderState( + credentialsProvider + ); + when(refreshAction.call()).thenReturn(true); + state.add(new DefaultCredentialsRefreshService.Registration("1", refreshAction)); + + state.refresh(); + verify(credentialsProvider, times(1)).refresh(); + verify(refreshAction, times(1)).call(); + + state.refresh(); + verify(credentialsProvider, times(2)).refresh(); + verify(refreshAction, times(2)).call(); + + state.unregister("1"); + state.refresh(); + verify(credentialsProvider, times(3)).refresh(); + verify(refreshAction, times(2)).call(); + } + + @Test + public void refreshActionIsRemovedIfItReturnsFalse() throws Exception { + DefaultCredentialsRefreshService.CredentialsProviderState state = new DefaultCredentialsRefreshService.CredentialsProviderState( + credentialsProvider + ); + when(refreshAction.call()).thenReturn(false); + state.add(new DefaultCredentialsRefreshService.Registration("1", refreshAction)); + + state.refresh(); + verify(credentialsProvider, times(1)).refresh(); + verify(refreshAction, times(1)).call(); + + state.refresh(); + verify(credentialsProvider, times(2)).refresh(); + verify(refreshAction, times(1)).call(); + } + + @Test + public void refreshActionIsRemovedIfItErrorsTooMuch() throws Exception { + DefaultCredentialsRefreshService.CredentialsProviderState state = new DefaultCredentialsRefreshService.CredentialsProviderState( + credentialsProvider + ); + when(refreshAction.call()).thenThrow(RuntimeException.class); + state.add(new DefaultCredentialsRefreshService.Registration("1", refreshAction)); + + int callsCountBeforeCancellation = 5; + IntStream.range(0, callsCountBeforeCancellation).forEach(i -> { + state.refresh(); + }); + + verify(credentialsProvider, times(callsCountBeforeCancellation)).refresh(); + verify(refreshAction, times(callsCountBeforeCancellation)).call(); + + state.refresh(); + verify(credentialsProvider, times(callsCountBeforeCancellation + 1)).refresh(); + verify(refreshAction, times(callsCountBeforeCancellation)).call(); + } + +} diff --git a/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java b/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java new file mode 100644 index 0000000000..6e1908fee2 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java @@ -0,0 +1,190 @@ +// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl; + +import com.rabbitmq.client.test.TestUtils; +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.server.handler.AbstractHandler; +import org.eclipse.jetty.server.handler.ContextHandler; +import org.junit.After; +import org.junit.Test; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Calendar; +import java.util.Date; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.IntStream; + +import static org.assertj.core.api.Assertions.assertThat; + +public class OAuth2ClientCredentialsGrantCredentialsProviderTest { + + Server server; + + @After + public void tearDown() throws Exception { + if (server != null) { + server.stop(); + } + } + + @Test + public void getToken() throws Exception { + Server server = new Server(); + ServerConnector connector = new ServerConnector(server); + int port = TestUtils.randomNetworkPort(); + connector.setPort(port); + server.setConnectors(new Connector[]{connector}); + + AtomicReference httpMethod = new AtomicReference<>(); + AtomicReference contentType = new AtomicReference<>(); + AtomicReference authorization = new AtomicReference<>(); + AtomicReference accept = new AtomicReference<>(); + AtomicReference accessToken = new AtomicReference<>(); + + int expiresIn = 60; + + ContextHandler context = new ContextHandler(); + context.setContextPath("/uaa/oauth/token/"); + context.setHandler(new AbstractHandler() { + + @Override + public void handle(String s, Request request, HttpServletRequest httpServletRequest, HttpServletResponse response) + throws IOException { + + httpMethod.set(request.getMethod()); + contentType.set(request.getContentType()); + authorization.set(request.getHeader("authorization")); + accept.set(request.getHeader("accept")); + + accessToken.set(UUID.randomUUID().toString()); + String json = sampleJsonToken(accessToken.get(), expiresIn); + + response.setStatus(HttpServletResponse.SC_OK); + response.setContentLength(json.length()); + response.setContentType("application/json"); + + response.getWriter().print(json); + + request.setHandled(true); + + } + }); + + server.setHandler(context); + + server.setStopTimeout(1000); + server.start(); + + OAuth2ClientCredentialsGrantCredentialsProvider provider = new OAuth2ClientCredentialsGrantCredentialsProvider( + "http://localhost:" + port + "/uaa/oauth/token/", + "rabbit_client", "rabbit_secret", + "password", // UAA-specific, standard is client_credentials + "rabbit_super", "rabbit_super" // UAA-specific, to distinguish between RabbitMQ users + ); + + String password = provider.getPassword(); + + assertThat(password).isEqualTo(accessToken.get()); + assertThat(provider.getExpiration()).isBetween(offsetNow(expiresIn - 10), offsetNow(expiresIn + 10)); + + assertThat(httpMethod).hasValue("POST"); + assertThat(contentType).hasValue("application/x-www-form-urlencoded"); + assertThat(authorization).hasValue("Basic cmFiYml0X2NsaWVudDpyYWJiaXRfc2VjcmV0"); + assertThat(accept).hasValue("application/json"); + } + + @Test + public void refresh() throws Exception { + AtomicInteger retrieveTokenCallCount = new AtomicInteger(0); + OAuth2ClientCredentialsGrantCredentialsProvider provider = new OAuth2ClientCredentialsGrantCredentialsProvider( + "http://localhost:8080/uaa/oauth/token/", + "rabbit_client", "rabbit_secret", + "password", // UAA-specific, standard is client_credentials + "rabbit_super", "rabbit_super" // UAA-specific, to distinguish between RabbitMQ users + ) { + @Override + protected Token retrieveToken() { + retrieveTokenCallCount.incrementAndGet(); + try { + Thread.sleep(2000L); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + return new Token(UUID.randomUUID().toString(), new Date()); + } + }; + + Set passwords = ConcurrentHashMap.newKeySet(); + CountDownLatch latch = new CountDownLatch(5); + IntStream.range(0, 5).forEach(i -> new Thread(() -> { + passwords.add(provider.getPassword()); + latch.countDown(); + }).start()); + + assertThat(latch.await(10, TimeUnit.SECONDS)).isTrue(); + + assertThat(retrieveTokenCallCount).hasValue(1); + assertThat(passwords).hasSize(1); + } + + @Test + public void parseToken() { + OAuth2ClientCredentialsGrantCredentialsProvider provider = new OAuth2ClientCredentialsGrantCredentialsProvider( + "http://localhost:8080/uaa/oauth/token", + "rabbit_client", "rabbit_secret", + "password", // UAA-specific, standard is client_credentials + "rabbit_super", "rabbit_super" // UAA-specific, to distinguish between RabbitMQ users + ); + + String accessToken = "18c1b1dfdda04382a8bcc14d077b71dd"; + int expiresIn = 43199; + String response = sampleJsonToken(accessToken, expiresIn); + + OAuth2ClientCredentialsGrantCredentialsProvider.Token token = provider.parseToken(response); + assertThat(token.getAccess()).isEqualTo("18c1b1dfdda04382a8bcc14d077b71dd"); + assertThat(token.getExpiration()).isBetween(offsetNow(expiresIn - 10), offsetNow(expiresIn + 1)); + } + + Date offsetNow(int seconds) { + Calendar calendar = Calendar.getInstance(); + calendar.add(Calendar.SECOND, seconds); + return calendar.getTime(); + } + + String sampleJsonToken(String accessToken, int expiresIn) { + String json = "{\n" + + " \"access_token\" : \"{accessToken}\",\n" + + " \"token_type\" : \"bearer\",\n" + + " \"expires_in\" : {expiresIn},\n" + + " \"scope\" : \"clients.read emails.write scim.userids password.write idps.write notifications.write oauth.login scim.write critical_notifications.write\",\n" + + " \"jti\" : \"18c1b1dfdda04382a8bcc14d077b71dd\"\n" + + "}"; + return json.replace("{accessToken}", accessToken).replace("{expiresIn}", expiresIn + ""); + } + +} diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index db5c7cd179..713930153b 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -19,6 +19,9 @@ import com.rabbitmq.client.JacksonJsonRpcTest; import com.rabbitmq.client.DefaultJsonRpcTest; import com.rabbitmq.client.impl.ValueWriterTest; +import com.rabbitmq.client.RefreshCredentialsTest; +import com.rabbitmq.client.impl.DefaultCredentialsRefreshServiceTest; +import com.rabbitmq.client.impl.OAuth2ClientCredentialsGrantCredentialsProviderTest; import com.rabbitmq.utility.IntAllocatorTests; import org.junit.runner.RunWith; import org.junit.runners.Suite; @@ -73,7 +76,10 @@ ConnectionTest.class, TlsUtilsTest.class, ChannelNTest.class, - ValueWriterTest.class + ValueWriterTest.class, + DefaultCredentialsRefreshServiceTest.class, + OAuth2ClientCredentialsGrantCredentialsProviderTest.class, + RefreshCredentialsTest.class }) public class ClientTests { diff --git a/src/test/java/com/rabbitmq/client/test/TestUtils.java b/src/test/java/com/rabbitmq/client/test/TestUtils.java index b385c73fde..21b1f542ad 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtils.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtils.java @@ -32,6 +32,7 @@ import javax.net.ssl.SSLContext; import java.io.IOException; +import java.net.ServerSocket; import java.security.NoSuchAlgorithmException; import java.util.Arrays; import java.util.Collection; @@ -240,4 +241,12 @@ static int versionCompare(String str1, String str2) { // e.g. "1.2.3" = "1.2.3" or "1.2.3" < "1.2.3.4" return Integer.signum(vals1.length - vals2.length); } + + public static int randomNetworkPort() throws IOException { + ServerSocket socket = new ServerSocket(); + socket.bind(null); + int port = socket.getLocalPort(); + socket.close(); + return port; + } } From 116f57024be21d466b0edcbd463db92d0bc1be22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 24 Jun 2019 14:16:26 +0200 Subject: [PATCH 1165/2114] Create RefreshProtectedCredentialsProvider class To protect from several actual token retrievals to happen at the same time. This class is used in the OAuth 2 client credentials grant provider. Add also a builder to make the OAuth 2 provider easier to configure, add TLS settings and a test. (cherry picked from commit 5752e55404c771aa73f12df9b440fdb38e78ce11) Conflicts: src/test/java/com/rabbitmq/client/test/ClientTests.java --- pom.xml | 7 + ...ntCredentialsGrantCredentialsProvider.java | 186 +++++++++++------- .../RefreshProtectedCredentialsProvider.java | 113 +++++++++++ .../DefaultCredentialsRefreshServiceTest.java | 4 +- ...edentialsGrantCredentialsProviderTest.java | 176 ++++++++++++----- ...freshProtectedCredentialsProviderTest.java | 90 +++++++++ .../com/rabbitmq/client/test/ClientTests.java | 6 +- .../{ => test}/RefreshCredentialsTest.java | 45 +++-- 8 files changed, 495 insertions(+), 132 deletions(-) create mode 100644 src/main/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProvider.java create mode 100644 src/test/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProviderTest.java rename src/test/java/com/rabbitmq/client/{ => test}/RefreshCredentialsTest.java (69%) diff --git a/pom.xml b/pom.xml index d4523675c8..837802079d 100644 --- a/pom.xml +++ b/pom.xml @@ -64,6 +64,7 @@ 3.0.0 3.12.2 9.4.19.v20190610 + 1.61 3.0.1 2.5.3 @@ -751,6 +752,12 @@ ${jetty.version} test + + org.bouncycastle + bcpkix-jdk15on + ${bouncycastle.version} + test + diff --git a/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java index ca3fb5c8a3..0338fcedd6 100644 --- a/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java @@ -16,51 +16,60 @@ package com.rabbitmq.client.impl; import com.fasterxml.jackson.databind.ObjectMapper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLSocketFactory; import java.io.*; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.util.*; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - -public class OAuth2ClientCredentialsGrantCredentialsProvider implements CredentialsProvider { - - private static final Logger LOGGER = LoggerFactory.getLogger(OAuth2ClientCredentialsGrantCredentialsProvider.class); +/** + * + * @see RefreshProtectedCredentialsProvider + */ +public class OAuth2ClientCredentialsGrantCredentialsProvider extends RefreshProtectedCredentialsProvider { private static final String UTF_8_CHARSET = "UTF-8"; - private final String serverUri; // should be renamed to tokenEndpointUri? + private final String tokenEndpointUri; private final String clientId; private final String clientSecret; private final String grantType; - // UAA specific, to distinguish between different users - private final String username, password; + + private final Map parameters; private final ObjectMapper objectMapper = new ObjectMapper(); private final String id; - private final AtomicReference token = new AtomicReference<>(); + private final HostnameVerifier hostnameVerifier; + private final SSLSocketFactory sslSocketFactory; + + public OAuth2ClientCredentialsGrantCredentialsProvider(String tokenEndpointUri, String clientId, String clientSecret, String grantType) { + this(tokenEndpointUri, clientId, clientSecret, grantType, new HashMap<>()); + } + + public OAuth2ClientCredentialsGrantCredentialsProvider(String tokenEndpointUri, String clientId, String clientSecret, String grantType, + HostnameVerifier hostnameVerifier, SSLSocketFactory sslSocketFactory) { + this(tokenEndpointUri, clientId, clientSecret, grantType, new HashMap<>(), hostnameVerifier, sslSocketFactory); + } - private final Lock refreshLock = new ReentrantLock(); - private final AtomicReference latch = new AtomicReference<>(); - private AtomicBoolean refreshInProcess = new AtomicBoolean(false); + public OAuth2ClientCredentialsGrantCredentialsProvider(String tokenEndpointUri, String clientId, String clientSecret, String grantType, Map parameters) { + this(tokenEndpointUri, clientId, clientSecret, grantType, parameters, null, null); + } - public OAuth2ClientCredentialsGrantCredentialsProvider(String serverUri, String clientId, String clientSecret, String grantType, String username, String password) { - this.serverUri = serverUri; + public OAuth2ClientCredentialsGrantCredentialsProvider(String tokenEndpointUri, String clientId, String clientSecret, String grantType, Map parameters, + HostnameVerifier hostnameVerifier, SSLSocketFactory sslSocketFactory) { + this.tokenEndpointUri = tokenEndpointUri; this.clientId = clientId; this.clientSecret = clientSecret; this.grantType = grantType; - this.username = username; - this.password = password; + this.parameters = Collections.unmodifiableMap(new HashMap<>(parameters)); + this.hostnameVerifier = hostnameVerifier; + this.sslSocketFactory = sslSocketFactory; this.id = UUID.randomUUID().toString(); } @@ -90,19 +99,8 @@ public String getUsername() { } @Override - public String getPassword() { - if (token.get() == null) { - refresh(); - } - return token.get().getAccess(); - } - - @Override - public Date getExpiration() { - if (token.get() == null) { - refresh(); - } - return token.get().getExpiration(); + protected String usernameFromToken(Token token) { + return ""; } protected Token parseToken(String response) { @@ -118,47 +116,21 @@ protected Token parseToken(String response) { } @Override - public void refresh() { - // refresh should happen at once. Other calls wait for the refresh to finish and move on. - if (refreshLock.tryLock()) { - LOGGER.debug("Refreshing token"); - try { - latch.set(new CountDownLatch(1)); - refreshInProcess.set(true); - token.set(retrieveToken()); - LOGGER.debug("Token refreshed"); - } finally { - latch.get().countDown(); - refreshInProcess.set(false); - refreshLock.unlock(); - } - } else { - try { - LOGGER.debug("Waiting for token refresh to be finished"); - while (!refreshInProcess.get()) { - Thread.sleep(10); - } - latch.get().await(); - LOGGER.debug("Done waiting for token refresh"); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - } - protected Token retrieveToken() { - // FIXME handle TLS specific settings try { StringBuilder urlParameters = new StringBuilder(); encode(urlParameters, "grant_type", grantType); - encode(urlParameters, "username", username); - encode(urlParameters, "password", password); + for (Map.Entry parameter : parameters.entrySet()) { + encode(urlParameters, parameter.getKey(), parameter.getValue()); + } byte[] postData = urlParameters.toString().getBytes(StandardCharsets.UTF_8); int postDataLength = postData.length; - URL url = new URL(serverUri); + URL url = new URL(tokenEndpointUri); + // FIXME close connection? // FIXME set timeout on request HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setDoOutput(true); conn.setInstanceFollowRedirects(false); conn.setRequestMethod("POST"); @@ -168,6 +140,9 @@ protected Token retrieveToken() { conn.setRequestProperty("accept", "application/json"); conn.setRequestProperty("content-length", Integer.toString(postDataLength)); conn.setUseCaches(false); + + configureHttpConnection(conn); + try (DataOutputStream wr = new DataOutputStream(conn.getOutputStream())) { wr.write(postData); } @@ -196,6 +171,28 @@ protected Token retrieveToken() { } } + @Override + protected String passwordFromToken(Token token) { + return token.getAccess(); + } + + @Override + protected Date expirationFromToken(Token token) { + return token.getExpiration(); + } + + protected void configureHttpConnection(HttpURLConnection connection) { + if (connection instanceof HttpsURLConnection) { + HttpsURLConnection securedConnection = (HttpsURLConnection) connection; + if (this.hostnameVerifier != null) { + securedConnection.setHostnameVerifier(this.hostnameVerifier); + } + if (this.sslSocketFactory != null) { + securedConnection.setSSLSocketFactory(this.sslSocketFactory); + } + } + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -230,4 +227,59 @@ public String getAccess() { return access; } } + + public static class OAuth2ClientCredentialsGrantCredentialsProviderBuilder { + + private final Map parameters = new HashMap<>(); + private String tokenEndpointUri; + private String clientId; + private String clientSecret; + private String grantType = "client_credentials"; + private HostnameVerifier hostnameVerifier; + + private SSLSocketFactory sslSocketFactory; + + public OAuth2ClientCredentialsGrantCredentialsProviderBuilder tokenEndpointUri(String tokenEndpointUri) { + this.tokenEndpointUri = tokenEndpointUri; + return this; + } + + public OAuth2ClientCredentialsGrantCredentialsProviderBuilder clientId(String clientId) { + this.clientId = clientId; + return this; + } + + public OAuth2ClientCredentialsGrantCredentialsProviderBuilder clientSecret(String clientSecret) { + this.clientSecret = clientSecret; + return this; + } + + public OAuth2ClientCredentialsGrantCredentialsProviderBuilder grantType(String grantType) { + this.grantType = grantType; + return this; + } + + public OAuth2ClientCredentialsGrantCredentialsProviderBuilder parameter(String name, String value) { + this.parameters.put(name, value); + return this; + } + + public OAuth2ClientCredentialsGrantCredentialsProviderBuilder setHostnameVerifier(HostnameVerifier hostnameVerifier) { + this.hostnameVerifier = hostnameVerifier; + return this; + } + + public OAuth2ClientCredentialsGrantCredentialsProviderBuilder setSslSocketFactory(SSLSocketFactory sslSocketFactory) { + this.sslSocketFactory = sslSocketFactory; + return this; + } + + public OAuth2ClientCredentialsGrantCredentialsProvider build() { + return new OAuth2ClientCredentialsGrantCredentialsProvider( + tokenEndpointUri, clientId, clientSecret, grantType, parameters, + hostnameVerifier, sslSocketFactory + ); + } + + } } diff --git a/src/main/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProvider.java new file mode 100644 index 0000000000..7bca427205 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProvider.java @@ -0,0 +1,113 @@ +// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Date; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +/** + * An abstract {@link CredentialsProvider} that does not let token refresh happen concurrently. + *

+ * A token is usually long-lived (several minutes or more), can be re-used inside the same application, + * and refreshing it is a costly operation. This base class lets a first call to {@link #refresh()} + * pass and block concurrent calls until the first call is over. Concurrent calls are then unblocked and + * can benefit from the refresh. This avoids unnecessary refresh operations to happen if a token + * is already being renewed. + *

+ * Subclasses need to provide the actual token retrieval (whether is a first retrieval or a renewal is + * a implementation detail) and how to extract information (username, password, expiration date) from the retrieved + * token. + * + * @param the type of token (usually specified by the subclass) + */ +public abstract class RefreshProtectedCredentialsProvider implements CredentialsProvider { + + private static final Logger LOGGER = LoggerFactory.getLogger(RefreshProtectedCredentialsProvider.class); + + private final AtomicReference token = new AtomicReference<>(); + + private final Lock refreshLock = new ReentrantLock(); + private final AtomicReference latch = new AtomicReference<>(); + private AtomicBoolean refreshInProcess = new AtomicBoolean(false); + + @Override + public String getUsername() { + if (token.get() == null) { + refresh(); + } + return usernameFromToken(token.get()); + } + + @Override + public String getPassword() { + if (token.get() == null) { + refresh(); + } + return passwordFromToken(token.get()); + } + + @Override + public Date getExpiration() { + if (token.get() == null) { + refresh(); + } + return expirationFromToken(token.get()); + } + + @Override + public void refresh() { + // refresh should happen at once. Other calls wait for the refresh to finish and move on. + if (refreshLock.tryLock()) { + LOGGER.debug("Refreshing token"); + try { + latch.set(new CountDownLatch(1)); + refreshInProcess.set(true); + token.set(retrieveToken()); + LOGGER.debug("Token refreshed"); + } finally { + latch.get().countDown(); + refreshInProcess.set(false); + refreshLock.unlock(); + } + } else { + try { + LOGGER.debug("Waiting for token refresh to be finished"); + while (!refreshInProcess.get()) { + Thread.sleep(10); + } + latch.get().await(); + LOGGER.debug("Done waiting for token refresh"); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + } + + protected abstract T retrieveToken(); + + protected abstract String usernameFromToken(T token); + + protected abstract String passwordFromToken(T token); + + protected abstract Date expirationFromToken(T token); +} diff --git a/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java b/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java index 66e59ba866..56e5bd9a89 100644 --- a/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java +++ b/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java @@ -166,9 +166,7 @@ public void refreshActionIsRemovedIfItErrorsTooMuch() throws Exception { state.add(new DefaultCredentialsRefreshService.Registration("1", refreshAction)); int callsCountBeforeCancellation = 5; - IntStream.range(0, callsCountBeforeCancellation).forEach(i -> { - state.refresh(); - }); + IntStream.range(0, callsCountBeforeCancellation).forEach(i -> state.refresh()); verify(credentialsProvider, times(callsCountBeforeCancellation)).refresh(); verify(refreshAction, times(callsCountBeforeCancellation)).call(); diff --git a/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java b/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java index 6e1908fee2..662b24235c 100644 --- a/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java +++ b/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java @@ -16,28 +16,39 @@ package com.rabbitmq.client.impl; import com.rabbitmq.client.test.TestUtils; -import org.eclipse.jetty.server.Connector; -import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; +import org.bouncycastle.asn1.x500.X500NameBuilder; +import org.bouncycastle.asn1.x500.style.BCStyle; +import org.bouncycastle.cert.X509CertificateHolder; +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; +import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder; +import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; +import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.server.*; import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.server.handler.ContextHandler; +import org.eclipse.jetty.util.ssl.SslContextFactory; import org.junit.After; import org.junit.Test; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManagerFactory; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.KeyStore; +import java.security.SecureRandom; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.Calendar; import java.util.Date; -import java.util.Set; +import java.util.Map; import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; -import java.util.stream.IntStream; import static org.assertj.core.api.Assertions.assertThat; @@ -65,23 +76,26 @@ public void getToken() throws Exception { AtomicReference authorization = new AtomicReference<>(); AtomicReference accept = new AtomicReference<>(); AtomicReference accessToken = new AtomicReference<>(); + AtomicReference> httpParameters = new AtomicReference<>(); int expiresIn = 60; ContextHandler context = new ContextHandler(); - context.setContextPath("/uaa/oauth/token/"); + context.setContextPath("/uaa/oauth/token"); context.setHandler(new AbstractHandler() { @Override public void handle(String s, Request request, HttpServletRequest httpServletRequest, HttpServletResponse response) throws IOException { - httpMethod.set(request.getMethod()); contentType.set(request.getContentType()); authorization.set(request.getHeader("authorization")); accept.set(request.getHeader("accept")); accessToken.set(UUID.randomUUID().toString()); + + httpParameters.set(request.getParameterMap()); + String json = sampleJsonToken(accessToken.get(), expiresIn); response.setStatus(HttpServletResponse.SC_OK); @@ -91,7 +105,6 @@ public void handle(String s, Request request, HttpServletRequest httpServletRequ response.getWriter().print(json); request.setHandled(true); - } }); @@ -100,12 +113,13 @@ public void handle(String s, Request request, HttpServletRequest httpServletRequ server.setStopTimeout(1000); server.start(); - OAuth2ClientCredentialsGrantCredentialsProvider provider = new OAuth2ClientCredentialsGrantCredentialsProvider( - "http://localhost:" + port + "/uaa/oauth/token/", - "rabbit_client", "rabbit_secret", - "password", // UAA-specific, standard is client_credentials - "rabbit_super", "rabbit_super" // UAA-specific, to distinguish between RabbitMQ users - ); + OAuth2ClientCredentialsGrantCredentialsProvider provider = new OAuth2ClientCredentialsGrantCredentialsProvider.OAuth2ClientCredentialsGrantCredentialsProviderBuilder() + .tokenEndpointUri("http://localhost:" + port + "/uaa/oauth/token/") + .clientId("rabbit_client").clientSecret("rabbit_secret") + .grantType("password") + .parameter("username", "rabbit_super") + .parameter("password", "rabbit_super") + .build(); String password = provider.getPassword(); @@ -116,49 +130,59 @@ public void handle(String s, Request request, HttpServletRequest httpServletRequ assertThat(contentType).hasValue("application/x-www-form-urlencoded"); assertThat(authorization).hasValue("Basic cmFiYml0X2NsaWVudDpyYWJiaXRfc2VjcmV0"); assertThat(accept).hasValue("application/json"); + Map parameters = httpParameters.get(); + assertThat(parameters).isNotNull().hasSize(3).containsKeys("grant_type", "username", "password") + .hasEntrySatisfying("grant_type", v -> assertThat(v).hasSize(1).contains("password")) + .hasEntrySatisfying("username", v -> assertThat(v).hasSize(1).contains("rabbit_super")) + .hasEntrySatisfying("password", v -> assertThat(v).hasSize(1).contains("rabbit_super")); } @Test - public void refresh() throws Exception { - AtomicInteger retrieveTokenCallCount = new AtomicInteger(0); - OAuth2ClientCredentialsGrantCredentialsProvider provider = new OAuth2ClientCredentialsGrantCredentialsProvider( - "http://localhost:8080/uaa/oauth/token/", - "rabbit_client", "rabbit_secret", - "password", // UAA-specific, standard is client_credentials - "rabbit_super", "rabbit_super" // UAA-specific, to distinguish between RabbitMQ users - ) { + public void tls() throws Exception { + int port = TestUtils.randomNetworkPort(); + + String accessToken = UUID.randomUUID().toString(); + int expiresIn = 60; + + AbstractHandler httpHandler = new AbstractHandler() { @Override - protected Token retrieveToken() { - retrieveTokenCallCount.incrementAndGet(); - try { - Thread.sleep(2000L); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - return new Token(UUID.randomUUID().toString(), new Date()); + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException { + String json = sampleJsonToken(accessToken, expiresIn); + + response.setStatus(HttpServletResponse.SC_OK); + response.setContentLength(json.length()); + response.setContentType("application/json"); + + response.getWriter().print(json); + + baseRequest.setHandled(true); } }; - Set passwords = ConcurrentHashMap.newKeySet(); - CountDownLatch latch = new CountDownLatch(5); - IntStream.range(0, 5).forEach(i -> new Thread(() -> { - passwords.add(provider.getPassword()); - latch.countDown(); - }).start()); + KeyStore keyStore = startHttpsServer(port, httpHandler); - assertThat(latch.await(10, TimeUnit.SECONDS)).isTrue(); + TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); + tmf.init(keyStore); + SSLContext sslContext = SSLContext.getInstance("TLSv1.2"); + sslContext.init(null, tmf.getTrustManagers(), null); - assertThat(retrieveTokenCallCount).hasValue(1); - assertThat(passwords).hasSize(1); + OAuth2ClientCredentialsGrantCredentialsProvider provider = new OAuth2ClientCredentialsGrantCredentialsProvider.OAuth2ClientCredentialsGrantCredentialsProviderBuilder() + .tokenEndpointUri("https://localhost:" + port + "/uaa/oauth/token/") + .clientId("rabbit_client").clientSecret("rabbit_secret") + .setSslSocketFactory(sslContext.getSocketFactory()) + .build(); + + String password = provider.getPassword(); + assertThat(password).isEqualTo(accessToken); + assertThat(provider.getExpiration()).isBetween(offsetNow(expiresIn - 10), offsetNow(expiresIn + 10)); } @Test public void parseToken() { OAuth2ClientCredentialsGrantCredentialsProvider provider = new OAuth2ClientCredentialsGrantCredentialsProvider( - "http://localhost:8080/uaa/oauth/token", + "http://localhost:8080/uaa/oauth/token/", "rabbit_client", "rabbit_secret", - "password", // UAA-specific, standard is client_credentials - "rabbit_super", "rabbit_super" // UAA-specific, to distinguish between RabbitMQ users + "client_credentials" ); String accessToken = "18c1b1dfdda04382a8bcc14d077b71dd"; @@ -187,4 +211,62 @@ String sampleJsonToken(String accessToken, int expiresIn) { return json.replace("{accessToken}", accessToken).replace("{expiresIn}", expiresIn + ""); } + KeyStore startHttpsServer(int port, Handler handler) throws Exception { + KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + String keyStorePassword = "password"; + keyStore.load(null, keyStorePassword.toCharArray()); + + KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); + kpg.initialize(2048); + KeyPair kp = kpg.generateKeyPair(); + + JcaX509v3CertificateBuilder certificateBuilder = new JcaX509v3CertificateBuilder( + new X500NameBuilder().addRDN(BCStyle.CN, "localhost").build(), + BigInteger.valueOf(new SecureRandom().nextInt()), + Date.from(Instant.now().minus(10, ChronoUnit.DAYS)), + Date.from(Instant.now().plus(10, ChronoUnit.DAYS)), + new X500NameBuilder().addRDN(BCStyle.CN, "localhost").build(), + kp.getPublic() + ); + + X509CertificateHolder certificateHolder = certificateBuilder.build(new JcaContentSignerBuilder("SHA256WithRSAEncryption") + .build(kp.getPrivate())); + + X509Certificate certificate = new JcaX509CertificateConverter().getCertificate(certificateHolder); + + keyStore.setKeyEntry("default", kp.getPrivate(), keyStorePassword.toCharArray(), new Certificate[]{certificate}); + + server = new Server(); + SslContextFactory sslContextFactory = new SslContextFactory.Server(); + sslContextFactory.setKeyStore(keyStore); + sslContextFactory.setKeyStorePassword(keyStorePassword); + + HttpConfiguration httpsConfiguration = new HttpConfiguration(); + httpsConfiguration.setSecureScheme("https"); + httpsConfiguration.setSecurePort(port); + httpsConfiguration.setOutputBufferSize(32768); + + SecureRequestCustomizer src = new SecureRequestCustomizer(); + src.setStsMaxAge(2000); + src.setStsIncludeSubDomains(true); + httpsConfiguration.addCustomizer(src); + + ServerConnector https = new ServerConnector(server, + new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()), + new HttpConnectionFactory(httpsConfiguration)); + https.setPort(port); + https.setIdleTimeout(500000); + + server.setConnectors(new Connector[]{https}); + + ContextHandler context = new ContextHandler(); + context.setContextPath("/uaa/oauth/token"); + context.setHandler(handler); + + server.setHandler(context); + + server.start(); + return keyStore; + } + } diff --git a/src/test/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProviderTest.java b/src/test/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProviderTest.java new file mode 100644 index 0000000000..5c15cd7400 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProviderTest.java @@ -0,0 +1,90 @@ +// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl; + +import org.junit.Test; + +import java.util.Date; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.IntStream; + +import static org.assertj.core.api.Assertions.assertThat; + +public class RefreshProtectedCredentialsProviderTest { + + @Test + public void refresh() throws Exception { + AtomicInteger retrieveTokenCallCount = new AtomicInteger(0); + + RefreshProtectedCredentialsProvider credentialsProvider = new RefreshProtectedCredentialsProvider() { + + @Override + protected TestToken retrieveToken() { + retrieveTokenCallCount.incrementAndGet(); + try { + Thread.sleep(2000L); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + return new TestToken(UUID.randomUUID().toString(), new Date()); + } + + @Override + protected String usernameFromToken(TestToken token) { + return ""; + } + + @Override + protected String passwordFromToken(TestToken token) { + return token.secret; + } + + @Override + protected Date expirationFromToken(TestToken token) { + return token.expiration; + } + }; + + Set passwords = ConcurrentHashMap.newKeySet(); + CountDownLatch latch = new CountDownLatch(5); + IntStream.range(0, 5).forEach(i -> new Thread(() -> { + passwords.add(credentialsProvider.getPassword()); + latch.countDown(); + }).start()); + + assertThat(latch.await(10, TimeUnit.SECONDS)).isTrue(); + + assertThat(retrieveTokenCallCount).hasValue(1); + assertThat(passwords).hasSize(1); + } + + private static class TestToken { + + final String secret; + final Date expiration; + + TestToken(String secret, Date expiration) { + this.secret = secret; + this.expiration = expiration; + } + } + +} diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index 713930153b..1ec240888f 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -17,11 +17,12 @@ package com.rabbitmq.client.test; import com.rabbitmq.client.JacksonJsonRpcTest; + import com.rabbitmq.client.DefaultJsonRpcTest; -import com.rabbitmq.client.impl.ValueWriterTest; -import com.rabbitmq.client.RefreshCredentialsTest; import com.rabbitmq.client.impl.DefaultCredentialsRefreshServiceTest; import com.rabbitmq.client.impl.OAuth2ClientCredentialsGrantCredentialsProviderTest; +import com.rabbitmq.client.impl.RefreshProtectedCredentialsProviderTest; +import com.rabbitmq.client.impl.ValueWriterTest; import com.rabbitmq.utility.IntAllocatorTests; import org.junit.runner.RunWith; import org.junit.runners.Suite; @@ -77,6 +78,7 @@ TlsUtilsTest.class, ChannelNTest.class, ValueWriterTest.class, + RefreshProtectedCredentialsProviderTest.class, DefaultCredentialsRefreshServiceTest.class, OAuth2ClientCredentialsGrantCredentialsProviderTest.class, RefreshCredentialsTest.class diff --git a/src/test/java/com/rabbitmq/client/RefreshCredentialsTest.java b/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java similarity index 69% rename from src/test/java/com/rabbitmq/client/RefreshCredentialsTest.java rename to src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java index 41fe348e28..fa455b7744 100644 --- a/src/test/java/com/rabbitmq/client/RefreshCredentialsTest.java +++ b/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java @@ -13,16 +13,19 @@ // If you have any questions regarding licensing, please contact us at // info@rabbitmq.com. -package com.rabbitmq.client; +package com.rabbitmq.client.test; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.impl.DefaultCredentialsRefreshService; -import com.rabbitmq.client.impl.OAuth2ClientCredentialsGrantCredentialsProvider; -import com.rabbitmq.client.test.TestUtils; +import com.rabbitmq.client.impl.RefreshProtectedCredentialsProvider; import org.junit.Before; import org.junit.Test; import java.time.Duration; import java.util.Calendar; +import java.util.Date; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -43,26 +46,31 @@ public void tearDown() { public void connectionAndRefreshCredentials() throws Exception { ConnectionFactory cf = TestUtils.connectionFactory(); CountDownLatch latch = new CountDownLatch(5); - // OAuth server is actually not used in this test, default RabbitMQ authentication backend is - OAuth2ClientCredentialsGrantCredentialsProvider provider = new OAuth2ClientCredentialsGrantCredentialsProvider( - "http://localhost:8080/uaa/oauth/token/", - "rabbit_client", "rabbit_secret", - "password", // UAA-specific, standard is client_credentials - "rabbit_super", "rabbit_super" // UAA-specific, to distinguish between RabbitMQ users - ) { + RefreshProtectedCredentialsProvider provider = new RefreshProtectedCredentialsProvider() { @Override - protected Token retrieveToken() { + protected TestToken retrieveToken() { latch.countDown(); Calendar calendar = Calendar.getInstance(); calendar.add(Calendar.SECOND, 2); - return new Token("guest", calendar.getTime()); + return new TestToken("guest", calendar.getTime()); } @Override - public String getUsername() { + protected String usernameFromToken(TestToken token) { return "guest"; } + + @Override + protected String passwordFromToken(TestToken token) { + return token.secret; + } + + @Override + protected Date expirationFromToken(TestToken token) { + return token.expiration; + } }; + cf.setCredentialsProvider(provider); refreshService = new DefaultCredentialsRefreshService.DefaultCredentialsRefreshServiceBuilder() .refreshDelayStrategy(DefaultCredentialsRefreshService.fixedDelayBeforeExpirationRefreshDelayStrategy(Duration.ofSeconds(1))) @@ -78,4 +86,15 @@ public String getUsername() { } } + private static class TestToken { + + final String secret; + final Date expiration; + + TestToken(String secret, Date expiration) { + this.secret = secret; + this.expiration = expiration; + } + } + } From 0ce9d78fa7179ccb1ad3754b349c8204710709bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 24 Jun 2019 17:55:57 +0200 Subject: [PATCH 1166/2114] Use Duration to track token expiration Easier to work with than a Date. (cherry picked from commit 6277348afb6a23d9c0db1bdc0a26a6a8ee0eb77b) --- .../rabbitmq/client/impl/AMQConnection.java | 8 +-- .../client/impl/CredentialsProvider.java | 9 ++-- .../impl/CredentialsRefreshService.java | 6 +-- .../DefaultCredentialsRefreshService.java | 51 +++++++++---------- ...ntCredentialsGrantCredentialsProvider.java | 39 +++++++++----- .../RefreshProtectedCredentialsProvider.java | 12 ++--- .../DefaultCredentialsRefreshServiceTest.java | 14 +---- ...edentialsGrantCredentialsProviderTest.java | 14 ++--- ...freshProtectedCredentialsProviderTest.java | 12 ++--- .../client/test/RefreshCredentialsTest.java | 26 ++++++---- 10 files changed, 95 insertions(+), 96 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index 67c2c29afe..a08a785cbc 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2019 Pivotal Software, Inc. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 @@ -341,8 +341,8 @@ public void start() String username = credentialsProvider.getUsername(); String password = credentialsProvider.getPassword(); - if (credentialsProvider.getExpiration() != null) { - if (this.credentialsRefreshService.needRefresh(credentialsProvider.getExpiration())) { + if (credentialsProvider.getTimeBeforeExpiration() != null) { + if (this.credentialsRefreshService.needRefresh(credentialsProvider.getTimeBeforeExpiration())) { credentialsProvider.refresh(); username = credentialsProvider.getUsername(); password = credentialsProvider.getPassword(); @@ -426,7 +426,7 @@ public void start() throw AMQChannel.wrap(sse); } - if (this.credentialsProvider.getExpiration() != null) { + if (this.credentialsProvider.getTimeBeforeExpiration() != null) { String registrationId = this.credentialsRefreshService.register(credentialsProvider, () -> { // return false if connection is closed, so refresh service can get rid of this registration if (!isOpen()) { diff --git a/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java index a7db53f8c3..e4f6bda06a 100644 --- a/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java @@ -15,7 +15,7 @@ package com.rabbitmq.client.impl; -import java.util.Date; +import java.time.Duration; /** * Provider interface for establishing credentials for connecting to the broker. Especially useful @@ -42,16 +42,15 @@ public interface CredentialsProvider { String getPassword(); /** - * The expiration date of the credentials, if any. + * The time before the credentials expire, if they do expire. *

* If credentials do not expire, must return null. Default * behavior is to return null, assuming credentials never * expire. * - * @return credentials expiration date + * @return time before expiration */ - default Date getExpiration() { - // no expiration by default + default Duration getTimeBeforeExpiration() { return null; } diff --git a/src/main/java/com/rabbitmq/client/impl/CredentialsRefreshService.java b/src/main/java/com/rabbitmq/client/impl/CredentialsRefreshService.java index 536c0dc0e0..2e6065336e 100644 --- a/src/main/java/com/rabbitmq/client/impl/CredentialsRefreshService.java +++ b/src/main/java/com/rabbitmq/client/impl/CredentialsRefreshService.java @@ -15,7 +15,7 @@ package com.rabbitmq.client.impl; -import java.util.Date; +import java.time.Duration; import java.util.concurrent.Callable; /** @@ -65,9 +65,9 @@ public interface CredentialsRefreshService { /** * Provide a hint about whether credentials should be renewed. * - * @param expiration + * @param timeBeforeExpiration * @return true if credentials should be renewed, false otherwise */ - boolean needRefresh(Date expiration); + boolean needRefresh(Duration timeBeforeExpiration); } diff --git a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java index 091948bb82..ec083b5895 100644 --- a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java +++ b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java @@ -19,7 +19,6 @@ import org.slf4j.LoggerFactory; import java.time.Duration; -import java.util.Date; import java.util.Iterator; import java.util.Map; import java.util.UUID; @@ -35,7 +34,7 @@ *

* This implementation keeps track of entities (typically AMQP connections) that need * to renew credentials. Token renewal is scheduled based on token expiration, using - * a Function refreshDelayStrategy. Once credentials + * a Function refreshDelayStrategy. Once credentials * for a {@link CredentialsProvider} have been renewed, the callback registered * by each entity/connection is performed. This callback typically propagates * the new credentials in the entity state, e.g. sending the new password to the @@ -51,11 +50,11 @@ public class DefaultCredentialsRefreshService implements CredentialsRefreshServi private final boolean privateScheduler; - private final Function refreshDelayStrategy; + private final Function refreshDelayStrategy; - private final Function needRefreshStrategy; + private final Function needRefreshStrategy; - public DefaultCredentialsRefreshService(ScheduledExecutorService scheduler, Function refreshDelayStrategy, Function needRefreshStrategy) { + public DefaultCredentialsRefreshService(ScheduledExecutorService scheduler, Function refreshDelayStrategy, Function needRefreshStrategy) { this.refreshDelayStrategy = refreshDelayStrategy; this.needRefreshStrategy = needRefreshStrategy; if (scheduler == null) { @@ -76,7 +75,7 @@ public DefaultCredentialsRefreshService(ScheduledExecutorService scheduler, Func * @param duration * @return */ - public static Function fixedDelayBeforeExpirationRefreshDelayStrategy(Duration duration) { + public static Function fixedDelayBeforeExpirationRefreshDelayStrategy(Duration duration) { return new FixedDelayBeforeExpirationRefreshDelayStrategy(duration.toMillis()); } @@ -86,20 +85,21 @@ public static Function fixedDelayBeforeExpirationRefreshDelayStrateg * @param limitBeforeExpiration * @return */ - public static Function fixedTimeNeedRefreshStrategy(Duration limitBeforeExpiration) { + public static Function fixedTimeNeedRefreshStrategy(Duration limitBeforeExpiration) { return new FixedTimeNeedRefreshStrategy(limitBeforeExpiration.toMillis()); } // TODO add a delay refresh strategy that bases the time on a percentage of the TTL, use it as default with 80% TTL private static Runnable refresh(ScheduledExecutorService scheduler, CredentialsProviderState credentialsProviderState, - Function refreshDelayStrategy) { + Function refreshDelayStrategy) { return () -> { LOGGER.debug("Refreshing token"); credentialsProviderState.refresh(); - Date expirationAfterRefresh = credentialsProviderState.credentialsProvider.getExpiration(); - long newDelay = refreshDelayStrategy.apply(expirationAfterRefresh); + Duration timeBeforeExpiration = credentialsProviderState.credentialsProvider.getTimeBeforeExpiration(); + + long newDelay = refreshDelayStrategy.apply(timeBeforeExpiration); LOGGER.debug("Scheduling refresh in {} milliseconds", newDelay); @@ -122,8 +122,7 @@ public String register(CredentialsProvider credentialsProvider, Callable { - Date expiration = credentialsProvider.getExpiration(); - long delay = refreshDelayStrategy.apply(expiration); + long delay = refreshDelayStrategy.apply(credentialsProvider.getTimeBeforeExpiration()); LOGGER.debug("Scheduling refresh in {} milliseconds", delay); return scheduler.schedule(refresh(scheduler, credentialsProviderState, refreshDelayStrategy), delay, TimeUnit.MILLISECONDS); }); @@ -140,8 +139,8 @@ public void unregister(CredentialsProvider credentialsProvider, String registrat } @Override - public boolean needRefresh(Date expiration) { - return this.needRefreshStrategy.apply(expiration); + public boolean needRefresh(Duration timeBeforeExpiration) { + return this.needRefreshStrategy.apply(timeBeforeExpiration); } public void close() { @@ -150,7 +149,7 @@ public void close() { } } - private static class FixedTimeNeedRefreshStrategy implements Function { + private static class FixedTimeNeedRefreshStrategy implements Function { private final long limitBeforeExpiration; @@ -159,13 +158,12 @@ private FixedTimeNeedRefreshStrategy(long limitBeforeExpiration) { } @Override - public Boolean apply(Date expiration) { - long ttl = expiration.getTime() - new Date().getTime(); - return ttl <= limitBeforeExpiration; + public Boolean apply(Duration timeBeforeExpiration) { + return timeBeforeExpiration.toMillis() <= limitBeforeExpiration; } } - private static class FixedDelayBeforeExpirationRefreshDelayStrategy implements Function { + private static class FixedDelayBeforeExpirationRefreshDelayStrategy implements Function { private final long delay; @@ -174,11 +172,10 @@ private FixedDelayBeforeExpirationRefreshDelayStrategy(long delay) { } @Override - public Long apply(Date expiration) { - long ttl = expiration.getTime() - new Date().getTime(); - long refreshTimeBeforeExpiration = ttl - delay; + public Long apply(Duration timeBeforeExpiration) { + long refreshTimeBeforeExpiration = timeBeforeExpiration.toMillis() - delay; if (refreshTimeBeforeExpiration < 0) { - return ttl; + return timeBeforeExpiration.toMillis(); } else { return refreshTimeBeforeExpiration; } @@ -279,21 +276,21 @@ public static class DefaultCredentialsRefreshServiceBuilder { private ScheduledExecutorService scheduler; - private Function refreshDelayStrategy = fixedDelayBeforeExpirationRefreshDelayStrategy(Duration.ofSeconds(60)); + private Function refreshDelayStrategy = fixedDelayBeforeExpirationRefreshDelayStrategy(Duration.ofSeconds(60)); - private Function needRefreshStrategy = fixedTimeNeedRefreshStrategy(Duration.ofSeconds(60)); + private Function needRefreshStrategy = fixedTimeNeedRefreshStrategy(Duration.ofSeconds(60)); public DefaultCredentialsRefreshServiceBuilder scheduler(ScheduledThreadPoolExecutor scheduler) { this.scheduler = scheduler; return this; } - public DefaultCredentialsRefreshServiceBuilder refreshDelayStrategy(Function refreshDelayStrategy) { + public DefaultCredentialsRefreshServiceBuilder refreshDelayStrategy(Function refreshDelayStrategy) { this.refreshDelayStrategy = refreshDelayStrategy; return this; } - public DefaultCredentialsRefreshServiceBuilder needRefreshStrategy(Function needRefreshStrategy) { + public DefaultCredentialsRefreshServiceBuilder needRefreshStrategy(Function needRefreshStrategy) { this.needRefreshStrategy = needRefreshStrategy; return this; } diff --git a/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java index 0338fcedd6..48f347555a 100644 --- a/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java @@ -25,6 +25,9 @@ import java.net.URL; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.*; /** @@ -107,9 +110,8 @@ protected Token parseToken(String response) { try { Map map = objectMapper.readValue(response, Map.class); int expiresIn = ((Number) map.get("expires_in")).intValue(); - Calendar calendar = Calendar.getInstance(); - calendar.add(Calendar.SECOND, expiresIn); - return new Token(map.get("access_token").toString(), calendar.getTime()); + Instant receivedAt = Instant.now(); + return new Token(map.get("access_token").toString(), expiresIn, receivedAt); } catch (IOException e) { throw new OAuthTokenManagementException("Error while parsing OAuth 2 token", e); } @@ -177,8 +179,8 @@ protected String passwordFromToken(Token token) { } @Override - protected Date expirationFromToken(Token token) { - return token.getExpiration(); + protected Duration timeBeforeExpiration(Token token) { + return token.getTimeBeforeExpiration(); } protected void configureHttpConnection(HttpURLConnection connection) { @@ -212,20 +214,33 @@ public static class Token { private final String access; - private final Date expiration; + private final int expiresIn; - public Token(String access, Date expiration) { - this.access = access; - this.expiration = expiration; - } + private final Instant receivedAt; - public Date getExpiration() { - return expiration; + public Token(String access, int expiresIn, Instant receivedAt) { + this.access = access; + this.expiresIn = expiresIn; + this.receivedAt = receivedAt; } public String getAccess() { return access; } + + public int getExpiresIn() { + return expiresIn; + } + + public Instant getReceivedAt() { + return receivedAt; + } + + public Duration getTimeBeforeExpiration() { + Instant now = Instant.now(); + long age = receivedAt.until(now, ChronoUnit.SECONDS); + return Duration.ofSeconds(expiresIn - age); + } } public static class OAuth2ClientCredentialsGrantCredentialsProviderBuilder { diff --git a/src/main/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProvider.java index 7bca427205..21f6bc9780 100644 --- a/src/main/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProvider.java @@ -18,7 +18,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.Date; +import java.time.Duration; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; @@ -35,8 +35,8 @@ * is already being renewed. *

* Subclasses need to provide the actual token retrieval (whether is a first retrieval or a renewal is - * a implementation detail) and how to extract information (username, password, expiration date) from the retrieved - * token. + * a implementation detail) and how to extract information (username, password, time before expiration) + * from the retrieved token. * * @param the type of token (usually specified by the subclass) */ @@ -67,11 +67,11 @@ public String getPassword() { } @Override - public Date getExpiration() { + public Duration getTimeBeforeExpiration() { if (token.get() == null) { refresh(); } - return expirationFromToken(token.get()); + return timeBeforeExpiration(token.get()); } @Override @@ -109,5 +109,5 @@ public void refresh() { protected abstract String passwordFromToken(T token); - protected abstract Date expirationFromToken(T token); + protected abstract Duration timeBeforeExpiration(T token); } diff --git a/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java b/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java index 56e5bd9a89..576612db54 100644 --- a/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java +++ b/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java @@ -23,8 +23,6 @@ import org.mockito.stubbing.Answer; import java.time.Duration; -import java.util.Calendar; -import java.util.Date; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.CopyOnWriteArrayList; @@ -63,11 +61,7 @@ public void scheduling() throws Exception { AtomicInteger passwordSequence = new AtomicInteger(0); when(credentialsProvider.getPassword()).thenAnswer( (Answer) invocation -> "password-" + passwordSequence.get()); - when(credentialsProvider.getExpiration()).thenAnswer((Answer) invocation -> { - Calendar calendar = Calendar.getInstance(); - calendar.add(Calendar.SECOND, 5); - return calendar.getTime(); - }); + when(credentialsProvider.getTimeBeforeExpiration()).thenAnswer((Answer) invocation -> Duration.ofSeconds(5)); doAnswer(invocation -> { passwordSequence.incrementAndGet(); return null; @@ -88,11 +82,7 @@ public void scheduling() throws Exception { AtomicInteger passwordSequence2 = new AtomicInteger(0); CredentialsProvider credentialsProvider2 = mock(CredentialsProvider.class); when(credentialsProvider2.getPassword()).thenAnswer((Answer) invocation -> "password2-" + passwordSequence2.get()); - when(credentialsProvider2.getExpiration()).thenAnswer((Answer) invocation -> { - Calendar calendar = Calendar.getInstance(); - calendar.add(Calendar.SECOND, 4); - return calendar.getTime(); - }); + when(credentialsProvider2.getTimeBeforeExpiration()).thenAnswer((Answer) invocation -> Duration.ofSeconds(4)); doAnswer(invocation -> { passwordSequence2.incrementAndGet(); return null; diff --git a/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java b/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java index 662b24235c..2cd19ee828 100644 --- a/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java +++ b/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java @@ -42,9 +42,9 @@ import java.security.SecureRandom; import java.security.cert.Certificate; import java.security.cert.X509Certificate; +import java.time.Duration; import java.time.Instant; import java.time.temporal.ChronoUnit; -import java.util.Calendar; import java.util.Date; import java.util.Map; import java.util.UUID; @@ -124,7 +124,7 @@ public void handle(String s, Request request, HttpServletRequest httpServletRequ String password = provider.getPassword(); assertThat(password).isEqualTo(accessToken.get()); - assertThat(provider.getExpiration()).isBetween(offsetNow(expiresIn - 10), offsetNow(expiresIn + 10)); + assertThat(provider.getTimeBeforeExpiration()).isBetween(Duration.ofSeconds(expiresIn - 10), Duration.ofSeconds(expiresIn + 10)); assertThat(httpMethod).hasValue("POST"); assertThat(contentType).hasValue("application/x-www-form-urlencoded"); @@ -174,7 +174,7 @@ public void handle(String target, Request baseRequest, HttpServletRequest reques String password = provider.getPassword(); assertThat(password).isEqualTo(accessToken); - assertThat(provider.getExpiration()).isBetween(offsetNow(expiresIn - 10), offsetNow(expiresIn + 10)); + assertThat(provider.getTimeBeforeExpiration()).isBetween(Duration.ofSeconds(expiresIn - 10), Duration.ofSeconds(expiresIn + 10)); } @Test @@ -191,13 +191,7 @@ public void parseToken() { OAuth2ClientCredentialsGrantCredentialsProvider.Token token = provider.parseToken(response); assertThat(token.getAccess()).isEqualTo("18c1b1dfdda04382a8bcc14d077b71dd"); - assertThat(token.getExpiration()).isBetween(offsetNow(expiresIn - 10), offsetNow(expiresIn + 1)); - } - - Date offsetNow(int seconds) { - Calendar calendar = Calendar.getInstance(); - calendar.add(Calendar.SECOND, seconds); - return calendar.getTime(); + assertThat(token.getTimeBeforeExpiration()).isBetween(Duration.ofSeconds(expiresIn - 10), Duration.ofSeconds(expiresIn + 1)); } String sampleJsonToken(String accessToken, int expiresIn) { diff --git a/src/test/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProviderTest.java b/src/test/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProviderTest.java index 5c15cd7400..a96c757e59 100644 --- a/src/test/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProviderTest.java +++ b/src/test/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProviderTest.java @@ -17,7 +17,7 @@ import org.junit.Test; -import java.util.Date; +import java.time.Duration; import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; @@ -44,7 +44,7 @@ protected TestToken retrieveToken() { } catch (InterruptedException e) { throw new RuntimeException(e); } - return new TestToken(UUID.randomUUID().toString(), new Date()); + return new TestToken(UUID.randomUUID().toString()); } @Override @@ -58,8 +58,8 @@ protected String passwordFromToken(TestToken token) { } @Override - protected Date expirationFromToken(TestToken token) { - return token.expiration; + protected Duration timeBeforeExpiration(TestToken token) { + return Duration.ofSeconds(1); } }; @@ -79,11 +79,9 @@ protected Date expirationFromToken(TestToken token) { private static class TestToken { final String secret; - final Date expiration; - TestToken(String secret, Date expiration) { + TestToken(String secret) { this.secret = secret; - this.expiration = expiration; } } diff --git a/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java b/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java index fa455b7744..0870d4d92b 100644 --- a/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java +++ b/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java @@ -24,8 +24,8 @@ import org.junit.Test; import java.time.Duration; -import java.util.Calendar; -import java.util.Date; +import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -50,9 +50,7 @@ public void connectionAndRefreshCredentials() throws Exception { @Override protected TestToken retrieveToken() { latch.countDown(); - Calendar calendar = Calendar.getInstance(); - calendar.add(Calendar.SECOND, 2); - return new TestToken("guest", calendar.getTime()); + return new TestToken("guest", 2, Instant.now()); } @Override @@ -66,8 +64,8 @@ protected String passwordFromToken(TestToken token) { } @Override - protected Date expirationFromToken(TestToken token) { - return token.expiration; + protected Duration timeBeforeExpiration(TestToken token) { + return token.getTimeBeforeExpiration(); } }; @@ -89,11 +87,19 @@ protected Date expirationFromToken(TestToken token) { private static class TestToken { final String secret; - final Date expiration; + final int expiresIn; + final Instant receivedAt; - TestToken(String secret, Date expiration) { + TestToken(String secret, int expiresIn, Instant receivedAt) { this.secret = secret; - this.expiration = expiration; + this.expiresIn = expiresIn; + this.receivedAt = receivedAt; + } + + public Duration getTimeBeforeExpiration() { + Instant now = Instant.now(); + long age = receivedAt.until(now, ChronoUnit.SECONDS); + return Duration.ofSeconds(expiresIn - age); } } From 5471dad4860c2da155b276235f80575e40aa3aa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 25 Jun 2019 10:53:22 +0200 Subject: [PATCH 1167/2114] Add ratio-based token refresh delay strategy (cherry picked from commit 97c8700390eb199ca895b729c98a515c1474f673) --- .../DefaultCredentialsRefreshService.java | 93 +++++++++++++------ .../DefaultCredentialsRefreshServiceTest.java | 40 ++++++-- 2 files changed, 98 insertions(+), 35 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java index ec083b5895..ed081017ae 100644 --- a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java +++ b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java @@ -50,11 +50,11 @@ public class DefaultCredentialsRefreshService implements CredentialsRefreshServi private final boolean privateScheduler; - private final Function refreshDelayStrategy; + private final Function refreshDelayStrategy; private final Function needRefreshStrategy; - public DefaultCredentialsRefreshService(ScheduledExecutorService scheduler, Function refreshDelayStrategy, Function needRefreshStrategy) { + public DefaultCredentialsRefreshService(ScheduledExecutorService scheduler, Function refreshDelayStrategy, Function needRefreshStrategy) { this.refreshDelayStrategy = refreshDelayStrategy; this.needRefreshStrategy = needRefreshStrategy; if (scheduler == null) { @@ -67,43 +67,57 @@ public DefaultCredentialsRefreshService(ScheduledExecutorService scheduler, Func } /** - * Delay before refresh is TTL - specified duration. + * Delay before refresh is a ratio of the time before expiration. *

- * E.g. if TTL is 60 seconds and specified duration is 20 seconds, refresh will + * E.g. if time before expiration is 60 seconds and specified ratio is 0.8, refresh will + * be scheduled in 60 x 0.8 = 48 seconds. + * + * @param ratio + * @return the delay before refreshing + */ + public static Function ratioRefreshDelayStrategy(double ratio) { + return new RatioRefreshDelayStrategy(ratio); + } + + /** + * Delay before refresh is time before expiration - specified duration. + *

+ * E.g. if time before expiration is 60 seconds and specified duration is 20 seconds, refresh will * be scheduled in 60 - 20 = 40 seconds. * * @param duration - * @return + * @return the delay before refreshing */ - public static Function fixedDelayBeforeExpirationRefreshDelayStrategy(Duration duration) { - return new FixedDelayBeforeExpirationRefreshDelayStrategy(duration.toMillis()); + public static Function fixedDelayBeforeExpirationRefreshDelayStrategy(Duration duration) { + return new FixedDelayBeforeExpirationRefreshDelayStrategy(duration); } /** * Advise to refresh credentials if TTL <= limit. * * @param limitBeforeExpiration - * @return + * @return true if credentials should be refreshed, false otherwise */ public static Function fixedTimeNeedRefreshStrategy(Duration limitBeforeExpiration) { return new FixedTimeNeedRefreshStrategy(limitBeforeExpiration.toMillis()); } - // TODO add a delay refresh strategy that bases the time on a percentage of the TTL, use it as default with 80% TTL - private static Runnable refresh(ScheduledExecutorService scheduler, CredentialsProviderState credentialsProviderState, - Function refreshDelayStrategy) { + Function refreshDelayStrategy) { return () -> { LOGGER.debug("Refreshing token"); credentialsProviderState.refresh(); Duration timeBeforeExpiration = credentialsProviderState.credentialsProvider.getTimeBeforeExpiration(); + Duration newDelay = refreshDelayStrategy.apply(timeBeforeExpiration); - long newDelay = refreshDelayStrategy.apply(timeBeforeExpiration); + LOGGER.debug("Scheduling refresh in {} seconds", newDelay.getSeconds()); - LOGGER.debug("Scheduling refresh in {} milliseconds", newDelay); - - ScheduledFuture scheduledFuture = scheduler.schedule(refresh(scheduler, credentialsProviderState, refreshDelayStrategy), newDelay, TimeUnit.MILLISECONDS); + ScheduledFuture scheduledFuture = scheduler.schedule( + refresh(scheduler, credentialsProviderState, refreshDelayStrategy), + newDelay.getSeconds(), + TimeUnit.SECONDS + ); credentialsProviderState.refreshTask.set(scheduledFuture); }; } @@ -122,9 +136,13 @@ public String register(CredentialsProvider credentialsProvider, Callable { - long delay = refreshDelayStrategy.apply(credentialsProvider.getTimeBeforeExpiration()); - LOGGER.debug("Scheduling refresh in {} milliseconds", delay); - return scheduler.schedule(refresh(scheduler, credentialsProviderState, refreshDelayStrategy), delay, TimeUnit.MILLISECONDS); + Duration delay = refreshDelayStrategy.apply(credentialsProvider.getTimeBeforeExpiration()); + LOGGER.debug("Scheduling refresh in {} seconds", delay.getSeconds()); + return scheduler.schedule( + refresh(scheduler, credentialsProviderState, refreshDelayStrategy), + delay.getSeconds(), + TimeUnit.SECONDS + ); }); return registrationId; @@ -163,25 +181,42 @@ public Boolean apply(Duration timeBeforeExpiration) { } } - private static class FixedDelayBeforeExpirationRefreshDelayStrategy implements Function { + private static class FixedDelayBeforeExpirationRefreshDelayStrategy implements Function { - private final long delay; + private final Duration delay; - private FixedDelayBeforeExpirationRefreshDelayStrategy(long delay) { + private FixedDelayBeforeExpirationRefreshDelayStrategy(Duration delay) { this.delay = delay; } @Override - public Long apply(Duration timeBeforeExpiration) { - long refreshTimeBeforeExpiration = timeBeforeExpiration.toMillis() - delay; - if (refreshTimeBeforeExpiration < 0) { - return timeBeforeExpiration.toMillis(); + public Duration apply(Duration timeBeforeExpiration) { + Duration refreshTimeBeforeExpiration = timeBeforeExpiration.minus(delay); + if (refreshTimeBeforeExpiration.isNegative()) { + return timeBeforeExpiration; } else { return refreshTimeBeforeExpiration; } } } + private static class RatioRefreshDelayStrategy implements Function { + + private final double ratio; + + private RatioRefreshDelayStrategy(double ratio) { + if (ratio < 0 || ratio > 1) { + throw new IllegalArgumentException("Ratio should be > 0 and <= 1: " + ratio); + } + this.ratio = ratio; + } + + @Override + public Duration apply(Duration duration) { + return Duration.ofSeconds((long) ((double) duration.getSeconds() * ratio)); + } + } + static class Registration { private final Callable refreshAction; @@ -240,7 +275,7 @@ void maybeSetRefreshTask(Supplier> scheduledFutureSupplier) { } void refresh() { - // FIXME check whether thread has been cancelled or not before refresh() and registratAction.call() + // FIXME check whether thread has been cancelled or not before refresh() and refreshAction.call() // FIXME protect this call, or at least log some error this.credentialsProvider.refresh(); @@ -276,16 +311,16 @@ public static class DefaultCredentialsRefreshServiceBuilder { private ScheduledExecutorService scheduler; - private Function refreshDelayStrategy = fixedDelayBeforeExpirationRefreshDelayStrategy(Duration.ofSeconds(60)); + private Function refreshDelayStrategy = ratioRefreshDelayStrategy(0.8); - private Function needRefreshStrategy = fixedTimeNeedRefreshStrategy(Duration.ofSeconds(60)); + private Function needRefreshStrategy = ttl -> false; public DefaultCredentialsRefreshServiceBuilder scheduler(ScheduledThreadPoolExecutor scheduler) { this.scheduler = scheduler; return this; } - public DefaultCredentialsRefreshServiceBuilder refreshDelayStrategy(Function refreshDelayStrategy) { + public DefaultCredentialsRefreshServiceBuilder refreshDelayStrategy(Function refreshDelayStrategy) { this.refreshDelayStrategy = refreshDelayStrategy; return this; } diff --git a/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java b/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java index 576612db54..2229c34d52 100644 --- a/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java +++ b/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java @@ -29,8 +29,12 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Function; import java.util.stream.IntStream; +import static com.rabbitmq.client.impl.DefaultCredentialsRefreshService.fixedDelayBeforeExpirationRefreshDelayStrategy; +import static com.rabbitmq.client.impl.DefaultCredentialsRefreshService.fixedTimeNeedRefreshStrategy; +import static java.time.Duration.ofSeconds; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.*; @@ -55,13 +59,13 @@ public void tearDown() { @Test public void scheduling() throws Exception { refreshService = new DefaultCredentialsRefreshService.DefaultCredentialsRefreshServiceBuilder() - .refreshDelayStrategy(DefaultCredentialsRefreshService.fixedDelayBeforeExpirationRefreshDelayStrategy(Duration.ofSeconds(2))) + .refreshDelayStrategy(fixedDelayBeforeExpirationRefreshDelayStrategy(ofSeconds(2))) .build(); AtomicInteger passwordSequence = new AtomicInteger(0); when(credentialsProvider.getPassword()).thenAnswer( (Answer) invocation -> "password-" + passwordSequence.get()); - when(credentialsProvider.getTimeBeforeExpiration()).thenAnswer((Answer) invocation -> Duration.ofSeconds(5)); + when(credentialsProvider.getTimeBeforeExpiration()).thenAnswer((Answer) invocation -> ofSeconds(5)); doAnswer(invocation -> { passwordSequence.incrementAndGet(); return null; @@ -82,13 +86,12 @@ public void scheduling() throws Exception { AtomicInteger passwordSequence2 = new AtomicInteger(0); CredentialsProvider credentialsProvider2 = mock(CredentialsProvider.class); when(credentialsProvider2.getPassword()).thenAnswer((Answer) invocation -> "password2-" + passwordSequence2.get()); - when(credentialsProvider2.getTimeBeforeExpiration()).thenAnswer((Answer) invocation -> Duration.ofSeconds(4)); + when(credentialsProvider2.getTimeBeforeExpiration()).thenAnswer((Answer) invocation -> ofSeconds(4)); doAnswer(invocation -> { passwordSequence2.incrementAndGet(); return null; }).when(credentialsProvider2).refresh(); - List passwords2 = new CopyOnWriteArrayList<>(); CountDownLatch latch2 = new CountDownLatch(2 * 1); refreshAction = () -> { @@ -104,8 +107,6 @@ public void scheduling() throws Exception { "password2-1", "password2-2" ); assertThat(passwords).hasSizeGreaterThan(4); - - } @Test @@ -166,4 +167,31 @@ public void refreshActionIsRemovedIfItErrorsTooMuch() throws Exception { verify(refreshAction, times(callsCountBeforeCancellation)).call(); } + @Test + public void fixedDelayBeforeExpirationRefreshDelayStrategyTest() { + Function delayStrategy = fixedDelayBeforeExpirationRefreshDelayStrategy(ofSeconds(20)); + assertThat(delayStrategy.apply(ofSeconds(60))).as("refresh delay is TTL - fixed delay").isEqualTo(ofSeconds(40)); + assertThat(delayStrategy.apply(ofSeconds(10))).as("refresh delay is TTL if TTL < fixed delay").isEqualTo(ofSeconds(10)); + } + + @Test + public void fixedTimeNeedRefreshStrategyTest() { + Function refreshStrategy = fixedTimeNeedRefreshStrategy(ofSeconds(20)); + assertThat(refreshStrategy.apply(ofSeconds(60))).isFalse(); + assertThat(refreshStrategy.apply(ofSeconds(20))).isTrue(); + assertThat(refreshStrategy.apply(ofSeconds(19))).isTrue(); + assertThat(refreshStrategy.apply(ofSeconds(10))).isTrue(); + } + + @Test + public void ratioRefreshDelayStrategyTest() { + Function delayStrategy = DefaultCredentialsRefreshService.ratioRefreshDelayStrategy(0.8); + assertThat(delayStrategy.apply(ofSeconds(60))).isEqualTo(ofSeconds(48)); + assertThat(delayStrategy.apply(ofSeconds(30))).isEqualTo(ofSeconds(24)); + assertThat(delayStrategy.apply(ofSeconds(10))).isEqualTo(ofSeconds(8)); + assertThat(delayStrategy.apply(ofSeconds(5))).isEqualTo(ofSeconds(4)); + assertThat(delayStrategy.apply(ofSeconds(2))).isEqualTo(ofSeconds(1)); + assertThat(delayStrategy.apply(ofSeconds(1))).isEqualTo(ofSeconds(0)); + } + } From c5eafdc39ca0f72898004b152b9bdc4c4c50213f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 25 Jun 2019 11:52:23 +0200 Subject: [PATCH 1168/2114] Handle thread interruption in credentials refresh service (cherry picked from commit 443a5896191edbf5652841856f9f534d38665496) --- .../DefaultCredentialsRefreshService.java | 35 ++++++++++-- .../DefaultCredentialsRefreshServiceTest.java | 57 +++++++++++++++++++ 2 files changed, 88 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java index ed081017ae..032a94c779 100644 --- a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java +++ b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java @@ -275,13 +275,38 @@ void maybeSetRefreshTask(Supplier> scheduledFutureSupplier) { } void refresh() { - // FIXME check whether thread has been cancelled or not before refresh() and refreshAction.call() + if (Thread.currentThread().isInterrupted()) { + return; + } - // FIXME protect this call, or at least log some error - this.credentialsProvider.refresh(); + int attemptCount = 0; + boolean refreshSucceeded = false; + while (attemptCount < 3) { + LOGGER.debug("Refreshing token for credentials provider {}", credentialsProvider); + try { + this.credentialsProvider.refresh(); + LOGGER.debug("Token refreshed for credentials provider {}", credentialsProvider); + refreshSucceeded = true; + break; + } catch (Exception e) { + LOGGER.warn("Error while trying to refresh token: {}", e.getMessage()); + } + attemptCount++; + try { + Thread.sleep(1000L); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return; + } + } + + if (!refreshSucceeded) { + LOGGER.warn("Token refresh failed after retry, aborting callbacks"); + return; + } Iterator iterator = registrations.values().iterator(); - while (iterator.hasNext()) { + while (iterator.hasNext() && !Thread.currentThread().isInterrupted()) { Registration registration = iterator.next(); // FIXME set a timeout on the call? (needs a separate thread) try { @@ -291,6 +316,8 @@ void refresh() { iterator.remove(); } registration.errorHistory.set(0); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); } catch (Exception e) { LOGGER.warn("Error while trying to refresh a connection token", e); registration.errorHistory.incrementAndGet(); diff --git a/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java b/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java index 2229c34d52..5a1518610d 100644 --- a/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java +++ b/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java @@ -167,6 +167,63 @@ public void refreshActionIsRemovedIfItErrorsTooMuch() throws Exception { verify(refreshAction, times(callsCountBeforeCancellation)).call(); } + @Test + public void errorInRefreshShouldBeRetried() throws Exception { + DefaultCredentialsRefreshService.CredentialsProviderState state = new DefaultCredentialsRefreshService.CredentialsProviderState( + credentialsProvider + ); + doThrow(RuntimeException.class).doThrow(RuntimeException.class) + .doNothing().when(credentialsProvider).refresh(); + + when(refreshAction.call()).thenReturn(true); + + state.add(new DefaultCredentialsRefreshService.Registration("1", refreshAction)); + + state.refresh(); + + verify(credentialsProvider, times(3)).refresh(); + verify(refreshAction, times(1)).call(); + } + + @Test + public void callbacksAreNotCalledWhenRetryOnRefreshIsExhausted() throws Exception { + DefaultCredentialsRefreshService.CredentialsProviderState state = new DefaultCredentialsRefreshService.CredentialsProviderState( + credentialsProvider + ); + doThrow(RuntimeException.class).when(credentialsProvider).refresh(); + + state.add(new DefaultCredentialsRefreshService.Registration("1", refreshAction)); + + state.refresh(); + + verify(credentialsProvider, times(3)).refresh(); + verify(refreshAction, times(0)).call(); + } + + @Test + public void refreshCanBeInterrupted() throws Exception { + DefaultCredentialsRefreshService.CredentialsProviderState state = new DefaultCredentialsRefreshService.CredentialsProviderState( + credentialsProvider + ); + + AtomicInteger callbackCount = new AtomicInteger(10); + when(refreshAction.call()).thenAnswer(invocation -> { + callbackCount.decrementAndGet(); + Thread.sleep(1000L); + return true; + }); + + IntStream.range(0, callbackCount.get()).forEach(i -> state.add(new DefaultCredentialsRefreshService.Registration(i + "", refreshAction))); + + Thread refreshThread = new Thread(() -> state.refresh()); + refreshThread.start(); + Thread.sleep(1000L); + refreshThread.interrupt(); + refreshThread.join(5000); + assertThat(refreshThread.isAlive()).isFalse(); + assertThat(callbackCount).hasValueGreaterThan(1); // not all the callbacks were called, because thread has been cancelled + } + @Test public void fixedDelayBeforeExpirationRefreshDelayStrategyTest() { Function delayStrategy = fixedDelayBeforeExpirationRefreshDelayStrategy(ofSeconds(20)); From e58fca1b05597eacb75865afc63151e153ca93eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 4 Jul 2019 12:01:17 +0200 Subject: [PATCH 1169/2114] Send update.secret extension when scheduled [#167029587] (cherry picked from commit 136b3ea7232356ad98e94b3f57d34e267c2cebeb) --- .../rabbitmq/client/impl/AMQConnection.java | 6 +- .../DefaultCredentialsRefreshServiceTest.java | 57 +++++++++++- .../client/test/RefreshCredentialsTest.java | 4 + .../com/rabbitmq/client/test/TestUtils.java | 93 +++++++++++++------ .../rabbitmq/client/test/TestUtilsTest.java | 19 ++++ 5 files changed, 147 insertions(+), 32 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index a08a785cbc..4b98db5af1 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -438,8 +438,10 @@ public void start() } String refreshedPassword = credentialsProvider.getPassword(); - // TODO send password to server with update-secret extension, using channel 0 - + AMQImpl.Connection.UpdateSecret updateSecret = new AMQImpl.Connection.UpdateSecret( + LongStringHelper.asLongString(refreshedPassword), "Refresh scheduled by client" + ); + _channel0.rpc(updateSecret); return true; }); diff --git a/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java b/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java index 5a1518610d..0fa8e7ca72 100644 --- a/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java +++ b/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java @@ -15,6 +15,10 @@ package com.rabbitmq.client.impl; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.test.TestUtils; import org.junit.After; import org.junit.Test; import org.junit.runner.RunWith; @@ -22,6 +26,7 @@ import org.mockito.junit.MockitoJUnitRunner; import org.mockito.stubbing.Answer; +import java.io.IOException; import java.time.Duration; import java.util.List; import java.util.concurrent.Callable; @@ -32,8 +37,7 @@ import java.util.function.Function; import java.util.stream.IntStream; -import static com.rabbitmq.client.impl.DefaultCredentialsRefreshService.fixedDelayBeforeExpirationRefreshDelayStrategy; -import static com.rabbitmq.client.impl.DefaultCredentialsRefreshService.fixedTimeNeedRefreshStrategy; +import static com.rabbitmq.client.impl.DefaultCredentialsRefreshService.*; import static java.time.Duration.ofSeconds; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.*; @@ -56,6 +60,55 @@ public void tearDown() { } } + @Test public void renew() { + ConnectionFactory cf = new ConnectionFactory(); + OAuth2ClientCredentialsGrantCredentialsProvider provider = new OAuth2ClientCredentialsGrantCredentialsProvider.OAuth2ClientCredentialsGrantCredentialsProviderBuilder() + .tokenEndpointUri("http://localhost:" + 8080 + "/uaa/oauth/token") + .clientId("rabbit_client").clientSecret("rabbit_secret") + .grantType("password") + .parameter("username", "rabbit_super") + .parameter("password", "rabbit_super") + .build(); + cf.setCredentialsProvider(provider); + + + } + + @Test public void connect() throws Exception { + ConnectionFactory cf = new ConnectionFactory(); + OAuth2ClientCredentialsGrantCredentialsProvider provider = new OAuth2ClientCredentialsGrantCredentialsProvider.OAuth2ClientCredentialsGrantCredentialsProviderBuilder() + .tokenEndpointUri("http://localhost:" + 8080 + "/uaa/oauth/token") + .clientId("rabbit_client").clientSecret("rabbit_secret") + .grantType("password") + .parameter("username", "rabbit_super") + .parameter("password", "rabbit_super") + .build(); + cf.setCredentialsProvider(provider); + refreshService = new DefaultCredentialsRefreshService.DefaultCredentialsRefreshServiceBuilder() +// .refreshDelayStrategy(ttl -> Duration.ofSeconds(60)) + .refreshDelayStrategy(ratioRefreshDelayStrategy(0.8)) + .needRefreshStrategy(expiration -> false) + .build(); + cf.setCredentialsRefreshService(refreshService); + try (Connection c = cf.newConnection()) { + + while (true) { + try { + Channel ch = c.createChannel(); + String queue = ch.queueDeclare().getQueue(); + TestUtils.sendAndConsumeMessage("", queue, queue, c); + System.out.println("Message sent and consumed"); + ch.close(); + } catch (IOException e) { + System.out.println(e.getCause().getMessage()); + } + Thread.sleep(10_000L); + } + } + + + } + @Test public void scheduling() throws Exception { refreshService = new DefaultCredentialsRefreshService.DefaultCredentialsRefreshServiceBuilder() diff --git a/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java b/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java index 0870d4d92b..963adc7964 100644 --- a/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java +++ b/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java @@ -21,7 +21,9 @@ import com.rabbitmq.client.impl.DefaultCredentialsRefreshService; import com.rabbitmq.client.impl.RefreshProtectedCredentialsProvider; import org.junit.Before; +import org.junit.ClassRule; import org.junit.Test; +import org.junit.rules.TestRule; import java.time.Duration; import java.time.Instant; @@ -33,6 +35,8 @@ public class RefreshCredentialsTest { + @ClassRule + public static TestRule brokerVersionTestRule = TestUtils.atLeast38(); DefaultCredentialsRefreshService refreshService; @Before diff --git a/src/test/java/com/rabbitmq/client/test/TestUtils.java b/src/test/java/com/rabbitmq/client/test/TestUtils.java index 21b1f542ad..e2890ab4bc 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtils.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtils.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2019 Pivotal Software, Inc. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 @@ -15,19 +15,14 @@ package com.rabbitmq.client.test; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.ConnectionFactory; -import com.rabbitmq.client.DefaultConsumer; -import com.rabbitmq.client.Envelope; -import com.rabbitmq.client.Recoverable; -import com.rabbitmq.client.RecoverableConnection; -import com.rabbitmq.client.RecoveryListener; -import com.rabbitmq.client.ShutdownSignalException; +import com.rabbitmq.client.*; import com.rabbitmq.client.impl.NetworkConnection; import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; import com.rabbitmq.tools.Host; +import org.junit.AssumptionViolatedException; +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; import org.slf4j.LoggerFactory; import javax.net.ssl.SSLContext; @@ -46,7 +41,7 @@ public class TestUtils { - public static final boolean USE_NIO = System.getProperty("use.nio") == null ? false : true; + public static final boolean USE_NIO = System.getProperty("use.nio") != null; public static ConnectionFactory connectionFactory() { ConnectionFactory connectionFactory = new ConnectionFactory(); @@ -79,7 +74,7 @@ public static SSLContext getSSLContext() throws NoSuchAlgorithmException { // pick the first protocol available, preferring TLSv1.2, then TLSv1, // falling back to SSLv3 if running on an ancient/crippled JDK - for(String proto : Arrays.asList("TLSv1.2", "TLSv1", "SSLv3")) { + for (String proto : Arrays.asList("TLSv1.2", "TLSv1", "SSLv3")) { try { c = SSLContext.getInstance(proto); return c; @@ -90,31 +85,49 @@ public static SSLContext getSSLContext() throws NoSuchAlgorithmException { throw new NoSuchAlgorithmException(); } + public static TestRule atLeast38() { + return new BrokerVersionTestRule("3.8.0"); + } + public static boolean isVersion37orLater(Connection connection) { + return atLeastVersion("3.7.0", connection); + } + + public static boolean isVersion38orLater(Connection connection) { + return atLeastVersion("3.8.0", connection); + } + + private static boolean atLeastVersion(String expectedVersion, Connection connection) { String currentVersion = null; try { - currentVersion = connection.getServerProperties().get("version").toString(); - // versions built from source: 3.7.0+rc.1.4.gedc5d96 - if (currentVersion.contains("+")) { - currentVersion = currentVersion.substring(0, currentVersion.indexOf("+")); - } - // alpha (snapshot) versions: 3.7.0~alpha.449-1 - if (currentVersion.contains("~")) { - currentVersion = currentVersion.substring(0, currentVersion.indexOf("~")); - } - // alpha (snapshot) versions: 3.7.1-alpha.40 - if (currentVersion.contains("-")) { - currentVersion = currentVersion.substring(0, currentVersion.indexOf("-")); - } - return "0.0.0".equals(currentVersion) || versionCompare(currentVersion, "3.7.0") >= 0; + currentVersion = currentVersion( + connection.getServerProperties().get("version").toString() + ); + return "0.0.0".equals(currentVersion) || versionCompare(currentVersion, expectedVersion) >= 0; } catch (RuntimeException e) { LoggerFactory.getLogger(TestUtils.class).warn("Unable to parse broker version {}", currentVersion, e); throw e; } } + private static String currentVersion(String currentVersion) { + // versions built from source: 3.7.0+rc.1.4.gedc5d96 + if (currentVersion.contains("+")) { + currentVersion = currentVersion.substring(0, currentVersion.indexOf("+")); + } + // alpha (snapshot) versions: 3.7.0~alpha.449-1 + if (currentVersion.contains("~")) { + currentVersion = currentVersion.substring(0, currentVersion.indexOf("~")); + } + // alpha (snapshot) versions: 3.7.1-alpha.40 + if (currentVersion.contains("-")) { + currentVersion = currentVersion.substring(0, currentVersion.indexOf("-")); + } + return currentVersion; + } + public static boolean sendAndConsumeMessage(String exchange, String routingKey, String queue, Connection c) - throws IOException, TimeoutException, InterruptedException { + throws IOException, TimeoutException, InterruptedException { Channel ch = c.createChannel(); try { ch.confirmSelect(); @@ -249,4 +262,28 @@ public static int randomNetworkPort() throws IOException { socket.close(); return port; } + + private static class BrokerVersionTestRule implements TestRule { + + private final String version; + + public BrokerVersionTestRule(String version) { + this.version = version; + } + + @Override + public Statement apply(Statement base, Description description) { + return new Statement() { + @Override + public void evaluate() throws Throwable { + try (Connection c = TestUtils.connectionFactory().newConnection()) { + if (!TestUtils.atLeastVersion(version, c)) { + throw new AssumptionViolatedException("Broker version < " + version + ", skipping."); + } + } + base.evaluate(); + } + }; + } + } } diff --git a/src/test/java/com/rabbitmq/client/test/TestUtilsTest.java b/src/test/java/com/rabbitmq/client/test/TestUtilsTest.java index 379196a6d0..00374f3a4e 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtilsTest.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtilsTest.java @@ -43,4 +43,23 @@ public void isVersion37orLater() { serverProperties.put("version", "3.7.1-alpha.40"); assertThat(TestUtils.isVersion37orLater(connection), is(true)); } + + @Test + public void isVersion38orLater() { + Map serverProperties = new HashMap<>(); + Connection connection = mock(Connection.class); + when(connection.getServerProperties()).thenReturn(serverProperties); + + serverProperties.put("version", "3.7.0+rc.1.4.gedc5d96"); + assertThat(TestUtils.isVersion38orLater(connection), is(false)); + + serverProperties.put("version", "3.7.0~alpha.449-1"); + assertThat(TestUtils.isVersion38orLater(connection), is(false)); + + serverProperties.put("version", "3.7.1-alpha.40"); + assertThat(TestUtils.isVersion38orLater(connection), is(false)); + + serverProperties.put("version", "3.8.0+beta.4.38.g33a7f97"); + assertThat(TestUtils.isVersion38orLater(connection), is(true)); + } } From bee8fb4cc95607907988e2eff10872376c5f06cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 4 Jul 2019 14:32:34 +0200 Subject: [PATCH 1170/2114] Remove some OAuth 2 integration tests They were supposed to be manual tests. (cherry picked from commit 7b50067c9a23412a7a156acf9d1dfe7fb45db778) --- .../DefaultCredentialsRefreshServiceTest.java | 57 +------------------ 1 file changed, 2 insertions(+), 55 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java b/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java index 0fa8e7ca72..5a1518610d 100644 --- a/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java +++ b/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java @@ -15,10 +15,6 @@ package com.rabbitmq.client.impl; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.ConnectionFactory; -import com.rabbitmq.client.test.TestUtils; import org.junit.After; import org.junit.Test; import org.junit.runner.RunWith; @@ -26,7 +22,6 @@ import org.mockito.junit.MockitoJUnitRunner; import org.mockito.stubbing.Answer; -import java.io.IOException; import java.time.Duration; import java.util.List; import java.util.concurrent.Callable; @@ -37,7 +32,8 @@ import java.util.function.Function; import java.util.stream.IntStream; -import static com.rabbitmq.client.impl.DefaultCredentialsRefreshService.*; +import static com.rabbitmq.client.impl.DefaultCredentialsRefreshService.fixedDelayBeforeExpirationRefreshDelayStrategy; +import static com.rabbitmq.client.impl.DefaultCredentialsRefreshService.fixedTimeNeedRefreshStrategy; import static java.time.Duration.ofSeconds; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.*; @@ -60,55 +56,6 @@ public void tearDown() { } } - @Test public void renew() { - ConnectionFactory cf = new ConnectionFactory(); - OAuth2ClientCredentialsGrantCredentialsProvider provider = new OAuth2ClientCredentialsGrantCredentialsProvider.OAuth2ClientCredentialsGrantCredentialsProviderBuilder() - .tokenEndpointUri("http://localhost:" + 8080 + "/uaa/oauth/token") - .clientId("rabbit_client").clientSecret("rabbit_secret") - .grantType("password") - .parameter("username", "rabbit_super") - .parameter("password", "rabbit_super") - .build(); - cf.setCredentialsProvider(provider); - - - } - - @Test public void connect() throws Exception { - ConnectionFactory cf = new ConnectionFactory(); - OAuth2ClientCredentialsGrantCredentialsProvider provider = new OAuth2ClientCredentialsGrantCredentialsProvider.OAuth2ClientCredentialsGrantCredentialsProviderBuilder() - .tokenEndpointUri("http://localhost:" + 8080 + "/uaa/oauth/token") - .clientId("rabbit_client").clientSecret("rabbit_secret") - .grantType("password") - .parameter("username", "rabbit_super") - .parameter("password", "rabbit_super") - .build(); - cf.setCredentialsProvider(provider); - refreshService = new DefaultCredentialsRefreshService.DefaultCredentialsRefreshServiceBuilder() -// .refreshDelayStrategy(ttl -> Duration.ofSeconds(60)) - .refreshDelayStrategy(ratioRefreshDelayStrategy(0.8)) - .needRefreshStrategy(expiration -> false) - .build(); - cf.setCredentialsRefreshService(refreshService); - try (Connection c = cf.newConnection()) { - - while (true) { - try { - Channel ch = c.createChannel(); - String queue = ch.queueDeclare().getQueue(); - TestUtils.sendAndConsumeMessage("", queue, queue, c); - System.out.println("Message sent and consumed"); - ch.close(); - } catch (IOException e) { - System.out.println(e.getCause().getMessage()); - } - Thread.sleep(10_000L); - } - } - - - } - @Test public void scheduling() throws Exception { refreshService = new DefaultCredentialsRefreshService.DefaultCredentialsRefreshServiceBuilder() From 9b3523020d98fdca7e2458a47893f871bc269678 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 4 Jul 2019 17:52:26 +0200 Subject: [PATCH 1171/2114] Handle credentials refresh error [#167029587] (cherry picked from commit 77951bc2a5a8dad2488c5a3ffb41c99b5208f570) Conflicts: src/test/java/com/rabbitmq/client/test/ClientTests.java --- .../rabbitmq/client/impl/AMQConnection.java | 21 ++- .../AMQConnectionRefreshCredentialsTest.java | 173 ++++++++++++++++++ .../com/rabbitmq/client/test/ClientTests.java | 5 +- 3 files changed, 191 insertions(+), 8 deletions(-) create mode 100644 src/test/java/com/rabbitmq/client/impl/AMQConnectionRefreshCredentialsTest.java diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index 4b98db5af1..cf41ded34d 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -243,11 +243,7 @@ public AMQConnection(ConnectionParams params, FrameHandler frameHandler, Metrics this.credentialsRefreshService = params.getCredentialsRefreshService(); - this._channel0 = new AMQChannel(this, 0) { - @Override public boolean processAsync(Command c) throws IOException { - return getConnection().processControlCommand(c); - } - }; + this._channel0 = createChannel0(); this._channelManager = null; @@ -262,6 +258,14 @@ public AMQConnection(ConnectionParams params, FrameHandler frameHandler, Metrics this.workPoolTimeout = params.getWorkPoolTimeout(); } + AMQChannel createChannel0() { + return new AMQChannel(this, 0) { + @Override public boolean processAsync(Command c) throws IOException { + return getConnection().processControlCommand(c); + } + }; + } + private void initializeConsumerWorkService() { this._workService = new ConsumerWorkService(consumerWorkServiceExecutor, threadFactory, workPoolTimeout, shutdownTimeout); } @@ -441,7 +445,12 @@ public void start() AMQImpl.Connection.UpdateSecret updateSecret = new AMQImpl.Connection.UpdateSecret( LongStringHelper.asLongString(refreshedPassword), "Refresh scheduled by client" ); - _channel0.rpc(updateSecret); + try { + _channel0.rpc(updateSecret); + } catch (ShutdownSignalException e) { + LOGGER.warn("Error while trying to update secret: {}. Connection has been closed.", e.getMessage()); + return false; + } return true; }); diff --git a/src/test/java/com/rabbitmq/client/impl/AMQConnectionRefreshCredentialsTest.java b/src/test/java/com/rabbitmq/client/impl/AMQConnectionRefreshCredentialsTest.java new file mode 100644 index 0000000000..d0978e1e61 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/impl/AMQConnectionRefreshCredentialsTest.java @@ -0,0 +1,173 @@ +// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl; + +import com.rabbitmq.client.Method; +import com.rabbitmq.client.*; +import com.rabbitmq.client.test.TestUtils; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.rules.TestRule; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import java.io.IOException; +import java.time.Duration; +import java.util.UUID; +import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.*; + +@RunWith(MockitoJUnitRunner.class) +public class AMQConnectionRefreshCredentialsTest { + + @ClassRule + public static TestRule brokerVersionTestRule = TestUtils.atLeast38(); + + @Mock + CredentialsProvider credentialsProvider; + + @Mock + CredentialsRefreshService refreshService; + + private static ConnectionFactory connectionFactoryThatSendsGarbageAfterUpdateSecret() { + ConnectionFactory cf = new ConnectionFactory() { + @Override + protected AMQConnection createConnection(ConnectionParams params, FrameHandler frameHandler, MetricsCollector metricsCollector) { + return new AMQConnection(params, frameHandler, metricsCollector) { + + @Override + AMQChannel createChannel0() { + return new AMQChannel(this, 0) { + @Override + public boolean processAsync(Command c) throws IOException { + return getConnection().processControlCommand(c); + } + + @Override + public AMQCommand rpc(Method m) throws IOException, ShutdownSignalException { + if (m instanceof AMQImpl.Connection.UpdateSecret) { + super.rpc(m); + return super.rpc(new AMQImpl.Connection.UpdateSecret(LongStringHelper.asLongString(""), "Refresh scheduled by client") { + @Override + public int protocolMethodId() { + return 255; + } + }); + } else { + return super.rpc(m); + } + + } + }; + + } + }; + } + }; + cf.setAutomaticRecoveryEnabled(false); + if (TestUtils.USE_NIO) { + cf.useNio(); + } + return cf; + } + + @Test + @SuppressWarnings("unchecked") + public void connectionIsUnregisteredFromRefreshServiceWhenClosed() throws Exception { + when(credentialsProvider.getUsername()).thenReturn("guest"); + when(credentialsProvider.getPassword()).thenReturn("guest"); + when(credentialsProvider.getTimeBeforeExpiration()).thenReturn(Duration.ofSeconds(10)); + + ConnectionFactory cf = TestUtils.connectionFactory(); + cf.setCredentialsProvider(credentialsProvider); + + String registrationId = UUID.randomUUID().toString(); + CountDownLatch unregisteredLatch = new CountDownLatch(1); + + AtomicReference> refreshTokenCallable = new AtomicReference<>(); + when(refreshService.register(eq(credentialsProvider), any(Callable.class))).thenAnswer(invocation -> { + refreshTokenCallable.set(invocation.getArgument(1)); + return registrationId; + }); + doAnswer(invocation -> { + unregisteredLatch.countDown(); + return null; + }).when(refreshService).unregister(credentialsProvider, registrationId); + + cf.setCredentialsRefreshService(refreshService); + + verify(refreshService, never()).register(any(CredentialsProvider.class), any(Callable.class)); + try (Connection c = cf.newConnection()) { + verify(refreshService, times(1)).register(eq(credentialsProvider), any(Callable.class)); + Channel ch = c.createChannel(); + String queue = ch.queueDeclare().getQueue(); + TestUtils.sendAndConsumeMessage("", queue, queue, c); + verify(refreshService, never()).unregister(any(CredentialsProvider.class), anyString()); + // calling refresh + assertThat(refreshTokenCallable.get().call()).isTrue(); + } + verify(refreshService, times(1)).register(eq(credentialsProvider), any(Callable.class)); + assertThat(unregisteredLatch.await(5, TimeUnit.SECONDS)).isTrue(); + verify(refreshService, times(1)).unregister(credentialsProvider, registrationId); + } + + @Test + @SuppressWarnings("unchecked") + public void connectionIsUnregisteredFromRefreshServiceIfUpdateSecretFails() throws Exception { + when(credentialsProvider.getUsername()).thenReturn("guest"); + when(credentialsProvider.getPassword()).thenReturn("guest"); + when(credentialsProvider.getTimeBeforeExpiration()).thenReturn(Duration.ofSeconds(10)); + + ConnectionFactory cf = connectionFactoryThatSendsGarbageAfterUpdateSecret(); + cf.setCredentialsProvider(credentialsProvider); + + String registrationId = UUID.randomUUID().toString(); + CountDownLatch unregisteredLatch = new CountDownLatch(1); + AtomicReference> refreshTokenCallable = new AtomicReference<>(); + when(refreshService.register(eq(credentialsProvider), any(Callable.class))).thenAnswer(invocation -> { + refreshTokenCallable.set(invocation.getArgument(1)); + return registrationId; + }); + doAnswer(invocation -> { + unregisteredLatch.countDown(); + return null; + }).when(refreshService).unregister(credentialsProvider, registrationId); + + cf.setCredentialsRefreshService(refreshService); + + Connection c = cf.newConnection(); + verify(refreshService, times(1)).register(eq(credentialsProvider), any(Callable.class)); + Channel ch = c.createChannel(); + String queue = ch.queueDeclare().getQueue(); + TestUtils.sendAndConsumeMessage("", queue, queue, c); + verify(refreshService, never()).unregister(any(CredentialsProvider.class), anyString()); + + verify(refreshService, never()).unregister(any(CredentialsProvider.class), anyString()); + // calling refresh, this sends garbage and should make the broker close the connection + assertThat(refreshTokenCallable.get().call()).isFalse(); + assertThat(unregisteredLatch.await(5, TimeUnit.SECONDS)).isTrue(); + verify(refreshService, times(1)).unregister(credentialsProvider, registrationId); + assertThat(c.isOpen()).isFalse(); + } +} diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index 1ec240888f..24a86ea7fa 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -17,12 +17,12 @@ package com.rabbitmq.client.test; import com.rabbitmq.client.JacksonJsonRpcTest; - import com.rabbitmq.client.DefaultJsonRpcTest; import com.rabbitmq.client.impl.DefaultCredentialsRefreshServiceTest; import com.rabbitmq.client.impl.OAuth2ClientCredentialsGrantCredentialsProviderTest; import com.rabbitmq.client.impl.RefreshProtectedCredentialsProviderTest; import com.rabbitmq.client.impl.ValueWriterTest; +import com.rabbitmq.client.impl.*; import com.rabbitmq.utility.IntAllocatorTests; import org.junit.runner.RunWith; import org.junit.runners.Suite; @@ -81,7 +81,8 @@ RefreshProtectedCredentialsProviderTest.class, DefaultCredentialsRefreshServiceTest.class, OAuth2ClientCredentialsGrantCredentialsProviderTest.class, - RefreshCredentialsTest.class + RefreshCredentialsTest.class, + AMQConnectionRefreshCredentialsTest.class }) public class ClientTests { From 3c2b4833bc9b0ef38f6338cd6b65690fa2698f25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 5 Jul 2019 10:47:45 +0200 Subject: [PATCH 1172/2114] Document credentials refresh service [#167029587] (cherry picked from commit 1c7b21c5f5f5f93e4ae5884269b5702c2ae38558) --- .../rabbitmq/client/ConnectionFactory.java | 28 +++++++++++-------- .../rabbitmq/client/impl/AMQConnection.java | 3 ++ 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 0047d55245..ea79e354f2 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -32,17 +32,8 @@ import java.net.URLDecoder; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.TimeoutException; +import java.util.*; +import java.util.concurrent.*; import java.util.function.Predicate; import static java.util.concurrent.TimeUnit.MINUTES; @@ -848,6 +839,21 @@ public MetricsCollector getMetricsCollector() { return metricsCollector; } + /** + * Set a {@link CredentialsRefreshService} instance to handle credentials refresh if appropriate. + *

+ * Each created connection will register to the refresh service to send an AMQP update.secret + * frame when credentials are about to expire. This is the refresh service responsibility to schedule + * credentials refresh and udpate.secret frame sending, based on the information provided + * by the {@link CredentialsProvider}. + *

+ * Note the {@link CredentialsRefreshService} is used only when the {@link CredentialsProvider} + * signals credentials can expire, by returning a non-null value from {@link CredentialsProvider#getTimeBeforeExpiration()}. + * + * @param credentialsRefreshService the refresh service to use + * @see #setCredentialsProvider(CredentialsProvider) + * @see DefaultCredentialsRefreshService + */ public void setCredentialsRefreshService(CredentialsRefreshService credentialsRefreshService) { this.credentialsRefreshService = credentialsRefreshService; } diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index cf41ded34d..cdb4623b71 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -346,6 +346,9 @@ public void start() String password = credentialsProvider.getPassword(); if (credentialsProvider.getTimeBeforeExpiration() != null) { + if (this.credentialsRefreshService == null) { + throw new IllegalStateException("Credentials can expire, a credentials refresh service should be set"); + } if (this.credentialsRefreshService.needRefresh(credentialsProvider.getTimeBeforeExpiration())) { credentialsProvider.refresh(); username = credentialsProvider.getUsername(); From aa4bb335032480edd93d5a9b7d7d8934764c0be7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 8 Jul 2019 15:01:51 +0200 Subject: [PATCH 1173/2114] Rename CredentialsRefreshService#needRefresh to isApproachingExpiration [#167029587] (cherry picked from commit 7dc7170ce0562cce0891f2f62f9c1258cfc52074) --- .../rabbitmq/client/impl/AMQConnection.java | 2 +- .../impl/CredentialsRefreshService.java | 8 ++- .../DefaultCredentialsRefreshService.java | 72 ++++++++++++++----- .../DefaultCredentialsRefreshServiceTest.java | 6 +- .../client/test/RefreshCredentialsTest.java | 2 +- 5 files changed, 66 insertions(+), 24 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index cdb4623b71..5717611bb7 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -349,7 +349,7 @@ public void start() if (this.credentialsRefreshService == null) { throw new IllegalStateException("Credentials can expire, a credentials refresh service should be set"); } - if (this.credentialsRefreshService.needRefresh(credentialsProvider.getTimeBeforeExpiration())) { + if (this.credentialsRefreshService.isApproachingExpiration(credentialsProvider.getTimeBeforeExpiration())) { credentialsProvider.refresh(); username = credentialsProvider.getUsername(); password = credentialsProvider.getPassword(); diff --git a/src/main/java/com/rabbitmq/client/impl/CredentialsRefreshService.java b/src/main/java/com/rabbitmq/client/impl/CredentialsRefreshService.java index 2e6065336e..675fa8fe1b 100644 --- a/src/main/java/com/rabbitmq/client/impl/CredentialsRefreshService.java +++ b/src/main/java/com/rabbitmq/client/impl/CredentialsRefreshService.java @@ -63,11 +63,15 @@ public interface CredentialsRefreshService { void unregister(CredentialsProvider credentialsProvider, String registrationId); /** - * Provide a hint about whether credentials should be renewed. + * Provide a hint about whether credentials should be renewed now or not before attempting to connect. + *

+ * This can avoid a connection to use almost expired credentials if this connection + * is created just before credentials are refreshed in the background, but does not + * benefit from the refresh. * * @param timeBeforeExpiration * @return true if credentials should be renewed, false otherwise */ - boolean needRefresh(Duration timeBeforeExpiration); + boolean isApproachingExpiration(Duration timeBeforeExpiration); } diff --git a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java index 032a94c779..39d6db1fda 100644 --- a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java +++ b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java @@ -44,19 +44,57 @@ public class DefaultCredentialsRefreshService implements CredentialsRefreshServi private static final Logger LOGGER = LoggerFactory.getLogger(DefaultCredentialsRefreshService.class); + /** + * Scheduler used to schedule credentials refresh. + *

+ * Default is a single-threaded scheduler, which should be enough for most scenarios, assuming + * that credentials expire after a few minutes or hours. This default scheduler + * is automatically disposed of when the {@link DefaultCredentialsRefreshService} is closed. + *

+ * If an external scheduler is passed in, it is the developer's responsibility to + * close it. + */ private final ScheduledExecutorService scheduler; private final ConcurrentMap credentialsProviderStates = new ConcurrentHashMap<>(); private final boolean privateScheduler; + /** + * Strategy to schedule credentials refresh after credentials retrieval. + *

+ * Typical strategies schedule refresh after a ratio of the time before expiration + * (e.g. 80 % of the time before expiration) or after a fixed time before + * expiration (e.g. 20 seconds before credentials expire). + * + * @see #ratioRefreshDelayStrategy(double) + * @see #fixedDelayBeforeExpirationRefreshDelayStrategy(Duration) + */ private final Function refreshDelayStrategy; - private final Function needRefreshStrategy; + /** + * Strategy to provide a hint about whether credentials should be renewed now or not before attempting to connect. + *

+ * This can avoid a connection to use almost expired credentials if this connection + * is created just before credentials are refreshed in the background, but does not + * benefit from the refresh. + *

+ * Note setting such a strategy may require knowledge of the credentials validity and must be consistent + * with the {@link #refreshDelayStrategy} chosen. For example, for a validity of 60 minutes and + * a {@link #refreshDelayStrategy} that instructs to refresh 10 minutes before credentials expire, this + * strategy could hint that credentials that expire in 11 minutes or less (1 minute before a refresh is actually + * scheduled) should be refreshed, which would trigger an early refresh. + *

+ * The default strategy always return false. + */ + private final Function approachingExpirationStrategy; - public DefaultCredentialsRefreshService(ScheduledExecutorService scheduler, Function refreshDelayStrategy, Function needRefreshStrategy) { + public DefaultCredentialsRefreshService(ScheduledExecutorService scheduler, Function refreshDelayStrategy, Function approachingExpirationStrategy) { + if (refreshDelayStrategy == null) { + throw new IllegalArgumentException("Refresh delay strategy can not be null"); + } this.refreshDelayStrategy = refreshDelayStrategy; - this.needRefreshStrategy = needRefreshStrategy; + this.approachingExpirationStrategy = approachingExpirationStrategy == null ? duration -> false : approachingExpirationStrategy; if (scheduler == null) { this.scheduler = Executors.newScheduledThreadPool(1); privateScheduler = true; @@ -69,8 +107,8 @@ public DefaultCredentialsRefreshService(ScheduledExecutorService scheduler, Func /** * Delay before refresh is a ratio of the time before expiration. *

- * E.g. if time before expiration is 60 seconds and specified ratio is 0.8, refresh will - * be scheduled in 60 x 0.8 = 48 seconds. + * E.g. if time before expiration is 60 minutes and specified ratio is 0.8, refresh will + * be scheduled in 60 x 0.8 = 48 minutes. * * @param ratio * @return the delay before refreshing @@ -82,8 +120,8 @@ public static Function ratioRefreshDelayStrategy(double rati /** * Delay before refresh is time before expiration - specified duration. *

- * E.g. if time before expiration is 60 seconds and specified duration is 20 seconds, refresh will - * be scheduled in 60 - 20 = 40 seconds. + * E.g. if time before expiration is 60 minutes and specified duration is 10 minutes, refresh will + * be scheduled in 60 - 10 = 50 minutes. * * @param duration * @return the delay before refreshing @@ -98,8 +136,8 @@ public static Function fixedDelayBeforeExpirationRefreshDela * @param limitBeforeExpiration * @return true if credentials should be refreshed, false otherwise */ - public static Function fixedTimeNeedRefreshStrategy(Duration limitBeforeExpiration) { - return new FixedTimeNeedRefreshStrategy(limitBeforeExpiration.toMillis()); + public static Function fixedTimeApproachingExpirationStrategy(Duration limitBeforeExpiration) { + return new FixedTimeApproachingExpirationStrategy(limitBeforeExpiration.toMillis()); } private static Runnable refresh(ScheduledExecutorService scheduler, CredentialsProviderState credentialsProviderState, @@ -157,8 +195,8 @@ public void unregister(CredentialsProvider credentialsProvider, String registrat } @Override - public boolean needRefresh(Duration timeBeforeExpiration) { - return this.needRefreshStrategy.apply(timeBeforeExpiration); + public boolean isApproachingExpiration(Duration timeBeforeExpiration) { + return this.approachingExpirationStrategy.apply(timeBeforeExpiration); } public void close() { @@ -167,11 +205,11 @@ public void close() { } } - private static class FixedTimeNeedRefreshStrategy implements Function { + private static class FixedTimeApproachingExpirationStrategy implements Function { private final long limitBeforeExpiration; - private FixedTimeNeedRefreshStrategy(long limitBeforeExpiration) { + private FixedTimeApproachingExpirationStrategy(long limitBeforeExpiration) { this.limitBeforeExpiration = limitBeforeExpiration; } @@ -340,7 +378,7 @@ public static class DefaultCredentialsRefreshServiceBuilder { private Function refreshDelayStrategy = ratioRefreshDelayStrategy(0.8); - private Function needRefreshStrategy = ttl -> false; + private Function approachingExpirationStrategy = ttl -> false; public DefaultCredentialsRefreshServiceBuilder scheduler(ScheduledThreadPoolExecutor scheduler) { this.scheduler = scheduler; @@ -352,13 +390,13 @@ public DefaultCredentialsRefreshServiceBuilder refreshDelayStrategy(Function needRefreshStrategy) { - this.needRefreshStrategy = needRefreshStrategy; + public DefaultCredentialsRefreshServiceBuilder approachingExpirationStrategy(Function approachingExpirationStrategy) { + this.approachingExpirationStrategy = approachingExpirationStrategy; return this; } public DefaultCredentialsRefreshService build() { - return new DefaultCredentialsRefreshService(scheduler, refreshDelayStrategy, needRefreshStrategy); + return new DefaultCredentialsRefreshService(scheduler, refreshDelayStrategy, approachingExpirationStrategy); } } diff --git a/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java b/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java index 5a1518610d..7009319b9c 100644 --- a/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java +++ b/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java @@ -33,7 +33,7 @@ import java.util.stream.IntStream; import static com.rabbitmq.client.impl.DefaultCredentialsRefreshService.fixedDelayBeforeExpirationRefreshDelayStrategy; -import static com.rabbitmq.client.impl.DefaultCredentialsRefreshService.fixedTimeNeedRefreshStrategy; +import static com.rabbitmq.client.impl.DefaultCredentialsRefreshService.fixedTimeApproachingExpirationStrategy; import static java.time.Duration.ofSeconds; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.*; @@ -232,8 +232,8 @@ public void fixedDelayBeforeExpirationRefreshDelayStrategyTest() { } @Test - public void fixedTimeNeedRefreshStrategyTest() { - Function refreshStrategy = fixedTimeNeedRefreshStrategy(ofSeconds(20)); + public void fixedTimeApproachingExpirationStrategyTest() { + Function refreshStrategy = fixedTimeApproachingExpirationStrategy(ofSeconds(20)); assertThat(refreshStrategy.apply(ofSeconds(60))).isFalse(); assertThat(refreshStrategy.apply(ofSeconds(20))).isTrue(); assertThat(refreshStrategy.apply(ofSeconds(19))).isTrue(); diff --git a/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java b/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java index 963adc7964..defa0c4b4f 100644 --- a/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java +++ b/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java @@ -76,7 +76,7 @@ protected Duration timeBeforeExpiration(TestToken token) { cf.setCredentialsProvider(provider); refreshService = new DefaultCredentialsRefreshService.DefaultCredentialsRefreshServiceBuilder() .refreshDelayStrategy(DefaultCredentialsRefreshService.fixedDelayBeforeExpirationRefreshDelayStrategy(Duration.ofSeconds(1))) - .needRefreshStrategy(expiration -> false) + .approachingExpirationStrategy(expiration -> false) .build(); cf.setCredentialsRefreshService(refreshService); From dc1b104f4461b8756aa1488d6afa941b0e14aa2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 8 Jul 2019 17:25:26 +0200 Subject: [PATCH 1174/2114] Document OAuth 2 credentials provider [#167029587] (cherry picked from commit 09f5320787594d64ee5cf6a79d9f488f90feefa9) Conflicts: src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java --- ...ntCredentialsGrantCredentialsProvider.java | 379 ++++++++++++++++-- ...edentialsGrantCredentialsProviderTest.java | 2 +- 2 files changed, 340 insertions(+), 41 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java index 48f347555a..71635b4baa 100644 --- a/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java @@ -16,23 +16,51 @@ package com.rabbitmq.client.impl; import com.fasterxml.jackson.databind.ObjectMapper; +import com.rabbitmq.client.TrustEverythingTrustManager; -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.*; import java.io.*; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; import java.time.Duration; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.*; +import java.util.function.Consumer; + +import static com.rabbitmq.client.ConnectionFactory.computeDefaultTlsProtocol; /** + * A {@link CredentialsProvider} that performs an + * OAuth 2 Client Credentials flow + * to retrieve a token. + *

+ * The provider has different parameters to set, e.g. the token endpoint URI of the OAuth server to + * request, the client ID, the client secret, the grant type, etc. The {@link OAuth2ClientCredentialsGrantCredentialsProviderBuilder} + * class is the preferred way to create an instance of the provider. + *

+ * The implementation uses the JDK {@link HttpURLConnection} API to request the OAuth server. This can + * be easily changed by overriding the {@link #retrieveToken()} method. + *

+ * This class expects a JSON document as a response and needs Jackson + * to deserialize the response into a {@link Token}. This can be changed by overriding the {@link #parseToken(String)} + * method. + *

+ * TLS is supported by providing a HTTPS URI and setting a {@link SSLContext}. See + * {@link OAuth2ClientCredentialsGrantCredentialsProviderBuilder#tls()} for more information. + * Applications in production should always use HTTPS to retrieve tokens. + *

+ * If more customization is needed, a {@link #connectionConfigurator} callback can be provided to configure + * the connection. * * @see RefreshProtectedCredentialsProvider + * @see CredentialsRefreshService + * @see OAuth2ClientCredentialsGrantCredentialsProviderBuilder + * @see OAuth2ClientCredentialsGrantCredentialsProviderBuilder#tls() */ public class OAuth2ClientCredentialsGrantCredentialsProvider extends RefreshProtectedCredentialsProvider { @@ -51,21 +79,94 @@ public class OAuth2ClientCredentialsGrantCredentialsProvider extends RefreshProt private final HostnameVerifier hostnameVerifier; private final SSLSocketFactory sslSocketFactory; + private final Consumer connectionConfigurator; + + /** + * Use {@link OAuth2ClientCredentialsGrantCredentialsProviderBuilder} to create an instance. + * + * @param tokenEndpointUri + * @param clientId + * @param clientSecret + * @param grantType + */ public OAuth2ClientCredentialsGrantCredentialsProvider(String tokenEndpointUri, String clientId, String clientSecret, String grantType) { this(tokenEndpointUri, clientId, clientSecret, grantType, new HashMap<>()); } + /** + * Use {@link OAuth2ClientCredentialsGrantCredentialsProviderBuilder} to create an instance. + * + * @param tokenEndpointUri + * @param clientId + * @param clientSecret + * @param grantType + * @param parameters + */ + public OAuth2ClientCredentialsGrantCredentialsProvider(String tokenEndpointUri, String clientId, String clientSecret, String grantType, Map parameters) { + this(tokenEndpointUri, clientId, clientSecret, grantType, parameters, null, null, null); + } + + /** + * Use {@link OAuth2ClientCredentialsGrantCredentialsProviderBuilder} to create an instance. + * + * @param tokenEndpointUri + * @param clientId + * @param clientSecret + * @param grantType + * @param parameters + * @param connectionConfigurator + */ + public OAuth2ClientCredentialsGrantCredentialsProvider(String tokenEndpointUri, String clientId, String clientSecret, String grantType, Map parameters, + Consumer connectionConfigurator) { + this(tokenEndpointUri, clientId, clientSecret, grantType, parameters, null, null, connectionConfigurator); + } + + /** + * Use {@link OAuth2ClientCredentialsGrantCredentialsProviderBuilder} to create an instance. + * + * @param tokenEndpointUri + * @param clientId + * @param clientSecret + * @param grantType + * @param hostnameVerifier + * @param sslSocketFactory + */ public OAuth2ClientCredentialsGrantCredentialsProvider(String tokenEndpointUri, String clientId, String clientSecret, String grantType, HostnameVerifier hostnameVerifier, SSLSocketFactory sslSocketFactory) { - this(tokenEndpointUri, clientId, clientSecret, grantType, new HashMap<>(), hostnameVerifier, sslSocketFactory); + this(tokenEndpointUri, clientId, clientSecret, grantType, new HashMap<>(), hostnameVerifier, sslSocketFactory, null); } - public OAuth2ClientCredentialsGrantCredentialsProvider(String tokenEndpointUri, String clientId, String clientSecret, String grantType, Map parameters) { - this(tokenEndpointUri, clientId, clientSecret, grantType, parameters, null, null); + /** + * Use {@link OAuth2ClientCredentialsGrantCredentialsProviderBuilder} to create an instance. + * + * @param tokenEndpointUri + * @param clientId + * @param clientSecret + * @param grantType + * @param parameters + * @param hostnameVerifier + * @param sslSocketFactory + */ + public OAuth2ClientCredentialsGrantCredentialsProvider(String tokenEndpointUri, String clientId, String clientSecret, String grantType, Map parameters, + HostnameVerifier hostnameVerifier, SSLSocketFactory sslSocketFactory) { + this(tokenEndpointUri, clientId, clientSecret, grantType, parameters, hostnameVerifier, sslSocketFactory, null); } + /** + * Use {@link OAuth2ClientCredentialsGrantCredentialsProviderBuilder} to create an instance. + * + * @param tokenEndpointUri + * @param clientId + * @param clientSecret + * @param grantType + * @param parameters + * @param hostnameVerifier + * @param sslSocketFactory + * @param connectionConfigurator + */ public OAuth2ClientCredentialsGrantCredentialsProvider(String tokenEndpointUri, String clientId, String clientSecret, String grantType, Map parameters, - HostnameVerifier hostnameVerifier, SSLSocketFactory sslSocketFactory) { + HostnameVerifier hostnameVerifier, SSLSocketFactory sslSocketFactory, + Consumer connectionConfigurator) { this.tokenEndpointUri = tokenEndpointUri; this.clientId = clientId; this.clientSecret = clientSecret; @@ -73,6 +174,8 @@ public OAuth2ClientCredentialsGrantCredentialsProvider(String tokenEndpointUri, this.parameters = Collections.unmodifiableMap(new HashMap<>(parameters)); this.hostnameVerifier = hostnameVerifier; this.sslSocketFactory = sslSocketFactory; + this.connectionConfigurator = connectionConfigurator == null ? c -> { + } : connectionConfigurator; this.id = UUID.randomUUID().toString(); } @@ -81,13 +184,17 @@ private static StringBuilder encode(StringBuilder builder, String name, String v if (builder.length() > 0) { builder.append("&"); } - builder.append(URLEncoder.encode(name, UTF_8_CHARSET)) + builder.append(encode(name, UTF_8_CHARSET)) .append("=") - .append(URLEncoder.encode(value, UTF_8_CHARSET)); + .append(encode(value, UTF_8_CHARSET)); } return builder; } + private static String encode(String value, String charset) throws UnsupportedEncodingException { + return URLEncoder.encode(value, charset); + } + private static String basicAuthentication(String username, String password) { String credentials = username + ":" + password; byte[] credentialsAsBytes = credentials.getBytes(StandardCharsets.ISO_8859_1); @@ -129,8 +236,6 @@ protected Token retrieveToken() { int postDataLength = postData.length; URL url = new URL(tokenEndpointUri); - // FIXME close connection? - // FIXME set timeout on request HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setDoOutput(true); @@ -142,37 +247,52 @@ protected Token retrieveToken() { conn.setRequestProperty("accept", "application/json"); conn.setRequestProperty("content-length", Integer.toString(postDataLength)); conn.setUseCaches(false); + conn.setConnectTimeout(60_000); + conn.setReadTimeout(60_000); - configureHttpConnection(conn); + configureConnection(conn); try (DataOutputStream wr = new DataOutputStream(conn.getOutputStream())) { wr.write(postData); } - int responseCode = conn.getResponseCode(); - if (responseCode != 200) { - throw new OAuthTokenManagementException( - "HTTP request for token retrieval did not " + - "return 200 response code: " + responseCode - ); - } - - StringBuffer content = new StringBuffer(); - try (BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()))) { - String inputLine; - while ((inputLine = in.readLine()) != null) { - content.append(inputLine); - } - } - - // FIXME check result is json + checkResponseCode(conn.getResponseCode()); + checkContentType(conn.getHeaderField("content-type")); - return parseToken(content.toString()); + return parseToken(extractResponseBody(conn.getInputStream())); } catch (IOException e) { throw new OAuthTokenManagementException("Error while retrieving OAuth 2 token", e); } } + protected void checkContentType(String headerField) throws OAuthTokenManagementException { + if (headerField == null || !headerField.toLowerCase().contains("json")) { + throw new OAuthTokenManagementException( + "HTTP request for token retrieval is not JSON: " + headerField + ); + } + } + + protected void checkResponseCode(int responseCode) throws OAuthTokenManagementException { + if (responseCode != 200) { + throw new OAuthTokenManagementException( + "HTTP request for token retrieval did not " + + "return 200 response code: " + responseCode + ); + } + } + + protected String extractResponseBody(InputStream inputStream) throws IOException { + StringBuffer content = new StringBuffer(); + try (BufferedReader in = new BufferedReader(new InputStreamReader(inputStream))) { + String inputLine; + while ((inputLine = in.readLine()) != null) { + content.append(inputLine); + } + } + return content.toString(); + } + @Override protected String passwordFromToken(Token token) { return token.getAccess(); @@ -183,7 +303,12 @@ protected Duration timeBeforeExpiration(Token token) { return token.getTimeBeforeExpiration(); } - protected void configureHttpConnection(HttpURLConnection connection) { + protected void configureConnection(HttpURLConnection connection) { + this.connectionConfigurator.accept(connection); + this.configureConnectionForHttps(connection); + } + + protected void configureConnectionForHttps(HttpURLConnection connection) { if (connection instanceof HttpsURLConnection) { HttpsURLConnection securedConnection = (HttpsURLConnection) connection; if (this.hostnameVerifier != null) { @@ -243,6 +368,9 @@ public Duration getTimeBeforeExpiration() { } } + /** + * Helper to create {@link OAuth2ClientCredentialsGrantCredentialsProvider} instances. + */ public static class OAuth2ClientCredentialsGrantCredentialsProviderBuilder { private final Map parameters = new HashMap<>(); @@ -250,51 +378,222 @@ public static class OAuth2ClientCredentialsGrantCredentialsProviderBuilder { private String clientId; private String clientSecret; private String grantType = "client_credentials"; - private HostnameVerifier hostnameVerifier; - private SSLSocketFactory sslSocketFactory; + private Consumer connectionConfigurator; + private TlsConfiguration tlsConfiguration = new TlsConfiguration(this); + + /** + * Set the URI to request to get the token. + * + * @param tokenEndpointUri + * @return this builder instance + */ public OAuth2ClientCredentialsGrantCredentialsProviderBuilder tokenEndpointUri(String tokenEndpointUri) { this.tokenEndpointUri = tokenEndpointUri; return this; } + /** + * Set the OAuth 2 client ID + *

+ * The client ID usually identifies the application that requests a token. + * + * @param clientId + * @return this builder instance + */ public OAuth2ClientCredentialsGrantCredentialsProviderBuilder clientId(String clientId) { this.clientId = clientId; return this; } + /** + * Set the secret (password) to use to get a token. + * + * @param clientSecret + * @return this builder instance + */ public OAuth2ClientCredentialsGrantCredentialsProviderBuilder clientSecret(String clientSecret) { this.clientSecret = clientSecret; return this; } + /** + * Set the grant type to use when requesting the token. + *

+ * The default is client_credentials, but some OAuth 2 servers can use + * non-standard grant types to request tokens with extra-information. + * + * @param grantType + * @return this builder instance + */ public OAuth2ClientCredentialsGrantCredentialsProviderBuilder grantType(String grantType) { this.grantType = grantType; return this; } + /** + * Extra parameters to pass in the request. + *

+ * These parameters can be used by the OAuth 2 server to narrow down the identify of the user. + * + * @param name + * @param value + * @return this builder instance + */ public OAuth2ClientCredentialsGrantCredentialsProviderBuilder parameter(String name, String value) { this.parameters.put(name, value); return this; } - public OAuth2ClientCredentialsGrantCredentialsProviderBuilder setHostnameVerifier(HostnameVerifier hostnameVerifier) { - this.hostnameVerifier = hostnameVerifier; + /** + * A hook to configure the {@link HttpURLConnection} before the request is sent. + *

+ * Can be used to configuration settings like timeouts. + * + * @param connectionConfigurator + * @return this builder instance + */ + public OAuth2ClientCredentialsGrantCredentialsProviderBuilder connectionConfigurator(Consumer connectionConfigurator) { + this.connectionConfigurator = connectionConfigurator; return this; } - public OAuth2ClientCredentialsGrantCredentialsProviderBuilder setSslSocketFactory(SSLSocketFactory sslSocketFactory) { - this.sslSocketFactory = sslSocketFactory; - return this; + /** + * Get access to the TLS configuration to get the token on HTTPS. + *

+ * It is recommended that applications in production use HTTPS and configure it properly + * to perform token retrieval. Not doing so could result in sensitive data + * transiting in clear on the network. + *

+ * You can "exit" the TLS configuration and come back to the builder by + * calling {@link TlsConfiguration#builder()}. + * + * @return the TLS configuration for this builder. + * @see TlsConfiguration + * @see TlsConfiguration#builder() + */ + public TlsConfiguration tls() { + return this.tlsConfiguration; } + /** + * Create the {@link OAuth2ClientCredentialsGrantCredentialsProvider} instance. + * + * @return + */ public OAuth2ClientCredentialsGrantCredentialsProvider build() { return new OAuth2ClientCredentialsGrantCredentialsProvider( tokenEndpointUri, clientId, clientSecret, grantType, parameters, - hostnameVerifier, sslSocketFactory + tlsConfiguration.hostnameVerifier, tlsConfiguration.sslSocketFactory(), + connectionConfigurator ); } } -} + + /** + * TLS configuration for a {@link OAuth2ClientCredentialsGrantCredentialsProvider}. + *

+ * Use it from {@link OAuth2ClientCredentialsGrantCredentialsProviderBuilder#tls()}. + */ + public static class TlsConfiguration { + + private final OAuth2ClientCredentialsGrantCredentialsProviderBuilder builder; + + private HostnameVerifier hostnameVerifier; + + private SSLSocketFactory sslSocketFactory; + + private SSLContext sslContext; + + public TlsConfiguration(OAuth2ClientCredentialsGrantCredentialsProviderBuilder builder) { + this.builder = builder; + } + + /** + * Set the hostname verifier. + *

+ * {@link HttpsURLConnection} sets a default hostname verifier, so + * setting a custom one is only needed for specific cases. + * + * @param hostnameVerifier + * @return this TLS configuration instance + * @see HostnameVerifier + */ + public TlsConfiguration hostnameVerifier(HostnameVerifier hostnameVerifier) { + this.hostnameVerifier = hostnameVerifier; + return this; + } + + /** + * Set the {@link SSLSocketFactory} to use in the {@link HttpsURLConnection}. + *

+ * The {@link SSLSocketFactory} supersedes the {@link SSLContext} value if both are set up. + * + * @param sslSocketFactory + * @return this TLS configuration instance + */ + public TlsConfiguration sslSocketFactory(SSLSocketFactory sslSocketFactory) { + this.sslSocketFactory = sslSocketFactory; + return this; + } + + /** + * Set the {@link SSLContext} to use to create the {@link SSLSocketFactory} for the {@link HttpsURLConnection}. + *

+ * This is the preferred way to configure TLS version to use, trusted servers, etc. + *

+ * Note the {@link SSLContext} is not used if the {@link SSLSocketFactory} is set. + * + * @param sslContext + * @return this TLS configuration instances + */ + public TlsConfiguration sslContext(SSLContext sslContext) { + this.sslContext = sslContext; + return this; + } + + /** + * Set up a non-secured environment, useful for development and testing. + *

+ * With this configuration, all servers are trusted. + * + * DO NOT USE this in production. + * + * @return a TLS configuration that trusts all servers + */ + public TlsConfiguration dev() { + try { + SSLContext sslContext = SSLContext.getInstance(computeDefaultTlsProtocol( + SSLContext.getDefault().getSupportedSSLParameters().getProtocols() + )); + sslContext.init(null, new TrustManager[]{new TrustEverythingTrustManager()}, null); + this.sslContext = sslContext; + } catch (NoSuchAlgorithmException | KeyManagementException e) { + throw new OAuthTokenManagementException("Error while creating TLS context for development configuration", e); + } + return this; + } + + /** + * Go back to the builder to configure non-TLS settings. + * + * @return the wrapping builder + */ + public OAuth2ClientCredentialsGrantCredentialsProviderBuilder builder() { + return builder; + } + + private SSLSocketFactory sslSocketFactory() { + if (this.sslSocketFactory != null) { + return this.sslSocketFactory; + } else if (this.sslContext != null) { + return this.sslContext.getSocketFactory(); + } + return null; + } + + } + +} \ No newline at end of file diff --git a/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java b/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java index 2cd19ee828..e1d1c5abbf 100644 --- a/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java +++ b/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java @@ -169,7 +169,7 @@ public void handle(String target, Request baseRequest, HttpServletRequest reques OAuth2ClientCredentialsGrantCredentialsProvider provider = new OAuth2ClientCredentialsGrantCredentialsProvider.OAuth2ClientCredentialsGrantCredentialsProviderBuilder() .tokenEndpointUri("https://localhost:" + port + "/uaa/oauth/token/") .clientId("rabbit_client").clientSecret("rabbit_secret") - .setSslSocketFactory(sslContext.getSocketFactory()) + .tls().sslContext(sslContext).builder() .build(); String password = provider.getPassword(); From 10ba790eb6da4ebbee26d1b73838bc6afd30bd3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 8 Jul 2019 17:47:03 +0200 Subject: [PATCH 1175/2114] Document DefaultCredentialsRefreshService [#167029587] (cherry picked from commit a9e8e733572ed9acea116bd76cba0926e368b70e) --- .../DefaultCredentialsRefreshService.java | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java index 39d6db1fda..d74d749a0d 100644 --- a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java +++ b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java @@ -39,6 +39,8 @@ * by each entity/connection is performed. This callback typically propagates * the new credentials in the entity state, e.g. sending the new password to the * broker for AMQP connections. + *

+ * Instances are preferably created with {@link DefaultCredentialsRefreshServiceBuilder}. */ public class DefaultCredentialsRefreshService implements CredentialsRefreshService { @@ -89,6 +91,13 @@ public class DefaultCredentialsRefreshService implements CredentialsRefreshServi */ private final Function approachingExpirationStrategy; + /** + * Constructor. Consider using {@link DefaultCredentialsRefreshServiceBuilder} to create instances. + * + * @param scheduler + * @param refreshDelayStrategy + * @param approachingExpirationStrategy + */ public DefaultCredentialsRefreshService(ScheduledExecutorService scheduler, Function refreshDelayStrategy, Function approachingExpirationStrategy) { if (refreshDelayStrategy == null) { throw new IllegalArgumentException("Refresh delay strategy can not be null"); @@ -371,6 +380,9 @@ void unregister(String registrationId) { } } + /** + * Builder to create instances of {@link DefaultCredentialsRefreshServiceBuilder}. + */ public static class DefaultCredentialsRefreshServiceBuilder { @@ -385,16 +397,43 @@ public DefaultCredentialsRefreshServiceBuilder scheduler(ScheduledThreadPoolExec return this; } + /** + * Set the strategy to schedule credentials refresh after credentials retrieval. + *

+ * Default is a 80 % ratio-based strategy (refresh is scheduled after 80 % of the time + * before expiration, e.g. 48 minutes for a token with a validity of 60 minutes, that + * is refresh will be scheduled 12 minutes before the token actually expires). + * + * @param refreshDelayStrategy + * @return this builder instance + * @see DefaultCredentialsRefreshService#refreshDelayStrategy + * @see DefaultCredentialsRefreshService#ratioRefreshDelayStrategy(double) + */ public DefaultCredentialsRefreshServiceBuilder refreshDelayStrategy(Function refreshDelayStrategy) { this.refreshDelayStrategy = refreshDelayStrategy; return this; } + /** + * Set the strategy to trigger an early refresh before attempting to connect. + *

+ * Default is to never advise to refresh before connecting. + * + * @param approachingExpirationStrategy + * @return this builder instances + * @see DefaultCredentialsRefreshService#approachingExpirationStrategy + * @see CredentialsRefreshService#isApproachingExpiration(Duration) + */ public DefaultCredentialsRefreshServiceBuilder approachingExpirationStrategy(Function approachingExpirationStrategy) { this.approachingExpirationStrategy = approachingExpirationStrategy; return this; } + /** + * Create the {@link DefaultCredentialsRefreshService} instance. + * + * @return + */ public DefaultCredentialsRefreshService build() { return new DefaultCredentialsRefreshService(scheduler, refreshDelayStrategy, approachingExpirationStrategy); } From e334a3ef2ebe05f1c51bad0283782a9a0cb7c546 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 12 Sep 2019 09:50:13 +0200 Subject: [PATCH 1176/2114] Bump dependencies References #625 (cherry picked from commit c737a939466647c43f5b544e8696cf0f19b2ae37) --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 837802079d..76005fa142 100644 --- a/pom.xml +++ b/pom.xml @@ -54,9 +54,9 @@ UTF-8 UTF-8 - 1.7.26 + 1.7.28 4.1.0 - 1.2.0 + 1.2.1 2.9.9.3 1.2.3 4.12 From 592bb7ec716a1ac9fcde4717b6c61edec4888b99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 12 Sep 2019 10:09:32 +0200 Subject: [PATCH 1177/2114] Bump test and build dependencies (cherry picked from commit d0e1a0863f8916c41755ba06a1d55043254fb908) --- pom.xml | 16 ++++----- .../com/rabbitmq/client/test/JavaNioTest.java | 35 +++++++++++-------- .../com/rabbitmq/client/test/RpcTest.java | 7 ++-- .../client/test/functional/Metrics.java | 6 ++-- 4 files changed, 34 insertions(+), 30 deletions(-) diff --git a/pom.xml b/pom.xml index 76005fa142..5d97a72dab 100644 --- a/pom.xml +++ b/pom.xml @@ -60,13 +60,13 @@ 2.9.9.3 1.2.3 4.12 - 3.1.6 + 4.0.1 3.0.0 - 3.12.2 - 9.4.19.v20190610 - 1.61 + 3.13.2 + 9.4.20.v20190813 + 1.63 - 3.0.1 + 3.1.1 2.5.3 2.3 3.0.2 @@ -75,9 +75,9 @@ 2.4.8 1.5 1.12 - 3.6.1 - 2.22.1 - 2.22.1 + 3.8.1 + 2.22.2 + 2.22.2 1.6 3.0.2 3.2.0 diff --git a/src/test/java/com/rabbitmq/client/test/JavaNioTest.java b/src/test/java/com/rabbitmq/client/test/JavaNioTest.java index 2b80277590..0d143e86e8 100644 --- a/src/test/java/com/rabbitmq/client/test/JavaNioTest.java +++ b/src/test/java/com/rabbitmq/client/test/JavaNioTest.java @@ -4,6 +4,7 @@ import com.rabbitmq.client.impl.nio.BlockingQueueNioQueue; import com.rabbitmq.client.impl.nio.DefaultByteBufferFactory; import com.rabbitmq.client.impl.nio.NioParams; +import org.assertj.core.api.Condition; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -14,10 +15,8 @@ import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicInteger; -import static org.hamcrest.Matchers.hasSize; -import static org.hamcrest.Matchers.isOneOf; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; /** @@ -125,19 +124,21 @@ public void shutdownCompleted(ShutdownSignalException cause) { public void nioLoopCleaning() throws Exception { ConnectionFactory connectionFactory = new ConnectionFactory(); connectionFactory.useNio(); - for(int i = 0; i < 10; i++) { + for (int i = 0; i < 10; i++) { Connection connection = connectionFactory.newConnection(); connection.abort(); } } - @Test public void messageSize() throws Exception { + @Test + public void messageSize() throws Exception { for (int i = 0; i < 50; i++) { sendAndVerifyMessage(testConnection, 76390); } } - @Test public void byteBufferFactory() throws Exception { + @Test + public void byteBufferFactory() throws Exception { ConnectionFactory cf = new ConnectionFactory(); cf.useNio(); int baseCapacity = 32768; @@ -155,12 +156,15 @@ public void nioLoopCleaning() throws Exception { sendAndVerifyMessage(c, 100); } - assertThat(byteBuffers, hasSize(2)); - assertThat(byteBuffers.get(0).capacity(), isOneOf(nioParams.getReadByteBufferSize(), nioParams.getWriteByteBufferSize())); - assertThat(byteBuffers.get(1).capacity(), isOneOf(nioParams.getReadByteBufferSize(), nioParams.getWriteByteBufferSize())); + assertThat(byteBuffers).hasSize(2); + Condition condition = new Condition<>(c -> c == nioParams.getReadByteBufferSize() || + c == nioParams.getWriteByteBufferSize(), "capacity set by factory"); + assertThat(byteBuffers.get(0).capacity()).is(condition); + assertThat(byteBuffers.get(1).capacity()).is(condition); } - @Test public void directByteBuffers() throws Exception { + @Test + public void directByteBuffers() throws Exception { ConnectionFactory cf = new ConnectionFactory(); cf.useNio(); cf.setNioParams(new NioParams().setByteBufferFactory(new DefaultByteBufferFactory(capacity -> ByteBuffer.allocateDirect(capacity)))); @@ -169,15 +173,16 @@ public void nioLoopCleaning() throws Exception { } } - @Test public void customWriteQueue() throws Exception { + @Test + public void customWriteQueue() throws Exception { ConnectionFactory cf = new ConnectionFactory(); cf.useNio(); AtomicInteger count = new AtomicInteger(0); cf.setNioParams(new NioParams().setWriteQueueFactory(ctx -> { count.incrementAndGet(); return new BlockingQueueNioQueue( - new LinkedBlockingQueue<>(ctx.getNioParams().getWriteQueueCapacity()), - ctx.getNioParams().getWriteEnqueuingTimeoutInMs() + new LinkedBlockingQueue<>(ctx.getNioParams().getWriteQueueCapacity()), + ctx.getNioParams().getWriteEnqueuingTimeoutInMs() ); })); try (Connection c = cf.newConnection()) { @@ -193,7 +198,7 @@ private void sendAndVerifyMessage(Connection connection, int size) throws Except } private Connection basicGetBasicConsume(ConnectionFactory connectionFactory, String queue, final CountDownLatch latch) - throws IOException, TimeoutException { + throws IOException, TimeoutException { Connection connection = connectionFactory.newConnection(); Channel channel = connection.createChannel(); channel.queueDeclare(queue, false, false, false, null); @@ -213,7 +218,7 @@ public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProp } private boolean basicGetBasicConsume(Connection connection, String queue, final CountDownLatch latch, int msgSize) - throws Exception { + throws Exception { Channel channel = connection.createChannel(); channel.queueDeclare(queue, false, false, false, null); channel.queuePurge(queue); diff --git a/src/test/java/com/rabbitmq/client/test/RpcTest.java b/src/test/java/com/rabbitmq/client/test/RpcTest.java index 0c05f761e2..66251738d3 100644 --- a/src/test/java/com/rabbitmq/client/test/RpcTest.java +++ b/src/test/java/com/rabbitmq/client/test/RpcTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2017-2019 Pivotal Software, Inc. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 @@ -24,13 +24,12 @@ import com.rabbitmq.client.impl.recovery.RecordedQueue; import com.rabbitmq.client.impl.recovery.TopologyRecoveryFilter; import com.rabbitmq.tools.Host; -import org.awaitility.Awaitility; -import org.awaitility.Duration; import org.junit.After; import org.junit.Before; import org.junit.Test; import java.io.IOException; +import java.time.Duration; import java.util.HashMap; import java.util.Map; import java.util.UUID; @@ -301,7 +300,7 @@ public void handleRecoveryStarted(Recoverable recoverable) { serverThread.interrupt(); - waitAtMost(Duration.ONE_SECOND).until(() -> !serverThread.isAlive()) ; + waitAtMost(Duration.ofSeconds(1)).until(() -> !serverThread.isAlive()) ; client.close(); } diff --git a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java index 783d9e197f..94d76bfe2d 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2019 Pivotal Software, Inc. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 @@ -30,13 +30,13 @@ import com.rabbitmq.client.test.BrokerTestCase; import com.rabbitmq.client.test.TestUtils; import com.rabbitmq.tools.Host; -import org.awaitility.Duration; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import java.io.IOException; import java.lang.reflect.Field; +import java.time.Duration; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -637,7 +637,7 @@ private void sendMessage(Channel channel) throws IOException { } private Duration timeout() { - return new Duration(10, TimeUnit.SECONDS); + return Duration.ofSeconds(10); } private static class MultipleAckConsumer extends DefaultConsumer { From d1779bad5342f8ed5ad78cfc3c316f9337e97897 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Thu, 12 Sep 2019 15:53:35 +0000 Subject: [PATCH 1178/2114] [maven-release-plugin] prepare release v5.8.0.RC1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 5d97a72dab..5283d0d91c 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.8.0-SNAPSHOT + 5.8.0.RC1 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v5.8.0.RC1 From 9f56b9ba5a70763c1cb7cb15bfdb47a08827db88 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Thu, 12 Sep 2019 15:53:40 +0000 Subject: [PATCH 1179/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 5283d0d91c..5d97a72dab 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.8.0.RC1 + 5.8.0-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v5.8.0.RC1 + HEAD From 91b3ccb595eeafcc8ec607a5bcaf32ae1926dd47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 12 Sep 2019 17:57:06 +0200 Subject: [PATCH 1180/2114] Set release version to 5.8.0.RC2 --- release-versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-versions.txt b/release-versions.txt index 34cae24ccc..e3a47a9087 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="5.8.0.RC1" +RELEASE_VERSION="5.8.0.RC2" DEVELOPMENT_VERSION="5.8.0-SNAPSHOT" From e3c662ea695126a0fc0c18b5640c5e3704eb3aff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 16 Sep 2019 11:34:18 +0200 Subject: [PATCH 1181/2114] Do not depend on generated classes for update-secret extension Some CI testing jobs are using the 3.7 branch of codegen, which does not contain the update-secret extension. The Java client then cannot be built because it requires some generated code for the extension. This commit adds the code to handle update-secret and thus makes the generated code not necessary. This is just a workaround for these testing jobs to succeed, it does not change the handling of the update-secret extension in the client. [#167029587] References #626 --- .../rabbitmq/client/impl/AMQConnection.java | 2 +- .../client/impl/UpdateSecretExtension.java | 108 ++++++++++++++++++ .../AMQConnectionRefreshCredentialsTest.java | 4 +- 3 files changed, 111 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/rabbitmq/client/impl/UpdateSecretExtension.java diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index 944a1a0a25..5908ca7dac 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -442,7 +442,7 @@ public void start() } String refreshedPassword = credentialsProvider.getPassword(); - AMQImpl.Connection.UpdateSecret updateSecret = new AMQImpl.Connection.UpdateSecret( + UpdateSecretExtension.UpdateSecret updateSecret = new UpdateSecretExtension.UpdateSecret( LongStringHelper.asLongString(refreshedPassword), "Refresh scheduled by client" ); try { diff --git a/src/main/java/com/rabbitmq/client/impl/UpdateSecretExtension.java b/src/main/java/com/rabbitmq/client/impl/UpdateSecretExtension.java new file mode 100644 index 0000000000..b54b90635c --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/UpdateSecretExtension.java @@ -0,0 +1,108 @@ +// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl; + +import com.rabbitmq.client.LongString; + +import java.io.IOException; +import java.util.Objects; + +/** + * Helper for update-secret extension {@link com.rabbitmq.client.Method}. + *

+ * {@link com.rabbitmq.client.Method} classes are usually automatically + * generated, but providing the class directly is necessary in this case + * for some internal CI testing jobs running against RabbitMQ 3.7. + * + * @since 5.8.0 + */ +abstract class UpdateSecretExtension { + + static class UpdateSecret extends Method { + + private final LongString newSecret; + private final String reason; + + public UpdateSecret(LongString newSecret, String reason) { + if (newSecret == null) + throw new IllegalStateException("Invalid configuration: 'newSecret' must be non-null."); + if (reason == null) + throw new IllegalStateException("Invalid configuration: 'reason' must be non-null."); + this.newSecret = newSecret; + this.reason = reason; + } + + public String getReason() { + return reason; + } + + public int protocolClassId() { + return 10; + } + + public int protocolMethodId() { + return 70; + } + + public String protocolMethodName() { + return "connection.update-secret"; + } + + public boolean hasContent() { + return false; + } + + public Object visit(AMQImpl.MethodVisitor visitor) throws IOException { + return null; + } + + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + UpdateSecret that = (UpdateSecret) o; + if (!Objects.equals(newSecret, that.newSecret)) + return false; + return Objects.equals(reason, that.reason); + } + + @Override + public int hashCode() { + int result = 0; + result = 31 * result + (newSecret != null ? newSecret.hashCode() : 0); + result = 31 * result + (reason != null ? reason.hashCode() : 0); + return result; + } + + public void appendArgumentDebugStringTo(StringBuilder acc) { + acc.append("(new-secret=") + .append(this.newSecret) + .append(", reason=") + .append(this.reason) + .append(")"); + } + + public void writeArgumentsTo(MethodArgumentWriter writer) + throws IOException { + writer.writeLongstr(this.newSecret); + writer.writeShortstr(this.reason); + } + } +} + diff --git a/src/test/java/com/rabbitmq/client/impl/AMQConnectionRefreshCredentialsTest.java b/src/test/java/com/rabbitmq/client/impl/AMQConnectionRefreshCredentialsTest.java index d0978e1e61..6293b39a1c 100644 --- a/src/test/java/com/rabbitmq/client/impl/AMQConnectionRefreshCredentialsTest.java +++ b/src/test/java/com/rabbitmq/client/impl/AMQConnectionRefreshCredentialsTest.java @@ -66,9 +66,9 @@ public boolean processAsync(Command c) throws IOException { @Override public AMQCommand rpc(Method m) throws IOException, ShutdownSignalException { - if (m instanceof AMQImpl.Connection.UpdateSecret) { + if (m instanceof UpdateSecretExtension.UpdateSecret) { super.rpc(m); - return super.rpc(new AMQImpl.Connection.UpdateSecret(LongStringHelper.asLongString(""), "Refresh scheduled by client") { + return super.rpc(new UpdateSecretExtension.UpdateSecret(LongStringHelper.asLongString(""), "Refresh scheduled by client") { @Override public int protocolMethodId() { return 255; From 96718db6498d16e342eb128f8ffc91f45857ba9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 16 Sep 2019 11:34:18 +0200 Subject: [PATCH 1182/2114] Do not depend on generated classes for update-secret extension Some CI testing jobs are using the 3.7 branch of codegen, which does not contain the update-secret extension. The Java client then cannot be built because it requires some generated code for the extension. This commit adds the code to handle update-secret and thus makes the generated code not necessary. This is just a workaround for these testing jobs to succeed, it does not change the handling of the update-secret extension in the client. [#167029587] References #626 (cherry picked from commit e3c662ea695126a0fc0c18b5640c5e3704eb3aff) --- .../rabbitmq/client/impl/AMQConnection.java | 2 +- .../client/impl/UpdateSecretExtension.java | 108 ++++++++++++++++++ .../AMQConnectionRefreshCredentialsTest.java | 4 +- 3 files changed, 111 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/rabbitmq/client/impl/UpdateSecretExtension.java diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index 5717611bb7..0d45cf0bb2 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -445,7 +445,7 @@ public void start() } String refreshedPassword = credentialsProvider.getPassword(); - AMQImpl.Connection.UpdateSecret updateSecret = new AMQImpl.Connection.UpdateSecret( + UpdateSecretExtension.UpdateSecret updateSecret = new UpdateSecretExtension.UpdateSecret( LongStringHelper.asLongString(refreshedPassword), "Refresh scheduled by client" ); try { diff --git a/src/main/java/com/rabbitmq/client/impl/UpdateSecretExtension.java b/src/main/java/com/rabbitmq/client/impl/UpdateSecretExtension.java new file mode 100644 index 0000000000..b54b90635c --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/UpdateSecretExtension.java @@ -0,0 +1,108 @@ +// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl; + +import com.rabbitmq.client.LongString; + +import java.io.IOException; +import java.util.Objects; + +/** + * Helper for update-secret extension {@link com.rabbitmq.client.Method}. + *

+ * {@link com.rabbitmq.client.Method} classes are usually automatically + * generated, but providing the class directly is necessary in this case + * for some internal CI testing jobs running against RabbitMQ 3.7. + * + * @since 5.8.0 + */ +abstract class UpdateSecretExtension { + + static class UpdateSecret extends Method { + + private final LongString newSecret; + private final String reason; + + public UpdateSecret(LongString newSecret, String reason) { + if (newSecret == null) + throw new IllegalStateException("Invalid configuration: 'newSecret' must be non-null."); + if (reason == null) + throw new IllegalStateException("Invalid configuration: 'reason' must be non-null."); + this.newSecret = newSecret; + this.reason = reason; + } + + public String getReason() { + return reason; + } + + public int protocolClassId() { + return 10; + } + + public int protocolMethodId() { + return 70; + } + + public String protocolMethodName() { + return "connection.update-secret"; + } + + public boolean hasContent() { + return false; + } + + public Object visit(AMQImpl.MethodVisitor visitor) throws IOException { + return null; + } + + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + UpdateSecret that = (UpdateSecret) o; + if (!Objects.equals(newSecret, that.newSecret)) + return false; + return Objects.equals(reason, that.reason); + } + + @Override + public int hashCode() { + int result = 0; + result = 31 * result + (newSecret != null ? newSecret.hashCode() : 0); + result = 31 * result + (reason != null ? reason.hashCode() : 0); + return result; + } + + public void appendArgumentDebugStringTo(StringBuilder acc) { + acc.append("(new-secret=") + .append(this.newSecret) + .append(", reason=") + .append(this.reason) + .append(")"); + } + + public void writeArgumentsTo(MethodArgumentWriter writer) + throws IOException { + writer.writeLongstr(this.newSecret); + writer.writeShortstr(this.reason); + } + } +} + diff --git a/src/test/java/com/rabbitmq/client/impl/AMQConnectionRefreshCredentialsTest.java b/src/test/java/com/rabbitmq/client/impl/AMQConnectionRefreshCredentialsTest.java index d0978e1e61..6293b39a1c 100644 --- a/src/test/java/com/rabbitmq/client/impl/AMQConnectionRefreshCredentialsTest.java +++ b/src/test/java/com/rabbitmq/client/impl/AMQConnectionRefreshCredentialsTest.java @@ -66,9 +66,9 @@ public boolean processAsync(Command c) throws IOException { @Override public AMQCommand rpc(Method m) throws IOException, ShutdownSignalException { - if (m instanceof AMQImpl.Connection.UpdateSecret) { + if (m instanceof UpdateSecretExtension.UpdateSecret) { super.rpc(m); - return super.rpc(new AMQImpl.Connection.UpdateSecret(LongStringHelper.asLongString(""), "Refresh scheduled by client") { + return super.rpc(new UpdateSecretExtension.UpdateSecret(LongStringHelper.asLongString(""), "Refresh scheduled by client") { @Override public int protocolMethodId() { return 255; From 1cda0a8031047f530a931b24d9387ebebabeca4c Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Tue, 17 Sep 2019 09:49:13 +0000 Subject: [PATCH 1183/2114] [maven-release-plugin] prepare release v5.8.0.RC2 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 5d97a72dab..0d4e065d51 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.8.0-SNAPSHOT + 5.8.0.RC2 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v5.8.0.RC2 From e4b0c2752d0b86aecdaea4053170e2cc0ebbefcc Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Tue, 17 Sep 2019 09:49:19 +0000 Subject: [PATCH 1184/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 0d4e065d51..5d97a72dab 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.8.0.RC2 + 5.8.0-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v5.8.0.RC2 + HEAD From b4f12c0fe04d12c3d61f1c9f1d70384a32ee54e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 17 Sep 2019 11:58:58 +0200 Subject: [PATCH 1185/2114] Set release version to 5.8.0.RC3 --- release-versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-versions.txt b/release-versions.txt index e3a47a9087..7449317a41 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,2 @@ -RELEASE_VERSION="5.8.0.RC2" +RELEASE_VERSION="5.8.0.RC3" DEVELOPMENT_VERSION="5.8.0-SNAPSHOT" From 3210e096d4ac02ecc6fc537accab00e1e4bfb3b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 18 Sep 2019 15:13:22 +0200 Subject: [PATCH 1186/2114] Delete test queue It would sit in the broker after the test suite because it is not exclusive and was not deleted. --- .../java/com/rabbitmq/client/test/functional/Confirm.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/test/java/com/rabbitmq/client/test/functional/Confirm.java b/src/test/java/com/rabbitmq/client/test/functional/Confirm.java index 20adb70886..3e66e18f15 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Confirm.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Confirm.java @@ -66,6 +66,12 @@ public void setUp() throws IOException, TimeoutException { "confirm-multiple-queues"); } + @Override + protected void releaseResources() throws IOException { + super.releaseResources(); + channel.queueDelete("confirm-durable-nonexclusive"); + } + @Test public void persistentMandatoryCombinations() throws IOException, InterruptedException, TimeoutException { boolean b[] = { false, true }; From 58b04fc76514cd0a8427229ecc4c5519317ddb55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 18 Sep 2019 15:13:22 +0200 Subject: [PATCH 1187/2114] Delete test queue It would sit in the broker after the test suite because it is not exclusive and was not deleted. (cherry picked from commit 3210e096d4ac02ecc6fc537accab00e1e4bfb3b1) --- .../java/com/rabbitmq/client/test/functional/Confirm.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/test/java/com/rabbitmq/client/test/functional/Confirm.java b/src/test/java/com/rabbitmq/client/test/functional/Confirm.java index 20adb70886..3e66e18f15 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Confirm.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Confirm.java @@ -66,6 +66,12 @@ public void setUp() throws IOException, TimeoutException { "confirm-multiple-queues"); } + @Override + protected void releaseResources() throws IOException { + super.releaseResources(); + channel.queueDelete("confirm-durable-nonexclusive"); + } + @Test public void persistentMandatoryCombinations() throws IOException, InterruptedException, TimeoutException { boolean b[] = { false, true }; From 0eda16cc3e81e5325eec70333cd85b2eadd493ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 24 Sep 2019 10:14:10 +0200 Subject: [PATCH 1188/2114] Bump Jackson to 2.9.10 To address CVE-2019-14540 and CVE-2019-16335. Note Jackson is an optional dependency, required only when using the JSON-RPC support. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a0ad962936..12c90a9003 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,7 @@ 1.7.28 4.1.0 1.2.1 - 2.9.9.3 + 2.9.10 1.2.3 4.12 4.0.1 From e60bd3a89f8d899078c0601b91b8087e81eb8efb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 24 Sep 2019 10:14:10 +0200 Subject: [PATCH 1189/2114] Bump Jackson to 2.9.10 To address CVE-2019-14540 and CVE-2019-16335. Note Jackson is an optional dependency, required only when using the JSON-RPC support. (cherry picked from commit 0eda16cc3e81e5325eec70333cd85b2eadd493ad) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5d97a72dab..2639a9fdec 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,7 @@ 1.7.28 4.1.0 1.2.1 - 2.9.9.3 + 2.9.10 1.2.3 4.12 4.0.1 From 97d6b26b82be0215e630551f253f652473845a78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 7 Oct 2019 17:45:45 +0200 Subject: [PATCH 1190/2114] Add release branch entry to release version file --- release-versions.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/release-versions.txt b/release-versions.txt index 222a336b2d..9f435a6f93 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,3 @@ RELEASE_VERSION="6.0.0.M2" DEVELOPMENT_VERSION="6.0.0-SNAPSHOT" +RELEASE_BRANCH="master" From 47e7aa4c355f3ca44d0af8118ae26576d05b7393 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 7 Oct 2019 17:46:36 +0200 Subject: [PATCH 1191/2114] Add release branch entry to release version file --- release-versions.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/release-versions.txt b/release-versions.txt index 7449317a41..d5cd6fe9bf 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,2 +1,3 @@ RELEASE_VERSION="5.8.0.RC3" DEVELOPMENT_VERSION="5.8.0-SNAPSHOT" +RELEASE_BRANCH="5.x.x-stable" From 0d175ffead36a68db983f05f54a1fc153d5e5550 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Tue, 5 Nov 2019 10:44:19 +0000 Subject: [PATCH 1192/2114] Bump default Jackson version to 2.9.10.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 12c90a9003..df78ebc658 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,7 @@ 1.7.28 4.1.0 1.2.1 - 2.9.10 + 2.9.10.1 1.2.3 4.12 4.0.1 From 3e9e1b81546e63bb66a45dfa5ffca2d9dbf96b06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 5 Nov 2019 11:43:50 +0000 Subject: [PATCH 1193/2114] Bump Jackson to 2.10.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index df78ebc658..8c0dbc79f1 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,7 @@ 1.7.28 4.1.0 1.2.1 - 2.9.10.1 + 2.10.0 1.2.3 4.12 4.0.1 From 0cdf59a4cfc7b84510a455bdace5533a83c30437 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 5 Nov 2019 11:43:50 +0000 Subject: [PATCH 1194/2114] Bump Jackson to 2.10.0 (cherry picked from commit 3e9e1b81546e63bb66a45dfa5ffca2d9dbf96b06) Conflicts: pom.xml --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2639a9fdec..012c55a062 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,7 @@ 1.7.28 4.1.0 1.2.1 - 2.9.10 + 2.10.0 1.2.3 4.12 4.0.1 From d2bcc9f321c0d6d7feceb88eb876ea482cf79023 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 15 Nov 2019 14:51:14 +0300 Subject: [PATCH 1195/2114] Clarify what "triple licensed" means References #630. --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9bcd1593d9..c10a4443c7 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,9 @@ See [Contributing](./CONTRIBUTING.md) and [How to Run Tests](./RUNNING_TESTS.md) ## License -This package, the RabbitMQ Java client library, is triple-licensed under +This package, the RabbitMQ Java client library, is [triple-licensed](https://www.rabbitmq.com/api-guide.html#license) under the Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 ("GPL") and the Apache License version 2 ("ASL"). + +This means that the user can consider the library to be licensed under **any of the licenses from the list** above. +For example, the user may choose the Apache Public License 2.0 and include this client into a commercial product. Codebases that are licensed under the GPLv2 may choose GPLv2, and so on. From 40168d8072140cb6cce4a179b834c9b71db6395a Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 15 Nov 2019 14:51:58 +0300 Subject: [PATCH 1196/2114] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c10a4443c7..013e1343ee 100644 --- a/README.md +++ b/README.md @@ -65,4 +65,5 @@ the Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 ("GPL") and the Apache License version 2 ("ASL"). This means that the user can consider the library to be licensed under **any of the licenses from the list** above. -For example, the user may choose the Apache Public License 2.0 and include this client into a commercial product. Codebases that are licensed under the GPLv2 may choose GPLv2, and so on. +For example, you may choose the Apache Public License 2.0 and include this client into a commercial product. +Projects that are licensed under the GPLv2 may choose GPLv2, and so on. From db24ce848a0cd9a6bf435b1219ad08e99d6a91c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 27 Nov 2019 17:28:00 +0100 Subject: [PATCH 1197/2114] Mention semantic versioning in readme --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 013e1343ee..036b0b36c2 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,9 @@ compile 'com.rabbitmq:amqp-client:4.11.3' See [Contributing](./CONTRIBUTING.md) and [How to Run Tests](./RUNNING_TESTS.md). +## Versioning + +This library uses [semantic versioning](https://semver.org/). ## License From 2586694d43e924201098340d8a140e9ede4d2a3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 12 Dec 2019 14:07:59 +0100 Subject: [PATCH 1198/2114] Bump dependencies References #625 --- pom.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 8c0dbc79f1..5fb49d00b2 100644 --- a/pom.xml +++ b/pom.xml @@ -54,10 +54,10 @@ UTF-8 UTF-8 - 1.7.28 - 4.1.0 - 1.2.1 - 2.10.0 + 1.7.29 + 4.1.2 + 1.3.2 + 2.10.1 1.2.3 4.12 4.0.1 From 1f6edae538d377226b49a7390aee426fe24055e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 12 Dec 2019 14:10:46 +0100 Subject: [PATCH 1199/2114] Bump test dependencies --- pom.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 5fb49d00b2..84bea85d05 100644 --- a/pom.xml +++ b/pom.xml @@ -61,10 +61,10 @@ 1.2.3 4.12 4.0.1 - 3.0.0 - 3.13.2 - 9.4.20.v20190813 - 1.63 + 3.2.0 + 3.14.0 + 9.4.24.v20191120 + 1.64 3.1.1 2.5.3 From 1e3efdce7344ec0063cc0ade212bfea5745c0500 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 12 Dec 2019 14:07:59 +0100 Subject: [PATCH 1200/2114] Bump dependencies References #625 (cherry picked from commit 2586694d43e924201098340d8a140e9ede4d2a3f) --- pom.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 012c55a062..112f0e2cca 100644 --- a/pom.xml +++ b/pom.xml @@ -54,10 +54,10 @@ UTF-8 UTF-8 - 1.7.28 - 4.1.0 - 1.2.1 - 2.10.0 + 1.7.29 + 4.1.2 + 1.3.2 + 2.10.1 1.2.3 4.12 4.0.1 From c643faf9cfe7e893cd615984e6805ec254a30f40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 12 Dec 2019 14:10:46 +0100 Subject: [PATCH 1201/2114] Bump test dependencies (cherry picked from commit 1f6edae538d377226b49a7390aee426fe24055e3) --- pom.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 112f0e2cca..b68cfcd1cd 100644 --- a/pom.xml +++ b/pom.xml @@ -61,10 +61,10 @@ 1.2.3 4.12 4.0.1 - 3.0.0 - 3.13.2 - 9.4.20.v20190813 - 1.63 + 3.2.0 + 3.14.0 + 9.4.24.v20191120 + 1.64 3.1.1 2.5.3 From c0f158ce6696d834f24c9277871b7518c88d2af0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 12 Dec 2019 14:43:10 +0100 Subject: [PATCH 1202/2114] Set release version to 5.8.0 --- release-versions.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release-versions.txt b/release-versions.txt index d5cd6fe9bf..302b34ece6 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,3 +1,3 @@ -RELEASE_VERSION="5.8.0.RC3" -DEVELOPMENT_VERSION="5.8.0-SNAPSHOT" +RELEASE_VERSION="5.8.0" +DEVELOPMENT_VERSION="5.8.1-SNAPSHOT" RELEASE_BRANCH="5.x.x-stable" From 3e1921b93a8baa91b7eedc3a986687402cbb7df3 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Thu, 12 Dec 2019 13:45:03 +0000 Subject: [PATCH 1203/2114] [maven-release-plugin] prepare release v5.8.0 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index b68cfcd1cd..5fc18abfd3 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.8.0-SNAPSHOT + 5.8.0 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v5.8.0 From 44f3e62fdd34769a1183be911bf7f05e07f17d8d Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Thu, 12 Dec 2019 13:45:10 +0000 Subject: [PATCH 1204/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 5fc18abfd3..8f6246fa08 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.8.0 + 5.8.1-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v5.8.0 + HEAD From fe2acc31dd1099be5ebc4807204602418e50aa64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 12 Dec 2019 14:55:25 +0100 Subject: [PATCH 1205/2114] Set release version to 5.8.1.RC1 --- release-versions.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release-versions.txt b/release-versions.txt index 302b34ece6..67caefa314 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,3 +1,3 @@ -RELEASE_VERSION="5.8.0" +RELEASE_VERSION="5.8.1.RC1" DEVELOPMENT_VERSION="5.8.1-SNAPSHOT" -RELEASE_BRANCH="5.x.x-stable" +RELEASE_BRANCH="5.8.x-stable" From da3d2f0fc86930a539a0933d59c19e786f9b6bf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 12 Dec 2019 14:56:38 +0100 Subject: [PATCH 1206/2114] Set release version to 5.9.0.RC1 --- release-versions.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/release-versions.txt b/release-versions.txt index 67caefa314..5682da02e8 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,3 +1,3 @@ -RELEASE_VERSION="5.8.1.RC1" -DEVELOPMENT_VERSION="5.8.1-SNAPSHOT" -RELEASE_BRANCH="5.8.x-stable" +RELEASE_VERSION="5.9.0.RC1" +DEVELOPMENT_VERSION="5.9.0-SNAPSHOT" +RELEASE_BRANCH="5.x.x-stable" From 24400f9d06142dd2586bf71964c4036118235e29 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Sat, 28 Dec 2019 19:35:38 +0300 Subject: [PATCH 1207/2114] (c) bump --- src/main/java/com/rabbitmq/client/impl/AMQConnection.java | 4 ++-- .../java/com/rabbitmq/client/impl/CredentialsProvider.java | 2 +- .../com/rabbitmq/client/impl/DefaultCredentialsProvider.java | 2 +- src/main/java/com/rabbitmq/client/impl/ValueReader.java | 2 +- src/main/java/com/rabbitmq/client/impl/ValueWriter.java | 2 +- .../java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java | 2 +- src/test/java/com/rabbitmq/client/test/TestUtils.java | 2 +- .../java/com/rabbitmq/client/test/functional/Metrics.java | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index 5908ca7dac..6a32a37d91 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 Pivotal Software, Inc. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 @@ -35,7 +35,7 @@ import java.util.concurrent.atomic.AtomicBoolean; final class Copyright { - final static String COPYRIGHT="Copyright (c) 2007-2019 Pivotal Software, Inc."; + final static String COPYRIGHT="Copyright (c) 2007-2020 Pivotal Software, Inc."; final static String LICENSE="Licensed under the MPL. See https://www.rabbitmq.com/"; } diff --git a/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java index e4f6bda06a..61bf56713f 100644 --- a/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 Pivotal Software, Inc. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java index 20cbbe3acc..cd58019bf6 100644 --- a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 Pivotal Software, Inc. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ValueReader.java b/src/main/java/com/rabbitmq/client/impl/ValueReader.java index 8a9e860443..32cf9a3732 100644 --- a/src/main/java/com/rabbitmq/client/impl/ValueReader.java +++ b/src/main/java/com/rabbitmq/client/impl/ValueReader.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 Pivotal Software, Inc. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ValueWriter.java b/src/main/java/com/rabbitmq/client/impl/ValueWriter.java index 0c997d1545..7340cbd718 100644 --- a/src/main/java/com/rabbitmq/client/impl/ValueWriter.java +++ b/src/main/java/com/rabbitmq/client/impl/ValueWriter.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 Pivotal Software, Inc. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java index 7a5d77337b..6c1775cf8c 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 Pivotal Software, Inc. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/TestUtils.java b/src/test/java/com/rabbitmq/client/test/TestUtils.java index e2890ab4bc..57d80db95c 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtils.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtils.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 Pivotal Software, Inc. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java index 94d76bfe2d..a39770f125 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 Pivotal Software, Inc. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 From c832a3ff781ae6d58f1e6472e4a572a61941b5ab Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Sat, 28 Dec 2019 19:35:38 +0300 Subject: [PATCH 1208/2114] (c) bump (cherry picked from commit 24400f9d06142dd2586bf71964c4036118235e29) --- src/main/java/com/rabbitmq/client/impl/AMQConnection.java | 4 ++-- .../java/com/rabbitmq/client/impl/CredentialsProvider.java | 2 +- .../com/rabbitmq/client/impl/DefaultCredentialsProvider.java | 2 +- src/main/java/com/rabbitmq/client/impl/ValueReader.java | 2 +- src/main/java/com/rabbitmq/client/impl/ValueWriter.java | 2 +- .../java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java | 2 +- src/test/java/com/rabbitmq/client/test/TestUtils.java | 2 +- .../java/com/rabbitmq/client/test/functional/Metrics.java | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index 0d45cf0bb2..8ed2740588 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 Pivotal Software, Inc. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 @@ -35,7 +35,7 @@ import java.util.concurrent.atomic.AtomicBoolean; final class Copyright { - final static String COPYRIGHT="Copyright (c) 2007-2019 Pivotal Software, Inc."; + final static String COPYRIGHT="Copyright (c) 2007-2020 Pivotal Software, Inc."; final static String LICENSE="Licensed under the MPL. See https://www.rabbitmq.com/"; } diff --git a/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java index e4f6bda06a..61bf56713f 100644 --- a/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 Pivotal Software, Inc. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java index 20cbbe3acc..cd58019bf6 100644 --- a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 Pivotal Software, Inc. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ValueReader.java b/src/main/java/com/rabbitmq/client/impl/ValueReader.java index 8a9e860443..32cf9a3732 100644 --- a/src/main/java/com/rabbitmq/client/impl/ValueReader.java +++ b/src/main/java/com/rabbitmq/client/impl/ValueReader.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 Pivotal Software, Inc. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ValueWriter.java b/src/main/java/com/rabbitmq/client/impl/ValueWriter.java index 0c997d1545..7340cbd718 100644 --- a/src/main/java/com/rabbitmq/client/impl/ValueWriter.java +++ b/src/main/java/com/rabbitmq/client/impl/ValueWriter.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 Pivotal Software, Inc. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java index 7a5d77337b..6c1775cf8c 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 Pivotal Software, Inc. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/TestUtils.java b/src/test/java/com/rabbitmq/client/test/TestUtils.java index e2890ab4bc..57d80db95c 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtils.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtils.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 Pivotal Software, Inc. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java index 94d76bfe2d..a39770f125 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 Pivotal Software, Inc. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 From 68370e69233ee0b108a0b2dd75b238911174ce8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 7 Jan 2020 10:23:35 +0100 Subject: [PATCH 1209/2114] Use 5.8.0 in readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 036b0b36c2..d75fc8db7b 100644 --- a/README.md +++ b/README.md @@ -23,14 +23,14 @@ They require Java 8 or higher. com.rabbitmq amqp-client - 5.7.3 + 5.8.0 ``` ### Gradle ``` groovy -compile 'com.rabbitmq:amqp-client:5.7.3' +compile 'com.rabbitmq:amqp-client:5.8.0' ``` #### 4.x Series From 933df7455e5b1eadbe50ecf064d7e5433743b79b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 7 Jan 2020 10:24:21 +0100 Subject: [PATCH 1210/2114] Add link to Java libraries support page --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index d75fc8db7b..f87890ec30 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,11 @@ See [Contributing](./CONTRIBUTING.md) and [How to Run Tests](./RUNNING_TESTS.md) This library uses [semantic versioning](https://semver.org/). +## Support + +See the [RabbitMQ Java libraries support page](https://www.rabbitmq.com/java-versions.html) +for the support timeline of this library. + ## License This package, the RabbitMQ Java client library, is [triple-licensed](https://www.rabbitmq.com/api-guide.html#license) under From e554e4bfe58c4f75cdf44e8e05357a9e61cb2f28 Mon Sep 17 00:00:00 2001 From: janssk1 Date: Mon, 3 Feb 2020 11:51:51 +0100 Subject: [PATCH 1211/2114] 637: Configurable correlatorId generation for RPCClient Change-Id: I17d7a214d3336ad6e5fe890857a48b457ea599b6 --- .../IncrementingCorrelationIdGenerator.java | 18 +++++++++++++ .../java/com/rabbitmq/client/RpcClient.java | 18 +++++-------- .../com/rabbitmq/client/RpcClientParams.java | 12 +++++++++ .../com/rabbitmq/client/test/RpcTest.java | 25 ++++++++++++++++--- 4 files changed, 57 insertions(+), 16 deletions(-) create mode 100644 src/main/java/com/rabbitmq/client/IncrementingCorrelationIdGenerator.java diff --git a/src/main/java/com/rabbitmq/client/IncrementingCorrelationIdGenerator.java b/src/main/java/com/rabbitmq/client/IncrementingCorrelationIdGenerator.java new file mode 100644 index 0000000000..3b712cfcdf --- /dev/null +++ b/src/main/java/com/rabbitmq/client/IncrementingCorrelationIdGenerator.java @@ -0,0 +1,18 @@ +package com.rabbitmq.client; + +import java.util.function.Supplier; + +public class IncrementingCorrelationIdGenerator implements Supplier { + + private final String _prefix; + private int _correlationId; + + public IncrementingCorrelationIdGenerator(String _prefix) { + this._prefix = _prefix; + } + + @Override + public String get() { + return _prefix + _correlationId++; + } +} diff --git a/src/main/java/com/rabbitmq/client/RpcClient.java b/src/main/java/com/rabbitmq/client/RpcClient.java index 2dfd50c830..c73e240ff5 100644 --- a/src/main/java/com/rabbitmq/client/RpcClient.java +++ b/src/main/java/com/rabbitmq/client/RpcClient.java @@ -28,6 +28,7 @@ import java.util.Map.Entry; import java.util.concurrent.TimeoutException; import java.util.function.Function; +import java.util.function.Supplier; import com.rabbitmq.client.impl.MethodArgumentReader; import com.rabbitmq.client.impl.MethodArgumentWriter; @@ -79,12 +80,14 @@ public class RpcClient { } }; + public static Supplier DEFAULT_CORRELATION_ID_GENERATOR = new IncrementingCorrelationIdGenerator(""); + private final Function _replyHandler; /** Map from request correlation ID to continuation BlockingCell */ private final Map> _continuationMap = new HashMap>(); /** Contains the most recently-used request correlation ID */ - private int _correlationId; + private final Supplier _correlationIdGenerator; /** Consumer attached to our reply queue */ private DefaultConsumer _consumer; @@ -109,7 +112,7 @@ public RpcClient(RpcClientParams params) throws _timeout = params.getTimeout(); _useMandatory = params.shouldUseMandatory(); _replyHandler = params.getReplyHandler(); - _correlationId = 0; + _correlationIdGenerator = params.getCorrelationIdGenerator(); _consumer = setupConsumer(); if (_useMandatory) { @@ -208,8 +211,7 @@ public Response doCall(AMQP.BasicProperties props, byte[] message, int timeout) BlockingCell k = new BlockingCell(); String replyId; synchronized (_continuationMap) { - _correlationId++; - replyId = "" + _correlationId; + replyId = _correlationIdGenerator.get(); props = ((props==null) ? new AMQP.BasicProperties.Builder() : props.builder()) .correlationId(replyId).replyTo(_replyTo).build(); _continuationMap.put(replyId, k); @@ -389,14 +391,6 @@ public Map> getContinuationMap() { return _continuationMap; } - /** - * Retrieve the correlation id. - * @return the most recently used correlation id - */ - public int getCorrelationId() { - return _correlationId; - } - /** * Retrieve the consumer. * @return an interface to the client's consumer object diff --git a/src/main/java/com/rabbitmq/client/RpcClientParams.java b/src/main/java/com/rabbitmq/client/RpcClientParams.java index ce046a6cb6..da3d56b9f8 100644 --- a/src/main/java/com/rabbitmq/client/RpcClientParams.java +++ b/src/main/java/com/rabbitmq/client/RpcClientParams.java @@ -16,6 +16,7 @@ package com.rabbitmq.client; import java.util.function.Function; +import java.util.function.Supplier; /** * Holder class to configure a {@link RpcClient}. @@ -54,6 +55,8 @@ public class RpcClientParams { */ private Function replyHandler = RpcClient.DEFAULT_REPLY_HANDLER; + private Supplier correlationIdGenerator = RpcClient.DEFAULT_CORRELATION_ID_GENERATOR; + /** * Set the channel to use for communication. * @@ -170,6 +173,15 @@ public boolean shouldUseMandatory() { return useMandatory; } + public RpcClientParams correlationIdGenerator(Supplier correlationIdGenerator) { + this.correlationIdGenerator = correlationIdGenerator; + return this; + } + + public Supplier getCorrelationIdGenerator() { + return correlationIdGenerator; + } + public Function getReplyHandler() { return replyHandler; } diff --git a/src/test/java/com/rabbitmq/client/test/RpcTest.java b/src/test/java/com/rabbitmq/client/test/RpcTest.java index 66251738d3..8837f726c7 100644 --- a/src/test/java/com/rabbitmq/client/test/RpcTest.java +++ b/src/test/java/com/rabbitmq/client/test/RpcTest.java @@ -24,6 +24,7 @@ import com.rabbitmq.client.impl.recovery.RecordedQueue; import com.rabbitmq.client.impl.recovery.TopologyRecoveryFilter; import com.rabbitmq.tools.Host; +import org.hamcrest.CoreMatchers; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -39,9 +40,7 @@ import java.util.concurrent.atomic.AtomicInteger; import static org.awaitility.Awaitility.waitAtMost; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static org.junit.Assert.*; public class RpcTest { @@ -138,6 +137,25 @@ public void rpcUnroutableWithMandatoryFlagShouldThrowUnroutableException() throw client.close(); } + @Test + public void rpcCustomCorrelatorId() throws Exception { + rpcServer = new TestRpcServer(serverChannel, queue); + new Thread(() -> { + try { + rpcServer.mainloop(); + } catch (Exception e) { + // safe to ignore when loops ends/server is canceled + } + }).start(); + RpcClient client = new RpcClient(new RpcClientParams() + .channel(clientChannel).exchange("").routingKey(queue).timeout(1000) + .correlationIdGenerator(new IncrementingCorrelationIdGenerator("myPrefix-")) + ); + RpcClient.Response response = client.doCall(null, "hello".getBytes()); + assertThat(response.getProperties().getCorrelationId(), CoreMatchers.equalTo("myPrefix-0")); + client.close(); + } + @Test public void rpcCustomReplyHandler() throws Exception { rpcServer = new TestRpcServer(serverChannel, queue); @@ -156,7 +174,6 @@ public void rpcCustomReplyHandler() throws Exception { return RpcClient.DEFAULT_REPLY_HANDLER.apply(reply); }) ); - assertEquals(0, replyHandlerCalls.get()); RpcClient.Response response = client.doCall(null, "hello".getBytes()); assertEquals(1, replyHandlerCalls.get()); assertEquals("*** hello ***", new String(response.getBody())); From 102cbbde18310edea0d6428adc686f07229d9839 Mon Sep 17 00:00:00 2001 From: janssk1 Date: Mon, 3 Feb 2020 14:09:57 +0100 Subject: [PATCH 1212/2114] 637: Default generator should not be static Change-Id: I3bb119f3f7debeb0d45ff81dc9154e26635f03bb --- src/main/java/com/rabbitmq/client/RpcClient.java | 2 -- src/main/java/com/rabbitmq/client/RpcClientParams.java | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/RpcClient.java b/src/main/java/com/rabbitmq/client/RpcClient.java index c73e240ff5..252e35e2a1 100644 --- a/src/main/java/com/rabbitmq/client/RpcClient.java +++ b/src/main/java/com/rabbitmq/client/RpcClient.java @@ -80,8 +80,6 @@ public class RpcClient { } }; - public static Supplier DEFAULT_CORRELATION_ID_GENERATOR = new IncrementingCorrelationIdGenerator(""); - private final Function _replyHandler; /** Map from request correlation ID to continuation BlockingCell */ diff --git a/src/main/java/com/rabbitmq/client/RpcClientParams.java b/src/main/java/com/rabbitmq/client/RpcClientParams.java index da3d56b9f8..db32896cd5 100644 --- a/src/main/java/com/rabbitmq/client/RpcClientParams.java +++ b/src/main/java/com/rabbitmq/client/RpcClientParams.java @@ -55,7 +55,7 @@ public class RpcClientParams { */ private Function replyHandler = RpcClient.DEFAULT_REPLY_HANDLER; - private Supplier correlationIdGenerator = RpcClient.DEFAULT_CORRELATION_ID_GENERATOR; + private Supplier correlationIdGenerator = new IncrementingCorrelationIdGenerator(""); /** * Set the channel to use for communication. From 59e9455d5eef03dee4e934e5c21219645fdd81fb Mon Sep 17 00:00:00 2001 From: janssk1 Date: Tue, 4 Feb 2020 18:49:45 +0100 Subject: [PATCH 1213/2114] 637: Default generator should not be static Change-Id: Ib1f90d5a25f1c5db32ff9c838cfbeb35aac5d671 --- .../client/IncrementingCorrelationIdGenerator.java | 4 ++++ src/main/java/com/rabbitmq/client/RpcClient.java | 13 +++++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/main/java/com/rabbitmq/client/IncrementingCorrelationIdGenerator.java b/src/main/java/com/rabbitmq/client/IncrementingCorrelationIdGenerator.java index 3b712cfcdf..e9f8012627 100644 --- a/src/main/java/com/rabbitmq/client/IncrementingCorrelationIdGenerator.java +++ b/src/main/java/com/rabbitmq/client/IncrementingCorrelationIdGenerator.java @@ -15,4 +15,8 @@ public IncrementingCorrelationIdGenerator(String _prefix) { public String get() { return _prefix + _correlationId++; } + + public int getCorrelationId() { + return _correlationId; + } } diff --git a/src/main/java/com/rabbitmq/client/RpcClient.java b/src/main/java/com/rabbitmq/client/RpcClient.java index 252e35e2a1..326e5a2f44 100644 --- a/src/main/java/com/rabbitmq/client/RpcClient.java +++ b/src/main/java/com/rabbitmq/client/RpcClient.java @@ -389,6 +389,19 @@ public Map> getContinuationMap() { return _continuationMap; } + /** + * Retrieve the correlation id. + * @return the most recently used correlation id + * @deprecated Only works for {@link IncrementingCorrelationIdGenerator} + */ + public int getCorrelationId() { + if (_correlationIdGenerator instanceof IncrementingCorrelationIdGenerator) { + return ((IncrementingCorrelationIdGenerator) _correlationIdGenerator).getCorrelationId(); + } else { + throw new UnsupportedOperationException(); + } + } + /** * Retrieve the consumer. * @return an interface to the client's consumer object From 96b24b38516cef7eb011d5e4d5d1cb91cb1c0fb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 17 Feb 2020 12:13:31 +0100 Subject: [PATCH 1214/2114] Polish correlation ID supplier support in RPC client References #637 --- .../IncrementingCorrelationIdGenerator.java | 22 ------ .../java/com/rabbitmq/client/RpcClient.java | 75 ++++++++++++++++--- .../com/rabbitmq/client/RpcClientParams.java | 24 ++++-- .../com/rabbitmq/client/test/RpcTest.java | 13 ++-- 4 files changed, 90 insertions(+), 44 deletions(-) delete mode 100644 src/main/java/com/rabbitmq/client/IncrementingCorrelationIdGenerator.java diff --git a/src/main/java/com/rabbitmq/client/IncrementingCorrelationIdGenerator.java b/src/main/java/com/rabbitmq/client/IncrementingCorrelationIdGenerator.java deleted file mode 100644 index e9f8012627..0000000000 --- a/src/main/java/com/rabbitmq/client/IncrementingCorrelationIdGenerator.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.rabbitmq.client; - -import java.util.function.Supplier; - -public class IncrementingCorrelationIdGenerator implements Supplier { - - private final String _prefix; - private int _correlationId; - - public IncrementingCorrelationIdGenerator(String _prefix) { - this._prefix = _prefix; - } - - @Override - public String get() { - return _prefix + _correlationId++; - } - - public int getCorrelationId() { - return _correlationId; - } -} diff --git a/src/main/java/com/rabbitmq/client/RpcClient.java b/src/main/java/com/rabbitmq/client/RpcClient.java index 326e5a2f44..880ed5c518 100644 --- a/src/main/java/com/rabbitmq/client/RpcClient.java +++ b/src/main/java/com/rabbitmq/client/RpcClient.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 Pivotal Software, Inc. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 @@ -84,9 +84,16 @@ public class RpcClient { /** Map from request correlation ID to continuation BlockingCell */ private final Map> _continuationMap = new HashMap>(); - /** Contains the most recently-used request correlation ID */ + + /** + * Generates correlation ID for each request. + * + * @since 5.9.0 + */ private final Supplier _correlationIdGenerator; + private String lastCorrelationId = "0"; + /** Consumer attached to our reply queue */ private DefaultConsumer _consumer; @@ -110,7 +117,7 @@ public RpcClient(RpcClientParams params) throws _timeout = params.getTimeout(); _useMandatory = params.shouldUseMandatory(); _replyHandler = params.getReplyHandler(); - _correlationIdGenerator = params.getCorrelationIdGenerator(); + _correlationIdGenerator = params.getCorrelationIdSupplier(); _consumer = setupConsumer(); if (_useMandatory) { @@ -210,6 +217,7 @@ public Response doCall(AMQP.BasicProperties props, byte[] message, int timeout) String replyId; synchronized (_continuationMap) { replyId = _correlationIdGenerator.get(); + lastCorrelationId = replyId; props = ((props==null) ? new AMQP.BasicProperties.Builder() : props.builder()) .correlationId(replyId).replyTo(_replyTo).build(); _continuationMap.put(replyId, k); @@ -390,16 +398,21 @@ public Map> getContinuationMap() { } /** - * Retrieve the correlation id. + * Retrieve the last correlation id used. + *

+ * Note as of 5.9.0, correlation IDs may not always be integers + * (by default, they are). + * This method will try to parse the last correlation ID string + * as an integer, so this may result in {@link NumberFormatException} + * if the correlation ID supplier provided by + * {@link RpcClientParams#correlationIdSupplier(Supplier)} + * does not generate appropriate IDs. + * * @return the most recently used correlation id - * @deprecated Only works for {@link IncrementingCorrelationIdGenerator} + * @see RpcClientParams#correlationIdSupplier(Supplier) */ public int getCorrelationId() { - if (_correlationIdGenerator instanceof IncrementingCorrelationIdGenerator) { - return ((IncrementingCorrelationIdGenerator) _correlationIdGenerator).getCorrelationId(); - } else { - throw new UnsupportedOperationException(); - } + return Integer.valueOf(this.lastCorrelationId); } /** @@ -447,5 +460,47 @@ public byte[] getBody() { return body; } } + + /** + * Creates generation IDs as a sequence of integers. + * + * @return + * @see RpcClientParams#correlationIdSupplier(Supplier) + * @since 5.9.0 + */ + public static Supplier incrementingCorrelationIdSupplier() { + return incrementingCorrelationIdSupplier(""); + } + + /** + * Creates generation IDs as a sequence of integers, with the provided prefix. + * + * @param prefix + * @return + * @see RpcClientParams#correlationIdSupplier(Supplier) + * @since 5.9.0 + */ + public static Supplier incrementingCorrelationIdSupplier(String prefix) { + return new IncrementingCorrelationIdSupplier(prefix); + } + + /** + * @since 5.9.0 + */ + private static class IncrementingCorrelationIdSupplier implements Supplier { + + private final String prefix; + private int correlationId; + + public IncrementingCorrelationIdSupplier(String prefix) { + this.prefix = prefix; + } + + @Override + public String get() { + return prefix + ++correlationId; + } + + } } diff --git a/src/main/java/com/rabbitmq/client/RpcClientParams.java b/src/main/java/com/rabbitmq/client/RpcClientParams.java index db32896cd5..870756e25a 100644 --- a/src/main/java/com/rabbitmq/client/RpcClientParams.java +++ b/src/main/java/com/rabbitmq/client/RpcClientParams.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 Pivotal Software, Inc. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 @@ -55,7 +55,10 @@ public class RpcClientParams { */ private Function replyHandler = RpcClient.DEFAULT_REPLY_HANDLER; - private Supplier correlationIdGenerator = new IncrementingCorrelationIdGenerator(""); + /** + * Logic to generate correlation IDs. + */ + private Supplier correlationIdSupplier = RpcClient.incrementingCorrelationIdSupplier(); /** * Set the channel to use for communication. @@ -149,7 +152,7 @@ public RpcClientParams timeout(int timeout) { * * @param useMandatory * @return - * @see #replyHandler(RpcClient.RpcClientReplyHandler) + * @see #replyHandler(Function) */ public RpcClientParams useMandatory(boolean useMandatory) { this.useMandatory = useMandatory; @@ -173,13 +176,20 @@ public boolean shouldUseMandatory() { return useMandatory; } - public RpcClientParams correlationIdGenerator(Supplier correlationIdGenerator) { - this.correlationIdGenerator = correlationIdGenerator; + /** + * Logic to generate correlation IDs. + * + * @param correlationIdGenerator + * @return + * @since 5.9.0 + */ + public RpcClientParams correlationIdSupplier(Supplier correlationIdGenerator) { + this.correlationIdSupplier = correlationIdGenerator; return this; } - public Supplier getCorrelationIdGenerator() { - return correlationIdGenerator; + public Supplier getCorrelationIdSupplier() { + return correlationIdSupplier; } public Function getReplyHandler() { diff --git a/src/test/java/com/rabbitmq/client/test/RpcTest.java b/src/test/java/com/rabbitmq/client/test/RpcTest.java index 8837f726c7..027c1e081a 100644 --- a/src/test/java/com/rabbitmq/client/test/RpcTest.java +++ b/src/test/java/com/rabbitmq/client/test/RpcTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2017-2020 Pivotal Software, Inc. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 @@ -24,7 +24,7 @@ import com.rabbitmq.client.impl.recovery.RecordedQueue; import com.rabbitmq.client.impl.recovery.TopologyRecoveryFilter; import com.rabbitmq.tools.Host; -import org.hamcrest.CoreMatchers; +import org.assertj.core.api.Assertions; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -86,6 +86,9 @@ public void rpc() throws Exception { assertEquals("*** hello ***", new String(response.getBody())); assertEquals("pre-hello", response.getProperties().getHeaders().get("pre").toString()); assertEquals("post-hello", response.getProperties().getHeaders().get("post").toString()); + + Assertions.assertThat(client.getCorrelationId()).isEqualTo(Integer.valueOf(response.getProperties().getCorrelationId())); + client.close(); } @@ -138,7 +141,7 @@ public void rpcUnroutableWithMandatoryFlagShouldThrowUnroutableException() throw } @Test - public void rpcCustomCorrelatorId() throws Exception { + public void rpcCustomCorrelationId() throws Exception { rpcServer = new TestRpcServer(serverChannel, queue); new Thread(() -> { try { @@ -149,10 +152,10 @@ public void rpcCustomCorrelatorId() throws Exception { }).start(); RpcClient client = new RpcClient(new RpcClientParams() .channel(clientChannel).exchange("").routingKey(queue).timeout(1000) - .correlationIdGenerator(new IncrementingCorrelationIdGenerator("myPrefix-")) + .correlationIdSupplier(RpcClient.incrementingCorrelationIdSupplier("myPrefix-")) ); RpcClient.Response response = client.doCall(null, "hello".getBytes()); - assertThat(response.getProperties().getCorrelationId(), CoreMatchers.equalTo("myPrefix-0")); + Assertions.assertThat(response.getProperties().getCorrelationId()).isEqualTo("myPrefix-1"); client.close(); } From e1e1d5e5e23289e6a0c56b3a6236dd37fec7ce5b Mon Sep 17 00:00:00 2001 From: janssk1 Date: Mon, 3 Feb 2020 11:51:51 +0100 Subject: [PATCH 1215/2114] 637: Configurable correlatorId generation for RPCClient Change-Id: I17d7a214d3336ad6e5fe890857a48b457ea599b6 (cherry picked from commit e554e4bfe58c4f75cdf44e8e05357a9e61cb2f28) --- .../IncrementingCorrelationIdGenerator.java | 18 +++++++++++++ .../java/com/rabbitmq/client/RpcClient.java | 18 +++++-------- .../com/rabbitmq/client/RpcClientParams.java | 12 +++++++++ .../com/rabbitmq/client/test/RpcTest.java | 25 ++++++++++++++++--- 4 files changed, 57 insertions(+), 16 deletions(-) create mode 100644 src/main/java/com/rabbitmq/client/IncrementingCorrelationIdGenerator.java diff --git a/src/main/java/com/rabbitmq/client/IncrementingCorrelationIdGenerator.java b/src/main/java/com/rabbitmq/client/IncrementingCorrelationIdGenerator.java new file mode 100644 index 0000000000..3b712cfcdf --- /dev/null +++ b/src/main/java/com/rabbitmq/client/IncrementingCorrelationIdGenerator.java @@ -0,0 +1,18 @@ +package com.rabbitmq.client; + +import java.util.function.Supplier; + +public class IncrementingCorrelationIdGenerator implements Supplier { + + private final String _prefix; + private int _correlationId; + + public IncrementingCorrelationIdGenerator(String _prefix) { + this._prefix = _prefix; + } + + @Override + public String get() { + return _prefix + _correlationId++; + } +} diff --git a/src/main/java/com/rabbitmq/client/RpcClient.java b/src/main/java/com/rabbitmq/client/RpcClient.java index 53563b0e8c..4a72ee8602 100644 --- a/src/main/java/com/rabbitmq/client/RpcClient.java +++ b/src/main/java/com/rabbitmq/client/RpcClient.java @@ -28,6 +28,7 @@ import java.util.Map.Entry; import java.util.concurrent.TimeoutException; import java.util.function.Function; +import java.util.function.Supplier; import com.rabbitmq.client.impl.MethodArgumentReader; import com.rabbitmq.client.impl.MethodArgumentWriter; @@ -79,12 +80,14 @@ public class RpcClient { } }; + public static Supplier DEFAULT_CORRELATION_ID_GENERATOR = new IncrementingCorrelationIdGenerator(""); + private final Function _replyHandler; /** Map from request correlation ID to continuation BlockingCell */ private final Map> _continuationMap = new HashMap>(); /** Contains the most recently-used request correlation ID */ - private int _correlationId; + private final Supplier _correlationIdGenerator; /** Consumer attached to our reply queue */ private DefaultConsumer _consumer; @@ -109,7 +112,7 @@ public RpcClient(RpcClientParams params) throws _timeout = params.getTimeout(); _useMandatory = params.shouldUseMandatory(); _replyHandler = params.getReplyHandler(); - _correlationId = 0; + _correlationIdGenerator = params.getCorrelationIdGenerator(); _consumer = setupConsumer(); if (_useMandatory) { @@ -293,8 +296,7 @@ public Response doCall(AMQP.BasicProperties props, byte[] message, int timeout) BlockingCell k = new BlockingCell(); String replyId; synchronized (_continuationMap) { - _correlationId++; - replyId = "" + _correlationId; + replyId = _correlationIdGenerator.get(); props = ((props==null) ? new AMQP.BasicProperties.Builder() : props.builder()) .correlationId(replyId).replyTo(_replyTo).build(); _continuationMap.put(replyId, k); @@ -474,14 +476,6 @@ public Map> getContinuationMap() { return _continuationMap; } - /** - * Retrieve the correlation id. - * @return the most recently used correlation id - */ - public int getCorrelationId() { - return _correlationId; - } - /** * Retrieve the consumer. * @return an interface to the client's consumer object diff --git a/src/main/java/com/rabbitmq/client/RpcClientParams.java b/src/main/java/com/rabbitmq/client/RpcClientParams.java index ce046a6cb6..da3d56b9f8 100644 --- a/src/main/java/com/rabbitmq/client/RpcClientParams.java +++ b/src/main/java/com/rabbitmq/client/RpcClientParams.java @@ -16,6 +16,7 @@ package com.rabbitmq.client; import java.util.function.Function; +import java.util.function.Supplier; /** * Holder class to configure a {@link RpcClient}. @@ -54,6 +55,8 @@ public class RpcClientParams { */ private Function replyHandler = RpcClient.DEFAULT_REPLY_HANDLER; + private Supplier correlationIdGenerator = RpcClient.DEFAULT_CORRELATION_ID_GENERATOR; + /** * Set the channel to use for communication. * @@ -170,6 +173,15 @@ public boolean shouldUseMandatory() { return useMandatory; } + public RpcClientParams correlationIdGenerator(Supplier correlationIdGenerator) { + this.correlationIdGenerator = correlationIdGenerator; + return this; + } + + public Supplier getCorrelationIdGenerator() { + return correlationIdGenerator; + } + public Function getReplyHandler() { return replyHandler; } diff --git a/src/test/java/com/rabbitmq/client/test/RpcTest.java b/src/test/java/com/rabbitmq/client/test/RpcTest.java index 66251738d3..8837f726c7 100644 --- a/src/test/java/com/rabbitmq/client/test/RpcTest.java +++ b/src/test/java/com/rabbitmq/client/test/RpcTest.java @@ -24,6 +24,7 @@ import com.rabbitmq.client.impl.recovery.RecordedQueue; import com.rabbitmq.client.impl.recovery.TopologyRecoveryFilter; import com.rabbitmq.tools.Host; +import org.hamcrest.CoreMatchers; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -39,9 +40,7 @@ import java.util.concurrent.atomic.AtomicInteger; import static org.awaitility.Awaitility.waitAtMost; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static org.junit.Assert.*; public class RpcTest { @@ -138,6 +137,25 @@ public void rpcUnroutableWithMandatoryFlagShouldThrowUnroutableException() throw client.close(); } + @Test + public void rpcCustomCorrelatorId() throws Exception { + rpcServer = new TestRpcServer(serverChannel, queue); + new Thread(() -> { + try { + rpcServer.mainloop(); + } catch (Exception e) { + // safe to ignore when loops ends/server is canceled + } + }).start(); + RpcClient client = new RpcClient(new RpcClientParams() + .channel(clientChannel).exchange("").routingKey(queue).timeout(1000) + .correlationIdGenerator(new IncrementingCorrelationIdGenerator("myPrefix-")) + ); + RpcClient.Response response = client.doCall(null, "hello".getBytes()); + assertThat(response.getProperties().getCorrelationId(), CoreMatchers.equalTo("myPrefix-0")); + client.close(); + } + @Test public void rpcCustomReplyHandler() throws Exception { rpcServer = new TestRpcServer(serverChannel, queue); @@ -156,7 +174,6 @@ public void rpcCustomReplyHandler() throws Exception { return RpcClient.DEFAULT_REPLY_HANDLER.apply(reply); }) ); - assertEquals(0, replyHandlerCalls.get()); RpcClient.Response response = client.doCall(null, "hello".getBytes()); assertEquals(1, replyHandlerCalls.get()); assertEquals("*** hello ***", new String(response.getBody())); From 466dcf6d5792cb79863d47c565c3377a5eebf61b Mon Sep 17 00:00:00 2001 From: janssk1 Date: Mon, 3 Feb 2020 14:09:57 +0100 Subject: [PATCH 1216/2114] 637: Default generator should not be static Change-Id: I3bb119f3f7debeb0d45ff81dc9154e26635f03bb (cherry picked from commit 102cbbde18310edea0d6428adc686f07229d9839) --- src/main/java/com/rabbitmq/client/RpcClient.java | 2 -- src/main/java/com/rabbitmq/client/RpcClientParams.java | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/RpcClient.java b/src/main/java/com/rabbitmq/client/RpcClient.java index 4a72ee8602..03599c516c 100644 --- a/src/main/java/com/rabbitmq/client/RpcClient.java +++ b/src/main/java/com/rabbitmq/client/RpcClient.java @@ -80,8 +80,6 @@ public class RpcClient { } }; - public static Supplier DEFAULT_CORRELATION_ID_GENERATOR = new IncrementingCorrelationIdGenerator(""); - private final Function _replyHandler; /** Map from request correlation ID to continuation BlockingCell */ diff --git a/src/main/java/com/rabbitmq/client/RpcClientParams.java b/src/main/java/com/rabbitmq/client/RpcClientParams.java index da3d56b9f8..db32896cd5 100644 --- a/src/main/java/com/rabbitmq/client/RpcClientParams.java +++ b/src/main/java/com/rabbitmq/client/RpcClientParams.java @@ -55,7 +55,7 @@ public class RpcClientParams { */ private Function replyHandler = RpcClient.DEFAULT_REPLY_HANDLER; - private Supplier correlationIdGenerator = RpcClient.DEFAULT_CORRELATION_ID_GENERATOR; + private Supplier correlationIdGenerator = new IncrementingCorrelationIdGenerator(""); /** * Set the channel to use for communication. From 5ee2a77c932161459a56d076767a396335335353 Mon Sep 17 00:00:00 2001 From: janssk1 Date: Tue, 4 Feb 2020 18:49:45 +0100 Subject: [PATCH 1217/2114] 637: Default generator should not be static Change-Id: Ib1f90d5a25f1c5db32ff9c838cfbeb35aac5d671 (cherry picked from commit 59e9455d5eef03dee4e934e5c21219645fdd81fb) --- .../client/IncrementingCorrelationIdGenerator.java | 4 ++++ src/main/java/com/rabbitmq/client/RpcClient.java | 13 +++++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/main/java/com/rabbitmq/client/IncrementingCorrelationIdGenerator.java b/src/main/java/com/rabbitmq/client/IncrementingCorrelationIdGenerator.java index 3b712cfcdf..e9f8012627 100644 --- a/src/main/java/com/rabbitmq/client/IncrementingCorrelationIdGenerator.java +++ b/src/main/java/com/rabbitmq/client/IncrementingCorrelationIdGenerator.java @@ -15,4 +15,8 @@ public IncrementingCorrelationIdGenerator(String _prefix) { public String get() { return _prefix + _correlationId++; } + + public int getCorrelationId() { + return _correlationId; + } } diff --git a/src/main/java/com/rabbitmq/client/RpcClient.java b/src/main/java/com/rabbitmq/client/RpcClient.java index 03599c516c..df0ed91fe2 100644 --- a/src/main/java/com/rabbitmq/client/RpcClient.java +++ b/src/main/java/com/rabbitmq/client/RpcClient.java @@ -474,6 +474,19 @@ public Map> getContinuationMap() { return _continuationMap; } + /** + * Retrieve the correlation id. + * @return the most recently used correlation id + * @deprecated Only works for {@link IncrementingCorrelationIdGenerator} + */ + public int getCorrelationId() { + if (_correlationIdGenerator instanceof IncrementingCorrelationIdGenerator) { + return ((IncrementingCorrelationIdGenerator) _correlationIdGenerator).getCorrelationId(); + } else { + throw new UnsupportedOperationException(); + } + } + /** * Retrieve the consumer. * @return an interface to the client's consumer object From 177c4ea56c4ad3fbfb507701a4c46d5fdcae7a40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 17 Feb 2020 12:13:31 +0100 Subject: [PATCH 1218/2114] Polish correlation ID supplier support in RPC client References #637 (cherry picked from commit 96b24b38516cef7eb011d5e4d5d1cb91cb1c0fb5) --- .../IncrementingCorrelationIdGenerator.java | 22 ------ .../java/com/rabbitmq/client/RpcClient.java | 75 ++++++++++++++++--- .../com/rabbitmq/client/RpcClientParams.java | 24 ++++-- .../com/rabbitmq/client/test/RpcTest.java | 13 ++-- 4 files changed, 90 insertions(+), 44 deletions(-) delete mode 100644 src/main/java/com/rabbitmq/client/IncrementingCorrelationIdGenerator.java diff --git a/src/main/java/com/rabbitmq/client/IncrementingCorrelationIdGenerator.java b/src/main/java/com/rabbitmq/client/IncrementingCorrelationIdGenerator.java deleted file mode 100644 index e9f8012627..0000000000 --- a/src/main/java/com/rabbitmq/client/IncrementingCorrelationIdGenerator.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.rabbitmq.client; - -import java.util.function.Supplier; - -public class IncrementingCorrelationIdGenerator implements Supplier { - - private final String _prefix; - private int _correlationId; - - public IncrementingCorrelationIdGenerator(String _prefix) { - this._prefix = _prefix; - } - - @Override - public String get() { - return _prefix + _correlationId++; - } - - public int getCorrelationId() { - return _correlationId; - } -} diff --git a/src/main/java/com/rabbitmq/client/RpcClient.java b/src/main/java/com/rabbitmq/client/RpcClient.java index df0ed91fe2..7c83c7eb2b 100644 --- a/src/main/java/com/rabbitmq/client/RpcClient.java +++ b/src/main/java/com/rabbitmq/client/RpcClient.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 Pivotal Software, Inc. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 @@ -84,9 +84,16 @@ public class RpcClient { /** Map from request correlation ID to continuation BlockingCell */ private final Map> _continuationMap = new HashMap>(); - /** Contains the most recently-used request correlation ID */ + + /** + * Generates correlation ID for each request. + * + * @since 5.9.0 + */ private final Supplier _correlationIdGenerator; + private String lastCorrelationId = "0"; + /** Consumer attached to our reply queue */ private DefaultConsumer _consumer; @@ -110,7 +117,7 @@ public RpcClient(RpcClientParams params) throws _timeout = params.getTimeout(); _useMandatory = params.shouldUseMandatory(); _replyHandler = params.getReplyHandler(); - _correlationIdGenerator = params.getCorrelationIdGenerator(); + _correlationIdGenerator = params.getCorrelationIdSupplier(); _consumer = setupConsumer(); if (_useMandatory) { @@ -295,6 +302,7 @@ public Response doCall(AMQP.BasicProperties props, byte[] message, int timeout) String replyId; synchronized (_continuationMap) { replyId = _correlationIdGenerator.get(); + lastCorrelationId = replyId; props = ((props==null) ? new AMQP.BasicProperties.Builder() : props.builder()) .correlationId(replyId).replyTo(_replyTo).build(); _continuationMap.put(replyId, k); @@ -475,16 +483,21 @@ public Map> getContinuationMap() { } /** - * Retrieve the correlation id. + * Retrieve the last correlation id used. + *

+ * Note as of 5.9.0, correlation IDs may not always be integers + * (by default, they are). + * This method will try to parse the last correlation ID string + * as an integer, so this may result in {@link NumberFormatException} + * if the correlation ID supplier provided by + * {@link RpcClientParams#correlationIdSupplier(Supplier)} + * does not generate appropriate IDs. + * * @return the most recently used correlation id - * @deprecated Only works for {@link IncrementingCorrelationIdGenerator} + * @see RpcClientParams#correlationIdSupplier(Supplier) */ public int getCorrelationId() { - if (_correlationIdGenerator instanceof IncrementingCorrelationIdGenerator) { - return ((IncrementingCorrelationIdGenerator) _correlationIdGenerator).getCorrelationId(); - } else { - throw new UnsupportedOperationException(); - } + return Integer.valueOf(this.lastCorrelationId); } /** @@ -532,5 +545,47 @@ public byte[] getBody() { return body; } } + + /** + * Creates generation IDs as a sequence of integers. + * + * @return + * @see RpcClientParams#correlationIdSupplier(Supplier) + * @since 5.9.0 + */ + public static Supplier incrementingCorrelationIdSupplier() { + return incrementingCorrelationIdSupplier(""); + } + + /** + * Creates generation IDs as a sequence of integers, with the provided prefix. + * + * @param prefix + * @return + * @see RpcClientParams#correlationIdSupplier(Supplier) + * @since 5.9.0 + */ + public static Supplier incrementingCorrelationIdSupplier(String prefix) { + return new IncrementingCorrelationIdSupplier(prefix); + } + + /** + * @since 5.9.0 + */ + private static class IncrementingCorrelationIdSupplier implements Supplier { + + private final String prefix; + private int correlationId; + + public IncrementingCorrelationIdSupplier(String prefix) { + this.prefix = prefix; + } + + @Override + public String get() { + return prefix + ++correlationId; + } + + } } diff --git a/src/main/java/com/rabbitmq/client/RpcClientParams.java b/src/main/java/com/rabbitmq/client/RpcClientParams.java index db32896cd5..870756e25a 100644 --- a/src/main/java/com/rabbitmq/client/RpcClientParams.java +++ b/src/main/java/com/rabbitmq/client/RpcClientParams.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 Pivotal Software, Inc. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 @@ -55,7 +55,10 @@ public class RpcClientParams { */ private Function replyHandler = RpcClient.DEFAULT_REPLY_HANDLER; - private Supplier correlationIdGenerator = new IncrementingCorrelationIdGenerator(""); + /** + * Logic to generate correlation IDs. + */ + private Supplier correlationIdSupplier = RpcClient.incrementingCorrelationIdSupplier(); /** * Set the channel to use for communication. @@ -149,7 +152,7 @@ public RpcClientParams timeout(int timeout) { * * @param useMandatory * @return - * @see #replyHandler(RpcClient.RpcClientReplyHandler) + * @see #replyHandler(Function) */ public RpcClientParams useMandatory(boolean useMandatory) { this.useMandatory = useMandatory; @@ -173,13 +176,20 @@ public boolean shouldUseMandatory() { return useMandatory; } - public RpcClientParams correlationIdGenerator(Supplier correlationIdGenerator) { - this.correlationIdGenerator = correlationIdGenerator; + /** + * Logic to generate correlation IDs. + * + * @param correlationIdGenerator + * @return + * @since 5.9.0 + */ + public RpcClientParams correlationIdSupplier(Supplier correlationIdGenerator) { + this.correlationIdSupplier = correlationIdGenerator; return this; } - public Supplier getCorrelationIdGenerator() { - return correlationIdGenerator; + public Supplier getCorrelationIdSupplier() { + return correlationIdSupplier; } public Function getReplyHandler() { diff --git a/src/test/java/com/rabbitmq/client/test/RpcTest.java b/src/test/java/com/rabbitmq/client/test/RpcTest.java index 8837f726c7..027c1e081a 100644 --- a/src/test/java/com/rabbitmq/client/test/RpcTest.java +++ b/src/test/java/com/rabbitmq/client/test/RpcTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2017-2020 Pivotal Software, Inc. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 @@ -24,7 +24,7 @@ import com.rabbitmq.client.impl.recovery.RecordedQueue; import com.rabbitmq.client.impl.recovery.TopologyRecoveryFilter; import com.rabbitmq.tools.Host; -import org.hamcrest.CoreMatchers; +import org.assertj.core.api.Assertions; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -86,6 +86,9 @@ public void rpc() throws Exception { assertEquals("*** hello ***", new String(response.getBody())); assertEquals("pre-hello", response.getProperties().getHeaders().get("pre").toString()); assertEquals("post-hello", response.getProperties().getHeaders().get("post").toString()); + + Assertions.assertThat(client.getCorrelationId()).isEqualTo(Integer.valueOf(response.getProperties().getCorrelationId())); + client.close(); } @@ -138,7 +141,7 @@ public void rpcUnroutableWithMandatoryFlagShouldThrowUnroutableException() throw } @Test - public void rpcCustomCorrelatorId() throws Exception { + public void rpcCustomCorrelationId() throws Exception { rpcServer = new TestRpcServer(serverChannel, queue); new Thread(() -> { try { @@ -149,10 +152,10 @@ public void rpcCustomCorrelatorId() throws Exception { }).start(); RpcClient client = new RpcClient(new RpcClientParams() .channel(clientChannel).exchange("").routingKey(queue).timeout(1000) - .correlationIdGenerator(new IncrementingCorrelationIdGenerator("myPrefix-")) + .correlationIdSupplier(RpcClient.incrementingCorrelationIdSupplier("myPrefix-")) ); RpcClient.Response response = client.doCall(null, "hello".getBytes()); - assertThat(response.getProperties().getCorrelationId(), CoreMatchers.equalTo("myPrefix-0")); + Assertions.assertThat(response.getProperties().getCorrelationId()).isEqualTo("myPrefix-1"); client.close(); } From 52c0643e3f0dd1d65fee7540410e7b611d239435 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 17 Feb 2020 14:24:36 +0100 Subject: [PATCH 1219/2114] Rename property References #637 --- src/main/java/com/rabbitmq/client/RpcClient.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/RpcClient.java b/src/main/java/com/rabbitmq/client/RpcClient.java index 880ed5c518..8a5099d3e7 100644 --- a/src/main/java/com/rabbitmq/client/RpcClient.java +++ b/src/main/java/com/rabbitmq/client/RpcClient.java @@ -90,7 +90,7 @@ public class RpcClient { * * @since 5.9.0 */ - private final Supplier _correlationIdGenerator; + private final Supplier _correlationIdSupplier; private String lastCorrelationId = "0"; @@ -117,7 +117,7 @@ public RpcClient(RpcClientParams params) throws _timeout = params.getTimeout(); _useMandatory = params.shouldUseMandatory(); _replyHandler = params.getReplyHandler(); - _correlationIdGenerator = params.getCorrelationIdSupplier(); + _correlationIdSupplier = params.getCorrelationIdSupplier(); _consumer = setupConsumer(); if (_useMandatory) { @@ -216,7 +216,7 @@ public Response doCall(AMQP.BasicProperties props, byte[] message, int timeout) BlockingCell k = new BlockingCell(); String replyId; synchronized (_continuationMap) { - replyId = _correlationIdGenerator.get(); + replyId = _correlationIdSupplier.get(); lastCorrelationId = replyId; props = ((props==null) ? new AMQP.BasicProperties.Builder() : props.builder()) .correlationId(replyId).replyTo(_replyTo).build(); From f25b038b2524a4526b1ea80f97d99355b35e2849 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 17 Feb 2020 14:24:36 +0100 Subject: [PATCH 1220/2114] Rename property References #637 (cherry picked from commit 52c0643e3f0dd1d65fee7540410e7b611d239435) --- src/main/java/com/rabbitmq/client/RpcClient.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/RpcClient.java b/src/main/java/com/rabbitmq/client/RpcClient.java index 7c83c7eb2b..a49e403f3e 100644 --- a/src/main/java/com/rabbitmq/client/RpcClient.java +++ b/src/main/java/com/rabbitmq/client/RpcClient.java @@ -90,7 +90,7 @@ public class RpcClient { * * @since 5.9.0 */ - private final Supplier _correlationIdGenerator; + private final Supplier _correlationIdSupplier; private String lastCorrelationId = "0"; @@ -117,7 +117,7 @@ public RpcClient(RpcClientParams params) throws _timeout = params.getTimeout(); _useMandatory = params.shouldUseMandatory(); _replyHandler = params.getReplyHandler(); - _correlationIdGenerator = params.getCorrelationIdSupplier(); + _correlationIdSupplier = params.getCorrelationIdSupplier(); _consumer = setupConsumer(); if (_useMandatory) { @@ -301,7 +301,7 @@ public Response doCall(AMQP.BasicProperties props, byte[] message, int timeout) BlockingCell k = new BlockingCell(); String replyId; synchronized (_continuationMap) { - replyId = _correlationIdGenerator.get(); + replyId = _correlationIdSupplier.get(); lastCorrelationId = replyId; props = ((props==null) ? new AMQP.BasicProperties.Builder() : props.builder()) .correlationId(replyId).replyTo(_replyTo).build(); From 91fe55a0b1a6131fe2c4dd110fb71fea908174c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Tue, 10 Mar 2020 15:45:14 +0100 Subject: [PATCH 1221/2114] Update copyright (year 2020) --- LICENSE-MPL-RabbitMQ | 2 +- codegen.py | 4 ++-- src/main/java/com/rabbitmq/client/Address.java | 2 +- src/main/java/com/rabbitmq/client/AddressResolver.java | 2 +- src/main/java/com/rabbitmq/client/AlreadyClosedException.java | 2 +- .../com/rabbitmq/client/AuthenticationFailureException.java | 2 +- src/main/java/com/rabbitmq/client/BasicProperties.java | 2 +- src/main/java/com/rabbitmq/client/BlockedCallback.java | 2 +- src/main/java/com/rabbitmq/client/BlockedListener.java | 2 +- src/main/java/com/rabbitmq/client/CancelCallback.java | 2 +- src/main/java/com/rabbitmq/client/Channel.java | 2 +- src/main/java/com/rabbitmq/client/Command.java | 2 +- src/main/java/com/rabbitmq/client/ConfirmCallback.java | 2 +- src/main/java/com/rabbitmq/client/ConfirmListener.java | 2 +- src/main/java/com/rabbitmq/client/Connection.java | 2 +- src/main/java/com/rabbitmq/client/ConnectionFactory.java | 2 +- .../com/rabbitmq/client/ConnectionFactoryConfigurator.java | 2 +- src/main/java/com/rabbitmq/client/Consumer.java | 2 +- .../java/com/rabbitmq/client/ConsumerCancelledException.java | 2 +- .../com/rabbitmq/client/ConsumerShutdownSignalCallback.java | 2 +- src/main/java/com/rabbitmq/client/ContentHeader.java | 2 +- src/main/java/com/rabbitmq/client/DefaultConsumer.java | 2 +- src/main/java/com/rabbitmq/client/DefaultSaslConfig.java | 2 +- .../com/rabbitmq/client/DefaultSocketChannelConfigurator.java | 2 +- .../java/com/rabbitmq/client/DefaultSocketConfigurator.java | 2 +- src/main/java/com/rabbitmq/client/DeliverCallback.java | 2 +- src/main/java/com/rabbitmq/client/Delivery.java | 2 +- .../java/com/rabbitmq/client/DnsRecordIpAddressResolver.java | 2 +- .../java/com/rabbitmq/client/DnsSrvRecordAddressResolver.java | 2 +- src/main/java/com/rabbitmq/client/Envelope.java | 2 +- src/main/java/com/rabbitmq/client/ExceptionHandler.java | 2 +- src/main/java/com/rabbitmq/client/GetResponse.java | 2 +- src/main/java/com/rabbitmq/client/JDKSaslConfig.java | 2 +- src/main/java/com/rabbitmq/client/ListAddressResolver.java | 2 +- src/main/java/com/rabbitmq/client/LongString.java | 2 +- .../java/com/rabbitmq/client/MalformedFrameException.java | 2 +- src/main/java/com/rabbitmq/client/MapRpcServer.java | 2 +- src/main/java/com/rabbitmq/client/MessageProperties.java | 2 +- src/main/java/com/rabbitmq/client/Method.java | 2 +- src/main/java/com/rabbitmq/client/MetricsCollector.java | 2 +- .../java/com/rabbitmq/client/MissedHeartbeatException.java | 2 +- src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java | 2 +- .../client/PossibleAuthenticationFailureException.java | 2 +- .../com/rabbitmq/client/ProtocolVersionMismatchException.java | 2 +- src/main/java/com/rabbitmq/client/Recoverable.java | 2 +- src/main/java/com/rabbitmq/client/RecoveryDelayHandler.java | 2 +- src/main/java/com/rabbitmq/client/RecoveryListener.java | 2 +- src/main/java/com/rabbitmq/client/Return.java | 2 +- src/main/java/com/rabbitmq/client/ReturnCallback.java | 2 +- src/main/java/com/rabbitmq/client/ReturnListener.java | 2 +- src/main/java/com/rabbitmq/client/RpcClient.java | 2 +- src/main/java/com/rabbitmq/client/RpcClientParams.java | 2 +- src/main/java/com/rabbitmq/client/RpcServer.java | 2 +- src/main/java/com/rabbitmq/client/SaslConfig.java | 2 +- src/main/java/com/rabbitmq/client/SaslMechanism.java | 2 +- src/main/java/com/rabbitmq/client/ShutdownListener.java | 2 +- src/main/java/com/rabbitmq/client/ShutdownNotifier.java | 2 +- .../java/com/rabbitmq/client/ShutdownSignalException.java | 2 +- .../java/com/rabbitmq/client/SocketChannelConfigurator.java | 2 +- .../java/com/rabbitmq/client/SocketChannelConfigurators.java | 2 +- src/main/java/com/rabbitmq/client/SocketConfigurator.java | 2 +- src/main/java/com/rabbitmq/client/SocketConfigurators.java | 2 +- src/main/java/com/rabbitmq/client/SslContextFactory.java | 2 +- src/main/java/com/rabbitmq/client/SslEngineConfigurator.java | 2 +- src/main/java/com/rabbitmq/client/SslEngineConfigurators.java | 2 +- src/main/java/com/rabbitmq/client/StringRpcServer.java | 2 +- .../java/com/rabbitmq/client/TopologyRecoveryException.java | 2 +- .../java/com/rabbitmq/client/TrustEverythingTrustManager.java | 2 +- src/main/java/com/rabbitmq/client/UnblockedCallback.java | 2 +- src/main/java/com/rabbitmq/client/UnexpectedFrameError.java | 2 +- src/main/java/com/rabbitmq/client/UnexpectedMethodError.java | 2 +- src/main/java/com/rabbitmq/client/UnknownClassOrMethodId.java | 2 +- .../com/rabbitmq/client/UnroutableRpcRequestException.java | 2 +- .../java/com/rabbitmq/client/impl/AMQBasicProperties.java | 2 +- src/main/java/com/rabbitmq/client/impl/AMQChannel.java | 2 +- src/main/java/com/rabbitmq/client/impl/AMQCommand.java | 2 +- src/main/java/com/rabbitmq/client/impl/AMQConnection.java | 4 ++-- src/main/java/com/rabbitmq/client/impl/AMQContentHeader.java | 2 +- .../com/rabbitmq/client/impl/AbstractMetricsCollector.java | 2 +- src/main/java/com/rabbitmq/client/impl/CRDemoMechanism.java | 2 +- src/main/java/com/rabbitmq/client/impl/ChannelManager.java | 2 +- src/main/java/com/rabbitmq/client/impl/ChannelN.java | 2 +- src/main/java/com/rabbitmq/client/impl/ClientVersion.java | 2 +- src/main/java/com/rabbitmq/client/impl/CommandAssembler.java | 2 +- .../com/rabbitmq/client/impl/CompletableFutureRpcWrapper.java | 2 +- src/main/java/com/rabbitmq/client/impl/ConnectionParams.java | 2 +- .../java/com/rabbitmq/client/impl/ConsumerDispatcher.java | 2 +- .../java/com/rabbitmq/client/impl/ConsumerWorkService.java | 2 +- .../com/rabbitmq/client/impl/ContentHeaderPropertyReader.java | 2 +- .../com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java | 2 +- .../java/com/rabbitmq/client/impl/CredentialsProvider.java | 2 +- .../com/rabbitmq/client/impl/CredentialsRefreshService.java | 2 +- .../com/rabbitmq/client/impl/DefaultCredentialsProvider.java | 2 +- .../client/impl/DefaultCredentialsRefreshService.java | 2 +- .../com/rabbitmq/client/impl/DefaultExceptionHandler.java | 2 +- src/main/java/com/rabbitmq/client/impl/Environment.java | 2 +- .../java/com/rabbitmq/client/impl/ErrorOnWriteListener.java | 2 +- src/main/java/com/rabbitmq/client/impl/ExternalMechanism.java | 2 +- .../com/rabbitmq/client/impl/ForgivingExceptionHandler.java | 2 +- src/main/java/com/rabbitmq/client/impl/Frame.java | 2 +- src/main/java/com/rabbitmq/client/impl/FrameHandler.java | 2 +- src/main/java/com/rabbitmq/client/impl/HeartbeatSender.java | 2 +- src/main/java/com/rabbitmq/client/impl/LongStringHelper.java | 2 +- src/main/java/com/rabbitmq/client/impl/Method.java | 2 +- .../java/com/rabbitmq/client/impl/MethodArgumentReader.java | 2 +- .../java/com/rabbitmq/client/impl/MethodArgumentWriter.java | 2 +- .../com/rabbitmq/client/impl/MicrometerMetricsCollector.java | 2 +- src/main/java/com/rabbitmq/client/impl/NetworkConnection.java | 2 +- .../impl/OAuth2ClientCredentialsGrantCredentialsProvider.java | 2 +- .../rabbitmq/client/impl/OAuthTokenManagementException.java | 2 +- src/main/java/com/rabbitmq/client/impl/PlainMechanism.java | 2 +- .../client/impl/RefreshProtectedCredentialsProvider.java | 2 +- .../com/rabbitmq/client/impl/RpcContinuationRpcWrapper.java | 2 +- src/main/java/com/rabbitmq/client/impl/RpcWrapper.java | 2 +- src/main/java/com/rabbitmq/client/impl/SetQueue.java | 2 +- .../com/rabbitmq/client/impl/ShutdownNotifierComponent.java | 2 +- .../java/com/rabbitmq/client/impl/SocketFrameHandler.java | 2 +- .../com/rabbitmq/client/impl/SocketFrameHandlerFactory.java | 2 +- .../com/rabbitmq/client/impl/StandardMetricsCollector.java | 2 +- .../java/com/rabbitmq/client/impl/StrictExceptionHandler.java | 2 +- src/main/java/com/rabbitmq/client/impl/TlsUtils.java | 2 +- .../java/com/rabbitmq/client/impl/TruncatedInputStream.java | 2 +- .../com/rabbitmq/client/impl/UnknownChannelException.java | 2 +- .../java/com/rabbitmq/client/impl/UpdateSecretExtension.java | 2 +- src/main/java/com/rabbitmq/client/impl/ValueReader.java | 2 +- src/main/java/com/rabbitmq/client/impl/ValueWriter.java | 2 +- .../com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java | 2 +- src/main/java/com/rabbitmq/client/impl/Version.java | 2 +- src/main/java/com/rabbitmq/client/impl/WorkPool.java | 2 +- .../java/com/rabbitmq/client/impl/WorkPoolFullException.java | 2 +- .../com/rabbitmq/client/impl/nio/ByteBufferOutputStream.java | 2 +- src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java | 2 +- .../java/com/rabbitmq/client/impl/nio/FrameWriteRequest.java | 2 +- .../java/com/rabbitmq/client/impl/nio/HeaderWriteRequest.java | 2 +- src/main/java/com/rabbitmq/client/impl/nio/NioHelper.java | 2 +- src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java | 2 +- .../java/com/rabbitmq/client/impl/nio/NioLoopContext.java | 2 +- src/main/java/com/rabbitmq/client/impl/nio/NioParams.java | 2 +- .../java/com/rabbitmq/client/impl/nio/SelectorHolder.java | 2 +- .../rabbitmq/client/impl/nio/SocketChannelFrameHandler.java | 2 +- .../client/impl/nio/SocketChannelFrameHandlerFactory.java | 2 +- .../client/impl/nio/SocketChannelFrameHandlerState.java | 2 +- .../rabbitmq/client/impl/nio/SocketChannelRegistration.java | 2 +- .../client/impl/nio/SslEngineByteBufferOutputStream.java | 2 +- .../com/rabbitmq/client/impl/nio/SslEngineFrameBuilder.java | 2 +- .../java/com/rabbitmq/client/impl/nio/SslEngineHelper.java | 2 +- src/main/java/com/rabbitmq/client/impl/nio/WriteRequest.java | 2 +- .../rabbitmq/client/impl/recovery/AutorecoveringChannel.java | 2 +- .../client/impl/recovery/AutorecoveringConnection.java | 2 +- .../java/com/rabbitmq/client/impl/recovery/BackoffPolicy.java | 2 +- .../client/impl/recovery/ConsumerRecoveryListener.java | 2 +- .../rabbitmq/client/impl/recovery/DefaultRetryHandler.java | 2 +- .../rabbitmq/client/impl/recovery/QueueRecoveryListener.java | 2 +- .../com/rabbitmq/client/impl/recovery/RecordedBinding.java | 2 +- .../com/rabbitmq/client/impl/recovery/RecordedConsumer.java | 2 +- .../com/rabbitmq/client/impl/recovery/RecordedEntity.java | 2 +- .../com/rabbitmq/client/impl/recovery/RecordedExchange.java | 2 +- .../client/impl/recovery/RecordedExchangeBinding.java | 2 +- .../rabbitmq/client/impl/recovery/RecordedNamedEntity.java | 2 +- .../java/com/rabbitmq/client/impl/recovery/RecordedQueue.java | 2 +- .../rabbitmq/client/impl/recovery/RecordedQueueBinding.java | 2 +- .../client/impl/recovery/RecoveryAwareAMQConnection.java | 2 +- .../impl/recovery/RecoveryAwareAMQConnectionFactory.java | 2 +- .../client/impl/recovery/RecoveryAwareChannelManager.java | 2 +- .../rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java | 2 +- .../client/impl/recovery/RecoveryCanBeginListener.java | 2 +- .../java/com/rabbitmq/client/impl/recovery/RetryContext.java | 2 +- .../java/com/rabbitmq/client/impl/recovery/RetryHandler.java | 2 +- .../java/com/rabbitmq/client/impl/recovery/RetryResult.java | 2 +- .../rabbitmq/client/impl/recovery/TopologyRecoveryFilter.java | 2 +- .../impl/recovery/TopologyRecoveryRetryHandlerBuilder.java | 2 +- .../client/impl/recovery/TopologyRecoveryRetryLogic.java | 2 +- src/main/java/com/rabbitmq/tools/json/JSONUtil.java | 2 +- .../java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java | 2 +- src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java | 2 +- .../java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java | 2 +- src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java | 2 +- .../com/rabbitmq/tools/jsonrpc/JsonRpcMappingException.java | 2 +- src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java | 2 +- .../java/com/rabbitmq/tools/jsonrpc/ParameterDescription.java | 2 +- .../java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java | 2 +- .../java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java | 2 +- src/main/java/com/rabbitmq/utility/BlockingCell.java | 2 +- .../java/com/rabbitmq/utility/BlockingValueOrException.java | 2 +- src/main/java/com/rabbitmq/utility/IntAllocator.java | 2 +- src/main/java/com/rabbitmq/utility/SensibleClone.java | 2 +- src/main/java/com/rabbitmq/utility/Utility.java | 2 +- src/main/java/com/rabbitmq/utility/ValueOrException.java | 2 +- src/test/java/com/rabbitmq/client/AbstractJsonRpcTest.java | 2 +- src/test/java/com/rabbitmq/client/JacksonJsonRpcTest.java | 2 +- src/test/java/com/rabbitmq/client/QueueingConsumer.java | 2 +- .../client/impl/AMQConnectionRefreshCredentialsTest.java | 2 +- .../client/impl/DefaultCredentialsRefreshServiceTest.java | 2 +- .../OAuth2ClientCredentialsGrantCredentialsProviderTest.java | 2 +- .../client/impl/RefreshProtectedCredentialsProviderTest.java | 2 +- src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java | 2 +- src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java | 2 +- src/test/java/com/rabbitmq/client/test/AMQBuilderApiTest.java | 2 +- src/test/java/com/rabbitmq/client/test/AMQChannelTest.java | 2 +- src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java | 2 +- .../java/com/rabbitmq/client/test/AbstractRMQTestSuite.java | 2 +- src/test/java/com/rabbitmq/client/test/AddressTest.java | 2 +- src/test/java/com/rabbitmq/client/test/AmqpUriTest.java | 2 +- src/test/java/com/rabbitmq/client/test/BlockingCellTest.java | 2 +- src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java | 2 +- src/test/java/com/rabbitmq/client/test/BrokerTestCase.java | 2 +- src/test/java/com/rabbitmq/client/test/Bug20004Test.java | 2 +- .../client/test/ChannelAsyncCompletableFutureTest.java | 2 +- src/test/java/com/rabbitmq/client/test/ChannelNTest.java | 2 +- .../rabbitmq/client/test/ChannelNumberAllocationTests.java | 2 +- .../client/test/ChannelRpcTimeoutIntegrationTest.java | 2 +- src/test/java/com/rabbitmq/client/test/ClientTests.java | 2 +- src/test/java/com/rabbitmq/client/test/ClientVersionTest.java | 2 +- .../java/com/rabbitmq/client/test/ClonePropertiesTest.java | 2 +- src/test/java/com/rabbitmq/client/test/CloseInMainLoop.java | 2 +- src/test/java/com/rabbitmq/client/test/ConfirmBase.java | 2 +- .../java/com/rabbitmq/client/test/ConnectionFactoryTest.java | 2 +- src/test/java/com/rabbitmq/client/test/ConnectionTest.java | 2 +- .../com/rabbitmq/client/test/DefaultRetryHandlerTest.java | 2 +- .../rabbitmq/client/test/DnsSrvRecordAddressResolverTest.java | 2 +- src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java | 2 +- .../java/com/rabbitmq/client/test/GeneratedClassesTest.java | 2 +- .../java/com/rabbitmq/client/test/LambdaCallbackTest.java | 2 +- src/test/java/com/rabbitmq/client/test/LongStringTest.java | 2 +- .../java/com/rabbitmq/client/test/MetricsCollectorTest.java | 2 +- .../rabbitmq/client/test/MicrometerMetricsCollectorTest.java | 2 +- .../java/com/rabbitmq/client/test/MultiThreadedChannel.java | 2 +- .../rabbitmq/client/test/NioDeadlockOnConnectionClosing.java | 2 +- .../client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java | 2 +- .../rabbitmq/client/test/PropertyFileInitialisationTest.java | 2 +- .../java/com/rabbitmq/client/test/QueueingConsumerTests.java | 2 +- .../client/test/RecoveryAwareAMQConnectionFactoryTest.java | 2 +- .../com/rabbitmq/client/test/RecoveryDelayHandlerTest.java | 2 +- .../java/com/rabbitmq/client/test/RefreshCredentialsTest.java | 2 +- src/test/java/com/rabbitmq/client/test/RpcTest.java | 2 +- .../com/rabbitmq/client/test/RpcTopologyRecordingTest.java | 2 +- .../java/com/rabbitmq/client/test/SharedThreadPoolTest.java | 2 +- .../java/com/rabbitmq/client/test/SslContextFactoryTest.java | 2 +- .../com/rabbitmq/client/test/StrictExceptionHandlerTest.java | 2 +- src/test/java/com/rabbitmq/client/test/TableTest.java | 2 +- src/test/java/com/rabbitmq/client/test/TestUtils.java | 2 +- src/test/java/com/rabbitmq/client/test/TestUtilsTest.java | 2 +- src/test/java/com/rabbitmq/client/test/TlsUtilsTest.java | 2 +- .../java/com/rabbitmq/client/test/TrafficListenerTest.java | 2 +- .../com/rabbitmq/client/test/TruncatedInputStreamTest.java | 2 +- .../java/com/rabbitmq/client/test/ValueOrExceptionTest.java | 2 +- .../rabbitmq/client/test/functional/AbstractRejectTest.java | 2 +- .../rabbitmq/client/test/functional/AlternateExchange.java | 2 +- .../java/com/rabbitmq/client/test/functional/BasicGet.java | 2 +- .../com/rabbitmq/client/test/functional/BindingLifecycle.java | 2 +- .../rabbitmq/client/test/functional/BindingLifecycleBase.java | 2 +- .../java/com/rabbitmq/client/test/functional/CcRoutes.java | 2 +- .../rabbitmq/client/test/functional/ClusteredTestBase.java | 2 +- .../java/com/rabbitmq/client/test/functional/Confirm.java | 2 +- .../com/rabbitmq/client/test/functional/ConnectionOpen.java | 2 +- .../rabbitmq/client/test/functional/ConnectionRecovery.java | 2 +- .../client/test/functional/ConsumerCancelNotification.java | 2 +- .../com/rabbitmq/client/test/functional/ConsumerCount.java | 2 +- .../rabbitmq/client/test/functional/ConsumerPriorities.java | 2 +- .../rabbitmq/client/test/functional/DeadLetterExchange.java | 2 +- .../com/rabbitmq/client/test/functional/DefaultExchange.java | 2 +- .../com/rabbitmq/client/test/functional/DirectReplyTo.java | 2 +- .../com/rabbitmq/client/test/functional/DoubleDeletion.java | 2 +- .../rabbitmq/client/test/functional/DurableOnTransient.java | 2 +- .../rabbitmq/client/test/functional/ExceptionHandling.java | 2 +- .../rabbitmq/client/test/functional/ExceptionMessages.java | 2 +- .../com/rabbitmq/client/test/functional/ExchangeDeclare.java | 2 +- .../client/test/functional/ExchangeDeleteIfUnused.java | 2 +- .../client/test/functional/ExchangeDeletePredeclared.java | 2 +- .../client/test/functional/ExchangeEquivalenceBase.java | 2 +- .../client/test/functional/ExchangeExchangeBindings.java | 2 +- .../test/functional/ExchangeExchangeBindingsAutoDelete.java | 2 +- .../java/com/rabbitmq/client/test/functional/FrameMax.java | 2 +- .../com/rabbitmq/client/test/functional/FunctionalTests.java | 2 +- .../client/test/functional/HeadersExchangeValidation.java | 2 +- .../java/com/rabbitmq/client/test/functional/Heartbeat.java | 2 +- .../com/rabbitmq/client/test/functional/InternalExchange.java | 2 +- .../java/com/rabbitmq/client/test/functional/InvalidAcks.java | 2 +- .../com/rabbitmq/client/test/functional/InvalidAcksBase.java | 2 +- .../com/rabbitmq/client/test/functional/InvalidAcksTx.java | 2 +- .../com/rabbitmq/client/test/functional/MessageCount.java | 2 +- .../java/com/rabbitmq/client/test/functional/Metrics.java | 2 +- src/test/java/com/rabbitmq/client/test/functional/Nack.java | 2 +- .../rabbitmq/client/test/functional/NoRequeueOnCancel.java | 2 +- src/test/java/com/rabbitmq/client/test/functional/Nowait.java | 2 +- .../rabbitmq/client/test/functional/PerConsumerPrefetch.java | 2 +- .../com/rabbitmq/client/test/functional/PerMessageTTL.java | 2 +- .../java/com/rabbitmq/client/test/functional/PerQueueTTL.java | 2 +- .../client/test/functional/PerQueueVsPerMessageTTL.java | 2 +- .../java/com/rabbitmq/client/test/functional/Policies.java | 2 +- .../java/com/rabbitmq/client/test/functional/QosTests.java | 2 +- .../com/rabbitmq/client/test/functional/QueueExclusivity.java | 2 +- .../java/com/rabbitmq/client/test/functional/QueueLease.java | 2 +- .../com/rabbitmq/client/test/functional/QueueLifecycle.java | 2 +- .../com/rabbitmq/client/test/functional/QueueSizeLimit.java | 2 +- .../java/com/rabbitmq/client/test/functional/Recover.java | 2 +- src/test/java/com/rabbitmq/client/test/functional/Reject.java | 2 +- .../client/test/functional/RequeueOnChannelClose.java | 2 +- .../com/rabbitmq/client/test/functional/RequeueOnClose.java | 2 +- .../client/test/functional/RequeueOnConnectionClose.java | 2 +- .../java/com/rabbitmq/client/test/functional/Routing.java | 2 +- .../com/rabbitmq/client/test/functional/SaslMechanisms.java | 2 +- .../java/com/rabbitmq/client/test/functional/TTLHandling.java | 2 +- src/test/java/com/rabbitmq/client/test/functional/Tables.java | 2 +- .../client/test/functional/TopologyRecoveryFiltering.java | 2 +- .../client/test/functional/TopologyRecoveryRetry.java | 2 +- .../com/rabbitmq/client/test/functional/Transactions.java | 2 +- .../client/test/functional/UnbindAutoDeleteExchange.java | 2 +- .../com/rabbitmq/client/test/functional/UnexpectedFrames.java | 2 +- .../com/rabbitmq/client/test/functional/UserIDHeader.java | 2 +- .../java/com/rabbitmq/client/test/server/AbsentQueue.java | 2 +- .../client/test/server/AlternateExchangeEquivalence.java | 2 +- .../com/rabbitmq/client/test/server/BlockedConnection.java | 2 +- .../java/com/rabbitmq/client/test/server/Bug19219Test.java | 2 +- .../rabbitmq/client/test/server/ChannelLimitNegotiation.java | 2 +- .../client/test/server/DeadLetterExchangeDurable.java | 2 +- .../rabbitmq/client/test/server/DurableBindingLifecycle.java | 2 +- .../client/test/server/EffectVisibilityCrossNodeTest.java | 2 +- .../rabbitmq/client/test/server/ExclusiveQueueDurability.java | 2 +- src/test/java/com/rabbitmq/client/test/server/Firehose.java | 2 +- src/test/java/com/rabbitmq/client/test/server/HATests.java | 2 +- .../java/com/rabbitmq/client/test/server/LoopbackUsers.java | 2 +- .../java/com/rabbitmq/client/test/server/MemoryAlarms.java | 2 +- .../java/com/rabbitmq/client/test/server/MessageRecovery.java | 2 +- .../java/com/rabbitmq/client/test/server/Permissions.java | 2 +- .../rabbitmq/client/test/server/PersistenceGuarantees.java | 2 +- .../java/com/rabbitmq/client/test/server/PriorityQueues.java | 2 +- .../java/com/rabbitmq/client/test/server/ServerTests.java | 2 +- src/test/java/com/rabbitmq/client/test/server/Shutdown.java | 2 +- .../com/rabbitmq/client/test/server/TopicPermissions.java | 2 +- .../com/rabbitmq/client/test/server/XDeathHeaderGrowth.java | 2 +- .../com/rabbitmq/client/test/ssl/BadVerifiedConnection.java | 2 +- .../client/test/ssl/ConnectionFactoryDefaultTlsVersion.java | 2 +- .../com/rabbitmq/client/test/ssl/HostnameVerification.java | 2 +- .../rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java | 2 +- src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java | 2 +- .../com/rabbitmq/client/test/ssl/TlsConnectionLogging.java | 2 +- .../com/rabbitmq/client/test/ssl/UnverifiedConnection.java | 2 +- .../java/com/rabbitmq/client/test/ssl/VerifiedConnection.java | 2 +- src/test/java/com/rabbitmq/tools/Host.java | 2 +- src/test/java/com/rabbitmq/utility/IntAllocatorTests.java | 2 +- 341 files changed, 343 insertions(+), 343 deletions(-) diff --git a/LICENSE-MPL-RabbitMQ b/LICENSE-MPL-RabbitMQ index b237a959b0..50770c2540 100644 --- a/LICENSE-MPL-RabbitMQ +++ b/LICENSE-MPL-RabbitMQ @@ -447,7 +447,7 @@ EXHIBIT A -Mozilla Public License. The Original Code is RabbitMQ. The Initial Developer of the Original Code is GoPivotal, Inc. - Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. + Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. Alternatively, the contents of this file may be used under the terms of the GNU General Public License version 2 (the "GPL2"), or diff --git a/codegen.py b/codegen.py index 3a67ce435d..42c577a0d9 100755 --- a/codegen.py +++ b/codegen.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -## Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. ## ## This software, the RabbitMQ Java client library, is triple-licensed under the ## Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 @@ -130,7 +130,7 @@ def printFileHeader(): print("""// NOTE: This -*- java -*- source code is autogenerated from the AMQP // specification! // -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/Address.java b/src/main/java/com/rabbitmq/client/Address.java index c70ae34df7..26b9cd9d3e 100644 --- a/src/main/java/com/rabbitmq/client/Address.java +++ b/src/main/java/com/rabbitmq/client/Address.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/AddressResolver.java b/src/main/java/com/rabbitmq/client/AddressResolver.java index 10ad17cb44..4a4f0d8461 100644 --- a/src/main/java/com/rabbitmq/client/AddressResolver.java +++ b/src/main/java/com/rabbitmq/client/AddressResolver.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/AlreadyClosedException.java b/src/main/java/com/rabbitmq/client/AlreadyClosedException.java index 06cca515ac..37060907f9 100644 --- a/src/main/java/com/rabbitmq/client/AlreadyClosedException.java +++ b/src/main/java/com/rabbitmq/client/AlreadyClosedException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/AuthenticationFailureException.java b/src/main/java/com/rabbitmq/client/AuthenticationFailureException.java index 998bddd2a1..391be6d039 100644 --- a/src/main/java/com/rabbitmq/client/AuthenticationFailureException.java +++ b/src/main/java/com/rabbitmq/client/AuthenticationFailureException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/BasicProperties.java b/src/main/java/com/rabbitmq/client/BasicProperties.java index 2dc7150cd1..4001508cfb 100644 --- a/src/main/java/com/rabbitmq/client/BasicProperties.java +++ b/src/main/java/com/rabbitmq/client/BasicProperties.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/BlockedCallback.java b/src/main/java/com/rabbitmq/client/BlockedCallback.java index 7e711dfdca..f679e79427 100644 --- a/src/main/java/com/rabbitmq/client/BlockedCallback.java +++ b/src/main/java/com/rabbitmq/client/BlockedCallback.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/BlockedListener.java b/src/main/java/com/rabbitmq/client/BlockedListener.java index 968fbb710c..4e0f820615 100644 --- a/src/main/java/com/rabbitmq/client/BlockedListener.java +++ b/src/main/java/com/rabbitmq/client/BlockedListener.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/CancelCallback.java b/src/main/java/com/rabbitmq/client/CancelCallback.java index c2691f053e..ee6df1964a 100644 --- a/src/main/java/com/rabbitmq/client/CancelCallback.java +++ b/src/main/java/com/rabbitmq/client/CancelCallback.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/Channel.java b/src/main/java/com/rabbitmq/client/Channel.java index f38d5e5f53..cdff101fd4 100644 --- a/src/main/java/com/rabbitmq/client/Channel.java +++ b/src/main/java/com/rabbitmq/client/Channel.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/Command.java b/src/main/java/com/rabbitmq/client/Command.java index b6c0e349a0..2630773ecc 100644 --- a/src/main/java/com/rabbitmq/client/Command.java +++ b/src/main/java/com/rabbitmq/client/Command.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ConfirmCallback.java b/src/main/java/com/rabbitmq/client/ConfirmCallback.java index fff2c9a6d6..41197874e3 100644 --- a/src/main/java/com/rabbitmq/client/ConfirmCallback.java +++ b/src/main/java/com/rabbitmq/client/ConfirmCallback.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ConfirmListener.java b/src/main/java/com/rabbitmq/client/ConfirmListener.java index 9404588554..51162d9baf 100644 --- a/src/main/java/com/rabbitmq/client/ConfirmListener.java +++ b/src/main/java/com/rabbitmq/client/ConfirmListener.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/Connection.java b/src/main/java/com/rabbitmq/client/Connection.java index 2b1c9281ee..d45c1b90ea 100644 --- a/src/main/java/com/rabbitmq/client/Connection.java +++ b/src/main/java/com/rabbitmq/client/Connection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index ebbdae3890..9c1dfa3fe0 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java b/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java index 694b7626a8..4470760d75 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/Consumer.java b/src/main/java/com/rabbitmq/client/Consumer.java index 61e799ae85..118ce0a8f3 100644 --- a/src/main/java/com/rabbitmq/client/Consumer.java +++ b/src/main/java/com/rabbitmq/client/Consumer.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ConsumerCancelledException.java b/src/main/java/com/rabbitmq/client/ConsumerCancelledException.java index 5d98220fd1..7078cfcf99 100644 --- a/src/main/java/com/rabbitmq/client/ConsumerCancelledException.java +++ b/src/main/java/com/rabbitmq/client/ConsumerCancelledException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ConsumerShutdownSignalCallback.java b/src/main/java/com/rabbitmq/client/ConsumerShutdownSignalCallback.java index 27e0f8ad39..fb055dde7e 100644 --- a/src/main/java/com/rabbitmq/client/ConsumerShutdownSignalCallback.java +++ b/src/main/java/com/rabbitmq/client/ConsumerShutdownSignalCallback.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ContentHeader.java b/src/main/java/com/rabbitmq/client/ContentHeader.java index 36e2ec29d2..ddb7d52b14 100644 --- a/src/main/java/com/rabbitmq/client/ContentHeader.java +++ b/src/main/java/com/rabbitmq/client/ContentHeader.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/DefaultConsumer.java b/src/main/java/com/rabbitmq/client/DefaultConsumer.java index 84ca404549..0e1670d39a 100644 --- a/src/main/java/com/rabbitmq/client/DefaultConsumer.java +++ b/src/main/java/com/rabbitmq/client/DefaultConsumer.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/DefaultSaslConfig.java b/src/main/java/com/rabbitmq/client/DefaultSaslConfig.java index 54373d868d..62ac85c4c1 100644 --- a/src/main/java/com/rabbitmq/client/DefaultSaslConfig.java +++ b/src/main/java/com/rabbitmq/client/DefaultSaslConfig.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/DefaultSocketChannelConfigurator.java b/src/main/java/com/rabbitmq/client/DefaultSocketChannelConfigurator.java index 425899532c..38494da70e 100644 --- a/src/main/java/com/rabbitmq/client/DefaultSocketChannelConfigurator.java +++ b/src/main/java/com/rabbitmq/client/DefaultSocketChannelConfigurator.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/DefaultSocketConfigurator.java b/src/main/java/com/rabbitmq/client/DefaultSocketConfigurator.java index e6fa99a5fc..0c3118e049 100644 --- a/src/main/java/com/rabbitmq/client/DefaultSocketConfigurator.java +++ b/src/main/java/com/rabbitmq/client/DefaultSocketConfigurator.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/DeliverCallback.java b/src/main/java/com/rabbitmq/client/DeliverCallback.java index ad44b7cf13..8e17dfb407 100644 --- a/src/main/java/com/rabbitmq/client/DeliverCallback.java +++ b/src/main/java/com/rabbitmq/client/DeliverCallback.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/Delivery.java b/src/main/java/com/rabbitmq/client/Delivery.java index eca6971be4..3e99f20974 100644 --- a/src/main/java/com/rabbitmq/client/Delivery.java +++ b/src/main/java/com/rabbitmq/client/Delivery.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/DnsRecordIpAddressResolver.java b/src/main/java/com/rabbitmq/client/DnsRecordIpAddressResolver.java index a26504c0fc..fb28f16a41 100644 --- a/src/main/java/com/rabbitmq/client/DnsRecordIpAddressResolver.java +++ b/src/main/java/com/rabbitmq/client/DnsRecordIpAddressResolver.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/DnsSrvRecordAddressResolver.java b/src/main/java/com/rabbitmq/client/DnsSrvRecordAddressResolver.java index 1388f716ae..81775fc9f6 100644 --- a/src/main/java/com/rabbitmq/client/DnsSrvRecordAddressResolver.java +++ b/src/main/java/com/rabbitmq/client/DnsSrvRecordAddressResolver.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/Envelope.java b/src/main/java/com/rabbitmq/client/Envelope.java index 3a83a05058..cc8e7ceda1 100644 --- a/src/main/java/com/rabbitmq/client/Envelope.java +++ b/src/main/java/com/rabbitmq/client/Envelope.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ExceptionHandler.java b/src/main/java/com/rabbitmq/client/ExceptionHandler.java index 45122737b1..3ed8183f28 100644 --- a/src/main/java/com/rabbitmq/client/ExceptionHandler.java +++ b/src/main/java/com/rabbitmq/client/ExceptionHandler.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/GetResponse.java b/src/main/java/com/rabbitmq/client/GetResponse.java index f6980304d6..ba157a0fb9 100644 --- a/src/main/java/com/rabbitmq/client/GetResponse.java +++ b/src/main/java/com/rabbitmq/client/GetResponse.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/JDKSaslConfig.java b/src/main/java/com/rabbitmq/client/JDKSaslConfig.java index 9c1e44a248..d8a240a30e 100644 --- a/src/main/java/com/rabbitmq/client/JDKSaslConfig.java +++ b/src/main/java/com/rabbitmq/client/JDKSaslConfig.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ListAddressResolver.java b/src/main/java/com/rabbitmq/client/ListAddressResolver.java index e4f80cb20e..a7b3d96657 100644 --- a/src/main/java/com/rabbitmq/client/ListAddressResolver.java +++ b/src/main/java/com/rabbitmq/client/ListAddressResolver.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/LongString.java b/src/main/java/com/rabbitmq/client/LongString.java index ee9a24169a..447ef1e510 100644 --- a/src/main/java/com/rabbitmq/client/LongString.java +++ b/src/main/java/com/rabbitmq/client/LongString.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/MalformedFrameException.java b/src/main/java/com/rabbitmq/client/MalformedFrameException.java index 2d63e5b961..ae799f0f5d 100644 --- a/src/main/java/com/rabbitmq/client/MalformedFrameException.java +++ b/src/main/java/com/rabbitmq/client/MalformedFrameException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/MapRpcServer.java b/src/main/java/com/rabbitmq/client/MapRpcServer.java index 2671a044cb..93ceaa10fe 100644 --- a/src/main/java/com/rabbitmq/client/MapRpcServer.java +++ b/src/main/java/com/rabbitmq/client/MapRpcServer.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/MessageProperties.java b/src/main/java/com/rabbitmq/client/MessageProperties.java index 4ba9b40e17..8369eeb645 100644 --- a/src/main/java/com/rabbitmq/client/MessageProperties.java +++ b/src/main/java/com/rabbitmq/client/MessageProperties.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/Method.java b/src/main/java/com/rabbitmq/client/Method.java index 393f64cc1b..bd7b8531e7 100644 --- a/src/main/java/com/rabbitmq/client/Method.java +++ b/src/main/java/com/rabbitmq/client/Method.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/MetricsCollector.java b/src/main/java/com/rabbitmq/client/MetricsCollector.java index 09315f8cb0..edaa64e13f 100644 --- a/src/main/java/com/rabbitmq/client/MetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/MetricsCollector.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/MissedHeartbeatException.java b/src/main/java/com/rabbitmq/client/MissedHeartbeatException.java index 90e8cdb83a..83400d2db5 100644 --- a/src/main/java/com/rabbitmq/client/MissedHeartbeatException.java +++ b/src/main/java/com/rabbitmq/client/MissedHeartbeatException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java b/src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java index 04df2ea595..f70e658aed 100644 --- a/src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/PossibleAuthenticationFailureException.java b/src/main/java/com/rabbitmq/client/PossibleAuthenticationFailureException.java index bbb053d611..d6cca886db 100644 --- a/src/main/java/com/rabbitmq/client/PossibleAuthenticationFailureException.java +++ b/src/main/java/com/rabbitmq/client/PossibleAuthenticationFailureException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ProtocolVersionMismatchException.java b/src/main/java/com/rabbitmq/client/ProtocolVersionMismatchException.java index 7b031b9621..8cd857545b 100644 --- a/src/main/java/com/rabbitmq/client/ProtocolVersionMismatchException.java +++ b/src/main/java/com/rabbitmq/client/ProtocolVersionMismatchException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/Recoverable.java b/src/main/java/com/rabbitmq/client/Recoverable.java index 50dcec5b4d..c4b066f66c 100644 --- a/src/main/java/com/rabbitmq/client/Recoverable.java +++ b/src/main/java/com/rabbitmq/client/Recoverable.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/RecoveryDelayHandler.java b/src/main/java/com/rabbitmq/client/RecoveryDelayHandler.java index 524d3c1786..e00c7d3940 100644 --- a/src/main/java/com/rabbitmq/client/RecoveryDelayHandler.java +++ b/src/main/java/com/rabbitmq/client/RecoveryDelayHandler.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/RecoveryListener.java b/src/main/java/com/rabbitmq/client/RecoveryListener.java index 2e346ae097..968b828521 100644 --- a/src/main/java/com/rabbitmq/client/RecoveryListener.java +++ b/src/main/java/com/rabbitmq/client/RecoveryListener.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/Return.java b/src/main/java/com/rabbitmq/client/Return.java index 5c78977bce..f441a69873 100644 --- a/src/main/java/com/rabbitmq/client/Return.java +++ b/src/main/java/com/rabbitmq/client/Return.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ReturnCallback.java b/src/main/java/com/rabbitmq/client/ReturnCallback.java index 0f413716e2..1eb1c99271 100644 --- a/src/main/java/com/rabbitmq/client/ReturnCallback.java +++ b/src/main/java/com/rabbitmq/client/ReturnCallback.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ReturnListener.java b/src/main/java/com/rabbitmq/client/ReturnListener.java index d5094c0d14..2ec72fbc15 100644 --- a/src/main/java/com/rabbitmq/client/ReturnListener.java +++ b/src/main/java/com/rabbitmq/client/ReturnListener.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/RpcClient.java b/src/main/java/com/rabbitmq/client/RpcClient.java index 8a5099d3e7..50b7c895c1 100644 --- a/src/main/java/com/rabbitmq/client/RpcClient.java +++ b/src/main/java/com/rabbitmq/client/RpcClient.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/RpcClientParams.java b/src/main/java/com/rabbitmq/client/RpcClientParams.java index 870756e25a..ea1ab30d87 100644 --- a/src/main/java/com/rabbitmq/client/RpcClientParams.java +++ b/src/main/java/com/rabbitmq/client/RpcClientParams.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/RpcServer.java b/src/main/java/com/rabbitmq/client/RpcServer.java index 457e5f6679..a1bc413c50 100644 --- a/src/main/java/com/rabbitmq/client/RpcServer.java +++ b/src/main/java/com/rabbitmq/client/RpcServer.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/SaslConfig.java b/src/main/java/com/rabbitmq/client/SaslConfig.java index 1db18614dc..d8555cf6b2 100644 --- a/src/main/java/com/rabbitmq/client/SaslConfig.java +++ b/src/main/java/com/rabbitmq/client/SaslConfig.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/SaslMechanism.java b/src/main/java/com/rabbitmq/client/SaslMechanism.java index a98bdcc866..d411f2072e 100644 --- a/src/main/java/com/rabbitmq/client/SaslMechanism.java +++ b/src/main/java/com/rabbitmq/client/SaslMechanism.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ShutdownListener.java b/src/main/java/com/rabbitmq/client/ShutdownListener.java index 351e0b9b9b..5a2427334f 100644 --- a/src/main/java/com/rabbitmq/client/ShutdownListener.java +++ b/src/main/java/com/rabbitmq/client/ShutdownListener.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ShutdownNotifier.java b/src/main/java/com/rabbitmq/client/ShutdownNotifier.java index 8802dcdaf9..66aa021d7a 100644 --- a/src/main/java/com/rabbitmq/client/ShutdownNotifier.java +++ b/src/main/java/com/rabbitmq/client/ShutdownNotifier.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ShutdownSignalException.java b/src/main/java/com/rabbitmq/client/ShutdownSignalException.java index 5e49720382..769158198d 100644 --- a/src/main/java/com/rabbitmq/client/ShutdownSignalException.java +++ b/src/main/java/com/rabbitmq/client/ShutdownSignalException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/SocketChannelConfigurator.java b/src/main/java/com/rabbitmq/client/SocketChannelConfigurator.java index ceb3a95a88..43307caada 100644 --- a/src/main/java/com/rabbitmq/client/SocketChannelConfigurator.java +++ b/src/main/java/com/rabbitmq/client/SocketChannelConfigurator.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/SocketChannelConfigurators.java b/src/main/java/com/rabbitmq/client/SocketChannelConfigurators.java index 566d3ddc13..0355528b4e 100644 --- a/src/main/java/com/rabbitmq/client/SocketChannelConfigurators.java +++ b/src/main/java/com/rabbitmq/client/SocketChannelConfigurators.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/SocketConfigurator.java b/src/main/java/com/rabbitmq/client/SocketConfigurator.java index 30c9ed4bab..8a49c57d96 100644 --- a/src/main/java/com/rabbitmq/client/SocketConfigurator.java +++ b/src/main/java/com/rabbitmq/client/SocketConfigurator.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/SocketConfigurators.java b/src/main/java/com/rabbitmq/client/SocketConfigurators.java index f738fe166d..dda986d36b 100644 --- a/src/main/java/com/rabbitmq/client/SocketConfigurators.java +++ b/src/main/java/com/rabbitmq/client/SocketConfigurators.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/SslContextFactory.java b/src/main/java/com/rabbitmq/client/SslContextFactory.java index 9a1fbcac6c..468c1237cd 100644 --- a/src/main/java/com/rabbitmq/client/SslContextFactory.java +++ b/src/main/java/com/rabbitmq/client/SslContextFactory.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/SslEngineConfigurator.java b/src/main/java/com/rabbitmq/client/SslEngineConfigurator.java index 01b22c4c05..6f95bb392a 100644 --- a/src/main/java/com/rabbitmq/client/SslEngineConfigurator.java +++ b/src/main/java/com/rabbitmq/client/SslEngineConfigurator.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/SslEngineConfigurators.java b/src/main/java/com/rabbitmq/client/SslEngineConfigurators.java index 44c2e16f70..0cb7b451d7 100644 --- a/src/main/java/com/rabbitmq/client/SslEngineConfigurators.java +++ b/src/main/java/com/rabbitmq/client/SslEngineConfigurators.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/StringRpcServer.java b/src/main/java/com/rabbitmq/client/StringRpcServer.java index 2f8e62bade..375079607a 100644 --- a/src/main/java/com/rabbitmq/client/StringRpcServer.java +++ b/src/main/java/com/rabbitmq/client/StringRpcServer.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/TopologyRecoveryException.java b/src/main/java/com/rabbitmq/client/TopologyRecoveryException.java index 0c2bcc1f5d..cf9d18d105 100644 --- a/src/main/java/com/rabbitmq/client/TopologyRecoveryException.java +++ b/src/main/java/com/rabbitmq/client/TopologyRecoveryException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/TrustEverythingTrustManager.java b/src/main/java/com/rabbitmq/client/TrustEverythingTrustManager.java index 544c74f1d8..9001d02507 100644 --- a/src/main/java/com/rabbitmq/client/TrustEverythingTrustManager.java +++ b/src/main/java/com/rabbitmq/client/TrustEverythingTrustManager.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/UnblockedCallback.java b/src/main/java/com/rabbitmq/client/UnblockedCallback.java index 8b3b5a6ad5..76ac083ac7 100644 --- a/src/main/java/com/rabbitmq/client/UnblockedCallback.java +++ b/src/main/java/com/rabbitmq/client/UnblockedCallback.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/UnexpectedFrameError.java b/src/main/java/com/rabbitmq/client/UnexpectedFrameError.java index 1bb425f5d8..e8275aec3a 100644 --- a/src/main/java/com/rabbitmq/client/UnexpectedFrameError.java +++ b/src/main/java/com/rabbitmq/client/UnexpectedFrameError.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/UnexpectedMethodError.java b/src/main/java/com/rabbitmq/client/UnexpectedMethodError.java index 8a14ebea87..ab30336a07 100644 --- a/src/main/java/com/rabbitmq/client/UnexpectedMethodError.java +++ b/src/main/java/com/rabbitmq/client/UnexpectedMethodError.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/UnknownClassOrMethodId.java b/src/main/java/com/rabbitmq/client/UnknownClassOrMethodId.java index 6440c8c0c9..1f0e3715f3 100644 --- a/src/main/java/com/rabbitmq/client/UnknownClassOrMethodId.java +++ b/src/main/java/com/rabbitmq/client/UnknownClassOrMethodId.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/UnroutableRpcRequestException.java b/src/main/java/com/rabbitmq/client/UnroutableRpcRequestException.java index 18ad13aa3c..89e9d059f0 100644 --- a/src/main/java/com/rabbitmq/client/UnroutableRpcRequestException.java +++ b/src/main/java/com/rabbitmq/client/UnroutableRpcRequestException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/AMQBasicProperties.java b/src/main/java/com/rabbitmq/client/impl/AMQBasicProperties.java index 35e2507b0c..591713e706 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQBasicProperties.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQBasicProperties.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java index b3ba519da8..1314d89077 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/AMQCommand.java b/src/main/java/com/rabbitmq/client/impl/AMQCommand.java index 929eaa3804..0395bb10f6 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQCommand.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQCommand.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index 6a32a37d91..28c03a847d 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 @@ -35,7 +35,7 @@ import java.util.concurrent.atomic.AtomicBoolean; final class Copyright { - final static String COPYRIGHT="Copyright (c) 2007-2020 Pivotal Software, Inc."; + final static String COPYRIGHT="Copyright (c) 2007-2020 VMware, Inc. or its affiliates."; final static String LICENSE="Licensed under the MPL. See https://www.rabbitmq.com/"; } diff --git a/src/main/java/com/rabbitmq/client/impl/AMQContentHeader.java b/src/main/java/com/rabbitmq/client/impl/AMQContentHeader.java index 97028e2376..523336e0ca 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQContentHeader.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQContentHeader.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java index b6647f13d4..5599b3a0a4 100644 --- a/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/CRDemoMechanism.java b/src/main/java/com/rabbitmq/client/impl/CRDemoMechanism.java index b61b4d0ad4..e516750b6c 100644 --- a/src/main/java/com/rabbitmq/client/impl/CRDemoMechanism.java +++ b/src/main/java/com/rabbitmq/client/impl/CRDemoMechanism.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelManager.java b/src/main/java/com/rabbitmq/client/impl/ChannelManager.java index 73b78f71b4..162c141f34 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelManager.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelManager.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java index 38d7d8e551..a3f7f5f794 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelN.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ClientVersion.java b/src/main/java/com/rabbitmq/client/impl/ClientVersion.java index 771c71d135..aae57e8a86 100644 --- a/src/main/java/com/rabbitmq/client/impl/ClientVersion.java +++ b/src/main/java/com/rabbitmq/client/impl/ClientVersion.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/CommandAssembler.java b/src/main/java/com/rabbitmq/client/impl/CommandAssembler.java index 0dbf1a25cd..1be564eb81 100644 --- a/src/main/java/com/rabbitmq/client/impl/CommandAssembler.java +++ b/src/main/java/com/rabbitmq/client/impl/CommandAssembler.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/CompletableFutureRpcWrapper.java b/src/main/java/com/rabbitmq/client/impl/CompletableFutureRpcWrapper.java index c2a3e5c649..1f1b91f569 100644 --- a/src/main/java/com/rabbitmq/client/impl/CompletableFutureRpcWrapper.java +++ b/src/main/java/com/rabbitmq/client/impl/CompletableFutureRpcWrapper.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java b/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java index 57a028783b..92428fc436 100644 --- a/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java +++ b/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ConsumerDispatcher.java b/src/main/java/com/rabbitmq/client/impl/ConsumerDispatcher.java index 91b1e7cb3b..bb22d9f626 100644 --- a/src/main/java/com/rabbitmq/client/impl/ConsumerDispatcher.java +++ b/src/main/java/com/rabbitmq/client/impl/ConsumerDispatcher.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ConsumerWorkService.java b/src/main/java/com/rabbitmq/client/impl/ConsumerWorkService.java index 128e9f07e9..bb662d98e7 100644 --- a/src/main/java/com/rabbitmq/client/impl/ConsumerWorkService.java +++ b/src/main/java/com/rabbitmq/client/impl/ConsumerWorkService.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java b/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java index ca1a13411e..d3502e9fe2 100644 --- a/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java +++ b/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java b/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java index ad6211ab6d..59440bc7e7 100644 --- a/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java +++ b/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java index 61bf56713f..abcfb6af17 100644 --- a/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/CredentialsRefreshService.java b/src/main/java/com/rabbitmq/client/impl/CredentialsRefreshService.java index 675fa8fe1b..d365053af1 100644 --- a/src/main/java/com/rabbitmq/client/impl/CredentialsRefreshService.java +++ b/src/main/java/com/rabbitmq/client/impl/CredentialsRefreshService.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java index cd58019bf6..6263524898 100644 --- a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java index d74d749a0d..2beafaad74 100644 --- a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java +++ b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/DefaultExceptionHandler.java b/src/main/java/com/rabbitmq/client/impl/DefaultExceptionHandler.java index 8183a9f296..f1a0def2f3 100644 --- a/src/main/java/com/rabbitmq/client/impl/DefaultExceptionHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/DefaultExceptionHandler.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/Environment.java b/src/main/java/com/rabbitmq/client/impl/Environment.java index 8ee8fab995..c7f6c528b0 100644 --- a/src/main/java/com/rabbitmq/client/impl/Environment.java +++ b/src/main/java/com/rabbitmq/client/impl/Environment.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ErrorOnWriteListener.java b/src/main/java/com/rabbitmq/client/impl/ErrorOnWriteListener.java index 84d493984a..7edf05e994 100644 --- a/src/main/java/com/rabbitmq/client/impl/ErrorOnWriteListener.java +++ b/src/main/java/com/rabbitmq/client/impl/ErrorOnWriteListener.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ExternalMechanism.java b/src/main/java/com/rabbitmq/client/impl/ExternalMechanism.java index 1983589dd9..5cddc69ac4 100644 --- a/src/main/java/com/rabbitmq/client/impl/ExternalMechanism.java +++ b/src/main/java/com/rabbitmq/client/impl/ExternalMechanism.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ForgivingExceptionHandler.java b/src/main/java/com/rabbitmq/client/impl/ForgivingExceptionHandler.java index a91bf86f30..e4c2648394 100644 --- a/src/main/java/com/rabbitmq/client/impl/ForgivingExceptionHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/ForgivingExceptionHandler.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/Frame.java b/src/main/java/com/rabbitmq/client/impl/Frame.java index 39a12d5eb6..12f53f7ad8 100644 --- a/src/main/java/com/rabbitmq/client/impl/Frame.java +++ b/src/main/java/com/rabbitmq/client/impl/Frame.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/FrameHandler.java b/src/main/java/com/rabbitmq/client/impl/FrameHandler.java index 91168340be..0e54b34435 100644 --- a/src/main/java/com/rabbitmq/client/impl/FrameHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/FrameHandler.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/HeartbeatSender.java b/src/main/java/com/rabbitmq/client/impl/HeartbeatSender.java index 69b2c00b83..998581d0a5 100644 --- a/src/main/java/com/rabbitmq/client/impl/HeartbeatSender.java +++ b/src/main/java/com/rabbitmq/client/impl/HeartbeatSender.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/LongStringHelper.java b/src/main/java/com/rabbitmq/client/impl/LongStringHelper.java index de5fc3c55e..d80d9a01f3 100644 --- a/src/main/java/com/rabbitmq/client/impl/LongStringHelper.java +++ b/src/main/java/com/rabbitmq/client/impl/LongStringHelper.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/Method.java b/src/main/java/com/rabbitmq/client/impl/Method.java index c89c377546..0b894416ac 100644 --- a/src/main/java/com/rabbitmq/client/impl/Method.java +++ b/src/main/java/com/rabbitmq/client/impl/Method.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/MethodArgumentReader.java b/src/main/java/com/rabbitmq/client/impl/MethodArgumentReader.java index e61ffc5380..24ab627450 100644 --- a/src/main/java/com/rabbitmq/client/impl/MethodArgumentReader.java +++ b/src/main/java/com/rabbitmq/client/impl/MethodArgumentReader.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/MethodArgumentWriter.java b/src/main/java/com/rabbitmq/client/impl/MethodArgumentWriter.java index 35ad76ab17..0782112c8e 100644 --- a/src/main/java/com/rabbitmq/client/impl/MethodArgumentWriter.java +++ b/src/main/java/com/rabbitmq/client/impl/MethodArgumentWriter.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java index d7b9d566d7..b2ba107cae 100644 --- a/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/NetworkConnection.java b/src/main/java/com/rabbitmq/client/impl/NetworkConnection.java index 281e36f892..747a1921a7 100644 --- a/src/main/java/com/rabbitmq/client/impl/NetworkConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/NetworkConnection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java index 090bcfa675..b594785742 100644 --- a/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/OAuthTokenManagementException.java b/src/main/java/com/rabbitmq/client/impl/OAuthTokenManagementException.java index 62db5e07a5..cf17053b24 100644 --- a/src/main/java/com/rabbitmq/client/impl/OAuthTokenManagementException.java +++ b/src/main/java/com/rabbitmq/client/impl/OAuthTokenManagementException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/PlainMechanism.java b/src/main/java/com/rabbitmq/client/impl/PlainMechanism.java index 7cd9aa70e8..c586385299 100644 --- a/src/main/java/com/rabbitmq/client/impl/PlainMechanism.java +++ b/src/main/java/com/rabbitmq/client/impl/PlainMechanism.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProvider.java index 21f6bc9780..a4cc01c186 100644 --- a/src/main/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProvider.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/RpcContinuationRpcWrapper.java b/src/main/java/com/rabbitmq/client/impl/RpcContinuationRpcWrapper.java index da57ffbae7..8fcf901b55 100644 --- a/src/main/java/com/rabbitmq/client/impl/RpcContinuationRpcWrapper.java +++ b/src/main/java/com/rabbitmq/client/impl/RpcContinuationRpcWrapper.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/RpcWrapper.java b/src/main/java/com/rabbitmq/client/impl/RpcWrapper.java index f504908394..84c3bb0363 100644 --- a/src/main/java/com/rabbitmq/client/impl/RpcWrapper.java +++ b/src/main/java/com/rabbitmq/client/impl/RpcWrapper.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/SetQueue.java b/src/main/java/com/rabbitmq/client/impl/SetQueue.java index 0ad6e86ba9..9ab2cd3526 100644 --- a/src/main/java/com/rabbitmq/client/impl/SetQueue.java +++ b/src/main/java/com/rabbitmq/client/impl/SetQueue.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ShutdownNotifierComponent.java b/src/main/java/com/rabbitmq/client/impl/ShutdownNotifierComponent.java index a8d2a9be93..0ee95e083c 100644 --- a/src/main/java/com/rabbitmq/client/impl/ShutdownNotifierComponent.java +++ b/src/main/java/com/rabbitmq/client/impl/ShutdownNotifierComponent.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java b/src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java index 02cc9a2d2d..8d1d2eee15 100644 --- a/src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/SocketFrameHandlerFactory.java b/src/main/java/com/rabbitmq/client/impl/SocketFrameHandlerFactory.java index 687f90d4fd..0391b31297 100644 --- a/src/main/java/com/rabbitmq/client/impl/SocketFrameHandlerFactory.java +++ b/src/main/java/com/rabbitmq/client/impl/SocketFrameHandlerFactory.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java index 29240bcc48..63876de058 100644 --- a/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/StrictExceptionHandler.java b/src/main/java/com/rabbitmq/client/impl/StrictExceptionHandler.java index dac47024af..d1f54768b0 100644 --- a/src/main/java/com/rabbitmq/client/impl/StrictExceptionHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/StrictExceptionHandler.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/TlsUtils.java b/src/main/java/com/rabbitmq/client/impl/TlsUtils.java index 938c1ad9d4..5b4290f79c 100644 --- a/src/main/java/com/rabbitmq/client/impl/TlsUtils.java +++ b/src/main/java/com/rabbitmq/client/impl/TlsUtils.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/TruncatedInputStream.java b/src/main/java/com/rabbitmq/client/impl/TruncatedInputStream.java index 0df6d3c492..a572952af8 100644 --- a/src/main/java/com/rabbitmq/client/impl/TruncatedInputStream.java +++ b/src/main/java/com/rabbitmq/client/impl/TruncatedInputStream.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/UnknownChannelException.java b/src/main/java/com/rabbitmq/client/impl/UnknownChannelException.java index 1bf87a0d8f..5e9474c5a9 100644 --- a/src/main/java/com/rabbitmq/client/impl/UnknownChannelException.java +++ b/src/main/java/com/rabbitmq/client/impl/UnknownChannelException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/UpdateSecretExtension.java b/src/main/java/com/rabbitmq/client/impl/UpdateSecretExtension.java index b54b90635c..5edd65813c 100644 --- a/src/main/java/com/rabbitmq/client/impl/UpdateSecretExtension.java +++ b/src/main/java/com/rabbitmq/client/impl/UpdateSecretExtension.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ValueReader.java b/src/main/java/com/rabbitmq/client/impl/ValueReader.java index 32cf9a3732..9611324f3a 100644 --- a/src/main/java/com/rabbitmq/client/impl/ValueReader.java +++ b/src/main/java/com/rabbitmq/client/impl/ValueReader.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ValueWriter.java b/src/main/java/com/rabbitmq/client/impl/ValueWriter.java index 7340cbd718..e6167cec7e 100644 --- a/src/main/java/com/rabbitmq/client/impl/ValueWriter.java +++ b/src/main/java/com/rabbitmq/client/impl/ValueWriter.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java b/src/main/java/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java index 33b4303294..7cff31c0ec 100644 --- a/src/main/java/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java +++ b/src/main/java/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/Version.java b/src/main/java/com/rabbitmq/client/impl/Version.java index addb073176..109359fe3d 100644 --- a/src/main/java/com/rabbitmq/client/impl/Version.java +++ b/src/main/java/com/rabbitmq/client/impl/Version.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/WorkPool.java b/src/main/java/com/rabbitmq/client/impl/WorkPool.java index dfccd33acf..39b8b743b7 100644 --- a/src/main/java/com/rabbitmq/client/impl/WorkPool.java +++ b/src/main/java/com/rabbitmq/client/impl/WorkPool.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/WorkPoolFullException.java b/src/main/java/com/rabbitmq/client/impl/WorkPoolFullException.java index 146d05f414..eba1fe14cf 100644 --- a/src/main/java/com/rabbitmq/client/impl/WorkPoolFullException.java +++ b/src/main/java/com/rabbitmq/client/impl/WorkPoolFullException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/ByteBufferOutputStream.java b/src/main/java/com/rabbitmq/client/impl/nio/ByteBufferOutputStream.java index a8b951b56a..16fe3f2682 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/ByteBufferOutputStream.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/ByteBufferOutputStream.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java b/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java index 770bca63b6..9ffcd29e65 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/FrameWriteRequest.java b/src/main/java/com/rabbitmq/client/impl/nio/FrameWriteRequest.java index 570fa24e5c..33a5ba5b74 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/FrameWriteRequest.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/FrameWriteRequest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/HeaderWriteRequest.java b/src/main/java/com/rabbitmq/client/impl/nio/HeaderWriteRequest.java index 96e35849e4..79e34359c3 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/HeaderWriteRequest.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/HeaderWriteRequest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioHelper.java b/src/main/java/com/rabbitmq/client/impl/nio/NioHelper.java index 277025222f..3438013c1f 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioHelper.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioHelper.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java b/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java index e153e721c8..f194eeef42 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioLoopContext.java b/src/main/java/com/rabbitmq/client/impl/nio/NioLoopContext.java index a74a99f5a2..47639cfc35 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioLoopContext.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioLoopContext.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java b/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java index 2f70cb1fe7..e4bb78de23 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SelectorHolder.java b/src/main/java/com/rabbitmq/client/impl/nio/SelectorHolder.java index 8542e52cb1..7426280acb 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SelectorHolder.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SelectorHolder.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandler.java b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandler.java index 8e9bab5dc5..d46ce4e0bb 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandler.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java index 784a5f80cd..f4473b8ae3 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java index bea18489c7..b5822fcd91 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelRegistration.java b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelRegistration.java index e09dee9010..2befb3d3a6 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelRegistration.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelRegistration.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferOutputStream.java b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferOutputStream.java index 11145eae1e..8ec782613d 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferOutputStream.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferOutputStream.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineFrameBuilder.java b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineFrameBuilder.java index 056470aae4..141bb47293 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineFrameBuilder.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineFrameBuilder.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java index c4b8a33c26..0de786c7b3 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/WriteRequest.java b/src/main/java/com/rabbitmq/client/impl/nio/WriteRequest.java index 635c8bc426..b696bc421f 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/WriteRequest.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/WriteRequest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java index e74170d247..969fb45593 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index 379961971c..f04e3778d5 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/BackoffPolicy.java b/src/main/java/com/rabbitmq/client/impl/recovery/BackoffPolicy.java index a05c2a8a3c..6ed2a2deef 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/BackoffPolicy.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/BackoffPolicy.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/ConsumerRecoveryListener.java b/src/main/java/com/rabbitmq/client/impl/recovery/ConsumerRecoveryListener.java index 1018f9a332..291528af3e 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/ConsumerRecoveryListener.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/ConsumerRecoveryListener.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java b/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java index ec9a86cbc8..1fa64afa4e 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/QueueRecoveryListener.java b/src/main/java/com/rabbitmq/client/impl/recovery/QueueRecoveryListener.java index ca3d518685..55eef2d9f1 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/QueueRecoveryListener.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/QueueRecoveryListener.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedBinding.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedBinding.java index 4b144ae00b..2cdf188ed7 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedBinding.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedBinding.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedConsumer.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedConsumer.java index 1eb9c7a943..4aa87a2d0b 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedConsumer.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedConsumer.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedEntity.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedEntity.java index b92dd6028b..c55a398563 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedEntity.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedEntity.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchange.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchange.java index 2884604fdc..d75530fad6 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchange.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchange.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchangeBinding.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchangeBinding.java index 3b6d72881d..286b793185 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchangeBinding.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchangeBinding.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedNamedEntity.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedNamedEntity.java index 7bb2e43514..b00a9c2df4 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedNamedEntity.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedNamedEntity.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java index f446e1682c..6cb43cfdae 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java index a933ce3acd..09d2636d32 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnection.java index b50e7027e5..94768de1db 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java index 3b326a76bf..01a172fac3 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelManager.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelManager.java index aed1cffc05..b9daf354f2 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelManager.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelManager.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java index c3cc81bed6..5373b6877f 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryCanBeginListener.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryCanBeginListener.java index fc21af6bc6..2c272198b4 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryCanBeginListener.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryCanBeginListener.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RetryContext.java b/src/main/java/com/rabbitmq/client/impl/recovery/RetryContext.java index a9bdc05e5f..60645e199a 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RetryContext.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RetryContext.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RetryHandler.java b/src/main/java/com/rabbitmq/client/impl/recovery/RetryHandler.java index 5ed7f823f0..459ca80080 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RetryHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RetryHandler.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RetryResult.java b/src/main/java/com/rabbitmq/client/impl/recovery/RetryResult.java index c4797c39bf..6c4e693314 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RetryResult.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RetryResult.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryFilter.java b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryFilter.java index d5f0ec9a26..835249ec55 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryFilter.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryFilter.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryHandlerBuilder.java b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryHandlerBuilder.java index 887a494bc5..c2ad1078d5 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryHandlerBuilder.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryHandlerBuilder.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java index 26db1f27a8..8daa2ac33e 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/tools/json/JSONUtil.java b/src/main/java/com/rabbitmq/tools/json/JSONUtil.java index c024e142c8..f814462e5e 100644 --- a/src/main/java/com/rabbitmq/tools/json/JSONUtil.java +++ b/src/main/java/com/rabbitmq/tools/json/JSONUtil.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java index 6c1775cf8c..8b239eed5b 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java index 88f3939fef..16a938711c 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java index 18c0e93b84..c46b95c259 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java index fdad5e1960..6e311dc6e4 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMappingException.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMappingException.java index 03a7d12b91..6a764e6960 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMappingException.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMappingException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java index e0b8373fd4..f5ca1990e2 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/ParameterDescription.java b/src/main/java/com/rabbitmq/tools/jsonrpc/ParameterDescription.java index 97fb9d0d01..6106cbf60c 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/ParameterDescription.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/ParameterDescription.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java b/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java index db637d1c38..44ac3a0b76 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java b/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java index a42a1b2f1d..af2029d98c 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/utility/BlockingCell.java b/src/main/java/com/rabbitmq/utility/BlockingCell.java index 7fc8ec5641..9f9dce24a4 100644 --- a/src/main/java/com/rabbitmq/utility/BlockingCell.java +++ b/src/main/java/com/rabbitmq/utility/BlockingCell.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/utility/BlockingValueOrException.java b/src/main/java/com/rabbitmq/utility/BlockingValueOrException.java index 683358c206..77df219b72 100644 --- a/src/main/java/com/rabbitmq/utility/BlockingValueOrException.java +++ b/src/main/java/com/rabbitmq/utility/BlockingValueOrException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/utility/IntAllocator.java b/src/main/java/com/rabbitmq/utility/IntAllocator.java index 6032a4dcc8..9c1e93cd1f 100644 --- a/src/main/java/com/rabbitmq/utility/IntAllocator.java +++ b/src/main/java/com/rabbitmq/utility/IntAllocator.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/utility/SensibleClone.java b/src/main/java/com/rabbitmq/utility/SensibleClone.java index 01f51b4f21..50405ec0eb 100644 --- a/src/main/java/com/rabbitmq/utility/SensibleClone.java +++ b/src/main/java/com/rabbitmq/utility/SensibleClone.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/utility/Utility.java b/src/main/java/com/rabbitmq/utility/Utility.java index 23e4c56bf3..805e02835c 100644 --- a/src/main/java/com/rabbitmq/utility/Utility.java +++ b/src/main/java/com/rabbitmq/utility/Utility.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/utility/ValueOrException.java b/src/main/java/com/rabbitmq/utility/ValueOrException.java index d882b28430..7be45ef8a2 100644 --- a/src/main/java/com/rabbitmq/utility/ValueOrException.java +++ b/src/main/java/com/rabbitmq/utility/ValueOrException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/AbstractJsonRpcTest.java b/src/test/java/com/rabbitmq/client/AbstractJsonRpcTest.java index e9ec771bd7..017cb6e308 100644 --- a/src/test/java/com/rabbitmq/client/AbstractJsonRpcTest.java +++ b/src/test/java/com/rabbitmq/client/AbstractJsonRpcTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/JacksonJsonRpcTest.java b/src/test/java/com/rabbitmq/client/JacksonJsonRpcTest.java index 091ce44680..af9b827810 100644 --- a/src/test/java/com/rabbitmq/client/JacksonJsonRpcTest.java +++ b/src/test/java/com/rabbitmq/client/JacksonJsonRpcTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/QueueingConsumer.java b/src/test/java/com/rabbitmq/client/QueueingConsumer.java index e803720e42..434e7a8d82 100644 --- a/src/test/java/com/rabbitmq/client/QueueingConsumer.java +++ b/src/test/java/com/rabbitmq/client/QueueingConsumer.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/impl/AMQConnectionRefreshCredentialsTest.java b/src/test/java/com/rabbitmq/client/impl/AMQConnectionRefreshCredentialsTest.java index 6293b39a1c..50493bcbd0 100644 --- a/src/test/java/com/rabbitmq/client/impl/AMQConnectionRefreshCredentialsTest.java +++ b/src/test/java/com/rabbitmq/client/impl/AMQConnectionRefreshCredentialsTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java b/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java index 7009319b9c..21faa59b15 100644 --- a/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java +++ b/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java b/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java index e1d1c5abbf..d81722779d 100644 --- a/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java +++ b/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProviderTest.java b/src/test/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProviderTest.java index a96c757e59..d273b3e70b 100644 --- a/src/test/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProviderTest.java +++ b/src/test/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProviderTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java b/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java index 76cbd0d6df..ead66ee8ad 100644 --- a/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java +++ b/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java b/src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java index fec748d205..30141ef9f0 100644 --- a/src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java +++ b/src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/AMQBuilderApiTest.java b/src/test/java/com/rabbitmq/client/test/AMQBuilderApiTest.java index 27a3f5b304..9d6fb50abb 100644 --- a/src/test/java/com/rabbitmq/client/test/AMQBuilderApiTest.java +++ b/src/test/java/com/rabbitmq/client/test/AMQBuilderApiTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/AMQChannelTest.java b/src/test/java/com/rabbitmq/client/test/AMQChannelTest.java index 04554f4aa5..cb5f65d4fb 100644 --- a/src/test/java/com/rabbitmq/client/test/AMQChannelTest.java +++ b/src/test/java/com/rabbitmq/client/test/AMQChannelTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java b/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java index ece2e42e05..c278b4cc13 100644 --- a/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java +++ b/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java b/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java index cb27d22e7c..70fdbaaa6e 100644 --- a/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java +++ b/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/AddressTest.java b/src/test/java/com/rabbitmq/client/test/AddressTest.java index a67bd96c86..ca714b146b 100644 --- a/src/test/java/com/rabbitmq/client/test/AddressTest.java +++ b/src/test/java/com/rabbitmq/client/test/AddressTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java b/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java index 11cd5bf248..9b4b467f9c 100644 --- a/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java +++ b/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/BlockingCellTest.java b/src/test/java/com/rabbitmq/client/test/BlockingCellTest.java index 83cc168694..7c4ef998b0 100644 --- a/src/test/java/com/rabbitmq/client/test/BlockingCellTest.java +++ b/src/test/java/com/rabbitmq/client/test/BlockingCellTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java b/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java index 6073c4b9f0..027a20cd35 100644 --- a/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java +++ b/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java index 2608c0ca2e..cda8d3ca44 100644 --- a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java +++ b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/Bug20004Test.java b/src/test/java/com/rabbitmq/client/test/Bug20004Test.java index 58581f076f..ac62af0095 100644 --- a/src/test/java/com/rabbitmq/client/test/Bug20004Test.java +++ b/src/test/java/com/rabbitmq/client/test/Bug20004Test.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ChannelAsyncCompletableFutureTest.java b/src/test/java/com/rabbitmq/client/test/ChannelAsyncCompletableFutureTest.java index c6e51f777f..cc1141d116 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelAsyncCompletableFutureTest.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelAsyncCompletableFutureTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ChannelNTest.java b/src/test/java/com/rabbitmq/client/test/ChannelNTest.java index 6f9056174f..34346366c8 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelNTest.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelNTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ChannelNumberAllocationTests.java b/src/test/java/com/rabbitmq/client/test/ChannelNumberAllocationTests.java index 93329ab822..a3ec4b81f7 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelNumberAllocationTests.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelNumberAllocationTests.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java b/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java index 875d608d96..87494900a6 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index 34e9436c3d..02a0aebadb 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ClientVersionTest.java b/src/test/java/com/rabbitmq/client/test/ClientVersionTest.java index 33b15a956b..3c36dd7015 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientVersionTest.java +++ b/src/test/java/com/rabbitmq/client/test/ClientVersionTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ClonePropertiesTest.java b/src/test/java/com/rabbitmq/client/test/ClonePropertiesTest.java index 153095ee01..6e50f31e29 100644 --- a/src/test/java/com/rabbitmq/client/test/ClonePropertiesTest.java +++ b/src/test/java/com/rabbitmq/client/test/ClonePropertiesTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/CloseInMainLoop.java b/src/test/java/com/rabbitmq/client/test/CloseInMainLoop.java index 623ce9a516..109f8200aa 100644 --- a/src/test/java/com/rabbitmq/client/test/CloseInMainLoop.java +++ b/src/test/java/com/rabbitmq/client/test/CloseInMainLoop.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ConfirmBase.java b/src/test/java/com/rabbitmq/client/test/ConfirmBase.java index 099f8e8d04..2421bfed40 100644 --- a/src/test/java/com/rabbitmq/client/test/ConfirmBase.java +++ b/src/test/java/com/rabbitmq/client/test/ConfirmBase.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java b/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java index 5ccb855fd4..f77cee0a7e 100644 --- a/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java +++ b/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ConnectionTest.java b/src/test/java/com/rabbitmq/client/test/ConnectionTest.java index 85dc789130..cef3e68a18 100644 --- a/src/test/java/com/rabbitmq/client/test/ConnectionTest.java +++ b/src/test/java/com/rabbitmq/client/test/ConnectionTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/DefaultRetryHandlerTest.java b/src/test/java/com/rabbitmq/client/test/DefaultRetryHandlerTest.java index cc105304a7..c6fe244c51 100644 --- a/src/test/java/com/rabbitmq/client/test/DefaultRetryHandlerTest.java +++ b/src/test/java/com/rabbitmq/client/test/DefaultRetryHandlerTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/DnsSrvRecordAddressResolverTest.java b/src/test/java/com/rabbitmq/client/test/DnsSrvRecordAddressResolverTest.java index 82bdea47de..886aa1f533 100644 --- a/src/test/java/com/rabbitmq/client/test/DnsSrvRecordAddressResolverTest.java +++ b/src/test/java/com/rabbitmq/client/test/DnsSrvRecordAddressResolverTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java b/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java index 3ed9f8596e..64605aaea6 100644 --- a/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java +++ b/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/GeneratedClassesTest.java b/src/test/java/com/rabbitmq/client/test/GeneratedClassesTest.java index e9dbcfca98..c144e7e3d3 100644 --- a/src/test/java/com/rabbitmq/client/test/GeneratedClassesTest.java +++ b/src/test/java/com/rabbitmq/client/test/GeneratedClassesTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/LambdaCallbackTest.java b/src/test/java/com/rabbitmq/client/test/LambdaCallbackTest.java index 571824a73a..29505b73ab 100644 --- a/src/test/java/com/rabbitmq/client/test/LambdaCallbackTest.java +++ b/src/test/java/com/rabbitmq/client/test/LambdaCallbackTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/LongStringTest.java b/src/test/java/com/rabbitmq/client/test/LongStringTest.java index df04cddd51..59f9556e2c 100644 --- a/src/test/java/com/rabbitmq/client/test/LongStringTest.java +++ b/src/test/java/com/rabbitmq/client/test/LongStringTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java b/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java index 9b2c8604dc..46a3569dd9 100644 --- a/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java +++ b/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/MicrometerMetricsCollectorTest.java b/src/test/java/com/rabbitmq/client/test/MicrometerMetricsCollectorTest.java index b84c956852..5cc8aa6178 100644 --- a/src/test/java/com/rabbitmq/client/test/MicrometerMetricsCollectorTest.java +++ b/src/test/java/com/rabbitmq/client/test/MicrometerMetricsCollectorTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/MultiThreadedChannel.java b/src/test/java/com/rabbitmq/client/test/MultiThreadedChannel.java index d583a03b4a..4790016a40 100644 --- a/src/test/java/com/rabbitmq/client/test/MultiThreadedChannel.java +++ b/src/test/java/com/rabbitmq/client/test/MultiThreadedChannel.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/NioDeadlockOnConnectionClosing.java b/src/test/java/com/rabbitmq/client/test/NioDeadlockOnConnectionClosing.java index 78082344b1..c9e1607653 100644 --- a/src/test/java/com/rabbitmq/client/test/NioDeadlockOnConnectionClosing.java +++ b/src/test/java/com/rabbitmq/client/test/NioDeadlockOnConnectionClosing.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java b/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java index 1047dc4287..5014bcda2f 100644 --- a/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java +++ b/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java b/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java index 34b6a63054..3d6099e12c 100644 --- a/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java +++ b/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/QueueingConsumerTests.java b/src/test/java/com/rabbitmq/client/test/QueueingConsumerTests.java index cf5114faef..01676ade92 100644 --- a/src/test/java/com/rabbitmq/client/test/QueueingConsumerTests.java +++ b/src/test/java/com/rabbitmq/client/test/QueueingConsumerTests.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/RecoveryAwareAMQConnectionFactoryTest.java b/src/test/java/com/rabbitmq/client/test/RecoveryAwareAMQConnectionFactoryTest.java index 704c252bc0..f09721a036 100644 --- a/src/test/java/com/rabbitmq/client/test/RecoveryAwareAMQConnectionFactoryTest.java +++ b/src/test/java/com/rabbitmq/client/test/RecoveryAwareAMQConnectionFactoryTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/RecoveryDelayHandlerTest.java b/src/test/java/com/rabbitmq/client/test/RecoveryDelayHandlerTest.java index 1b988251f3..7828b5eefe 100644 --- a/src/test/java/com/rabbitmq/client/test/RecoveryDelayHandlerTest.java +++ b/src/test/java/com/rabbitmq/client/test/RecoveryDelayHandlerTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java b/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java index defa0c4b4f..b72c95ee1d 100644 --- a/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java +++ b/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/RpcTest.java b/src/test/java/com/rabbitmq/client/test/RpcTest.java index 027c1e081a..87d0be518b 100644 --- a/src/test/java/com/rabbitmq/client/test/RpcTest.java +++ b/src/test/java/com/rabbitmq/client/test/RpcTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/RpcTopologyRecordingTest.java b/src/test/java/com/rabbitmq/client/test/RpcTopologyRecordingTest.java index 47c56b9953..1f0f023018 100644 --- a/src/test/java/com/rabbitmq/client/test/RpcTopologyRecordingTest.java +++ b/src/test/java/com/rabbitmq/client/test/RpcTopologyRecordingTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java b/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java index 15d7749a37..a1fe0175f5 100644 --- a/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java +++ b/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/SslContextFactoryTest.java b/src/test/java/com/rabbitmq/client/test/SslContextFactoryTest.java index ed930c111e..4f591221ce 100644 --- a/src/test/java/com/rabbitmq/client/test/SslContextFactoryTest.java +++ b/src/test/java/com/rabbitmq/client/test/SslContextFactoryTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/StrictExceptionHandlerTest.java b/src/test/java/com/rabbitmq/client/test/StrictExceptionHandlerTest.java index 3b09ede84b..300d8ad053 100644 --- a/src/test/java/com/rabbitmq/client/test/StrictExceptionHandlerTest.java +++ b/src/test/java/com/rabbitmq/client/test/StrictExceptionHandlerTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/TableTest.java b/src/test/java/com/rabbitmq/client/test/TableTest.java index 630c7fc34d..e750301413 100644 --- a/src/test/java/com/rabbitmq/client/test/TableTest.java +++ b/src/test/java/com/rabbitmq/client/test/TableTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/TestUtils.java b/src/test/java/com/rabbitmq/client/test/TestUtils.java index 57d80db95c..012882d3f4 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtils.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtils.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/TestUtilsTest.java b/src/test/java/com/rabbitmq/client/test/TestUtilsTest.java index 00374f3a4e..1de1fe975a 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtilsTest.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtilsTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/TlsUtilsTest.java b/src/test/java/com/rabbitmq/client/test/TlsUtilsTest.java index e632e47282..078989ca12 100644 --- a/src/test/java/com/rabbitmq/client/test/TlsUtilsTest.java +++ b/src/test/java/com/rabbitmq/client/test/TlsUtilsTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/TrafficListenerTest.java b/src/test/java/com/rabbitmq/client/test/TrafficListenerTest.java index d860678d98..69c223cf31 100644 --- a/src/test/java/com/rabbitmq/client/test/TrafficListenerTest.java +++ b/src/test/java/com/rabbitmq/client/test/TrafficListenerTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/TruncatedInputStreamTest.java b/src/test/java/com/rabbitmq/client/test/TruncatedInputStreamTest.java index 4409798a17..570f15c848 100644 --- a/src/test/java/com/rabbitmq/client/test/TruncatedInputStreamTest.java +++ b/src/test/java/com/rabbitmq/client/test/TruncatedInputStreamTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ValueOrExceptionTest.java b/src/test/java/com/rabbitmq/client/test/ValueOrExceptionTest.java index de58c84aba..789dccfa29 100644 --- a/src/test/java/com/rabbitmq/client/test/ValueOrExceptionTest.java +++ b/src/test/java/com/rabbitmq/client/test/ValueOrExceptionTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/AbstractRejectTest.java b/src/test/java/com/rabbitmq/client/test/functional/AbstractRejectTest.java index 9d58d590de..470418c384 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/AbstractRejectTest.java +++ b/src/test/java/com/rabbitmq/client/test/functional/AbstractRejectTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/AlternateExchange.java b/src/test/java/com/rabbitmq/client/test/functional/AlternateExchange.java index 242e95032b..fc620a5034 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/AlternateExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/AlternateExchange.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/BasicGet.java b/src/test/java/com/rabbitmq/client/test/functional/BasicGet.java index dddd17e8d6..1e854ec495 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/BasicGet.java +++ b/src/test/java/com/rabbitmq/client/test/functional/BasicGet.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java b/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java index 0223c4c878..48c82a22ad 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java +++ b/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycleBase.java b/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycleBase.java index bb5f24c634..ae21a981f5 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycleBase.java +++ b/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycleBase.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java b/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java index 7e02faae15..4782459840 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java +++ b/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java b/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java index 6d1b430cf9..c3ae467c4f 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/Confirm.java b/src/test/java/com/rabbitmq/client/test/functional/Confirm.java index 3e66e18f15..9f0860b820 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Confirm.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Confirm.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionOpen.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionOpen.java index 91b6f18ba9..9f99ba1797 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionOpen.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionOpen.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java index 04cf8b04d2..486e5448ce 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java b/src/test/java/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java index fdda32ea18..082725531b 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConsumerCount.java b/src/test/java/com/rabbitmq/client/test/functional/ConsumerCount.java index e4230d9f92..73f91a5e10 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConsumerCount.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConsumerCount.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConsumerPriorities.java b/src/test/java/com/rabbitmq/client/test/functional/ConsumerPriorities.java index 7193decee2..a3eebd85bb 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConsumerPriorities.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConsumerPriorities.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java index 6a7f97725e..fa6124ce16 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/DefaultExchange.java b/src/test/java/com/rabbitmq/client/test/functional/DefaultExchange.java index fb27da6391..df2ceb5fdd 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DefaultExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DefaultExchange.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/DirectReplyTo.java b/src/test/java/com/rabbitmq/client/test/functional/DirectReplyTo.java index 1573c5f4c4..c8d1befec1 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DirectReplyTo.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DirectReplyTo.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/DoubleDeletion.java b/src/test/java/com/rabbitmq/client/test/functional/DoubleDeletion.java index 305b152fab..20b87d7312 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DoubleDeletion.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DoubleDeletion.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/DurableOnTransient.java b/src/test/java/com/rabbitmq/client/test/functional/DurableOnTransient.java index adb11c9bf3..dc9f5d5155 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DurableOnTransient.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DurableOnTransient.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExceptionHandling.java b/src/test/java/com/rabbitmq/client/test/functional/ExceptionHandling.java index f0c22e90f6..f0c73fcd17 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExceptionHandling.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExceptionHandling.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExceptionMessages.java b/src/test/java/com/rabbitmq/client/test/functional/ExceptionMessages.java index 88b53a8b9a..d2810dcb94 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExceptionMessages.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExceptionMessages.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java index 2eeef91572..5578560302 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java index dab4ebd080..ec763486f0 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeletePredeclared.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeletePredeclared.java index 0b1cf6969b..ee25ca6232 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeletePredeclared.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeletePredeclared.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java index 0e8bfcd92a..f2f3916ca5 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java index 739da0c71a..b3ed2f5a3a 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java index baf7a1ce6a..15f63fbd48 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java b/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java index 303d01e00d..ac1e98e7e6 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java +++ b/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java b/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java index 1e28fa27ba..27083cd048 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java +++ b/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java b/src/test/java/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java index ac28b3ed68..2ff1a36781 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java +++ b/src/test/java/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java b/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java index 14c58c60a0..b4f9c9b756 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/InternalExchange.java b/src/test/java/com/rabbitmq/client/test/functional/InternalExchange.java index 97b34bfdba..cfb705b06b 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/InternalExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/InternalExchange.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/InvalidAcks.java b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcks.java index b869378d50..dff81c600b 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/InvalidAcks.java +++ b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcks.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksBase.java b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksBase.java index e71404a268..025954022f 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksBase.java +++ b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksBase.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksTx.java b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksTx.java index 388c7ee414..635929bb4b 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksTx.java +++ b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksTx.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/MessageCount.java b/src/test/java/com/rabbitmq/client/test/functional/MessageCount.java index 9820e6aa68..a8d302a55a 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/MessageCount.java +++ b/src/test/java/com/rabbitmq/client/test/functional/MessageCount.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java index a39770f125..98b82ed7af 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/Nack.java b/src/test/java/com/rabbitmq/client/test/functional/Nack.java index 65057cb363..5b39638d78 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Nack.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Nack.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java b/src/test/java/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java index c7b220e660..829cf3d25f 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java +++ b/src/test/java/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/Nowait.java b/src/test/java/com/rabbitmq/client/test/functional/Nowait.java index b6c03cb593..af79b0d195 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Nowait.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Nowait.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java b/src/test/java/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java index 31dd63f3a0..16a1cfdf95 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java +++ b/src/test/java/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/PerMessageTTL.java b/src/test/java/com/rabbitmq/client/test/functional/PerMessageTTL.java index 00a3adc98d..0b25fbe699 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/PerMessageTTL.java +++ b/src/test/java/com/rabbitmq/client/test/functional/PerMessageTTL.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/PerQueueTTL.java b/src/test/java/com/rabbitmq/client/test/functional/PerQueueTTL.java index 8a221e2bb6..55c44e6cb3 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/PerQueueTTL.java +++ b/src/test/java/com/rabbitmq/client/test/functional/PerQueueTTL.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java b/src/test/java/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java index b586c98c5d..f4c9914bda 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java +++ b/src/test/java/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/Policies.java b/src/test/java/com/rabbitmq/client/test/functional/Policies.java index f1dba4d33d..8f86294766 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Policies.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Policies.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/QosTests.java b/src/test/java/com/rabbitmq/client/test/functional/QosTests.java index 637df3c894..1634741a83 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QosTests.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QosTests.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/QueueExclusivity.java b/src/test/java/com/rabbitmq/client/test/functional/QueueExclusivity.java index 5d7f84663a..3351b1d1a6 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QueueExclusivity.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QueueExclusivity.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/QueueLease.java b/src/test/java/com/rabbitmq/client/test/functional/QueueLease.java index b5ab03a48d..3ec1986792 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QueueLease.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QueueLease.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java b/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java index 77c5e6df92..c082a91c41 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/QueueSizeLimit.java b/src/test/java/com/rabbitmq/client/test/functional/QueueSizeLimit.java index 7bec3e47c2..fd4c26343e 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QueueSizeLimit.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QueueSizeLimit.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/Recover.java b/src/test/java/com/rabbitmq/client/test/functional/Recover.java index 0d764cc6b1..654846648f 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Recover.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Recover.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/Reject.java b/src/test/java/com/rabbitmq/client/test/functional/Reject.java index 0a99111137..11f3d52d37 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Reject.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Reject.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java index c9e44830c3..6b1eb781a0 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java +++ b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/RequeueOnClose.java b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnClose.java index 35150997a8..1900f97218 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/RequeueOnClose.java +++ b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnClose.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java index 8f36f0e2b6..6af8d01dd2 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java +++ b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/Routing.java b/src/test/java/com/rabbitmq/client/test/functional/Routing.java index f4efdab194..cfaf9eb38b 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Routing.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Routing.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/SaslMechanisms.java b/src/test/java/com/rabbitmq/client/test/functional/SaslMechanisms.java index d4dcf9130d..1d769f8a10 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/SaslMechanisms.java +++ b/src/test/java/com/rabbitmq/client/test/functional/SaslMechanisms.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/TTLHandling.java b/src/test/java/com/rabbitmq/client/test/functional/TTLHandling.java index 40719510fa..26d501e35f 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/TTLHandling.java +++ b/src/test/java/com/rabbitmq/client/test/functional/TTLHandling.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/Tables.java b/src/test/java/com/rabbitmq/client/test/functional/Tables.java index 009d8c827e..ad631596e9 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Tables.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Tables.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java index 3eb9687eea..e8c3ff1148 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java +++ b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java index f6dc2ac5ae..215645fcaf 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java +++ b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/Transactions.java b/src/test/java/com/rabbitmq/client/test/functional/Transactions.java index ff677dde35..25fb8410c5 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Transactions.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Transactions.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java b/src/test/java/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java index cb9491a6e7..fcafc73ebb 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java b/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java index 80c5bce1e9..04d105b81e 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java +++ b/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/UserIDHeader.java b/src/test/java/com/rabbitmq/client/test/functional/UserIDHeader.java index 7d64fee7a7..17db1bc8a8 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/UserIDHeader.java +++ b/src/test/java/com/rabbitmq/client/test/functional/UserIDHeader.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java b/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java index 83c1be3454..886820c094 100644 --- a/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java +++ b/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java b/src/test/java/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java index 213240039d..fbc019b263 100644 --- a/src/test/java/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java +++ b/src/test/java/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java b/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java index 61a84ae731..30e07d3a2c 100644 --- a/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/Bug19219Test.java b/src/test/java/com/rabbitmq/client/test/server/Bug19219Test.java index f048252728..7f48b7aeb4 100644 --- a/src/test/java/com/rabbitmq/client/test/server/Bug19219Test.java +++ b/src/test/java/com/rabbitmq/client/test/server/Bug19219Test.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java b/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java index f6500b0677..cd8a99ed34 100644 --- a/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java +++ b/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java b/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java index c6c4e85c91..8ee7169797 100644 --- a/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java +++ b/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java b/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java index 388a3ce7a5..a8c4ff6b8d 100644 --- a/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java +++ b/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java b/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java index cea5f368a1..0aa40943fe 100644 --- a/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java +++ b/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java b/src/test/java/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java index 57cb457087..7d931f12cf 100644 --- a/src/test/java/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java +++ b/src/test/java/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/Firehose.java b/src/test/java/com/rabbitmq/client/test/server/Firehose.java index c1c95ab8a4..56b0cdcb10 100644 --- a/src/test/java/com/rabbitmq/client/test/server/Firehose.java +++ b/src/test/java/com/rabbitmq/client/test/server/Firehose.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/HATests.java b/src/test/java/com/rabbitmq/client/test/server/HATests.java index 17b8ad1351..8918098f5d 100644 --- a/src/test/java/com/rabbitmq/client/test/server/HATests.java +++ b/src/test/java/com/rabbitmq/client/test/server/HATests.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/LoopbackUsers.java b/src/test/java/com/rabbitmq/client/test/server/LoopbackUsers.java index a7ddad4560..d9b7be93b1 100644 --- a/src/test/java/com/rabbitmq/client/test/server/LoopbackUsers.java +++ b/src/test/java/com/rabbitmq/client/test/server/LoopbackUsers.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java b/src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java index 76a092d868..b664e7b62e 100644 --- a/src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java +++ b/src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java b/src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java index 71df04dce5..4080fdce8c 100644 --- a/src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/Permissions.java b/src/test/java/com/rabbitmq/client/test/server/Permissions.java index 233b85e9cc..24c25a4391 100644 --- a/src/test/java/com/rabbitmq/client/test/server/Permissions.java +++ b/src/test/java/com/rabbitmq/client/test/server/Permissions.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/PersistenceGuarantees.java b/src/test/java/com/rabbitmq/client/test/server/PersistenceGuarantees.java index 4070393600..42846db2a1 100644 --- a/src/test/java/com/rabbitmq/client/test/server/PersistenceGuarantees.java +++ b/src/test/java/com/rabbitmq/client/test/server/PersistenceGuarantees.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/PriorityQueues.java b/src/test/java/com/rabbitmq/client/test/server/PriorityQueues.java index ad1629bd62..805b5c6fc4 100644 --- a/src/test/java/com/rabbitmq/client/test/server/PriorityQueues.java +++ b/src/test/java/com/rabbitmq/client/test/server/PriorityQueues.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/ServerTests.java b/src/test/java/com/rabbitmq/client/test/server/ServerTests.java index bf8631a4b8..bda7cac3fd 100644 --- a/src/test/java/com/rabbitmq/client/test/server/ServerTests.java +++ b/src/test/java/com/rabbitmq/client/test/server/ServerTests.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/Shutdown.java b/src/test/java/com/rabbitmq/client/test/server/Shutdown.java index bab3724818..53cd63c184 100644 --- a/src/test/java/com/rabbitmq/client/test/server/Shutdown.java +++ b/src/test/java/com/rabbitmq/client/test/server/Shutdown.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/TopicPermissions.java b/src/test/java/com/rabbitmq/client/test/server/TopicPermissions.java index 1a5c02a4c8..c258e7a773 100644 --- a/src/test/java/com/rabbitmq/client/test/server/TopicPermissions.java +++ b/src/test/java/com/rabbitmq/client/test/server/TopicPermissions.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java b/src/test/java/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java index 16bd88ab02..4aa0839f39 100644 --- a/src/test/java/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java +++ b/src/test/java/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java index a11998c499..9b9e291314 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java b/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java index 9d6546572b..0ffbc52df5 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java index 20f3d5c297..2158b5c347 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java index 07ac30a901..4c22736e8b 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java index 88107b41fe..0dbb808584 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java b/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java index 363d749dde..ee4e817612 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java index 6d65599b4c..dd041fef5c 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java index e662113085..52c3763064 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/tools/Host.java b/src/test/java/com/rabbitmq/tools/Host.java index c30ec7fc6f..91f4c68f50 100644 --- a/src/test/java/com/rabbitmq/tools/Host.java +++ b/src/test/java/com/rabbitmq/tools/Host.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/utility/IntAllocatorTests.java b/src/test/java/com/rabbitmq/utility/IntAllocatorTests.java index 96586f5686..1dbdfa95a6 100644 --- a/src/test/java/com/rabbitmq/utility/IntAllocatorTests.java +++ b/src/test/java/com/rabbitmq/utility/IntAllocatorTests.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 From 76fbcd4339929293f016b376e713d537161844bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Tue, 10 Mar 2020 15:47:09 +0100 Subject: [PATCH 1222/2114] Update copyright (year 2020) --- .../com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java b/src/main/java/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java index 7cff31c0ec..97be3a8270 100644 --- a/src/main/java/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java +++ b/src/main/java/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java @@ -14,7 +14,7 @@ // info@rabbitmq.com. /* - * Modifications Copyright 2015 Pivotal Software, Inc and licenced as per + * Modifications Copyright 2015-2020 VMware, Inc. or its affiliates. and licenced as per * the rest of the RabbitMQ Java client. */ From 3bc7ee6a281e767d9a2b48035d098e989487535c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Tue, 10 Mar 2020 15:47:26 +0100 Subject: [PATCH 1223/2114] pom.xml: Change organization name from Pivotal to VMware --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 84bea85d05..5eca03dfbe 100644 --- a/pom.xml +++ b/pom.xml @@ -33,7 +33,7 @@ info@rabbitmq.com Team RabbitMQ - Pivotal Software, Inc. + VMware, Inc. or its affiliates. https://rabbitmq.com @@ -46,7 +46,7 @@ - Pivotal Software, Inc. + VMware, Inc. or its affiliates. https://www.rabbitmq.com From 733788e26ba73ea90a1be72b99227c6a10003054 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 1 Apr 2020 11:46:06 +0200 Subject: [PATCH 1224/2114] Check qos, heartbeat, max channel are unsigned shorts To avoid truncation and subtle bugs. Fixes #640 --- .../java/com/rabbitmq/client/Channel.java | 33 ++++--- .../rabbitmq/client/ConnectionFactory.java | 16 ++- .../rabbitmq/client/impl/AMQConnection.java | 18 +++- .../com/rabbitmq/client/impl/ChannelN.java | 32 +++--- .../rabbitmq/client/test/ChannelNTest.java | 31 ++++++ .../com/rabbitmq/client/test/ClientTests.java | 1 - .../client/test/ConnectionFactoryTest.java | 99 ++++++++++++------- .../rabbitmq/client/test/ssl/SSLTests.java | 4 +- 8 files changed, 163 insertions(+), 71 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/Channel.java b/src/main/java/com/rabbitmq/client/Channel.java index cdff101fd4..f6c1c240d4 100644 --- a/src/main/java/com/rabbitmq/client/Channel.java +++ b/src/main/java/com/rabbitmq/client/Channel.java @@ -193,42 +193,49 @@ public interface Channel extends ShutdownNotifier, AutoCloseable { /** * Request specific "quality of service" settings. - * + *

* These settings impose limits on the amount of data the server * will deliver to consumers before requiring acknowledgements. * Thus they provide a means of consumer-initiated flow control. - * @see com.rabbitmq.client.AMQP.Basic.Qos - * @param prefetchSize maximum amount of content (measured in - * octets) that the server will deliver, 0 if unlimited + *

+ * Note the prefetch count must be between 0 and 65535 (unsigned short in AMQP 0-9-1). + * + * @param prefetchSize maximum amount of content (measured in + * octets) that the server will deliver, 0 if unlimited * @param prefetchCount maximum number of messages that the server - * will deliver, 0 if unlimited - * @param global true if the settings should be applied to the - * entire channel rather than each consumer + * will deliver, 0 if unlimited + * @param global true if the settings should be applied to the + * entire channel rather than each consumer * @throws java.io.IOException if an error is encountered + * @see com.rabbitmq.client.AMQP.Basic.Qos */ void basicQos(int prefetchSize, int prefetchCount, boolean global) throws IOException; /** * Request a specific prefetchCount "quality of service" settings * for this channel. + *

+ * Note the prefetch count must be between 0 and 65535 (unsigned short in AMQP 0-9-1). * - * @see #basicQos(int, int, boolean) * @param prefetchCount maximum number of messages that the server - * will deliver, 0 if unlimited - * @param global true if the settings should be applied to the - * entire channel rather than each consumer + * will deliver, 0 if unlimited + * @param global true if the settings should be applied to the + * entire channel rather than each consumer * @throws java.io.IOException if an error is encountered + * @see #basicQos(int, int, boolean) */ void basicQos(int prefetchCount, boolean global) throws IOException; /** * Request a specific prefetchCount "quality of service" settings * for this channel. + *

+ * Note the prefetch count must be between 0 and 65535 (unsigned short in AMQP 0-9-1). * - * @see #basicQos(int, int, boolean) * @param prefetchCount maximum number of messages that the server - * will deliver, 0 if unlimited + * will deliver, 0 if unlimited * @throws java.io.IOException if an error is encountered + * @see #basicQos(int, int, boolean) */ void basicQos(int prefetchCount) throws IOException; diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 9c1dfa3fe0..22d468432e 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -47,6 +47,8 @@ */ public class ConnectionFactory implements Cloneable { + private static final int MAX_UNSIGNED_SHORT = 65535; + /** Default user name */ public static final String DEFAULT_USER = "guest"; /** Default password */ @@ -384,10 +386,16 @@ public int getRequestedChannelMax() { } /** - * Set the requested maximum channel number + * Set the requested maximum channel number. + *

+ * Note the value must be between 0 and 65535 (unsigned short in AMQP 0-9-1). + * * @param requestedChannelMax initially requested maximum channel number; zero for unlimited */ public void setRequestedChannelMax(int requestedChannelMax) { + if (requestedChannelMax < 0 || requestedChannelMax > MAX_UNSIGNED_SHORT) { + throw new IllegalArgumentException("Requested channel max must be between 0 and " + MAX_UNSIGNED_SHORT); + } this.requestedChannelMax = requestedChannelMax; } @@ -477,10 +485,16 @@ public int getShutdownTimeout() { * Set the requested heartbeat timeout. Heartbeat frames will be sent at about 1/2 the timeout interval. * If server heartbeat timeout is configured to a non-zero value, this method can only be used * to lower the value; otherwise any value provided by the client will be used. + *

+ * Note the value must be between 0 and 65535 (unsigned short in AMQP 0-9-1). + * * @param requestedHeartbeat the initially requested heartbeat timeout, in seconds; zero for none * @see RabbitMQ Heartbeats Guide */ public void setRequestedHeartbeat(int requestedHeartbeat) { + if (requestedHeartbeat < 0 || requestedHeartbeat > MAX_UNSIGNED_SHORT) { + throw new IllegalArgumentException("Requested heartbeat must be between 0 and " + MAX_UNSIGNED_SHORT); + } this.requestedHeartbeat = requestedHeartbeat; } diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index 28c03a847d..7c09e6900c 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -15,13 +15,12 @@ package com.rabbitmq.client.impl; -import com.rabbitmq.client.*; import com.rabbitmq.client.Method; +import com.rabbitmq.client.*; import com.rabbitmq.client.impl.AMQChannel.BlockingRpcContinuation; import com.rabbitmq.client.impl.recovery.RecoveryCanBeginListener; import com.rabbitmq.utility.BlockingCell; import com.rabbitmq.utility.Utility; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -47,6 +46,8 @@ final class Copyright { */ public class AMQConnection extends ShutdownNotifierComponent implements Connection, NetworkConnection { + private static final int MAX_UNSIGNED_SHORT = 65535; + private static final Logger LOGGER = LoggerFactory.getLogger(AMQConnection.class); // we want socket write and channel shutdown timeouts to kick in after // the heartbeat one, so we use a value of 105% of the effective heartbeat timeout @@ -399,6 +400,11 @@ public void start() int channelMax = negotiateChannelMax(this.requestedChannelMax, connTune.getChannelMax()); + + if (!checkUnsignedShort(channelMax)) { + throw new IllegalArgumentException("Negotiated channel max must be between 0 and " + MAX_UNSIGNED_SHORT + ": " + channelMax); + } + _channelManager = instantiateChannelManager(channelMax, threadFactory); int frameMax = @@ -410,6 +416,10 @@ public void start() negotiatedMaxValue(this.requestedHeartbeat, connTune.getHeartbeat()); + if (!checkUnsignedShort(heartbeat)) { + throw new IllegalArgumentException("Negotiated heartbeat must be between 0 and " + MAX_UNSIGNED_SHORT + ": " + heartbeat); + } + setHeartbeat(heartbeat); _channel0.transmit(new AMQP.Connection.TuneOk.Builder() @@ -626,6 +636,10 @@ private static int negotiatedMaxValue(int clientValue, int serverValue) { Math.min(clientValue, serverValue); } + private static boolean checkUnsignedShort(int value) { + return value >= 0 && value <= MAX_UNSIGNED_SHORT; + } + private class MainLoop implements Runnable { /** diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java index a3f7f5f794..db4d9b86e3 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelN.java @@ -15,30 +15,24 @@ package com.rabbitmq.client.impl; -import java.io.IOException; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.SortedSet; -import java.util.TreeSet; -import java.util.concurrent.*; - -import com.rabbitmq.client.ConfirmCallback; import com.rabbitmq.client.*; -import com.rabbitmq.client.AMQP.BasicProperties; +import com.rabbitmq.client.Connection; import com.rabbitmq.client.Method; -import com.rabbitmq.client.impl.AMQImpl.Basic; +import com.rabbitmq.client.AMQP.BasicProperties; import com.rabbitmq.client.impl.AMQImpl.Channel; -import com.rabbitmq.client.impl.AMQImpl.Confirm; -import com.rabbitmq.client.impl.AMQImpl.Exchange; import com.rabbitmq.client.impl.AMQImpl.Queue; -import com.rabbitmq.client.impl.AMQImpl.Tx; +import com.rabbitmq.client.impl.AMQImpl.*; import com.rabbitmq.utility.Utility; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.IOException; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeoutException; + /** * Main interface to AMQP protocol functionality. Public API - * Implementation of all AMQChannels except channel zero. @@ -50,6 +44,7 @@ * */ public class ChannelN extends AMQChannel implements com.rabbitmq.client.Channel { + private static final int MAX_UNSIGNED_SHORT = 65535; private static final String UNSPECIFIED_OUT_OF_BAND = ""; private static final Logger LOGGER = LoggerFactory.getLogger(ChannelN.class); @@ -647,7 +642,10 @@ public AMQCommand transformReply(AMQCommand command) { public void basicQos(int prefetchSize, int prefetchCount, boolean global) throws IOException { - exnWrappingRpc(new Basic.Qos(prefetchSize, prefetchCount, global)); + if (prefetchCount < 0 || prefetchCount > MAX_UNSIGNED_SHORT) { + throw new IllegalArgumentException("Prefetch count must be between 0 and " + MAX_UNSIGNED_SHORT); + } + exnWrappingRpc(new Basic.Qos(prefetchSize, prefetchCount, global)); } /** Public API - {@inheritDoc} */ diff --git a/src/test/java/com/rabbitmq/client/test/ChannelNTest.java b/src/test/java/com/rabbitmq/client/test/ChannelNTest.java index 34346366c8..80c7902be4 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelNTest.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelNTest.java @@ -24,6 +24,9 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; public class ChannelNTest { @@ -57,4 +60,32 @@ public void callingBasicCancelForUnknownConsumerDoesNotThrowException() throws E channel.basicCancel("does-not-exist"); } + @Test + public void qosShouldBeUnsignedShort() { + AMQConnection connection = Mockito.mock(AMQConnection.class); + ChannelN channel = new ChannelN(connection, 1, consumerWorkService); + class TestConfig { + int value; + Consumer call; + + public TestConfig(int value, Consumer call) { + this.value = value; + this.call = call; + } + } + Consumer qos = value -> channel.basicQos(value); + Consumer qosGlobal = value -> channel.basicQos(value, true); + Consumer qosPrefetchSize = value -> channel.basicQos(10, value, true); + Stream.of( + new TestConfig(-1, qos), new TestConfig(65536, qos) + ).flatMap(config -> Stream.of(config, new TestConfig(config.value, qosGlobal), new TestConfig(config.value, qosPrefetchSize))) + .forEach(config -> assertThatThrownBy(() -> config.call.apply(config.value)).isInstanceOf(IllegalArgumentException.class)); + } + + interface Consumer { + + void apply(int value) throws Exception; + + } + } diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index 02a0aebadb..77e2a75f83 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -52,7 +52,6 @@ ConnectionFactoryTest.class, RecoveryAwareAMQConnectionFactoryTest.class, RpcTest.class, - SslContextFactoryTest.class, LambdaCallbackTest.class, ChannelAsyncCompletableFutureTest.class, RecoveryDelayHandlerTest.class, diff --git a/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java b/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java index f77cee0a7e..7a9dd3d320 100644 --- a/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java +++ b/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java @@ -15,19 +15,8 @@ package com.rabbitmq.client.test; -import com.rabbitmq.client.Address; -import com.rabbitmq.client.AddressResolver; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.ConnectionFactory; -import com.rabbitmq.client.DnsRecordIpAddressResolver; -import com.rabbitmq.client.ListAddressResolver; -import com.rabbitmq.client.MetricsCollector; -import com.rabbitmq.client.impl.AMQConnection; -import com.rabbitmq.client.impl.ConnectionParams; -import com.rabbitmq.client.impl.CredentialsProvider; -import com.rabbitmq.client.impl.FrameHandler; -import com.rabbitmq.client.impl.FrameHandlerFactory; -import org.junit.AfterClass; +import com.rabbitmq.client.*; +import com.rabbitmq.client.impl.*; import org.junit.Test; import java.io.IOException; @@ -37,17 +26,18 @@ import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; +import java.util.stream.Stream; -import static org.hamcrest.Matchers.allOf; -import static org.hamcrest.Matchers.instanceOf; -import static org.hamcrest.Matchers.notNullValue; -import static org.junit.Assert.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.Mockito.*; public class ConnectionFactoryTest { // see https://github.com/rabbitmq/rabbitmq-java-client/issues/262 - @Test public void tryNextAddressIfTimeoutExceptionNoAutoRecovery() throws IOException, TimeoutException { + @Test + public void tryNextAddressIfTimeoutExceptionNoAutoRecovery() throws IOException, TimeoutException { final AMQConnection connectionThatThrowsTimeout = mock(AMQConnection.class); final AMQConnection connectionThatSucceeds = mock(AMQConnection.class); final Queue connections = new ArrayBlockingQueue(10); @@ -69,22 +59,23 @@ protected synchronized FrameHandlerFactory createFrameHandlerFactory() { doThrow(TimeoutException.class).when(connectionThatThrowsTimeout).start(); doNothing().when(connectionThatSucceeds).start(); Connection returnedConnection = connectionFactory.newConnection( - new Address[] { new Address("host1"), new Address("host2") } + new Address[]{new Address("host1"), new Address("host2")} ); - assertSame(connectionThatSucceeds, returnedConnection); + assertThat(returnedConnection).isSameAs(connectionThatSucceeds); } - + // see https://github.com/rabbitmq/rabbitmq-java-client/pull/350 - @Test public void customizeCredentialsProvider() throws Exception { + @Test + public void customizeCredentialsProvider() throws Exception { final CredentialsProvider provider = mock(CredentialsProvider.class); final AMQConnection connection = mock(AMQConnection.class); final AtomicBoolean createCalled = new AtomicBoolean(false); - + ConnectionFactory connectionFactory = new ConnectionFactory() { @Override protected AMQConnection createConnection(ConnectionParams params, FrameHandler frameHandler, - MetricsCollector metricsCollector) { - assertSame(provider, params.getCredentialsProvider()); + MetricsCollector metricsCollector) { + assertThat(provider).isSameAs(params.getCredentialsProvider()); createCalled.set(true); return connection; } @@ -96,22 +87,23 @@ protected synchronized FrameHandlerFactory createFrameHandlerFactory() { }; connectionFactory.setCredentialsProvider(provider); connectionFactory.setAutomaticRecoveryEnabled(false); - + doNothing().when(connection).start(); - + Connection returnedConnection = connectionFactory.newConnection(); - assertSame(returnedConnection, connection); - assertTrue(createCalled.get()); + assertThat(returnedConnection).isSameAs(connection); + assertThat(createCalled).isTrue(); } - @Test public void shouldNotUseDnsResolutionWhenOneAddressAndNoTls() throws Exception { + @Test + public void shouldNotUseDnsResolutionWhenOneAddressAndNoTls() throws Exception { AMQConnection connection = mock(AMQConnection.class); AtomicReference addressResolver = new AtomicReference<>(); ConnectionFactory connectionFactory = new ConnectionFactory() { @Override protected AMQConnection createConnection(ConnectionParams params, FrameHandler frameHandler, - MetricsCollector metricsCollector) { + MetricsCollector metricsCollector) { return connection; } @@ -131,18 +123,18 @@ protected synchronized FrameHandlerFactory createFrameHandlerFactory() { doNothing().when(connection).start(); connectionFactory.newConnection(); - - assertThat(addressResolver.get(), allOf(notNullValue(), instanceOf(ListAddressResolver.class))); + assertThat(addressResolver.get()).isNotNull().isInstanceOf(ListAddressResolver.class); } - @Test public void shouldNotUseDnsResolutionWhenOneAddressAndTls() throws Exception { + @Test + public void shouldNotUseDnsResolutionWhenOneAddressAndTls() throws Exception { AMQConnection connection = mock(AMQConnection.class); AtomicReference addressResolver = new AtomicReference<>(); ConnectionFactory connectionFactory = new ConnectionFactory() { @Override protected AMQConnection createConnection(ConnectionParams params, FrameHandler frameHandler, - MetricsCollector metricsCollector) { + MetricsCollector metricsCollector) { return connection; } @@ -164,7 +156,42 @@ protected synchronized FrameHandlerFactory createFrameHandlerFactory() { connectionFactory.useSslProtocol(); connectionFactory.newConnection(); - assertThat(addressResolver.get(), allOf(notNullValue(), instanceOf(ListAddressResolver.class))); + assertThat(addressResolver.get()).isNotNull().isInstanceOf(ListAddressResolver.class); + } + + @Test + public void heartbeatAndChannelMaxMustBeUnsignedShorts() { + class TestConfig { + int value; + Consumer call; + boolean expectException; + + public TestConfig(int value, Consumer call, boolean expectException) { + this.value = value; + this.call = call; + this.expectException = expectException; + } + } + + ConnectionFactory cf = new ConnectionFactory(); + Consumer setHeartbeat = cf::setRequestedHeartbeat; + Consumer setChannelMax = cf::setRequestedChannelMax; + + Stream.of( + new TestConfig(0, setHeartbeat, false), + new TestConfig(10, setHeartbeat, false), + new TestConfig(65535, setHeartbeat, false), + new TestConfig(-1, setHeartbeat, true), + new TestConfig(65536, setHeartbeat, true)) + .flatMap(config -> Stream.of(config, new TestConfig(config.value, setChannelMax, config.expectException))) + .forEach(config -> { + if (config.expectException) { + assertThatThrownBy(() -> config.call.accept(config.value)).isInstanceOf(IllegalArgumentException.class); + } else { + config.call.accept(config.value); + } + }); + } } diff --git a/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java index 0dbb808584..1dddf62e38 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java @@ -17,6 +17,7 @@ package com.rabbitmq.client.test.ssl; import com.rabbitmq.client.test.AbstractRMQTestSuite; +import com.rabbitmq.client.test.SslContextFactoryTest; import org.junit.runner.RunWith; import org.junit.runner.Runner; import org.junit.runners.Suite; @@ -34,7 +35,8 @@ ConnectionFactoryDefaultTlsVersion.class, NioTlsUnverifiedConnection.class, HostnameVerification.class, - TlsConnectionLogging.class + TlsConnectionLogging.class, + SslContextFactoryTest.class }) public class SSLTests { From d979c388603698fc6a7b2d26507ec6554ab684a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 1 Apr 2020 15:20:00 +0200 Subject: [PATCH 1225/2114] Bump test dependencies Don't use JUnit's assertThat anymore, as it's deprecated in 4.13. Use assertj instead. Get rid of Awaitility (created a waitUntil test utility instead) and Hamcrest (not used anymore). --- pom.xml | 21 +-- .../rabbitmq/client/test/AMQChannelTest.java | 37 +++-- .../ChannelRpcTimeoutIntegrationTest.java | 10 +- .../client/test/ClientVersionTest.java | 8 +- .../test/DnsSrvRecordAddressResolverTest.java | 15 +- .../client/test/FrameBuilderTest.java | 37 +++-- .../com/rabbitmq/client/test/FrameTest.java | 5 +- .../client/test/MetricsCollectorTest.java | 93 ++++++------ .../test/MicrometerMetricsCollectorTest.java | 17 +-- ...NoAutoRecoveryWhenTcpWindowIsFullTest.java | 31 ++-- .../test/PropertyFileInitialisationTest.java | 86 +++++------ .../com/rabbitmq/client/test/RpcTest.java | 4 +- .../test/StrictExceptionHandlerTest.java | 7 +- .../com/rabbitmq/client/test/TestUtils.java | 25 +++ .../rabbitmq/client/test/TestUtilsTest.java | 17 +-- .../test/functional/ConnectionRecovery.java | 142 +++++++++--------- .../client/test/functional/Metrics.java | 132 ++++++++-------- .../functional/TopologyRecoveryFiltering.java | 14 +- src/test/java/com/rabbitmq/tools/Host.java | 3 +- 19 files changed, 331 insertions(+), 373 deletions(-) diff --git a/pom.xml b/pom.xml index 5eca03dfbe..5dbf1ec00e 100644 --- a/pom.xml +++ b/pom.xml @@ -59,11 +59,10 @@ 1.3.2 2.10.1 1.2.3 - 4.12 - 4.0.1 - 3.2.0 - 3.14.0 - 9.4.24.v20191120 + 4.13 + 3.3.3 + 3.15.0 + 9.4.27.v20200227 1.64 3.1.1 @@ -722,12 +721,6 @@ ${logback.version} test - - org.awaitility - awaitility - ${awaitility.version} - test - org.mockito mockito-core @@ -740,12 +733,6 @@ ${assertj.version} test - - org.hamcrest - hamcrest-library - 1.3 - test - org.eclipse.jetty jetty-servlet diff --git a/src/test/java/com/rabbitmq/client/test/AMQChannelTest.java b/src/test/java/com/rabbitmq/client/test/AMQChannelTest.java index cb5f65d4fb..73a8731eea 100644 --- a/src/test/java/com/rabbitmq/client/test/AMQChannelTest.java +++ b/src/test/java/com/rabbitmq/client/test/AMQChannelTest.java @@ -33,8 +33,8 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; -import static org.hamcrest.Matchers.*; -import static org.junit.Assert.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; import static org.mockito.Mockito.*; public class AMQChannelTest { @@ -69,10 +69,10 @@ public class AMQChannelTest { fail("Should time out and throw an exception"); } catch(ChannelContinuationTimeoutException e) { // OK - assertThat((DummyAmqChannel) e.getChannel(), is(channel)); - assertThat(e.getChannelNumber(), is(channel.getChannelNumber())); - assertThat(e.getMethod(), is(method)); - assertNull("outstanding RPC should have been cleaned", channel.nextOutstandingRpc()); + assertThat((DummyAmqChannel) e.getChannel()).isEqualTo(channel); + assertThat(e.getChannelNumber()).isEqualTo(channel.getChannelNumber()); + assertThat(e.getMethod()).isEqualTo(method); + assertThat(channel.nextOutstandingRpc()).as("outstanding RPC should have been cleaned").isNull(); } } @@ -105,7 +105,7 @@ public Void call() throws Exception { }, (long) (rpcTimeout / 2.0), TimeUnit.MILLISECONDS); AMQCommand rpcResponse = channel.rpc(method); - assertThat(rpcResponse.getMethod(), is(response)); + assertThat(rpcResponse.getMethod()).isEqualTo(response); } @Test @@ -130,10 +130,10 @@ public void testRpcTimeoutReplyComesDuringNexRpc() throws Exception { fail("Should time out and throw an exception"); } catch(final ChannelContinuationTimeoutException e) { // OK - assertThat((DummyAmqChannel) e.getChannel(), is(channel)); - assertThat(e.getChannelNumber(), is(channel.getChannelNumber())); - assertThat(e.getMethod(), is(method)); - assertNull("outstanding RPC should have been cleaned", channel.nextOutstandingRpc()); + assertThat((DummyAmqChannel) e.getChannel()).isEqualTo(channel); + assertThat(e.getChannelNumber()).isEqualTo(channel.getChannelNumber()); + assertThat(e.getMethod()).isEqualTo(method); + assertThat(channel.nextOutstandingRpc()).as("outstanding RPC should have been cleaned").isNull(); } // now do a basic.consume request and have the queue.declareok returned instead @@ -151,18 +151,15 @@ public void testRpcTimeoutReplyComesDuringNexRpc() throws Exception { final Method response2 = new AMQImpl.Basic.ConsumeOk.Builder() .consumerTag("456").build(); - scheduler.schedule(new Callable() { - @Override - public Void call() throws Exception { - channel.handleCompleteInboundCommand(new AMQCommand(response1)); - Thread.sleep(10); - channel.handleCompleteInboundCommand(new AMQCommand(response2)); - return null; - } + scheduler.schedule((Callable) () -> { + channel.handleCompleteInboundCommand(new AMQCommand(response1)); + Thread.sleep(10); + channel.handleCompleteInboundCommand(new AMQCommand(response2)); + return null; }, (long) (rpcTimeout / 2.0), TimeUnit.MILLISECONDS); AMQCommand rpcResponse = channel.rpc(method); - assertThat(rpcResponse.getMethod(), is(response2)); + assertThat(rpcResponse.getMethod()).isEqualTo(response2); } static class DummyAmqChannel extends AMQChannel { diff --git a/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java b/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java index 87494900a6..948074580f 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java @@ -27,8 +27,8 @@ import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeoutException; -import static org.hamcrest.Matchers.*; -import static org.junit.Assert.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; public class ChannelRpcTimeoutIntegrationTest { @@ -73,9 +73,9 @@ public void tearDown() { fail("Should time out and throw an exception"); } catch(ChannelContinuationTimeoutException e) { // OK - assertThat((Channel) e.getChannel(), is(channel)); - assertThat(e.getChannelNumber(), is(channel.getChannelNumber())); - assertThat(e.getMethod(), instanceOf(AMQP.Queue.Declare.class)); + assertThat((Channel) e.getChannel()).isEqualTo(channel); + assertThat(e.getChannelNumber()).isEqualTo(channel.getChannelNumber()); + assertThat(e.getMethod()).isInstanceOf(AMQP.Queue.Declare.class); } } finally { connection.close(); diff --git a/src/test/java/com/rabbitmq/client/test/ClientVersionTest.java b/src/test/java/com/rabbitmq/client/test/ClientVersionTest.java index 3c36dd7015..9d7560adaf 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientVersionTest.java +++ b/src/test/java/com/rabbitmq/client/test/ClientVersionTest.java @@ -18,15 +18,13 @@ import com.rabbitmq.client.impl.ClientVersion; import org.junit.Test; -import static org.hamcrest.Matchers.not; -import static org.hamcrest.Matchers.notNullValue; -import static org.junit.Assert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; public class ClientVersionTest { @Test public void clientVersion() { - assertThat(ClientVersion.VERSION, notNullValue()); - assertThat(ClientVersion.VERSION, not("0.0.0")); + assertThat(ClientVersion.VERSION).isNotNull(); + assertThat(ClientVersion.VERSION).isNotEqualTo("0.0.0"); } } diff --git a/src/test/java/com/rabbitmq/client/test/DnsSrvRecordAddressResolverTest.java b/src/test/java/com/rabbitmq/client/test/DnsSrvRecordAddressResolverTest.java index 886aa1f533..e315d1147c 100644 --- a/src/test/java/com/rabbitmq/client/test/DnsSrvRecordAddressResolverTest.java +++ b/src/test/java/com/rabbitmq/client/test/DnsSrvRecordAddressResolverTest.java @@ -23,8 +23,7 @@ import java.util.Arrays; import java.util.List; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; /** * @@ -46,12 +45,12 @@ protected List lookupSrvRecords(String service, String dnsUrls) throw }; List

addresses = resolver.getAddresses(); - assertThat(addresses.size(), is(5)); - assertThat(addresses.get(0).getHost(), is("alt1.xmpp-server.l.google.com")); - assertThat(addresses.get(1).getHost(), is("alt2.xmpp-server.l.google.com")); - assertThat(addresses.get(2).getHost(), is("alt3.xmpp-server.l.google.com")); - assertThat(addresses.get(3).getHost(), is("alt4.xmpp-server.l.google.com")); - assertThat(addresses.get(4).getHost(), is("alt5.xmpp-server.l.google.com")); + assertThat(addresses.size()).isEqualTo(5); + assertThat(addresses.get(0).getHost()).isEqualTo("alt1.xmpp-server.l.google.com"); + assertThat(addresses.get(1).getHost()).isEqualTo("alt2.xmpp-server.l.google.com"); + assertThat(addresses.get(2).getHost()).isEqualTo("alt3.xmpp-server.l.google.com"); + assertThat(addresses.get(3).getHost()).isEqualTo("alt4.xmpp-server.l.google.com"); + assertThat(addresses.get(4).getHost()).isEqualTo("alt5.xmpp-server.l.google.com"); } } diff --git a/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java b/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java index 64605aaea6..9d2892e304 100644 --- a/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java +++ b/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java @@ -28,11 +28,8 @@ import java.nio.ByteBuffer; import java.nio.channels.ReadableByteChannel; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; -import static org.hamcrest.Matchers.nullValue; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; /** * @@ -52,10 +49,10 @@ public void buildFrameInOneGo() throws IOException { buffer = ByteBuffer.wrap(new byte[] { 1, 0, 0, 0, 0, 0, 3, 1, 2, 3, end() }); builder = new FrameBuilder(channel, buffer); Frame frame = builder.readFrame(); - assertThat(frame, notNullValue()); - assertThat(frame.getType(), is(1)); - assertThat(frame.getChannel(), is(0)); - assertThat(frame.getPayload().length, is(3)); + assertThat(frame).isNotNull(); + assertThat(frame.getType()).isEqualTo(1); + assertThat(frame.getChannel()).isEqualTo(0); + assertThat(frame.getPayload()).hasSize(3); } @Test @@ -73,13 +70,13 @@ public void buildFramesInOneGo() throws IOException { int frameCount = 0; Frame frame; while ((frame = builder.readFrame()) != null) { - assertThat(frame, notNullValue()); - assertThat(frame.getType(), is(1)); - assertThat(frame.getChannel(), is(0)); - assertThat(frame.getPayload().length, is(3)); + assertThat(frame).isNotNull(); + assertThat(frame.getType()).isEqualTo(1); + assertThat(frame.getChannel()).isEqualTo(0); + assertThat(frame.getPayload()).hasSize(3); frameCount++; } - assertThat(frameCount, is(nbFrames)); + assertThat(frameCount).isEqualTo(nbFrames); } @Test @@ -87,17 +84,17 @@ public void buildFrameInSeveralCalls() throws IOException { buffer = ByteBuffer.wrap(new byte[] { 1, 0, 0, 0, 0, 0, 3, 1, 2 }); builder = new FrameBuilder(channel, buffer); Frame frame = builder.readFrame(); - assertThat(frame, nullValue()); + assertThat(frame).isNull(); buffer.clear(); buffer.put(b(3)).put(end()); buffer.flip(); frame = builder.readFrame(); - assertThat(frame, notNullValue()); - assertThat(frame.getType(), is(1)); - assertThat(frame.getChannel(), is(0)); - assertThat(frame.getPayload().length, is(3)); + assertThat(frame).isNotNull(); + assertThat(frame.getType()).isEqualTo(1); + assertThat(frame.getChannel()).isEqualTo(0); + assertThat(frame.getPayload()).hasSize(3); } @Test @@ -127,7 +124,7 @@ public void protocolMismatchHeader() throws IOException { builder.readFrame(); fail("protocol header not correct, exception should have been thrown"); } catch (MalformedFrameException e) { - assertThat(e.getMessage(), is(messages[i])); + assertThat(e.getMessage()).isEqualTo(messages[i]); } } } diff --git a/src/test/java/com/rabbitmq/client/test/FrameTest.java b/src/test/java/com/rabbitmq/client/test/FrameTest.java index a154a6cfe3..26441a848b 100644 --- a/src/test/java/com/rabbitmq/client/test/FrameTest.java +++ b/src/test/java/com/rabbitmq/client/test/FrameTest.java @@ -17,8 +17,7 @@ import java.util.List; import java.util.Random; -import static org.hamcrest.Matchers.equalTo; -import static org.junit.Assert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; /** * @@ -72,7 +71,7 @@ private void checkWrittenChunks(int totalFrameSize, AccumulatorWritableByteChann for (byte[] chunk : channel.chunks) { totalWritten += chunk.length; } - assertThat(totalWritten, equalTo(totalFrameSize)); + assertThat(totalWritten).isEqualTo(totalFrameSize); } private static class AccumulatorWritableByteChannel implements WritableByteChannel { diff --git a/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java b/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java index 46a3569dd9..72d6409774 100644 --- a/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java +++ b/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java @@ -28,8 +28,7 @@ import java.io.IOException; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -70,16 +69,16 @@ public void basicGetAndAck() { metrics.consumedMessage(channel, 6, false); metrics.basicAck(channel, 6, false); - assertThat(acknowledgedMessages(metrics), is(1L)); + assertThat(acknowledgedMessages(metrics)).isEqualTo(1L); metrics.basicAck(channel, 3, true); - assertThat(acknowledgedMessages(metrics), is(1L+2L)); + assertThat(acknowledgedMessages(metrics)).isEqualTo(1L+2L); metrics.basicAck(channel, 6, true); - assertThat(acknowledgedMessages(metrics), is(1L+2L+1L)); + assertThat(acknowledgedMessages(metrics)).isEqualTo(1L+2L+1L); metrics.basicAck(channel, 10, true); - assertThat(acknowledgedMessages(metrics), is(1L+2L+1L)); + assertThat(acknowledgedMessages(metrics)).isEqualTo(1L+2L+1L); } @Test public void basicConsumeAndAck() { @@ -99,8 +98,8 @@ public void basicGetAndAck() { metrics.basicConsume(channel, consumerTagWithManualAck, false); metrics.consumedMessage(channel, 1, consumerTagWithAutoAck); - assertThat(consumedMessages(metrics), is(1L)); - assertThat(acknowledgedMessages(metrics), is(0L)); + assertThat(consumedMessages(metrics)).isEqualTo(1L); + assertThat(acknowledgedMessages(metrics)).isEqualTo(0L); metrics.consumedMessage(channel, 2, consumerTagWithManualAck); metrics.consumedMessage(channel, 3, consumerTagWithManualAck); @@ -109,44 +108,44 @@ public void basicGetAndAck() { metrics.consumedMessage(channel, 6, consumerTagWithManualAck); metrics.basicAck(channel, 6, false); - assertThat(acknowledgedMessages(metrics), is(1L)); + assertThat(acknowledgedMessages(metrics)).isEqualTo(1L); metrics.basicAck(channel, 3, true); - assertThat(acknowledgedMessages(metrics), is(1L+2L)); + assertThat(acknowledgedMessages(metrics)).isEqualTo(1L+2L); metrics.basicAck(channel, 6, true); - assertThat(acknowledgedMessages(metrics), is(1L+2L+1L)); + assertThat(acknowledgedMessages(metrics)).isEqualTo(1L+2L+1L); metrics.basicAck(channel, 10, true); - assertThat(acknowledgedMessages(metrics), is(1L+2L+1L)); + assertThat(acknowledgedMessages(metrics)).isEqualTo(1L+2L+1L); } @Test public void publishingAndPublishingFailures() { AbstractMetricsCollector metrics = factory.create(); Channel channel = mock(Channel.class); - assertThat(failedToPublishMessages(metrics), is(0L)); - assertThat(publishedMessages(metrics), is(0L)); + assertThat(failedToPublishMessages(metrics)).isEqualTo(0L); + assertThat(publishedMessages(metrics)).isEqualTo(0L); metrics.basicPublishFailure(channel, new IOException()); - assertThat(failedToPublishMessages(metrics), is(1L)); - assertThat(publishedMessages(metrics), is(0L)); + assertThat(failedToPublishMessages(metrics)).isEqualTo(1L); + assertThat(publishedMessages(metrics)).isEqualTo(0L); metrics.basicPublish(channel, 0L); - assertThat(failedToPublishMessages(metrics), is(1L)); - assertThat(publishedMessages(metrics), is(1L)); + assertThat(failedToPublishMessages(metrics)).isEqualTo(1L); + assertThat(publishedMessages(metrics)).isEqualTo(1L); metrics.basicPublishFailure(channel, new IOException()); - assertThat(failedToPublishMessages(metrics), is(2L)); - assertThat(publishedMessages(metrics), is(1L)); + assertThat(failedToPublishMessages(metrics)).isEqualTo(2L); + assertThat(publishedMessages(metrics)).isEqualTo(1L); metrics.basicPublish(channel, 0L); - assertThat(failedToPublishMessages(metrics), is(2L)); - assertThat(publishedMessages(metrics), is(2L)); + assertThat(failedToPublishMessages(metrics)).isEqualTo(2L); + assertThat(publishedMessages(metrics)).isEqualTo(2L); metrics.cleanStaleState(); - assertThat(failedToPublishMessages(metrics), is(2L)); - assertThat(publishedMessages(metrics), is(2L)); + assertThat(failedToPublishMessages(metrics)).isEqualTo(2L); + assertThat(publishedMessages(metrics)).isEqualTo(2L); } @Test public void publishingAcknowledgements() { @@ -161,19 +160,19 @@ public void basicGetAndAck() { metrics.newChannel(channel); // begins with no messages acknowledged - assertThat(publishAck(metrics), is(0L)); + assertThat(publishAck(metrics)).isEqualTo(0L); // first acknowledgement gets tracked metrics.basicPublish(channel, 1); metrics.basicPublishAck(channel, 1, false); - assertThat(publishAck(metrics), is(1L)); + assertThat(publishAck(metrics)).isEqualTo(1L); // second acknowledgement gets tracked metrics.basicPublish(channel, 2); metrics.basicPublishAck(channel, 2, false); - assertThat(publishAck(metrics), is(2L)); + assertThat(publishAck(metrics)).isEqualTo(2L); // this is idempotent metrics.basicPublishAck(channel, 2, false); - assertThat(publishAck(metrics), is(2L)); + assertThat(publishAck(metrics)).isEqualTo(2L); // multi-ack metrics.basicPublish(channel, 3); @@ -181,18 +180,18 @@ public void basicGetAndAck() { metrics.basicPublish(channel, 5); // ack-ing in the middle metrics.basicPublishAck(channel, 4, false); - assertThat(publishAck(metrics), is(3L)); + assertThat(publishAck(metrics)).isEqualTo(3L); // ack-ing several at once metrics.basicPublishAck(channel, 5, true); - assertThat(publishAck(metrics), is(5L)); + assertThat(publishAck(metrics)).isEqualTo(5L); // ack-ing non existent doesn't affect metrics metrics.basicPublishAck(channel, 123, true); - assertThat(publishAck(metrics), is(5L)); + assertThat(publishAck(metrics)).isEqualTo(5L); // cleaning stale state doesn't affect the metric metrics.cleanStaleState(); - assertThat(publishAck(metrics), is(5L)); + assertThat(publishAck(metrics)).isEqualTo(5L); } @Test public void publishingNotAcknowledgements() { @@ -206,15 +205,15 @@ public void basicGetAndAck() { metrics.newConnection(connection); metrics.newChannel(channel); // begins with no messages not-acknowledged - assertThat(publishNack(metrics), is(0L)); + assertThat(publishNack(metrics)).isEqualTo(0L); // first not-acknowledgement gets tracked metrics.basicPublish(channel, 1); metrics.basicPublishNack(channel, 1, false); - assertThat(publishNack(metrics), is(1L)); + assertThat(publishNack(metrics)).isEqualTo(1L); // second not-acknowledgement gets tracked metrics.basicPublish(channel, 2); metrics.basicPublishNack(channel, 2, false); - assertThat(publishNack(metrics), is(2L)); + assertThat(publishNack(metrics)).isEqualTo(2L); // multi-nack metrics.basicPublish(channel, 3); @@ -222,34 +221,34 @@ public void basicGetAndAck() { metrics.basicPublish(channel, 5); // ack-ing in the middle metrics.basicPublishNack(channel, 4, false); - assertThat(publishNack(metrics), is(3L)); + assertThat(publishNack(metrics)).isEqualTo(3L); // ack-ing several at once metrics.basicPublishNack(channel, 5, true); - assertThat(publishNack(metrics), is(5L)); + assertThat(publishNack(metrics)).isEqualTo(5L); // ack-ing non existent doesn't affect metrics metrics.basicPublishNack(channel, 123, true); - assertThat(publishNack(metrics), is(5L)); + assertThat(publishNack(metrics)).isEqualTo(5L); // cleaning stale state doesn't affect the metric metrics.cleanStaleState(); - assertThat(publishNack(metrics), is(5L)); + assertThat(publishNack(metrics)).isEqualTo(5L); } @Test public void publishingUnrouted() { AbstractMetricsCollector metrics = factory.create(); Channel channel = mock(Channel.class); // begins with no messages not-acknowledged - assertThat(publishUnrouted(metrics), is(0L)); + assertThat(publishUnrouted(metrics)).isEqualTo(0L); // first unrouted gets tracked metrics.basicPublishUnrouted(channel); - assertThat(publishUnrouted(metrics), is(1L)); + assertThat(publishUnrouted(metrics)).isEqualTo(1L); // second unrouted gets tracked metrics.basicPublishUnrouted(channel); - assertThat(publishUnrouted(metrics), is(2L)); + assertThat(publishUnrouted(metrics)).isEqualTo(2L); // cleaning stale state doesn't affect the metric metrics.cleanStaleState(); - assertThat(publishUnrouted(metrics), is(2L)); + assertThat(publishUnrouted(metrics)).isEqualTo(2L); } @Test public void cleanStaleState() { @@ -283,13 +282,13 @@ public void basicGetAndAck() { metrics.newChannel(closedChannel); metrics.newChannel(openChannelInClosedConnection); - assertThat(connections(metrics), is(2L)); - assertThat(channels(metrics), is(2L+1L)); + assertThat(connections(metrics)).isEqualTo(2L); + assertThat(channels(metrics)).isEqualTo(2L+1L); metrics.cleanStaleState(); - assertThat(connections(metrics), is(1L)); - assertThat(channels(metrics), is(1L)); + assertThat(connections(metrics)).isEqualTo(1L); + assertThat(channels(metrics)).isEqualTo(1L); } diff --git a/src/test/java/com/rabbitmq/client/test/MicrometerMetricsCollectorTest.java b/src/test/java/com/rabbitmq/client/test/MicrometerMetricsCollectorTest.java index 5cc8aa6178..77798a0088 100644 --- a/src/test/java/com/rabbitmq/client/test/MicrometerMetricsCollectorTest.java +++ b/src/test/java/com/rabbitmq/client/test/MicrometerMetricsCollectorTest.java @@ -18,14 +18,10 @@ import com.rabbitmq.client.impl.MicrometerMetricsCollector; import io.micrometer.core.instrument.Meter; import io.micrometer.core.instrument.simple.SimpleMeterRegistry; +import org.assertj.core.api.Assertions; import org.junit.Before; import org.junit.Test; -import java.util.Iterator; - -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; - /** * */ @@ -44,7 +40,7 @@ public void init() { public void noTag() { collector = new MicrometerMetricsCollector(registry, "rabbitmq"); for (Meter meter : registry.getMeters()) { - assertThat(size(meter.getId().getTags()), is(0)); + Assertions.assertThat(meter.getId().getTags()).isEmpty(); } } @@ -52,7 +48,7 @@ public void noTag() { public void tags() { collector = new MicrometerMetricsCollector(registry, "rabbitmq", "uri", "/api/users"); for (Meter meter : registry.getMeters()) { - assertThat(size(meter.getId().getTags()), is(1)); + Assertions.assertThat(meter.getId().getTags()).hasSize(1); } } @@ -61,11 +57,4 @@ public void tagsMustBeKeyValuePairs() { collector = new MicrometerMetricsCollector(registry, "rabbitmq", "uri"); } - static int size(Iterable iterable) { - Iterator iterator = iterable.iterator(); - int i = 0; - for ( ; iterator.hasNext() ; ++i ) iterator.next(); - return i; - } - } diff --git a/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java b/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java index 5014bcda2f..62a237cb83 100644 --- a/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java +++ b/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java @@ -42,8 +42,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; /** * Test to trigger and check the fix of rabbitmq/rabbitmq-java-client#341, @@ -149,15 +148,13 @@ public void handleRecoveryStarted(Recoverable recoverable) { produceMessagesInBackground(producingChannel, queue); startConsumer(queue); - assertThat( - "Connection should have been closed and should have recovered by now", - recoveryLatch.await(60, TimeUnit.SECONDS), is(true) - ); + assertThat(recoveryLatch.await(60, TimeUnit.SECONDS)) + .as("Connection should have been closed and should have recovered by now") + .isTrue(); - assertThat( - "Consumer should have recovered by now", - consumerOkLatch.await(5, TimeUnit.SECONDS), is(true) - ); + assertThat(consumerOkLatch.await(5, TimeUnit.SECONDS)) + .as("Consumer should have recovered by now") + .isTrue(); } private void closeConnectionIfOpen(Connection connection) throws IOException { @@ -173,16 +170,12 @@ private void declareQueue(final Channel channel, final String queue) throws IOEx private void produceMessagesInBackground(final Channel channel, final String queue) throws IOException { final AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder().deliveryMode(1).build(); - executorService.submit(new Callable() { - - @Override - public Void call() throws Exception { - for (int i = 0; i < NUM_MESSAGES_TO_PRODUCE; i++) { - channel.basicPublish("", queue, false, properties, MESSAGE_CONTENT); - } - closeConnectionIfOpen(producingConnection); - return null; + executorService.submit((Callable) () -> { + for (int i = 0; i < NUM_MESSAGES_TO_PRODUCE; i++) { + channel.basicPublish("", queue, false, properties, MESSAGE_CONTENT); } + closeConnectionIfOpen(producingConnection); + return null; }); } diff --git a/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java b/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java index 3d6099e12c..0c5df5823f 100644 --- a/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java +++ b/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java @@ -30,11 +30,7 @@ import java.util.Properties; import static com.rabbitmq.client.impl.AMQConnection.defaultClientProperties; -import static org.hamcrest.Matchers.hasSize; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; -import static org.hamcrest.Matchers.notNullValue; -import static org.junit.Assert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; /** * @@ -84,24 +80,24 @@ public static Object[] data() { @Test public void propertyInitialisationUri() { cf.load(Collections.singletonMap("rabbitmq.uri", "amqp://foo:bar@127.0.0.1:5673/dummy")); - assertThat(cf.getUsername(), is("foo")); - assertThat(cf.getPassword(), is("bar")); - assertThat(cf.getVirtualHost(), is("dummy")); - assertThat(cf.getHost(), is("127.0.0.1")); - assertThat(cf.getPort(), is(5673)); + assertThat(cf.getUsername()).isEqualTo("foo"); + assertThat(cf.getPassword()).isEqualTo("bar"); + assertThat(cf.getVirtualHost()).isEqualTo("dummy"); + assertThat(cf.getHost()).isEqualTo("127.0.0.1"); + assertThat(cf.getPort()).isEqualTo(5673); } @Test public void propertyInitialisationIncludeDefaultClientPropertiesByDefault() { - cf.load(new HashMap()); - assertThat(cf.getClientProperties().entrySet(), hasSize(defaultClientProperties().size())); + cf.load(new HashMap<>()); + assertThat(cf.getClientProperties().entrySet()).hasSize(defaultClientProperties().size()); } @Test public void propertyInitialisationAddCustomClientProperty() { cf.load(new HashMap() {{ put("rabbitmq.client.properties.foo", "bar"); }}); - assertThat(cf.getClientProperties().entrySet(), hasSize(defaultClientProperties().size() + 1)); - assertThat(cf.getClientProperties().get("foo").toString(), is("bar")); + assertThat(cf.getClientProperties().entrySet()).hasSize(defaultClientProperties().size() + 1); + assertThat(cf.getClientProperties()).extracting("foo").isEqualTo("bar"); } @Test public void propertyInitialisationGetRidOfDefaultClientPropertyWithEmptyValue() { @@ -109,7 +105,7 @@ public static Object[] data() { cf.load(new HashMap() {{ put("rabbitmq.client.properties." + key, ""); }}); - assertThat(cf.getClientProperties().entrySet(), hasSize(defaultClientProperties().size() - 1)); + assertThat(cf.getClientProperties().entrySet()).hasSize(defaultClientProperties().size() - 1); } @Test public void propertyInitialisationOverrideDefaultClientProperty() { @@ -117,8 +113,8 @@ public static Object[] data() { cf.load(new HashMap() {{ put("rabbitmq.client.properties." + key, "whatever"); }}); - assertThat(cf.getClientProperties().entrySet(), hasSize(defaultClientProperties().size())); - assertThat(cf.getClientProperties().get(key).toString(), is("whatever")); + assertThat(cf.getClientProperties().entrySet()).hasSize(defaultClientProperties().size()); + assertThat(cf.getClientProperties()).extracting(key).isEqualTo("whatever"); } @Test public void propertyInitialisationDoNotUseNio() throws Exception { @@ -126,37 +122,37 @@ public static Object[] data() { put("rabbitmq.use.nio", "false"); put("rabbitmq.nio.nb.io.threads", "2"); }}); - assertThat(cf.getNioParams().getNbIoThreads(), not(2)); + assertThat(cf.getNioParams().getNbIoThreads()).isNotEqualTo(2); } private void checkConnectionFactory() { - assertThat(cf.getUsername(), is("foo")); - assertThat(cf.getPassword(), is("bar")); - assertThat(cf.getVirtualHost(), is("dummy")); - assertThat(cf.getHost(), is("127.0.0.1")); - assertThat(cf.getPort(), is(5673)); - - assertThat(cf.getRequestedChannelMax(), is(1)); - assertThat(cf.getRequestedFrameMax(), is(2)); - assertThat(cf.getRequestedHeartbeat(), is(10)); - assertThat(cf.getConnectionTimeout(), is(10000)); - assertThat(cf.getHandshakeTimeout(), is(5000)); - - assertThat(cf.getClientProperties().entrySet(), hasSize(defaultClientProperties().size() + 1)); - assertThat(cf.getClientProperties().get("foo").toString(), is("bar")); - - assertThat(cf.isAutomaticRecoveryEnabled(), is(false)); - assertThat(cf.isTopologyRecoveryEnabled(), is(false)); - assertThat(cf.getNetworkRecoveryInterval(), is(10000l)); - assertThat(cf.getChannelRpcTimeout(), is(10000)); - assertThat(cf.isChannelShouldCheckRpcResponseType(), is(true)); - - assertThat(cf.getNioParams(), notNullValue()); - assertThat(cf.getNioParams().getReadByteBufferSize(), is(32000)); - assertThat(cf.getNioParams().getWriteByteBufferSize(), is(32000)); - assertThat(cf.getNioParams().getNbIoThreads(), is(2)); - assertThat(cf.getNioParams().getWriteEnqueuingTimeoutInMs(), is(5000)); - assertThat(cf.getNioParams().getWriteQueueCapacity(), is(1000)); + assertThat(cf.getUsername()).isEqualTo("foo"); + assertThat(cf.getPassword()).isEqualTo("bar"); + assertThat(cf.getVirtualHost()).isEqualTo("dummy"); + assertThat(cf.getHost()).isEqualTo("127.0.0.1"); + assertThat(cf.getPort()).isEqualTo(5673); + + assertThat(cf.getRequestedChannelMax()).isEqualTo(1); + assertThat(cf.getRequestedFrameMax()).isEqualTo(2); + assertThat(cf.getRequestedHeartbeat()).isEqualTo(10); + assertThat(cf.getConnectionTimeout()).isEqualTo(10000); + assertThat(cf.getHandshakeTimeout()).isEqualTo(5000); + + assertThat(cf.getClientProperties().entrySet()).hasSize(defaultClientProperties().size() + 1); + assertThat(cf.getClientProperties()).extracting("foo").isEqualTo("bar"); + + assertThat(cf.isAutomaticRecoveryEnabled()).isFalse(); + assertThat(cf.isTopologyRecoveryEnabled()).isFalse(); + assertThat(cf.getNetworkRecoveryInterval()).isEqualTo(10000l); + assertThat(cf.getChannelRpcTimeout()).isEqualTo(10000); + assertThat(cf.isChannelShouldCheckRpcResponseType()).isTrue(); + + assertThat(cf.getNioParams()).isNotNull(); + assertThat(cf.getNioParams().getReadByteBufferSize()).isEqualTo(32000); + assertThat(cf.getNioParams().getWriteByteBufferSize()).isEqualTo(32000); + assertThat(cf.getNioParams().getNbIoThreads()).isEqualTo(2); + assertThat(cf.getNioParams().getWriteEnqueuingTimeoutInMs()).isEqualTo(5000); + assertThat(cf.getNioParams().getWriteQueueCapacity()).isEqualTo(1000); } private Properties getPropertiesWitPrefix(String prefix) throws IOException { diff --git a/src/test/java/com/rabbitmq/client/test/RpcTest.java b/src/test/java/com/rabbitmq/client/test/RpcTest.java index 87d0be518b..a11544f2b4 100644 --- a/src/test/java/com/rabbitmq/client/test/RpcTest.java +++ b/src/test/java/com/rabbitmq/client/test/RpcTest.java @@ -39,7 +39,7 @@ import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; -import static org.awaitility.Awaitility.waitAtMost; +import static com.rabbitmq.client.test.TestUtils.waitAtMost; import static org.junit.Assert.*; public class RpcTest { @@ -320,7 +320,7 @@ public void handleRecoveryStarted(Recoverable recoverable) { serverThread.interrupt(); - waitAtMost(Duration.ofSeconds(1)).until(() -> !serverThread.isAlive()) ; + waitAtMost(Duration.ofSeconds(1), () -> !serverThread.isAlive()); client.close(); } diff --git a/src/test/java/com/rabbitmq/client/test/StrictExceptionHandlerTest.java b/src/test/java/com/rabbitmq/client/test/StrictExceptionHandlerTest.java index 300d8ad053..06bf5efe7c 100644 --- a/src/test/java/com/rabbitmq/client/test/StrictExceptionHandlerTest.java +++ b/src/test/java/com/rabbitmq/client/test/StrictExceptionHandlerTest.java @@ -28,9 +28,8 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; public class StrictExceptionHandlerTest { @@ -58,7 +57,7 @@ public void handleConsumerException(Channel channel, Throwable exception, Consum channel )); channel.basicPublish("", queue, null, new byte[0]); - assertThat(latch.await(5, TimeUnit.SECONDS), is(true)); + assertThat(latch.await(5, TimeUnit.SECONDS)).isTrue(); } } diff --git a/src/test/java/com/rabbitmq/client/test/TestUtils.java b/src/test/java/com/rabbitmq/client/test/TestUtils.java index 012882d3f4..b6cec91132 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtils.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtils.java @@ -19,6 +19,7 @@ import com.rabbitmq.client.impl.NetworkConnection; import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; import com.rabbitmq.tools.Host; +import org.assertj.core.api.Assertions; import org.junit.AssumptionViolatedException; import org.junit.rules.TestRule; import org.junit.runner.Description; @@ -29,6 +30,7 @@ import java.io.IOException; import java.net.ServerSocket; import java.security.NoSuchAlgorithmException; +import java.time.Duration; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -36,6 +38,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import java.util.function.BooleanSupplier; import static org.junit.Assert.assertTrue; @@ -53,6 +56,28 @@ public static ConnectionFactory connectionFactory() { return connectionFactory; } + public static void waitAtMost(Duration timeout, BooleanSupplier condition) { + if (condition.getAsBoolean()) { + return; + } + int waitTime = 100; + int waitedTime = 0; + long timeoutInMs = timeout.toMillis(); + while (waitedTime <= timeoutInMs) { + try { + Thread.sleep(waitTime); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException(e); + } + if (condition.getAsBoolean()) { + return; + } + waitedTime += waitTime; + } + Assertions.fail("Waited " + timeout.getSeconds() + " second(s), condition never got true"); + } + public static void close(Connection connection) { if (connection != null) { try { diff --git a/src/test/java/com/rabbitmq/client/test/TestUtilsTest.java b/src/test/java/com/rabbitmq/client/test/TestUtilsTest.java index 1de1fe975a..76e5276d7d 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtilsTest.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtilsTest.java @@ -16,13 +16,12 @@ package com.rabbitmq.client.test; import com.rabbitmq.client.Connection; +import org.assertj.core.api.Assertions; import org.junit.Test; import java.util.HashMap; import java.util.Map; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -35,13 +34,13 @@ public void isVersion37orLater() { when(connection.getServerProperties()).thenReturn(serverProperties); serverProperties.put("version", "3.7.0+rc.1.4.gedc5d96"); - assertThat(TestUtils.isVersion37orLater(connection), is(true)); + Assertions.assertThat(TestUtils.isVersion37orLater(connection)).isTrue(); serverProperties.put("version", "3.7.0~alpha.449-1"); - assertThat(TestUtils.isVersion37orLater(connection), is(true)); + Assertions.assertThat(TestUtils.isVersion37orLater(connection)).isTrue(); serverProperties.put("version", "3.7.1-alpha.40"); - assertThat(TestUtils.isVersion37orLater(connection), is(true)); + Assertions.assertThat(TestUtils.isVersion37orLater(connection)).isTrue(); } @Test @@ -51,15 +50,15 @@ public void isVersion38orLater() { when(connection.getServerProperties()).thenReturn(serverProperties); serverProperties.put("version", "3.7.0+rc.1.4.gedc5d96"); - assertThat(TestUtils.isVersion38orLater(connection), is(false)); + Assertions.assertThat(TestUtils.isVersion38orLater(connection)).isFalse(); serverProperties.put("version", "3.7.0~alpha.449-1"); - assertThat(TestUtils.isVersion38orLater(connection), is(false)); + Assertions.assertThat(TestUtils.isVersion38orLater(connection)).isFalse(); serverProperties.put("version", "3.7.1-alpha.40"); - assertThat(TestUtils.isVersion38orLater(connection), is(false)); + Assertions.assertThat(TestUtils.isVersion38orLater(connection)).isFalse(); serverProperties.put("version", "3.8.0+beta.4.38.g33a7f97"); - assertThat(TestUtils.isVersion38orLater(connection), is(true)); + Assertions.assertThat(TestUtils.isVersion38orLater(connection)).isTrue(); } } diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java index 486e5448ce..426e3c2c0f 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -40,9 +40,8 @@ import java.util.concurrent.atomic.AtomicReference; import static com.rabbitmq.client.test.TestUtils.prepareForRecovery; -import static org.hamcrest.Matchers.greaterThanOrEqualTo; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; @SuppressWarnings("ThrowFromFinallyBlock") public class ConnectionRecovery extends BrokerTestCase { @@ -51,9 +50,9 @@ public class ConnectionRecovery extends BrokerTestCase { private static final int MANY_DECLARATIONS_LOOP_COUNT = 500; @Test public void connectionRecovery() throws IOException, InterruptedException { - assertTrue(connection.isOpen()); + assertThat(connection.isOpen()).isTrue(); closeAndWaitForRecovery(); - assertTrue(connection.isOpen()); + assertThat(connection.isOpen()).isTrue(); } @Test public void namedConnectionRecovery() @@ -61,20 +60,20 @@ public class ConnectionRecovery extends BrokerTestCase { String connectionName = "custom name"; RecoverableConnection c = newRecoveringConnection(connectionName); try { - assertTrue(c.isOpen()); - assertEquals(connectionName, c.getClientProvidedName()); + assertThat(c.isOpen()).isTrue(); + assertThat(connectionName).isEqualTo(c.getClientProvidedName()); TestUtils.closeAndWaitForRecovery(c); - assertTrue(c.isOpen()); - assertEquals(connectionName, c.getClientProvidedName()); + assertThat(c.isOpen()).isTrue(); + assertThat(connectionName).isEqualTo(c.getClientProvidedName()); } finally { c.abort(); } } @Test public void connectionRecoveryWithServerRestart() throws IOException, InterruptedException { - assertTrue(connection.isOpen()); + assertThat(connection.isOpen()).isTrue(); restartPrimaryAndWaitForRecovery(); - assertTrue(connection.isOpen()); + assertThat(connection.isOpen()).isTrue(); } @Test public void connectionRecoveryWithArrayOfAddresses() @@ -82,9 +81,9 @@ public class ConnectionRecovery extends BrokerTestCase { final Address[] addresses = {new Address("127.0.0.1"), new Address("127.0.0.1", 5672)}; RecoverableConnection c = newRecoveringConnection(addresses); try { - assertTrue(c.isOpen()); + assertThat(c.isOpen()).isTrue(); TestUtils.closeAndWaitForRecovery(c); - assertTrue(c.isOpen()); + assertThat(c.isOpen()).isTrue(); } finally { c.abort(); } @@ -98,9 +97,9 @@ public class ConnectionRecovery extends BrokerTestCase { RecoverableConnection c = newRecoveringConnection(addresses); try { - assertTrue(c.isOpen()); + assertThat(c.isOpen()).isTrue(); TestUtils.closeAndWaitForRecovery(c); - assertTrue(c.isOpen()); + assertThat(c.isOpen()).isTrue(); } finally { c.abort(); } @@ -113,14 +112,14 @@ public class ConnectionRecovery extends BrokerTestCase { String q = "java-client.test.recovery.q2"; ch.queueDeclare(q, false, true, false, null); ch.queueDeclarePassive(q); - assertTrue(c.isOpen()); + assertThat(c.isOpen()).isTrue(); try { CountDownLatch shutdownLatch = prepareForShutdown(c); CountDownLatch recoveryLatch = prepareForRecovery(c); Host.closeConnection((NetworkConnection) c); wait(shutdownLatch); wait(recoveryLatch); - assertTrue(c.isOpen()); + assertThat(c.isOpen()).isTrue(); ch.queueDeclarePassive(q); fail("expected passive declaration to throw"); } catch (java.io.IOException e) { @@ -154,15 +153,15 @@ public String getPassword() { }); RecoverableConnection c = (RecoverableConnection) cf.newConnection(); try { - assertTrue(c.isOpen()); - assertThat(usernameRequested.get(), is(1)); - assertThat(passwordRequested.get(), is(1)); + assertThat(c.isOpen()).isTrue(); + assertThat(usernameRequested.get()).isEqualTo(1); + assertThat(passwordRequested.get()).isEqualTo(1); TestUtils.closeAndWaitForRecovery(c); - assertTrue(c.isOpen()); + assertThat(c.isOpen()).isTrue(); // username is requested in AMQConnection#toString, so it can be accessed at any time - assertThat(usernameRequested.get(), greaterThanOrEqualTo(2)); - assertThat(passwordRequested.get(), is(2)); + assertThat(usernameRequested.get()).isGreaterThanOrEqualTo(2); + assertThat(passwordRequested.get()).isEqualTo(2); } finally { c.abort(); } @@ -204,13 +203,13 @@ public void handleRecoveryStarted(Recoverable recoverable) { latch.countDown(); } }); - assertTrue(connection.isOpen()); + assertThat(connection.isOpen()).isTrue(); closeAndWaitForRecovery(); - assertTrue(connection.isOpen()); - assertEquals("shutdown hook 1", events.get(0)); - assertEquals("shutdown hook 2", events.get(1)); + assertThat(connection.isOpen()).isTrue(); + assertThat(events).element(0).isEqualTo("shutdown hook 1"); + assertThat(events).element(1).isEqualTo("shutdown hook 2"); recoveryCanBeginLatch.await(5, TimeUnit.SECONDS); - assertEquals("recovery start hook 1", events.get(2)); + assertThat(events).element(2).isEqualTo("recovery start hook 1"); connection.close(); wait(latch); } @@ -223,9 +222,9 @@ public void shutdownCompleted(ShutdownSignalException cause) { latch.countDown(); } }); - assertTrue(connection.isOpen()); + assertThat(connection.isOpen()).isTrue(); closeAndWaitForRecovery(); - assertTrue(connection.isOpen()); + assertThat(connection.isOpen()).isTrue(); connection.close(); wait(latch); } @@ -238,11 +237,11 @@ public void shutdownCompleted(ShutdownSignalException cause) { latch.countDown(); } }); - assertTrue(connection.isOpen()); + assertThat(connection.isOpen()).isTrue(); closeAndWaitForRecovery(); - assertTrue(connection.isOpen()); + assertThat(connection.isOpen()).isTrue(); closeAndWaitForRecovery(); - assertTrue(connection.isOpen()); + assertThat(connection.isOpen()).isTrue(); connection.close(); wait(latch); } @@ -271,8 +270,8 @@ public void handleUnblocked() throws IOException { Channel ch1 = connection.createChannel(); Channel ch2 = connection.createChannel(); - assertTrue(ch1.isOpen()); - assertTrue(ch2.isOpen()); + assertThat(ch1.isOpen()).isTrue(); + assertThat(ch2.isOpen()).isTrue(); closeAndWaitForRecovery(); expectChannelRecovery(ch1); expectChannelRecovery(ch2); @@ -391,7 +390,7 @@ private void testClientNamedQueueRecoveryWith(String q, boolean noWait) throws I ch.basicPublish(x, "", null, "msg".getBytes()); waitForConfirms(ch); AMQP.Queue.DeclareOk ok = ch.queueDeclare(q, false, false, true, null); - assertEquals(1, ok.getMessageCount()); + assertThat(ok.getMessageCount()).isEqualTo(1); ch.queueDelete(q); ch.exchangeDelete(x); } @@ -422,7 +421,7 @@ public void queueRecovered(String oldName, String newName) { ch.basicPublish(x, "", null, "msg".getBytes()); waitForConfirms(ch); AMQP.Queue.DeclareOk ok = ch.queueDeclarePassive(nameAfter.get()); - assertEquals(1, ok.getMessageCount()); + assertThat(ok.getMessageCount()).isEqualTo(1); ch.queueDelete(nameAfter.get()); ch.exchangeDelete(x); } @@ -511,13 +510,10 @@ public void queueRecovered(String oldName, String newName) { final AtomicReference nameBefore = new AtomicReference(); final AtomicReference nameAfter = new AtomicReference(); final CountDownLatch listenerLatch = new CountDownLatch(1); - ((AutorecoveringConnection)connection).addQueueRecoveryListener(new QueueRecoveryListener() { - @Override - public void queueRecovered(String oldName, String newName) { - nameBefore.set(oldName); - nameAfter.set(newName); - listenerLatch.countDown(); - } + ((AutorecoveringConnection)connection).addQueueRecoveryListener((oldName, newName) -> { + nameBefore.set(oldName); + nameAfter.set(newName); + listenerLatch.countDown(); }); closeAndWaitForRecovery(); @@ -525,7 +521,7 @@ public void queueRecovered(String oldName, String newName) { expectChannelRecovery(channel); channel.basicPublish(x, "", null, "msg".getBytes()); assertDelivered(q, 1); - assertFalse(nameBefore.get().equals(nameAfter.get())); + assertThat(nameBefore).doesNotHaveValue(nameAfter.get()); channel.queueDelete(q); } @@ -620,11 +616,11 @@ public void queueRecovered(String oldName, String newName) { channel.queueDeclare(q, true, false, false, null); // now delete it using the delegate so AutorecoveringConnection and AutorecoveringChannel are not aware of it ((AutorecoveringChannel)channel).getDelegate().queueDelete(q); - assertNotNull(((AutorecoveringConnection)connection).getRecordedQueues().get(q)); + assertThat(((AutorecoveringConnection)connection).getRecordedQueues().get(q)).isNotNull(); // exclude the queue from recovery ((AutorecoveringConnection)connection).excludeQueueFromRecovery(q, true); // verify its not there - assertNull(((AutorecoveringConnection)connection).getRecordedQueues().get(q)); + assertThat(((AutorecoveringConnection)connection).getRecordedQueues().get(q)).isNull(); // reconnect closeAndWaitForRecovery(); expectChannelRecovery(channel); @@ -669,7 +665,7 @@ public void consumerRecovered(String oldConsumerTag, String newConsumerTag) { assertConsumerCount(n, q); closeAndWaitForRecovery(); wait(listenerLatch); - assertTrue(tagA.get().equals(tagB.get())); + assertThat(tagA.get().equals(tagB.get())).isTrue(); expectChannelRecovery(channel); assertConsumerCount(n, q); @@ -721,8 +717,8 @@ public void handleRecoveryStarted(Recoverable recoverable) { RecoverableChannel ch2 = (RecoverableChannel) connection.createChannel(); ch2.addRecoveryListener(listener); - assertTrue(ch1.isOpen()); - assertTrue(ch2.isOpen()); + assertThat(ch1.isOpen()).isTrue(); + assertThat(ch2.isOpen()).isTrue(); closeAndWaitForRecovery(); expectChannelRecovery(ch1); expectChannelRecovery(ch2); @@ -777,23 +773,23 @@ public void handleDelivery(String consumerTag, Channel channel1 = connection.createChannel(); Channel channel2 = connection.createChannel(); - assertEquals(0, connectionConsumers.size()); + assertThat(connectionConsumers).isEmpty(); String queue = channel1.queueDeclare().getQueue(); - channel1.basicConsume(queue, true, new HashMap(), new DefaultConsumer(channel1)); - assertEquals(1, connectionConsumers.size()); - channel1.basicConsume(queue, true, new HashMap(), new DefaultConsumer(channel1)); - assertEquals(2, connectionConsumers.size()); + channel1.basicConsume(queue, true, new HashMap<>(), new DefaultConsumer(channel1)); + assertThat(connectionConsumers).hasSize(1); + channel1.basicConsume(queue, true, new HashMap<>(), new DefaultConsumer(channel1)); + assertThat(connectionConsumers).hasSize(2); - channel2.basicConsume(queue, true, new HashMap(), new DefaultConsumer(channel2)); - assertEquals(3, connectionConsumers.size()); + channel2.basicConsume(queue, true, new HashMap<>(), new DefaultConsumer(channel2)); + assertThat(connectionConsumers).hasSize(3); channel1.close(); - assertEquals(3 - 2, connectionConsumers.size()); + assertThat(connectionConsumers).hasSize(3 - 2); channel2.close(); - assertEquals(0, connectionConsumers.size()); + assertThat(connectionConsumers).isEmpty(); } finally { connection.abort(); } @@ -804,9 +800,9 @@ public void handleDelivery(String consumerTag, connectionFactory.setRecoveryDelayHandler(new RecoveryDelayHandler.ExponentialBackoffDelayHandler()); Connection testConnection = connectionFactory.newConnection(); try { - assertTrue(testConnection.isOpen()); + assertThat(testConnection.isOpen()).isTrue(); TestUtils.closeAndWaitForRecovery((RecoverableConnection) testConnection); - assertTrue(testConnection.isOpen()); + assertThat(testConnection.isOpen()).isTrue(); } finally { connection.close(); } @@ -817,9 +813,9 @@ public void handleDelivery(String consumerTag, final ThreadPoolExecutor executor = new ThreadPoolExecutor(8, 8, 30, TimeUnit.SECONDS, new LinkedBlockingQueue()); executor.allowCoreThreadTimeOut(true); ConnectionFactory connectionFactory = buildConnectionFactoryWithRecoveryEnabled(false); - assertNull(connectionFactory.getTopologyRecoveryExecutor()); + assertThat(connectionFactory.getTopologyRecoveryExecutor()).isNull(); connectionFactory.setTopologyRecoveryExecutor(executor); - assertEquals(executor, connectionFactory.getTopologyRecoveryExecutor()); + assertThat(connectionFactory.getTopologyRecoveryExecutor()).isEqualTo(executor); RecoverableConnection testConnection = (RecoverableConnection) connectionFactory.newConnection(); try { final List channels = new ArrayList(); @@ -864,7 +860,7 @@ public void handleDelivery(String consumerTag, Envelope envelope, BasicPropertie } } // verify all queues/consumers got it - assertTrue(latch.await(30, TimeUnit.SECONDS)); + assertThat(latch.await(30, TimeUnit.SECONDS)).isTrue(); // cleanup Channel cleanupChannel = testConnection.createChannel(); @@ -878,7 +874,7 @@ public void handleDelivery(String consumerTag, Envelope envelope, BasicPropertie } private void assertConsumerCount(int exp, String q) throws IOException { - assertEquals(exp, channel.queueDeclarePassive(q).getConsumerCount()); + assertThat(channel.queueDeclarePassive(q).getConsumerCount()).isEqualTo(exp); } private static AMQP.Queue.DeclareOk declareClientNamedQueue(Channel ch, String q) throws IOException { @@ -906,11 +902,11 @@ private static void expectQueueRecovery(Channel ch, String q) throws IOException ch.confirmSelect(); ch.queuePurge(q); AMQP.Queue.DeclareOk ok1 = declareClientNamedQueue(ch, q); - assertEquals(0, ok1.getMessageCount()); + assertThat(ok1.getMessageCount()).isEqualTo(0); ch.basicPublish("", q, null, "msg".getBytes()); waitForConfirms(ch); AMQP.Queue.DeclareOk ok2 = declareClientNamedQueue(ch, q); - assertEquals(1, ok2.getMessageCount()); + assertThat(ok2.getMessageCount()).isEqualTo(1); } private static void expectAutoDeleteQueueAndBindingRecovery(Channel ch, String x, String q) throws IOException, InterruptedException, @@ -918,12 +914,12 @@ private static void expectAutoDeleteQueueAndBindingRecovery(Channel ch, String x ch.confirmSelect(); ch.queuePurge(q); AMQP.Queue.DeclareOk ok1 = declareClientNamedAutoDeleteQueue(ch, q); - assertEquals(0, ok1.getMessageCount()); + assertThat(ok1.getMessageCount()).isEqualTo(0); ch.exchangeDeclare(x, "fanout"); ch.basicPublish(x, "", null, "msg".getBytes()); waitForConfirms(ch); AMQP.Queue.DeclareOk ok2 = declareClientNamedAutoDeleteQueue(ch, q); - assertEquals(1, ok2.getMessageCount()); + assertThat(ok2.getMessageCount()).isEqualTo(1); } private static void expectExchangeRecovery(Channel ch, String x) throws IOException, InterruptedException, TimeoutException { @@ -964,7 +960,7 @@ private void restartPrimaryAndWaitForRecovery(Connection connection) throws IOEx } private static void expectChannelRecovery(Channel ch) { - assertTrue(ch.isOpen()); + assertThat(ch.isOpen()).isTrue(); } @Override @@ -1020,7 +1016,7 @@ private static ConnectionFactory buildConnectionFactoryWithRecoveryEnabled(boole private static void wait(CountDownLatch latch) throws InterruptedException { // we want to wait for recovery to complete for a reasonable amount of time // but still make recovery failures easy to notice in development environments - assertTrue(latch.await(90, TimeUnit.SECONDS)); + assertThat(latch.await(90, TimeUnit.SECONDS)).isTrue(); } private static void waitForConfirms(Channel ch) throws InterruptedException, TimeoutException { @@ -1028,10 +1024,10 @@ private static void waitForConfirms(Channel ch) throws InterruptedException, Tim } private static void assertRecordedQueues(Connection conn, int size) { - assertEquals(size, ((AutorecoveringConnection)conn).getRecordedQueues().size()); + assertThat(((AutorecoveringConnection)conn).getRecordedQueues()).hasSize(size); } private static void assertRecordedExchanges(Connection conn, int size) { - assertEquals(size, ((AutorecoveringConnection)conn).getRecordedExchanges().size()); + assertThat(((AutorecoveringConnection)conn).getRecordedExchanges()).hasSize(size); } } diff --git a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java index 98b82ed7af..3e2dc6df74 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java @@ -49,11 +49,8 @@ import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; -import static org.awaitility.Awaitility.waitAtMost; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; +import static com.rabbitmq.client.test.TestUtils.waitAtMost; +import static org.assertj.core.api.Assertions.assertThat; /** * @@ -88,51 +85,51 @@ protected void releaseResources() throws IOException { Connection connection2 = null; try { connection1 = connectionFactory.newConnection(); - assertThat(metrics.getConnections().getCount(), is(1L)); + assertThat(metrics.getConnections().getCount()).isEqualTo(1L); connection1.createChannel(); connection1.createChannel(); Channel channel = connection1.createChannel(); - assertThat(metrics.getChannels().getCount(), is(3L)); + assertThat(metrics.getChannels().getCount()).isEqualTo(3L); sendMessage(channel); - assertThat(metrics.getPublishedMessages().getCount(), is(1L)); + assertThat(metrics.getPublishedMessages().getCount()).isEqualTo(1L); sendMessage(channel); - assertThat(metrics.getPublishedMessages().getCount(), is(2L)); + assertThat(metrics.getPublishedMessages().getCount()).isEqualTo(2L); channel.basicGet(QUEUE, true); - assertThat(metrics.getConsumedMessages().getCount(), is(1L)); + assertThat(metrics.getConsumedMessages().getCount()).isEqualTo(1L); channel.basicGet(QUEUE, true); - assertThat(metrics.getConsumedMessages().getCount(), is(2L)); + assertThat(metrics.getConsumedMessages().getCount()).isEqualTo(2L); channel.basicGet(QUEUE, true); - assertThat(metrics.getConsumedMessages().getCount(), is(2L)); + assertThat(metrics.getConsumedMessages().getCount()).isEqualTo(2L); connection2 = connectionFactory.newConnection(); - assertThat(metrics.getConnections().getCount(), is(2L)); + assertThat(metrics.getConnections().getCount()).isEqualTo(2L); connection2.createChannel(); channel = connection2.createChannel(); - assertThat(metrics.getChannels().getCount(), is(3L+2L)); + assertThat(metrics.getChannels().getCount()).isEqualTo(3L+2L); sendMessage(channel); sendMessage(channel); - assertThat(metrics.getPublishedMessages().getCount(), is(2L+2L)); + assertThat(metrics.getPublishedMessages().getCount()).isEqualTo(2L+2L); channel.basicGet(QUEUE, true); - assertThat(metrics.getConsumedMessages().getCount(), is(2L+1L)); + assertThat(metrics.getConsumedMessages().getCount()).isEqualTo(2L+1L); channel.basicConsume(QUEUE, true, new DefaultConsumer(channel)); - waitAtMost(timeout()).until(() -> metrics.getConsumedMessages().getCount(), equalTo(2L+1L+1L)); + waitAtMost(timeout(), () -> metrics.getConsumedMessages().getCount() == 2L+1L+1L); safeClose(connection1); - waitAtMost(timeout()).until(() -> metrics.getConnections().getCount(), equalTo(1L)); - waitAtMost(timeout()).until(() -> metrics.getChannels().getCount(), equalTo(2L)); + waitAtMost(timeout(), () -> metrics.getConnections().getCount() == 1L); + waitAtMost(timeout(), () -> metrics.getChannels().getCount() == 2L); safeClose(connection2); - waitAtMost(timeout()).until(() -> metrics.getConnections().getCount(), equalTo(0L)); - waitAtMost(timeout()).until(() -> metrics.getChannels().getCount(), equalTo(0L)); + waitAtMost(timeout(), () -> metrics.getConnections().getCount() == 0L); + waitAtMost(timeout(), () -> metrics.getChannels().getCount() == 0L); - assertThat(metrics.getAcknowledgedMessages().getCount(), is(0L)); - assertThat(metrics.getRejectedMessages().getCount(), is(0L)); + assertThat(metrics.getAcknowledgedMessages().getCount()).isEqualTo(0L); + assertThat(metrics.getRejectedMessages().getCount()).isEqualTo(0L); } finally { safeClose(connection1); @@ -148,7 +145,7 @@ protected void releaseResources() throws IOException { connection = connectionFactory.newConnection(); Channel channel = connection.createChannel(); channel.confirmSelect(); - assertThat(metrics.getPublishUnroutedMessages().getCount(), is(0L)); + assertThat(metrics.getPublishUnroutedMessages().getCount()).isEqualTo(0L); // when channel.basicPublish( "amq.direct", @@ -158,10 +155,7 @@ protected void releaseResources() throws IOException { "any-message".getBytes() ); // then - waitAtMost(timeout()).until( - () -> metrics.getPublishUnroutedMessages().getCount(), - equalTo(1L) - ); + waitAtMost(timeout(), () -> metrics.getPublishUnroutedMessages().getCount() == 1L); } finally { safeClose(connection); } @@ -175,13 +169,13 @@ protected void releaseResources() throws IOException { connection = connectionFactory.newConnection(); Channel channel = connection.createChannel(); channel.confirmSelect(); - assertThat(metrics.getPublishAcknowledgedMessages().getCount(), is(0L)); + assertThat(metrics.getPublishAcknowledgedMessages().getCount()).isEqualTo(0L); channel.basicConsume(QUEUE, false, new MultipleAckConsumer(channel, false)); // when sendMessage(channel); channel.waitForConfirms(30 * 60 * 1000); // then - assertThat(metrics.getPublishAcknowledgedMessages().getCount(), is(1L)); + assertThat(metrics.getPublishAcknowledgedMessages().getCount()).isEqualTo(1L); } finally { safeClose(connection); } @@ -200,8 +194,8 @@ protected void releaseResources() throws IOException { sendMessage(channel1); GetResponse getResponse = channel1.basicGet(QUEUE, false); channel1.basicAck(getResponse.getEnvelope().getDeliveryTag(), false); - assertThat(metrics.getConsumedMessages().getCount(), is(1L)); - assertThat(metrics.getAcknowledgedMessages().getCount(), is(1L)); + assertThat(metrics.getConsumedMessages().getCount()).isEqualTo(1L); + assertThat(metrics.getAcknowledgedMessages().getCount()).isEqualTo(1L); // basicGet / basicAck sendMessage(channel1); @@ -218,18 +212,18 @@ protected void releaseResources() throws IOException { GetResponse response5 = channel1.basicGet(QUEUE, false); GetResponse response6 = channel2.basicGet(QUEUE, false); - assertThat(metrics.getConsumedMessages().getCount(), is(1L+6L)); - assertThat(metrics.getAcknowledgedMessages().getCount(), is(1L)); + assertThat(metrics.getConsumedMessages().getCount()).isEqualTo(1L+6L); + assertThat(metrics.getAcknowledgedMessages().getCount()).isEqualTo(1L); channel1.basicAck(response5.getEnvelope().getDeliveryTag(), false); - assertThat(metrics.getAcknowledgedMessages().getCount(), is(1L+1L)); + assertThat(metrics.getAcknowledgedMessages().getCount()).isEqualTo(1L+1L); channel1.basicAck(response3.getEnvelope().getDeliveryTag(), true); - assertThat(metrics.getAcknowledgedMessages().getCount(), is(1L+1L+2L)); + assertThat(metrics.getAcknowledgedMessages().getCount()).isEqualTo(1L+1L+2L); channel2.basicAck(response2.getEnvelope().getDeliveryTag(), true); - assertThat(metrics.getAcknowledgedMessages().getCount(), is(1L+(1L+2L)+1L)); + assertThat(metrics.getAcknowledgedMessages().getCount()).isEqualTo(1L+(1L+2L)+1L); channel2.basicAck(response6.getEnvelope().getDeliveryTag(), true); - assertThat(metrics.getAcknowledgedMessages().getCount(), is(1L+(1L+2L)+1L+2L)); + assertThat(metrics.getAcknowledgedMessages().getCount()).isEqualTo(1L+(1L+2L)+1L+2L); long alreadySentMessages = 1+(1+2)+1+2; @@ -244,15 +238,9 @@ protected void releaseResources() throws IOException { sendMessage(i%2 == 0 ? channel1 : channel2); } - waitAtMost(timeout()).until( - () -> metrics.getConsumedMessages().getCount(), - equalTo(alreadySentMessages+nbMessages) - ); + waitAtMost(timeout(), () -> metrics.getConsumedMessages().getCount() == alreadySentMessages+nbMessages); - waitAtMost(timeout()).until( - () -> metrics.getAcknowledgedMessages().getCount(), - equalTo(alreadySentMessages+nbMessages) - ); + waitAtMost(timeout(), () -> metrics.getAcknowledgedMessages().getCount() == alreadySentMessages+nbMessages); } finally { safeClose(connection); @@ -277,10 +265,10 @@ protected void releaseResources() throws IOException { GetResponse response3 = channel.basicGet(QUEUE, false); channel.basicReject(response2.getEnvelope().getDeliveryTag(), false); - assertThat(metrics.getRejectedMessages().getCount(), is(1L)); + assertThat(metrics.getRejectedMessages().getCount()).isEqualTo(1L); channel.basicNack(response3.getEnvelope().getDeliveryTag(), true, false); - assertThat(metrics.getRejectedMessages().getCount(), is(1L+2L)); + assertThat(metrics.getRejectedMessages().getCount()).isEqualTo(1L+2L); } finally { safeClose(connection); } @@ -326,9 +314,9 @@ protected void releaseResources() throws IOException { } executorService.invokeAll(tasks); - assertThat(metrics.getPublishedMessages().getCount(), is(nbOfMessages)); - waitAtMost(timeout()).until(() -> metrics.getConsumedMessages().getCount(), equalTo(nbOfMessages)); - assertThat(metrics.getAcknowledgedMessages().getCount(), is(0L)); + assertThat(metrics.getPublishedMessages().getCount()).isEqualTo(nbOfMessages); + waitAtMost(timeout(), () -> metrics.getConsumedMessages().getCount() == nbOfMessages); + assertThat(metrics.getAcknowledgedMessages().getCount()).isEqualTo(0L); // to remove the listeners for(int i = 0; i < nbChannels; i++) { @@ -355,9 +343,9 @@ protected void releaseResources() throws IOException { } executorService.invokeAll(tasks); - assertThat(metrics.getPublishedMessages().getCount(), is(2*nbOfMessages)); - waitAtMost(timeout()).until(() -> metrics.getConsumedMessages().getCount(), equalTo(2*nbOfMessages)); - waitAtMost(timeout()).until(() -> metrics.getAcknowledgedMessages().getCount(), equalTo(nbOfMessages)); + assertThat(metrics.getPublishedMessages().getCount()).isEqualTo(2*nbOfMessages); + waitAtMost(timeout(), () -> metrics.getConsumedMessages().getCount() == 2*nbOfMessages); + waitAtMost(timeout(), () -> metrics.getAcknowledgedMessages().getCount() == nbOfMessages); // to remove the listeners for(int i = 0; i < nbChannels; i++) { @@ -384,10 +372,10 @@ protected void releaseResources() throws IOException { } executorService.invokeAll(tasks); - assertThat(metrics.getPublishedMessages().getCount(), is(3*nbOfMessages)); - waitAtMost(timeout()).until(() -> metrics.getConsumedMessages().getCount(), equalTo(3*nbOfMessages)); - waitAtMost(timeout()).until(() -> metrics.getAcknowledgedMessages().getCount(), equalTo(nbOfMessages)); - waitAtMost(timeout()).until(() -> metrics.getRejectedMessages().getCount(), equalTo(nbOfMessages)); + assertThat(metrics.getPublishedMessages().getCount()).isEqualTo(3*nbOfMessages); + waitAtMost(timeout(), () -> metrics.getConsumedMessages().getCount() == 3*nbOfMessages); + waitAtMost(timeout(), () -> metrics.getAcknowledgedMessages().getCount() == nbOfMessages); + waitAtMost(timeout(), () -> metrics.getRejectedMessages().getCount() == nbOfMessages); } finally { for (Connection connection : connections) { safeClose(connection); @@ -405,13 +393,13 @@ protected void releaseResources() throws IOException { connection = connectionFactory.newConnection(); Channel channel = connection.createChannel(); - assertThat(metrics.getConnections().getCount(), is(1L)); - assertThat(metrics.getChannels().getCount(), is(1L)); + assertThat(metrics.getConnections().getCount()).isEqualTo(1L); + assertThat(metrics.getChannels().getCount()).isEqualTo(1L); channel.basicPublish("unlikelynameforanexchange", "", null, "msg".getBytes("UTF-8")); - waitAtMost(timeout()).until(() -> metrics.getChannels().getCount(), is(0L)); - assertThat(metrics.getConnections().getCount(), is(1L)); + waitAtMost(timeout(), () -> metrics.getChannels().getCount() == 0L); + assertThat(metrics.getConnections().getCount()).isEqualTo(1L); } finally { safeClose(connection); } @@ -429,19 +417,19 @@ protected void releaseResources() throws IOException { connection = connectionFactory.newConnection(); Collection shutdownHooks = getShutdownHooks(connection); - assertThat(shutdownHooks.size(), is(0)); + assertThat(shutdownHooks.size()).isEqualTo(0); connection.createChannel(); - assertThat(metrics.getConnections().getCount(), is(1L)); - assertThat(metrics.getChannels().getCount(), is(1L)); + assertThat(metrics.getConnections().getCount()).isEqualTo(1L); + assertThat(metrics.getChannels().getCount()).isEqualTo(1L); closeAndWaitForRecovery((AutorecoveringConnection) connection); - assertThat(metrics.getConnections().getCount(), is(1L)); - assertThat(metrics.getChannels().getCount(), is(1L)); + assertThat(metrics.getConnections().getCount()).isEqualTo(1L); + assertThat(metrics.getChannels().getCount()).isEqualTo(1L); - assertThat(shutdownHooks.size(), is(0)); + assertThat(shutdownHooks.size()).isEqualTo(0); } finally { safeClose(connection); } @@ -482,10 +470,10 @@ protected void releaseResources() throws IOException { sendMessage(channel2); } - waitAtMost(timeout()).until(() -> ackedMessages.get(), equalTo(nbMessages * 2)); + waitAtMost(timeout(), () -> ackedMessages.get() == nbMessages * 2); - assertThat(metrics.getConsumedMessages().getCount(), is((long) (nbMessages * 2))); - assertThat(metrics.getAcknowledgedMessages().getCount(), is((long) (nbMessages * 2))); + assertThat(metrics.getConsumedMessages().getCount()).isEqualTo((long) (nbMessages * 2)); + assertThat(metrics.getAcknowledgedMessages().getCount()).isEqualTo((long) (nbMessages * 2)); } finally { safeClose(connection); @@ -517,7 +505,7 @@ public void handleRecoveryStarted(Recoverable recoverable) { } }); Host.closeConnection(connection); - assertTrue(latch.await(5, TimeUnit.SECONDS)); + assertThat(latch.await(5, TimeUnit.SECONDS)).isTrue(); } private Collection getShutdownHooks(Connection connection) throws NoSuchFieldException, IllegalAccessException { diff --git a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java index e8c3ff1148..27c210639c 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java +++ b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java @@ -32,17 +32,13 @@ import org.junit.Test; import java.io.IOException; +import java.time.Duration; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; -import static com.rabbitmq.client.test.TestUtils.closeAndWaitForRecovery; -import static com.rabbitmq.client.test.TestUtils.exchangeExists; -import static com.rabbitmq.client.test.TestUtils.queueExists; -import static com.rabbitmq.client.test.TestUtils.sendAndConsumeMessage; -import static org.awaitility.Awaitility.waitAtMost; -import static org.hamcrest.Matchers.is; +import static com.rabbitmq.client.test.TestUtils.*; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -147,7 +143,7 @@ public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProp } }); ch.basicPublish("topology.recovery.exchange", "recovered.consumer", null, "".getBytes()); - waitAtMost(5, TimeUnit.SECONDS).untilAtomic(recoveredConsumerMessageCount, is(1)); + waitAtMost(Duration.ofSeconds(5), () -> recoveredConsumerMessageCount.get() == 1); final AtomicInteger filteredConsumerMessageCount = new AtomicInteger(0); final CountDownLatch filteredConsumerLatch = new CountDownLatch(2); @@ -160,13 +156,13 @@ public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProp } }); ch.basicPublish("topology.recovery.exchange", "filtered.consumer", null, "".getBytes()); - waitAtMost(5, TimeUnit.SECONDS).untilAtomic(filteredConsumerMessageCount, is(1)); + waitAtMost(Duration.ofSeconds(5), () -> filteredConsumerMessageCount.get() == 1); closeAndWaitForRecovery((RecoverableConnection) c); int initialCount = recoveredConsumerMessageCount.get(); ch.basicPublish("topology.recovery.exchange", "recovered.consumer", null, "".getBytes()); - waitAtMost(5, TimeUnit.SECONDS).untilAtomic(recoveredConsumerMessageCount, is(initialCount + 1)); + waitAtMost(Duration.ofSeconds(5), () -> recoveredConsumerMessageCount.get() == initialCount + 1); ch.basicPublish("topology.recovery.exchange", "filtered.consumer", null, "".getBytes()); assertFalse("Consumer shouldn't recover, no extra messages should have been received", diff --git a/src/test/java/com/rabbitmq/tools/Host.java b/src/test/java/com/rabbitmq/tools/Host.java index 91f4c68f50..47c34b01ab 100644 --- a/src/test/java/com/rabbitmq/tools/Host.java +++ b/src/test/java/com/rabbitmq/tools/Host.java @@ -173,7 +173,8 @@ public static String makeCommand() public static String nodenameA() { - return System.getProperty("test-broker.A.nodename"); +// return System.getProperty("test-broker.A.nodename"); + return "rabbit@acogoluegnes-inspiron"; } public static String node_portA() From bc204c380a1c74e35e74f96ab7e14b9cfaa41c71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 1 Apr 2020 15:51:24 +0200 Subject: [PATCH 1226/2114] Bump Maven plugin --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5dbf1ec00e..319a9f3ffd 100644 --- a/pom.xml +++ b/pom.xml @@ -65,7 +65,7 @@ 9.4.27.v20200227 1.64 - 3.1.1 + 3.2.0 2.5.3 2.3 3.0.2 From 29dc1c825fca5e088d78828bfdbec739636067e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 1 Apr 2020 16:02:54 +0200 Subject: [PATCH 1227/2114] Change copyright and organization name to VMware --- LICENSE-MPL-RabbitMQ | 2 +- codegen.py | 4 ++-- pom.xml | 4 ++-- src/main/java/com/rabbitmq/client/Address.java | 2 +- src/main/java/com/rabbitmq/client/AddressResolver.java | 2 +- src/main/java/com/rabbitmq/client/AlreadyClosedException.java | 2 +- .../com/rabbitmq/client/AuthenticationFailureException.java | 2 +- src/main/java/com/rabbitmq/client/BasicProperties.java | 2 +- src/main/java/com/rabbitmq/client/BlockedCallback.java | 2 +- src/main/java/com/rabbitmq/client/BlockedListener.java | 2 +- src/main/java/com/rabbitmq/client/CancelCallback.java | 2 +- src/main/java/com/rabbitmq/client/Channel.java | 2 +- src/main/java/com/rabbitmq/client/Command.java | 2 +- src/main/java/com/rabbitmq/client/ConfirmCallback.java | 2 +- src/main/java/com/rabbitmq/client/ConfirmListener.java | 2 +- src/main/java/com/rabbitmq/client/Connection.java | 2 +- src/main/java/com/rabbitmq/client/ConnectionFactory.java | 2 +- .../com/rabbitmq/client/ConnectionFactoryConfigurator.java | 2 +- src/main/java/com/rabbitmq/client/Consumer.java | 2 +- .../java/com/rabbitmq/client/ConsumerCancelledException.java | 2 +- .../com/rabbitmq/client/ConsumerShutdownSignalCallback.java | 2 +- src/main/java/com/rabbitmq/client/ContentHeader.java | 2 +- src/main/java/com/rabbitmq/client/DefaultConsumer.java | 2 +- src/main/java/com/rabbitmq/client/DefaultSaslConfig.java | 2 +- .../com/rabbitmq/client/DefaultSocketChannelConfigurator.java | 2 +- .../java/com/rabbitmq/client/DefaultSocketConfigurator.java | 2 +- src/main/java/com/rabbitmq/client/DeliverCallback.java | 2 +- src/main/java/com/rabbitmq/client/Delivery.java | 2 +- .../java/com/rabbitmq/client/DnsRecordIpAddressResolver.java | 2 +- .../java/com/rabbitmq/client/DnsSrvRecordAddressResolver.java | 2 +- src/main/java/com/rabbitmq/client/Envelope.java | 2 +- src/main/java/com/rabbitmq/client/ExceptionHandler.java | 2 +- src/main/java/com/rabbitmq/client/GetResponse.java | 2 +- src/main/java/com/rabbitmq/client/JDKSaslConfig.java | 2 +- src/main/java/com/rabbitmq/client/ListAddressResolver.java | 2 +- src/main/java/com/rabbitmq/client/LongString.java | 2 +- .../java/com/rabbitmq/client/MalformedFrameException.java | 2 +- src/main/java/com/rabbitmq/client/MapRpcServer.java | 2 +- src/main/java/com/rabbitmq/client/MessageProperties.java | 2 +- src/main/java/com/rabbitmq/client/Method.java | 2 +- src/main/java/com/rabbitmq/client/MetricsCollector.java | 2 +- .../java/com/rabbitmq/client/MissedHeartbeatException.java | 2 +- src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java | 2 +- .../client/PossibleAuthenticationFailureException.java | 2 +- .../com/rabbitmq/client/ProtocolVersionMismatchException.java | 2 +- src/main/java/com/rabbitmq/client/Recoverable.java | 2 +- src/main/java/com/rabbitmq/client/RecoveryDelayHandler.java | 2 +- src/main/java/com/rabbitmq/client/RecoveryListener.java | 2 +- src/main/java/com/rabbitmq/client/Return.java | 2 +- src/main/java/com/rabbitmq/client/ReturnCallback.java | 2 +- src/main/java/com/rabbitmq/client/ReturnListener.java | 2 +- src/main/java/com/rabbitmq/client/RpcClient.java | 2 +- src/main/java/com/rabbitmq/client/RpcClientParams.java | 2 +- src/main/java/com/rabbitmq/client/RpcServer.java | 2 +- src/main/java/com/rabbitmq/client/SaslConfig.java | 2 +- src/main/java/com/rabbitmq/client/SaslMechanism.java | 2 +- src/main/java/com/rabbitmq/client/ShutdownListener.java | 2 +- src/main/java/com/rabbitmq/client/ShutdownNotifier.java | 2 +- .../java/com/rabbitmq/client/ShutdownSignalException.java | 2 +- .../java/com/rabbitmq/client/SocketChannelConfigurator.java | 2 +- .../java/com/rabbitmq/client/SocketChannelConfigurators.java | 2 +- src/main/java/com/rabbitmq/client/SocketConfigurator.java | 2 +- src/main/java/com/rabbitmq/client/SocketConfigurators.java | 2 +- src/main/java/com/rabbitmq/client/SslContextFactory.java | 2 +- src/main/java/com/rabbitmq/client/SslEngineConfigurator.java | 2 +- src/main/java/com/rabbitmq/client/SslEngineConfigurators.java | 2 +- src/main/java/com/rabbitmq/client/StringRpcServer.java | 2 +- .../java/com/rabbitmq/client/TopologyRecoveryException.java | 2 +- .../java/com/rabbitmq/client/TrustEverythingTrustManager.java | 2 +- src/main/java/com/rabbitmq/client/UnblockedCallback.java | 2 +- src/main/java/com/rabbitmq/client/UnexpectedFrameError.java | 2 +- src/main/java/com/rabbitmq/client/UnexpectedMethodError.java | 2 +- src/main/java/com/rabbitmq/client/UnknownClassOrMethodId.java | 2 +- .../com/rabbitmq/client/UnroutableRpcRequestException.java | 2 +- .../java/com/rabbitmq/client/impl/AMQBasicProperties.java | 2 +- src/main/java/com/rabbitmq/client/impl/AMQChannel.java | 2 +- src/main/java/com/rabbitmq/client/impl/AMQCommand.java | 2 +- src/main/java/com/rabbitmq/client/impl/AMQConnection.java | 4 ++-- src/main/java/com/rabbitmq/client/impl/AMQContentHeader.java | 2 +- .../com/rabbitmq/client/impl/AbstractMetricsCollector.java | 2 +- src/main/java/com/rabbitmq/client/impl/CRDemoMechanism.java | 2 +- src/main/java/com/rabbitmq/client/impl/ChannelManager.java | 2 +- src/main/java/com/rabbitmq/client/impl/ChannelN.java | 2 +- src/main/java/com/rabbitmq/client/impl/ClientVersion.java | 2 +- src/main/java/com/rabbitmq/client/impl/CommandAssembler.java | 2 +- .../com/rabbitmq/client/impl/CompletableFutureRpcWrapper.java | 2 +- src/main/java/com/rabbitmq/client/impl/ConnectionParams.java | 2 +- .../java/com/rabbitmq/client/impl/ConsumerDispatcher.java | 2 +- .../java/com/rabbitmq/client/impl/ConsumerWorkService.java | 2 +- .../com/rabbitmq/client/impl/ContentHeaderPropertyReader.java | 2 +- .../com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java | 2 +- .../java/com/rabbitmq/client/impl/CredentialsProvider.java | 2 +- .../com/rabbitmq/client/impl/CredentialsRefreshService.java | 2 +- .../com/rabbitmq/client/impl/DefaultCredentialsProvider.java | 2 +- .../client/impl/DefaultCredentialsRefreshService.java | 2 +- .../com/rabbitmq/client/impl/DefaultExceptionHandler.java | 2 +- src/main/java/com/rabbitmq/client/impl/Environment.java | 2 +- .../java/com/rabbitmq/client/impl/ErrorOnWriteListener.java | 2 +- src/main/java/com/rabbitmq/client/impl/ExternalMechanism.java | 2 +- .../com/rabbitmq/client/impl/ForgivingExceptionHandler.java | 2 +- src/main/java/com/rabbitmq/client/impl/Frame.java | 2 +- src/main/java/com/rabbitmq/client/impl/FrameHandler.java | 2 +- src/main/java/com/rabbitmq/client/impl/HeartbeatSender.java | 2 +- src/main/java/com/rabbitmq/client/impl/LongStringHelper.java | 2 +- src/main/java/com/rabbitmq/client/impl/Method.java | 2 +- .../java/com/rabbitmq/client/impl/MethodArgumentReader.java | 2 +- .../java/com/rabbitmq/client/impl/MethodArgumentWriter.java | 2 +- .../com/rabbitmq/client/impl/MicrometerMetricsCollector.java | 2 +- src/main/java/com/rabbitmq/client/impl/NetworkConnection.java | 2 +- .../impl/OAuth2ClientCredentialsGrantCredentialsProvider.java | 2 +- .../rabbitmq/client/impl/OAuthTokenManagementException.java | 2 +- src/main/java/com/rabbitmq/client/impl/PlainMechanism.java | 2 +- .../client/impl/RefreshProtectedCredentialsProvider.java | 2 +- .../com/rabbitmq/client/impl/RpcContinuationRpcWrapper.java | 2 +- src/main/java/com/rabbitmq/client/impl/RpcWrapper.java | 2 +- src/main/java/com/rabbitmq/client/impl/SetQueue.java | 2 +- .../com/rabbitmq/client/impl/ShutdownNotifierComponent.java | 2 +- .../java/com/rabbitmq/client/impl/SocketFrameHandler.java | 2 +- .../com/rabbitmq/client/impl/SocketFrameHandlerFactory.java | 2 +- .../com/rabbitmq/client/impl/StandardMetricsCollector.java | 2 +- .../java/com/rabbitmq/client/impl/StrictExceptionHandler.java | 2 +- src/main/java/com/rabbitmq/client/impl/TlsUtils.java | 2 +- .../java/com/rabbitmq/client/impl/TruncatedInputStream.java | 2 +- .../com/rabbitmq/client/impl/UnknownChannelException.java | 2 +- .../java/com/rabbitmq/client/impl/UpdateSecretExtension.java | 2 +- src/main/java/com/rabbitmq/client/impl/ValueReader.java | 2 +- src/main/java/com/rabbitmq/client/impl/ValueWriter.java | 2 +- .../com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java | 4 ++-- src/main/java/com/rabbitmq/client/impl/Version.java | 2 +- src/main/java/com/rabbitmq/client/impl/WorkPool.java | 2 +- .../java/com/rabbitmq/client/impl/WorkPoolFullException.java | 2 +- .../com/rabbitmq/client/impl/nio/ByteBufferOutputStream.java | 2 +- src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java | 2 +- .../java/com/rabbitmq/client/impl/nio/FrameWriteRequest.java | 2 +- .../java/com/rabbitmq/client/impl/nio/HeaderWriteRequest.java | 2 +- src/main/java/com/rabbitmq/client/impl/nio/NioHelper.java | 2 +- src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java | 2 +- .../java/com/rabbitmq/client/impl/nio/NioLoopContext.java | 2 +- src/main/java/com/rabbitmq/client/impl/nio/NioParams.java | 2 +- .../java/com/rabbitmq/client/impl/nio/SelectorHolder.java | 2 +- .../rabbitmq/client/impl/nio/SocketChannelFrameHandler.java | 2 +- .../client/impl/nio/SocketChannelFrameHandlerFactory.java | 2 +- .../client/impl/nio/SocketChannelFrameHandlerState.java | 2 +- .../rabbitmq/client/impl/nio/SocketChannelRegistration.java | 2 +- .../client/impl/nio/SslEngineByteBufferOutputStream.java | 2 +- .../com/rabbitmq/client/impl/nio/SslEngineFrameBuilder.java | 2 +- .../java/com/rabbitmq/client/impl/nio/SslEngineHelper.java | 2 +- src/main/java/com/rabbitmq/client/impl/nio/WriteRequest.java | 2 +- .../rabbitmq/client/impl/recovery/AutorecoveringChannel.java | 2 +- .../client/impl/recovery/AutorecoveringConnection.java | 2 +- .../java/com/rabbitmq/client/impl/recovery/BackoffPolicy.java | 2 +- .../client/impl/recovery/ConsumerRecoveryListener.java | 2 +- .../rabbitmq/client/impl/recovery/DefaultRetryHandler.java | 2 +- .../rabbitmq/client/impl/recovery/QueueRecoveryListener.java | 2 +- .../com/rabbitmq/client/impl/recovery/RecordedBinding.java | 2 +- .../com/rabbitmq/client/impl/recovery/RecordedConsumer.java | 2 +- .../com/rabbitmq/client/impl/recovery/RecordedEntity.java | 2 +- .../com/rabbitmq/client/impl/recovery/RecordedExchange.java | 2 +- .../client/impl/recovery/RecordedExchangeBinding.java | 2 +- .../rabbitmq/client/impl/recovery/RecordedNamedEntity.java | 2 +- .../java/com/rabbitmq/client/impl/recovery/RecordedQueue.java | 2 +- .../rabbitmq/client/impl/recovery/RecordedQueueBinding.java | 2 +- .../client/impl/recovery/RecoveryAwareAMQConnection.java | 2 +- .../impl/recovery/RecoveryAwareAMQConnectionFactory.java | 2 +- .../client/impl/recovery/RecoveryAwareChannelManager.java | 2 +- .../rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java | 2 +- .../client/impl/recovery/RecoveryCanBeginListener.java | 2 +- .../java/com/rabbitmq/client/impl/recovery/RetryContext.java | 2 +- .../java/com/rabbitmq/client/impl/recovery/RetryHandler.java | 2 +- .../java/com/rabbitmq/client/impl/recovery/RetryResult.java | 2 +- .../rabbitmq/client/impl/recovery/TopologyRecoveryFilter.java | 2 +- .../impl/recovery/TopologyRecoveryRetryHandlerBuilder.java | 2 +- .../client/impl/recovery/TopologyRecoveryRetryLogic.java | 2 +- src/main/java/com/rabbitmq/tools/json/JSONReader.java | 4 ++-- src/main/java/com/rabbitmq/tools/json/JSONSerializable.java | 2 +- src/main/java/com/rabbitmq/tools/json/JSONUtil.java | 2 +- src/main/java/com/rabbitmq/tools/json/JSONWriter.java | 4 ++-- .../java/com/rabbitmq/tools/jsonrpc/DefaultJsonRpcMapper.java | 2 +- .../java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java | 2 +- src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java | 2 +- .../java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java | 2 +- src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java | 2 +- .../com/rabbitmq/tools/jsonrpc/JsonRpcMappingException.java | 2 +- src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java | 2 +- .../java/com/rabbitmq/tools/jsonrpc/ParameterDescription.java | 2 +- .../java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java | 2 +- .../java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java | 2 +- src/main/java/com/rabbitmq/utility/BlockingCell.java | 2 +- .../java/com/rabbitmq/utility/BlockingValueOrException.java | 2 +- src/main/java/com/rabbitmq/utility/IntAllocator.java | 2 +- src/main/java/com/rabbitmq/utility/SensibleClone.java | 2 +- src/main/java/com/rabbitmq/utility/Utility.java | 2 +- src/main/java/com/rabbitmq/utility/ValueOrException.java | 2 +- src/test/java/com/rabbitmq/client/AbstractJsonRpcTest.java | 2 +- src/test/java/com/rabbitmq/client/DefaultJsonRpcTest.java | 2 +- src/test/java/com/rabbitmq/client/JacksonJsonRpcTest.java | 2 +- src/test/java/com/rabbitmq/client/QueueingConsumer.java | 2 +- .../client/impl/AMQConnectionRefreshCredentialsTest.java | 2 +- .../client/impl/DefaultCredentialsRefreshServiceTest.java | 2 +- .../OAuth2ClientCredentialsGrantCredentialsProviderTest.java | 2 +- .../client/impl/RefreshProtectedCredentialsProviderTest.java | 2 +- src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java | 2 +- src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java | 2 +- src/test/java/com/rabbitmq/client/test/AMQBuilderApiTest.java | 2 +- src/test/java/com/rabbitmq/client/test/AMQChannelTest.java | 2 +- src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java | 2 +- .../java/com/rabbitmq/client/test/AbstractRMQTestSuite.java | 2 +- src/test/java/com/rabbitmq/client/test/AddressTest.java | 2 +- src/test/java/com/rabbitmq/client/test/AmqpUriTest.java | 2 +- src/test/java/com/rabbitmq/client/test/BlockingCellTest.java | 2 +- src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java | 2 +- src/test/java/com/rabbitmq/client/test/BrokerTestCase.java | 2 +- src/test/java/com/rabbitmq/client/test/Bug20004Test.java | 2 +- .../client/test/ChannelAsyncCompletableFutureTest.java | 2 +- src/test/java/com/rabbitmq/client/test/ChannelNTest.java | 2 +- .../rabbitmq/client/test/ChannelNumberAllocationTests.java | 2 +- .../client/test/ChannelRpcTimeoutIntegrationTest.java | 2 +- src/test/java/com/rabbitmq/client/test/ClientTests.java | 2 +- src/test/java/com/rabbitmq/client/test/ClientVersionTest.java | 2 +- .../java/com/rabbitmq/client/test/ClonePropertiesTest.java | 2 +- src/test/java/com/rabbitmq/client/test/CloseInMainLoop.java | 2 +- src/test/java/com/rabbitmq/client/test/ConfirmBase.java | 2 +- .../java/com/rabbitmq/client/test/ConnectionFactoryTest.java | 2 +- src/test/java/com/rabbitmq/client/test/ConnectionTest.java | 2 +- .../com/rabbitmq/client/test/DefaultRetryHandlerTest.java | 2 +- .../rabbitmq/client/test/DnsSrvRecordAddressResolverTest.java | 2 +- src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java | 2 +- .../java/com/rabbitmq/client/test/GeneratedClassesTest.java | 2 +- src/test/java/com/rabbitmq/client/test/JSONReadWriteTest.java | 2 +- .../java/com/rabbitmq/client/test/LambdaCallbackTest.java | 2 +- src/test/java/com/rabbitmq/client/test/LongStringTest.java | 2 +- .../java/com/rabbitmq/client/test/MetricsCollectorTest.java | 2 +- .../rabbitmq/client/test/MicrometerMetricsCollectorTest.java | 2 +- .../java/com/rabbitmq/client/test/MultiThreadedChannel.java | 2 +- .../rabbitmq/client/test/NioDeadlockOnConnectionClosing.java | 2 +- .../client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java | 2 +- .../rabbitmq/client/test/PropertyFileInitialisationTest.java | 2 +- .../java/com/rabbitmq/client/test/QueueingConsumerTests.java | 2 +- .../client/test/RecoveryAwareAMQConnectionFactoryTest.java | 2 +- .../com/rabbitmq/client/test/RecoveryDelayHandlerTest.java | 2 +- .../java/com/rabbitmq/client/test/RefreshCredentialsTest.java | 2 +- src/test/java/com/rabbitmq/client/test/RpcTest.java | 2 +- .../com/rabbitmq/client/test/RpcTopologyRecordingTest.java | 2 +- .../java/com/rabbitmq/client/test/SharedThreadPoolTest.java | 2 +- .../java/com/rabbitmq/client/test/SslContextFactoryTest.java | 2 +- .../com/rabbitmq/client/test/StrictExceptionHandlerTest.java | 2 +- src/test/java/com/rabbitmq/client/test/TableTest.java | 2 +- src/test/java/com/rabbitmq/client/test/TestUtils.java | 2 +- src/test/java/com/rabbitmq/client/test/TestUtilsTest.java | 2 +- src/test/java/com/rabbitmq/client/test/TlsUtilsTest.java | 2 +- .../java/com/rabbitmq/client/test/TrafficListenerTest.java | 2 +- .../com/rabbitmq/client/test/TruncatedInputStreamTest.java | 2 +- .../java/com/rabbitmq/client/test/ValueOrExceptionTest.java | 2 +- .../rabbitmq/client/test/functional/AbstractRejectTest.java | 2 +- .../rabbitmq/client/test/functional/AlternateExchange.java | 2 +- .../java/com/rabbitmq/client/test/functional/BasicGet.java | 2 +- .../com/rabbitmq/client/test/functional/BindingLifecycle.java | 2 +- .../rabbitmq/client/test/functional/BindingLifecycleBase.java | 2 +- .../java/com/rabbitmq/client/test/functional/CcRoutes.java | 2 +- .../rabbitmq/client/test/functional/ClusteredTestBase.java | 2 +- .../java/com/rabbitmq/client/test/functional/Confirm.java | 2 +- .../com/rabbitmq/client/test/functional/ConnectionOpen.java | 2 +- .../rabbitmq/client/test/functional/ConnectionRecovery.java | 2 +- .../client/test/functional/ConsumerCancelNotification.java | 2 +- .../com/rabbitmq/client/test/functional/ConsumerCount.java | 2 +- .../rabbitmq/client/test/functional/ConsumerPriorities.java | 2 +- .../rabbitmq/client/test/functional/DeadLetterExchange.java | 2 +- .../com/rabbitmq/client/test/functional/DefaultExchange.java | 2 +- .../com/rabbitmq/client/test/functional/DirectReplyTo.java | 2 +- .../com/rabbitmq/client/test/functional/DoubleDeletion.java | 2 +- .../rabbitmq/client/test/functional/DurableOnTransient.java | 2 +- .../rabbitmq/client/test/functional/ExceptionHandling.java | 2 +- .../rabbitmq/client/test/functional/ExceptionMessages.java | 2 +- .../com/rabbitmq/client/test/functional/ExchangeDeclare.java | 2 +- .../client/test/functional/ExchangeDeleteIfUnused.java | 2 +- .../client/test/functional/ExchangeDeletePredeclared.java | 2 +- .../client/test/functional/ExchangeEquivalenceBase.java | 2 +- .../client/test/functional/ExchangeExchangeBindings.java | 2 +- .../test/functional/ExchangeExchangeBindingsAutoDelete.java | 2 +- .../java/com/rabbitmq/client/test/functional/FrameMax.java | 2 +- .../com/rabbitmq/client/test/functional/FunctionalTests.java | 2 +- .../client/test/functional/HeadersExchangeValidation.java | 2 +- .../java/com/rabbitmq/client/test/functional/Heartbeat.java | 2 +- .../com/rabbitmq/client/test/functional/InternalExchange.java | 2 +- .../java/com/rabbitmq/client/test/functional/InvalidAcks.java | 2 +- .../com/rabbitmq/client/test/functional/InvalidAcksBase.java | 2 +- .../com/rabbitmq/client/test/functional/InvalidAcksTx.java | 2 +- .../com/rabbitmq/client/test/functional/MessageCount.java | 2 +- .../java/com/rabbitmq/client/test/functional/Metrics.java | 2 +- src/test/java/com/rabbitmq/client/test/functional/Nack.java | 2 +- .../rabbitmq/client/test/functional/NoRequeueOnCancel.java | 2 +- src/test/java/com/rabbitmq/client/test/functional/Nowait.java | 2 +- .../rabbitmq/client/test/functional/PerConsumerPrefetch.java | 2 +- .../com/rabbitmq/client/test/functional/PerMessageTTL.java | 2 +- .../java/com/rabbitmq/client/test/functional/PerQueueTTL.java | 2 +- .../client/test/functional/PerQueueVsPerMessageTTL.java | 2 +- .../java/com/rabbitmq/client/test/functional/Policies.java | 2 +- .../java/com/rabbitmq/client/test/functional/QosTests.java | 2 +- .../com/rabbitmq/client/test/functional/QueueExclusivity.java | 2 +- .../java/com/rabbitmq/client/test/functional/QueueLease.java | 2 +- .../com/rabbitmq/client/test/functional/QueueLifecycle.java | 2 +- .../com/rabbitmq/client/test/functional/QueueSizeLimit.java | 2 +- .../java/com/rabbitmq/client/test/functional/Recover.java | 2 +- src/test/java/com/rabbitmq/client/test/functional/Reject.java | 2 +- .../client/test/functional/RequeueOnChannelClose.java | 2 +- .../com/rabbitmq/client/test/functional/RequeueOnClose.java | 2 +- .../client/test/functional/RequeueOnConnectionClose.java | 2 +- .../java/com/rabbitmq/client/test/functional/Routing.java | 2 +- .../com/rabbitmq/client/test/functional/SaslMechanisms.java | 2 +- .../java/com/rabbitmq/client/test/functional/TTLHandling.java | 2 +- src/test/java/com/rabbitmq/client/test/functional/Tables.java | 2 +- .../client/test/functional/TopologyRecoveryFiltering.java | 2 +- .../client/test/functional/TopologyRecoveryRetry.java | 2 +- .../com/rabbitmq/client/test/functional/Transactions.java | 2 +- .../client/test/functional/UnbindAutoDeleteExchange.java | 2 +- .../com/rabbitmq/client/test/functional/UnexpectedFrames.java | 2 +- .../com/rabbitmq/client/test/functional/UserIDHeader.java | 2 +- .../java/com/rabbitmq/client/test/server/AbsentQueue.java | 2 +- .../client/test/server/AlternateExchangeEquivalence.java | 2 +- .../com/rabbitmq/client/test/server/BlockedConnection.java | 2 +- .../java/com/rabbitmq/client/test/server/Bug19219Test.java | 2 +- .../rabbitmq/client/test/server/ChannelLimitNegotiation.java | 2 +- .../client/test/server/DeadLetterExchangeDurable.java | 2 +- .../rabbitmq/client/test/server/DurableBindingLifecycle.java | 2 +- .../client/test/server/EffectVisibilityCrossNodeTest.java | 2 +- .../rabbitmq/client/test/server/ExclusiveQueueDurability.java | 2 +- src/test/java/com/rabbitmq/client/test/server/Firehose.java | 2 +- src/test/java/com/rabbitmq/client/test/server/HATests.java | 2 +- .../java/com/rabbitmq/client/test/server/LoopbackUsers.java | 2 +- .../java/com/rabbitmq/client/test/server/MemoryAlarms.java | 2 +- .../java/com/rabbitmq/client/test/server/MessageRecovery.java | 2 +- .../java/com/rabbitmq/client/test/server/Permissions.java | 2 +- .../rabbitmq/client/test/server/PersistenceGuarantees.java | 2 +- .../java/com/rabbitmq/client/test/server/PriorityQueues.java | 2 +- .../java/com/rabbitmq/client/test/server/ServerTests.java | 2 +- src/test/java/com/rabbitmq/client/test/server/Shutdown.java | 2 +- .../com/rabbitmq/client/test/server/TopicPermissions.java | 2 +- .../com/rabbitmq/client/test/server/XDeathHeaderGrowth.java | 2 +- .../com/rabbitmq/client/test/ssl/BadVerifiedConnection.java | 2 +- .../client/test/ssl/ConnectionFactoryDefaultTlsVersion.java | 2 +- .../com/rabbitmq/client/test/ssl/HostnameVerification.java | 2 +- .../rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java | 2 +- src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java | 2 +- .../com/rabbitmq/client/test/ssl/TlsConnectionLogging.java | 2 +- .../com/rabbitmq/client/test/ssl/UnverifiedConnection.java | 2 +- .../java/com/rabbitmq/client/test/ssl/VerifiedConnection.java | 2 +- src/test/java/com/rabbitmq/tools/Host.java | 2 +- src/test/java/com/rabbitmq/utility/IntAllocatorTests.java | 2 +- 348 files changed, 354 insertions(+), 354 deletions(-) diff --git a/LICENSE-MPL-RabbitMQ b/LICENSE-MPL-RabbitMQ index b237a959b0..50770c2540 100644 --- a/LICENSE-MPL-RabbitMQ +++ b/LICENSE-MPL-RabbitMQ @@ -447,7 +447,7 @@ EXHIBIT A -Mozilla Public License. The Original Code is RabbitMQ. The Initial Developer of the Original Code is GoPivotal, Inc. - Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. + Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. Alternatively, the contents of this file may be used under the terms of the GNU General Public License version 2 (the "GPL2"), or diff --git a/codegen.py b/codegen.py index 3a67ce435d..42c577a0d9 100755 --- a/codegen.py +++ b/codegen.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -## Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. ## ## This software, the RabbitMQ Java client library, is triple-licensed under the ## Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 @@ -130,7 +130,7 @@ def printFileHeader(): print("""// NOTE: This -*- java -*- source code is autogenerated from the AMQP // specification! // -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/pom.xml b/pom.xml index 8f6246fa08..0c79405b3b 100644 --- a/pom.xml +++ b/pom.xml @@ -33,7 +33,7 @@ info@rabbitmq.com Team RabbitMQ - Pivotal Software, Inc. + VMware, Inc. or its affiliates. https://rabbitmq.com @@ -46,7 +46,7 @@ - Pivotal Software, Inc. + VMware, Inc. or its affiliates. https://www.rabbitmq.com diff --git a/src/main/java/com/rabbitmq/client/Address.java b/src/main/java/com/rabbitmq/client/Address.java index c70ae34df7..26b9cd9d3e 100644 --- a/src/main/java/com/rabbitmq/client/Address.java +++ b/src/main/java/com/rabbitmq/client/Address.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/AddressResolver.java b/src/main/java/com/rabbitmq/client/AddressResolver.java index 10ad17cb44..4a4f0d8461 100644 --- a/src/main/java/com/rabbitmq/client/AddressResolver.java +++ b/src/main/java/com/rabbitmq/client/AddressResolver.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/AlreadyClosedException.java b/src/main/java/com/rabbitmq/client/AlreadyClosedException.java index 06cca515ac..37060907f9 100644 --- a/src/main/java/com/rabbitmq/client/AlreadyClosedException.java +++ b/src/main/java/com/rabbitmq/client/AlreadyClosedException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/AuthenticationFailureException.java b/src/main/java/com/rabbitmq/client/AuthenticationFailureException.java index 998bddd2a1..391be6d039 100644 --- a/src/main/java/com/rabbitmq/client/AuthenticationFailureException.java +++ b/src/main/java/com/rabbitmq/client/AuthenticationFailureException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/BasicProperties.java b/src/main/java/com/rabbitmq/client/BasicProperties.java index 2dc7150cd1..4001508cfb 100644 --- a/src/main/java/com/rabbitmq/client/BasicProperties.java +++ b/src/main/java/com/rabbitmq/client/BasicProperties.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/BlockedCallback.java b/src/main/java/com/rabbitmq/client/BlockedCallback.java index 7e711dfdca..f679e79427 100644 --- a/src/main/java/com/rabbitmq/client/BlockedCallback.java +++ b/src/main/java/com/rabbitmq/client/BlockedCallback.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/BlockedListener.java b/src/main/java/com/rabbitmq/client/BlockedListener.java index 968fbb710c..4e0f820615 100644 --- a/src/main/java/com/rabbitmq/client/BlockedListener.java +++ b/src/main/java/com/rabbitmq/client/BlockedListener.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/CancelCallback.java b/src/main/java/com/rabbitmq/client/CancelCallback.java index c2691f053e..ee6df1964a 100644 --- a/src/main/java/com/rabbitmq/client/CancelCallback.java +++ b/src/main/java/com/rabbitmq/client/CancelCallback.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/Channel.java b/src/main/java/com/rabbitmq/client/Channel.java index b1daa31100..cd0b9b2962 100644 --- a/src/main/java/com/rabbitmq/client/Channel.java +++ b/src/main/java/com/rabbitmq/client/Channel.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/Command.java b/src/main/java/com/rabbitmq/client/Command.java index b6c0e349a0..2630773ecc 100644 --- a/src/main/java/com/rabbitmq/client/Command.java +++ b/src/main/java/com/rabbitmq/client/Command.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ConfirmCallback.java b/src/main/java/com/rabbitmq/client/ConfirmCallback.java index fff2c9a6d6..41197874e3 100644 --- a/src/main/java/com/rabbitmq/client/ConfirmCallback.java +++ b/src/main/java/com/rabbitmq/client/ConfirmCallback.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ConfirmListener.java b/src/main/java/com/rabbitmq/client/ConfirmListener.java index 9404588554..51162d9baf 100644 --- a/src/main/java/com/rabbitmq/client/ConfirmListener.java +++ b/src/main/java/com/rabbitmq/client/ConfirmListener.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/Connection.java b/src/main/java/com/rabbitmq/client/Connection.java index 2b1c9281ee..d45c1b90ea 100644 --- a/src/main/java/com/rabbitmq/client/Connection.java +++ b/src/main/java/com/rabbitmq/client/Connection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index ea79e354f2..b6b1f5b848 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java b/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java index 694b7626a8..4470760d75 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/Consumer.java b/src/main/java/com/rabbitmq/client/Consumer.java index 61e799ae85..118ce0a8f3 100644 --- a/src/main/java/com/rabbitmq/client/Consumer.java +++ b/src/main/java/com/rabbitmq/client/Consumer.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ConsumerCancelledException.java b/src/main/java/com/rabbitmq/client/ConsumerCancelledException.java index 5d98220fd1..7078cfcf99 100644 --- a/src/main/java/com/rabbitmq/client/ConsumerCancelledException.java +++ b/src/main/java/com/rabbitmq/client/ConsumerCancelledException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ConsumerShutdownSignalCallback.java b/src/main/java/com/rabbitmq/client/ConsumerShutdownSignalCallback.java index 27e0f8ad39..fb055dde7e 100644 --- a/src/main/java/com/rabbitmq/client/ConsumerShutdownSignalCallback.java +++ b/src/main/java/com/rabbitmq/client/ConsumerShutdownSignalCallback.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ContentHeader.java b/src/main/java/com/rabbitmq/client/ContentHeader.java index 36e2ec29d2..ddb7d52b14 100644 --- a/src/main/java/com/rabbitmq/client/ContentHeader.java +++ b/src/main/java/com/rabbitmq/client/ContentHeader.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/DefaultConsumer.java b/src/main/java/com/rabbitmq/client/DefaultConsumer.java index 84ca404549..0e1670d39a 100644 --- a/src/main/java/com/rabbitmq/client/DefaultConsumer.java +++ b/src/main/java/com/rabbitmq/client/DefaultConsumer.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/DefaultSaslConfig.java b/src/main/java/com/rabbitmq/client/DefaultSaslConfig.java index 54373d868d..62ac85c4c1 100644 --- a/src/main/java/com/rabbitmq/client/DefaultSaslConfig.java +++ b/src/main/java/com/rabbitmq/client/DefaultSaslConfig.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/DefaultSocketChannelConfigurator.java b/src/main/java/com/rabbitmq/client/DefaultSocketChannelConfigurator.java index 425899532c..38494da70e 100644 --- a/src/main/java/com/rabbitmq/client/DefaultSocketChannelConfigurator.java +++ b/src/main/java/com/rabbitmq/client/DefaultSocketChannelConfigurator.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/DefaultSocketConfigurator.java b/src/main/java/com/rabbitmq/client/DefaultSocketConfigurator.java index e6fa99a5fc..0c3118e049 100644 --- a/src/main/java/com/rabbitmq/client/DefaultSocketConfigurator.java +++ b/src/main/java/com/rabbitmq/client/DefaultSocketConfigurator.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/DeliverCallback.java b/src/main/java/com/rabbitmq/client/DeliverCallback.java index ad44b7cf13..8e17dfb407 100644 --- a/src/main/java/com/rabbitmq/client/DeliverCallback.java +++ b/src/main/java/com/rabbitmq/client/DeliverCallback.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/Delivery.java b/src/main/java/com/rabbitmq/client/Delivery.java index eca6971be4..3e99f20974 100644 --- a/src/main/java/com/rabbitmq/client/Delivery.java +++ b/src/main/java/com/rabbitmq/client/Delivery.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/DnsRecordIpAddressResolver.java b/src/main/java/com/rabbitmq/client/DnsRecordIpAddressResolver.java index a26504c0fc..fb28f16a41 100644 --- a/src/main/java/com/rabbitmq/client/DnsRecordIpAddressResolver.java +++ b/src/main/java/com/rabbitmq/client/DnsRecordIpAddressResolver.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/DnsSrvRecordAddressResolver.java b/src/main/java/com/rabbitmq/client/DnsSrvRecordAddressResolver.java index 1388f716ae..81775fc9f6 100644 --- a/src/main/java/com/rabbitmq/client/DnsSrvRecordAddressResolver.java +++ b/src/main/java/com/rabbitmq/client/DnsSrvRecordAddressResolver.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/Envelope.java b/src/main/java/com/rabbitmq/client/Envelope.java index 3a83a05058..cc8e7ceda1 100644 --- a/src/main/java/com/rabbitmq/client/Envelope.java +++ b/src/main/java/com/rabbitmq/client/Envelope.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ExceptionHandler.java b/src/main/java/com/rabbitmq/client/ExceptionHandler.java index 45122737b1..3ed8183f28 100644 --- a/src/main/java/com/rabbitmq/client/ExceptionHandler.java +++ b/src/main/java/com/rabbitmq/client/ExceptionHandler.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/GetResponse.java b/src/main/java/com/rabbitmq/client/GetResponse.java index f6980304d6..ba157a0fb9 100644 --- a/src/main/java/com/rabbitmq/client/GetResponse.java +++ b/src/main/java/com/rabbitmq/client/GetResponse.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/JDKSaslConfig.java b/src/main/java/com/rabbitmq/client/JDKSaslConfig.java index 9c1e44a248..d8a240a30e 100644 --- a/src/main/java/com/rabbitmq/client/JDKSaslConfig.java +++ b/src/main/java/com/rabbitmq/client/JDKSaslConfig.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ListAddressResolver.java b/src/main/java/com/rabbitmq/client/ListAddressResolver.java index e4f80cb20e..a7b3d96657 100644 --- a/src/main/java/com/rabbitmq/client/ListAddressResolver.java +++ b/src/main/java/com/rabbitmq/client/ListAddressResolver.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/LongString.java b/src/main/java/com/rabbitmq/client/LongString.java index ee9a24169a..447ef1e510 100644 --- a/src/main/java/com/rabbitmq/client/LongString.java +++ b/src/main/java/com/rabbitmq/client/LongString.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/MalformedFrameException.java b/src/main/java/com/rabbitmq/client/MalformedFrameException.java index 2d63e5b961..ae799f0f5d 100644 --- a/src/main/java/com/rabbitmq/client/MalformedFrameException.java +++ b/src/main/java/com/rabbitmq/client/MalformedFrameException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/MapRpcServer.java b/src/main/java/com/rabbitmq/client/MapRpcServer.java index 2671a044cb..93ceaa10fe 100644 --- a/src/main/java/com/rabbitmq/client/MapRpcServer.java +++ b/src/main/java/com/rabbitmq/client/MapRpcServer.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/MessageProperties.java b/src/main/java/com/rabbitmq/client/MessageProperties.java index 4ba9b40e17..8369eeb645 100644 --- a/src/main/java/com/rabbitmq/client/MessageProperties.java +++ b/src/main/java/com/rabbitmq/client/MessageProperties.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/Method.java b/src/main/java/com/rabbitmq/client/Method.java index 393f64cc1b..bd7b8531e7 100644 --- a/src/main/java/com/rabbitmq/client/Method.java +++ b/src/main/java/com/rabbitmq/client/Method.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/MetricsCollector.java b/src/main/java/com/rabbitmq/client/MetricsCollector.java index 31d4480423..9b289d87bd 100644 --- a/src/main/java/com/rabbitmq/client/MetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/MetricsCollector.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/MissedHeartbeatException.java b/src/main/java/com/rabbitmq/client/MissedHeartbeatException.java index 90e8cdb83a..83400d2db5 100644 --- a/src/main/java/com/rabbitmq/client/MissedHeartbeatException.java +++ b/src/main/java/com/rabbitmq/client/MissedHeartbeatException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java b/src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java index 30e0d83402..163fe8afe4 100644 --- a/src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/PossibleAuthenticationFailureException.java b/src/main/java/com/rabbitmq/client/PossibleAuthenticationFailureException.java index bbb053d611..d6cca886db 100644 --- a/src/main/java/com/rabbitmq/client/PossibleAuthenticationFailureException.java +++ b/src/main/java/com/rabbitmq/client/PossibleAuthenticationFailureException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ProtocolVersionMismatchException.java b/src/main/java/com/rabbitmq/client/ProtocolVersionMismatchException.java index 7b031b9621..8cd857545b 100644 --- a/src/main/java/com/rabbitmq/client/ProtocolVersionMismatchException.java +++ b/src/main/java/com/rabbitmq/client/ProtocolVersionMismatchException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/Recoverable.java b/src/main/java/com/rabbitmq/client/Recoverable.java index 50dcec5b4d..c4b066f66c 100644 --- a/src/main/java/com/rabbitmq/client/Recoverable.java +++ b/src/main/java/com/rabbitmq/client/Recoverable.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/RecoveryDelayHandler.java b/src/main/java/com/rabbitmq/client/RecoveryDelayHandler.java index 524d3c1786..e00c7d3940 100644 --- a/src/main/java/com/rabbitmq/client/RecoveryDelayHandler.java +++ b/src/main/java/com/rabbitmq/client/RecoveryDelayHandler.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/RecoveryListener.java b/src/main/java/com/rabbitmq/client/RecoveryListener.java index 2e346ae097..968b828521 100644 --- a/src/main/java/com/rabbitmq/client/RecoveryListener.java +++ b/src/main/java/com/rabbitmq/client/RecoveryListener.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/Return.java b/src/main/java/com/rabbitmq/client/Return.java index 5c78977bce..f441a69873 100644 --- a/src/main/java/com/rabbitmq/client/Return.java +++ b/src/main/java/com/rabbitmq/client/Return.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ReturnCallback.java b/src/main/java/com/rabbitmq/client/ReturnCallback.java index 0f413716e2..1eb1c99271 100644 --- a/src/main/java/com/rabbitmq/client/ReturnCallback.java +++ b/src/main/java/com/rabbitmq/client/ReturnCallback.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ReturnListener.java b/src/main/java/com/rabbitmq/client/ReturnListener.java index d5094c0d14..2ec72fbc15 100644 --- a/src/main/java/com/rabbitmq/client/ReturnListener.java +++ b/src/main/java/com/rabbitmq/client/ReturnListener.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/RpcClient.java b/src/main/java/com/rabbitmq/client/RpcClient.java index a49e403f3e..7e5a4e4ef6 100644 --- a/src/main/java/com/rabbitmq/client/RpcClient.java +++ b/src/main/java/com/rabbitmq/client/RpcClient.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/RpcClientParams.java b/src/main/java/com/rabbitmq/client/RpcClientParams.java index 870756e25a..ea1ab30d87 100644 --- a/src/main/java/com/rabbitmq/client/RpcClientParams.java +++ b/src/main/java/com/rabbitmq/client/RpcClientParams.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/RpcServer.java b/src/main/java/com/rabbitmq/client/RpcServer.java index 457e5f6679..a1bc413c50 100644 --- a/src/main/java/com/rabbitmq/client/RpcServer.java +++ b/src/main/java/com/rabbitmq/client/RpcServer.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/SaslConfig.java b/src/main/java/com/rabbitmq/client/SaslConfig.java index 1db18614dc..d8555cf6b2 100644 --- a/src/main/java/com/rabbitmq/client/SaslConfig.java +++ b/src/main/java/com/rabbitmq/client/SaslConfig.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/SaslMechanism.java b/src/main/java/com/rabbitmq/client/SaslMechanism.java index a98bdcc866..d411f2072e 100644 --- a/src/main/java/com/rabbitmq/client/SaslMechanism.java +++ b/src/main/java/com/rabbitmq/client/SaslMechanism.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ShutdownListener.java b/src/main/java/com/rabbitmq/client/ShutdownListener.java index 351e0b9b9b..5a2427334f 100644 --- a/src/main/java/com/rabbitmq/client/ShutdownListener.java +++ b/src/main/java/com/rabbitmq/client/ShutdownListener.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ShutdownNotifier.java b/src/main/java/com/rabbitmq/client/ShutdownNotifier.java index 8802dcdaf9..66aa021d7a 100644 --- a/src/main/java/com/rabbitmq/client/ShutdownNotifier.java +++ b/src/main/java/com/rabbitmq/client/ShutdownNotifier.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ShutdownSignalException.java b/src/main/java/com/rabbitmq/client/ShutdownSignalException.java index 5e49720382..769158198d 100644 --- a/src/main/java/com/rabbitmq/client/ShutdownSignalException.java +++ b/src/main/java/com/rabbitmq/client/ShutdownSignalException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/SocketChannelConfigurator.java b/src/main/java/com/rabbitmq/client/SocketChannelConfigurator.java index ceb3a95a88..43307caada 100644 --- a/src/main/java/com/rabbitmq/client/SocketChannelConfigurator.java +++ b/src/main/java/com/rabbitmq/client/SocketChannelConfigurator.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/SocketChannelConfigurators.java b/src/main/java/com/rabbitmq/client/SocketChannelConfigurators.java index 566d3ddc13..0355528b4e 100644 --- a/src/main/java/com/rabbitmq/client/SocketChannelConfigurators.java +++ b/src/main/java/com/rabbitmq/client/SocketChannelConfigurators.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/SocketConfigurator.java b/src/main/java/com/rabbitmq/client/SocketConfigurator.java index 30c9ed4bab..8a49c57d96 100644 --- a/src/main/java/com/rabbitmq/client/SocketConfigurator.java +++ b/src/main/java/com/rabbitmq/client/SocketConfigurator.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/SocketConfigurators.java b/src/main/java/com/rabbitmq/client/SocketConfigurators.java index 551ad95ca9..5d3ea0e280 100644 --- a/src/main/java/com/rabbitmq/client/SocketConfigurators.java +++ b/src/main/java/com/rabbitmq/client/SocketConfigurators.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/SslContextFactory.java b/src/main/java/com/rabbitmq/client/SslContextFactory.java index 9a1fbcac6c..468c1237cd 100644 --- a/src/main/java/com/rabbitmq/client/SslContextFactory.java +++ b/src/main/java/com/rabbitmq/client/SslContextFactory.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/SslEngineConfigurator.java b/src/main/java/com/rabbitmq/client/SslEngineConfigurator.java index 01b22c4c05..6f95bb392a 100644 --- a/src/main/java/com/rabbitmq/client/SslEngineConfigurator.java +++ b/src/main/java/com/rabbitmq/client/SslEngineConfigurator.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/SslEngineConfigurators.java b/src/main/java/com/rabbitmq/client/SslEngineConfigurators.java index 44c2e16f70..0cb7b451d7 100644 --- a/src/main/java/com/rabbitmq/client/SslEngineConfigurators.java +++ b/src/main/java/com/rabbitmq/client/SslEngineConfigurators.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/StringRpcServer.java b/src/main/java/com/rabbitmq/client/StringRpcServer.java index 2f8e62bade..375079607a 100644 --- a/src/main/java/com/rabbitmq/client/StringRpcServer.java +++ b/src/main/java/com/rabbitmq/client/StringRpcServer.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/TopologyRecoveryException.java b/src/main/java/com/rabbitmq/client/TopologyRecoveryException.java index 0c2bcc1f5d..cf9d18d105 100644 --- a/src/main/java/com/rabbitmq/client/TopologyRecoveryException.java +++ b/src/main/java/com/rabbitmq/client/TopologyRecoveryException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/TrustEverythingTrustManager.java b/src/main/java/com/rabbitmq/client/TrustEverythingTrustManager.java index 544c74f1d8..9001d02507 100644 --- a/src/main/java/com/rabbitmq/client/TrustEverythingTrustManager.java +++ b/src/main/java/com/rabbitmq/client/TrustEverythingTrustManager.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/UnblockedCallback.java b/src/main/java/com/rabbitmq/client/UnblockedCallback.java index 8b3b5a6ad5..76ac083ac7 100644 --- a/src/main/java/com/rabbitmq/client/UnblockedCallback.java +++ b/src/main/java/com/rabbitmq/client/UnblockedCallback.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/UnexpectedFrameError.java b/src/main/java/com/rabbitmq/client/UnexpectedFrameError.java index 1bb425f5d8..e8275aec3a 100644 --- a/src/main/java/com/rabbitmq/client/UnexpectedFrameError.java +++ b/src/main/java/com/rabbitmq/client/UnexpectedFrameError.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/UnexpectedMethodError.java b/src/main/java/com/rabbitmq/client/UnexpectedMethodError.java index 8a14ebea87..ab30336a07 100644 --- a/src/main/java/com/rabbitmq/client/UnexpectedMethodError.java +++ b/src/main/java/com/rabbitmq/client/UnexpectedMethodError.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/UnknownClassOrMethodId.java b/src/main/java/com/rabbitmq/client/UnknownClassOrMethodId.java index 6440c8c0c9..1f0e3715f3 100644 --- a/src/main/java/com/rabbitmq/client/UnknownClassOrMethodId.java +++ b/src/main/java/com/rabbitmq/client/UnknownClassOrMethodId.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/UnroutableRpcRequestException.java b/src/main/java/com/rabbitmq/client/UnroutableRpcRequestException.java index 18ad13aa3c..89e9d059f0 100644 --- a/src/main/java/com/rabbitmq/client/UnroutableRpcRequestException.java +++ b/src/main/java/com/rabbitmq/client/UnroutableRpcRequestException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/AMQBasicProperties.java b/src/main/java/com/rabbitmq/client/impl/AMQBasicProperties.java index 35e2507b0c..591713e706 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQBasicProperties.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQBasicProperties.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java index 3cdcf8c50f..837fdef8d9 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/AMQCommand.java b/src/main/java/com/rabbitmq/client/impl/AMQCommand.java index 929eaa3804..0395bb10f6 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQCommand.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQCommand.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index 8ed2740588..c989b3a972 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 @@ -35,7 +35,7 @@ import java.util.concurrent.atomic.AtomicBoolean; final class Copyright { - final static String COPYRIGHT="Copyright (c) 2007-2020 Pivotal Software, Inc."; + final static String COPYRIGHT="Copyright (c) 2007-2020 VMware, Inc. or its affiliates."; final static String LICENSE="Licensed under the MPL. See https://www.rabbitmq.com/"; } diff --git a/src/main/java/com/rabbitmq/client/impl/AMQContentHeader.java b/src/main/java/com/rabbitmq/client/impl/AMQContentHeader.java index 97028e2376..523336e0ca 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQContentHeader.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQContentHeader.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java index 435a794481..c0a3c5eb6b 100644 --- a/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/CRDemoMechanism.java b/src/main/java/com/rabbitmq/client/impl/CRDemoMechanism.java index b61b4d0ad4..e516750b6c 100644 --- a/src/main/java/com/rabbitmq/client/impl/CRDemoMechanism.java +++ b/src/main/java/com/rabbitmq/client/impl/CRDemoMechanism.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelManager.java b/src/main/java/com/rabbitmq/client/impl/ChannelManager.java index 73b78f71b4..162c141f34 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelManager.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelManager.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java index 5ab12bda20..61f2d0683e 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelN.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ClientVersion.java b/src/main/java/com/rabbitmq/client/impl/ClientVersion.java index dcda1072cd..53ec1b927c 100644 --- a/src/main/java/com/rabbitmq/client/impl/ClientVersion.java +++ b/src/main/java/com/rabbitmq/client/impl/ClientVersion.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/CommandAssembler.java b/src/main/java/com/rabbitmq/client/impl/CommandAssembler.java index da65cef8f2..8a2915c0d7 100644 --- a/src/main/java/com/rabbitmq/client/impl/CommandAssembler.java +++ b/src/main/java/com/rabbitmq/client/impl/CommandAssembler.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/CompletableFutureRpcWrapper.java b/src/main/java/com/rabbitmq/client/impl/CompletableFutureRpcWrapper.java index c2a3e5c649..1f1b91f569 100644 --- a/src/main/java/com/rabbitmq/client/impl/CompletableFutureRpcWrapper.java +++ b/src/main/java/com/rabbitmq/client/impl/CompletableFutureRpcWrapper.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java b/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java index 57a028783b..92428fc436 100644 --- a/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java +++ b/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ConsumerDispatcher.java b/src/main/java/com/rabbitmq/client/impl/ConsumerDispatcher.java index 91b1e7cb3b..bb22d9f626 100644 --- a/src/main/java/com/rabbitmq/client/impl/ConsumerDispatcher.java +++ b/src/main/java/com/rabbitmq/client/impl/ConsumerDispatcher.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ConsumerWorkService.java b/src/main/java/com/rabbitmq/client/impl/ConsumerWorkService.java index 128e9f07e9..bb662d98e7 100644 --- a/src/main/java/com/rabbitmq/client/impl/ConsumerWorkService.java +++ b/src/main/java/com/rabbitmq/client/impl/ConsumerWorkService.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java b/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java index ca1a13411e..d3502e9fe2 100644 --- a/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java +++ b/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java b/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java index ad6211ab6d..59440bc7e7 100644 --- a/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java +++ b/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java index 61bf56713f..abcfb6af17 100644 --- a/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/CredentialsRefreshService.java b/src/main/java/com/rabbitmq/client/impl/CredentialsRefreshService.java index 675fa8fe1b..d365053af1 100644 --- a/src/main/java/com/rabbitmq/client/impl/CredentialsRefreshService.java +++ b/src/main/java/com/rabbitmq/client/impl/CredentialsRefreshService.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java index cd58019bf6..6263524898 100644 --- a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java index d74d749a0d..2beafaad74 100644 --- a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java +++ b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/DefaultExceptionHandler.java b/src/main/java/com/rabbitmq/client/impl/DefaultExceptionHandler.java index 8183a9f296..f1a0def2f3 100644 --- a/src/main/java/com/rabbitmq/client/impl/DefaultExceptionHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/DefaultExceptionHandler.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/Environment.java b/src/main/java/com/rabbitmq/client/impl/Environment.java index 8ee8fab995..c7f6c528b0 100644 --- a/src/main/java/com/rabbitmq/client/impl/Environment.java +++ b/src/main/java/com/rabbitmq/client/impl/Environment.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ErrorOnWriteListener.java b/src/main/java/com/rabbitmq/client/impl/ErrorOnWriteListener.java index 84d493984a..7edf05e994 100644 --- a/src/main/java/com/rabbitmq/client/impl/ErrorOnWriteListener.java +++ b/src/main/java/com/rabbitmq/client/impl/ErrorOnWriteListener.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ExternalMechanism.java b/src/main/java/com/rabbitmq/client/impl/ExternalMechanism.java index 1983589dd9..5cddc69ac4 100644 --- a/src/main/java/com/rabbitmq/client/impl/ExternalMechanism.java +++ b/src/main/java/com/rabbitmq/client/impl/ExternalMechanism.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ForgivingExceptionHandler.java b/src/main/java/com/rabbitmq/client/impl/ForgivingExceptionHandler.java index a91bf86f30..e4c2648394 100644 --- a/src/main/java/com/rabbitmq/client/impl/ForgivingExceptionHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/ForgivingExceptionHandler.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/Frame.java b/src/main/java/com/rabbitmq/client/impl/Frame.java index a5fd59e454..f99b9d1260 100644 --- a/src/main/java/com/rabbitmq/client/impl/Frame.java +++ b/src/main/java/com/rabbitmq/client/impl/Frame.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/FrameHandler.java b/src/main/java/com/rabbitmq/client/impl/FrameHandler.java index 91168340be..0e54b34435 100644 --- a/src/main/java/com/rabbitmq/client/impl/FrameHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/FrameHandler.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/HeartbeatSender.java b/src/main/java/com/rabbitmq/client/impl/HeartbeatSender.java index 69b2c00b83..998581d0a5 100644 --- a/src/main/java/com/rabbitmq/client/impl/HeartbeatSender.java +++ b/src/main/java/com/rabbitmq/client/impl/HeartbeatSender.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/LongStringHelper.java b/src/main/java/com/rabbitmq/client/impl/LongStringHelper.java index de5fc3c55e..d80d9a01f3 100644 --- a/src/main/java/com/rabbitmq/client/impl/LongStringHelper.java +++ b/src/main/java/com/rabbitmq/client/impl/LongStringHelper.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/Method.java b/src/main/java/com/rabbitmq/client/impl/Method.java index c89c377546..0b894416ac 100644 --- a/src/main/java/com/rabbitmq/client/impl/Method.java +++ b/src/main/java/com/rabbitmq/client/impl/Method.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/MethodArgumentReader.java b/src/main/java/com/rabbitmq/client/impl/MethodArgumentReader.java index e61ffc5380..24ab627450 100644 --- a/src/main/java/com/rabbitmq/client/impl/MethodArgumentReader.java +++ b/src/main/java/com/rabbitmq/client/impl/MethodArgumentReader.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/MethodArgumentWriter.java b/src/main/java/com/rabbitmq/client/impl/MethodArgumentWriter.java index db2005d32f..02317eec87 100644 --- a/src/main/java/com/rabbitmq/client/impl/MethodArgumentWriter.java +++ b/src/main/java/com/rabbitmq/client/impl/MethodArgumentWriter.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java index 17db75e9d9..ab910361df 100644 --- a/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/NetworkConnection.java b/src/main/java/com/rabbitmq/client/impl/NetworkConnection.java index 281e36f892..747a1921a7 100644 --- a/src/main/java/com/rabbitmq/client/impl/NetworkConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/NetworkConnection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java index 71635b4baa..da3ff81973 100644 --- a/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/OAuthTokenManagementException.java b/src/main/java/com/rabbitmq/client/impl/OAuthTokenManagementException.java index 62db5e07a5..cf17053b24 100644 --- a/src/main/java/com/rabbitmq/client/impl/OAuthTokenManagementException.java +++ b/src/main/java/com/rabbitmq/client/impl/OAuthTokenManagementException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/PlainMechanism.java b/src/main/java/com/rabbitmq/client/impl/PlainMechanism.java index 7cd9aa70e8..c586385299 100644 --- a/src/main/java/com/rabbitmq/client/impl/PlainMechanism.java +++ b/src/main/java/com/rabbitmq/client/impl/PlainMechanism.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProvider.java index 21f6bc9780..a4cc01c186 100644 --- a/src/main/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProvider.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/RpcContinuationRpcWrapper.java b/src/main/java/com/rabbitmq/client/impl/RpcContinuationRpcWrapper.java index da57ffbae7..8fcf901b55 100644 --- a/src/main/java/com/rabbitmq/client/impl/RpcContinuationRpcWrapper.java +++ b/src/main/java/com/rabbitmq/client/impl/RpcContinuationRpcWrapper.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/RpcWrapper.java b/src/main/java/com/rabbitmq/client/impl/RpcWrapper.java index f504908394..84c3bb0363 100644 --- a/src/main/java/com/rabbitmq/client/impl/RpcWrapper.java +++ b/src/main/java/com/rabbitmq/client/impl/RpcWrapper.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/SetQueue.java b/src/main/java/com/rabbitmq/client/impl/SetQueue.java index 0ad6e86ba9..9ab2cd3526 100644 --- a/src/main/java/com/rabbitmq/client/impl/SetQueue.java +++ b/src/main/java/com/rabbitmq/client/impl/SetQueue.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ShutdownNotifierComponent.java b/src/main/java/com/rabbitmq/client/impl/ShutdownNotifierComponent.java index a8d2a9be93..0ee95e083c 100644 --- a/src/main/java/com/rabbitmq/client/impl/ShutdownNotifierComponent.java +++ b/src/main/java/com/rabbitmq/client/impl/ShutdownNotifierComponent.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java b/src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java index 02cc9a2d2d..8d1d2eee15 100644 --- a/src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/SocketFrameHandlerFactory.java b/src/main/java/com/rabbitmq/client/impl/SocketFrameHandlerFactory.java index 687f90d4fd..0391b31297 100644 --- a/src/main/java/com/rabbitmq/client/impl/SocketFrameHandlerFactory.java +++ b/src/main/java/com/rabbitmq/client/impl/SocketFrameHandlerFactory.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java index ac5896c472..f6273bef19 100644 --- a/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/StrictExceptionHandler.java b/src/main/java/com/rabbitmq/client/impl/StrictExceptionHandler.java index dac47024af..d1f54768b0 100644 --- a/src/main/java/com/rabbitmq/client/impl/StrictExceptionHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/StrictExceptionHandler.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/TlsUtils.java b/src/main/java/com/rabbitmq/client/impl/TlsUtils.java index 938c1ad9d4..5b4290f79c 100644 --- a/src/main/java/com/rabbitmq/client/impl/TlsUtils.java +++ b/src/main/java/com/rabbitmq/client/impl/TlsUtils.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/TruncatedInputStream.java b/src/main/java/com/rabbitmq/client/impl/TruncatedInputStream.java index 0df6d3c492..a572952af8 100644 --- a/src/main/java/com/rabbitmq/client/impl/TruncatedInputStream.java +++ b/src/main/java/com/rabbitmq/client/impl/TruncatedInputStream.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/UnknownChannelException.java b/src/main/java/com/rabbitmq/client/impl/UnknownChannelException.java index 1bf87a0d8f..5e9474c5a9 100644 --- a/src/main/java/com/rabbitmq/client/impl/UnknownChannelException.java +++ b/src/main/java/com/rabbitmq/client/impl/UnknownChannelException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/UpdateSecretExtension.java b/src/main/java/com/rabbitmq/client/impl/UpdateSecretExtension.java index b54b90635c..5edd65813c 100644 --- a/src/main/java/com/rabbitmq/client/impl/UpdateSecretExtension.java +++ b/src/main/java/com/rabbitmq/client/impl/UpdateSecretExtension.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ValueReader.java b/src/main/java/com/rabbitmq/client/impl/ValueReader.java index 32cf9a3732..9611324f3a 100644 --- a/src/main/java/com/rabbitmq/client/impl/ValueReader.java +++ b/src/main/java/com/rabbitmq/client/impl/ValueReader.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ValueWriter.java b/src/main/java/com/rabbitmq/client/impl/ValueWriter.java index 7340cbd718..e6167cec7e 100644 --- a/src/main/java/com/rabbitmq/client/impl/ValueWriter.java +++ b/src/main/java/com/rabbitmq/client/impl/ValueWriter.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java b/src/main/java/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java index 33b4303294..97be3a8270 100644 --- a/src/main/java/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java +++ b/src/main/java/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 @@ -14,7 +14,7 @@ // info@rabbitmq.com. /* - * Modifications Copyright 2015 Pivotal Software, Inc and licenced as per + * Modifications Copyright 2015-2020 VMware, Inc. or its affiliates. and licenced as per * the rest of the RabbitMQ Java client. */ diff --git a/src/main/java/com/rabbitmq/client/impl/Version.java b/src/main/java/com/rabbitmq/client/impl/Version.java index addb073176..109359fe3d 100644 --- a/src/main/java/com/rabbitmq/client/impl/Version.java +++ b/src/main/java/com/rabbitmq/client/impl/Version.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/WorkPool.java b/src/main/java/com/rabbitmq/client/impl/WorkPool.java index dfccd33acf..39b8b743b7 100644 --- a/src/main/java/com/rabbitmq/client/impl/WorkPool.java +++ b/src/main/java/com/rabbitmq/client/impl/WorkPool.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/WorkPoolFullException.java b/src/main/java/com/rabbitmq/client/impl/WorkPoolFullException.java index 146d05f414..eba1fe14cf 100644 --- a/src/main/java/com/rabbitmq/client/impl/WorkPoolFullException.java +++ b/src/main/java/com/rabbitmq/client/impl/WorkPoolFullException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/ByteBufferOutputStream.java b/src/main/java/com/rabbitmq/client/impl/nio/ByteBufferOutputStream.java index a8b951b56a..16fe3f2682 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/ByteBufferOutputStream.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/ByteBufferOutputStream.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java b/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java index 5bb867899f..bc99531070 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/FrameWriteRequest.java b/src/main/java/com/rabbitmq/client/impl/nio/FrameWriteRequest.java index 570fa24e5c..33a5ba5b74 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/FrameWriteRequest.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/FrameWriteRequest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/HeaderWriteRequest.java b/src/main/java/com/rabbitmq/client/impl/nio/HeaderWriteRequest.java index 96e35849e4..79e34359c3 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/HeaderWriteRequest.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/HeaderWriteRequest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioHelper.java b/src/main/java/com/rabbitmq/client/impl/nio/NioHelper.java index 277025222f..3438013c1f 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioHelper.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioHelper.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java b/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java index e153e721c8..f194eeef42 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioLoopContext.java b/src/main/java/com/rabbitmq/client/impl/nio/NioLoopContext.java index a74a99f5a2..47639cfc35 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioLoopContext.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioLoopContext.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java b/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java index ea555283cc..fa0f545605 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SelectorHolder.java b/src/main/java/com/rabbitmq/client/impl/nio/SelectorHolder.java index 8542e52cb1..7426280acb 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SelectorHolder.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SelectorHolder.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandler.java b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandler.java index 8e9bab5dc5..d46ce4e0bb 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandler.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java index 784a5f80cd..f4473b8ae3 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java index bea18489c7..b5822fcd91 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelRegistration.java b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelRegistration.java index e09dee9010..2befb3d3a6 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelRegistration.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelRegistration.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferOutputStream.java b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferOutputStream.java index 11145eae1e..8ec782613d 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferOutputStream.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferOutputStream.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineFrameBuilder.java b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineFrameBuilder.java index 056470aae4..141bb47293 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineFrameBuilder.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineFrameBuilder.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java index c4b8a33c26..0de786c7b3 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/WriteRequest.java b/src/main/java/com/rabbitmq/client/impl/nio/WriteRequest.java index 635c8bc426..b696bc421f 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/WriteRequest.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/WriteRequest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java index e74170d247..969fb45593 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index 379961971c..f04e3778d5 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/BackoffPolicy.java b/src/main/java/com/rabbitmq/client/impl/recovery/BackoffPolicy.java index a05c2a8a3c..6ed2a2deef 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/BackoffPolicy.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/BackoffPolicy.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/ConsumerRecoveryListener.java b/src/main/java/com/rabbitmq/client/impl/recovery/ConsumerRecoveryListener.java index 1018f9a332..291528af3e 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/ConsumerRecoveryListener.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/ConsumerRecoveryListener.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java b/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java index ec9a86cbc8..1fa64afa4e 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/QueueRecoveryListener.java b/src/main/java/com/rabbitmq/client/impl/recovery/QueueRecoveryListener.java index ca3d518685..55eef2d9f1 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/QueueRecoveryListener.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/QueueRecoveryListener.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedBinding.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedBinding.java index 4b144ae00b..2cdf188ed7 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedBinding.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedBinding.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedConsumer.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedConsumer.java index 1eb9c7a943..4aa87a2d0b 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedConsumer.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedConsumer.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedEntity.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedEntity.java index b92dd6028b..c55a398563 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedEntity.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedEntity.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchange.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchange.java index 2884604fdc..d75530fad6 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchange.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchange.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchangeBinding.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchangeBinding.java index 3b6d72881d..286b793185 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchangeBinding.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchangeBinding.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedNamedEntity.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedNamedEntity.java index 7bb2e43514..b00a9c2df4 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedNamedEntity.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedNamedEntity.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java index f446e1682c..6cb43cfdae 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java index a933ce3acd..09d2636d32 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnection.java index b50e7027e5..94768de1db 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java index 3b326a76bf..01a172fac3 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelManager.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelManager.java index aed1cffc05..b9daf354f2 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelManager.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelManager.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java index faaa095bf6..206c20a1c7 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryCanBeginListener.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryCanBeginListener.java index fc21af6bc6..2c272198b4 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryCanBeginListener.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryCanBeginListener.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RetryContext.java b/src/main/java/com/rabbitmq/client/impl/recovery/RetryContext.java index a9bdc05e5f..60645e199a 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RetryContext.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RetryContext.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RetryHandler.java b/src/main/java/com/rabbitmq/client/impl/recovery/RetryHandler.java index 5ed7f823f0..459ca80080 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RetryHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RetryHandler.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RetryResult.java b/src/main/java/com/rabbitmq/client/impl/recovery/RetryResult.java index c4797c39bf..6c4e693314 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RetryResult.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RetryResult.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryFilter.java b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryFilter.java index d5f0ec9a26..835249ec55 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryFilter.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryFilter.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryHandlerBuilder.java b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryHandlerBuilder.java index 887a494bc5..c2ad1078d5 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryHandlerBuilder.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryHandlerBuilder.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java index 26db1f27a8..8daa2ac33e 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/tools/json/JSONReader.java b/src/main/java/com/rabbitmq/tools/json/JSONReader.java index 5bd332c7bd..c22ee8eb00 100644 --- a/src/main/java/com/rabbitmq/tools/json/JSONReader.java +++ b/src/main/java/com/rabbitmq/tools/json/JSONReader.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 @@ -15,7 +15,7 @@ /* Copyright (c) 2006-2007 Frank Carver - Copyright (c) 2007-2016 Pivotal Software, Inc. All Rights Reserved + Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All Rights Reserved Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/src/main/java/com/rabbitmq/tools/json/JSONSerializable.java b/src/main/java/com/rabbitmq/tools/json/JSONSerializable.java index 39f72d4ac2..e3fdcd1180 100644 --- a/src/main/java/com/rabbitmq/tools/json/JSONSerializable.java +++ b/src/main/java/com/rabbitmq/tools/json/JSONSerializable.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/tools/json/JSONUtil.java b/src/main/java/com/rabbitmq/tools/json/JSONUtil.java index c024e142c8..f814462e5e 100644 --- a/src/main/java/com/rabbitmq/tools/json/JSONUtil.java +++ b/src/main/java/com/rabbitmq/tools/json/JSONUtil.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/tools/json/JSONWriter.java b/src/main/java/com/rabbitmq/tools/json/JSONWriter.java index ec05322c34..187fb5402f 100644 --- a/src/main/java/com/rabbitmq/tools/json/JSONWriter.java +++ b/src/main/java/com/rabbitmq/tools/json/JSONWriter.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 @@ -15,7 +15,7 @@ /* Copyright (c) 2006-2007 Frank Carver - Copyright (c) 2007-2016 Pivotal Software, Inc. All Rights Reserved + Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All Rights Reserved Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/DefaultJsonRpcMapper.java b/src/main/java/com/rabbitmq/tools/jsonrpc/DefaultJsonRpcMapper.java index c9c050e02a..204e68007b 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/DefaultJsonRpcMapper.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/DefaultJsonRpcMapper.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java index 6c1775cf8c..8b239eed5b 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java index 870eadd843..bea5ccf690 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java index 18c0e93b84..c46b95c259 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java index fdad5e1960..6e311dc6e4 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMappingException.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMappingException.java index 03a7d12b91..6a764e6960 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMappingException.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMappingException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java index 61a3796647..6cfe8eec98 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/ParameterDescription.java b/src/main/java/com/rabbitmq/tools/jsonrpc/ParameterDescription.java index 97fb9d0d01..6106cbf60c 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/ParameterDescription.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/ParameterDescription.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java b/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java index db637d1c38..44ac3a0b76 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java b/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java index a42a1b2f1d..af2029d98c 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/utility/BlockingCell.java b/src/main/java/com/rabbitmq/utility/BlockingCell.java index 7fc8ec5641..9f9dce24a4 100644 --- a/src/main/java/com/rabbitmq/utility/BlockingCell.java +++ b/src/main/java/com/rabbitmq/utility/BlockingCell.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/utility/BlockingValueOrException.java b/src/main/java/com/rabbitmq/utility/BlockingValueOrException.java index 683358c206..77df219b72 100644 --- a/src/main/java/com/rabbitmq/utility/BlockingValueOrException.java +++ b/src/main/java/com/rabbitmq/utility/BlockingValueOrException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/utility/IntAllocator.java b/src/main/java/com/rabbitmq/utility/IntAllocator.java index 6032a4dcc8..9c1e93cd1f 100644 --- a/src/main/java/com/rabbitmq/utility/IntAllocator.java +++ b/src/main/java/com/rabbitmq/utility/IntAllocator.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/utility/SensibleClone.java b/src/main/java/com/rabbitmq/utility/SensibleClone.java index 01f51b4f21..50405ec0eb 100644 --- a/src/main/java/com/rabbitmq/utility/SensibleClone.java +++ b/src/main/java/com/rabbitmq/utility/SensibleClone.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/utility/Utility.java b/src/main/java/com/rabbitmq/utility/Utility.java index d345717fc4..f4cbbf324d 100644 --- a/src/main/java/com/rabbitmq/utility/Utility.java +++ b/src/main/java/com/rabbitmq/utility/Utility.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/utility/ValueOrException.java b/src/main/java/com/rabbitmq/utility/ValueOrException.java index d882b28430..7be45ef8a2 100644 --- a/src/main/java/com/rabbitmq/utility/ValueOrException.java +++ b/src/main/java/com/rabbitmq/utility/ValueOrException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/AbstractJsonRpcTest.java b/src/test/java/com/rabbitmq/client/AbstractJsonRpcTest.java index e9ec771bd7..017cb6e308 100644 --- a/src/test/java/com/rabbitmq/client/AbstractJsonRpcTest.java +++ b/src/test/java/com/rabbitmq/client/AbstractJsonRpcTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/DefaultJsonRpcTest.java b/src/test/java/com/rabbitmq/client/DefaultJsonRpcTest.java index 049554d1d2..42cd9cfa66 100644 --- a/src/test/java/com/rabbitmq/client/DefaultJsonRpcTest.java +++ b/src/test/java/com/rabbitmq/client/DefaultJsonRpcTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/JacksonJsonRpcTest.java b/src/test/java/com/rabbitmq/client/JacksonJsonRpcTest.java index 091ce44680..af9b827810 100644 --- a/src/test/java/com/rabbitmq/client/JacksonJsonRpcTest.java +++ b/src/test/java/com/rabbitmq/client/JacksonJsonRpcTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/QueueingConsumer.java b/src/test/java/com/rabbitmq/client/QueueingConsumer.java index e803720e42..434e7a8d82 100644 --- a/src/test/java/com/rabbitmq/client/QueueingConsumer.java +++ b/src/test/java/com/rabbitmq/client/QueueingConsumer.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/impl/AMQConnectionRefreshCredentialsTest.java b/src/test/java/com/rabbitmq/client/impl/AMQConnectionRefreshCredentialsTest.java index 6293b39a1c..50493bcbd0 100644 --- a/src/test/java/com/rabbitmq/client/impl/AMQConnectionRefreshCredentialsTest.java +++ b/src/test/java/com/rabbitmq/client/impl/AMQConnectionRefreshCredentialsTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java b/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java index 7009319b9c..21faa59b15 100644 --- a/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java +++ b/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java b/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java index e1d1c5abbf..d81722779d 100644 --- a/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java +++ b/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProviderTest.java b/src/test/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProviderTest.java index a96c757e59..d273b3e70b 100644 --- a/src/test/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProviderTest.java +++ b/src/test/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProviderTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java b/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java index 76cbd0d6df..ead66ee8ad 100644 --- a/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java +++ b/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java b/src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java index fec748d205..30141ef9f0 100644 --- a/src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java +++ b/src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/AMQBuilderApiTest.java b/src/test/java/com/rabbitmq/client/test/AMQBuilderApiTest.java index 27a3f5b304..9d6fb50abb 100644 --- a/src/test/java/com/rabbitmq/client/test/AMQBuilderApiTest.java +++ b/src/test/java/com/rabbitmq/client/test/AMQBuilderApiTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/AMQChannelTest.java b/src/test/java/com/rabbitmq/client/test/AMQChannelTest.java index 04554f4aa5..cb5f65d4fb 100644 --- a/src/test/java/com/rabbitmq/client/test/AMQChannelTest.java +++ b/src/test/java/com/rabbitmq/client/test/AMQChannelTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java b/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java index ece2e42e05..c278b4cc13 100644 --- a/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java +++ b/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java b/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java index cb27d22e7c..70fdbaaa6e 100644 --- a/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java +++ b/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/AddressTest.java b/src/test/java/com/rabbitmq/client/test/AddressTest.java index a67bd96c86..ca714b146b 100644 --- a/src/test/java/com/rabbitmq/client/test/AddressTest.java +++ b/src/test/java/com/rabbitmq/client/test/AddressTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java b/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java index 11cd5bf248..9b4b467f9c 100644 --- a/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java +++ b/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/BlockingCellTest.java b/src/test/java/com/rabbitmq/client/test/BlockingCellTest.java index 83cc168694..7c4ef998b0 100644 --- a/src/test/java/com/rabbitmq/client/test/BlockingCellTest.java +++ b/src/test/java/com/rabbitmq/client/test/BlockingCellTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java b/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java index b9853a6731..0d713308d2 100644 --- a/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java +++ b/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java index 2608c0ca2e..cda8d3ca44 100644 --- a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java +++ b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/Bug20004Test.java b/src/test/java/com/rabbitmq/client/test/Bug20004Test.java index 58581f076f..ac62af0095 100644 --- a/src/test/java/com/rabbitmq/client/test/Bug20004Test.java +++ b/src/test/java/com/rabbitmq/client/test/Bug20004Test.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ChannelAsyncCompletableFutureTest.java b/src/test/java/com/rabbitmq/client/test/ChannelAsyncCompletableFutureTest.java index c6e51f777f..cc1141d116 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelAsyncCompletableFutureTest.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelAsyncCompletableFutureTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ChannelNTest.java b/src/test/java/com/rabbitmq/client/test/ChannelNTest.java index f6e85e686e..214173a577 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelNTest.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelNTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ChannelNumberAllocationTests.java b/src/test/java/com/rabbitmq/client/test/ChannelNumberAllocationTests.java index 93329ab822..a3ec4b81f7 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelNumberAllocationTests.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelNumberAllocationTests.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java b/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java index 875d608d96..87494900a6 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index 24a86ea7fa..1d1be76fda 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ClientVersionTest.java b/src/test/java/com/rabbitmq/client/test/ClientVersionTest.java index 33b15a956b..3c36dd7015 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientVersionTest.java +++ b/src/test/java/com/rabbitmq/client/test/ClientVersionTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ClonePropertiesTest.java b/src/test/java/com/rabbitmq/client/test/ClonePropertiesTest.java index 153095ee01..6e50f31e29 100644 --- a/src/test/java/com/rabbitmq/client/test/ClonePropertiesTest.java +++ b/src/test/java/com/rabbitmq/client/test/ClonePropertiesTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/CloseInMainLoop.java b/src/test/java/com/rabbitmq/client/test/CloseInMainLoop.java index 623ce9a516..109f8200aa 100644 --- a/src/test/java/com/rabbitmq/client/test/CloseInMainLoop.java +++ b/src/test/java/com/rabbitmq/client/test/CloseInMainLoop.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ConfirmBase.java b/src/test/java/com/rabbitmq/client/test/ConfirmBase.java index 099f8e8d04..2421bfed40 100644 --- a/src/test/java/com/rabbitmq/client/test/ConfirmBase.java +++ b/src/test/java/com/rabbitmq/client/test/ConfirmBase.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java b/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java index adca51336a..feacb2327c 100644 --- a/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java +++ b/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ConnectionTest.java b/src/test/java/com/rabbitmq/client/test/ConnectionTest.java index 85dc789130..cef3e68a18 100644 --- a/src/test/java/com/rabbitmq/client/test/ConnectionTest.java +++ b/src/test/java/com/rabbitmq/client/test/ConnectionTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/DefaultRetryHandlerTest.java b/src/test/java/com/rabbitmq/client/test/DefaultRetryHandlerTest.java index cc105304a7..c6fe244c51 100644 --- a/src/test/java/com/rabbitmq/client/test/DefaultRetryHandlerTest.java +++ b/src/test/java/com/rabbitmq/client/test/DefaultRetryHandlerTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/DnsSrvRecordAddressResolverTest.java b/src/test/java/com/rabbitmq/client/test/DnsSrvRecordAddressResolverTest.java index 82bdea47de..886aa1f533 100644 --- a/src/test/java/com/rabbitmq/client/test/DnsSrvRecordAddressResolverTest.java +++ b/src/test/java/com/rabbitmq/client/test/DnsSrvRecordAddressResolverTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java b/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java index ce71a779a7..64013cadd8 100644 --- a/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java +++ b/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/GeneratedClassesTest.java b/src/test/java/com/rabbitmq/client/test/GeneratedClassesTest.java index e9dbcfca98..c144e7e3d3 100644 --- a/src/test/java/com/rabbitmq/client/test/GeneratedClassesTest.java +++ b/src/test/java/com/rabbitmq/client/test/GeneratedClassesTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/JSONReadWriteTest.java b/src/test/java/com/rabbitmq/client/test/JSONReadWriteTest.java index 44f322f2e0..3c71951aab 100644 --- a/src/test/java/com/rabbitmq/client/test/JSONReadWriteTest.java +++ b/src/test/java/com/rabbitmq/client/test/JSONReadWriteTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/LambdaCallbackTest.java b/src/test/java/com/rabbitmq/client/test/LambdaCallbackTest.java index 571824a73a..29505b73ab 100644 --- a/src/test/java/com/rabbitmq/client/test/LambdaCallbackTest.java +++ b/src/test/java/com/rabbitmq/client/test/LambdaCallbackTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/LongStringTest.java b/src/test/java/com/rabbitmq/client/test/LongStringTest.java index df04cddd51..59f9556e2c 100644 --- a/src/test/java/com/rabbitmq/client/test/LongStringTest.java +++ b/src/test/java/com/rabbitmq/client/test/LongStringTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java b/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java index 74f85ac668..27b4f21cd8 100644 --- a/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java +++ b/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/MicrometerMetricsCollectorTest.java b/src/test/java/com/rabbitmq/client/test/MicrometerMetricsCollectorTest.java index b84c956852..5cc8aa6178 100644 --- a/src/test/java/com/rabbitmq/client/test/MicrometerMetricsCollectorTest.java +++ b/src/test/java/com/rabbitmq/client/test/MicrometerMetricsCollectorTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/MultiThreadedChannel.java b/src/test/java/com/rabbitmq/client/test/MultiThreadedChannel.java index d583a03b4a..4790016a40 100644 --- a/src/test/java/com/rabbitmq/client/test/MultiThreadedChannel.java +++ b/src/test/java/com/rabbitmq/client/test/MultiThreadedChannel.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/NioDeadlockOnConnectionClosing.java b/src/test/java/com/rabbitmq/client/test/NioDeadlockOnConnectionClosing.java index 78082344b1..c9e1607653 100644 --- a/src/test/java/com/rabbitmq/client/test/NioDeadlockOnConnectionClosing.java +++ b/src/test/java/com/rabbitmq/client/test/NioDeadlockOnConnectionClosing.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java b/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java index 1047dc4287..5014bcda2f 100644 --- a/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java +++ b/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java b/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java index 34b6a63054..3d6099e12c 100644 --- a/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java +++ b/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/QueueingConsumerTests.java b/src/test/java/com/rabbitmq/client/test/QueueingConsumerTests.java index cf5114faef..01676ade92 100644 --- a/src/test/java/com/rabbitmq/client/test/QueueingConsumerTests.java +++ b/src/test/java/com/rabbitmq/client/test/QueueingConsumerTests.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/RecoveryAwareAMQConnectionFactoryTest.java b/src/test/java/com/rabbitmq/client/test/RecoveryAwareAMQConnectionFactoryTest.java index 704c252bc0..f09721a036 100644 --- a/src/test/java/com/rabbitmq/client/test/RecoveryAwareAMQConnectionFactoryTest.java +++ b/src/test/java/com/rabbitmq/client/test/RecoveryAwareAMQConnectionFactoryTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/RecoveryDelayHandlerTest.java b/src/test/java/com/rabbitmq/client/test/RecoveryDelayHandlerTest.java index 1b988251f3..7828b5eefe 100644 --- a/src/test/java/com/rabbitmq/client/test/RecoveryDelayHandlerTest.java +++ b/src/test/java/com/rabbitmq/client/test/RecoveryDelayHandlerTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java b/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java index defa0c4b4f..b72c95ee1d 100644 --- a/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java +++ b/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/RpcTest.java b/src/test/java/com/rabbitmq/client/test/RpcTest.java index 027c1e081a..87d0be518b 100644 --- a/src/test/java/com/rabbitmq/client/test/RpcTest.java +++ b/src/test/java/com/rabbitmq/client/test/RpcTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/RpcTopologyRecordingTest.java b/src/test/java/com/rabbitmq/client/test/RpcTopologyRecordingTest.java index 47c56b9953..1f0f023018 100644 --- a/src/test/java/com/rabbitmq/client/test/RpcTopologyRecordingTest.java +++ b/src/test/java/com/rabbitmq/client/test/RpcTopologyRecordingTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java b/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java index 15d7749a37..a1fe0175f5 100644 --- a/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java +++ b/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/SslContextFactoryTest.java b/src/test/java/com/rabbitmq/client/test/SslContextFactoryTest.java index ed930c111e..4f591221ce 100644 --- a/src/test/java/com/rabbitmq/client/test/SslContextFactoryTest.java +++ b/src/test/java/com/rabbitmq/client/test/SslContextFactoryTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/StrictExceptionHandlerTest.java b/src/test/java/com/rabbitmq/client/test/StrictExceptionHandlerTest.java index 3b09ede84b..300d8ad053 100644 --- a/src/test/java/com/rabbitmq/client/test/StrictExceptionHandlerTest.java +++ b/src/test/java/com/rabbitmq/client/test/StrictExceptionHandlerTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/TableTest.java b/src/test/java/com/rabbitmq/client/test/TableTest.java index 630c7fc34d..e750301413 100644 --- a/src/test/java/com/rabbitmq/client/test/TableTest.java +++ b/src/test/java/com/rabbitmq/client/test/TableTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/TestUtils.java b/src/test/java/com/rabbitmq/client/test/TestUtils.java index 57d80db95c..012882d3f4 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtils.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtils.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/TestUtilsTest.java b/src/test/java/com/rabbitmq/client/test/TestUtilsTest.java index 00374f3a4e..1de1fe975a 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtilsTest.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtilsTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/TlsUtilsTest.java b/src/test/java/com/rabbitmq/client/test/TlsUtilsTest.java index e632e47282..078989ca12 100644 --- a/src/test/java/com/rabbitmq/client/test/TlsUtilsTest.java +++ b/src/test/java/com/rabbitmq/client/test/TlsUtilsTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/TrafficListenerTest.java b/src/test/java/com/rabbitmq/client/test/TrafficListenerTest.java index d860678d98..69c223cf31 100644 --- a/src/test/java/com/rabbitmq/client/test/TrafficListenerTest.java +++ b/src/test/java/com/rabbitmq/client/test/TrafficListenerTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/TruncatedInputStreamTest.java b/src/test/java/com/rabbitmq/client/test/TruncatedInputStreamTest.java index 4409798a17..570f15c848 100644 --- a/src/test/java/com/rabbitmq/client/test/TruncatedInputStreamTest.java +++ b/src/test/java/com/rabbitmq/client/test/TruncatedInputStreamTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ValueOrExceptionTest.java b/src/test/java/com/rabbitmq/client/test/ValueOrExceptionTest.java index de58c84aba..789dccfa29 100644 --- a/src/test/java/com/rabbitmq/client/test/ValueOrExceptionTest.java +++ b/src/test/java/com/rabbitmq/client/test/ValueOrExceptionTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/AbstractRejectTest.java b/src/test/java/com/rabbitmq/client/test/functional/AbstractRejectTest.java index 9d58d590de..470418c384 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/AbstractRejectTest.java +++ b/src/test/java/com/rabbitmq/client/test/functional/AbstractRejectTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/AlternateExchange.java b/src/test/java/com/rabbitmq/client/test/functional/AlternateExchange.java index 242e95032b..fc620a5034 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/AlternateExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/AlternateExchange.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/BasicGet.java b/src/test/java/com/rabbitmq/client/test/functional/BasicGet.java index dddd17e8d6..1e854ec495 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/BasicGet.java +++ b/src/test/java/com/rabbitmq/client/test/functional/BasicGet.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java b/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java index 0223c4c878..48c82a22ad 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java +++ b/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycleBase.java b/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycleBase.java index bb5f24c634..ae21a981f5 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycleBase.java +++ b/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycleBase.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java b/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java index 7e02faae15..4782459840 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java +++ b/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java b/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java index 6d1b430cf9..c3ae467c4f 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/Confirm.java b/src/test/java/com/rabbitmq/client/test/functional/Confirm.java index 3e66e18f15..9f0860b820 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Confirm.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Confirm.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionOpen.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionOpen.java index 91b6f18ba9..9f99ba1797 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionOpen.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionOpen.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java index 04cf8b04d2..486e5448ce 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java b/src/test/java/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java index fdda32ea18..082725531b 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConsumerCount.java b/src/test/java/com/rabbitmq/client/test/functional/ConsumerCount.java index e4230d9f92..73f91a5e10 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConsumerCount.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConsumerCount.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConsumerPriorities.java b/src/test/java/com/rabbitmq/client/test/functional/ConsumerPriorities.java index 7193decee2..a3eebd85bb 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConsumerPriorities.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConsumerPriorities.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java index 6a7f97725e..fa6124ce16 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/DefaultExchange.java b/src/test/java/com/rabbitmq/client/test/functional/DefaultExchange.java index fb27da6391..df2ceb5fdd 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DefaultExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DefaultExchange.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/DirectReplyTo.java b/src/test/java/com/rabbitmq/client/test/functional/DirectReplyTo.java index 1573c5f4c4..c8d1befec1 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DirectReplyTo.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DirectReplyTo.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/DoubleDeletion.java b/src/test/java/com/rabbitmq/client/test/functional/DoubleDeletion.java index 305b152fab..20b87d7312 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DoubleDeletion.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DoubleDeletion.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/DurableOnTransient.java b/src/test/java/com/rabbitmq/client/test/functional/DurableOnTransient.java index adb11c9bf3..dc9f5d5155 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DurableOnTransient.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DurableOnTransient.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExceptionHandling.java b/src/test/java/com/rabbitmq/client/test/functional/ExceptionHandling.java index f0c22e90f6..f0c73fcd17 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExceptionHandling.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExceptionHandling.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExceptionMessages.java b/src/test/java/com/rabbitmq/client/test/functional/ExceptionMessages.java index 88b53a8b9a..d2810dcb94 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExceptionMessages.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExceptionMessages.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java index 2eeef91572..5578560302 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java index dab4ebd080..ec763486f0 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeletePredeclared.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeletePredeclared.java index 0b1cf6969b..ee25ca6232 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeletePredeclared.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeletePredeclared.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java index 0e8bfcd92a..f2f3916ca5 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java index 739da0c71a..b3ed2f5a3a 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java index baf7a1ce6a..15f63fbd48 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java b/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java index 303d01e00d..ac1e98e7e6 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java +++ b/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java b/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java index fb48f29585..f8a89554a5 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java +++ b/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java b/src/test/java/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java index ac28b3ed68..2ff1a36781 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java +++ b/src/test/java/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java b/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java index 14c58c60a0..b4f9c9b756 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/InternalExchange.java b/src/test/java/com/rabbitmq/client/test/functional/InternalExchange.java index 97b34bfdba..cfb705b06b 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/InternalExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/InternalExchange.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/InvalidAcks.java b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcks.java index b869378d50..dff81c600b 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/InvalidAcks.java +++ b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcks.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksBase.java b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksBase.java index e71404a268..025954022f 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksBase.java +++ b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksBase.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksTx.java b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksTx.java index 388c7ee414..635929bb4b 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksTx.java +++ b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksTx.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/MessageCount.java b/src/test/java/com/rabbitmq/client/test/functional/MessageCount.java index 9820e6aa68..a8d302a55a 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/MessageCount.java +++ b/src/test/java/com/rabbitmq/client/test/functional/MessageCount.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java index a39770f125..98b82ed7af 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/Nack.java b/src/test/java/com/rabbitmq/client/test/functional/Nack.java index 65057cb363..5b39638d78 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Nack.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Nack.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java b/src/test/java/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java index c7b220e660..829cf3d25f 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java +++ b/src/test/java/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/Nowait.java b/src/test/java/com/rabbitmq/client/test/functional/Nowait.java index b6c03cb593..af79b0d195 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Nowait.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Nowait.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java b/src/test/java/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java index 31dd63f3a0..16a1cfdf95 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java +++ b/src/test/java/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/PerMessageTTL.java b/src/test/java/com/rabbitmq/client/test/functional/PerMessageTTL.java index 00a3adc98d..0b25fbe699 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/PerMessageTTL.java +++ b/src/test/java/com/rabbitmq/client/test/functional/PerMessageTTL.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/PerQueueTTL.java b/src/test/java/com/rabbitmq/client/test/functional/PerQueueTTL.java index 8a221e2bb6..55c44e6cb3 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/PerQueueTTL.java +++ b/src/test/java/com/rabbitmq/client/test/functional/PerQueueTTL.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java b/src/test/java/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java index b586c98c5d..f4c9914bda 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java +++ b/src/test/java/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/Policies.java b/src/test/java/com/rabbitmq/client/test/functional/Policies.java index f1dba4d33d..8f86294766 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Policies.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Policies.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/QosTests.java b/src/test/java/com/rabbitmq/client/test/functional/QosTests.java index 637df3c894..1634741a83 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QosTests.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QosTests.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/QueueExclusivity.java b/src/test/java/com/rabbitmq/client/test/functional/QueueExclusivity.java index 5d7f84663a..3351b1d1a6 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QueueExclusivity.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QueueExclusivity.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/QueueLease.java b/src/test/java/com/rabbitmq/client/test/functional/QueueLease.java index b5ab03a48d..3ec1986792 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QueueLease.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QueueLease.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java b/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java index 77c5e6df92..c082a91c41 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/QueueSizeLimit.java b/src/test/java/com/rabbitmq/client/test/functional/QueueSizeLimit.java index 7bec3e47c2..fd4c26343e 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QueueSizeLimit.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QueueSizeLimit.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/Recover.java b/src/test/java/com/rabbitmq/client/test/functional/Recover.java index 0d764cc6b1..654846648f 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Recover.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Recover.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/Reject.java b/src/test/java/com/rabbitmq/client/test/functional/Reject.java index 0a99111137..11f3d52d37 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Reject.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Reject.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java index c9e44830c3..6b1eb781a0 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java +++ b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/RequeueOnClose.java b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnClose.java index 35150997a8..1900f97218 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/RequeueOnClose.java +++ b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnClose.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java index 8f36f0e2b6..6af8d01dd2 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java +++ b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/Routing.java b/src/test/java/com/rabbitmq/client/test/functional/Routing.java index f4efdab194..cfaf9eb38b 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Routing.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Routing.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/SaslMechanisms.java b/src/test/java/com/rabbitmq/client/test/functional/SaslMechanisms.java index d4dcf9130d..1d769f8a10 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/SaslMechanisms.java +++ b/src/test/java/com/rabbitmq/client/test/functional/SaslMechanisms.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/TTLHandling.java b/src/test/java/com/rabbitmq/client/test/functional/TTLHandling.java index 40719510fa..26d501e35f 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/TTLHandling.java +++ b/src/test/java/com/rabbitmq/client/test/functional/TTLHandling.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/Tables.java b/src/test/java/com/rabbitmq/client/test/functional/Tables.java index 009d8c827e..ad631596e9 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Tables.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Tables.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java index 3eb9687eea..e8c3ff1148 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java +++ b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java index f6dc2ac5ae..215645fcaf 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java +++ b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/Transactions.java b/src/test/java/com/rabbitmq/client/test/functional/Transactions.java index ff677dde35..25fb8410c5 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Transactions.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Transactions.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java b/src/test/java/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java index cb9491a6e7..fcafc73ebb 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java b/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java index 2599a7663c..de118e90dd 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java +++ b/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/UserIDHeader.java b/src/test/java/com/rabbitmq/client/test/functional/UserIDHeader.java index 7d64fee7a7..17db1bc8a8 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/UserIDHeader.java +++ b/src/test/java/com/rabbitmq/client/test/functional/UserIDHeader.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java b/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java index 83c1be3454..886820c094 100644 --- a/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java +++ b/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java b/src/test/java/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java index 213240039d..fbc019b263 100644 --- a/src/test/java/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java +++ b/src/test/java/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java b/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java index 61a84ae731..30e07d3a2c 100644 --- a/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/Bug19219Test.java b/src/test/java/com/rabbitmq/client/test/server/Bug19219Test.java index f048252728..7f48b7aeb4 100644 --- a/src/test/java/com/rabbitmq/client/test/server/Bug19219Test.java +++ b/src/test/java/com/rabbitmq/client/test/server/Bug19219Test.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java b/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java index f6500b0677..cd8a99ed34 100644 --- a/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java +++ b/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java b/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java index c6c4e85c91..8ee7169797 100644 --- a/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java +++ b/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java b/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java index 388a3ce7a5..a8c4ff6b8d 100644 --- a/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java +++ b/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java b/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java index cea5f368a1..0aa40943fe 100644 --- a/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java +++ b/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java b/src/test/java/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java index 57cb457087..7d931f12cf 100644 --- a/src/test/java/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java +++ b/src/test/java/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/Firehose.java b/src/test/java/com/rabbitmq/client/test/server/Firehose.java index c1c95ab8a4..56b0cdcb10 100644 --- a/src/test/java/com/rabbitmq/client/test/server/Firehose.java +++ b/src/test/java/com/rabbitmq/client/test/server/Firehose.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/HATests.java b/src/test/java/com/rabbitmq/client/test/server/HATests.java index 17b8ad1351..8918098f5d 100644 --- a/src/test/java/com/rabbitmq/client/test/server/HATests.java +++ b/src/test/java/com/rabbitmq/client/test/server/HATests.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/LoopbackUsers.java b/src/test/java/com/rabbitmq/client/test/server/LoopbackUsers.java index a7ddad4560..d9b7be93b1 100644 --- a/src/test/java/com/rabbitmq/client/test/server/LoopbackUsers.java +++ b/src/test/java/com/rabbitmq/client/test/server/LoopbackUsers.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java b/src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java index 76a092d868..b664e7b62e 100644 --- a/src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java +++ b/src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java b/src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java index 71df04dce5..4080fdce8c 100644 --- a/src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/Permissions.java b/src/test/java/com/rabbitmq/client/test/server/Permissions.java index 233b85e9cc..24c25a4391 100644 --- a/src/test/java/com/rabbitmq/client/test/server/Permissions.java +++ b/src/test/java/com/rabbitmq/client/test/server/Permissions.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/PersistenceGuarantees.java b/src/test/java/com/rabbitmq/client/test/server/PersistenceGuarantees.java index 4070393600..42846db2a1 100644 --- a/src/test/java/com/rabbitmq/client/test/server/PersistenceGuarantees.java +++ b/src/test/java/com/rabbitmq/client/test/server/PersistenceGuarantees.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/PriorityQueues.java b/src/test/java/com/rabbitmq/client/test/server/PriorityQueues.java index ad1629bd62..805b5c6fc4 100644 --- a/src/test/java/com/rabbitmq/client/test/server/PriorityQueues.java +++ b/src/test/java/com/rabbitmq/client/test/server/PriorityQueues.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/ServerTests.java b/src/test/java/com/rabbitmq/client/test/server/ServerTests.java index bf8631a4b8..bda7cac3fd 100644 --- a/src/test/java/com/rabbitmq/client/test/server/ServerTests.java +++ b/src/test/java/com/rabbitmq/client/test/server/ServerTests.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/Shutdown.java b/src/test/java/com/rabbitmq/client/test/server/Shutdown.java index bab3724818..53cd63c184 100644 --- a/src/test/java/com/rabbitmq/client/test/server/Shutdown.java +++ b/src/test/java/com/rabbitmq/client/test/server/Shutdown.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/TopicPermissions.java b/src/test/java/com/rabbitmq/client/test/server/TopicPermissions.java index 1a5c02a4c8..c258e7a773 100644 --- a/src/test/java/com/rabbitmq/client/test/server/TopicPermissions.java +++ b/src/test/java/com/rabbitmq/client/test/server/TopicPermissions.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java b/src/test/java/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java index 16bd88ab02..4aa0839f39 100644 --- a/src/test/java/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java +++ b/src/test/java/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java index a11998c499..9b9e291314 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java b/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java index 9d6546572b..0ffbc52df5 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java index 71b6a497f9..9fef361381 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java index 07ac30a901..4c22736e8b 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java index 88107b41fe..0dbb808584 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java b/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java index 6eb865ea41..845e0a476c 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java index 6d65599b4c..dd041fef5c 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java index e662113085..52c3763064 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/tools/Host.java b/src/test/java/com/rabbitmq/tools/Host.java index c30ec7fc6f..91f4c68f50 100644 --- a/src/test/java/com/rabbitmq/tools/Host.java +++ b/src/test/java/com/rabbitmq/tools/Host.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/utility/IntAllocatorTests.java b/src/test/java/com/rabbitmq/utility/IntAllocatorTests.java index 96586f5686..1dbdfa95a6 100644 --- a/src/test/java/com/rabbitmq/utility/IntAllocatorTests.java +++ b/src/test/java/com/rabbitmq/utility/IntAllocatorTests.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. +// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 From 14d9c1f1bb730dfe9d644cc81dba22fe733c0c4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 1 Apr 2020 11:46:06 +0200 Subject: [PATCH 1228/2114] Check qos, heartbeat, max channel are unsigned shorts To avoid truncation and subtle bugs. Fixes #640 (cherry picked from commit 733788e26ba73ea90a1be72b99227c6a10003054) Conflicts: src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java --- .../java/com/rabbitmq/client/Channel.java | 33 ++++--- .../rabbitmq/client/ConnectionFactory.java | 16 ++- .../rabbitmq/client/impl/AMQConnection.java | 18 +++- .../com/rabbitmq/client/impl/ChannelN.java | 32 +++--- .../rabbitmq/client/test/ChannelNTest.java | 31 ++++++ .../com/rabbitmq/client/test/ClientTests.java | 1 - .../client/test/ConnectionFactoryTest.java | 97 ++++++++++++------- .../rabbitmq/client/test/ssl/SSLTests.java | 4 +- 8 files changed, 163 insertions(+), 69 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/Channel.java b/src/main/java/com/rabbitmq/client/Channel.java index cd0b9b2962..b84df3d95b 100644 --- a/src/main/java/com/rabbitmq/client/Channel.java +++ b/src/main/java/com/rabbitmq/client/Channel.java @@ -197,42 +197,49 @@ public interface Channel extends ShutdownNotifier, AutoCloseable { /** * Request specific "quality of service" settings. - * + *

* These settings impose limits on the amount of data the server * will deliver to consumers before requiring acknowledgements. * Thus they provide a means of consumer-initiated flow control. - * @see com.rabbitmq.client.AMQP.Basic.Qos - * @param prefetchSize maximum amount of content (measured in - * octets) that the server will deliver, 0 if unlimited + *

+ * Note the prefetch count must be between 0 and 65535 (unsigned short in AMQP 0-9-1). + * + * @param prefetchSize maximum amount of content (measured in + * octets) that the server will deliver, 0 if unlimited * @param prefetchCount maximum number of messages that the server - * will deliver, 0 if unlimited - * @param global true if the settings should be applied to the - * entire channel rather than each consumer + * will deliver, 0 if unlimited + * @param global true if the settings should be applied to the + * entire channel rather than each consumer * @throws java.io.IOException if an error is encountered + * @see com.rabbitmq.client.AMQP.Basic.Qos */ void basicQos(int prefetchSize, int prefetchCount, boolean global) throws IOException; /** * Request a specific prefetchCount "quality of service" settings * for this channel. + *

+ * Note the prefetch count must be between 0 and 65535 (unsigned short in AMQP 0-9-1). * - * @see #basicQos(int, int, boolean) * @param prefetchCount maximum number of messages that the server - * will deliver, 0 if unlimited - * @param global true if the settings should be applied to the - * entire channel rather than each consumer + * will deliver, 0 if unlimited + * @param global true if the settings should be applied to the + * entire channel rather than each consumer * @throws java.io.IOException if an error is encountered + * @see #basicQos(int, int, boolean) */ void basicQos(int prefetchCount, boolean global) throws IOException; /** * Request a specific prefetchCount "quality of service" settings * for this channel. + *

+ * Note the prefetch count must be between 0 and 65535 (unsigned short in AMQP 0-9-1). * - * @see #basicQos(int, int, boolean) * @param prefetchCount maximum number of messages that the server - * will deliver, 0 if unlimited + * will deliver, 0 if unlimited * @throws java.io.IOException if an error is encountered + * @see #basicQos(int, int, boolean) */ void basicQos(int prefetchCount) throws IOException; diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index b6b1f5b848..7fdcdb1324 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -47,6 +47,8 @@ */ public class ConnectionFactory implements Cloneable { + private static final int MAX_UNSIGNED_SHORT = 65535; + /** Default user name */ public static final String DEFAULT_USER = "guest"; /** Default password */ @@ -384,10 +386,16 @@ public int getRequestedChannelMax() { } /** - * Set the requested maximum channel number + * Set the requested maximum channel number. + *

+ * Note the value must be between 0 and 65535 (unsigned short in AMQP 0-9-1). + * * @param requestedChannelMax initially requested maximum channel number; zero for unlimited */ public void setRequestedChannelMax(int requestedChannelMax) { + if (requestedChannelMax < 0 || requestedChannelMax > MAX_UNSIGNED_SHORT) { + throw new IllegalArgumentException("Requested channel max must be between 0 and " + MAX_UNSIGNED_SHORT); + } this.requestedChannelMax = requestedChannelMax; } @@ -477,10 +485,16 @@ public int getShutdownTimeout() { * Set the requested heartbeat timeout. Heartbeat frames will be sent at about 1/2 the timeout interval. * If server heartbeat timeout is configured to a non-zero value, this method can only be used * to lower the value; otherwise any value provided by the client will be used. + *

+ * Note the value must be between 0 and 65535 (unsigned short in AMQP 0-9-1). + * * @param requestedHeartbeat the initially requested heartbeat timeout, in seconds; zero for none * @see RabbitMQ Heartbeats Guide */ public void setRequestedHeartbeat(int requestedHeartbeat) { + if (requestedHeartbeat < 0 || requestedHeartbeat > MAX_UNSIGNED_SHORT) { + throw new IllegalArgumentException("Requested heartbeat must be between 0 and " + MAX_UNSIGNED_SHORT); + } this.requestedHeartbeat = requestedHeartbeat; } diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index c989b3a972..b140788a84 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -15,13 +15,12 @@ package com.rabbitmq.client.impl; -import com.rabbitmq.client.*; import com.rabbitmq.client.Method; +import com.rabbitmq.client.*; import com.rabbitmq.client.impl.AMQChannel.BlockingRpcContinuation; import com.rabbitmq.client.impl.recovery.RecoveryCanBeginListener; import com.rabbitmq.utility.BlockingCell; import com.rabbitmq.utility.Utility; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -47,6 +46,8 @@ final class Copyright { */ public class AMQConnection extends ShutdownNotifierComponent implements Connection, NetworkConnection { + private static final int MAX_UNSIGNED_SHORT = 65535; + private static final Logger LOGGER = LoggerFactory.getLogger(AMQConnection.class); // we want socket write and channel shutdown timeouts to kick in after // the heartbeat one, so we use a value of 105% of the effective heartbeat timeout @@ -402,6 +403,11 @@ public void start() int channelMax = negotiateChannelMax(this.requestedChannelMax, connTune.getChannelMax()); + + if (!checkUnsignedShort(channelMax)) { + throw new IllegalArgumentException("Negotiated channel max must be between 0 and " + MAX_UNSIGNED_SHORT + ": " + channelMax); + } + _channelManager = instantiateChannelManager(channelMax, threadFactory); int frameMax = @@ -413,6 +419,10 @@ public void start() negotiatedMaxValue(this.requestedHeartbeat, connTune.getHeartbeat()); + if (!checkUnsignedShort(heartbeat)) { + throw new IllegalArgumentException("Negotiated heartbeat must be between 0 and " + MAX_UNSIGNED_SHORT + ": " + heartbeat); + } + setHeartbeat(heartbeat); _channel0.transmit(new AMQP.Connection.TuneOk.Builder() @@ -629,6 +639,10 @@ private static int negotiatedMaxValue(int clientValue, int serverValue) { Math.min(clientValue, serverValue); } + private static boolean checkUnsignedShort(int value) { + return value >= 0 && value <= MAX_UNSIGNED_SHORT; + } + private class MainLoop implements Runnable { /** diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java index 61f2d0683e..94da03e7bc 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelN.java @@ -15,30 +15,24 @@ package com.rabbitmq.client.impl; -import java.io.IOException; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.SortedSet; -import java.util.TreeSet; -import java.util.concurrent.*; - -import com.rabbitmq.client.ConfirmCallback; import com.rabbitmq.client.*; -import com.rabbitmq.client.AMQP.BasicProperties; +import com.rabbitmq.client.Connection; import com.rabbitmq.client.Method; -import com.rabbitmq.client.impl.AMQImpl.Basic; +import com.rabbitmq.client.AMQP.BasicProperties; import com.rabbitmq.client.impl.AMQImpl.Channel; -import com.rabbitmq.client.impl.AMQImpl.Confirm; -import com.rabbitmq.client.impl.AMQImpl.Exchange; import com.rabbitmq.client.impl.AMQImpl.Queue; -import com.rabbitmq.client.impl.AMQImpl.Tx; +import com.rabbitmq.client.impl.AMQImpl.*; import com.rabbitmq.utility.Utility; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.IOException; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeoutException; + /** * Main interface to AMQP protocol functionality. Public API - * Implementation of all AMQChannels except channel zero. @@ -50,6 +44,7 @@ * */ public class ChannelN extends AMQChannel implements com.rabbitmq.client.Channel { + private static final int MAX_UNSIGNED_SHORT = 65535; private static final String UNSPECIFIED_OUT_OF_BAND = ""; private static final Logger LOGGER = LoggerFactory.getLogger(ChannelN.class); @@ -647,7 +642,10 @@ public AMQCommand transformReply(AMQCommand command) { public void basicQos(int prefetchSize, int prefetchCount, boolean global) throws IOException { - exnWrappingRpc(new Basic.Qos(prefetchSize, prefetchCount, global)); + if (prefetchCount < 0 || prefetchCount > MAX_UNSIGNED_SHORT) { + throw new IllegalArgumentException("Prefetch count must be between 0 and " + MAX_UNSIGNED_SHORT); + } + exnWrappingRpc(new Basic.Qos(prefetchSize, prefetchCount, global)); } /** Public API - {@inheritDoc} */ diff --git a/src/test/java/com/rabbitmq/client/test/ChannelNTest.java b/src/test/java/com/rabbitmq/client/test/ChannelNTest.java index 214173a577..194f086ef8 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelNTest.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelNTest.java @@ -25,6 +25,9 @@ import java.io.IOException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; public class ChannelNTest { @@ -58,4 +61,32 @@ public void callingBasicCancelForUnknownConsumerThrowsException() throws Excepti channel.basicCancel("does-not-exist"); } + @Test + public void qosShouldBeUnsignedShort() { + AMQConnection connection = Mockito.mock(AMQConnection.class); + ChannelN channel = new ChannelN(connection, 1, consumerWorkService); + class TestConfig { + int value; + Consumer call; + + public TestConfig(int value, Consumer call) { + this.value = value; + this.call = call; + } + } + Consumer qos = value -> channel.basicQos(value); + Consumer qosGlobal = value -> channel.basicQos(value, true); + Consumer qosPrefetchSize = value -> channel.basicQos(10, value, true); + Stream.of( + new TestConfig(-1, qos), new TestConfig(65536, qos) + ).flatMap(config -> Stream.of(config, new TestConfig(config.value, qosGlobal), new TestConfig(config.value, qosPrefetchSize))) + .forEach(config -> assertThatThrownBy(() -> config.call.apply(config.value)).isInstanceOf(IllegalArgumentException.class)); + } + + interface Consumer { + + void apply(int value) throws Exception; + + } + } diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index 1d1be76fda..601234b2db 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -57,7 +57,6 @@ ConnectionFactoryTest.class, RecoveryAwareAMQConnectionFactoryTest.class, RpcTest.class, - SslContextFactoryTest.class, LambdaCallbackTest.class, ChannelAsyncCompletableFutureTest.class, RecoveryDelayHandlerTest.class, diff --git a/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java b/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java index feacb2327c..0d1b695783 100644 --- a/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java +++ b/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java @@ -15,18 +15,8 @@ package com.rabbitmq.client.test; -import com.rabbitmq.client.Address; -import com.rabbitmq.client.AddressResolver; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.ConnectionFactory; -import com.rabbitmq.client.DnsRecordIpAddressResolver; -import com.rabbitmq.client.ListAddressResolver; -import com.rabbitmq.client.MetricsCollector; -import com.rabbitmq.client.impl.AMQConnection; -import com.rabbitmq.client.impl.ConnectionParams; -import com.rabbitmq.client.impl.CredentialsProvider; -import com.rabbitmq.client.impl.FrameHandler; -import com.rabbitmq.client.impl.FrameHandlerFactory; +import com.rabbitmq.client.*; +import com.rabbitmq.client.impl.*; import org.junit.Test; import java.io.IOException; @@ -36,17 +26,18 @@ import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; +import java.util.stream.Stream; -import static org.hamcrest.Matchers.allOf; -import static org.hamcrest.Matchers.instanceOf; -import static org.hamcrest.Matchers.notNullValue; -import static org.junit.Assert.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.Mockito.*; public class ConnectionFactoryTest { // see https://github.com/rabbitmq/rabbitmq-java-client/issues/262 - @Test public void tryNextAddressIfTimeoutExceptionNoAutoRecovery() throws IOException, TimeoutException { + @Test + public void tryNextAddressIfTimeoutExceptionNoAutoRecovery() throws IOException, TimeoutException { final AMQConnection connectionThatThrowsTimeout = mock(AMQConnection.class); final AMQConnection connectionThatSucceeds = mock(AMQConnection.class); final Queue connections = new ArrayBlockingQueue(10); @@ -68,22 +59,23 @@ protected synchronized FrameHandlerFactory createFrameHandlerFactory() { doThrow(TimeoutException.class).when(connectionThatThrowsTimeout).start(); doNothing().when(connectionThatSucceeds).start(); Connection returnedConnection = connectionFactory.newConnection( - new Address[] { new Address("host1"), new Address("host2") } + new Address[]{new Address("host1"), new Address("host2")} ); - assertSame(connectionThatSucceeds, returnedConnection); + assertThat(returnedConnection).isSameAs(connectionThatSucceeds); } - + // see https://github.com/rabbitmq/rabbitmq-java-client/pull/350 - @Test public void customizeCredentialsProvider() throws Exception { + @Test + public void customizeCredentialsProvider() throws Exception { final CredentialsProvider provider = mock(CredentialsProvider.class); final AMQConnection connection = mock(AMQConnection.class); final AtomicBoolean createCalled = new AtomicBoolean(false); - + ConnectionFactory connectionFactory = new ConnectionFactory() { @Override protected AMQConnection createConnection(ConnectionParams params, FrameHandler frameHandler, - MetricsCollector metricsCollector) { - assertSame(provider, params.getCredentialsProvider()); + MetricsCollector metricsCollector) { + assertThat(provider).isSameAs(params.getCredentialsProvider()); createCalled.set(true); return connection; } @@ -95,22 +87,23 @@ protected synchronized FrameHandlerFactory createFrameHandlerFactory() { }; connectionFactory.setCredentialsProvider(provider); connectionFactory.setAutomaticRecoveryEnabled(false); - + doNothing().when(connection).start(); - + Connection returnedConnection = connectionFactory.newConnection(); - assertSame(returnedConnection, connection); - assertTrue(createCalled.get()); + assertThat(returnedConnection).isSameAs(connection); + assertThat(createCalled).isTrue(); } - @Test public void shouldUseDnsResolutionWhenOneAddressAndNoTls() throws Exception { + @Test + public void shouldNotUseDnsResolutionWhenOneAddressAndNoTls() throws Exception { AMQConnection connection = mock(AMQConnection.class); AtomicReference addressResolver = new AtomicReference<>(); ConnectionFactory connectionFactory = new ConnectionFactory() { @Override protected AMQConnection createConnection(ConnectionParams params, FrameHandler frameHandler, - MetricsCollector metricsCollector) { + MetricsCollector metricsCollector) { return connection; } @@ -131,17 +124,18 @@ protected synchronized FrameHandlerFactory createFrameHandlerFactory() { doNothing().when(connection).start(); connectionFactory.newConnection(); - assertThat(addressResolver.get(), allOf(notNullValue(), instanceOf(DnsRecordIpAddressResolver.class))); + assertThat(addressResolver.get()).isNotNull().isInstanceOf(ListAddressResolver.class); } - @Test public void shouldNotUseDnsResolutionWhenOneAddressAndTls() throws Exception { + @Test + public void shouldNotUseDnsResolutionWhenOneAddressAndTls() throws Exception { AMQConnection connection = mock(AMQConnection.class); AtomicReference addressResolver = new AtomicReference<>(); ConnectionFactory connectionFactory = new ConnectionFactory() { @Override protected AMQConnection createConnection(ConnectionParams params, FrameHandler frameHandler, - MetricsCollector metricsCollector) { + MetricsCollector metricsCollector) { return connection; } @@ -163,7 +157,42 @@ protected synchronized FrameHandlerFactory createFrameHandlerFactory() { connectionFactory.useSslProtocol(); connectionFactory.newConnection(); - assertThat(addressResolver.get(), allOf(notNullValue(), instanceOf(ListAddressResolver.class))); + assertThat(addressResolver.get()).isNotNull().isInstanceOf(ListAddressResolver.class); + } + + @Test + public void heartbeatAndChannelMaxMustBeUnsignedShorts() { + class TestConfig { + int value; + Consumer call; + boolean expectException; + + public TestConfig(int value, Consumer call, boolean expectException) { + this.value = value; + this.call = call; + this.expectException = expectException; + } + } + + ConnectionFactory cf = new ConnectionFactory(); + Consumer setHeartbeat = cf::setRequestedHeartbeat; + Consumer setChannelMax = cf::setRequestedChannelMax; + + Stream.of( + new TestConfig(0, setHeartbeat, false), + new TestConfig(10, setHeartbeat, false), + new TestConfig(65535, setHeartbeat, false), + new TestConfig(-1, setHeartbeat, true), + new TestConfig(65536, setHeartbeat, true)) + .flatMap(config -> Stream.of(config, new TestConfig(config.value, setChannelMax, config.expectException))) + .forEach(config -> { + if (config.expectException) { + assertThatThrownBy(() -> config.call.accept(config.value)).isInstanceOf(IllegalArgumentException.class); + } else { + config.call.accept(config.value); + } + }); + } } diff --git a/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java index 0dbb808584..1dddf62e38 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java @@ -17,6 +17,7 @@ package com.rabbitmq.client.test.ssl; import com.rabbitmq.client.test.AbstractRMQTestSuite; +import com.rabbitmq.client.test.SslContextFactoryTest; import org.junit.runner.RunWith; import org.junit.runner.Runner; import org.junit.runners.Suite; @@ -34,7 +35,8 @@ ConnectionFactoryDefaultTlsVersion.class, NioTlsUnverifiedConnection.class, HostnameVerification.class, - TlsConnectionLogging.class + TlsConnectionLogging.class, + SslContextFactoryTest.class }) public class SSLTests { From af4295c33986fb1e6854c1fdb915d109bd64a341 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 1 Apr 2020 15:20:00 +0200 Subject: [PATCH 1229/2114] Bump test dependencies Don't use JUnit's assertThat anymore, as it's deprecated in 4.13. Use assertj instead. Get rid of Awaitility (created a waitUntil test utility instead) and Hamcrest (not used anymore). (cherry picked from commit d979c388603698fc6a7b2d26507ec6554ab684a2) Conflicts: src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java --- pom.xml | 21 +-- .../rabbitmq/client/test/AMQChannelTest.java | 37 +++-- .../ChannelRpcTimeoutIntegrationTest.java | 10 +- .../client/test/ClientVersionTest.java | 8 +- .../test/DnsSrvRecordAddressResolverTest.java | 15 +- .../client/test/FrameBuilderTest.java | 37 +++-- .../com/rabbitmq/client/test/FrameTest.java | 5 +- .../client/test/MetricsCollectorTest.java | 83 +++++----- .../test/MicrometerMetricsCollectorTest.java | 17 +-- ...NoAutoRecoveryWhenTcpWindowIsFullTest.java | 31 ++-- .../test/PropertyFileInitialisationTest.java | 86 +++++------ .../com/rabbitmq/client/test/RpcTest.java | 4 +- .../test/StrictExceptionHandlerTest.java | 7 +- .../com/rabbitmq/client/test/TestUtils.java | 25 +++ .../rabbitmq/client/test/TestUtilsTest.java | 17 +-- .../test/functional/ConnectionRecovery.java | 142 +++++++++--------- .../client/test/functional/Metrics.java | 132 ++++++++-------- .../functional/TopologyRecoveryFiltering.java | 14 +- src/test/java/com/rabbitmq/tools/Host.java | 3 +- 19 files changed, 326 insertions(+), 368 deletions(-) diff --git a/pom.xml b/pom.xml index 0c79405b3b..76f2173524 100644 --- a/pom.xml +++ b/pom.xml @@ -59,11 +59,10 @@ 1.3.2 2.10.1 1.2.3 - 4.12 - 4.0.1 - 3.2.0 - 3.14.0 - 9.4.24.v20191120 + 4.13 + 3.3.3 + 3.15.0 + 9.4.27.v20200227 1.64 3.1.1 @@ -722,12 +721,6 @@ ${logback.version} test - - org.awaitility - awaitility - ${awaitility.version} - test - org.mockito mockito-core @@ -740,12 +733,6 @@ ${assertj.version} test - - org.hamcrest - hamcrest-library - 1.3 - test - org.eclipse.jetty jetty-servlet diff --git a/src/test/java/com/rabbitmq/client/test/AMQChannelTest.java b/src/test/java/com/rabbitmq/client/test/AMQChannelTest.java index cb5f65d4fb..73a8731eea 100644 --- a/src/test/java/com/rabbitmq/client/test/AMQChannelTest.java +++ b/src/test/java/com/rabbitmq/client/test/AMQChannelTest.java @@ -33,8 +33,8 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; -import static org.hamcrest.Matchers.*; -import static org.junit.Assert.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; import static org.mockito.Mockito.*; public class AMQChannelTest { @@ -69,10 +69,10 @@ public class AMQChannelTest { fail("Should time out and throw an exception"); } catch(ChannelContinuationTimeoutException e) { // OK - assertThat((DummyAmqChannel) e.getChannel(), is(channel)); - assertThat(e.getChannelNumber(), is(channel.getChannelNumber())); - assertThat(e.getMethod(), is(method)); - assertNull("outstanding RPC should have been cleaned", channel.nextOutstandingRpc()); + assertThat((DummyAmqChannel) e.getChannel()).isEqualTo(channel); + assertThat(e.getChannelNumber()).isEqualTo(channel.getChannelNumber()); + assertThat(e.getMethod()).isEqualTo(method); + assertThat(channel.nextOutstandingRpc()).as("outstanding RPC should have been cleaned").isNull(); } } @@ -105,7 +105,7 @@ public Void call() throws Exception { }, (long) (rpcTimeout / 2.0), TimeUnit.MILLISECONDS); AMQCommand rpcResponse = channel.rpc(method); - assertThat(rpcResponse.getMethod(), is(response)); + assertThat(rpcResponse.getMethod()).isEqualTo(response); } @Test @@ -130,10 +130,10 @@ public void testRpcTimeoutReplyComesDuringNexRpc() throws Exception { fail("Should time out and throw an exception"); } catch(final ChannelContinuationTimeoutException e) { // OK - assertThat((DummyAmqChannel) e.getChannel(), is(channel)); - assertThat(e.getChannelNumber(), is(channel.getChannelNumber())); - assertThat(e.getMethod(), is(method)); - assertNull("outstanding RPC should have been cleaned", channel.nextOutstandingRpc()); + assertThat((DummyAmqChannel) e.getChannel()).isEqualTo(channel); + assertThat(e.getChannelNumber()).isEqualTo(channel.getChannelNumber()); + assertThat(e.getMethod()).isEqualTo(method); + assertThat(channel.nextOutstandingRpc()).as("outstanding RPC should have been cleaned").isNull(); } // now do a basic.consume request and have the queue.declareok returned instead @@ -151,18 +151,15 @@ public void testRpcTimeoutReplyComesDuringNexRpc() throws Exception { final Method response2 = new AMQImpl.Basic.ConsumeOk.Builder() .consumerTag("456").build(); - scheduler.schedule(new Callable() { - @Override - public Void call() throws Exception { - channel.handleCompleteInboundCommand(new AMQCommand(response1)); - Thread.sleep(10); - channel.handleCompleteInboundCommand(new AMQCommand(response2)); - return null; - } + scheduler.schedule((Callable) () -> { + channel.handleCompleteInboundCommand(new AMQCommand(response1)); + Thread.sleep(10); + channel.handleCompleteInboundCommand(new AMQCommand(response2)); + return null; }, (long) (rpcTimeout / 2.0), TimeUnit.MILLISECONDS); AMQCommand rpcResponse = channel.rpc(method); - assertThat(rpcResponse.getMethod(), is(response2)); + assertThat(rpcResponse.getMethod()).isEqualTo(response2); } static class DummyAmqChannel extends AMQChannel { diff --git a/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java b/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java index 87494900a6..948074580f 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java @@ -27,8 +27,8 @@ import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeoutException; -import static org.hamcrest.Matchers.*; -import static org.junit.Assert.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; public class ChannelRpcTimeoutIntegrationTest { @@ -73,9 +73,9 @@ public void tearDown() { fail("Should time out and throw an exception"); } catch(ChannelContinuationTimeoutException e) { // OK - assertThat((Channel) e.getChannel(), is(channel)); - assertThat(e.getChannelNumber(), is(channel.getChannelNumber())); - assertThat(e.getMethod(), instanceOf(AMQP.Queue.Declare.class)); + assertThat((Channel) e.getChannel()).isEqualTo(channel); + assertThat(e.getChannelNumber()).isEqualTo(channel.getChannelNumber()); + assertThat(e.getMethod()).isInstanceOf(AMQP.Queue.Declare.class); } } finally { connection.close(); diff --git a/src/test/java/com/rabbitmq/client/test/ClientVersionTest.java b/src/test/java/com/rabbitmq/client/test/ClientVersionTest.java index 3c36dd7015..9d7560adaf 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientVersionTest.java +++ b/src/test/java/com/rabbitmq/client/test/ClientVersionTest.java @@ -18,15 +18,13 @@ import com.rabbitmq.client.impl.ClientVersion; import org.junit.Test; -import static org.hamcrest.Matchers.not; -import static org.hamcrest.Matchers.notNullValue; -import static org.junit.Assert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; public class ClientVersionTest { @Test public void clientVersion() { - assertThat(ClientVersion.VERSION, notNullValue()); - assertThat(ClientVersion.VERSION, not("0.0.0")); + assertThat(ClientVersion.VERSION).isNotNull(); + assertThat(ClientVersion.VERSION).isNotEqualTo("0.0.0"); } } diff --git a/src/test/java/com/rabbitmq/client/test/DnsSrvRecordAddressResolverTest.java b/src/test/java/com/rabbitmq/client/test/DnsSrvRecordAddressResolverTest.java index 886aa1f533..e315d1147c 100644 --- a/src/test/java/com/rabbitmq/client/test/DnsSrvRecordAddressResolverTest.java +++ b/src/test/java/com/rabbitmq/client/test/DnsSrvRecordAddressResolverTest.java @@ -23,8 +23,7 @@ import java.util.Arrays; import java.util.List; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; /** * @@ -46,12 +45,12 @@ protected List lookupSrvRecords(String service, String dnsUrls) throw }; List

addresses = resolver.getAddresses(); - assertThat(addresses.size(), is(5)); - assertThat(addresses.get(0).getHost(), is("alt1.xmpp-server.l.google.com")); - assertThat(addresses.get(1).getHost(), is("alt2.xmpp-server.l.google.com")); - assertThat(addresses.get(2).getHost(), is("alt3.xmpp-server.l.google.com")); - assertThat(addresses.get(3).getHost(), is("alt4.xmpp-server.l.google.com")); - assertThat(addresses.get(4).getHost(), is("alt5.xmpp-server.l.google.com")); + assertThat(addresses.size()).isEqualTo(5); + assertThat(addresses.get(0).getHost()).isEqualTo("alt1.xmpp-server.l.google.com"); + assertThat(addresses.get(1).getHost()).isEqualTo("alt2.xmpp-server.l.google.com"); + assertThat(addresses.get(2).getHost()).isEqualTo("alt3.xmpp-server.l.google.com"); + assertThat(addresses.get(3).getHost()).isEqualTo("alt4.xmpp-server.l.google.com"); + assertThat(addresses.get(4).getHost()).isEqualTo("alt5.xmpp-server.l.google.com"); } } diff --git a/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java b/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java index 64013cadd8..9c4c4197ec 100644 --- a/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java +++ b/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java @@ -28,11 +28,8 @@ import java.nio.ByteBuffer; import java.nio.channels.ReadableByteChannel; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; -import static org.hamcrest.Matchers.nullValue; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; /** * @@ -52,10 +49,10 @@ public void buildFrameInOneGo() throws IOException { buffer = ByteBuffer.wrap(new byte[] { 1, 0, 0, 0, 0, 0, 3, 1, 2, 3, end() }); builder = new FrameBuilder(channel, buffer); Frame frame = builder.readFrame(); - assertThat(frame, notNullValue()); - assertThat(frame.type, is(1)); - assertThat(frame.channel, is(0)); - assertThat(frame.getPayload().length, is(3)); + assertThat(frame).isNotNull(); + assertThat(frame.type).isEqualTo(1); + assertThat(frame.channel).isEqualTo(0); + assertThat(frame.getPayload()).hasSize(3); } @Test @@ -73,13 +70,13 @@ public void buildFramesInOneGo() throws IOException { int frameCount = 0; Frame frame; while ((frame = builder.readFrame()) != null) { - assertThat(frame, notNullValue()); - assertThat(frame.type, is(1)); - assertThat(frame.channel, is(0)); - assertThat(frame.getPayload().length, is(3)); + assertThat(frame).isNotNull(); + assertThat(frame.type).isEqualTo(1); + assertThat(frame.channel).isEqualTo(0); + assertThat(frame.getPayload()).hasSize(3); frameCount++; } - assertThat(frameCount, is(nbFrames)); + assertThat(frameCount).isEqualTo(nbFrames); } @Test @@ -87,17 +84,17 @@ public void buildFrameInSeveralCalls() throws IOException { buffer = ByteBuffer.wrap(new byte[] { 1, 0, 0, 0, 0, 0, 3, 1, 2 }); builder = new FrameBuilder(channel, buffer); Frame frame = builder.readFrame(); - assertThat(frame, nullValue()); + assertThat(frame).isNull(); buffer.clear(); buffer.put(b(3)).put(end()); buffer.flip(); frame = builder.readFrame(); - assertThat(frame, notNullValue()); - assertThat(frame.type, is(1)); - assertThat(frame.channel, is(0)); - assertThat(frame.getPayload().length, is(3)); + assertThat(frame).isNotNull(); + assertThat(frame.type).isEqualTo(1); + assertThat(frame.channel).isEqualTo(0); + assertThat(frame.getPayload()).hasSize(3); } @Test @@ -127,7 +124,7 @@ public void protocolMismatchHeader() throws IOException { builder.readFrame(); fail("protocol header not correct, exception should have been thrown"); } catch (MalformedFrameException e) { - assertThat(e.getMessage(), is(messages[i])); + assertThat(e.getMessage()).isEqualTo(messages[i]); } } } diff --git a/src/test/java/com/rabbitmq/client/test/FrameTest.java b/src/test/java/com/rabbitmq/client/test/FrameTest.java index a154a6cfe3..26441a848b 100644 --- a/src/test/java/com/rabbitmq/client/test/FrameTest.java +++ b/src/test/java/com/rabbitmq/client/test/FrameTest.java @@ -17,8 +17,7 @@ import java.util.List; import java.util.Random; -import static org.hamcrest.Matchers.equalTo; -import static org.junit.Assert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; /** * @@ -72,7 +71,7 @@ private void checkWrittenChunks(int totalFrameSize, AccumulatorWritableByteChann for (byte[] chunk : channel.chunks) { totalWritten += chunk.length; } - assertThat(totalWritten, equalTo(totalFrameSize)); + assertThat(totalWritten).isEqualTo(totalFrameSize); } private static class AccumulatorWritableByteChannel implements WritableByteChannel { diff --git a/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java b/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java index 27b4f21cd8..5d424a69a3 100644 --- a/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java +++ b/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java @@ -28,8 +28,7 @@ import java.io.IOException; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -70,16 +69,16 @@ public void basicGetAndAck() { metrics.consumedMessage(channel, 6, false); metrics.basicAck(channel, 6, false); - assertThat(acknowledgedMessages(metrics), is(1L)); + assertThat(acknowledgedMessages(metrics)).isEqualTo(1L); metrics.basicAck(channel, 3, true); - assertThat(acknowledgedMessages(metrics), is(1L+2L)); + assertThat(acknowledgedMessages(metrics)).isEqualTo(1L+2L); metrics.basicAck(channel, 6, true); - assertThat(acknowledgedMessages(metrics), is(1L+2L+1L)); + assertThat(acknowledgedMessages(metrics)).isEqualTo(1L+2L+1L); metrics.basicAck(channel, 10, true); - assertThat(acknowledgedMessages(metrics), is(1L+2L+1L)); + assertThat(acknowledgedMessages(metrics)).isEqualTo(1L+2L+1L); } @Test public void basicConsumeAndAck() { @@ -99,8 +98,8 @@ public void basicGetAndAck() { metrics.basicConsume(channel, consumerTagWithManualAck, false); metrics.consumedMessage(channel, 1, consumerTagWithAutoAck); - assertThat(consumedMessages(metrics), is(1L)); - assertThat(acknowledgedMessages(metrics), is(0L)); + assertThat(consumedMessages(metrics)).isEqualTo(1L); + assertThat(acknowledgedMessages(metrics)).isEqualTo(0L); metrics.consumedMessage(channel, 2, consumerTagWithManualAck); metrics.consumedMessage(channel, 3, consumerTagWithManualAck); @@ -109,44 +108,44 @@ public void basicGetAndAck() { metrics.consumedMessage(channel, 6, consumerTagWithManualAck); metrics.basicAck(channel, 6, false); - assertThat(acknowledgedMessages(metrics), is(1L)); + assertThat(acknowledgedMessages(metrics)).isEqualTo(1L); metrics.basicAck(channel, 3, true); - assertThat(acknowledgedMessages(metrics), is(1L+2L)); + assertThat(acknowledgedMessages(metrics)).isEqualTo(1L+2L); metrics.basicAck(channel, 6, true); - assertThat(acknowledgedMessages(metrics), is(1L+2L+1L)); + assertThat(acknowledgedMessages(metrics)).isEqualTo(1L+2L+1L); metrics.basicAck(channel, 10, true); - assertThat(acknowledgedMessages(metrics), is(1L+2L+1L)); + assertThat(acknowledgedMessages(metrics)).isEqualTo(1L+2L+1L); } @Test public void publishingAndPublishingFailures() { AbstractMetricsCollector metrics = factory.create(); Channel channel = mock(Channel.class); - assertThat(failedToPublishMessages(metrics), is(0L)); - assertThat(publishedMessages(metrics), is(0L)); + assertThat(failedToPublishMessages(metrics)).isEqualTo(0L); + assertThat(publishedMessages(metrics)).isEqualTo(0L); metrics.basicPublishFailure(channel, new IOException()); - assertThat(failedToPublishMessages(metrics), is(1L)); - assertThat(publishedMessages(metrics), is(0L)); + assertThat(failedToPublishMessages(metrics)).isEqualTo(1L); + assertThat(publishedMessages(metrics)).isEqualTo(0L); metrics.basicPublish(channel); - assertThat(failedToPublishMessages(metrics), is(1L)); - assertThat(publishedMessages(metrics), is(1L)); + assertThat(failedToPublishMessages(metrics)).isEqualTo(1L); + assertThat(publishedMessages(metrics)).isEqualTo(1L); metrics.basicPublishFailure(channel, new IOException()); - assertThat(failedToPublishMessages(metrics), is(2L)); - assertThat(publishedMessages(metrics), is(1L)); + assertThat(failedToPublishMessages(metrics)).isEqualTo(2L); + assertThat(publishedMessages(metrics)).isEqualTo(1L); metrics.basicPublish(channel); - assertThat(failedToPublishMessages(metrics), is(2L)); - assertThat(publishedMessages(metrics), is(2L)); + assertThat(failedToPublishMessages(metrics)).isEqualTo(2L); + assertThat(publishedMessages(metrics)).isEqualTo(2L); metrics.cleanStaleState(); - assertThat(failedToPublishMessages(metrics), is(2L)); - assertThat(publishedMessages(metrics), is(2L)); + assertThat(failedToPublishMessages(metrics)).isEqualTo(2L); + assertThat(publishedMessages(metrics)).isEqualTo(2L); } @Test public void publishingAcknowledgements() { @@ -154,19 +153,19 @@ public void basicGetAndAck() { AbstractMetricsCollector metrics = factory.create(); Channel channel = mock(Channel.class); // begins with no messages acknowledged - assertThat(publishAck(metrics), is(0L)); + assertThat(publishAck(metrics)).isEqualTo(0L); // first acknowledgement gets tracked metrics.basicPublishAck(channel, anyDeliveryTag, false); - assertThat(publishAck(metrics), is(1L)); + assertThat(publishAck(metrics)).isEqualTo(1L); // second acknowledgement gets tracked metrics.basicPublishAck(channel, anyDeliveryTag, false); - assertThat(publishAck(metrics), is(2L)); + assertThat(publishAck(metrics)).isEqualTo(2L); // multiple deliveries aren't tracked metrics.basicPublishAck(channel, anyDeliveryTag, true); - assertThat(publishAck(metrics), is(2L)); + assertThat(publishAck(metrics)).isEqualTo(2); // cleaning stale state doesn't affect the metric metrics.cleanStaleState(); - assertThat(publishAck(metrics), is(2L)); + assertThat(publishAck(metrics)).isEqualTo(2); } @Test public void publishingNotAcknowledgements() { @@ -174,35 +173,35 @@ public void basicGetAndAck() { AbstractMetricsCollector metrics = factory.create(); Channel channel = mock(Channel.class); // begins with no messages not-acknowledged - assertThat(publishNack(metrics), is(0L)); + assertThat(publishNack(metrics)).isEqualTo(0L); // first not-acknowledgement gets tracked metrics.basicPublishNack(channel, anyDeliveryTag, false); - assertThat(publishNack(metrics), is(1L)); + assertThat(publishNack(metrics)).isEqualTo(1L); // second not-acknowledgement gets tracked metrics.basicPublishNack(channel, anyDeliveryTag, false); - assertThat(publishNack(metrics), is(2L)); + assertThat(publishNack(metrics)).isEqualTo(2L); // multiple deliveries aren't tracked metrics.basicPublishNack(channel, anyDeliveryTag, true); - assertThat(publishNack(metrics), is(2L)); + assertThat(publishNack(metrics)).isEqualTo(2L); // cleaning stale state doesn't affect the metric metrics.cleanStaleState(); - assertThat(publishNack(metrics), is(2L)); + assertThat(publishNack(metrics)).isEqualTo(2L); } @Test public void publishingUnrouted() { AbstractMetricsCollector metrics = factory.create(); Channel channel = mock(Channel.class); // begins with no messages not-acknowledged - assertThat(publishUnrouted(metrics), is(0L)); + assertThat(publishUnrouted(metrics)).isEqualTo(0L); // first unrouted gets tracked metrics.basicPublishUnrouted(channel); - assertThat(publishUnrouted(metrics), is(1L)); + assertThat(publishUnrouted(metrics)).isEqualTo(1L); // second unrouted gets tracked metrics.basicPublishUnrouted(channel); - assertThat(publishUnrouted(metrics), is(2L)); + assertThat(publishUnrouted(metrics)).isEqualTo(2L); // cleaning stale state doesn't affect the metric metrics.cleanStaleState(); - assertThat(publishUnrouted(metrics), is(2L)); + assertThat(publishUnrouted(metrics)).isEqualTo(2L); } @Test public void cleanStaleState() { @@ -236,13 +235,13 @@ public void basicGetAndAck() { metrics.newChannel(closedChannel); metrics.newChannel(openChannelInClosedConnection); - assertThat(connections(metrics), is(2L)); - assertThat(channels(metrics), is(2L+1L)); + assertThat(connections(metrics)).isEqualTo(2L); + assertThat(channels(metrics)).isEqualTo(2L+1L); metrics.cleanStaleState(); - assertThat(connections(metrics), is(1L)); - assertThat(channels(metrics), is(1L)); + assertThat(connections(metrics)).isEqualTo(1L); + assertThat(channels(metrics)).isEqualTo(1L); } diff --git a/src/test/java/com/rabbitmq/client/test/MicrometerMetricsCollectorTest.java b/src/test/java/com/rabbitmq/client/test/MicrometerMetricsCollectorTest.java index 5cc8aa6178..77798a0088 100644 --- a/src/test/java/com/rabbitmq/client/test/MicrometerMetricsCollectorTest.java +++ b/src/test/java/com/rabbitmq/client/test/MicrometerMetricsCollectorTest.java @@ -18,14 +18,10 @@ import com.rabbitmq.client.impl.MicrometerMetricsCollector; import io.micrometer.core.instrument.Meter; import io.micrometer.core.instrument.simple.SimpleMeterRegistry; +import org.assertj.core.api.Assertions; import org.junit.Before; import org.junit.Test; -import java.util.Iterator; - -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; - /** * */ @@ -44,7 +40,7 @@ public void init() { public void noTag() { collector = new MicrometerMetricsCollector(registry, "rabbitmq"); for (Meter meter : registry.getMeters()) { - assertThat(size(meter.getId().getTags()), is(0)); + Assertions.assertThat(meter.getId().getTags()).isEmpty(); } } @@ -52,7 +48,7 @@ public void noTag() { public void tags() { collector = new MicrometerMetricsCollector(registry, "rabbitmq", "uri", "/api/users"); for (Meter meter : registry.getMeters()) { - assertThat(size(meter.getId().getTags()), is(1)); + Assertions.assertThat(meter.getId().getTags()).hasSize(1); } } @@ -61,11 +57,4 @@ public void tagsMustBeKeyValuePairs() { collector = new MicrometerMetricsCollector(registry, "rabbitmq", "uri"); } - static int size(Iterable iterable) { - Iterator iterator = iterable.iterator(); - int i = 0; - for ( ; iterator.hasNext() ; ++i ) iterator.next(); - return i; - } - } diff --git a/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java b/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java index 5014bcda2f..62a237cb83 100644 --- a/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java +++ b/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java @@ -42,8 +42,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; /** * Test to trigger and check the fix of rabbitmq/rabbitmq-java-client#341, @@ -149,15 +148,13 @@ public void handleRecoveryStarted(Recoverable recoverable) { produceMessagesInBackground(producingChannel, queue); startConsumer(queue); - assertThat( - "Connection should have been closed and should have recovered by now", - recoveryLatch.await(60, TimeUnit.SECONDS), is(true) - ); + assertThat(recoveryLatch.await(60, TimeUnit.SECONDS)) + .as("Connection should have been closed and should have recovered by now") + .isTrue(); - assertThat( - "Consumer should have recovered by now", - consumerOkLatch.await(5, TimeUnit.SECONDS), is(true) - ); + assertThat(consumerOkLatch.await(5, TimeUnit.SECONDS)) + .as("Consumer should have recovered by now") + .isTrue(); } private void closeConnectionIfOpen(Connection connection) throws IOException { @@ -173,16 +170,12 @@ private void declareQueue(final Channel channel, final String queue) throws IOEx private void produceMessagesInBackground(final Channel channel, final String queue) throws IOException { final AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder().deliveryMode(1).build(); - executorService.submit(new Callable() { - - @Override - public Void call() throws Exception { - for (int i = 0; i < NUM_MESSAGES_TO_PRODUCE; i++) { - channel.basicPublish("", queue, false, properties, MESSAGE_CONTENT); - } - closeConnectionIfOpen(producingConnection); - return null; + executorService.submit((Callable) () -> { + for (int i = 0; i < NUM_MESSAGES_TO_PRODUCE; i++) { + channel.basicPublish("", queue, false, properties, MESSAGE_CONTENT); } + closeConnectionIfOpen(producingConnection); + return null; }); } diff --git a/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java b/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java index 3d6099e12c..0c5df5823f 100644 --- a/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java +++ b/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java @@ -30,11 +30,7 @@ import java.util.Properties; import static com.rabbitmq.client.impl.AMQConnection.defaultClientProperties; -import static org.hamcrest.Matchers.hasSize; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; -import static org.hamcrest.Matchers.notNullValue; -import static org.junit.Assert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; /** * @@ -84,24 +80,24 @@ public static Object[] data() { @Test public void propertyInitialisationUri() { cf.load(Collections.singletonMap("rabbitmq.uri", "amqp://foo:bar@127.0.0.1:5673/dummy")); - assertThat(cf.getUsername(), is("foo")); - assertThat(cf.getPassword(), is("bar")); - assertThat(cf.getVirtualHost(), is("dummy")); - assertThat(cf.getHost(), is("127.0.0.1")); - assertThat(cf.getPort(), is(5673)); + assertThat(cf.getUsername()).isEqualTo("foo"); + assertThat(cf.getPassword()).isEqualTo("bar"); + assertThat(cf.getVirtualHost()).isEqualTo("dummy"); + assertThat(cf.getHost()).isEqualTo("127.0.0.1"); + assertThat(cf.getPort()).isEqualTo(5673); } @Test public void propertyInitialisationIncludeDefaultClientPropertiesByDefault() { - cf.load(new HashMap()); - assertThat(cf.getClientProperties().entrySet(), hasSize(defaultClientProperties().size())); + cf.load(new HashMap<>()); + assertThat(cf.getClientProperties().entrySet()).hasSize(defaultClientProperties().size()); } @Test public void propertyInitialisationAddCustomClientProperty() { cf.load(new HashMap() {{ put("rabbitmq.client.properties.foo", "bar"); }}); - assertThat(cf.getClientProperties().entrySet(), hasSize(defaultClientProperties().size() + 1)); - assertThat(cf.getClientProperties().get("foo").toString(), is("bar")); + assertThat(cf.getClientProperties().entrySet()).hasSize(defaultClientProperties().size() + 1); + assertThat(cf.getClientProperties()).extracting("foo").isEqualTo("bar"); } @Test public void propertyInitialisationGetRidOfDefaultClientPropertyWithEmptyValue() { @@ -109,7 +105,7 @@ public static Object[] data() { cf.load(new HashMap() {{ put("rabbitmq.client.properties." + key, ""); }}); - assertThat(cf.getClientProperties().entrySet(), hasSize(defaultClientProperties().size() - 1)); + assertThat(cf.getClientProperties().entrySet()).hasSize(defaultClientProperties().size() - 1); } @Test public void propertyInitialisationOverrideDefaultClientProperty() { @@ -117,8 +113,8 @@ public static Object[] data() { cf.load(new HashMap() {{ put("rabbitmq.client.properties." + key, "whatever"); }}); - assertThat(cf.getClientProperties().entrySet(), hasSize(defaultClientProperties().size())); - assertThat(cf.getClientProperties().get(key).toString(), is("whatever")); + assertThat(cf.getClientProperties().entrySet()).hasSize(defaultClientProperties().size()); + assertThat(cf.getClientProperties()).extracting(key).isEqualTo("whatever"); } @Test public void propertyInitialisationDoNotUseNio() throws Exception { @@ -126,37 +122,37 @@ public static Object[] data() { put("rabbitmq.use.nio", "false"); put("rabbitmq.nio.nb.io.threads", "2"); }}); - assertThat(cf.getNioParams().getNbIoThreads(), not(2)); + assertThat(cf.getNioParams().getNbIoThreads()).isNotEqualTo(2); } private void checkConnectionFactory() { - assertThat(cf.getUsername(), is("foo")); - assertThat(cf.getPassword(), is("bar")); - assertThat(cf.getVirtualHost(), is("dummy")); - assertThat(cf.getHost(), is("127.0.0.1")); - assertThat(cf.getPort(), is(5673)); - - assertThat(cf.getRequestedChannelMax(), is(1)); - assertThat(cf.getRequestedFrameMax(), is(2)); - assertThat(cf.getRequestedHeartbeat(), is(10)); - assertThat(cf.getConnectionTimeout(), is(10000)); - assertThat(cf.getHandshakeTimeout(), is(5000)); - - assertThat(cf.getClientProperties().entrySet(), hasSize(defaultClientProperties().size() + 1)); - assertThat(cf.getClientProperties().get("foo").toString(), is("bar")); - - assertThat(cf.isAutomaticRecoveryEnabled(), is(false)); - assertThat(cf.isTopologyRecoveryEnabled(), is(false)); - assertThat(cf.getNetworkRecoveryInterval(), is(10000l)); - assertThat(cf.getChannelRpcTimeout(), is(10000)); - assertThat(cf.isChannelShouldCheckRpcResponseType(), is(true)); - - assertThat(cf.getNioParams(), notNullValue()); - assertThat(cf.getNioParams().getReadByteBufferSize(), is(32000)); - assertThat(cf.getNioParams().getWriteByteBufferSize(), is(32000)); - assertThat(cf.getNioParams().getNbIoThreads(), is(2)); - assertThat(cf.getNioParams().getWriteEnqueuingTimeoutInMs(), is(5000)); - assertThat(cf.getNioParams().getWriteQueueCapacity(), is(1000)); + assertThat(cf.getUsername()).isEqualTo("foo"); + assertThat(cf.getPassword()).isEqualTo("bar"); + assertThat(cf.getVirtualHost()).isEqualTo("dummy"); + assertThat(cf.getHost()).isEqualTo("127.0.0.1"); + assertThat(cf.getPort()).isEqualTo(5673); + + assertThat(cf.getRequestedChannelMax()).isEqualTo(1); + assertThat(cf.getRequestedFrameMax()).isEqualTo(2); + assertThat(cf.getRequestedHeartbeat()).isEqualTo(10); + assertThat(cf.getConnectionTimeout()).isEqualTo(10000); + assertThat(cf.getHandshakeTimeout()).isEqualTo(5000); + + assertThat(cf.getClientProperties().entrySet()).hasSize(defaultClientProperties().size() + 1); + assertThat(cf.getClientProperties()).extracting("foo").isEqualTo("bar"); + + assertThat(cf.isAutomaticRecoveryEnabled()).isFalse(); + assertThat(cf.isTopologyRecoveryEnabled()).isFalse(); + assertThat(cf.getNetworkRecoveryInterval()).isEqualTo(10000l); + assertThat(cf.getChannelRpcTimeout()).isEqualTo(10000); + assertThat(cf.isChannelShouldCheckRpcResponseType()).isTrue(); + + assertThat(cf.getNioParams()).isNotNull(); + assertThat(cf.getNioParams().getReadByteBufferSize()).isEqualTo(32000); + assertThat(cf.getNioParams().getWriteByteBufferSize()).isEqualTo(32000); + assertThat(cf.getNioParams().getNbIoThreads()).isEqualTo(2); + assertThat(cf.getNioParams().getWriteEnqueuingTimeoutInMs()).isEqualTo(5000); + assertThat(cf.getNioParams().getWriteQueueCapacity()).isEqualTo(1000); } private Properties getPropertiesWitPrefix(String prefix) throws IOException { diff --git a/src/test/java/com/rabbitmq/client/test/RpcTest.java b/src/test/java/com/rabbitmq/client/test/RpcTest.java index 87d0be518b..a11544f2b4 100644 --- a/src/test/java/com/rabbitmq/client/test/RpcTest.java +++ b/src/test/java/com/rabbitmq/client/test/RpcTest.java @@ -39,7 +39,7 @@ import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; -import static org.awaitility.Awaitility.waitAtMost; +import static com.rabbitmq.client.test.TestUtils.waitAtMost; import static org.junit.Assert.*; public class RpcTest { @@ -320,7 +320,7 @@ public void handleRecoveryStarted(Recoverable recoverable) { serverThread.interrupt(); - waitAtMost(Duration.ofSeconds(1)).until(() -> !serverThread.isAlive()) ; + waitAtMost(Duration.ofSeconds(1), () -> !serverThread.isAlive()); client.close(); } diff --git a/src/test/java/com/rabbitmq/client/test/StrictExceptionHandlerTest.java b/src/test/java/com/rabbitmq/client/test/StrictExceptionHandlerTest.java index 300d8ad053..06bf5efe7c 100644 --- a/src/test/java/com/rabbitmq/client/test/StrictExceptionHandlerTest.java +++ b/src/test/java/com/rabbitmq/client/test/StrictExceptionHandlerTest.java @@ -28,9 +28,8 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; public class StrictExceptionHandlerTest { @@ -58,7 +57,7 @@ public void handleConsumerException(Channel channel, Throwable exception, Consum channel )); channel.basicPublish("", queue, null, new byte[0]); - assertThat(latch.await(5, TimeUnit.SECONDS), is(true)); + assertThat(latch.await(5, TimeUnit.SECONDS)).isTrue(); } } diff --git a/src/test/java/com/rabbitmq/client/test/TestUtils.java b/src/test/java/com/rabbitmq/client/test/TestUtils.java index 012882d3f4..b6cec91132 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtils.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtils.java @@ -19,6 +19,7 @@ import com.rabbitmq.client.impl.NetworkConnection; import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; import com.rabbitmq.tools.Host; +import org.assertj.core.api.Assertions; import org.junit.AssumptionViolatedException; import org.junit.rules.TestRule; import org.junit.runner.Description; @@ -29,6 +30,7 @@ import java.io.IOException; import java.net.ServerSocket; import java.security.NoSuchAlgorithmException; +import java.time.Duration; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -36,6 +38,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import java.util.function.BooleanSupplier; import static org.junit.Assert.assertTrue; @@ -53,6 +56,28 @@ public static ConnectionFactory connectionFactory() { return connectionFactory; } + public static void waitAtMost(Duration timeout, BooleanSupplier condition) { + if (condition.getAsBoolean()) { + return; + } + int waitTime = 100; + int waitedTime = 0; + long timeoutInMs = timeout.toMillis(); + while (waitedTime <= timeoutInMs) { + try { + Thread.sleep(waitTime); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException(e); + } + if (condition.getAsBoolean()) { + return; + } + waitedTime += waitTime; + } + Assertions.fail("Waited " + timeout.getSeconds() + " second(s), condition never got true"); + } + public static void close(Connection connection) { if (connection != null) { try { diff --git a/src/test/java/com/rabbitmq/client/test/TestUtilsTest.java b/src/test/java/com/rabbitmq/client/test/TestUtilsTest.java index 1de1fe975a..76e5276d7d 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtilsTest.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtilsTest.java @@ -16,13 +16,12 @@ package com.rabbitmq.client.test; import com.rabbitmq.client.Connection; +import org.assertj.core.api.Assertions; import org.junit.Test; import java.util.HashMap; import java.util.Map; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -35,13 +34,13 @@ public void isVersion37orLater() { when(connection.getServerProperties()).thenReturn(serverProperties); serverProperties.put("version", "3.7.0+rc.1.4.gedc5d96"); - assertThat(TestUtils.isVersion37orLater(connection), is(true)); + Assertions.assertThat(TestUtils.isVersion37orLater(connection)).isTrue(); serverProperties.put("version", "3.7.0~alpha.449-1"); - assertThat(TestUtils.isVersion37orLater(connection), is(true)); + Assertions.assertThat(TestUtils.isVersion37orLater(connection)).isTrue(); serverProperties.put("version", "3.7.1-alpha.40"); - assertThat(TestUtils.isVersion37orLater(connection), is(true)); + Assertions.assertThat(TestUtils.isVersion37orLater(connection)).isTrue(); } @Test @@ -51,15 +50,15 @@ public void isVersion38orLater() { when(connection.getServerProperties()).thenReturn(serverProperties); serverProperties.put("version", "3.7.0+rc.1.4.gedc5d96"); - assertThat(TestUtils.isVersion38orLater(connection), is(false)); + Assertions.assertThat(TestUtils.isVersion38orLater(connection)).isFalse(); serverProperties.put("version", "3.7.0~alpha.449-1"); - assertThat(TestUtils.isVersion38orLater(connection), is(false)); + Assertions.assertThat(TestUtils.isVersion38orLater(connection)).isFalse(); serverProperties.put("version", "3.7.1-alpha.40"); - assertThat(TestUtils.isVersion38orLater(connection), is(false)); + Assertions.assertThat(TestUtils.isVersion38orLater(connection)).isFalse(); serverProperties.put("version", "3.8.0+beta.4.38.g33a7f97"); - assertThat(TestUtils.isVersion38orLater(connection), is(true)); + Assertions.assertThat(TestUtils.isVersion38orLater(connection)).isTrue(); } } diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java index 486e5448ce..426e3c2c0f 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -40,9 +40,8 @@ import java.util.concurrent.atomic.AtomicReference; import static com.rabbitmq.client.test.TestUtils.prepareForRecovery; -import static org.hamcrest.Matchers.greaterThanOrEqualTo; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; @SuppressWarnings("ThrowFromFinallyBlock") public class ConnectionRecovery extends BrokerTestCase { @@ -51,9 +50,9 @@ public class ConnectionRecovery extends BrokerTestCase { private static final int MANY_DECLARATIONS_LOOP_COUNT = 500; @Test public void connectionRecovery() throws IOException, InterruptedException { - assertTrue(connection.isOpen()); + assertThat(connection.isOpen()).isTrue(); closeAndWaitForRecovery(); - assertTrue(connection.isOpen()); + assertThat(connection.isOpen()).isTrue(); } @Test public void namedConnectionRecovery() @@ -61,20 +60,20 @@ public class ConnectionRecovery extends BrokerTestCase { String connectionName = "custom name"; RecoverableConnection c = newRecoveringConnection(connectionName); try { - assertTrue(c.isOpen()); - assertEquals(connectionName, c.getClientProvidedName()); + assertThat(c.isOpen()).isTrue(); + assertThat(connectionName).isEqualTo(c.getClientProvidedName()); TestUtils.closeAndWaitForRecovery(c); - assertTrue(c.isOpen()); - assertEquals(connectionName, c.getClientProvidedName()); + assertThat(c.isOpen()).isTrue(); + assertThat(connectionName).isEqualTo(c.getClientProvidedName()); } finally { c.abort(); } } @Test public void connectionRecoveryWithServerRestart() throws IOException, InterruptedException { - assertTrue(connection.isOpen()); + assertThat(connection.isOpen()).isTrue(); restartPrimaryAndWaitForRecovery(); - assertTrue(connection.isOpen()); + assertThat(connection.isOpen()).isTrue(); } @Test public void connectionRecoveryWithArrayOfAddresses() @@ -82,9 +81,9 @@ public class ConnectionRecovery extends BrokerTestCase { final Address[] addresses = {new Address("127.0.0.1"), new Address("127.0.0.1", 5672)}; RecoverableConnection c = newRecoveringConnection(addresses); try { - assertTrue(c.isOpen()); + assertThat(c.isOpen()).isTrue(); TestUtils.closeAndWaitForRecovery(c); - assertTrue(c.isOpen()); + assertThat(c.isOpen()).isTrue(); } finally { c.abort(); } @@ -98,9 +97,9 @@ public class ConnectionRecovery extends BrokerTestCase { RecoverableConnection c = newRecoveringConnection(addresses); try { - assertTrue(c.isOpen()); + assertThat(c.isOpen()).isTrue(); TestUtils.closeAndWaitForRecovery(c); - assertTrue(c.isOpen()); + assertThat(c.isOpen()).isTrue(); } finally { c.abort(); } @@ -113,14 +112,14 @@ public class ConnectionRecovery extends BrokerTestCase { String q = "java-client.test.recovery.q2"; ch.queueDeclare(q, false, true, false, null); ch.queueDeclarePassive(q); - assertTrue(c.isOpen()); + assertThat(c.isOpen()).isTrue(); try { CountDownLatch shutdownLatch = prepareForShutdown(c); CountDownLatch recoveryLatch = prepareForRecovery(c); Host.closeConnection((NetworkConnection) c); wait(shutdownLatch); wait(recoveryLatch); - assertTrue(c.isOpen()); + assertThat(c.isOpen()).isTrue(); ch.queueDeclarePassive(q); fail("expected passive declaration to throw"); } catch (java.io.IOException e) { @@ -154,15 +153,15 @@ public String getPassword() { }); RecoverableConnection c = (RecoverableConnection) cf.newConnection(); try { - assertTrue(c.isOpen()); - assertThat(usernameRequested.get(), is(1)); - assertThat(passwordRequested.get(), is(1)); + assertThat(c.isOpen()).isTrue(); + assertThat(usernameRequested.get()).isEqualTo(1); + assertThat(passwordRequested.get()).isEqualTo(1); TestUtils.closeAndWaitForRecovery(c); - assertTrue(c.isOpen()); + assertThat(c.isOpen()).isTrue(); // username is requested in AMQConnection#toString, so it can be accessed at any time - assertThat(usernameRequested.get(), greaterThanOrEqualTo(2)); - assertThat(passwordRequested.get(), is(2)); + assertThat(usernameRequested.get()).isGreaterThanOrEqualTo(2); + assertThat(passwordRequested.get()).isEqualTo(2); } finally { c.abort(); } @@ -204,13 +203,13 @@ public void handleRecoveryStarted(Recoverable recoverable) { latch.countDown(); } }); - assertTrue(connection.isOpen()); + assertThat(connection.isOpen()).isTrue(); closeAndWaitForRecovery(); - assertTrue(connection.isOpen()); - assertEquals("shutdown hook 1", events.get(0)); - assertEquals("shutdown hook 2", events.get(1)); + assertThat(connection.isOpen()).isTrue(); + assertThat(events).element(0).isEqualTo("shutdown hook 1"); + assertThat(events).element(1).isEqualTo("shutdown hook 2"); recoveryCanBeginLatch.await(5, TimeUnit.SECONDS); - assertEquals("recovery start hook 1", events.get(2)); + assertThat(events).element(2).isEqualTo("recovery start hook 1"); connection.close(); wait(latch); } @@ -223,9 +222,9 @@ public void shutdownCompleted(ShutdownSignalException cause) { latch.countDown(); } }); - assertTrue(connection.isOpen()); + assertThat(connection.isOpen()).isTrue(); closeAndWaitForRecovery(); - assertTrue(connection.isOpen()); + assertThat(connection.isOpen()).isTrue(); connection.close(); wait(latch); } @@ -238,11 +237,11 @@ public void shutdownCompleted(ShutdownSignalException cause) { latch.countDown(); } }); - assertTrue(connection.isOpen()); + assertThat(connection.isOpen()).isTrue(); closeAndWaitForRecovery(); - assertTrue(connection.isOpen()); + assertThat(connection.isOpen()).isTrue(); closeAndWaitForRecovery(); - assertTrue(connection.isOpen()); + assertThat(connection.isOpen()).isTrue(); connection.close(); wait(latch); } @@ -271,8 +270,8 @@ public void handleUnblocked() throws IOException { Channel ch1 = connection.createChannel(); Channel ch2 = connection.createChannel(); - assertTrue(ch1.isOpen()); - assertTrue(ch2.isOpen()); + assertThat(ch1.isOpen()).isTrue(); + assertThat(ch2.isOpen()).isTrue(); closeAndWaitForRecovery(); expectChannelRecovery(ch1); expectChannelRecovery(ch2); @@ -391,7 +390,7 @@ private void testClientNamedQueueRecoveryWith(String q, boolean noWait) throws I ch.basicPublish(x, "", null, "msg".getBytes()); waitForConfirms(ch); AMQP.Queue.DeclareOk ok = ch.queueDeclare(q, false, false, true, null); - assertEquals(1, ok.getMessageCount()); + assertThat(ok.getMessageCount()).isEqualTo(1); ch.queueDelete(q); ch.exchangeDelete(x); } @@ -422,7 +421,7 @@ public void queueRecovered(String oldName, String newName) { ch.basicPublish(x, "", null, "msg".getBytes()); waitForConfirms(ch); AMQP.Queue.DeclareOk ok = ch.queueDeclarePassive(nameAfter.get()); - assertEquals(1, ok.getMessageCount()); + assertThat(ok.getMessageCount()).isEqualTo(1); ch.queueDelete(nameAfter.get()); ch.exchangeDelete(x); } @@ -511,13 +510,10 @@ public void queueRecovered(String oldName, String newName) { final AtomicReference nameBefore = new AtomicReference(); final AtomicReference nameAfter = new AtomicReference(); final CountDownLatch listenerLatch = new CountDownLatch(1); - ((AutorecoveringConnection)connection).addQueueRecoveryListener(new QueueRecoveryListener() { - @Override - public void queueRecovered(String oldName, String newName) { - nameBefore.set(oldName); - nameAfter.set(newName); - listenerLatch.countDown(); - } + ((AutorecoveringConnection)connection).addQueueRecoveryListener((oldName, newName) -> { + nameBefore.set(oldName); + nameAfter.set(newName); + listenerLatch.countDown(); }); closeAndWaitForRecovery(); @@ -525,7 +521,7 @@ public void queueRecovered(String oldName, String newName) { expectChannelRecovery(channel); channel.basicPublish(x, "", null, "msg".getBytes()); assertDelivered(q, 1); - assertFalse(nameBefore.get().equals(nameAfter.get())); + assertThat(nameBefore).doesNotHaveValue(nameAfter.get()); channel.queueDelete(q); } @@ -620,11 +616,11 @@ public void queueRecovered(String oldName, String newName) { channel.queueDeclare(q, true, false, false, null); // now delete it using the delegate so AutorecoveringConnection and AutorecoveringChannel are not aware of it ((AutorecoveringChannel)channel).getDelegate().queueDelete(q); - assertNotNull(((AutorecoveringConnection)connection).getRecordedQueues().get(q)); + assertThat(((AutorecoveringConnection)connection).getRecordedQueues().get(q)).isNotNull(); // exclude the queue from recovery ((AutorecoveringConnection)connection).excludeQueueFromRecovery(q, true); // verify its not there - assertNull(((AutorecoveringConnection)connection).getRecordedQueues().get(q)); + assertThat(((AutorecoveringConnection)connection).getRecordedQueues().get(q)).isNull(); // reconnect closeAndWaitForRecovery(); expectChannelRecovery(channel); @@ -669,7 +665,7 @@ public void consumerRecovered(String oldConsumerTag, String newConsumerTag) { assertConsumerCount(n, q); closeAndWaitForRecovery(); wait(listenerLatch); - assertTrue(tagA.get().equals(tagB.get())); + assertThat(tagA.get().equals(tagB.get())).isTrue(); expectChannelRecovery(channel); assertConsumerCount(n, q); @@ -721,8 +717,8 @@ public void handleRecoveryStarted(Recoverable recoverable) { RecoverableChannel ch2 = (RecoverableChannel) connection.createChannel(); ch2.addRecoveryListener(listener); - assertTrue(ch1.isOpen()); - assertTrue(ch2.isOpen()); + assertThat(ch1.isOpen()).isTrue(); + assertThat(ch2.isOpen()).isTrue(); closeAndWaitForRecovery(); expectChannelRecovery(ch1); expectChannelRecovery(ch2); @@ -777,23 +773,23 @@ public void handleDelivery(String consumerTag, Channel channel1 = connection.createChannel(); Channel channel2 = connection.createChannel(); - assertEquals(0, connectionConsumers.size()); + assertThat(connectionConsumers).isEmpty(); String queue = channel1.queueDeclare().getQueue(); - channel1.basicConsume(queue, true, new HashMap(), new DefaultConsumer(channel1)); - assertEquals(1, connectionConsumers.size()); - channel1.basicConsume(queue, true, new HashMap(), new DefaultConsumer(channel1)); - assertEquals(2, connectionConsumers.size()); + channel1.basicConsume(queue, true, new HashMap<>(), new DefaultConsumer(channel1)); + assertThat(connectionConsumers).hasSize(1); + channel1.basicConsume(queue, true, new HashMap<>(), new DefaultConsumer(channel1)); + assertThat(connectionConsumers).hasSize(2); - channel2.basicConsume(queue, true, new HashMap(), new DefaultConsumer(channel2)); - assertEquals(3, connectionConsumers.size()); + channel2.basicConsume(queue, true, new HashMap<>(), new DefaultConsumer(channel2)); + assertThat(connectionConsumers).hasSize(3); channel1.close(); - assertEquals(3 - 2, connectionConsumers.size()); + assertThat(connectionConsumers).hasSize(3 - 2); channel2.close(); - assertEquals(0, connectionConsumers.size()); + assertThat(connectionConsumers).isEmpty(); } finally { connection.abort(); } @@ -804,9 +800,9 @@ public void handleDelivery(String consumerTag, connectionFactory.setRecoveryDelayHandler(new RecoveryDelayHandler.ExponentialBackoffDelayHandler()); Connection testConnection = connectionFactory.newConnection(); try { - assertTrue(testConnection.isOpen()); + assertThat(testConnection.isOpen()).isTrue(); TestUtils.closeAndWaitForRecovery((RecoverableConnection) testConnection); - assertTrue(testConnection.isOpen()); + assertThat(testConnection.isOpen()).isTrue(); } finally { connection.close(); } @@ -817,9 +813,9 @@ public void handleDelivery(String consumerTag, final ThreadPoolExecutor executor = new ThreadPoolExecutor(8, 8, 30, TimeUnit.SECONDS, new LinkedBlockingQueue()); executor.allowCoreThreadTimeOut(true); ConnectionFactory connectionFactory = buildConnectionFactoryWithRecoveryEnabled(false); - assertNull(connectionFactory.getTopologyRecoveryExecutor()); + assertThat(connectionFactory.getTopologyRecoveryExecutor()).isNull(); connectionFactory.setTopologyRecoveryExecutor(executor); - assertEquals(executor, connectionFactory.getTopologyRecoveryExecutor()); + assertThat(connectionFactory.getTopologyRecoveryExecutor()).isEqualTo(executor); RecoverableConnection testConnection = (RecoverableConnection) connectionFactory.newConnection(); try { final List channels = new ArrayList(); @@ -864,7 +860,7 @@ public void handleDelivery(String consumerTag, Envelope envelope, BasicPropertie } } // verify all queues/consumers got it - assertTrue(latch.await(30, TimeUnit.SECONDS)); + assertThat(latch.await(30, TimeUnit.SECONDS)).isTrue(); // cleanup Channel cleanupChannel = testConnection.createChannel(); @@ -878,7 +874,7 @@ public void handleDelivery(String consumerTag, Envelope envelope, BasicPropertie } private void assertConsumerCount(int exp, String q) throws IOException { - assertEquals(exp, channel.queueDeclarePassive(q).getConsumerCount()); + assertThat(channel.queueDeclarePassive(q).getConsumerCount()).isEqualTo(exp); } private static AMQP.Queue.DeclareOk declareClientNamedQueue(Channel ch, String q) throws IOException { @@ -906,11 +902,11 @@ private static void expectQueueRecovery(Channel ch, String q) throws IOException ch.confirmSelect(); ch.queuePurge(q); AMQP.Queue.DeclareOk ok1 = declareClientNamedQueue(ch, q); - assertEquals(0, ok1.getMessageCount()); + assertThat(ok1.getMessageCount()).isEqualTo(0); ch.basicPublish("", q, null, "msg".getBytes()); waitForConfirms(ch); AMQP.Queue.DeclareOk ok2 = declareClientNamedQueue(ch, q); - assertEquals(1, ok2.getMessageCount()); + assertThat(ok2.getMessageCount()).isEqualTo(1); } private static void expectAutoDeleteQueueAndBindingRecovery(Channel ch, String x, String q) throws IOException, InterruptedException, @@ -918,12 +914,12 @@ private static void expectAutoDeleteQueueAndBindingRecovery(Channel ch, String x ch.confirmSelect(); ch.queuePurge(q); AMQP.Queue.DeclareOk ok1 = declareClientNamedAutoDeleteQueue(ch, q); - assertEquals(0, ok1.getMessageCount()); + assertThat(ok1.getMessageCount()).isEqualTo(0); ch.exchangeDeclare(x, "fanout"); ch.basicPublish(x, "", null, "msg".getBytes()); waitForConfirms(ch); AMQP.Queue.DeclareOk ok2 = declareClientNamedAutoDeleteQueue(ch, q); - assertEquals(1, ok2.getMessageCount()); + assertThat(ok2.getMessageCount()).isEqualTo(1); } private static void expectExchangeRecovery(Channel ch, String x) throws IOException, InterruptedException, TimeoutException { @@ -964,7 +960,7 @@ private void restartPrimaryAndWaitForRecovery(Connection connection) throws IOEx } private static void expectChannelRecovery(Channel ch) { - assertTrue(ch.isOpen()); + assertThat(ch.isOpen()).isTrue(); } @Override @@ -1020,7 +1016,7 @@ private static ConnectionFactory buildConnectionFactoryWithRecoveryEnabled(boole private static void wait(CountDownLatch latch) throws InterruptedException { // we want to wait for recovery to complete for a reasonable amount of time // but still make recovery failures easy to notice in development environments - assertTrue(latch.await(90, TimeUnit.SECONDS)); + assertThat(latch.await(90, TimeUnit.SECONDS)).isTrue(); } private static void waitForConfirms(Channel ch) throws InterruptedException, TimeoutException { @@ -1028,10 +1024,10 @@ private static void waitForConfirms(Channel ch) throws InterruptedException, Tim } private static void assertRecordedQueues(Connection conn, int size) { - assertEquals(size, ((AutorecoveringConnection)conn).getRecordedQueues().size()); + assertThat(((AutorecoveringConnection)conn).getRecordedQueues()).hasSize(size); } private static void assertRecordedExchanges(Connection conn, int size) { - assertEquals(size, ((AutorecoveringConnection)conn).getRecordedExchanges().size()); + assertThat(((AutorecoveringConnection)conn).getRecordedExchanges()).hasSize(size); } } diff --git a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java index 98b82ed7af..3e2dc6df74 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java @@ -49,11 +49,8 @@ import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; -import static org.awaitility.Awaitility.waitAtMost; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; +import static com.rabbitmq.client.test.TestUtils.waitAtMost; +import static org.assertj.core.api.Assertions.assertThat; /** * @@ -88,51 +85,51 @@ protected void releaseResources() throws IOException { Connection connection2 = null; try { connection1 = connectionFactory.newConnection(); - assertThat(metrics.getConnections().getCount(), is(1L)); + assertThat(metrics.getConnections().getCount()).isEqualTo(1L); connection1.createChannel(); connection1.createChannel(); Channel channel = connection1.createChannel(); - assertThat(metrics.getChannels().getCount(), is(3L)); + assertThat(metrics.getChannels().getCount()).isEqualTo(3L); sendMessage(channel); - assertThat(metrics.getPublishedMessages().getCount(), is(1L)); + assertThat(metrics.getPublishedMessages().getCount()).isEqualTo(1L); sendMessage(channel); - assertThat(metrics.getPublishedMessages().getCount(), is(2L)); + assertThat(metrics.getPublishedMessages().getCount()).isEqualTo(2L); channel.basicGet(QUEUE, true); - assertThat(metrics.getConsumedMessages().getCount(), is(1L)); + assertThat(metrics.getConsumedMessages().getCount()).isEqualTo(1L); channel.basicGet(QUEUE, true); - assertThat(metrics.getConsumedMessages().getCount(), is(2L)); + assertThat(metrics.getConsumedMessages().getCount()).isEqualTo(2L); channel.basicGet(QUEUE, true); - assertThat(metrics.getConsumedMessages().getCount(), is(2L)); + assertThat(metrics.getConsumedMessages().getCount()).isEqualTo(2L); connection2 = connectionFactory.newConnection(); - assertThat(metrics.getConnections().getCount(), is(2L)); + assertThat(metrics.getConnections().getCount()).isEqualTo(2L); connection2.createChannel(); channel = connection2.createChannel(); - assertThat(metrics.getChannels().getCount(), is(3L+2L)); + assertThat(metrics.getChannels().getCount()).isEqualTo(3L+2L); sendMessage(channel); sendMessage(channel); - assertThat(metrics.getPublishedMessages().getCount(), is(2L+2L)); + assertThat(metrics.getPublishedMessages().getCount()).isEqualTo(2L+2L); channel.basicGet(QUEUE, true); - assertThat(metrics.getConsumedMessages().getCount(), is(2L+1L)); + assertThat(metrics.getConsumedMessages().getCount()).isEqualTo(2L+1L); channel.basicConsume(QUEUE, true, new DefaultConsumer(channel)); - waitAtMost(timeout()).until(() -> metrics.getConsumedMessages().getCount(), equalTo(2L+1L+1L)); + waitAtMost(timeout(), () -> metrics.getConsumedMessages().getCount() == 2L+1L+1L); safeClose(connection1); - waitAtMost(timeout()).until(() -> metrics.getConnections().getCount(), equalTo(1L)); - waitAtMost(timeout()).until(() -> metrics.getChannels().getCount(), equalTo(2L)); + waitAtMost(timeout(), () -> metrics.getConnections().getCount() == 1L); + waitAtMost(timeout(), () -> metrics.getChannels().getCount() == 2L); safeClose(connection2); - waitAtMost(timeout()).until(() -> metrics.getConnections().getCount(), equalTo(0L)); - waitAtMost(timeout()).until(() -> metrics.getChannels().getCount(), equalTo(0L)); + waitAtMost(timeout(), () -> metrics.getConnections().getCount() == 0L); + waitAtMost(timeout(), () -> metrics.getChannels().getCount() == 0L); - assertThat(metrics.getAcknowledgedMessages().getCount(), is(0L)); - assertThat(metrics.getRejectedMessages().getCount(), is(0L)); + assertThat(metrics.getAcknowledgedMessages().getCount()).isEqualTo(0L); + assertThat(metrics.getRejectedMessages().getCount()).isEqualTo(0L); } finally { safeClose(connection1); @@ -148,7 +145,7 @@ protected void releaseResources() throws IOException { connection = connectionFactory.newConnection(); Channel channel = connection.createChannel(); channel.confirmSelect(); - assertThat(metrics.getPublishUnroutedMessages().getCount(), is(0L)); + assertThat(metrics.getPublishUnroutedMessages().getCount()).isEqualTo(0L); // when channel.basicPublish( "amq.direct", @@ -158,10 +155,7 @@ protected void releaseResources() throws IOException { "any-message".getBytes() ); // then - waitAtMost(timeout()).until( - () -> metrics.getPublishUnroutedMessages().getCount(), - equalTo(1L) - ); + waitAtMost(timeout(), () -> metrics.getPublishUnroutedMessages().getCount() == 1L); } finally { safeClose(connection); } @@ -175,13 +169,13 @@ protected void releaseResources() throws IOException { connection = connectionFactory.newConnection(); Channel channel = connection.createChannel(); channel.confirmSelect(); - assertThat(metrics.getPublishAcknowledgedMessages().getCount(), is(0L)); + assertThat(metrics.getPublishAcknowledgedMessages().getCount()).isEqualTo(0L); channel.basicConsume(QUEUE, false, new MultipleAckConsumer(channel, false)); // when sendMessage(channel); channel.waitForConfirms(30 * 60 * 1000); // then - assertThat(metrics.getPublishAcknowledgedMessages().getCount(), is(1L)); + assertThat(metrics.getPublishAcknowledgedMessages().getCount()).isEqualTo(1L); } finally { safeClose(connection); } @@ -200,8 +194,8 @@ protected void releaseResources() throws IOException { sendMessage(channel1); GetResponse getResponse = channel1.basicGet(QUEUE, false); channel1.basicAck(getResponse.getEnvelope().getDeliveryTag(), false); - assertThat(metrics.getConsumedMessages().getCount(), is(1L)); - assertThat(metrics.getAcknowledgedMessages().getCount(), is(1L)); + assertThat(metrics.getConsumedMessages().getCount()).isEqualTo(1L); + assertThat(metrics.getAcknowledgedMessages().getCount()).isEqualTo(1L); // basicGet / basicAck sendMessage(channel1); @@ -218,18 +212,18 @@ protected void releaseResources() throws IOException { GetResponse response5 = channel1.basicGet(QUEUE, false); GetResponse response6 = channel2.basicGet(QUEUE, false); - assertThat(metrics.getConsumedMessages().getCount(), is(1L+6L)); - assertThat(metrics.getAcknowledgedMessages().getCount(), is(1L)); + assertThat(metrics.getConsumedMessages().getCount()).isEqualTo(1L+6L); + assertThat(metrics.getAcknowledgedMessages().getCount()).isEqualTo(1L); channel1.basicAck(response5.getEnvelope().getDeliveryTag(), false); - assertThat(metrics.getAcknowledgedMessages().getCount(), is(1L+1L)); + assertThat(metrics.getAcknowledgedMessages().getCount()).isEqualTo(1L+1L); channel1.basicAck(response3.getEnvelope().getDeliveryTag(), true); - assertThat(metrics.getAcknowledgedMessages().getCount(), is(1L+1L+2L)); + assertThat(metrics.getAcknowledgedMessages().getCount()).isEqualTo(1L+1L+2L); channel2.basicAck(response2.getEnvelope().getDeliveryTag(), true); - assertThat(metrics.getAcknowledgedMessages().getCount(), is(1L+(1L+2L)+1L)); + assertThat(metrics.getAcknowledgedMessages().getCount()).isEqualTo(1L+(1L+2L)+1L); channel2.basicAck(response6.getEnvelope().getDeliveryTag(), true); - assertThat(metrics.getAcknowledgedMessages().getCount(), is(1L+(1L+2L)+1L+2L)); + assertThat(metrics.getAcknowledgedMessages().getCount()).isEqualTo(1L+(1L+2L)+1L+2L); long alreadySentMessages = 1+(1+2)+1+2; @@ -244,15 +238,9 @@ protected void releaseResources() throws IOException { sendMessage(i%2 == 0 ? channel1 : channel2); } - waitAtMost(timeout()).until( - () -> metrics.getConsumedMessages().getCount(), - equalTo(alreadySentMessages+nbMessages) - ); + waitAtMost(timeout(), () -> metrics.getConsumedMessages().getCount() == alreadySentMessages+nbMessages); - waitAtMost(timeout()).until( - () -> metrics.getAcknowledgedMessages().getCount(), - equalTo(alreadySentMessages+nbMessages) - ); + waitAtMost(timeout(), () -> metrics.getAcknowledgedMessages().getCount() == alreadySentMessages+nbMessages); } finally { safeClose(connection); @@ -277,10 +265,10 @@ protected void releaseResources() throws IOException { GetResponse response3 = channel.basicGet(QUEUE, false); channel.basicReject(response2.getEnvelope().getDeliveryTag(), false); - assertThat(metrics.getRejectedMessages().getCount(), is(1L)); + assertThat(metrics.getRejectedMessages().getCount()).isEqualTo(1L); channel.basicNack(response3.getEnvelope().getDeliveryTag(), true, false); - assertThat(metrics.getRejectedMessages().getCount(), is(1L+2L)); + assertThat(metrics.getRejectedMessages().getCount()).isEqualTo(1L+2L); } finally { safeClose(connection); } @@ -326,9 +314,9 @@ protected void releaseResources() throws IOException { } executorService.invokeAll(tasks); - assertThat(metrics.getPublishedMessages().getCount(), is(nbOfMessages)); - waitAtMost(timeout()).until(() -> metrics.getConsumedMessages().getCount(), equalTo(nbOfMessages)); - assertThat(metrics.getAcknowledgedMessages().getCount(), is(0L)); + assertThat(metrics.getPublishedMessages().getCount()).isEqualTo(nbOfMessages); + waitAtMost(timeout(), () -> metrics.getConsumedMessages().getCount() == nbOfMessages); + assertThat(metrics.getAcknowledgedMessages().getCount()).isEqualTo(0L); // to remove the listeners for(int i = 0; i < nbChannels; i++) { @@ -355,9 +343,9 @@ protected void releaseResources() throws IOException { } executorService.invokeAll(tasks); - assertThat(metrics.getPublishedMessages().getCount(), is(2*nbOfMessages)); - waitAtMost(timeout()).until(() -> metrics.getConsumedMessages().getCount(), equalTo(2*nbOfMessages)); - waitAtMost(timeout()).until(() -> metrics.getAcknowledgedMessages().getCount(), equalTo(nbOfMessages)); + assertThat(metrics.getPublishedMessages().getCount()).isEqualTo(2*nbOfMessages); + waitAtMost(timeout(), () -> metrics.getConsumedMessages().getCount() == 2*nbOfMessages); + waitAtMost(timeout(), () -> metrics.getAcknowledgedMessages().getCount() == nbOfMessages); // to remove the listeners for(int i = 0; i < nbChannels; i++) { @@ -384,10 +372,10 @@ protected void releaseResources() throws IOException { } executorService.invokeAll(tasks); - assertThat(metrics.getPublishedMessages().getCount(), is(3*nbOfMessages)); - waitAtMost(timeout()).until(() -> metrics.getConsumedMessages().getCount(), equalTo(3*nbOfMessages)); - waitAtMost(timeout()).until(() -> metrics.getAcknowledgedMessages().getCount(), equalTo(nbOfMessages)); - waitAtMost(timeout()).until(() -> metrics.getRejectedMessages().getCount(), equalTo(nbOfMessages)); + assertThat(metrics.getPublishedMessages().getCount()).isEqualTo(3*nbOfMessages); + waitAtMost(timeout(), () -> metrics.getConsumedMessages().getCount() == 3*nbOfMessages); + waitAtMost(timeout(), () -> metrics.getAcknowledgedMessages().getCount() == nbOfMessages); + waitAtMost(timeout(), () -> metrics.getRejectedMessages().getCount() == nbOfMessages); } finally { for (Connection connection : connections) { safeClose(connection); @@ -405,13 +393,13 @@ protected void releaseResources() throws IOException { connection = connectionFactory.newConnection(); Channel channel = connection.createChannel(); - assertThat(metrics.getConnections().getCount(), is(1L)); - assertThat(metrics.getChannels().getCount(), is(1L)); + assertThat(metrics.getConnections().getCount()).isEqualTo(1L); + assertThat(metrics.getChannels().getCount()).isEqualTo(1L); channel.basicPublish("unlikelynameforanexchange", "", null, "msg".getBytes("UTF-8")); - waitAtMost(timeout()).until(() -> metrics.getChannels().getCount(), is(0L)); - assertThat(metrics.getConnections().getCount(), is(1L)); + waitAtMost(timeout(), () -> metrics.getChannels().getCount() == 0L); + assertThat(metrics.getConnections().getCount()).isEqualTo(1L); } finally { safeClose(connection); } @@ -429,19 +417,19 @@ protected void releaseResources() throws IOException { connection = connectionFactory.newConnection(); Collection shutdownHooks = getShutdownHooks(connection); - assertThat(shutdownHooks.size(), is(0)); + assertThat(shutdownHooks.size()).isEqualTo(0); connection.createChannel(); - assertThat(metrics.getConnections().getCount(), is(1L)); - assertThat(metrics.getChannels().getCount(), is(1L)); + assertThat(metrics.getConnections().getCount()).isEqualTo(1L); + assertThat(metrics.getChannels().getCount()).isEqualTo(1L); closeAndWaitForRecovery((AutorecoveringConnection) connection); - assertThat(metrics.getConnections().getCount(), is(1L)); - assertThat(metrics.getChannels().getCount(), is(1L)); + assertThat(metrics.getConnections().getCount()).isEqualTo(1L); + assertThat(metrics.getChannels().getCount()).isEqualTo(1L); - assertThat(shutdownHooks.size(), is(0)); + assertThat(shutdownHooks.size()).isEqualTo(0); } finally { safeClose(connection); } @@ -482,10 +470,10 @@ protected void releaseResources() throws IOException { sendMessage(channel2); } - waitAtMost(timeout()).until(() -> ackedMessages.get(), equalTo(nbMessages * 2)); + waitAtMost(timeout(), () -> ackedMessages.get() == nbMessages * 2); - assertThat(metrics.getConsumedMessages().getCount(), is((long) (nbMessages * 2))); - assertThat(metrics.getAcknowledgedMessages().getCount(), is((long) (nbMessages * 2))); + assertThat(metrics.getConsumedMessages().getCount()).isEqualTo((long) (nbMessages * 2)); + assertThat(metrics.getAcknowledgedMessages().getCount()).isEqualTo((long) (nbMessages * 2)); } finally { safeClose(connection); @@ -517,7 +505,7 @@ public void handleRecoveryStarted(Recoverable recoverable) { } }); Host.closeConnection(connection); - assertTrue(latch.await(5, TimeUnit.SECONDS)); + assertThat(latch.await(5, TimeUnit.SECONDS)).isTrue(); } private Collection getShutdownHooks(Connection connection) throws NoSuchFieldException, IllegalAccessException { diff --git a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java index e8c3ff1148..27c210639c 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java +++ b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java @@ -32,17 +32,13 @@ import org.junit.Test; import java.io.IOException; +import java.time.Duration; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; -import static com.rabbitmq.client.test.TestUtils.closeAndWaitForRecovery; -import static com.rabbitmq.client.test.TestUtils.exchangeExists; -import static com.rabbitmq.client.test.TestUtils.queueExists; -import static com.rabbitmq.client.test.TestUtils.sendAndConsumeMessage; -import static org.awaitility.Awaitility.waitAtMost; -import static org.hamcrest.Matchers.is; +import static com.rabbitmq.client.test.TestUtils.*; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -147,7 +143,7 @@ public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProp } }); ch.basicPublish("topology.recovery.exchange", "recovered.consumer", null, "".getBytes()); - waitAtMost(5, TimeUnit.SECONDS).untilAtomic(recoveredConsumerMessageCount, is(1)); + waitAtMost(Duration.ofSeconds(5), () -> recoveredConsumerMessageCount.get() == 1); final AtomicInteger filteredConsumerMessageCount = new AtomicInteger(0); final CountDownLatch filteredConsumerLatch = new CountDownLatch(2); @@ -160,13 +156,13 @@ public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProp } }); ch.basicPublish("topology.recovery.exchange", "filtered.consumer", null, "".getBytes()); - waitAtMost(5, TimeUnit.SECONDS).untilAtomic(filteredConsumerMessageCount, is(1)); + waitAtMost(Duration.ofSeconds(5), () -> filteredConsumerMessageCount.get() == 1); closeAndWaitForRecovery((RecoverableConnection) c); int initialCount = recoveredConsumerMessageCount.get(); ch.basicPublish("topology.recovery.exchange", "recovered.consumer", null, "".getBytes()); - waitAtMost(5, TimeUnit.SECONDS).untilAtomic(recoveredConsumerMessageCount, is(initialCount + 1)); + waitAtMost(Duration.ofSeconds(5), () -> recoveredConsumerMessageCount.get() == initialCount + 1); ch.basicPublish("topology.recovery.exchange", "filtered.consumer", null, "".getBytes()); assertFalse("Consumer shouldn't recover, no extra messages should have been received", diff --git a/src/test/java/com/rabbitmq/tools/Host.java b/src/test/java/com/rabbitmq/tools/Host.java index 91f4c68f50..47c34b01ab 100644 --- a/src/test/java/com/rabbitmq/tools/Host.java +++ b/src/test/java/com/rabbitmq/tools/Host.java @@ -173,7 +173,8 @@ public static String makeCommand() public static String nodenameA() { - return System.getProperty("test-broker.A.nodename"); +// return System.getProperty("test-broker.A.nodename"); + return "rabbit@acogoluegnes-inspiron"; } public static String node_portA() From 855bcbcdb6ffdfc2514d6320f990817eefd6e99a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 1 Apr 2020 15:51:24 +0200 Subject: [PATCH 1230/2114] Bump Maven plugin (cherry picked from commit bc204c380a1c74e35e74f96ab7e14b9cfaa41c71) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 76f2173524..a3d188dfe9 100644 --- a/pom.xml +++ b/pom.xml @@ -65,7 +65,7 @@ 9.4.27.v20200227 1.64 - 3.1.1 + 3.2.0 2.5.3 2.3 3.0.2 From df38f551ccc87d1e1996004195a95774b2030c87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 1 Apr 2020 17:26:49 +0200 Subject: [PATCH 1231/2114] Fix test --- .../java/com/rabbitmq/client/test/ConnectionFactoryTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java b/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java index 0d1b695783..ff1e7e4b80 100644 --- a/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java +++ b/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java @@ -124,7 +124,7 @@ protected synchronized FrameHandlerFactory createFrameHandlerFactory() { doNothing().when(connection).start(); connectionFactory.newConnection(); - assertThat(addressResolver.get()).isNotNull().isInstanceOf(ListAddressResolver.class); + assertThat(addressResolver.get()).isNotNull().isInstanceOf(DnsRecordIpAddressResolver.class); } @Test From ec6f0e9a2c0b8b4471bc534c482789b156ad78a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 1 Apr 2020 17:56:51 +0200 Subject: [PATCH 1232/2114] Fix broker node name --- src/test/java/com/rabbitmq/tools/Host.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/test/java/com/rabbitmq/tools/Host.java b/src/test/java/com/rabbitmq/tools/Host.java index 47c34b01ab..91f4c68f50 100644 --- a/src/test/java/com/rabbitmq/tools/Host.java +++ b/src/test/java/com/rabbitmq/tools/Host.java @@ -173,8 +173,7 @@ public static String makeCommand() public static String nodenameA() { -// return System.getProperty("test-broker.A.nodename"); - return "rabbit@acogoluegnes-inspiron"; + return System.getProperty("test-broker.A.nodename"); } public static String node_portA() From efb05908d5685f1242521decc94bbeab08564e70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 1 Apr 2020 17:57:31 +0200 Subject: [PATCH 1233/2114] Fix broker node name --- src/test/java/com/rabbitmq/tools/Host.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/test/java/com/rabbitmq/tools/Host.java b/src/test/java/com/rabbitmq/tools/Host.java index 47c34b01ab..91f4c68f50 100644 --- a/src/test/java/com/rabbitmq/tools/Host.java +++ b/src/test/java/com/rabbitmq/tools/Host.java @@ -173,8 +173,7 @@ public static String makeCommand() public static String nodenameA() { -// return System.getProperty("test-broker.A.nodename"); - return "rabbit@acogoluegnes-inspiron"; + return System.getProperty("test-broker.A.nodename"); } public static String node_portA() From f2ea8622effd331b5da86b8d84972f85827e52dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 2 Apr 2020 11:03:06 +0200 Subject: [PATCH 1234/2114] Make sure qos, heartbeat, max channel are unsigned shorts Sets the value to 0 or 65535 and issues a warning if it is out of range. Fixes #642 --- .../rabbitmq/client/ConnectionFactory.java | 28 +++++++++++---- .../rabbitmq/client/impl/AMQConnection.java | 18 ++++++---- .../com/rabbitmq/client/impl/ChannelN.java | 8 +++-- .../rabbitmq/client/test/ChannelNTest.java | 32 ++++++++++++++--- .../client/test/ConnectionFactoryTest.java | 35 ++++++++++--------- 5 files changed, 84 insertions(+), 37 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 7fdcdb1324..71286d3b3b 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -21,6 +21,8 @@ import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; import com.rabbitmq.client.impl.recovery.RetryHandler; import com.rabbitmq.client.impl.recovery.TopologyRecoveryFilter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.net.SocketFactory; import javax.net.ssl.SSLContext; @@ -47,6 +49,8 @@ */ public class ConnectionFactory implements Cloneable { + private static final Logger LOGGER = LoggerFactory.getLogger(ConnectionFactory.class); + private static final int MAX_UNSIGNED_SHORT = 65535; /** Default user name */ @@ -393,10 +397,11 @@ public int getRequestedChannelMax() { * @param requestedChannelMax initially requested maximum channel number; zero for unlimited */ public void setRequestedChannelMax(int requestedChannelMax) { - if (requestedChannelMax < 0 || requestedChannelMax > MAX_UNSIGNED_SHORT) { - throw new IllegalArgumentException("Requested channel max must be between 0 and " + MAX_UNSIGNED_SHORT); + this.requestedChannelMax = ensureUnsignedShort(requestedChannelMax); + if (this.requestedChannelMax != requestedChannelMax) { + LOGGER.warn("Requested channel max must be between 0 and {}, value has been set to {} instead of {}", + MAX_UNSIGNED_SHORT, this.requestedChannelMax, requestedChannelMax); } - this.requestedChannelMax = requestedChannelMax; } /** @@ -492,10 +497,11 @@ public int getShutdownTimeout() { * @see RabbitMQ Heartbeats Guide */ public void setRequestedHeartbeat(int requestedHeartbeat) { - if (requestedHeartbeat < 0 || requestedHeartbeat > MAX_UNSIGNED_SHORT) { - throw new IllegalArgumentException("Requested heartbeat must be between 0 and " + MAX_UNSIGNED_SHORT); + this.requestedHeartbeat = ensureUnsignedShort(requestedHeartbeat); + if (this.requestedHeartbeat != requestedHeartbeat) { + LOGGER.warn("Requested heartbeat must be between 0 and {}, value has been set to {} instead of {}", + MAX_UNSIGNED_SHORT, this.requestedHeartbeat, requestedHeartbeat); } - this.requestedHeartbeat = requestedHeartbeat; } /** @@ -1574,4 +1580,14 @@ public void setTopologyRecoveryRetryHandler(RetryHandler topologyRecoveryRetryHa public void setTrafficListener(TrafficListener trafficListener) { this.trafficListener = trafficListener; } + + public static int ensureUnsignedShort(int value) { + if (value < 0) { + return 0; + } else if (value > MAX_UNSIGNED_SHORT) { + return MAX_UNSIGNED_SHORT; + } else { + return value; + } + } } diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index b140788a84..d99784f933 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -400,12 +400,15 @@ public void start() } try { - int channelMax = + int negotiatedChannelMax = negotiateChannelMax(this.requestedChannelMax, connTune.getChannelMax()); - if (!checkUnsignedShort(channelMax)) { - throw new IllegalArgumentException("Negotiated channel max must be between 0 and " + MAX_UNSIGNED_SHORT + ": " + channelMax); + int channelMax = ConnectionFactory.ensureUnsignedShort(negotiatedChannelMax); + + if (channelMax != negotiatedChannelMax) { + LOGGER.warn("Channel max must be between 0 and {}, value has been set to {} instead of {}", + MAX_UNSIGNED_SHORT, channelMax, negotiatedChannelMax); } _channelManager = instantiateChannelManager(channelMax, threadFactory); @@ -415,12 +418,15 @@ public void start() connTune.getFrameMax()); this._frameMax = frameMax; - int heartbeat = + int negotiatedHeartbeat = negotiatedMaxValue(this.requestedHeartbeat, connTune.getHeartbeat()); - if (!checkUnsignedShort(heartbeat)) { - throw new IllegalArgumentException("Negotiated heartbeat must be between 0 and " + MAX_UNSIGNED_SHORT + ": " + heartbeat); + int heartbeat = ConnectionFactory.ensureUnsignedShort(negotiatedHeartbeat); + + if (heartbeat != negotiatedHeartbeat) { + LOGGER.warn("Heartbeat must be between 0 and {}, value has been set to {} instead of {}", + MAX_UNSIGNED_SHORT, heartbeat, negotiatedHeartbeat); } setHeartbeat(heartbeat); diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java index 94da03e7bc..2bbc37a3ca 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelN.java @@ -642,10 +642,12 @@ public AMQCommand transformReply(AMQCommand command) { public void basicQos(int prefetchSize, int prefetchCount, boolean global) throws IOException { - if (prefetchCount < 0 || prefetchCount > MAX_UNSIGNED_SHORT) { - throw new IllegalArgumentException("Prefetch count must be between 0 and " + MAX_UNSIGNED_SHORT); + int unsignedShortPrefetchCount = ConnectionFactory.ensureUnsignedShort(prefetchCount); + if (unsignedShortPrefetchCount != prefetchCount) { + LOGGER.warn("Prefetch count must be between 0 and {}, value has been set to {} instead of {}", + MAX_UNSIGNED_SHORT, unsignedShortPrefetchCount, prefetchCount); } - exnWrappingRpc(new Basic.Qos(prefetchSize, prefetchCount, global)); + exnWrappingRpc(new Basic.Qos(prefetchSize, unsignedShortPrefetchCount, global)); } /** Public API - {@inheritDoc} */ diff --git a/src/test/java/com/rabbitmq/client/test/ChannelNTest.java b/src/test/java/com/rabbitmq/client/test/ChannelNTest.java index 194f086ef8..c955c28071 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelNTest.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelNTest.java @@ -25,8 +25,10 @@ import java.io.IOException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Stream; +import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; public class ChannelNTest { @@ -64,23 +66,43 @@ public void callingBasicCancelForUnknownConsumerThrowsException() throws Excepti @Test public void qosShouldBeUnsignedShort() { AMQConnection connection = Mockito.mock(AMQConnection.class); - ChannelN channel = new ChannelN(connection, 1, consumerWorkService); + AtomicReference qosMethod = new AtomicReference<>(); + ChannelN channel = new ChannelN(connection, 1, consumerWorkService) { + @Override + public AMQCommand exnWrappingRpc(Method m) { + qosMethod.set((com.rabbitmq.client.AMQP.Basic.Qos) m); + return null; + } + }; class TestConfig { int value; Consumer call; + int expected; - public TestConfig(int value, Consumer call) { + public TestConfig(int value, Consumer call, int expected) { this.value = value; this.call = call; + this.expected = expected; } } Consumer qos = value -> channel.basicQos(value); Consumer qosGlobal = value -> channel.basicQos(value, true); Consumer qosPrefetchSize = value -> channel.basicQos(10, value, true); Stream.of( - new TestConfig(-1, qos), new TestConfig(65536, qos) - ).flatMap(config -> Stream.of(config, new TestConfig(config.value, qosGlobal), new TestConfig(config.value, qosPrefetchSize))) - .forEach(config -> assertThatThrownBy(() -> config.call.apply(config.value)).isInstanceOf(IllegalArgumentException.class)); + new TestConfig(-1, qos, 0), new TestConfig(65536, qos, 65535), + new TestConfig(10, qos, 10), new TestConfig(0, qos, 0) + ).flatMap(config -> Stream.of(config, new TestConfig(config.value, qosGlobal, config.expected), new TestConfig(config.value, qosPrefetchSize, config.expected))) + .forEach(config -> { + try { + assertThat(qosMethod.get()).isNull(); + config.call.apply(config.value); + assertThat(qosMethod.get()).isNotNull(); + assertThat(qosMethod.get().getPrefetchCount()).isEqualTo(config.expected); + qosMethod.set(null); + } catch (Exception e) { + e.printStackTrace(); + } + }); } interface Consumer { diff --git a/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java b/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java index ff1e7e4b80..1846078ff2 100644 --- a/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java +++ b/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java @@ -27,10 +27,10 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; +import java.util.function.Supplier; import java.util.stream.Stream; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.Mockito.*; public class ConnectionFactoryTest { @@ -164,33 +164,34 @@ protected synchronized FrameHandlerFactory createFrameHandlerFactory() { public void heartbeatAndChannelMaxMustBeUnsignedShorts() { class TestConfig { int value; - Consumer call; - boolean expectException; + Supplier getCall; + Consumer setCall; + int expected; - public TestConfig(int value, Consumer call, boolean expectException) { + public TestConfig(int value, Supplier getCall, Consumer setCall, int expected) { this.value = value; - this.call = call; - this.expectException = expectException; + this.getCall = getCall; + this.setCall = setCall; + this.expected = expected; } } ConnectionFactory cf = new ConnectionFactory(); + Supplier getHeartbeart = () -> cf.getRequestedHeartbeat(); Consumer setHeartbeat = cf::setRequestedHeartbeat; + Supplier getChannelMax = () -> cf.getRequestedChannelMax(); Consumer setChannelMax = cf::setRequestedChannelMax; Stream.of( - new TestConfig(0, setHeartbeat, false), - new TestConfig(10, setHeartbeat, false), - new TestConfig(65535, setHeartbeat, false), - new TestConfig(-1, setHeartbeat, true), - new TestConfig(65536, setHeartbeat, true)) - .flatMap(config -> Stream.of(config, new TestConfig(config.value, setChannelMax, config.expectException))) + new TestConfig(0, getHeartbeart, setHeartbeat, 0), + new TestConfig(10, getHeartbeart, setHeartbeat, 10), + new TestConfig(65535, getHeartbeart, setHeartbeat, 65535), + new TestConfig(-1, getHeartbeart, setHeartbeat, 0), + new TestConfig(65536, getHeartbeart, setHeartbeat, 65535)) + .flatMap(config -> Stream.of(config, new TestConfig(config.value, getChannelMax, setChannelMax, config.expected))) .forEach(config -> { - if (config.expectException) { - assertThatThrownBy(() -> config.call.accept(config.value)).isInstanceOf(IllegalArgumentException.class); - } else { - config.call.accept(config.value); - } + config.setCall.accept(config.value); + assertThat(config.getCall.get()).isEqualTo(config.expected); }); } From 880308399aa107171bdddb17de97eb5551fd5d9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 3 Apr 2020 14:47:57 +0200 Subject: [PATCH 1235/2114] Bump optional dependencies Fixes #644 --- pom.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index a3d188dfe9..bf3107a86b 100644 --- a/pom.xml +++ b/pom.xml @@ -54,10 +54,10 @@ UTF-8 UTF-8 - 1.7.29 - 4.1.2 - 1.3.2 - 2.10.1 + 1.7.30 + 4.1.5 + 1.4.1 + 2.10.3 1.2.3 4.13 3.3.3 From 4bc22ce4ca2a700be332243630ec477c042d640b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 3 Apr 2020 14:50:00 +0200 Subject: [PATCH 1236/2114] Set version to 5.9.0-SNAPSHOT in POM --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index bf3107a86b..322d53e335 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.8.1-SNAPSHOT + 5.9.0-SNAPSHOT jar RabbitMQ Java Client From ea945d313a9f9084c70fafe39504b07c676e2ec1 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Fri, 3 Apr 2020 14:21:35 +0000 Subject: [PATCH 1237/2114] [maven-release-plugin] prepare release v5.9.0.RC1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 322d53e335..3096cf2127 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.9.0-SNAPSHOT + 5.9.0.RC1 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v5.9.0.RC1 From 963729f57fd21f9de7bf4bd309b0d6a525322e0a Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Fri, 3 Apr 2020 14:21:42 +0000 Subject: [PATCH 1238/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 3096cf2127..322d53e335 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.9.0.RC1 + 5.9.0-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v5.9.0.RC1 + HEAD From ea25ebf3f2acf55cc25a531d89c4b5741768ee2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 3 Apr 2020 16:26:22 +0200 Subject: [PATCH 1239/2114] Set release version to 5.9.0.RC2 --- release-versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-versions.txt b/release-versions.txt index 5682da02e8..1c6d8d6528 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,3 +1,3 @@ -RELEASE_VERSION="5.9.0.RC1" +RELEASE_VERSION="5.9.0.RC2" DEVELOPMENT_VERSION="5.9.0-SNAPSHOT" RELEASE_BRANCH="5.x.x-stable" From 08a8819b13d67e2a4e45ca0b81cab8e5bfb23fdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 14 Apr 2020 14:11:42 +0200 Subject: [PATCH 1240/2114] Set release version to 5.9.0 --- release-versions.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release-versions.txt b/release-versions.txt index 1c6d8d6528..7607b9254a 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,3 +1,3 @@ -RELEASE_VERSION="5.9.0.RC2" -DEVELOPMENT_VERSION="5.9.0-SNAPSHOT" +RELEASE_VERSION="5.9.0" +DEVELOPMENT_VERSION="5.10.0-SNAPSHOT" RELEASE_BRANCH="5.x.x-stable" From 86f9aceae30cb325225fa155c0cc6ddaa0ad6f39 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Tue, 14 Apr 2020 12:13:54 +0000 Subject: [PATCH 1241/2114] [maven-release-plugin] prepare release v5.9.0 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 322d53e335..12590442f4 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.9.0-SNAPSHOT + 5.9.0 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v5.9.0 From 668f1a2f38b6448929db31867ec4db8fde3fdbb0 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Tue, 14 Apr 2020 12:14:01 +0000 Subject: [PATCH 1242/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 12590442f4..57d0eca42f 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.9.0 + 5.10.0-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v5.9.0 + HEAD From 14ee07904b2117e7b1c0a97670546ef19ab72aa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 14 Apr 2020 14:37:10 +0200 Subject: [PATCH 1243/2114] Set release version to 5.10.0.RC1 --- release-versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-versions.txt b/release-versions.txt index 7607b9254a..643407832b 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,3 +1,3 @@ -RELEASE_VERSION="5.9.0" +RELEASE_VERSION="5.10.0.RC1" DEVELOPMENT_VERSION="5.10.0-SNAPSHOT" RELEASE_BRANCH="5.x.x-stable" From 2fef42653f56cea922d9de582c78ec30475db889 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 14 Apr 2020 14:52:58 +0200 Subject: [PATCH 1244/2114] Set version to 5.9.0 in readme --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index f87890ec30..a714be9ec6 100644 --- a/README.md +++ b/README.md @@ -23,14 +23,14 @@ They require Java 8 or higher. com.rabbitmq amqp-client - 5.8.0 + 5.9.0 ``` ### Gradle ``` groovy -compile 'com.rabbitmq:amqp-client:5.8.0' +compile 'com.rabbitmq:amqp-client:5.9.0' ``` #### 4.x Series @@ -42,14 +42,14 @@ They require Java 6 or higher. com.rabbitmq amqp-client - 4.11.3 + 4.12.0 ``` ### Gradle ``` groovy -compile 'com.rabbitmq:amqp-client:4.11.3' +compile 'com.rabbitmq:amqp-client:4.12.0' ``` From 99e1054e4a3d15234984ee5103de125d91e2e90c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 16 Apr 2020 16:19:05 +0200 Subject: [PATCH 1245/2114] Add TLS keys to properties-based configuration Fixes #646 --- pom.xml | 8 +- .../client/ConnectionFactoryConfigurator.java | 267 ++++++++++++++---- .../test/PropertyFileInitialisationTest.java | 229 +++++++++++---- .../tls/keystore.p12 | Bin 0 -> 2453 bytes .../tls/truststore.jks | Bin 0 -> 1218 bytes 5 files changed, 387 insertions(+), 117 deletions(-) create mode 100644 src/test/resources/property-file-initialisation/tls/keystore.p12 create mode 100644 src/test/resources/property-file-initialisation/tls/truststore.jks diff --git a/pom.xml b/pom.xml index 319a9f3ffd..335158c551 100644 --- a/pom.xml +++ b/pom.xml @@ -68,7 +68,7 @@ 3.2.0 2.5.3 2.3 - 3.0.2 + 3.1.0 3.0.1 2.0 2.4.8 @@ -783,6 +783,12 @@ org.apache.maven.plugins maven-resources-plugin ${maven.resources.plugin.version} + + + p12 + jks + + org.codehaus.gmaven diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java b/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java index 4470760d75..9cd9c7ee31 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java @@ -18,36 +18,35 @@ import com.rabbitmq.client.impl.AMQConnection; import com.rabbitmq.client.impl.nio.NioParams; -import java.io.BufferedReader; -import java.io.FileReader; +import javax.net.ssl.*; +import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; -import java.io.Reader; import java.net.URISyntaxException; -import java.security.KeyManagementException; -import java.security.NoSuchAlgorithmException; -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; +import java.security.*; +import java.security.cert.CertificateException; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; /** * Helper class to load {@link ConnectionFactory} settings from a property file. - * + *

* The authorised keys are the constants values in this class (e.g. USERNAME). * The property file/properties instance/map instance keys can have * a prefix, the default being rabbitmq.. - * + *

* Property files can be loaded from the file system (the default), * but also from the classpath, by using the classpath: prefix * in the location. - * + *

* Client properties can be set by using * the client.properties. prefix, e.g. client.properties.app.name. * Default client properties and custom client properties are merged. To remove * a default client property, set its key to an empty value. * - * @since 4.4.0 * @see ConnectionFactory#load(String, String) + * @since 5.1.0 */ public class ConnectionFactoryConfigurator { @@ -76,6 +75,33 @@ public class ConnectionFactoryConfigurator { public static final String NIO_NB_IO_THREADS = "nio.nb.io.threads"; public static final String NIO_WRITE_ENQUEUING_TIMEOUT_IN_MS = "nio.write.enqueuing.timeout.in.ms"; public static final String NIO_WRITE_QUEUE_CAPACITY = "nio.write.queue.capacity"; + public static final String SSL_ALGORITHM = "ssl.algorithm"; + public static final String SSL_ENABLED = "ssl.enabled"; + public static final String SSL_KEY_STORE = "ssl.key.store"; + public static final String SSL_KEY_STORE_PASSWORD = "ssl.key.store.password"; + public static final String SSL_KEY_STORE_TYPE = "ssl.key.store.type"; + public static final String SSL_KEY_STORE_ALGORITHM = "ssl.key.store.algorithm"; + public static final String SSL_TRUST_STORE = "ssl.trust.store"; + public static final String SSL_TRUST_STORE_PASSWORD = "ssl.trust.store.password"; + public static final String SSL_TRUST_STORE_TYPE = "ssl.trust.store.type"; + public static final String SSL_TRUST_STORE_ALGORITHM = "ssl.trust.store.algorithm"; + public static final String SSL_VALIDATE_SERVER_CERTIFICATE = "ssl.validate.server.certificate"; + public static final String SSL_VERIFY_HOSTNAME = "ssl.verify.hostname"; + + // aliases allow to be compatible with keys from Spring Boot and still be consistent with + // the initial naming of the keys + private static final Map> ALIASES = new ConcurrentHashMap>() {{ + put(SSL_KEY_STORE, Arrays.asList("ssl.key-store")); + put(SSL_KEY_STORE_PASSWORD, Arrays.asList("ssl.key-store-password")); + put(SSL_KEY_STORE_TYPE, Arrays.asList("ssl.key-store-type")); + put(SSL_KEY_STORE_ALGORITHM, Arrays.asList("ssl.key-store-algorithm")); + put(SSL_TRUST_STORE, Arrays.asList("ssl.trust-store")); + put(SSL_TRUST_STORE_PASSWORD, Arrays.asList("ssl.trust-store-password")); + put(SSL_TRUST_STORE_TYPE, Arrays.asList("ssl.trust-store-type")); + put(SSL_TRUST_STORE_ALGORITHM, Arrays.asList("ssl.trust-store-algorithm")); + put(SSL_VALIDATE_SERVER_CERTIFICATE, Arrays.asList("ssl.validate-server-certificate")); + put(SSL_VERIFY_HOSTNAME, Arrays.asList("ssl.verify-hostname")); + }}; @SuppressWarnings("unchecked") public static void load(ConnectionFactory cf, String propertyFileLocation, String prefix) throws IOException { @@ -83,32 +109,22 @@ public static void load(ConnectionFactory cf, String propertyFileLocation, Strin throw new IllegalArgumentException("Property file argument cannot be null or empty"); } Properties properties = new Properties(); - if (propertyFileLocation.startsWith("classpath:")) { - InputStream in = null; - try { - in = ConnectionFactoryConfigurator.class.getResourceAsStream( - propertyFileLocation.substring("classpath:".length()) - ); - properties.load(in); - } finally { - if (in != null) { - in.close(); - } - } - } else { - Reader reader = null; - try { - reader = new BufferedReader(new FileReader(propertyFileLocation)); - properties.load(reader); - } finally { - if (reader != null) { - reader.close(); - } - } + try (InputStream in = loadResource(propertyFileLocation)) { + properties.load(in); } load(cf, (Map) properties, prefix); } + private static InputStream loadResource(String location) throws FileNotFoundException { + if (location.startsWith("classpath:")) { + return ConnectionFactoryConfigurator.class.getResourceAsStream( + location.substring("classpath:".length()) + ); + } else { + return new FileInputStream(location); + } + } + public static void load(ConnectionFactory cf, Map properties, String prefix) { prefix = prefix == null ? "" : prefix; String uri = properties.get(prefix + "uri"); @@ -116,54 +132,54 @@ public static void load(ConnectionFactory cf, Map properties, St try { cf.setUri(uri); } catch (URISyntaxException e) { - throw new IllegalArgumentException("Error while setting AMQP URI: "+uri, e); + throw new IllegalArgumentException("Error while setting AMQP URI: " + uri, e); } catch (NoSuchAlgorithmException e) { - throw new IllegalArgumentException("Error while setting AMQP URI: "+uri, e); + throw new IllegalArgumentException("Error while setting AMQP URI: " + uri, e); } catch (KeyManagementException e) { - throw new IllegalArgumentException("Error while setting AMQP URI: "+uri, e); + throw new IllegalArgumentException("Error while setting AMQP URI: " + uri, e); } } - String username = properties.get(prefix + USERNAME); + String username = lookUp(USERNAME, properties, prefix); if (username != null) { cf.setUsername(username); } - String password = properties.get(prefix + PASSWORD); + String password = lookUp(PASSWORD, properties, prefix); if (password != null) { cf.setPassword(password); } - String vhost = properties.get(prefix + VIRTUAL_HOST); + String vhost = lookUp(VIRTUAL_HOST, properties, prefix); if (vhost != null) { cf.setVirtualHost(vhost); } - String host = properties.get(prefix + HOST); + String host = lookUp(HOST, properties, prefix); if (host != null) { cf.setHost(host); } - String port = properties.get(prefix + PORT); + String port = lookUp(PORT, properties, prefix); if (port != null) { cf.setPort(Integer.valueOf(port)); } - String requestedChannelMax = properties.get(prefix + CONNECTION_CHANNEL_MAX); + String requestedChannelMax = lookUp(CONNECTION_CHANNEL_MAX, properties, prefix); if (requestedChannelMax != null) { cf.setRequestedChannelMax(Integer.valueOf(requestedChannelMax)); } - String requestedFrameMax = properties.get(prefix + CONNECTION_FRAME_MAX); + String requestedFrameMax = lookUp(CONNECTION_FRAME_MAX, properties, prefix); if (requestedFrameMax != null) { cf.setRequestedFrameMax(Integer.valueOf(requestedFrameMax)); } - String requestedHeartbeat = properties.get(prefix + CONNECTION_HEARTBEAT); + String requestedHeartbeat = lookUp(CONNECTION_HEARTBEAT, properties, prefix); if (requestedHeartbeat != null) { cf.setRequestedHeartbeat(Integer.valueOf(requestedHeartbeat)); } - String connectionTimeout = properties.get(prefix + CONNECTION_TIMEOUT); + String connectionTimeout = lookUp(CONNECTION_TIMEOUT, properties, prefix); if (connectionTimeout != null) { cf.setConnectionTimeout(Integer.valueOf(connectionTimeout)); } - String handshakeTimeout = properties.get(prefix + HANDSHAKE_TIMEOUT); + String handshakeTimeout = lookUp(HANDSHAKE_TIMEOUT, properties, prefix); if (handshakeTimeout != null) { cf.setHandshakeTimeout(Integer.valueOf(handshakeTimeout)); } - String shutdownTimeout = properties.get(prefix + SHUTDOWN_TIMEOUT); + String shutdownTimeout = lookUp(SHUTDOWN_TIMEOUT, properties, prefix); if (shutdownTimeout != null) { cf.setShutdownTimeout(Integer.valueOf(shutdownTimeout)); } @@ -180,63 +196,175 @@ public static void load(ConnectionFactory cf, Map properties, St clientProperties.remove(clientPropertyKey); } else { clientProperties.put( - clientPropertyKey, - entry.getValue() + clientPropertyKey, + entry.getValue() ); } } } cf.setClientProperties(clientProperties); - String automaticRecovery = properties.get(prefix + CONNECTION_RECOVERY_ENABLED); + String automaticRecovery = lookUp(CONNECTION_RECOVERY_ENABLED, properties, prefix); if (automaticRecovery != null) { cf.setAutomaticRecoveryEnabled(Boolean.valueOf(automaticRecovery)); } - String topologyRecovery = properties.get(prefix + TOPOLOGY_RECOVERY_ENABLED); + String topologyRecovery = lookUp(TOPOLOGY_RECOVERY_ENABLED, properties, prefix); if (topologyRecovery != null) { cf.setTopologyRecoveryEnabled(Boolean.getBoolean(topologyRecovery)); } - String networkRecoveryInterval = properties.get(prefix + CONNECTION_RECOVERY_INTERVAL); + String networkRecoveryInterval = lookUp(CONNECTION_RECOVERY_INTERVAL, properties, prefix); if (networkRecoveryInterval != null) { cf.setNetworkRecoveryInterval(Long.valueOf(networkRecoveryInterval)); } - String channelRpcTimeout = properties.get(prefix + CHANNEL_RPC_TIMEOUT); + String channelRpcTimeout = lookUp(CHANNEL_RPC_TIMEOUT, properties, prefix); if (channelRpcTimeout != null) { cf.setChannelRpcTimeout(Integer.valueOf(channelRpcTimeout)); } - String channelShouldCheckRpcResponseType = properties.get(prefix + CHANNEL_SHOULD_CHECK_RPC_RESPONSE_TYPE); + String channelShouldCheckRpcResponseType = lookUp(CHANNEL_SHOULD_CHECK_RPC_RESPONSE_TYPE, properties, prefix); if (channelShouldCheckRpcResponseType != null) { cf.setChannelShouldCheckRpcResponseType(Boolean.valueOf(channelShouldCheckRpcResponseType)); } - String useNio = properties.get(prefix + USE_NIO); + String useNio = lookUp(USE_NIO, properties, prefix); if (useNio != null && Boolean.valueOf(useNio)) { cf.useNio(); NioParams nioParams = new NioParams(); - String readByteBufferSize = properties.get(prefix + NIO_READ_BYTE_BUFFER_SIZE); + String readByteBufferSize = lookUp(NIO_READ_BYTE_BUFFER_SIZE, properties, prefix); if (readByteBufferSize != null) { nioParams.setReadByteBufferSize(Integer.valueOf(readByteBufferSize)); } - String writeByteBufferSize = properties.get(prefix + NIO_WRITE_BYTE_BUFFER_SIZE); + String writeByteBufferSize = lookUp(NIO_WRITE_BYTE_BUFFER_SIZE, properties, prefix); if (writeByteBufferSize != null) { nioParams.setWriteByteBufferSize(Integer.valueOf(writeByteBufferSize)); } - String nbIoThreads = properties.get(prefix + NIO_NB_IO_THREADS); + String nbIoThreads = lookUp(NIO_NB_IO_THREADS, properties, prefix); if (nbIoThreads != null) { nioParams.setNbIoThreads(Integer.valueOf(nbIoThreads)); } - String writeEnqueuingTime = properties.get(prefix + NIO_WRITE_ENQUEUING_TIMEOUT_IN_MS); + String writeEnqueuingTime = lookUp(NIO_WRITE_ENQUEUING_TIMEOUT_IN_MS, properties, prefix); if (writeEnqueuingTime != null) { nioParams.setWriteEnqueuingTimeoutInMs(Integer.valueOf(writeEnqueuingTime)); } - String writeQueueCapacity = properties.get(prefix + NIO_WRITE_QUEUE_CAPACITY); + String writeQueueCapacity = lookUp(NIO_WRITE_QUEUE_CAPACITY, properties, prefix); if (writeQueueCapacity != null) { nioParams.setWriteQueueCapacity(Integer.valueOf(writeQueueCapacity)); } cf.setNioParams(nioParams); } + + String useSsl = lookUp(SSL_ENABLED, properties, prefix); + if (useSsl != null && Boolean.valueOf(useSsl)) { + setUpSsl(cf, properties, prefix); + } + } + + private static void setUpSsl(ConnectionFactory cf, Map properties, String prefix) { + String algorithm = lookUp(SSL_ALGORITHM, properties, prefix); + String keyStoreLocation = lookUp(SSL_KEY_STORE, properties, prefix); + String keyStorePassword = lookUp(SSL_KEY_STORE_PASSWORD, properties, prefix); + String keyStoreType = lookUp(SSL_KEY_STORE_TYPE, properties, prefix, "PKCS12"); + String keyStoreAlgorithm = lookUp(SSL_KEY_STORE_ALGORITHM, properties, prefix, "SunX509"); + String trustStoreLocation = lookUp(SSL_TRUST_STORE, properties, prefix); + String trustStorePassword = lookUp(SSL_TRUST_STORE_PASSWORD, properties, prefix); + String trustStoreType = lookUp(SSL_TRUST_STORE_TYPE, properties, prefix, "JKS"); + String trustStoreAlgorithm = lookUp(SSL_TRUST_STORE_ALGORITHM, properties, prefix, "SunX509"); + String validateServerCertificate = lookUp(SSL_VALIDATE_SERVER_CERTIFICATE, properties, prefix); + String verifyHostname = lookUp(SSL_VERIFY_HOSTNAME, properties, prefix); + + try { + algorithm = algorithm == null ? + ConnectionFactory.computeDefaultTlsProtocol(SSLContext.getDefault().getSupportedSSLParameters().getProtocols()) : algorithm; + boolean enableHostnameVerification = verifyHostname == null ? Boolean.FALSE : Boolean.valueOf(verifyHostname); + + if (keyStoreLocation == null && trustStoreLocation == null) { + setUpBasicSsl( + cf, + validateServerCertificate == null ? Boolean.FALSE : Boolean.valueOf(validateServerCertificate), + enableHostnameVerification, + algorithm + ); + } else { + KeyManager[] keyManagers = configureKeyManagers(keyStoreLocation, keyStorePassword, keyStoreType, keyStoreAlgorithm); + TrustManager[] trustManagers = configureTrustManagers(trustStoreLocation, trustStorePassword, trustStoreType, trustStoreAlgorithm); + + // create ssl context + SSLContext sslContext = SSLContext.getInstance(algorithm); + sslContext.init(keyManagers, trustManagers, null); + + cf.useSslProtocol(sslContext); + + if (enableHostnameVerification) { + cf.enableHostnameVerification(); + } + } + } catch (NoSuchAlgorithmException | IOException | CertificateException | + UnrecoverableKeyException | KeyStoreException | KeyManagementException e) { + throw new IllegalStateException("Error while configuring TLS", e); + } + } + + private static KeyManager[] configureKeyManagers(String keystore, String keystorePassword, String keystoreType, String keystoreAlgorithm) throws KeyStoreException, IOException, NoSuchAlgorithmException, + CertificateException, UnrecoverableKeyException { + char[] keyPassphrase = null; + if (keystorePassword != null) { + keyPassphrase = keystorePassword.toCharArray(); + } + KeyManager[] keyManagers = null; + if (keystore != null) { + KeyStore ks = KeyStore.getInstance(keystoreType); + try (InputStream in = loadResource(keystore)) { + ks.load(in, keyPassphrase); + } + KeyManagerFactory kmf = KeyManagerFactory.getInstance(keystoreAlgorithm); + kmf.init(ks, keyPassphrase); + keyManagers = kmf.getKeyManagers(); + } + return keyManagers; + } + + private static TrustManager[] configureTrustManagers(String truststore, String truststorePassword, String truststoreType, String truststoreAlgorithm) + throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException { + char[] trustPassphrase = null; + if (truststorePassword != null) { + trustPassphrase = truststorePassword.toCharArray(); + } + TrustManager[] trustManagers = null; + if (truststore != null) { + KeyStore tks = KeyStore.getInstance(truststoreType); + try (InputStream in = loadResource(truststore)) { + tks.load(in, trustPassphrase); + } + TrustManagerFactory tmf = TrustManagerFactory.getInstance(truststoreAlgorithm); + tmf.init(tks); + trustManagers = tmf.getTrustManagers(); + } + return trustManagers; + } + + private static void setUpBasicSsl(ConnectionFactory cf, boolean validateServerCertificate, boolean verifyHostname, String sslAlgorithm) throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException { + if (validateServerCertificate) { + useDefaultTrustStore(cf, sslAlgorithm, verifyHostname); + } else { + if (sslAlgorithm == null) { + cf.useSslProtocol(); + } else { + cf.useSslProtocol(sslAlgorithm); + } + } + } + + private static void useDefaultTrustStore(ConnectionFactory cf, String sslAlgorithm, boolean verifyHostname) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException { + SSLContext sslContext = SSLContext.getInstance(sslAlgorithm); + TrustManagerFactory trustManagerFactory = + TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + trustManagerFactory.init((KeyStore) null); + sslContext.init(null, trustManagerFactory.getTrustManagers(), null); + cf.useSslProtocol(sslContext); + if (verifyHostname) { + cf.enableHostnameVerification(); + } } public static void load(ConnectionFactory connectionFactory, String propertyFileLocation) throws IOException { @@ -256,4 +384,21 @@ public static void load(ConnectionFactory connectionFactory, Properties properti public static void load(ConnectionFactory connectionFactory, Map properties) { load(connectionFactory, properties, DEFAULT_PREFIX); } + + public static String lookUp(String key, Map properties, String prefix) { + return lookUp(key, properties, prefix, null); + } + + public static String lookUp(String key, Map properties, String prefix, String defaultValue) { + String value = properties.get(prefix + key); + if (value == null) { + value = ALIASES.getOrDefault(key, Collections.emptyList()).stream() + .map(alias -> properties.get(prefix + alias)) + .filter(v -> v != null) + .findFirst().orElse(defaultValue); + } + return value; + } + + } diff --git a/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java b/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java index 0c5df5823f..2a140721a5 100644 --- a/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java +++ b/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java @@ -18,66 +18,64 @@ import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.ConnectionFactoryConfigurator; import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; +import javax.net.ssl.SSLContext; import java.io.FileReader; import java.io.IOException; import java.io.Reader; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; +import java.util.*; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Stream; import static com.rabbitmq.client.impl.AMQConnection.defaultClientProperties; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; /** * */ -@RunWith(Parameterized.class) public class PropertyFileInitialisationTest { - @Parameterized.Parameters - public static Object[] data() { - return new Object[] { - "./src/test/resources/property-file-initialisation/configuration.properties", - "classpath:/property-file-initialisation/configuration.properties" - }; - } - - @Parameterized.Parameter - public String propertyFileLocation; - ConnectionFactory cf = new ConnectionFactory(); - @Test public void propertyInitialisationFromFile() throws IOException { - cf.load(propertyFileLocation); - checkConnectionFactory(); + @Test + public void propertyInitialisationFromFile() throws IOException { + for (String propertyFileLocation : Arrays.asList( + "./src/test/resources/property-file-initialisation/configuration.properties", + "classpath:/property-file-initialisation/configuration.properties")) { + ConnectionFactory connectionFactory = new ConnectionFactory(); + connectionFactory.load(propertyFileLocation); + checkConnectionFactory(connectionFactory); + } } - @Test public void propertyInitialisationCustomPrefix() throws Exception { + @Test + public void propertyInitialisationCustomPrefix() throws Exception { Properties propertiesCustomPrefix = getPropertiesWitPrefix("prefix."); cf.load(propertiesCustomPrefix, "prefix."); checkConnectionFactory(); } - @Test public void propertyInitialisationNoPrefix() throws Exception { + @Test + public void propertyInitialisationNoPrefix() throws Exception { Properties propertiesCustomPrefix = getPropertiesWitPrefix(""); cf.load(propertiesCustomPrefix, ""); checkConnectionFactory(); } - @Test public void propertyInitialisationNullPrefix() throws Exception { + @Test + public void propertyInitialisationNullPrefix() throws Exception { Properties propertiesCustomPrefix = getPropertiesWitPrefix(""); cf.load(propertiesCustomPrefix, null); checkConnectionFactory(); } - @Test public void propertyInitialisationUri() { + @Test + public void propertyInitialisationUri() { cf.load(Collections.singletonMap("rabbitmq.uri", "amqp://foo:bar@127.0.0.1:5673/dummy")); assertThat(cf.getUsername()).isEqualTo("foo"); @@ -87,12 +85,14 @@ public static Object[] data() { assertThat(cf.getPort()).isEqualTo(5673); } - @Test public void propertyInitialisationIncludeDefaultClientPropertiesByDefault() { + @Test + public void propertyInitialisationIncludeDefaultClientPropertiesByDefault() { cf.load(new HashMap<>()); assertThat(cf.getClientProperties().entrySet()).hasSize(defaultClientProperties().size()); } - @Test public void propertyInitialisationAddCustomClientProperty() { + @Test + public void propertyInitialisationAddCustomClientProperty() { cf.load(new HashMap() {{ put("rabbitmq.client.properties.foo", "bar"); }}); @@ -100,7 +100,8 @@ public static Object[] data() { assertThat(cf.getClientProperties()).extracting("foo").isEqualTo("bar"); } - @Test public void propertyInitialisationGetRidOfDefaultClientPropertyWithEmptyValue() { + @Test + public void propertyInitialisationGetRidOfDefaultClientPropertyWithEmptyValue() { final String key = defaultClientProperties().entrySet().iterator().next().getKey(); cf.load(new HashMap() {{ put("rabbitmq.client.properties." + key, ""); @@ -108,7 +109,8 @@ public static Object[] data() { assertThat(cf.getClientProperties().entrySet()).hasSize(defaultClientProperties().size() - 1); } - @Test public void propertyInitialisationOverrideDefaultClientProperty() { + @Test + public void propertyInitialisationOverrideDefaultClientProperty() { final String key = defaultClientProperties().entrySet().iterator().next().getKey(); cf.load(new HashMap() {{ put("rabbitmq.client.properties." + key, "whatever"); @@ -117,7 +119,8 @@ public static Object[] data() { assertThat(cf.getClientProperties()).extracting(key).isEqualTo("whatever"); } - @Test public void propertyInitialisationDoNotUseNio() throws Exception { + @Test + public void propertyInitialisationDoNotUseNio() throws Exception { cf.load(new HashMap() {{ put("rabbitmq.use.nio", "false"); put("rabbitmq.nio.nb.io.threads", "2"); @@ -125,34 +128,150 @@ public static Object[] data() { assertThat(cf.getNioParams().getNbIoThreads()).isNotEqualTo(2); } + @Test + public void lookUp() { + assertThat(ConnectionFactoryConfigurator.lookUp( + ConnectionFactoryConfigurator.SSL_KEY_STORE, + Collections.singletonMap(ConnectionFactoryConfigurator.SSL_KEY_STORE, "some file"), + "" + )).as("exact key should be looked up").isEqualTo("some file"); + + assertThat(ConnectionFactoryConfigurator.lookUp( + ConnectionFactoryConfigurator.SSL_KEY_STORE, + Collections.emptyMap(), + "" + )).as("lookup should return null when no match").isNull(); + + assertThat(ConnectionFactoryConfigurator.lookUp( + ConnectionFactoryConfigurator.SSL_KEY_STORE, + Collections.singletonMap("ssl.key-store", "some file"), // key alias + "" + )).as("alias key should be used when initial is missing").isEqualTo("some file"); + + assertThat(ConnectionFactoryConfigurator.lookUp( + ConnectionFactoryConfigurator.SSL_TRUST_STORE_TYPE, + Collections.emptyMap(), + "", + "JKS" + )).as("default value should be returned when key is not found").isEqualTo("JKS"); + } + + @Test + public void tlsInitialisationWithKeyManagerAndTrustManagerShouldSucceed() { + Stream.of("./src/test/resources/property-file-initialisation/tls/", + "classpath:/property-file-initialisation/tls/").forEach(baseDirectory -> { + Map configuration = new HashMap<>(); + configuration.put(ConnectionFactoryConfigurator.SSL_ENABLED, "true"); + configuration.put(ConnectionFactoryConfigurator.SSL_KEY_STORE, baseDirectory + "keystore.p12"); + configuration.put(ConnectionFactoryConfigurator.SSL_KEY_STORE_PASSWORD, "bunnies"); + configuration.put(ConnectionFactoryConfigurator.SSL_KEY_STORE_TYPE, "PKCS12"); + configuration.put(ConnectionFactoryConfigurator.SSL_KEY_STORE_ALGORITHM, "SunX509"); + + configuration.put(ConnectionFactoryConfigurator.SSL_TRUST_STORE, baseDirectory + "truststore.jks"); + configuration.put(ConnectionFactoryConfigurator.SSL_TRUST_STORE_PASSWORD, "bunnies"); + configuration.put(ConnectionFactoryConfigurator.SSL_TRUST_STORE_TYPE, "JKS"); + configuration.put(ConnectionFactoryConfigurator.SSL_TRUST_STORE_ALGORITHM, "SunX509"); + + configuration.put(ConnectionFactoryConfigurator.SSL_VERIFY_HOSTNAME, "true"); + + ConnectionFactory connectionFactory = mock(ConnectionFactory.class); + ConnectionFactoryConfigurator.load(connectionFactory, configuration, ""); + + verify(connectionFactory, times(1)).useSslProtocol(any(SSLContext.class)); + verify(connectionFactory, times(1)).enableHostnameVerification(); + }); + } + + @Test + public void tlsNotEnabledIfNotConfigured() { + ConnectionFactory connectionFactory = mock(ConnectionFactory.class); + ConnectionFactoryConfigurator.load(connectionFactory, Collections.emptyMap(), ""); + verify(connectionFactory, never()).useSslProtocol(any(SSLContext.class)); + } + + @Test + public void tlsNotEnabledIfDisabled() { + ConnectionFactory connectionFactory = mock(ConnectionFactory.class); + ConnectionFactoryConfigurator.load( + connectionFactory, + Collections.singletonMap(ConnectionFactoryConfigurator.SSL_ENABLED, "false"), + "" + ); + verify(connectionFactory, never()).useSslProtocol(any(SSLContext.class)); + } + + @Test + public void tlsSslContextSetIfTlsEnabled() { + AtomicBoolean sslProtocolSet = new AtomicBoolean(false); + ConnectionFactory connectionFactory = new ConnectionFactory() { + @Override + public void useSslProtocol(SSLContext context) { + sslProtocolSet.set(true); + super.useSslProtocol(context); + } + }; + ConnectionFactoryConfigurator.load( + connectionFactory, + Collections.singletonMap(ConnectionFactoryConfigurator.SSL_ENABLED, "true"), + "" + ); + assertThat(sslProtocolSet).isTrue(); + } + + @Test + public void tlsBasicSetupShouldTrustEveryoneWhenServerValidationIsNotEnabled() throws Exception { + String algorithm = ConnectionFactory.computeDefaultTlsProtocol(SSLContext.getDefault().getSupportedSSLParameters().getProtocols()); + Map configuration = new HashMap<>(); + configuration.put(ConnectionFactoryConfigurator.SSL_ENABLED, "true"); + configuration.put(ConnectionFactoryConfigurator.SSL_VALIDATE_SERVER_CERTIFICATE, "false"); + ConnectionFactory connectionFactory = mock(ConnectionFactory.class); + ConnectionFactoryConfigurator.load(connectionFactory, configuration, ""); + verify(connectionFactory, times(1)).useSslProtocol(algorithm); + } + + @Test + public void tlsBasicSetupShouldSetDefaultTrustManagerWhenServerValidationIsEnabled() throws Exception { + Map configuration = new HashMap<>(); + configuration.put(ConnectionFactoryConfigurator.SSL_ENABLED, "true"); + configuration.put(ConnectionFactoryConfigurator.SSL_VALIDATE_SERVER_CERTIFICATE, "true"); + ConnectionFactory connectionFactory = mock(ConnectionFactory.class); + ConnectionFactoryConfigurator.load(connectionFactory, configuration, ""); + verify(connectionFactory, never()).useSslProtocol(anyString()); + verify(connectionFactory, times(1)).useSslProtocol(any(SSLContext.class)); + } + private void checkConnectionFactory() { - assertThat(cf.getUsername()).isEqualTo("foo"); - assertThat(cf.getPassword()).isEqualTo("bar"); - assertThat(cf.getVirtualHost()).isEqualTo("dummy"); - assertThat(cf.getHost()).isEqualTo("127.0.0.1"); - assertThat(cf.getPort()).isEqualTo(5673); + checkConnectionFactory(this.cf); + } - assertThat(cf.getRequestedChannelMax()).isEqualTo(1); - assertThat(cf.getRequestedFrameMax()).isEqualTo(2); - assertThat(cf.getRequestedHeartbeat()).isEqualTo(10); - assertThat(cf.getConnectionTimeout()).isEqualTo(10000); - assertThat(cf.getHandshakeTimeout()).isEqualTo(5000); + private void checkConnectionFactory(ConnectionFactory connectionFactory) { + assertThat(connectionFactory.getUsername()).isEqualTo("foo"); + assertThat(connectionFactory.getPassword()).isEqualTo("bar"); + assertThat(connectionFactory.getVirtualHost()).isEqualTo("dummy"); + assertThat(connectionFactory.getHost()).isEqualTo("127.0.0.1"); + assertThat(connectionFactory.getPort()).isEqualTo(5673); - assertThat(cf.getClientProperties().entrySet()).hasSize(defaultClientProperties().size() + 1); - assertThat(cf.getClientProperties()).extracting("foo").isEqualTo("bar"); + assertThat(connectionFactory.getRequestedChannelMax()).isEqualTo(1); + assertThat(connectionFactory.getRequestedFrameMax()).isEqualTo(2); + assertThat(connectionFactory.getRequestedHeartbeat()).isEqualTo(10); + assertThat(connectionFactory.getConnectionTimeout()).isEqualTo(10000); + assertThat(connectionFactory.getHandshakeTimeout()).isEqualTo(5000); + + assertThat(connectionFactory.getClientProperties().entrySet()).hasSize(defaultClientProperties().size() + 1); + assertThat(connectionFactory.getClientProperties()).extracting("foo").isEqualTo("bar"); - assertThat(cf.isAutomaticRecoveryEnabled()).isFalse(); - assertThat(cf.isTopologyRecoveryEnabled()).isFalse(); - assertThat(cf.getNetworkRecoveryInterval()).isEqualTo(10000l); - assertThat(cf.getChannelRpcTimeout()).isEqualTo(10000); - assertThat(cf.isChannelShouldCheckRpcResponseType()).isTrue(); + assertThat(connectionFactory.isAutomaticRecoveryEnabled()).isFalse(); + assertThat(connectionFactory.isTopologyRecoveryEnabled()).isFalse(); + assertThat(connectionFactory.getNetworkRecoveryInterval()).isEqualTo(10000l); + assertThat(connectionFactory.getChannelRpcTimeout()).isEqualTo(10000); + assertThat(connectionFactory.isChannelShouldCheckRpcResponseType()).isTrue(); - assertThat(cf.getNioParams()).isNotNull(); - assertThat(cf.getNioParams().getReadByteBufferSize()).isEqualTo(32000); - assertThat(cf.getNioParams().getWriteByteBufferSize()).isEqualTo(32000); - assertThat(cf.getNioParams().getNbIoThreads()).isEqualTo(2); - assertThat(cf.getNioParams().getWriteEnqueuingTimeoutInMs()).isEqualTo(5000); - assertThat(cf.getNioParams().getWriteQueueCapacity()).isEqualTo(1000); + assertThat(connectionFactory.getNioParams()).isNotNull(); + assertThat(connectionFactory.getNioParams().getReadByteBufferSize()).isEqualTo(32000); + assertThat(connectionFactory.getNioParams().getWriteByteBufferSize()).isEqualTo(32000); + assertThat(connectionFactory.getNioParams().getNbIoThreads()).isEqualTo(2); + assertThat(connectionFactory.getNioParams().getWriteEnqueuingTimeoutInMs()).isEqualTo(5000); + assertThat(connectionFactory.getNioParams().getWriteQueueCapacity()).isEqualTo(1000); } private Properties getPropertiesWitPrefix(String prefix) throws IOException { @@ -168,8 +287,8 @@ private Properties getPropertiesWitPrefix(String prefix) throws IOException { Properties propertiesCustomPrefix = new Properties(); for (Map.Entry entry : properties.entrySet()) { propertiesCustomPrefix.put( - prefix + entry.getKey().toString().substring(ConnectionFactoryConfigurator.DEFAULT_PREFIX.length()), - entry.getValue() + prefix + entry.getKey().toString().substring(ConnectionFactoryConfigurator.DEFAULT_PREFIX.length()), + entry.getValue() ); } return propertiesCustomPrefix; diff --git a/src/test/resources/property-file-initialisation/tls/keystore.p12 b/src/test/resources/property-file-initialisation/tls/keystore.p12 new file mode 100644 index 0000000000000000000000000000000000000000..a5280a6cbfc9397e6a2ad7146b3859e685bc4434 GIT binary patch literal 2453 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 literal 0 HcmV?d00001 From 5c3fce8d224c434c3f3858840123b03d28a1d9cd Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 22 Apr 2020 20:19:10 +0300 Subject: [PATCH 1246/2114] AutorecoveringConnection.maybeDeleteRecordedAutoDeleteExchange does not need to acquire a lock on this.consumers It most likely was a copy-paste artefact introduced back in 2013-2014. AutorecoveringConnection.maybeDeleteRecordedAutoDeleteQueue does need to lock this.consumers as conditional queue deletion does need to check the number of known consumers on that queue. 1aad565 addressed a potential deadlock caused by the unsafe order of lock acquisitions. In #648 another similar issue was discovered which #649 tried to address by acquiring a lock on this.consumers early. However, exchange cleanup does not need to lock this.consumers as it does not mutate it. Closes #648. --- .../impl/recovery/AutorecoveringConnection.java | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index f04e3778d5..785d98e5f4 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -1032,15 +1032,13 @@ void maybeDeleteRecordedAutoDeleteQueue(String queue) { } void maybeDeleteRecordedAutoDeleteExchange(String exchange) { - synchronized (this.consumers) { - synchronized (this.recordedExchanges) { - if(!hasMoreDestinationsBoundToExchange(Utility.copy(this.recordedBindings), exchange)) { - RecordedExchange x = this.recordedExchanges.get(exchange); - // last binding where this exchange is the source is gone, remove recorded exchange - // if it is auto-deleted. See bug 26364. - if(x != null && x.isAutoDelete()) { - deleteRecordedExchange(exchange); - } + synchronized (this.recordedExchanges) { + if(!hasMoreDestinationsBoundToExchange(Utility.copy(this.recordedBindings), exchange)) { + RecordedExchange x = this.recordedExchanges.get(exchange); + // last binding where this exchange is the source is gone, remove recorded exchange + // if it is auto-deleted. See bug 26364. + if(x != null && x.isAutoDelete()) { + deleteRecordedExchange(exchange); } } } From 051c30d5d75ec3c81b69883dcdfceea236c1178c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 16 Apr 2020 16:19:05 +0200 Subject: [PATCH 1247/2114] Add TLS keys to properties-based configuration Fixes #646 (cherry picked from commit 99e1054e4a3d15234984ee5103de125d91e2e90c) --- pom.xml | 8 +- .../client/ConnectionFactoryConfigurator.java | 267 ++++++++++++++---- .../test/PropertyFileInitialisationTest.java | 229 +++++++++++---- .../tls/keystore.p12 | Bin 0 -> 2453 bytes .../tls/truststore.jks | Bin 0 -> 1218 bytes 5 files changed, 387 insertions(+), 117 deletions(-) create mode 100644 src/test/resources/property-file-initialisation/tls/keystore.p12 create mode 100644 src/test/resources/property-file-initialisation/tls/truststore.jks diff --git a/pom.xml b/pom.xml index 57d0eca42f..f9f31bc6a5 100644 --- a/pom.xml +++ b/pom.xml @@ -68,7 +68,7 @@ 3.2.0 2.5.3 2.3 - 3.0.2 + 3.1.0 3.0.1 2.0 2.4.8 @@ -783,6 +783,12 @@ org.apache.maven.plugins maven-resources-plugin ${maven.resources.plugin.version} + + + p12 + jks + + org.codehaus.gmaven diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java b/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java index 4470760d75..9cd9c7ee31 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java @@ -18,36 +18,35 @@ import com.rabbitmq.client.impl.AMQConnection; import com.rabbitmq.client.impl.nio.NioParams; -import java.io.BufferedReader; -import java.io.FileReader; +import javax.net.ssl.*; +import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; -import java.io.Reader; import java.net.URISyntaxException; -import java.security.KeyManagementException; -import java.security.NoSuchAlgorithmException; -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; +import java.security.*; +import java.security.cert.CertificateException; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; /** * Helper class to load {@link ConnectionFactory} settings from a property file. - * + *

* The authorised keys are the constants values in this class (e.g. USERNAME). * The property file/properties instance/map instance keys can have * a prefix, the default being rabbitmq.. - * + *

* Property files can be loaded from the file system (the default), * but also from the classpath, by using the classpath: prefix * in the location. - * + *

* Client properties can be set by using * the client.properties. prefix, e.g. client.properties.app.name. * Default client properties and custom client properties are merged. To remove * a default client property, set its key to an empty value. * - * @since 4.4.0 * @see ConnectionFactory#load(String, String) + * @since 5.1.0 */ public class ConnectionFactoryConfigurator { @@ -76,6 +75,33 @@ public class ConnectionFactoryConfigurator { public static final String NIO_NB_IO_THREADS = "nio.nb.io.threads"; public static final String NIO_WRITE_ENQUEUING_TIMEOUT_IN_MS = "nio.write.enqueuing.timeout.in.ms"; public static final String NIO_WRITE_QUEUE_CAPACITY = "nio.write.queue.capacity"; + public static final String SSL_ALGORITHM = "ssl.algorithm"; + public static final String SSL_ENABLED = "ssl.enabled"; + public static final String SSL_KEY_STORE = "ssl.key.store"; + public static final String SSL_KEY_STORE_PASSWORD = "ssl.key.store.password"; + public static final String SSL_KEY_STORE_TYPE = "ssl.key.store.type"; + public static final String SSL_KEY_STORE_ALGORITHM = "ssl.key.store.algorithm"; + public static final String SSL_TRUST_STORE = "ssl.trust.store"; + public static final String SSL_TRUST_STORE_PASSWORD = "ssl.trust.store.password"; + public static final String SSL_TRUST_STORE_TYPE = "ssl.trust.store.type"; + public static final String SSL_TRUST_STORE_ALGORITHM = "ssl.trust.store.algorithm"; + public static final String SSL_VALIDATE_SERVER_CERTIFICATE = "ssl.validate.server.certificate"; + public static final String SSL_VERIFY_HOSTNAME = "ssl.verify.hostname"; + + // aliases allow to be compatible with keys from Spring Boot and still be consistent with + // the initial naming of the keys + private static final Map> ALIASES = new ConcurrentHashMap>() {{ + put(SSL_KEY_STORE, Arrays.asList("ssl.key-store")); + put(SSL_KEY_STORE_PASSWORD, Arrays.asList("ssl.key-store-password")); + put(SSL_KEY_STORE_TYPE, Arrays.asList("ssl.key-store-type")); + put(SSL_KEY_STORE_ALGORITHM, Arrays.asList("ssl.key-store-algorithm")); + put(SSL_TRUST_STORE, Arrays.asList("ssl.trust-store")); + put(SSL_TRUST_STORE_PASSWORD, Arrays.asList("ssl.trust-store-password")); + put(SSL_TRUST_STORE_TYPE, Arrays.asList("ssl.trust-store-type")); + put(SSL_TRUST_STORE_ALGORITHM, Arrays.asList("ssl.trust-store-algorithm")); + put(SSL_VALIDATE_SERVER_CERTIFICATE, Arrays.asList("ssl.validate-server-certificate")); + put(SSL_VERIFY_HOSTNAME, Arrays.asList("ssl.verify-hostname")); + }}; @SuppressWarnings("unchecked") public static void load(ConnectionFactory cf, String propertyFileLocation, String prefix) throws IOException { @@ -83,32 +109,22 @@ public static void load(ConnectionFactory cf, String propertyFileLocation, Strin throw new IllegalArgumentException("Property file argument cannot be null or empty"); } Properties properties = new Properties(); - if (propertyFileLocation.startsWith("classpath:")) { - InputStream in = null; - try { - in = ConnectionFactoryConfigurator.class.getResourceAsStream( - propertyFileLocation.substring("classpath:".length()) - ); - properties.load(in); - } finally { - if (in != null) { - in.close(); - } - } - } else { - Reader reader = null; - try { - reader = new BufferedReader(new FileReader(propertyFileLocation)); - properties.load(reader); - } finally { - if (reader != null) { - reader.close(); - } - } + try (InputStream in = loadResource(propertyFileLocation)) { + properties.load(in); } load(cf, (Map) properties, prefix); } + private static InputStream loadResource(String location) throws FileNotFoundException { + if (location.startsWith("classpath:")) { + return ConnectionFactoryConfigurator.class.getResourceAsStream( + location.substring("classpath:".length()) + ); + } else { + return new FileInputStream(location); + } + } + public static void load(ConnectionFactory cf, Map properties, String prefix) { prefix = prefix == null ? "" : prefix; String uri = properties.get(prefix + "uri"); @@ -116,54 +132,54 @@ public static void load(ConnectionFactory cf, Map properties, St try { cf.setUri(uri); } catch (URISyntaxException e) { - throw new IllegalArgumentException("Error while setting AMQP URI: "+uri, e); + throw new IllegalArgumentException("Error while setting AMQP URI: " + uri, e); } catch (NoSuchAlgorithmException e) { - throw new IllegalArgumentException("Error while setting AMQP URI: "+uri, e); + throw new IllegalArgumentException("Error while setting AMQP URI: " + uri, e); } catch (KeyManagementException e) { - throw new IllegalArgumentException("Error while setting AMQP URI: "+uri, e); + throw new IllegalArgumentException("Error while setting AMQP URI: " + uri, e); } } - String username = properties.get(prefix + USERNAME); + String username = lookUp(USERNAME, properties, prefix); if (username != null) { cf.setUsername(username); } - String password = properties.get(prefix + PASSWORD); + String password = lookUp(PASSWORD, properties, prefix); if (password != null) { cf.setPassword(password); } - String vhost = properties.get(prefix + VIRTUAL_HOST); + String vhost = lookUp(VIRTUAL_HOST, properties, prefix); if (vhost != null) { cf.setVirtualHost(vhost); } - String host = properties.get(prefix + HOST); + String host = lookUp(HOST, properties, prefix); if (host != null) { cf.setHost(host); } - String port = properties.get(prefix + PORT); + String port = lookUp(PORT, properties, prefix); if (port != null) { cf.setPort(Integer.valueOf(port)); } - String requestedChannelMax = properties.get(prefix + CONNECTION_CHANNEL_MAX); + String requestedChannelMax = lookUp(CONNECTION_CHANNEL_MAX, properties, prefix); if (requestedChannelMax != null) { cf.setRequestedChannelMax(Integer.valueOf(requestedChannelMax)); } - String requestedFrameMax = properties.get(prefix + CONNECTION_FRAME_MAX); + String requestedFrameMax = lookUp(CONNECTION_FRAME_MAX, properties, prefix); if (requestedFrameMax != null) { cf.setRequestedFrameMax(Integer.valueOf(requestedFrameMax)); } - String requestedHeartbeat = properties.get(prefix + CONNECTION_HEARTBEAT); + String requestedHeartbeat = lookUp(CONNECTION_HEARTBEAT, properties, prefix); if (requestedHeartbeat != null) { cf.setRequestedHeartbeat(Integer.valueOf(requestedHeartbeat)); } - String connectionTimeout = properties.get(prefix + CONNECTION_TIMEOUT); + String connectionTimeout = lookUp(CONNECTION_TIMEOUT, properties, prefix); if (connectionTimeout != null) { cf.setConnectionTimeout(Integer.valueOf(connectionTimeout)); } - String handshakeTimeout = properties.get(prefix + HANDSHAKE_TIMEOUT); + String handshakeTimeout = lookUp(HANDSHAKE_TIMEOUT, properties, prefix); if (handshakeTimeout != null) { cf.setHandshakeTimeout(Integer.valueOf(handshakeTimeout)); } - String shutdownTimeout = properties.get(prefix + SHUTDOWN_TIMEOUT); + String shutdownTimeout = lookUp(SHUTDOWN_TIMEOUT, properties, prefix); if (shutdownTimeout != null) { cf.setShutdownTimeout(Integer.valueOf(shutdownTimeout)); } @@ -180,63 +196,175 @@ public static void load(ConnectionFactory cf, Map properties, St clientProperties.remove(clientPropertyKey); } else { clientProperties.put( - clientPropertyKey, - entry.getValue() + clientPropertyKey, + entry.getValue() ); } } } cf.setClientProperties(clientProperties); - String automaticRecovery = properties.get(prefix + CONNECTION_RECOVERY_ENABLED); + String automaticRecovery = lookUp(CONNECTION_RECOVERY_ENABLED, properties, prefix); if (automaticRecovery != null) { cf.setAutomaticRecoveryEnabled(Boolean.valueOf(automaticRecovery)); } - String topologyRecovery = properties.get(prefix + TOPOLOGY_RECOVERY_ENABLED); + String topologyRecovery = lookUp(TOPOLOGY_RECOVERY_ENABLED, properties, prefix); if (topologyRecovery != null) { cf.setTopologyRecoveryEnabled(Boolean.getBoolean(topologyRecovery)); } - String networkRecoveryInterval = properties.get(prefix + CONNECTION_RECOVERY_INTERVAL); + String networkRecoveryInterval = lookUp(CONNECTION_RECOVERY_INTERVAL, properties, prefix); if (networkRecoveryInterval != null) { cf.setNetworkRecoveryInterval(Long.valueOf(networkRecoveryInterval)); } - String channelRpcTimeout = properties.get(prefix + CHANNEL_RPC_TIMEOUT); + String channelRpcTimeout = lookUp(CHANNEL_RPC_TIMEOUT, properties, prefix); if (channelRpcTimeout != null) { cf.setChannelRpcTimeout(Integer.valueOf(channelRpcTimeout)); } - String channelShouldCheckRpcResponseType = properties.get(prefix + CHANNEL_SHOULD_CHECK_RPC_RESPONSE_TYPE); + String channelShouldCheckRpcResponseType = lookUp(CHANNEL_SHOULD_CHECK_RPC_RESPONSE_TYPE, properties, prefix); if (channelShouldCheckRpcResponseType != null) { cf.setChannelShouldCheckRpcResponseType(Boolean.valueOf(channelShouldCheckRpcResponseType)); } - String useNio = properties.get(prefix + USE_NIO); + String useNio = lookUp(USE_NIO, properties, prefix); if (useNio != null && Boolean.valueOf(useNio)) { cf.useNio(); NioParams nioParams = new NioParams(); - String readByteBufferSize = properties.get(prefix + NIO_READ_BYTE_BUFFER_SIZE); + String readByteBufferSize = lookUp(NIO_READ_BYTE_BUFFER_SIZE, properties, prefix); if (readByteBufferSize != null) { nioParams.setReadByteBufferSize(Integer.valueOf(readByteBufferSize)); } - String writeByteBufferSize = properties.get(prefix + NIO_WRITE_BYTE_BUFFER_SIZE); + String writeByteBufferSize = lookUp(NIO_WRITE_BYTE_BUFFER_SIZE, properties, prefix); if (writeByteBufferSize != null) { nioParams.setWriteByteBufferSize(Integer.valueOf(writeByteBufferSize)); } - String nbIoThreads = properties.get(prefix + NIO_NB_IO_THREADS); + String nbIoThreads = lookUp(NIO_NB_IO_THREADS, properties, prefix); if (nbIoThreads != null) { nioParams.setNbIoThreads(Integer.valueOf(nbIoThreads)); } - String writeEnqueuingTime = properties.get(prefix + NIO_WRITE_ENQUEUING_TIMEOUT_IN_MS); + String writeEnqueuingTime = lookUp(NIO_WRITE_ENQUEUING_TIMEOUT_IN_MS, properties, prefix); if (writeEnqueuingTime != null) { nioParams.setWriteEnqueuingTimeoutInMs(Integer.valueOf(writeEnqueuingTime)); } - String writeQueueCapacity = properties.get(prefix + NIO_WRITE_QUEUE_CAPACITY); + String writeQueueCapacity = lookUp(NIO_WRITE_QUEUE_CAPACITY, properties, prefix); if (writeQueueCapacity != null) { nioParams.setWriteQueueCapacity(Integer.valueOf(writeQueueCapacity)); } cf.setNioParams(nioParams); } + + String useSsl = lookUp(SSL_ENABLED, properties, prefix); + if (useSsl != null && Boolean.valueOf(useSsl)) { + setUpSsl(cf, properties, prefix); + } + } + + private static void setUpSsl(ConnectionFactory cf, Map properties, String prefix) { + String algorithm = lookUp(SSL_ALGORITHM, properties, prefix); + String keyStoreLocation = lookUp(SSL_KEY_STORE, properties, prefix); + String keyStorePassword = lookUp(SSL_KEY_STORE_PASSWORD, properties, prefix); + String keyStoreType = lookUp(SSL_KEY_STORE_TYPE, properties, prefix, "PKCS12"); + String keyStoreAlgorithm = lookUp(SSL_KEY_STORE_ALGORITHM, properties, prefix, "SunX509"); + String trustStoreLocation = lookUp(SSL_TRUST_STORE, properties, prefix); + String trustStorePassword = lookUp(SSL_TRUST_STORE_PASSWORD, properties, prefix); + String trustStoreType = lookUp(SSL_TRUST_STORE_TYPE, properties, prefix, "JKS"); + String trustStoreAlgorithm = lookUp(SSL_TRUST_STORE_ALGORITHM, properties, prefix, "SunX509"); + String validateServerCertificate = lookUp(SSL_VALIDATE_SERVER_CERTIFICATE, properties, prefix); + String verifyHostname = lookUp(SSL_VERIFY_HOSTNAME, properties, prefix); + + try { + algorithm = algorithm == null ? + ConnectionFactory.computeDefaultTlsProtocol(SSLContext.getDefault().getSupportedSSLParameters().getProtocols()) : algorithm; + boolean enableHostnameVerification = verifyHostname == null ? Boolean.FALSE : Boolean.valueOf(verifyHostname); + + if (keyStoreLocation == null && trustStoreLocation == null) { + setUpBasicSsl( + cf, + validateServerCertificate == null ? Boolean.FALSE : Boolean.valueOf(validateServerCertificate), + enableHostnameVerification, + algorithm + ); + } else { + KeyManager[] keyManagers = configureKeyManagers(keyStoreLocation, keyStorePassword, keyStoreType, keyStoreAlgorithm); + TrustManager[] trustManagers = configureTrustManagers(trustStoreLocation, trustStorePassword, trustStoreType, trustStoreAlgorithm); + + // create ssl context + SSLContext sslContext = SSLContext.getInstance(algorithm); + sslContext.init(keyManagers, trustManagers, null); + + cf.useSslProtocol(sslContext); + + if (enableHostnameVerification) { + cf.enableHostnameVerification(); + } + } + } catch (NoSuchAlgorithmException | IOException | CertificateException | + UnrecoverableKeyException | KeyStoreException | KeyManagementException e) { + throw new IllegalStateException("Error while configuring TLS", e); + } + } + + private static KeyManager[] configureKeyManagers(String keystore, String keystorePassword, String keystoreType, String keystoreAlgorithm) throws KeyStoreException, IOException, NoSuchAlgorithmException, + CertificateException, UnrecoverableKeyException { + char[] keyPassphrase = null; + if (keystorePassword != null) { + keyPassphrase = keystorePassword.toCharArray(); + } + KeyManager[] keyManagers = null; + if (keystore != null) { + KeyStore ks = KeyStore.getInstance(keystoreType); + try (InputStream in = loadResource(keystore)) { + ks.load(in, keyPassphrase); + } + KeyManagerFactory kmf = KeyManagerFactory.getInstance(keystoreAlgorithm); + kmf.init(ks, keyPassphrase); + keyManagers = kmf.getKeyManagers(); + } + return keyManagers; + } + + private static TrustManager[] configureTrustManagers(String truststore, String truststorePassword, String truststoreType, String truststoreAlgorithm) + throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException { + char[] trustPassphrase = null; + if (truststorePassword != null) { + trustPassphrase = truststorePassword.toCharArray(); + } + TrustManager[] trustManagers = null; + if (truststore != null) { + KeyStore tks = KeyStore.getInstance(truststoreType); + try (InputStream in = loadResource(truststore)) { + tks.load(in, trustPassphrase); + } + TrustManagerFactory tmf = TrustManagerFactory.getInstance(truststoreAlgorithm); + tmf.init(tks); + trustManagers = tmf.getTrustManagers(); + } + return trustManagers; + } + + private static void setUpBasicSsl(ConnectionFactory cf, boolean validateServerCertificate, boolean verifyHostname, String sslAlgorithm) throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException { + if (validateServerCertificate) { + useDefaultTrustStore(cf, sslAlgorithm, verifyHostname); + } else { + if (sslAlgorithm == null) { + cf.useSslProtocol(); + } else { + cf.useSslProtocol(sslAlgorithm); + } + } + } + + private static void useDefaultTrustStore(ConnectionFactory cf, String sslAlgorithm, boolean verifyHostname) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException { + SSLContext sslContext = SSLContext.getInstance(sslAlgorithm); + TrustManagerFactory trustManagerFactory = + TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + trustManagerFactory.init((KeyStore) null); + sslContext.init(null, trustManagerFactory.getTrustManagers(), null); + cf.useSslProtocol(sslContext); + if (verifyHostname) { + cf.enableHostnameVerification(); + } } public static void load(ConnectionFactory connectionFactory, String propertyFileLocation) throws IOException { @@ -256,4 +384,21 @@ public static void load(ConnectionFactory connectionFactory, Properties properti public static void load(ConnectionFactory connectionFactory, Map properties) { load(connectionFactory, properties, DEFAULT_PREFIX); } + + public static String lookUp(String key, Map properties, String prefix) { + return lookUp(key, properties, prefix, null); + } + + public static String lookUp(String key, Map properties, String prefix, String defaultValue) { + String value = properties.get(prefix + key); + if (value == null) { + value = ALIASES.getOrDefault(key, Collections.emptyList()).stream() + .map(alias -> properties.get(prefix + alias)) + .filter(v -> v != null) + .findFirst().orElse(defaultValue); + } + return value; + } + + } diff --git a/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java b/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java index 0c5df5823f..2a140721a5 100644 --- a/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java +++ b/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java @@ -18,66 +18,64 @@ import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.ConnectionFactoryConfigurator; import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; +import javax.net.ssl.SSLContext; import java.io.FileReader; import java.io.IOException; import java.io.Reader; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; +import java.util.*; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Stream; import static com.rabbitmq.client.impl.AMQConnection.defaultClientProperties; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; /** * */ -@RunWith(Parameterized.class) public class PropertyFileInitialisationTest { - @Parameterized.Parameters - public static Object[] data() { - return new Object[] { - "./src/test/resources/property-file-initialisation/configuration.properties", - "classpath:/property-file-initialisation/configuration.properties" - }; - } - - @Parameterized.Parameter - public String propertyFileLocation; - ConnectionFactory cf = new ConnectionFactory(); - @Test public void propertyInitialisationFromFile() throws IOException { - cf.load(propertyFileLocation); - checkConnectionFactory(); + @Test + public void propertyInitialisationFromFile() throws IOException { + for (String propertyFileLocation : Arrays.asList( + "./src/test/resources/property-file-initialisation/configuration.properties", + "classpath:/property-file-initialisation/configuration.properties")) { + ConnectionFactory connectionFactory = new ConnectionFactory(); + connectionFactory.load(propertyFileLocation); + checkConnectionFactory(connectionFactory); + } } - @Test public void propertyInitialisationCustomPrefix() throws Exception { + @Test + public void propertyInitialisationCustomPrefix() throws Exception { Properties propertiesCustomPrefix = getPropertiesWitPrefix("prefix."); cf.load(propertiesCustomPrefix, "prefix."); checkConnectionFactory(); } - @Test public void propertyInitialisationNoPrefix() throws Exception { + @Test + public void propertyInitialisationNoPrefix() throws Exception { Properties propertiesCustomPrefix = getPropertiesWitPrefix(""); cf.load(propertiesCustomPrefix, ""); checkConnectionFactory(); } - @Test public void propertyInitialisationNullPrefix() throws Exception { + @Test + public void propertyInitialisationNullPrefix() throws Exception { Properties propertiesCustomPrefix = getPropertiesWitPrefix(""); cf.load(propertiesCustomPrefix, null); checkConnectionFactory(); } - @Test public void propertyInitialisationUri() { + @Test + public void propertyInitialisationUri() { cf.load(Collections.singletonMap("rabbitmq.uri", "amqp://foo:bar@127.0.0.1:5673/dummy")); assertThat(cf.getUsername()).isEqualTo("foo"); @@ -87,12 +85,14 @@ public static Object[] data() { assertThat(cf.getPort()).isEqualTo(5673); } - @Test public void propertyInitialisationIncludeDefaultClientPropertiesByDefault() { + @Test + public void propertyInitialisationIncludeDefaultClientPropertiesByDefault() { cf.load(new HashMap<>()); assertThat(cf.getClientProperties().entrySet()).hasSize(defaultClientProperties().size()); } - @Test public void propertyInitialisationAddCustomClientProperty() { + @Test + public void propertyInitialisationAddCustomClientProperty() { cf.load(new HashMap() {{ put("rabbitmq.client.properties.foo", "bar"); }}); @@ -100,7 +100,8 @@ public static Object[] data() { assertThat(cf.getClientProperties()).extracting("foo").isEqualTo("bar"); } - @Test public void propertyInitialisationGetRidOfDefaultClientPropertyWithEmptyValue() { + @Test + public void propertyInitialisationGetRidOfDefaultClientPropertyWithEmptyValue() { final String key = defaultClientProperties().entrySet().iterator().next().getKey(); cf.load(new HashMap() {{ put("rabbitmq.client.properties." + key, ""); @@ -108,7 +109,8 @@ public static Object[] data() { assertThat(cf.getClientProperties().entrySet()).hasSize(defaultClientProperties().size() - 1); } - @Test public void propertyInitialisationOverrideDefaultClientProperty() { + @Test + public void propertyInitialisationOverrideDefaultClientProperty() { final String key = defaultClientProperties().entrySet().iterator().next().getKey(); cf.load(new HashMap() {{ put("rabbitmq.client.properties." + key, "whatever"); @@ -117,7 +119,8 @@ public static Object[] data() { assertThat(cf.getClientProperties()).extracting(key).isEqualTo("whatever"); } - @Test public void propertyInitialisationDoNotUseNio() throws Exception { + @Test + public void propertyInitialisationDoNotUseNio() throws Exception { cf.load(new HashMap() {{ put("rabbitmq.use.nio", "false"); put("rabbitmq.nio.nb.io.threads", "2"); @@ -125,34 +128,150 @@ public static Object[] data() { assertThat(cf.getNioParams().getNbIoThreads()).isNotEqualTo(2); } + @Test + public void lookUp() { + assertThat(ConnectionFactoryConfigurator.lookUp( + ConnectionFactoryConfigurator.SSL_KEY_STORE, + Collections.singletonMap(ConnectionFactoryConfigurator.SSL_KEY_STORE, "some file"), + "" + )).as("exact key should be looked up").isEqualTo("some file"); + + assertThat(ConnectionFactoryConfigurator.lookUp( + ConnectionFactoryConfigurator.SSL_KEY_STORE, + Collections.emptyMap(), + "" + )).as("lookup should return null when no match").isNull(); + + assertThat(ConnectionFactoryConfigurator.lookUp( + ConnectionFactoryConfigurator.SSL_KEY_STORE, + Collections.singletonMap("ssl.key-store", "some file"), // key alias + "" + )).as("alias key should be used when initial is missing").isEqualTo("some file"); + + assertThat(ConnectionFactoryConfigurator.lookUp( + ConnectionFactoryConfigurator.SSL_TRUST_STORE_TYPE, + Collections.emptyMap(), + "", + "JKS" + )).as("default value should be returned when key is not found").isEqualTo("JKS"); + } + + @Test + public void tlsInitialisationWithKeyManagerAndTrustManagerShouldSucceed() { + Stream.of("./src/test/resources/property-file-initialisation/tls/", + "classpath:/property-file-initialisation/tls/").forEach(baseDirectory -> { + Map configuration = new HashMap<>(); + configuration.put(ConnectionFactoryConfigurator.SSL_ENABLED, "true"); + configuration.put(ConnectionFactoryConfigurator.SSL_KEY_STORE, baseDirectory + "keystore.p12"); + configuration.put(ConnectionFactoryConfigurator.SSL_KEY_STORE_PASSWORD, "bunnies"); + configuration.put(ConnectionFactoryConfigurator.SSL_KEY_STORE_TYPE, "PKCS12"); + configuration.put(ConnectionFactoryConfigurator.SSL_KEY_STORE_ALGORITHM, "SunX509"); + + configuration.put(ConnectionFactoryConfigurator.SSL_TRUST_STORE, baseDirectory + "truststore.jks"); + configuration.put(ConnectionFactoryConfigurator.SSL_TRUST_STORE_PASSWORD, "bunnies"); + configuration.put(ConnectionFactoryConfigurator.SSL_TRUST_STORE_TYPE, "JKS"); + configuration.put(ConnectionFactoryConfigurator.SSL_TRUST_STORE_ALGORITHM, "SunX509"); + + configuration.put(ConnectionFactoryConfigurator.SSL_VERIFY_HOSTNAME, "true"); + + ConnectionFactory connectionFactory = mock(ConnectionFactory.class); + ConnectionFactoryConfigurator.load(connectionFactory, configuration, ""); + + verify(connectionFactory, times(1)).useSslProtocol(any(SSLContext.class)); + verify(connectionFactory, times(1)).enableHostnameVerification(); + }); + } + + @Test + public void tlsNotEnabledIfNotConfigured() { + ConnectionFactory connectionFactory = mock(ConnectionFactory.class); + ConnectionFactoryConfigurator.load(connectionFactory, Collections.emptyMap(), ""); + verify(connectionFactory, never()).useSslProtocol(any(SSLContext.class)); + } + + @Test + public void tlsNotEnabledIfDisabled() { + ConnectionFactory connectionFactory = mock(ConnectionFactory.class); + ConnectionFactoryConfigurator.load( + connectionFactory, + Collections.singletonMap(ConnectionFactoryConfigurator.SSL_ENABLED, "false"), + "" + ); + verify(connectionFactory, never()).useSslProtocol(any(SSLContext.class)); + } + + @Test + public void tlsSslContextSetIfTlsEnabled() { + AtomicBoolean sslProtocolSet = new AtomicBoolean(false); + ConnectionFactory connectionFactory = new ConnectionFactory() { + @Override + public void useSslProtocol(SSLContext context) { + sslProtocolSet.set(true); + super.useSslProtocol(context); + } + }; + ConnectionFactoryConfigurator.load( + connectionFactory, + Collections.singletonMap(ConnectionFactoryConfigurator.SSL_ENABLED, "true"), + "" + ); + assertThat(sslProtocolSet).isTrue(); + } + + @Test + public void tlsBasicSetupShouldTrustEveryoneWhenServerValidationIsNotEnabled() throws Exception { + String algorithm = ConnectionFactory.computeDefaultTlsProtocol(SSLContext.getDefault().getSupportedSSLParameters().getProtocols()); + Map configuration = new HashMap<>(); + configuration.put(ConnectionFactoryConfigurator.SSL_ENABLED, "true"); + configuration.put(ConnectionFactoryConfigurator.SSL_VALIDATE_SERVER_CERTIFICATE, "false"); + ConnectionFactory connectionFactory = mock(ConnectionFactory.class); + ConnectionFactoryConfigurator.load(connectionFactory, configuration, ""); + verify(connectionFactory, times(1)).useSslProtocol(algorithm); + } + + @Test + public void tlsBasicSetupShouldSetDefaultTrustManagerWhenServerValidationIsEnabled() throws Exception { + Map configuration = new HashMap<>(); + configuration.put(ConnectionFactoryConfigurator.SSL_ENABLED, "true"); + configuration.put(ConnectionFactoryConfigurator.SSL_VALIDATE_SERVER_CERTIFICATE, "true"); + ConnectionFactory connectionFactory = mock(ConnectionFactory.class); + ConnectionFactoryConfigurator.load(connectionFactory, configuration, ""); + verify(connectionFactory, never()).useSslProtocol(anyString()); + verify(connectionFactory, times(1)).useSslProtocol(any(SSLContext.class)); + } + private void checkConnectionFactory() { - assertThat(cf.getUsername()).isEqualTo("foo"); - assertThat(cf.getPassword()).isEqualTo("bar"); - assertThat(cf.getVirtualHost()).isEqualTo("dummy"); - assertThat(cf.getHost()).isEqualTo("127.0.0.1"); - assertThat(cf.getPort()).isEqualTo(5673); + checkConnectionFactory(this.cf); + } - assertThat(cf.getRequestedChannelMax()).isEqualTo(1); - assertThat(cf.getRequestedFrameMax()).isEqualTo(2); - assertThat(cf.getRequestedHeartbeat()).isEqualTo(10); - assertThat(cf.getConnectionTimeout()).isEqualTo(10000); - assertThat(cf.getHandshakeTimeout()).isEqualTo(5000); + private void checkConnectionFactory(ConnectionFactory connectionFactory) { + assertThat(connectionFactory.getUsername()).isEqualTo("foo"); + assertThat(connectionFactory.getPassword()).isEqualTo("bar"); + assertThat(connectionFactory.getVirtualHost()).isEqualTo("dummy"); + assertThat(connectionFactory.getHost()).isEqualTo("127.0.0.1"); + assertThat(connectionFactory.getPort()).isEqualTo(5673); - assertThat(cf.getClientProperties().entrySet()).hasSize(defaultClientProperties().size() + 1); - assertThat(cf.getClientProperties()).extracting("foo").isEqualTo("bar"); + assertThat(connectionFactory.getRequestedChannelMax()).isEqualTo(1); + assertThat(connectionFactory.getRequestedFrameMax()).isEqualTo(2); + assertThat(connectionFactory.getRequestedHeartbeat()).isEqualTo(10); + assertThat(connectionFactory.getConnectionTimeout()).isEqualTo(10000); + assertThat(connectionFactory.getHandshakeTimeout()).isEqualTo(5000); + + assertThat(connectionFactory.getClientProperties().entrySet()).hasSize(defaultClientProperties().size() + 1); + assertThat(connectionFactory.getClientProperties()).extracting("foo").isEqualTo("bar"); - assertThat(cf.isAutomaticRecoveryEnabled()).isFalse(); - assertThat(cf.isTopologyRecoveryEnabled()).isFalse(); - assertThat(cf.getNetworkRecoveryInterval()).isEqualTo(10000l); - assertThat(cf.getChannelRpcTimeout()).isEqualTo(10000); - assertThat(cf.isChannelShouldCheckRpcResponseType()).isTrue(); + assertThat(connectionFactory.isAutomaticRecoveryEnabled()).isFalse(); + assertThat(connectionFactory.isTopologyRecoveryEnabled()).isFalse(); + assertThat(connectionFactory.getNetworkRecoveryInterval()).isEqualTo(10000l); + assertThat(connectionFactory.getChannelRpcTimeout()).isEqualTo(10000); + assertThat(connectionFactory.isChannelShouldCheckRpcResponseType()).isTrue(); - assertThat(cf.getNioParams()).isNotNull(); - assertThat(cf.getNioParams().getReadByteBufferSize()).isEqualTo(32000); - assertThat(cf.getNioParams().getWriteByteBufferSize()).isEqualTo(32000); - assertThat(cf.getNioParams().getNbIoThreads()).isEqualTo(2); - assertThat(cf.getNioParams().getWriteEnqueuingTimeoutInMs()).isEqualTo(5000); - assertThat(cf.getNioParams().getWriteQueueCapacity()).isEqualTo(1000); + assertThat(connectionFactory.getNioParams()).isNotNull(); + assertThat(connectionFactory.getNioParams().getReadByteBufferSize()).isEqualTo(32000); + assertThat(connectionFactory.getNioParams().getWriteByteBufferSize()).isEqualTo(32000); + assertThat(connectionFactory.getNioParams().getNbIoThreads()).isEqualTo(2); + assertThat(connectionFactory.getNioParams().getWriteEnqueuingTimeoutInMs()).isEqualTo(5000); + assertThat(connectionFactory.getNioParams().getWriteQueueCapacity()).isEqualTo(1000); } private Properties getPropertiesWitPrefix(String prefix) throws IOException { @@ -168,8 +287,8 @@ private Properties getPropertiesWitPrefix(String prefix) throws IOException { Properties propertiesCustomPrefix = new Properties(); for (Map.Entry entry : properties.entrySet()) { propertiesCustomPrefix.put( - prefix + entry.getKey().toString().substring(ConnectionFactoryConfigurator.DEFAULT_PREFIX.length()), - entry.getValue() + prefix + entry.getKey().toString().substring(ConnectionFactoryConfigurator.DEFAULT_PREFIX.length()), + entry.getValue() ); } return propertiesCustomPrefix; diff --git a/src/test/resources/property-file-initialisation/tls/keystore.p12 b/src/test/resources/property-file-initialisation/tls/keystore.p12 new file mode 100644 index 0000000000000000000000000000000000000000..a5280a6cbfc9397e6a2ad7146b3859e685bc4434 GIT binary patch literal 2453 zcmV;G32OE*f(elV0Ru3C30DRQDuzgg_YDCD0ic2jNCbijL@_XY_nhDe6@ z4FLxRpn?PFFoFZ*0s#Opf&<+K2`Yw2hW8Bt2LUh~1_~;MNQUt@E?CQoZmLNl(%$Xi%*sEDPmpsXTtmVgCUP z9c0jUNIZ#6_<{ghk2g}iObqpcM)QEt(AGmT`A&qTRq}`6bsLo{4N3aM%bUcg>8)8H zih9lQtQ2hC209&3$!6Zuws=frumiq*Ph0B`Z{h9%m=kGyH4|mckw~3BcjKy_^I>1T zU}k#gdqJ-KcoBGM3fD*C^!=@dWXm}B6)Cn~!MA>9w#xq)xBD+T<`Z^G;1aymUs&y| z)lL4bU(NQ83io1~x$#p5gfX#^1;xsqaE3dxZ3TLP2u-NvGCqE-Q1c`}+X5$WlICbM z98B$V%AKoBvk_phj$`s2LC(EsHy@H$G0@8iM`SZ!oau;v^CUdI;})}7ZMa>_+gfO0 zC|A{x96tO8RL7(ZsZ|0k6-=;v9%YfrZDo)Aju4YT} z@?<>*lXEM!c_!LiHQxt_$|LAQUOzst_hR`s!Bo=%7l_xBYw`JhymkE_4hTVq%8baH zW`h4HhoeEy%Huv%O&IQe9LpinL?oa^kg{xk2KT;fu1C1VPUsHwT*h*;VGicvncJHA z5k_Hr3M)$uD4gn{V#liwH7byi`odl@r6d^`T0<35ObC)yn?+de1#n-_IwN{b&e&}* z6rN;hu|-}}M7k(&LNQUz=3HJr#wi9;Mp8KdCt_i zjeT4eMw)imK#f{xkLGMrIntd`KIsRX%CA!65B`kut~Gp4*qh;R0<`P1HhhLo$JCCQ zX1-mBrErs%H?p<9!!s`n;d3?gi;y@LOPmqo{+>JkHE8fHekww?56X z`;Lv9R5-i9)Zl7d^Da`&wK<=Y1QDB7^a=q4qtcax93pN*DHDLvT{$+D>{>E@Aq*y>xyZI z(ML5rE2vIMq^cI4IwVN!kDGsiZ^vQWws9}Uq6(goz9BmikW+cHC69H1a>qcs^FETn z1PoE9Y`y6^%|%`JEj{)zDr%@VB^qIcX<2 zd1}_S6!F(CLVzBNeNp}h)oNF$U&y^s>CTYTt-cY3ogap^euT2+tCh*)W|Sq?phJPB z*GP=RGn>{AlPkl4!45$|XJ#_vZ0|w3+1(iWU`3mV2|L8%p=IcE7EFRrxCFF^;=lrA z&U7=lLBX>NYUnEFA@m@p!~^2UTS(t8dd3373t`D=$NT%DaiOrNqM2K}Y*Me^UanJ; zv^Vnn(2h4h^{#vtKANAPvUPA>&Y3G{yCB2E!?eTFgOe&bEK1_Nrd*>scJc_R*!z8| z09;_Xr>GyPD0I*JNOCwv>?AyewOywN1jbFAPsjI$R3)mu`O$MCJ;Xo!ig%OFYm}$x z3`omJ-nMWhuH#jLAnf7p@OYs-TfvP*Pl1?u&l@Xr7t8?71;dDbcR%QAj-8mKlg_1* zG8)#HNp)K=!~JI{w=c!8X_>p}Q|%f(e0|}XK(vV2+`j#;IU9)+k6Geh!bBi&@Gb5tbioO{q?AsWkf*!d4!$uo7c zKfR++p?zp`HJ_c$>!6%yo%4MYP4>37gfz$*$ky`X5(71XsKF)WPAn`p|Buma7&K}0 zeW0+jHYN^Ll$!0!>S8`L_c6VlkTE*E@c<9jb_$V4wZE4QGsfNV3hf*=-sOf&{(-0Ru3C1a}4rDuzgg_YDCD0ic2eXas@;WH5pRU@(FNTm}g$hDe6@ z4FLxRpn?QVFoFb00s#Opf&@Ya2`Yw2hW8Bt2LUiC1_~;MNQU8^@R{Tt>+g$%b7#^NFz$ZuT}>j7sL!X zJ?^yu$ir)lBSKE0=$l)J_I+=8>tj3{$J`O2AvNLeAMJc@?e_Ly4C?$Qma}j$1w$q z#ACO4@N?e^h`7qeH0!%U<6`^_hu_r`KNZ7wrZB$o1kPyjv0#|`qAvb>6EdhhGCwm$ zf{|;*6Vb|}+Mn>MfV0i&wr0Lpe_Vd=<^IczN3G1d4BKo5+FqZ%``G}Kp%~9mw*8B= zAQ#4r-w|EseD#9gNh%Xk&&U)o_dtK6vziatFkh&_1d8tfbSintht6Tkn($OGsh})H zh8@TaYQa2=>a~!TS0E(RIfNZy7NkL6Qn&%j6K;5Jg^*kNc)ikK-l)-7u`QfNWiy*a z{YZlXBQF7Ut%wD_S=3Jqqzt)T)IzC}w<(|--bk7^U9LMefC~NY)iJ|Qhr_rU>(Fo? z-RfKn4TT*bM;O zk)FZl1Y*Du>-O+@(|VsDy1X;s@%Qm5+_Y!Ula?fVV>oxZ2oT`J^mKJp?-K%Lo_5Eu+ z-brRhBaw_WU(dJ^DK9i5;^e)@bBMbLc;%#H+Hrxvz_MC}{2B{@8o6)da|vT_a`(^&AtD{p!3!qQmQr$F5mI{9igs7JW+#Jz=Q?Bs;OIk!g&=DH9pU)R!$VNkVwe5dy!_?$wmqIiU4X=Z@4t(Hp@XMO>4jw@AjMJpT zD@eg-3X2(&n9f(y3Nl@KJDshhY4-F@!&v)E;g-l5$UI;F#yC6|HgrUOr#v0ByQn6z z>p7&AmnnlqIaJg2Chb#Nf42f8?5|QE!=+~41XmuQ1&%=h!^FIreQMO=D2Fu;X%YJ$ zw4;V}3r%g$5tll}d|mId5LaShl=6L=-wc0hG)5xMnn@bk0;4M-5NiiK_c9xe zop#+A7Jvo1fh9NXzOAY~pD;c!AutIB1uG5%0vZJX1Qb6MJC1$<{Xd?3cCOfI_8rl1 gntKEk`UyVFG_s>ccNeh1daTsm2u%w$0s{etpb_dgAOHXW literal 0 HcmV?d00001 From e1f2c8e28e5a113d55dd57f6dfc6929e3af264fd Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 22 Apr 2020 20:19:10 +0300 Subject: [PATCH 1248/2114] AutorecoveringConnection.maybeDeleteRecordedAutoDeleteExchange does not need to acquire a lock on this.consumers It most likely was a copy-paste artefact introduced back in 2013-2014. AutorecoveringConnection.maybeDeleteRecordedAutoDeleteQueue does need to lock this.consumers as conditional queue deletion does need to check the number of known consumers on that queue. 1aad565 addressed a potential deadlock caused by the unsafe order of lock acquisitions. In #648 another similar issue was discovered which #649 tried to address by acquiring a lock on this.consumers early. However, exchange cleanup does not need to lock this.consumers as it does not mutate it. Closes #648. (cherry picked from commit 5c3fce8d224c434c3f3858840123b03d28a1d9cd) --- .../impl/recovery/AutorecoveringConnection.java | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index f04e3778d5..785d98e5f4 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -1032,15 +1032,13 @@ void maybeDeleteRecordedAutoDeleteQueue(String queue) { } void maybeDeleteRecordedAutoDeleteExchange(String exchange) { - synchronized (this.consumers) { - synchronized (this.recordedExchanges) { - if(!hasMoreDestinationsBoundToExchange(Utility.copy(this.recordedBindings), exchange)) { - RecordedExchange x = this.recordedExchanges.get(exchange); - // last binding where this exchange is the source is gone, remove recorded exchange - // if it is auto-deleted. See bug 26364. - if(x != null && x.isAutoDelete()) { - deleteRecordedExchange(exchange); - } + synchronized (this.recordedExchanges) { + if(!hasMoreDestinationsBoundToExchange(Utility.copy(this.recordedBindings), exchange)) { + RecordedExchange x = this.recordedExchanges.get(exchange); + // last binding where this exchange is the source is gone, remove recorded exchange + // if it is auto-deleted. See bug 26364. + if(x != null && x.isAutoDelete()) { + deleteRecordedExchange(exchange); } } } From 7d7ca78500b25156d5694e26034ec000a18fd787 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 28 Apr 2020 11:45:55 +0200 Subject: [PATCH 1249/2114] Lock NIO loop initialization (precaution) The initialization is supposed to be called in a lock already. --- .../client/impl/nio/NioLoopContext.java | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioLoopContext.java b/src/main/java/com/rabbitmq/client/impl/nio/NioLoopContext.java index 47639cfc35..a73a7a0420 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioLoopContext.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioLoopContext.java @@ -54,12 +54,19 @@ public NioLoopContext(SocketChannelFrameHandlerFactory socketChannelFrameHandler } void initStateIfNecessary() throws IOException { - // FIXME this should be synchronized - if (this.readSelectorState == null) { - this.readSelectorState = new SelectorHolder(Selector.open()); - this.writeSelectorState = new SelectorHolder(Selector.open()); + // This code is supposed to be called only from the SocketChannelFrameHandlerFactory + // and while holding the lock. + // We lock just in case some other code calls this method in the future. + socketChannelFrameHandlerFactory.lock(); + try { + if (this.readSelectorState == null) { + this.readSelectorState = new SelectorHolder(Selector.open()); + this.writeSelectorState = new SelectorHolder(Selector.open()); - startIoLoops(); + startIoLoops(); + } + } finally { + socketChannelFrameHandlerFactory.unlock(); } } From ef5142e8a0ec89e0e9d137cd1cdff0276f3ba76c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 29 Apr 2020 09:19:32 +0200 Subject: [PATCH 1250/2114] Bump Maven to 3.6.3 --- .mvn/wrapper/MavenWrapperDownloader.java | 117 ++++++++ .mvn/wrapper/maven-wrapper.jar | Bin 48336 -> 50710 bytes .mvn/wrapper/maven-wrapper.properties | 3 +- mvnw | 89 +++++- mvnw.cmd | 327 +++++++++++++---------- 5 files changed, 387 insertions(+), 149 deletions(-) create mode 100644 .mvn/wrapper/MavenWrapperDownloader.java mode change 100755 => 100644 .mvn/wrapper/maven-wrapper.jar mode change 100755 => 100644 .mvn/wrapper/maven-wrapper.properties mode change 100755 => 100644 mvnw.cmd diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java new file mode 100644 index 0000000000..b901097f2d --- /dev/null +++ b/.mvn/wrapper/MavenWrapperDownloader.java @@ -0,0 +1,117 @@ +/* + * Copyright 2007-present 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. + * 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. + */ +import java.net.*; +import java.io.*; +import java.nio.channels.*; +import java.util.Properties; + +public class MavenWrapperDownloader { + + private static final String WRAPPER_VERSION = "0.5.6"; + /** + * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. + */ + private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" + + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; + + /** + * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to + * use instead of the default one. + */ + private static final String MAVEN_WRAPPER_PROPERTIES_PATH = + ".mvn/wrapper/maven-wrapper.properties"; + + /** + * Path where the maven-wrapper.jar will be saved to. + */ + private static final String MAVEN_WRAPPER_JAR_PATH = + ".mvn/wrapper/maven-wrapper.jar"; + + /** + * Name of the property which should be used to override the default download url for the wrapper. + */ + private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; + + public static void main(String args[]) { + System.out.println("- Downloader started"); + File baseDirectory = new File(args[0]); + System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); + + // If the maven-wrapper.properties exists, read it and check if it contains a custom + // wrapperUrl parameter. + File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); + String url = DEFAULT_DOWNLOAD_URL; + if(mavenWrapperPropertyFile.exists()) { + FileInputStream mavenWrapperPropertyFileInputStream = null; + try { + mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); + Properties mavenWrapperProperties = new Properties(); + mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); + url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); + } catch (IOException e) { + System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); + } finally { + try { + if(mavenWrapperPropertyFileInputStream != null) { + mavenWrapperPropertyFileInputStream.close(); + } + } catch (IOException e) { + // Ignore ... + } + } + } + System.out.println("- Downloading from: " + url); + + File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); + if(!outputFile.getParentFile().exists()) { + if(!outputFile.getParentFile().mkdirs()) { + System.out.println( + "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); + } + } + System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); + try { + downloadFileFromURL(url, outputFile); + System.out.println("Done"); + System.exit(0); + } catch (Throwable e) { + System.out.println("- Error downloading"); + e.printStackTrace(); + System.exit(1); + } + } + + private static void downloadFileFromURL(String urlString, File destination) throws Exception { + if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { + String username = System.getenv("MVNW_USERNAME"); + char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); + Authenticator.setDefault(new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(username, password); + } + }); + } + URL website = new URL(urlString); + ReadableByteChannel rbc; + rbc = Channels.newChannel(website.openStream()); + FileOutputStream fos = new FileOutputStream(destination); + fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); + fos.close(); + rbc.close(); + } + +} diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar old mode 100755 new mode 100644 index f775b1c04cf89b25c7814d3a8a7c810301092e57..2cc7d4a55c0cd0092912bf49ae38b3a9e3fd0054 GIT binary patch delta 13080 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 b%O!U$ef%H-8Z!hlL?I>w1WwuCzxjUv+~`jN diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties old mode 100755 new mode 100644 index a3ba20ec52..642d572ce9 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -1 +1,2 @@ -distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.6.1/apache-maven-3.6.1-bin.zip +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar diff --git a/mvnw b/mvnw index 4e574d9a02..41c0f0c23d 100755 --- a/mvnw +++ b/mvnw @@ -8,7 +8,7 @@ # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # -# https://www.apache.org/licenses/LICENSE-2.0 +# 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 @@ -19,7 +19,7 @@ # ---------------------------------------------------------------------------- # ---------------------------------------------------------------------------- -# Maven2 Start Up Batch script +# Maven Start Up Batch script # # Required ENV vars: # ------------------ @@ -114,7 +114,6 @@ if $mingw ; then M2_HOME="`(cd "$M2_HOME"; pwd)`" [ -n "$JAVA_HOME" ] && JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" - # TODO classpath? fi if [ -z "$JAVA_HOME" ]; then @@ -200,6 +199,85 @@ if [ -z "$BASE_DIR" ]; then exit 1; fi +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ -n "$MVNW_REPOURL" ]; then + jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} if [ "$MVNW_VERBOSE" = true ]; then echo $MAVEN_PROJECTBASEDIR @@ -218,6 +296,11 @@ if $cygwin; then MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` fi +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain exec "$JAVACMD" \ diff --git a/mvnw.cmd b/mvnw.cmd old mode 100755 new mode 100644 index 23ab056e29..86115719e5 --- a/mvnw.cmd +++ b/mvnw.cmd @@ -1,145 +1,182 @@ -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM https://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Maven2 Start Up Batch script -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM M2_HOME - location of maven2's installed home dir -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" -if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" - -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" -if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%" == "on" pause - -if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% - -exit /B %ERROR_CODE% +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + +FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% From 653aa486d87d0729cc6968eaf998be6fc1128518 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 28 Apr 2020 11:45:55 +0200 Subject: [PATCH 1251/2114] Lock NIO loop initialization (precaution) The initialization is supposed to be called in a lock already. (cherry picked from commit 7d7ca78500b25156d5694e26034ec000a18fd787) --- .../client/impl/nio/NioLoopContext.java | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioLoopContext.java b/src/main/java/com/rabbitmq/client/impl/nio/NioLoopContext.java index 47639cfc35..a73a7a0420 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioLoopContext.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioLoopContext.java @@ -54,12 +54,19 @@ public NioLoopContext(SocketChannelFrameHandlerFactory socketChannelFrameHandler } void initStateIfNecessary() throws IOException { - // FIXME this should be synchronized - if (this.readSelectorState == null) { - this.readSelectorState = new SelectorHolder(Selector.open()); - this.writeSelectorState = new SelectorHolder(Selector.open()); + // This code is supposed to be called only from the SocketChannelFrameHandlerFactory + // and while holding the lock. + // We lock just in case some other code calls this method in the future. + socketChannelFrameHandlerFactory.lock(); + try { + if (this.readSelectorState == null) { + this.readSelectorState = new SelectorHolder(Selector.open()); + this.writeSelectorState = new SelectorHolder(Selector.open()); - startIoLoops(); + startIoLoops(); + } + } finally { + socketChannelFrameHandlerFactory.unlock(); } } From 8a334573c0c0f720f668030e18c6dc48f62ed5f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 29 Apr 2020 09:20:33 +0200 Subject: [PATCH 1252/2114] Bump Maven to 3.6.3 --- .mvn/wrapper/MavenWrapperDownloader.java | 117 ++++++++ .mvn/wrapper/maven-wrapper.jar | Bin 48336 -> 50710 bytes .mvn/wrapper/maven-wrapper.properties | 3 +- mvnw | 89 +++++- mvnw.cmd | 327 +++++++++++++---------- 5 files changed, 387 insertions(+), 149 deletions(-) create mode 100644 .mvn/wrapper/MavenWrapperDownloader.java mode change 100755 => 100644 .mvn/wrapper/maven-wrapper.jar mode change 100755 => 100644 .mvn/wrapper/maven-wrapper.properties mode change 100755 => 100644 mvnw.cmd diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java new file mode 100644 index 0000000000..b901097f2d --- /dev/null +++ b/.mvn/wrapper/MavenWrapperDownloader.java @@ -0,0 +1,117 @@ +/* + * Copyright 2007-present 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. + * 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. + */ +import java.net.*; +import java.io.*; +import java.nio.channels.*; +import java.util.Properties; + +public class MavenWrapperDownloader { + + private static final String WRAPPER_VERSION = "0.5.6"; + /** + * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. + */ + private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" + + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; + + /** + * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to + * use instead of the default one. + */ + private static final String MAVEN_WRAPPER_PROPERTIES_PATH = + ".mvn/wrapper/maven-wrapper.properties"; + + /** + * Path where the maven-wrapper.jar will be saved to. + */ + private static final String MAVEN_WRAPPER_JAR_PATH = + ".mvn/wrapper/maven-wrapper.jar"; + + /** + * Name of the property which should be used to override the default download url for the wrapper. + */ + private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; + + public static void main(String args[]) { + System.out.println("- Downloader started"); + File baseDirectory = new File(args[0]); + System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); + + // If the maven-wrapper.properties exists, read it and check if it contains a custom + // wrapperUrl parameter. + File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); + String url = DEFAULT_DOWNLOAD_URL; + if(mavenWrapperPropertyFile.exists()) { + FileInputStream mavenWrapperPropertyFileInputStream = null; + try { + mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); + Properties mavenWrapperProperties = new Properties(); + mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); + url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); + } catch (IOException e) { + System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); + } finally { + try { + if(mavenWrapperPropertyFileInputStream != null) { + mavenWrapperPropertyFileInputStream.close(); + } + } catch (IOException e) { + // Ignore ... + } + } + } + System.out.println("- Downloading from: " + url); + + File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); + if(!outputFile.getParentFile().exists()) { + if(!outputFile.getParentFile().mkdirs()) { + System.out.println( + "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); + } + } + System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); + try { + downloadFileFromURL(url, outputFile); + System.out.println("Done"); + System.exit(0); + } catch (Throwable e) { + System.out.println("- Error downloading"); + e.printStackTrace(); + System.exit(1); + } + } + + private static void downloadFileFromURL(String urlString, File destination) throws Exception { + if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { + String username = System.getenv("MVNW_USERNAME"); + char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); + Authenticator.setDefault(new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(username, password); + } + }); + } + URL website = new URL(urlString); + ReadableByteChannel rbc; + rbc = Channels.newChannel(website.openStream()); + FileOutputStream fos = new FileOutputStream(destination); + fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); + fos.close(); + rbc.close(); + } + +} diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar old mode 100755 new mode 100644 index f775b1c04cf89b25c7814d3a8a7c810301092e57..2cc7d4a55c0cd0092912bf49ae38b3a9e3fd0054 GIT binary patch delta 13080 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 b%O!U$ef%H-8Z!hlL?I>w1WwuCzxjUv+~`jN diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties old mode 100755 new mode 100644 index a3ba20ec52..642d572ce9 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -1 +1,2 @@ -distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.6.1/apache-maven-3.6.1-bin.zip +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar diff --git a/mvnw b/mvnw index 4e574d9a02..41c0f0c23d 100755 --- a/mvnw +++ b/mvnw @@ -8,7 +8,7 @@ # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # -# https://www.apache.org/licenses/LICENSE-2.0 +# 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 @@ -19,7 +19,7 @@ # ---------------------------------------------------------------------------- # ---------------------------------------------------------------------------- -# Maven2 Start Up Batch script +# Maven Start Up Batch script # # Required ENV vars: # ------------------ @@ -114,7 +114,6 @@ if $mingw ; then M2_HOME="`(cd "$M2_HOME"; pwd)`" [ -n "$JAVA_HOME" ] && JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" - # TODO classpath? fi if [ -z "$JAVA_HOME" ]; then @@ -200,6 +199,85 @@ if [ -z "$BASE_DIR" ]; then exit 1; fi +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ -n "$MVNW_REPOURL" ]; then + jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} if [ "$MVNW_VERBOSE" = true ]; then echo $MAVEN_PROJECTBASEDIR @@ -218,6 +296,11 @@ if $cygwin; then MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` fi +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain exec "$JAVACMD" \ diff --git a/mvnw.cmd b/mvnw.cmd old mode 100755 new mode 100644 index 23ab056e29..86115719e5 --- a/mvnw.cmd +++ b/mvnw.cmd @@ -1,145 +1,182 @@ -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM https://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Maven2 Start Up Batch script -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM M2_HOME - location of maven2's installed home dir -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" -if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" - -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" -if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%" == "on" pause - -if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% - -exit /B %ERROR_CODE% +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + +FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% From 0646231ff9d2022ba24cd1a5f2243fa71bbac39b Mon Sep 17 00:00:00 2001 From: dcorbacho Date: Mon, 13 Jul 2020 12:00:04 +0100 Subject: [PATCH 1253/2114] Switch to Mozilla Public License 2.0 (MPL 2.0) --- LICENSE | 2 +- LICENSE-MPL-RabbitMQ | 840 ++++++++---------- README.md | 2 +- codegen.py | 4 +- .../java/com/rabbitmq/client/Address.java | 2 +- .../com/rabbitmq/client/AddressResolver.java | 2 +- .../client/AlreadyClosedException.java | 2 +- .../AuthenticationFailureException.java | 2 +- .../com/rabbitmq/client/BasicProperties.java | 2 +- .../com/rabbitmq/client/BlockedCallback.java | 2 +- .../com/rabbitmq/client/BlockedListener.java | 2 +- .../com/rabbitmq/client/CancelCallback.java | 2 +- .../java/com/rabbitmq/client/Channel.java | 2 +- .../java/com/rabbitmq/client/Command.java | 2 +- .../com/rabbitmq/client/ConfirmCallback.java | 2 +- .../com/rabbitmq/client/ConfirmListener.java | 2 +- .../java/com/rabbitmq/client/Connection.java | 2 +- .../rabbitmq/client/ConnectionFactory.java | 2 +- .../client/ConnectionFactoryConfigurator.java | 2 +- .../java/com/rabbitmq/client/Consumer.java | 2 +- .../client/ConsumerCancelledException.java | 2 +- .../ConsumerShutdownSignalCallback.java | 2 +- .../com/rabbitmq/client/ContentHeader.java | 2 +- .../com/rabbitmq/client/DefaultConsumer.java | 2 +- .../rabbitmq/client/DefaultSaslConfig.java | 2 +- .../DefaultSocketChannelConfigurator.java | 2 +- .../client/DefaultSocketConfigurator.java | 2 +- .../com/rabbitmq/client/DeliverCallback.java | 2 +- .../java/com/rabbitmq/client/Delivery.java | 2 +- .../client/DnsRecordIpAddressResolver.java | 2 +- .../client/DnsSrvRecordAddressResolver.java | 2 +- .../java/com/rabbitmq/client/Envelope.java | 2 +- .../com/rabbitmq/client/ExceptionHandler.java | 2 +- .../java/com/rabbitmq/client/GetResponse.java | 2 +- .../com/rabbitmq/client/JDKSaslConfig.java | 2 +- .../rabbitmq/client/ListAddressResolver.java | 2 +- .../java/com/rabbitmq/client/LongString.java | 2 +- .../client/MalformedFrameException.java | 2 +- .../com/rabbitmq/client/MapRpcServer.java | 2 +- .../rabbitmq/client/MessageProperties.java | 2 +- src/main/java/com/rabbitmq/client/Method.java | 2 +- .../com/rabbitmq/client/MetricsCollector.java | 2 +- .../client/MissedHeartbeatException.java | 2 +- .../rabbitmq/client/NoOpMetricsCollector.java | 2 +- ...ossibleAuthenticationFailureException.java | 2 +- .../ProtocolVersionMismatchException.java | 2 +- .../java/com/rabbitmq/client/Recoverable.java | 2 +- .../rabbitmq/client/RecoveryDelayHandler.java | 2 +- .../com/rabbitmq/client/RecoveryListener.java | 2 +- src/main/java/com/rabbitmq/client/Return.java | 2 +- .../com/rabbitmq/client/ReturnCallback.java | 2 +- .../com/rabbitmq/client/ReturnListener.java | 2 +- .../java/com/rabbitmq/client/RpcClient.java | 2 +- .../com/rabbitmq/client/RpcClientParams.java | 2 +- .../java/com/rabbitmq/client/RpcServer.java | 2 +- .../java/com/rabbitmq/client/SaslConfig.java | 2 +- .../com/rabbitmq/client/SaslMechanism.java | 2 +- .../com/rabbitmq/client/ShutdownListener.java | 2 +- .../com/rabbitmq/client/ShutdownNotifier.java | 2 +- .../client/ShutdownSignalException.java | 2 +- .../client/SocketChannelConfigurator.java | 2 +- .../client/SocketChannelConfigurators.java | 2 +- .../rabbitmq/client/SocketConfigurator.java | 2 +- .../rabbitmq/client/SocketConfigurators.java | 2 +- .../rabbitmq/client/SslContextFactory.java | 2 +- .../client/SslEngineConfigurator.java | 2 +- .../client/SslEngineConfigurators.java | 2 +- .../com/rabbitmq/client/StringRpcServer.java | 2 +- .../client/TopologyRecoveryException.java | 2 +- .../client/TrustEverythingTrustManager.java | 2 +- .../rabbitmq/client/UnblockedCallback.java | 2 +- .../rabbitmq/client/UnexpectedFrameError.java | 2 +- .../client/UnexpectedMethodError.java | 2 +- .../client/UnknownClassOrMethodId.java | 2 +- .../client/UnroutableRpcRequestException.java | 2 +- .../client/impl/AMQBasicProperties.java | 2 +- .../com/rabbitmq/client/impl/AMQChannel.java | 2 +- .../com/rabbitmq/client/impl/AMQCommand.java | 2 +- .../rabbitmq/client/impl/AMQConnection.java | 2 +- .../client/impl/AMQContentHeader.java | 2 +- .../client/impl/AbstractMetricsCollector.java | 2 +- .../rabbitmq/client/impl/CRDemoMechanism.java | 2 +- .../rabbitmq/client/impl/ChannelManager.java | 2 +- .../com/rabbitmq/client/impl/ChannelN.java | 2 +- .../rabbitmq/client/impl/ClientVersion.java | 2 +- .../client/impl/CommandAssembler.java | 2 +- .../impl/CompletableFutureRpcWrapper.java | 2 +- .../client/impl/ConnectionParams.java | 2 +- .../client/impl/ConsumerDispatcher.java | 2 +- .../client/impl/ConsumerWorkService.java | 2 +- .../impl/ContentHeaderPropertyReader.java | 2 +- .../impl/ContentHeaderPropertyWriter.java | 2 +- .../client/impl/CredentialsProvider.java | 4 +- .../impl/CredentialsRefreshService.java | 2 +- .../impl/DefaultCredentialsProvider.java | 2 +- .../DefaultCredentialsRefreshService.java | 2 +- .../client/impl/DefaultExceptionHandler.java | 2 +- .../com/rabbitmq/client/impl/Environment.java | 2 +- .../client/impl/ErrorOnWriteListener.java | 2 +- .../client/impl/ExternalMechanism.java | 2 +- .../impl/ForgivingExceptionHandler.java | 2 +- .../java/com/rabbitmq/client/impl/Frame.java | 2 +- .../rabbitmq/client/impl/FrameHandler.java | 2 +- .../rabbitmq/client/impl/HeartbeatSender.java | 2 +- .../client/impl/LongStringHelper.java | 2 +- .../java/com/rabbitmq/client/impl/Method.java | 2 +- .../client/impl/MethodArgumentReader.java | 2 +- .../client/impl/MethodArgumentWriter.java | 2 +- .../impl/MicrometerMetricsCollector.java | 2 +- .../client/impl/NetworkConnection.java | 2 +- ...ntCredentialsGrantCredentialsProvider.java | 2 +- .../impl/OAuthTokenManagementException.java | 2 +- .../rabbitmq/client/impl/PlainMechanism.java | 2 +- .../RefreshProtectedCredentialsProvider.java | 2 +- .../impl/RpcContinuationRpcWrapper.java | 2 +- .../com/rabbitmq/client/impl/RpcWrapper.java | 2 +- .../com/rabbitmq/client/impl/SetQueue.java | 2 +- .../impl/ShutdownNotifierComponent.java | 2 +- .../client/impl/SocketFrameHandler.java | 2 +- .../impl/SocketFrameHandlerFactory.java | 2 +- .../client/impl/StandardMetricsCollector.java | 2 +- .../client/impl/StrictExceptionHandler.java | 2 +- .../com/rabbitmq/client/impl/TlsUtils.java | 2 +- .../client/impl/TruncatedInputStream.java | 2 +- .../client/impl/UnknownChannelException.java | 2 +- .../client/impl/UpdateSecretExtension.java | 2 +- .../com/rabbitmq/client/impl/ValueReader.java | 2 +- .../com/rabbitmq/client/impl/ValueWriter.java | 2 +- .../impl/VariableLinkedBlockingQueue.java | 2 +- .../com/rabbitmq/client/impl/Version.java | 2 +- .../com/rabbitmq/client/impl/WorkPool.java | 2 +- .../client/impl/WorkPoolFullException.java | 2 +- .../impl/nio/ByteBufferOutputStream.java | 2 +- .../client/impl/nio/FrameBuilder.java | 2 +- .../client/impl/nio/FrameWriteRequest.java | 2 +- .../client/impl/nio/HeaderWriteRequest.java | 2 +- .../rabbitmq/client/impl/nio/NioHelper.java | 2 +- .../com/rabbitmq/client/impl/nio/NioLoop.java | 2 +- .../client/impl/nio/NioLoopContext.java | 2 +- .../rabbitmq/client/impl/nio/NioParams.java | 2 +- .../client/impl/nio/SelectorHolder.java | 2 +- .../impl/nio/SocketChannelFrameHandler.java | 2 +- .../nio/SocketChannelFrameHandlerFactory.java | 2 +- .../nio/SocketChannelFrameHandlerState.java | 2 +- .../impl/nio/SocketChannelRegistration.java | 2 +- .../nio/SslEngineByteBufferOutputStream.java | 2 +- .../impl/nio/SslEngineFrameBuilder.java | 2 +- .../client/impl/nio/SslEngineHelper.java | 2 +- .../client/impl/nio/WriteRequest.java | 2 +- .../impl/recovery/AutorecoveringChannel.java | 2 +- .../recovery/AutorecoveringConnection.java | 2 +- .../client/impl/recovery/BackoffPolicy.java | 2 +- .../recovery/ConsumerRecoveryListener.java | 2 +- .../impl/recovery/DefaultRetryHandler.java | 2 +- .../impl/recovery/QueueRecoveryListener.java | 2 +- .../client/impl/recovery/RecordedBinding.java | 2 +- .../impl/recovery/RecordedConsumer.java | 2 +- .../client/impl/recovery/RecordedEntity.java | 2 +- .../impl/recovery/RecordedExchange.java | 2 +- .../recovery/RecordedExchangeBinding.java | 2 +- .../impl/recovery/RecordedNamedEntity.java | 2 +- .../client/impl/recovery/RecordedQueue.java | 2 +- .../impl/recovery/RecordedQueueBinding.java | 2 +- .../recovery/RecoveryAwareAMQConnection.java | 2 +- .../RecoveryAwareAMQConnectionFactory.java | 2 +- .../recovery/RecoveryAwareChannelManager.java | 2 +- .../impl/recovery/RecoveryAwareChannelN.java | 2 +- .../recovery/RecoveryCanBeginListener.java | 2 +- .../client/impl/recovery/RetryContext.java | 2 +- .../client/impl/recovery/RetryHandler.java | 2 +- .../client/impl/recovery/RetryResult.java | 2 +- .../impl/recovery/TopologyRecoveryFilter.java | 2 +- .../TopologyRecoveryRetryHandlerBuilder.java | 2 +- .../recovery/TopologyRecoveryRetryLogic.java | 2 +- .../com/rabbitmq/tools/json/JSONUtil.java | 2 +- .../tools/jsonrpc/JacksonJsonRpcMapper.java | 2 +- .../rabbitmq/tools/jsonrpc/JsonRpcClient.java | 2 +- .../tools/jsonrpc/JsonRpcException.java | 2 +- .../rabbitmq/tools/jsonrpc/JsonRpcMapper.java | 2 +- .../jsonrpc/JsonRpcMappingException.java | 2 +- .../rabbitmq/tools/jsonrpc/JsonRpcServer.java | 2 +- .../tools/jsonrpc/ParameterDescription.java | 2 +- .../tools/jsonrpc/ProcedureDescription.java | 2 +- .../tools/jsonrpc/ServiceDescription.java | 2 +- .../com/rabbitmq/utility/BlockingCell.java | 2 +- .../utility/BlockingValueOrException.java | 2 +- .../com/rabbitmq/utility/IntAllocator.java | 2 +- .../com/rabbitmq/utility/SensibleClone.java | 2 +- .../java/com/rabbitmq/utility/Utility.java | 2 +- .../rabbitmq/utility/ValueOrException.java | 2 +- .../rabbitmq/client/AbstractJsonRpcTest.java | 2 +- .../rabbitmq/client/JacksonJsonRpcTest.java | 2 +- .../com/rabbitmq/client/QueueingConsumer.java | 2 +- .../AMQConnectionRefreshCredentialsTest.java | 2 +- .../DefaultCredentialsRefreshServiceTest.java | 2 +- ...edentialsGrantCredentialsProviderTest.java | 2 +- ...freshProtectedCredentialsProviderTest.java | 2 +- .../rabbitmq/client/impl/ValueWriterTest.java | 2 +- .../rabbitmq/client/impl/WorkPoolTests.java | 2 +- .../client/test/AMQBuilderApiTest.java | 2 +- .../rabbitmq/client/test/AMQChannelTest.java | 2 +- .../client/test/AMQConnectionTest.java | 2 +- .../client/test/AbstractRMQTestSuite.java | 2 +- .../com/rabbitmq/client/test/AddressTest.java | 2 +- .../com/rabbitmq/client/test/AmqpUriTest.java | 2 +- .../client/test/BlockingCellTest.java | 2 +- .../client/test/BrokenFramesTest.java | 2 +- .../rabbitmq/client/test/BrokerTestCase.java | 2 +- .../rabbitmq/client/test/Bug20004Test.java | 2 +- .../ChannelAsyncCompletableFutureTest.java | 2 +- .../rabbitmq/client/test/ChannelNTest.java | 2 +- .../test/ChannelNumberAllocationTests.java | 2 +- .../ChannelRpcTimeoutIntegrationTest.java | 2 +- .../com/rabbitmq/client/test/ClientTests.java | 2 +- .../client/test/ClientVersionTest.java | 2 +- .../client/test/ClonePropertiesTest.java | 2 +- .../rabbitmq/client/test/CloseInMainLoop.java | 2 +- .../com/rabbitmq/client/test/ConfirmBase.java | 2 +- .../client/test/ConnectionFactoryTest.java | 2 +- .../rabbitmq/client/test/ConnectionTest.java | 2 +- .../client/test/DefaultRetryHandlerTest.java | 2 +- .../test/DnsSrvRecordAddressResolverTest.java | 2 +- .../client/test/FrameBuilderTest.java | 2 +- .../client/test/GeneratedClassesTest.java | 2 +- .../client/test/LambdaCallbackTest.java | 2 +- .../rabbitmq/client/test/LongStringTest.java | 2 +- .../client/test/MetricsCollectorTest.java | 2 +- .../test/MicrometerMetricsCollectorTest.java | 2 +- .../client/test/MultiThreadedChannel.java | 2 +- .../test/NioDeadlockOnConnectionClosing.java | 2 +- ...NoAutoRecoveryWhenTcpWindowIsFullTest.java | 2 +- .../test/PropertyFileInitialisationTest.java | 2 +- .../client/test/QueueingConsumerTests.java | 2 +- ...RecoveryAwareAMQConnectionFactoryTest.java | 2 +- .../client/test/RecoveryDelayHandlerTest.java | 2 +- .../client/test/RefreshCredentialsTest.java | 2 +- .../com/rabbitmq/client/test/RpcTest.java | 2 +- .../client/test/RpcTopologyRecordingTest.java | 2 +- .../client/test/SharedThreadPoolTest.java | 2 +- .../client/test/SslContextFactoryTest.java | 2 +- .../test/StrictExceptionHandlerTest.java | 2 +- .../com/rabbitmq/client/test/TableTest.java | 2 +- .../com/rabbitmq/client/test/TestUtils.java | 2 +- .../rabbitmq/client/test/TestUtilsTest.java | 2 +- .../rabbitmq/client/test/TlsUtilsTest.java | 2 +- .../client/test/TrafficListenerTest.java | 2 +- .../client/test/TruncatedInputStreamTest.java | 2 +- .../client/test/ValueOrExceptionTest.java | 2 +- .../test/functional/AbstractRejectTest.java | 2 +- .../test/functional/AlternateExchange.java | 2 +- .../client/test/functional/BasicGet.java | 2 +- .../test/functional/BindingLifecycle.java | 2 +- .../test/functional/BindingLifecycleBase.java | 2 +- .../client/test/functional/CcRoutes.java | 2 +- .../test/functional/ClusteredTestBase.java | 2 +- .../client/test/functional/Confirm.java | 2 +- .../test/functional/ConnectionOpen.java | 2 +- .../test/functional/ConnectionRecovery.java | 2 +- .../ConsumerCancelNotification.java | 2 +- .../client/test/functional/ConsumerCount.java | 2 +- .../test/functional/ConsumerPriorities.java | 2 +- .../test/functional/DeadLetterExchange.java | 2 +- .../test/functional/DefaultExchange.java | 2 +- .../client/test/functional/DirectReplyTo.java | 2 +- .../test/functional/DoubleDeletion.java | 2 +- .../test/functional/DurableOnTransient.java | 2 +- .../test/functional/ExceptionHandling.java | 2 +- .../test/functional/ExceptionMessages.java | 2 +- .../test/functional/ExchangeDeclare.java | 2 +- .../functional/ExchangeDeleteIfUnused.java | 2 +- .../functional/ExchangeDeletePredeclared.java | 2 +- .../functional/ExchangeEquivalenceBase.java | 2 +- .../functional/ExchangeExchangeBindings.java | 2 +- .../ExchangeExchangeBindingsAutoDelete.java | 2 +- .../client/test/functional/FrameMax.java | 2 +- .../test/functional/FunctionalTests.java | 2 +- .../functional/HeadersExchangeValidation.java | 2 +- .../client/test/functional/Heartbeat.java | 2 +- .../test/functional/InternalExchange.java | 2 +- .../client/test/functional/InvalidAcks.java | 2 +- .../test/functional/InvalidAcksBase.java | 2 +- .../client/test/functional/InvalidAcksTx.java | 2 +- .../client/test/functional/MessageCount.java | 2 +- .../client/test/functional/Metrics.java | 2 +- .../rabbitmq/client/test/functional/Nack.java | 2 +- .../test/functional/NoRequeueOnCancel.java | 2 +- .../client/test/functional/Nowait.java | 2 +- .../test/functional/PerConsumerPrefetch.java | 2 +- .../client/test/functional/PerMessageTTL.java | 2 +- .../client/test/functional/PerQueueTTL.java | 2 +- .../functional/PerQueueVsPerMessageTTL.java | 2 +- .../client/test/functional/Policies.java | 2 +- .../client/test/functional/QosTests.java | 2 +- .../test/functional/QueueExclusivity.java | 2 +- .../client/test/functional/QueueLease.java | 2 +- .../test/functional/QueueLifecycle.java | 2 +- .../test/functional/QueueSizeLimit.java | 2 +- .../client/test/functional/Recover.java | 2 +- .../client/test/functional/Reject.java | 2 +- .../functional/RequeueOnChannelClose.java | 2 +- .../test/functional/RequeueOnClose.java | 2 +- .../functional/RequeueOnConnectionClose.java | 2 +- .../client/test/functional/Routing.java | 2 +- .../test/functional/SaslMechanisms.java | 2 +- .../client/test/functional/TTLHandling.java | 2 +- .../client/test/functional/Tables.java | 2 +- .../functional/TopologyRecoveryFiltering.java | 2 +- .../functional/TopologyRecoveryRetry.java | 2 +- .../client/test/functional/Transactions.java | 2 +- .../functional/UnbindAutoDeleteExchange.java | 2 +- .../test/functional/UnexpectedFrames.java | 2 +- .../client/test/functional/UserIDHeader.java | 2 +- .../client/test/server/AbsentQueue.java | 2 +- .../server/AlternateExchangeEquivalence.java | 2 +- .../client/test/server/BlockedConnection.java | 2 +- .../client/test/server/Bug19219Test.java | 2 +- .../test/server/ChannelLimitNegotiation.java | 2 +- .../server/DeadLetterExchangeDurable.java | 2 +- .../test/server/DurableBindingLifecycle.java | 2 +- .../server/EffectVisibilityCrossNodeTest.java | 2 +- .../test/server/ExclusiveQueueDurability.java | 2 +- .../rabbitmq/client/test/server/Firehose.java | 2 +- .../rabbitmq/client/test/server/HATests.java | 2 +- .../client/test/server/LoopbackUsers.java | 2 +- .../client/test/server/MemoryAlarms.java | 2 +- .../client/test/server/MessageRecovery.java | 2 +- .../client/test/server/Permissions.java | 2 +- .../test/server/PersistenceGuarantees.java | 2 +- .../client/test/server/PriorityQueues.java | 2 +- .../client/test/server/ServerTests.java | 2 +- .../rabbitmq/client/test/server/Shutdown.java | 2 +- .../client/test/server/TopicPermissions.java | 2 +- .../test/server/XDeathHeaderGrowth.java | 2 +- .../test/ssl/BadVerifiedConnection.java | 2 +- .../ConnectionFactoryDefaultTlsVersion.java | 2 +- .../client/test/ssl/HostnameVerification.java | 2 +- .../test/ssl/NioTlsUnverifiedConnection.java | 2 +- .../rabbitmq/client/test/ssl/SSLTests.java | 2 +- .../client/test/ssl/TlsConnectionLogging.java | 2 +- .../client/test/ssl/UnverifiedConnection.java | 2 +- .../client/test/ssl/VerifiedConnection.java | 2 +- src/test/java/com/rabbitmq/tools/Host.java | 2 +- .../rabbitmq/utility/IntAllocatorTests.java | 2 +- 343 files changed, 717 insertions(+), 811 deletions(-) diff --git a/LICENSE b/LICENSE index dc3c875662..53599f221a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,5 @@ This package, the RabbitMQ Java client library, is triple-licensed under -the Mozilla Public License 1.1 ("MPL"), the GNU General Public License +the Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, please see LICENSE-APACHE2. diff --git a/LICENSE-MPL-RabbitMQ b/LICENSE-MPL-RabbitMQ index 50770c2540..14e2f777f6 100644 --- a/LICENSE-MPL-RabbitMQ +++ b/LICENSE-MPL-RabbitMQ @@ -1,467 +1,373 @@ - MOZILLA PUBLIC LICENSE - Version 1.1 - - --------------- - -1. Definitions. - - 1.0.1. "Commercial Use" means distribution or otherwise making the - Covered Code available to a third party. - - 1.1. "Contributor" means each entity that creates or contributes to - the creation of Modifications. - - 1.2. "Contributor Version" means the combination of the Original - Code, prior Modifications used by a Contributor, and the Modifications - made by that particular Contributor. - - 1.3. "Covered Code" means the Original Code or Modifications or the - combination of the Original Code and Modifications, in each case - including portions thereof. - - 1.4. "Electronic Distribution Mechanism" means a mechanism generally - accepted in the software development community for the electronic - transfer of data. - - 1.5. "Executable" means Covered Code in any form other than Source - Code. - - 1.6. "Initial Developer" means the individual or entity identified - as the Initial Developer in the Source Code notice required by Exhibit - A. - - 1.7. "Larger Work" means a work which combines Covered Code or - portions thereof with code not governed by the terms of this License. - - 1.8. "License" means this document. - - 1.8.1. "Licensable" means having the right to grant, to the maximum - extent possible, whether at the time of the initial grant or - subsequently acquired, any and all of the rights conveyed herein. - - 1.9. "Modifications" means any addition to or deletion from the - substance or structure of either the Original Code or any previous - Modifications. When Covered Code is released as a series of files, a - Modification is: - A. Any addition to or deletion from the contents of a file - containing Original Code or previous Modifications. - - B. Any new file that contains any part of the Original Code or - previous Modifications. - - 1.10. "Original Code" means Source Code of computer software code - which is described in the Source Code notice required by Exhibit A as - Original Code, and which, at the time of its release under this - License is not already Covered Code governed by this License. - - 1.10.1. "Patent Claims" means any patent claim(s), now owned or - hereafter acquired, including without limitation, method, process, - and apparatus claims, in any patent Licensable by grantor. - - 1.11. "Source Code" means the preferred form of the Covered Code for - making modifications to it, including all modules it contains, plus - any associated interface definition files, scripts used to control - compilation and installation of an Executable, or source code - differential comparisons against either the Original Code or another - well known, available Covered Code of the Contributor's choice. The - Source Code can be in a compressed or archival form, provided the - appropriate decompression or de-archiving software is widely available - for no charge. - - 1.12. "You" (or "Your") means an individual or a legal entity - exercising rights under, and complying with all of the terms of, this - License or a future version of this License issued under Section 6.1. - For legal entities, "You" includes any entity which controls, is - controlled by, or is under common control with You. For purposes of - this definition, "control" means (a) the power, direct or indirect, - to cause the direction or management of such entity, whether by - contract or otherwise, or (b) ownership of more than fifty percent - (50%) of the outstanding shares or beneficial ownership of such - entity. - -2. Source Code License. - - 2.1. The Initial Developer Grant. - The Initial Developer hereby grants You a world-wide, royalty-free, - non-exclusive license, subject to third party intellectual property - claims: - (a) under intellectual property rights (other than patent or - trademark) Licensable by Initial Developer to use, reproduce, - modify, display, perform, sublicense and distribute the Original - Code (or portions thereof) with or without Modifications, and/or - as part of a Larger Work; and - - (b) under Patents Claims infringed by the making, using or - selling of Original Code, to make, have made, use, practice, - sell, and offer for sale, and/or otherwise dispose of the - Original Code (or portions thereof). - - (c) the licenses granted in this Section 2.1(a) and (b) are - effective on the date Initial Developer first distributes - Original Code under the terms of this License. - - (d) Notwithstanding Section 2.1(b) above, no patent license is - granted: 1) for code that You delete from the Original Code; 2) - separate from the Original Code; or 3) for infringements caused - by: i) the modification of the Original Code or ii) the - combination of the Original Code with other software or devices. - - 2.2. Contributor Grant. - Subject to third party intellectual property claims, each Contributor - hereby grants You a world-wide, royalty-free, non-exclusive license - - (a) under intellectual property rights (other than patent or - trademark) Licensable by Contributor, to use, reproduce, modify, - display, perform, sublicense and distribute the Modifications - created by such Contributor (or portions thereof) either on an - unmodified basis, with other Modifications, as Covered Code - and/or as part of a Larger Work; and - - (b) under Patent Claims infringed by the making, using, or - selling of Modifications made by that Contributor either alone - and/or in combination with its Contributor Version (or portions - of such combination), to make, use, sell, offer for sale, have - made, and/or otherwise dispose of: 1) Modifications made by that - Contributor (or portions thereof); and 2) the combination of - Modifications made by that Contributor with its Contributor - Version (or portions of such combination). - - (c) the licenses granted in Sections 2.2(a) and 2.2(b) are - effective on the date Contributor first makes Commercial Use of - the Covered Code. - - (d) Notwithstanding Section 2.2(b) above, no patent license is - granted: 1) for any code that Contributor has deleted from the - Contributor Version; 2) separate from the Contributor Version; - 3) for infringements caused by: i) third party modifications of - Contributor Version or ii) the combination of Modifications made - by that Contributor with other software (except as part of the - Contributor Version) or other devices; or 4) under Patent Claims - infringed by Covered Code in the absence of Modifications made by - that Contributor. - -3. Distribution Obligations. - - 3.1. Application of License. - The Modifications which You create or to which You contribute are - governed by the terms of this License, including without limitation - Section 2.2. The Source Code version of Covered Code may be - distributed only under the terms of this License or a future version - of this License released under Section 6.1, and You must include a - copy of this License with every copy of the Source Code You - distribute. You may not offer or impose any terms on any Source Code - version that alters or restricts the applicable version of this - License or the recipients' rights hereunder. However, You may include - an additional document offering the additional rights described in - Section 3.5. - - 3.2. Availability of Source Code. - Any Modification which You create or to which You contribute must be - made available in Source Code form under the terms of this License - either on the same media as an Executable version or via an accepted - Electronic Distribution Mechanism to anyone to whom you made an - Executable version available; and if made available via Electronic - Distribution Mechanism, must remain available for at least twelve (12) - months after the date it initially became available, or at least six - (6) months after a subsequent version of that particular Modification - has been made available to such recipients. You are responsible for - ensuring that the Source Code version remains available even if the - Electronic Distribution Mechanism is maintained by a third party. - - 3.3. Description of Modifications. - You must cause all Covered Code to which You contribute to contain a - file documenting the changes You made to create that Covered Code and - the date of any change. You must include a prominent statement that - the Modification is derived, directly or indirectly, from Original - Code provided by the Initial Developer and including the name of the - Initial Developer in (a) the Source Code, and (b) in any notice in an - Executable version or related documentation in which You describe the - origin or ownership of the Covered Code. - - 3.4. Intellectual Property Matters - (a) Third Party Claims. - If Contributor has knowledge that a license under a third party's - intellectual property rights is required to exercise the rights - granted by such Contributor under Sections 2.1 or 2.2, - Contributor must include a text file with the Source Code - distribution titled "LEGAL" which describes the claim and the - party making the claim in sufficient detail that a recipient will - know whom to contact. If Contributor obtains such knowledge after - the Modification is made available as described in Section 3.2, - Contributor shall promptly modify the LEGAL file in all copies - Contributor makes available thereafter and shall take other steps - (such as notifying appropriate mailing lists or newsgroups) - reasonably calculated to inform those who received the Covered - Code that new knowledge has been obtained. - - (b) Contributor APIs. - If Contributor's Modifications include an application programming - interface and Contributor has knowledge of patent licenses which - are reasonably necessary to implement that API, Contributor must - also include this information in the LEGAL file. - - (c) Representations. - Contributor represents that, except as disclosed pursuant to - Section 3.4(a) above, Contributor believes that Contributor's - Modifications are Contributor's original creation(s) and/or - Contributor has sufficient rights to grant the rights conveyed by - this License. - - 3.5. Required Notices. - You must duplicate the notice in Exhibit A in each file of the Source - Code. If it is not possible to put such notice in a particular Source - Code file due to its structure, then You must include such notice in a - location (such as a relevant directory) where a user would be likely - to look for such a notice. If You created one or more Modification(s) - You may add your name as a Contributor to the notice described in - Exhibit A. You must also duplicate this License in any documentation - for the Source Code where You describe recipients' rights or ownership - rights relating to Covered Code. You may choose to offer, and to - charge a fee for, warranty, support, indemnity or liability - obligations to one or more recipients of Covered Code. However, You - may do so only on Your own behalf, and not on behalf of the Initial - Developer or any Contributor. You must make it absolutely clear than - any such warranty, support, indemnity or liability obligation is - offered by You alone, and You hereby agree to indemnify the Initial - Developer and every Contributor for any liability incurred by the - Initial Developer or such Contributor as a result of warranty, - support, indemnity or liability terms You offer. - - 3.6. Distribution of Executable Versions. - You may distribute Covered Code in Executable form only if the - requirements of Section 3.1-3.5 have been met for that Covered Code, - and if You include a notice stating that the Source Code version of - the Covered Code is available under the terms of this License, - including a description of how and where You have fulfilled the - obligations of Section 3.2. The notice must be conspicuously included - in any notice in an Executable version, related documentation or - collateral in which You describe recipients' rights relating to the - Covered Code. You may distribute the Executable version of Covered - Code or ownership rights under a license of Your choice, which may - contain terms different from this License, provided that You are in - compliance with the terms of this License and that the license for the - Executable version does not attempt to limit or alter the recipient's - rights in the Source Code version from the rights set forth in this - License. If You distribute the Executable version under a different - license You must make it absolutely clear that any terms which differ - from this License are offered by You alone, not by the Initial - Developer or any Contributor. You hereby agree to indemnify the - Initial Developer and every Contributor for any liability incurred by - the Initial Developer or such Contributor as a result of any such - terms You offer. - - 3.7. Larger Works. - You may create a Larger Work by combining Covered Code with other code - not governed by the terms of this License and distribute the Larger - Work as a single product. In such a case, You must make sure the - requirements of this License are fulfilled for the Covered Code. - -4. Inability to Comply Due to Statute or Regulation. - - If it is impossible for You to comply with any of the terms of this - License with respect to some or all of the Covered Code due to - statute, judicial order, or regulation then You must: (a) comply with - the terms of this License to the maximum extent possible; and (b) - describe the limitations and the code they affect. Such description - must be included in the LEGAL file described in Section 3.4 and must - be included with all distributions of the Source Code. Except to the - extent prohibited by statute or regulation, such description must be - sufficiently detailed for a recipient of ordinary skill to be able to - understand it. - -5. Application of this License. - - This License applies to code to which the Initial Developer has - attached the notice in Exhibit A and to related Covered Code. - -6. Versions of the License. - - 6.1. New Versions. - Netscape Communications Corporation ("Netscape") may publish revised - and/or new versions of the License from time to time. Each version - will be given a distinguishing version number. - - 6.2. Effect of New Versions. - Once Covered Code has been published under a particular version of the - License, You may always continue to use it under the terms of that - version. You may also choose to use such Covered Code under the terms - of any subsequent version of the License published by Netscape. No one - other than Netscape has the right to modify the terms applicable to - Covered Code created under this License. - - 6.3. Derivative Works. - If You create or use a modified version of this License (which you may - only do in order to apply it to code which is not already Covered Code - governed by this License), You must (a) rename Your license so that - the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape", - "MPL", "NPL" or any confusingly similar phrase do not appear in your - license (except to note that your license differs from this License) - and (b) otherwise make it clear that Your version of the license - contains terms which differ from the Mozilla Public License and - Netscape Public License. (Filling in the name of the Initial - Developer, Original Code or Contributor in the notice described in - Exhibit A shall not of themselves be deemed to be modifications of - this License.) - -7. DISCLAIMER OF WARRANTY. - - COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, - WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF - DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. - THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE - IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, - YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE - COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER - OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF - ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. - -8. TERMINATION. - - 8.1. This License and the rights granted hereunder will terminate - automatically if You fail to comply with terms herein and fail to cure - such breach within 30 days of becoming aware of the breach. All - sublicenses to the Covered Code which are properly granted shall - survive any termination of this License. Provisions which, by their - nature, must remain in effect beyond the termination of this License - shall survive. - - 8.2. If You initiate litigation by asserting a patent infringement - claim (excluding declatory judgment actions) against Initial Developer - or a Contributor (the Initial Developer or Contributor against whom - You file such action is referred to as "Participant") alleging that: - - (a) such Participant's Contributor Version directly or indirectly - infringes any patent, then any and all rights granted by such - Participant to You under Sections 2.1 and/or 2.2 of this License - shall, upon 60 days notice from Participant terminate prospectively, - unless if within 60 days after receipt of notice You either: (i) - agree in writing to pay Participant a mutually agreeable reasonable - royalty for Your past and future use of Modifications made by such - Participant, or (ii) withdraw Your litigation claim with respect to - the Contributor Version against such Participant. If within 60 days - of notice, a reasonable royalty and payment arrangement are not - mutually agreed upon in writing by the parties or the litigation claim - is not withdrawn, the rights granted by Participant to You under - Sections 2.1 and/or 2.2 automatically terminate at the expiration of - the 60 day notice period specified above. - - (b) any software, hardware, or device, other than such Participant's - Contributor Version, directly or indirectly infringes any patent, then - any rights granted to You by such Participant under Sections 2.1(b) - and 2.2(b) are revoked effective as of the date You first made, used, - sold, distributed, or had made, Modifications made by that - Participant. - - 8.3. If You assert a patent infringement claim against Participant - alleging that such Participant's Contributor Version directly or - indirectly infringes any patent where such claim is resolved (such as - by license or settlement) prior to the initiation of patent - infringement litigation, then the reasonable value of the licenses - granted by such Participant under Sections 2.1 or 2.2 shall be taken - into account in determining the amount or value of any payment or - license. - - 8.4. In the event of termination under Sections 8.1 or 8.2 above, - all end user license agreements (excluding distributors and resellers) - which have been validly granted by You or any distributor hereunder - prior to termination shall survive termination. - -9. LIMITATION OF LIABILITY. - - UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT - (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL - DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE, - OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR - ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY - CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, - WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER - COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN - INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF - LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY - RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW - PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE - EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO - THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. - -10. U.S. GOVERNMENT END USERS. - - The Covered Code is a "commercial item," as that term is defined in - 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer - software" and "commercial computer software documentation," as such - terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 - C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), - all U.S. Government End Users acquire Covered Code with only those - rights set forth herein. - -11. MISCELLANEOUS. - - This License represents the complete agreement concerning subject - matter hereof. If any provision of this License is held to be - unenforceable, such provision shall be reformed only to the extent - necessary to make it enforceable. This License shall be governed by - California law provisions (except to the extent applicable law, if - any, provides otherwise), excluding its conflict-of-law provisions. - With respect to disputes in which at least one party is a citizen of, - or an entity chartered or registered to do business in the United - States of America, any litigation relating to this License shall be - subject to the jurisdiction of the Federal Courts of the Northern - District of California, with venue lying in Santa Clara County, - California, with the losing party responsible for costs, including - without limitation, court costs and reasonable attorneys' fees and - expenses. The application of the United Nations Convention on - Contracts for the International Sale of Goods is expressly excluded. - Any law or regulation which provides that the language of a contract - shall be construed against the drafter shall not apply to this - License. - -12. RESPONSIBILITY FOR CLAIMS. - - As between Initial Developer and the Contributors, each party is - responsible for claims and damages arising, directly or indirectly, - out of its utilization of rights under this License and You agree to - work with Initial Developer and Contributors to distribute such - responsibility on an equitable basis. Nothing herein is intended or - shall be deemed to constitute any admission of liability. - -13. MULTIPLE-LICENSED CODE. - - Initial Developer may designate portions of the Covered Code as - "Multiple-Licensed". "Multiple-Licensed" means that the Initial - Developer permits you to utilize portions of the Covered Code under - Your choice of the MPL or the alternative licenses, if any, specified - by the Initial Developer in the file described in Exhibit A. - -EXHIBIT A -Mozilla Public License. - - ``The contents of this file are subject to the Mozilla Public License - Version 1.1 (the "License"); you may not use this file except in - compliance with the License. You may obtain a copy of the License at - https://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - License for the specific language governing rights and limitations - under the License. - - The Original Code is RabbitMQ. - - The Initial Developer of the Original Code is GoPivotal, Inc. - Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. - - Alternatively, the contents of this file may be used under the terms - of the GNU General Public License version 2 (the "GPL2"), or - the Apache License version 2 (the "ASL2") in which case the - provisions of GPL2 or the ASL2 are applicable instead of those - above. If you wish to allow use of your version of this file only - under the terms of the GPL2 or the ASL2 and not to allow others to use - your version of this file under the MPL, indicate your decision by - deleting the provisions above and replace them with the notice and - other provisions required by the GPL2 or the ASL2. If you do not delete - the provisions above, a recipient may use your version of this file - under either the MPL, the GPL2 or the ASL2.'' - - [NOTE: The text of this Exhibit A may differ slightly from the text of - the notices in the Source Code files of the Original Code. You should - use the text of this Exhibit A rather than the text found in the - Original Code Source Code for Your Modifications.] +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/README.md b/README.md index a714be9ec6..826f1837af 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ for the support timeline of this library. ## License This package, the RabbitMQ Java client library, is [triple-licensed](https://www.rabbitmq.com/api-guide.html#license) under -the Mozilla Public License 1.1 ("MPL"), the GNU General Public License +the Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 ("GPL") and the Apache License version 2 ("ASL"). This means that the user can consider the library to be licensed under **any of the licenses from the list** above. diff --git a/codegen.py b/codegen.py index 42c577a0d9..42e29eaab1 100755 --- a/codegen.py +++ b/codegen.py @@ -3,7 +3,7 @@ ## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. ## ## This software, the RabbitMQ Java client library, is triple-licensed under the -## Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +## Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 ## ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see ## LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, ## please see LICENSE-APACHE2. @@ -133,7 +133,7 @@ def printFileHeader(): // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/Address.java b/src/main/java/com/rabbitmq/client/Address.java index 26b9cd9d3e..394f5e7b60 100644 --- a/src/main/java/com/rabbitmq/client/Address.java +++ b/src/main/java/com/rabbitmq/client/Address.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/AddressResolver.java b/src/main/java/com/rabbitmq/client/AddressResolver.java index 4a4f0d8461..8350bac153 100644 --- a/src/main/java/com/rabbitmq/client/AddressResolver.java +++ b/src/main/java/com/rabbitmq/client/AddressResolver.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/AlreadyClosedException.java b/src/main/java/com/rabbitmq/client/AlreadyClosedException.java index 37060907f9..69a000847e 100644 --- a/src/main/java/com/rabbitmq/client/AlreadyClosedException.java +++ b/src/main/java/com/rabbitmq/client/AlreadyClosedException.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/AuthenticationFailureException.java b/src/main/java/com/rabbitmq/client/AuthenticationFailureException.java index 391be6d039..56f26561ca 100644 --- a/src/main/java/com/rabbitmq/client/AuthenticationFailureException.java +++ b/src/main/java/com/rabbitmq/client/AuthenticationFailureException.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/BasicProperties.java b/src/main/java/com/rabbitmq/client/BasicProperties.java index 4001508cfb..9a0b953698 100644 --- a/src/main/java/com/rabbitmq/client/BasicProperties.java +++ b/src/main/java/com/rabbitmq/client/BasicProperties.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/BlockedCallback.java b/src/main/java/com/rabbitmq/client/BlockedCallback.java index f679e79427..d9e22fbe88 100644 --- a/src/main/java/com/rabbitmq/client/BlockedCallback.java +++ b/src/main/java/com/rabbitmq/client/BlockedCallback.java @@ -1,7 +1,7 @@ // Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/BlockedListener.java b/src/main/java/com/rabbitmq/client/BlockedListener.java index 4e0f820615..521f8d19cd 100644 --- a/src/main/java/com/rabbitmq/client/BlockedListener.java +++ b/src/main/java/com/rabbitmq/client/BlockedListener.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/CancelCallback.java b/src/main/java/com/rabbitmq/client/CancelCallback.java index ee6df1964a..419f34a4bd 100644 --- a/src/main/java/com/rabbitmq/client/CancelCallback.java +++ b/src/main/java/com/rabbitmq/client/CancelCallback.java @@ -1,7 +1,7 @@ // Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/Channel.java b/src/main/java/com/rabbitmq/client/Channel.java index f6c1c240d4..5ed6ba2ab6 100644 --- a/src/main/java/com/rabbitmq/client/Channel.java +++ b/src/main/java/com/rabbitmq/client/Channel.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/Command.java b/src/main/java/com/rabbitmq/client/Command.java index 2630773ecc..dad5c6aa64 100644 --- a/src/main/java/com/rabbitmq/client/Command.java +++ b/src/main/java/com/rabbitmq/client/Command.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/ConfirmCallback.java b/src/main/java/com/rabbitmq/client/ConfirmCallback.java index 41197874e3..e02355f957 100644 --- a/src/main/java/com/rabbitmq/client/ConfirmCallback.java +++ b/src/main/java/com/rabbitmq/client/ConfirmCallback.java @@ -1,7 +1,7 @@ // Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/ConfirmListener.java b/src/main/java/com/rabbitmq/client/ConfirmListener.java index 51162d9baf..50f25ad2c3 100644 --- a/src/main/java/com/rabbitmq/client/ConfirmListener.java +++ b/src/main/java/com/rabbitmq/client/ConfirmListener.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/Connection.java b/src/main/java/com/rabbitmq/client/Connection.java index d45c1b90ea..5004ac9372 100644 --- a/src/main/java/com/rabbitmq/client/Connection.java +++ b/src/main/java/com/rabbitmq/client/Connection.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 22d468432e..195b3af2a8 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java b/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java index 9cd9c7ee31..d59770380e 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java @@ -1,7 +1,7 @@ // Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/Consumer.java b/src/main/java/com/rabbitmq/client/Consumer.java index 118ce0a8f3..cb57e9d956 100644 --- a/src/main/java/com/rabbitmq/client/Consumer.java +++ b/src/main/java/com/rabbitmq/client/Consumer.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/ConsumerCancelledException.java b/src/main/java/com/rabbitmq/client/ConsumerCancelledException.java index 7078cfcf99..44495fceb4 100644 --- a/src/main/java/com/rabbitmq/client/ConsumerCancelledException.java +++ b/src/main/java/com/rabbitmq/client/ConsumerCancelledException.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/ConsumerShutdownSignalCallback.java b/src/main/java/com/rabbitmq/client/ConsumerShutdownSignalCallback.java index fb055dde7e..0fe41694a4 100644 --- a/src/main/java/com/rabbitmq/client/ConsumerShutdownSignalCallback.java +++ b/src/main/java/com/rabbitmq/client/ConsumerShutdownSignalCallback.java @@ -1,7 +1,7 @@ // Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/ContentHeader.java b/src/main/java/com/rabbitmq/client/ContentHeader.java index ddb7d52b14..ff3f0f0a1e 100644 --- a/src/main/java/com/rabbitmq/client/ContentHeader.java +++ b/src/main/java/com/rabbitmq/client/ContentHeader.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/DefaultConsumer.java b/src/main/java/com/rabbitmq/client/DefaultConsumer.java index 0e1670d39a..b2b4644b3c 100644 --- a/src/main/java/com/rabbitmq/client/DefaultConsumer.java +++ b/src/main/java/com/rabbitmq/client/DefaultConsumer.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/DefaultSaslConfig.java b/src/main/java/com/rabbitmq/client/DefaultSaslConfig.java index 62ac85c4c1..0e4de02da1 100644 --- a/src/main/java/com/rabbitmq/client/DefaultSaslConfig.java +++ b/src/main/java/com/rabbitmq/client/DefaultSaslConfig.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/DefaultSocketChannelConfigurator.java b/src/main/java/com/rabbitmq/client/DefaultSocketChannelConfigurator.java index 38494da70e..470bd6f940 100644 --- a/src/main/java/com/rabbitmq/client/DefaultSocketChannelConfigurator.java +++ b/src/main/java/com/rabbitmq/client/DefaultSocketChannelConfigurator.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/DefaultSocketConfigurator.java b/src/main/java/com/rabbitmq/client/DefaultSocketConfigurator.java index 0c3118e049..57732f45c3 100644 --- a/src/main/java/com/rabbitmq/client/DefaultSocketConfigurator.java +++ b/src/main/java/com/rabbitmq/client/DefaultSocketConfigurator.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/DeliverCallback.java b/src/main/java/com/rabbitmq/client/DeliverCallback.java index 8e17dfb407..4760c7be1a 100644 --- a/src/main/java/com/rabbitmq/client/DeliverCallback.java +++ b/src/main/java/com/rabbitmq/client/DeliverCallback.java @@ -1,7 +1,7 @@ // Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/Delivery.java b/src/main/java/com/rabbitmq/client/Delivery.java index 3e99f20974..91c36ffa3d 100644 --- a/src/main/java/com/rabbitmq/client/Delivery.java +++ b/src/main/java/com/rabbitmq/client/Delivery.java @@ -1,7 +1,7 @@ // Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/DnsRecordIpAddressResolver.java b/src/main/java/com/rabbitmq/client/DnsRecordIpAddressResolver.java index fb28f16a41..2f9ce570a4 100644 --- a/src/main/java/com/rabbitmq/client/DnsRecordIpAddressResolver.java +++ b/src/main/java/com/rabbitmq/client/DnsRecordIpAddressResolver.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/DnsSrvRecordAddressResolver.java b/src/main/java/com/rabbitmq/client/DnsSrvRecordAddressResolver.java index 81775fc9f6..5c340c3347 100644 --- a/src/main/java/com/rabbitmq/client/DnsSrvRecordAddressResolver.java +++ b/src/main/java/com/rabbitmq/client/DnsSrvRecordAddressResolver.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/Envelope.java b/src/main/java/com/rabbitmq/client/Envelope.java index cc8e7ceda1..d8164f050d 100644 --- a/src/main/java/com/rabbitmq/client/Envelope.java +++ b/src/main/java/com/rabbitmq/client/Envelope.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/ExceptionHandler.java b/src/main/java/com/rabbitmq/client/ExceptionHandler.java index 3ed8183f28..90c982d11e 100644 --- a/src/main/java/com/rabbitmq/client/ExceptionHandler.java +++ b/src/main/java/com/rabbitmq/client/ExceptionHandler.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/GetResponse.java b/src/main/java/com/rabbitmq/client/GetResponse.java index ba157a0fb9..83ea3bc991 100644 --- a/src/main/java/com/rabbitmq/client/GetResponse.java +++ b/src/main/java/com/rabbitmq/client/GetResponse.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/JDKSaslConfig.java b/src/main/java/com/rabbitmq/client/JDKSaslConfig.java index d8a240a30e..e39beb2eec 100644 --- a/src/main/java/com/rabbitmq/client/JDKSaslConfig.java +++ b/src/main/java/com/rabbitmq/client/JDKSaslConfig.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/ListAddressResolver.java b/src/main/java/com/rabbitmq/client/ListAddressResolver.java index a7b3d96657..e04eaa4431 100644 --- a/src/main/java/com/rabbitmq/client/ListAddressResolver.java +++ b/src/main/java/com/rabbitmq/client/ListAddressResolver.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/LongString.java b/src/main/java/com/rabbitmq/client/LongString.java index 447ef1e510..3b091b98fc 100644 --- a/src/main/java/com/rabbitmq/client/LongString.java +++ b/src/main/java/com/rabbitmq/client/LongString.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/MalformedFrameException.java b/src/main/java/com/rabbitmq/client/MalformedFrameException.java index ae799f0f5d..a05dc95928 100644 --- a/src/main/java/com/rabbitmq/client/MalformedFrameException.java +++ b/src/main/java/com/rabbitmq/client/MalformedFrameException.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/MapRpcServer.java b/src/main/java/com/rabbitmq/client/MapRpcServer.java index 93ceaa10fe..5a65fe3126 100644 --- a/src/main/java/com/rabbitmq/client/MapRpcServer.java +++ b/src/main/java/com/rabbitmq/client/MapRpcServer.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/MessageProperties.java b/src/main/java/com/rabbitmq/client/MessageProperties.java index 8369eeb645..bd7b6cd71c 100644 --- a/src/main/java/com/rabbitmq/client/MessageProperties.java +++ b/src/main/java/com/rabbitmq/client/MessageProperties.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/Method.java b/src/main/java/com/rabbitmq/client/Method.java index bd7b8531e7..d6aa573ce0 100644 --- a/src/main/java/com/rabbitmq/client/Method.java +++ b/src/main/java/com/rabbitmq/client/Method.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/MetricsCollector.java b/src/main/java/com/rabbitmq/client/MetricsCollector.java index edaa64e13f..4e636767ce 100644 --- a/src/main/java/com/rabbitmq/client/MetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/MetricsCollector.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/MissedHeartbeatException.java b/src/main/java/com/rabbitmq/client/MissedHeartbeatException.java index 83400d2db5..ef3bf5335d 100644 --- a/src/main/java/com/rabbitmq/client/MissedHeartbeatException.java +++ b/src/main/java/com/rabbitmq/client/MissedHeartbeatException.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java b/src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java index f70e658aed..f744de5ddb 100644 --- a/src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/PossibleAuthenticationFailureException.java b/src/main/java/com/rabbitmq/client/PossibleAuthenticationFailureException.java index d6cca886db..9c8876d8e4 100644 --- a/src/main/java/com/rabbitmq/client/PossibleAuthenticationFailureException.java +++ b/src/main/java/com/rabbitmq/client/PossibleAuthenticationFailureException.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/ProtocolVersionMismatchException.java b/src/main/java/com/rabbitmq/client/ProtocolVersionMismatchException.java index 8cd857545b..e15e5873e3 100644 --- a/src/main/java/com/rabbitmq/client/ProtocolVersionMismatchException.java +++ b/src/main/java/com/rabbitmq/client/ProtocolVersionMismatchException.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/Recoverable.java b/src/main/java/com/rabbitmq/client/Recoverable.java index c4b066f66c..30d68992ba 100644 --- a/src/main/java/com/rabbitmq/client/Recoverable.java +++ b/src/main/java/com/rabbitmq/client/Recoverable.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/RecoveryDelayHandler.java b/src/main/java/com/rabbitmq/client/RecoveryDelayHandler.java index e00c7d3940..84a2d577e7 100644 --- a/src/main/java/com/rabbitmq/client/RecoveryDelayHandler.java +++ b/src/main/java/com/rabbitmq/client/RecoveryDelayHandler.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/RecoveryListener.java b/src/main/java/com/rabbitmq/client/RecoveryListener.java index 968b828521..a3374414e2 100644 --- a/src/main/java/com/rabbitmq/client/RecoveryListener.java +++ b/src/main/java/com/rabbitmq/client/RecoveryListener.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/Return.java b/src/main/java/com/rabbitmq/client/Return.java index f441a69873..d25532b773 100644 --- a/src/main/java/com/rabbitmq/client/Return.java +++ b/src/main/java/com/rabbitmq/client/Return.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/ReturnCallback.java b/src/main/java/com/rabbitmq/client/ReturnCallback.java index 1eb1c99271..efa3ad6065 100644 --- a/src/main/java/com/rabbitmq/client/ReturnCallback.java +++ b/src/main/java/com/rabbitmq/client/ReturnCallback.java @@ -1,7 +1,7 @@ // Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/ReturnListener.java b/src/main/java/com/rabbitmq/client/ReturnListener.java index 2ec72fbc15..5f45f84ef4 100644 --- a/src/main/java/com/rabbitmq/client/ReturnListener.java +++ b/src/main/java/com/rabbitmq/client/ReturnListener.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/RpcClient.java b/src/main/java/com/rabbitmq/client/RpcClient.java index 50b7c895c1..17b9d3259f 100644 --- a/src/main/java/com/rabbitmq/client/RpcClient.java +++ b/src/main/java/com/rabbitmq/client/RpcClient.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/RpcClientParams.java b/src/main/java/com/rabbitmq/client/RpcClientParams.java index ea1ab30d87..190792250f 100644 --- a/src/main/java/com/rabbitmq/client/RpcClientParams.java +++ b/src/main/java/com/rabbitmq/client/RpcClientParams.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/RpcServer.java b/src/main/java/com/rabbitmq/client/RpcServer.java index a1bc413c50..426c8d749f 100644 --- a/src/main/java/com/rabbitmq/client/RpcServer.java +++ b/src/main/java/com/rabbitmq/client/RpcServer.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/SaslConfig.java b/src/main/java/com/rabbitmq/client/SaslConfig.java index d8555cf6b2..5042f2c16f 100644 --- a/src/main/java/com/rabbitmq/client/SaslConfig.java +++ b/src/main/java/com/rabbitmq/client/SaslConfig.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/SaslMechanism.java b/src/main/java/com/rabbitmq/client/SaslMechanism.java index d411f2072e..9a11b5a27f 100644 --- a/src/main/java/com/rabbitmq/client/SaslMechanism.java +++ b/src/main/java/com/rabbitmq/client/SaslMechanism.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/ShutdownListener.java b/src/main/java/com/rabbitmq/client/ShutdownListener.java index 5a2427334f..9775e454b0 100644 --- a/src/main/java/com/rabbitmq/client/ShutdownListener.java +++ b/src/main/java/com/rabbitmq/client/ShutdownListener.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/ShutdownNotifier.java b/src/main/java/com/rabbitmq/client/ShutdownNotifier.java index 66aa021d7a..9c1e3e8bfc 100644 --- a/src/main/java/com/rabbitmq/client/ShutdownNotifier.java +++ b/src/main/java/com/rabbitmq/client/ShutdownNotifier.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/ShutdownSignalException.java b/src/main/java/com/rabbitmq/client/ShutdownSignalException.java index 769158198d..24be455978 100644 --- a/src/main/java/com/rabbitmq/client/ShutdownSignalException.java +++ b/src/main/java/com/rabbitmq/client/ShutdownSignalException.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/SocketChannelConfigurator.java b/src/main/java/com/rabbitmq/client/SocketChannelConfigurator.java index 43307caada..4571e707f9 100644 --- a/src/main/java/com/rabbitmq/client/SocketChannelConfigurator.java +++ b/src/main/java/com/rabbitmq/client/SocketChannelConfigurator.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/SocketChannelConfigurators.java b/src/main/java/com/rabbitmq/client/SocketChannelConfigurators.java index 0355528b4e..711af1cf58 100644 --- a/src/main/java/com/rabbitmq/client/SocketChannelConfigurators.java +++ b/src/main/java/com/rabbitmq/client/SocketChannelConfigurators.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/SocketConfigurator.java b/src/main/java/com/rabbitmq/client/SocketConfigurator.java index 8a49c57d96..151f572461 100644 --- a/src/main/java/com/rabbitmq/client/SocketConfigurator.java +++ b/src/main/java/com/rabbitmq/client/SocketConfigurator.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/SocketConfigurators.java b/src/main/java/com/rabbitmq/client/SocketConfigurators.java index dda986d36b..08220dfb67 100644 --- a/src/main/java/com/rabbitmq/client/SocketConfigurators.java +++ b/src/main/java/com/rabbitmq/client/SocketConfigurators.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/SslContextFactory.java b/src/main/java/com/rabbitmq/client/SslContextFactory.java index 468c1237cd..0b285a9bf9 100644 --- a/src/main/java/com/rabbitmq/client/SslContextFactory.java +++ b/src/main/java/com/rabbitmq/client/SslContextFactory.java @@ -1,7 +1,7 @@ // Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/SslEngineConfigurator.java b/src/main/java/com/rabbitmq/client/SslEngineConfigurator.java index 6f95bb392a..0ed04182f3 100644 --- a/src/main/java/com/rabbitmq/client/SslEngineConfigurator.java +++ b/src/main/java/com/rabbitmq/client/SslEngineConfigurator.java @@ -1,7 +1,7 @@ // Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/SslEngineConfigurators.java b/src/main/java/com/rabbitmq/client/SslEngineConfigurators.java index 0cb7b451d7..6e8ca36589 100644 --- a/src/main/java/com/rabbitmq/client/SslEngineConfigurators.java +++ b/src/main/java/com/rabbitmq/client/SslEngineConfigurators.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/StringRpcServer.java b/src/main/java/com/rabbitmq/client/StringRpcServer.java index 375079607a..d437cb28b4 100644 --- a/src/main/java/com/rabbitmq/client/StringRpcServer.java +++ b/src/main/java/com/rabbitmq/client/StringRpcServer.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/TopologyRecoveryException.java b/src/main/java/com/rabbitmq/client/TopologyRecoveryException.java index cf9d18d105..bdd8b7f807 100644 --- a/src/main/java/com/rabbitmq/client/TopologyRecoveryException.java +++ b/src/main/java/com/rabbitmq/client/TopologyRecoveryException.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/TrustEverythingTrustManager.java b/src/main/java/com/rabbitmq/client/TrustEverythingTrustManager.java index 9001d02507..e7913d048e 100644 --- a/src/main/java/com/rabbitmq/client/TrustEverythingTrustManager.java +++ b/src/main/java/com/rabbitmq/client/TrustEverythingTrustManager.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/UnblockedCallback.java b/src/main/java/com/rabbitmq/client/UnblockedCallback.java index 76ac083ac7..6d79423922 100644 --- a/src/main/java/com/rabbitmq/client/UnblockedCallback.java +++ b/src/main/java/com/rabbitmq/client/UnblockedCallback.java @@ -1,7 +1,7 @@ // Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/UnexpectedFrameError.java b/src/main/java/com/rabbitmq/client/UnexpectedFrameError.java index e8275aec3a..e15e449e5b 100644 --- a/src/main/java/com/rabbitmq/client/UnexpectedFrameError.java +++ b/src/main/java/com/rabbitmq/client/UnexpectedFrameError.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/UnexpectedMethodError.java b/src/main/java/com/rabbitmq/client/UnexpectedMethodError.java index ab30336a07..f5cde49379 100644 --- a/src/main/java/com/rabbitmq/client/UnexpectedMethodError.java +++ b/src/main/java/com/rabbitmq/client/UnexpectedMethodError.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/UnknownClassOrMethodId.java b/src/main/java/com/rabbitmq/client/UnknownClassOrMethodId.java index 1f0e3715f3..3ad973a7b6 100644 --- a/src/main/java/com/rabbitmq/client/UnknownClassOrMethodId.java +++ b/src/main/java/com/rabbitmq/client/UnknownClassOrMethodId.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/UnroutableRpcRequestException.java b/src/main/java/com/rabbitmq/client/UnroutableRpcRequestException.java index 89e9d059f0..1a2877e14a 100644 --- a/src/main/java/com/rabbitmq/client/UnroutableRpcRequestException.java +++ b/src/main/java/com/rabbitmq/client/UnroutableRpcRequestException.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/AMQBasicProperties.java b/src/main/java/com/rabbitmq/client/impl/AMQBasicProperties.java index 591713e706..54f312f06a 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQBasicProperties.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQBasicProperties.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java index 1314d89077..60e756de4b 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/AMQCommand.java b/src/main/java/com/rabbitmq/client/impl/AMQCommand.java index 0395bb10f6..b8cb3c97dd 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQCommand.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQCommand.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index 7c09e6900c..884be2a700 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/AMQContentHeader.java b/src/main/java/com/rabbitmq/client/impl/AMQContentHeader.java index 523336e0ca..e3bf4a479f 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQContentHeader.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQContentHeader.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java index 5599b3a0a4..e3edc917fc 100644 --- a/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/CRDemoMechanism.java b/src/main/java/com/rabbitmq/client/impl/CRDemoMechanism.java index e516750b6c..85f0d47cc4 100644 --- a/src/main/java/com/rabbitmq/client/impl/CRDemoMechanism.java +++ b/src/main/java/com/rabbitmq/client/impl/CRDemoMechanism.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelManager.java b/src/main/java/com/rabbitmq/client/impl/ChannelManager.java index 162c141f34..59f7bb3fee 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelManager.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelManager.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java index db4d9b86e3..8dc19f4ad6 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelN.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/ClientVersion.java b/src/main/java/com/rabbitmq/client/impl/ClientVersion.java index aae57e8a86..9fd29d86f9 100644 --- a/src/main/java/com/rabbitmq/client/impl/ClientVersion.java +++ b/src/main/java/com/rabbitmq/client/impl/ClientVersion.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/CommandAssembler.java b/src/main/java/com/rabbitmq/client/impl/CommandAssembler.java index 1be564eb81..d44df8d5c9 100644 --- a/src/main/java/com/rabbitmq/client/impl/CommandAssembler.java +++ b/src/main/java/com/rabbitmq/client/impl/CommandAssembler.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/CompletableFutureRpcWrapper.java b/src/main/java/com/rabbitmq/client/impl/CompletableFutureRpcWrapper.java index 1f1b91f569..2157e15d71 100644 --- a/src/main/java/com/rabbitmq/client/impl/CompletableFutureRpcWrapper.java +++ b/src/main/java/com/rabbitmq/client/impl/CompletableFutureRpcWrapper.java @@ -1,7 +1,7 @@ // Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java b/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java index 92428fc436..a2b49d0f98 100644 --- a/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java +++ b/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/ConsumerDispatcher.java b/src/main/java/com/rabbitmq/client/impl/ConsumerDispatcher.java index bb22d9f626..fec98710fe 100644 --- a/src/main/java/com/rabbitmq/client/impl/ConsumerDispatcher.java +++ b/src/main/java/com/rabbitmq/client/impl/ConsumerDispatcher.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/ConsumerWorkService.java b/src/main/java/com/rabbitmq/client/impl/ConsumerWorkService.java index bb662d98e7..b3810aae2f 100644 --- a/src/main/java/com/rabbitmq/client/impl/ConsumerWorkService.java +++ b/src/main/java/com/rabbitmq/client/impl/ConsumerWorkService.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java b/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java index d3502e9fe2..115c3ef520 100644 --- a/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java +++ b/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java b/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java index 59440bc7e7..029329a13d 100644 --- a/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java +++ b/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java index abcfb6af17..19b159df78 100644 --- a/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. @@ -63,4 +63,4 @@ default void refresh() { // no need to refresh anything by default } -} \ No newline at end of file +} diff --git a/src/main/java/com/rabbitmq/client/impl/CredentialsRefreshService.java b/src/main/java/com/rabbitmq/client/impl/CredentialsRefreshService.java index d365053af1..a490a61a5b 100644 --- a/src/main/java/com/rabbitmq/client/impl/CredentialsRefreshService.java +++ b/src/main/java/com/rabbitmq/client/impl/CredentialsRefreshService.java @@ -1,7 +1,7 @@ // Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java index 6263524898..eaf8a90c0c 100644 --- a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java index 2beafaad74..f4edeae391 100644 --- a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java +++ b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java @@ -1,7 +1,7 @@ // Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/DefaultExceptionHandler.java b/src/main/java/com/rabbitmq/client/impl/DefaultExceptionHandler.java index f1a0def2f3..f521a37c14 100644 --- a/src/main/java/com/rabbitmq/client/impl/DefaultExceptionHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/DefaultExceptionHandler.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/Environment.java b/src/main/java/com/rabbitmq/client/impl/Environment.java index c7f6c528b0..149b9a102e 100644 --- a/src/main/java/com/rabbitmq/client/impl/Environment.java +++ b/src/main/java/com/rabbitmq/client/impl/Environment.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/ErrorOnWriteListener.java b/src/main/java/com/rabbitmq/client/impl/ErrorOnWriteListener.java index 7edf05e994..dd9de0ce1c 100644 --- a/src/main/java/com/rabbitmq/client/impl/ErrorOnWriteListener.java +++ b/src/main/java/com/rabbitmq/client/impl/ErrorOnWriteListener.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/ExternalMechanism.java b/src/main/java/com/rabbitmq/client/impl/ExternalMechanism.java index 5cddc69ac4..e50a0c17c7 100644 --- a/src/main/java/com/rabbitmq/client/impl/ExternalMechanism.java +++ b/src/main/java/com/rabbitmq/client/impl/ExternalMechanism.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/ForgivingExceptionHandler.java b/src/main/java/com/rabbitmq/client/impl/ForgivingExceptionHandler.java index e4c2648394..8a7d790382 100644 --- a/src/main/java/com/rabbitmq/client/impl/ForgivingExceptionHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/ForgivingExceptionHandler.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/Frame.java b/src/main/java/com/rabbitmq/client/impl/Frame.java index 12f53f7ad8..f97e345b9c 100644 --- a/src/main/java/com/rabbitmq/client/impl/Frame.java +++ b/src/main/java/com/rabbitmq/client/impl/Frame.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/FrameHandler.java b/src/main/java/com/rabbitmq/client/impl/FrameHandler.java index 0e54b34435..8d49352cb5 100644 --- a/src/main/java/com/rabbitmq/client/impl/FrameHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/FrameHandler.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/HeartbeatSender.java b/src/main/java/com/rabbitmq/client/impl/HeartbeatSender.java index 998581d0a5..d682317fe3 100644 --- a/src/main/java/com/rabbitmq/client/impl/HeartbeatSender.java +++ b/src/main/java/com/rabbitmq/client/impl/HeartbeatSender.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/LongStringHelper.java b/src/main/java/com/rabbitmq/client/impl/LongStringHelper.java index d80d9a01f3..0a824db6de 100644 --- a/src/main/java/com/rabbitmq/client/impl/LongStringHelper.java +++ b/src/main/java/com/rabbitmq/client/impl/LongStringHelper.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/Method.java b/src/main/java/com/rabbitmq/client/impl/Method.java index 0b894416ac..73b0e5e0d5 100644 --- a/src/main/java/com/rabbitmq/client/impl/Method.java +++ b/src/main/java/com/rabbitmq/client/impl/Method.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/MethodArgumentReader.java b/src/main/java/com/rabbitmq/client/impl/MethodArgumentReader.java index 24ab627450..e5c3f437ee 100644 --- a/src/main/java/com/rabbitmq/client/impl/MethodArgumentReader.java +++ b/src/main/java/com/rabbitmq/client/impl/MethodArgumentReader.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/MethodArgumentWriter.java b/src/main/java/com/rabbitmq/client/impl/MethodArgumentWriter.java index 0782112c8e..53fdfcfcfd 100644 --- a/src/main/java/com/rabbitmq/client/impl/MethodArgumentWriter.java +++ b/src/main/java/com/rabbitmq/client/impl/MethodArgumentWriter.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java index b2ba107cae..d38c0b14c4 100644 --- a/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/NetworkConnection.java b/src/main/java/com/rabbitmq/client/impl/NetworkConnection.java index 747a1921a7..03ca1d2201 100644 --- a/src/main/java/com/rabbitmq/client/impl/NetworkConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/NetworkConnection.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java index b594785742..cc8189ab05 100644 --- a/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java @@ -1,7 +1,7 @@ // Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/OAuthTokenManagementException.java b/src/main/java/com/rabbitmq/client/impl/OAuthTokenManagementException.java index cf17053b24..d3419189cb 100644 --- a/src/main/java/com/rabbitmq/client/impl/OAuthTokenManagementException.java +++ b/src/main/java/com/rabbitmq/client/impl/OAuthTokenManagementException.java @@ -1,7 +1,7 @@ // Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/PlainMechanism.java b/src/main/java/com/rabbitmq/client/impl/PlainMechanism.java index c586385299..75651d74b0 100644 --- a/src/main/java/com/rabbitmq/client/impl/PlainMechanism.java +++ b/src/main/java/com/rabbitmq/client/impl/PlainMechanism.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProvider.java index a4cc01c186..cd8f855b01 100644 --- a/src/main/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProvider.java @@ -1,7 +1,7 @@ // Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/RpcContinuationRpcWrapper.java b/src/main/java/com/rabbitmq/client/impl/RpcContinuationRpcWrapper.java index 8fcf901b55..71d60a4690 100644 --- a/src/main/java/com/rabbitmq/client/impl/RpcContinuationRpcWrapper.java +++ b/src/main/java/com/rabbitmq/client/impl/RpcContinuationRpcWrapper.java @@ -1,7 +1,7 @@ // Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/RpcWrapper.java b/src/main/java/com/rabbitmq/client/impl/RpcWrapper.java index 84c3bb0363..8d81258ffc 100644 --- a/src/main/java/com/rabbitmq/client/impl/RpcWrapper.java +++ b/src/main/java/com/rabbitmq/client/impl/RpcWrapper.java @@ -1,7 +1,7 @@ // Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/SetQueue.java b/src/main/java/com/rabbitmq/client/impl/SetQueue.java index 9ab2cd3526..6a5dc8db12 100644 --- a/src/main/java/com/rabbitmq/client/impl/SetQueue.java +++ b/src/main/java/com/rabbitmq/client/impl/SetQueue.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/ShutdownNotifierComponent.java b/src/main/java/com/rabbitmq/client/impl/ShutdownNotifierComponent.java index 0ee95e083c..e4ec15836b 100644 --- a/src/main/java/com/rabbitmq/client/impl/ShutdownNotifierComponent.java +++ b/src/main/java/com/rabbitmq/client/impl/ShutdownNotifierComponent.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java b/src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java index 8d1d2eee15..6efd6f83f9 100644 --- a/src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/SocketFrameHandlerFactory.java b/src/main/java/com/rabbitmq/client/impl/SocketFrameHandlerFactory.java index 0391b31297..1186b6ea93 100644 --- a/src/main/java/com/rabbitmq/client/impl/SocketFrameHandlerFactory.java +++ b/src/main/java/com/rabbitmq/client/impl/SocketFrameHandlerFactory.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java index 63876de058..e504ac5fc6 100644 --- a/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/StrictExceptionHandler.java b/src/main/java/com/rabbitmq/client/impl/StrictExceptionHandler.java index d1f54768b0..62f37d72b4 100644 --- a/src/main/java/com/rabbitmq/client/impl/StrictExceptionHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/StrictExceptionHandler.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/TlsUtils.java b/src/main/java/com/rabbitmq/client/impl/TlsUtils.java index 5b4290f79c..a11deddc2c 100644 --- a/src/main/java/com/rabbitmq/client/impl/TlsUtils.java +++ b/src/main/java/com/rabbitmq/client/impl/TlsUtils.java @@ -1,7 +1,7 @@ // Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/TruncatedInputStream.java b/src/main/java/com/rabbitmq/client/impl/TruncatedInputStream.java index a572952af8..dd35c3f2e6 100644 --- a/src/main/java/com/rabbitmq/client/impl/TruncatedInputStream.java +++ b/src/main/java/com/rabbitmq/client/impl/TruncatedInputStream.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/UnknownChannelException.java b/src/main/java/com/rabbitmq/client/impl/UnknownChannelException.java index 5e9474c5a9..ff59b907cf 100644 --- a/src/main/java/com/rabbitmq/client/impl/UnknownChannelException.java +++ b/src/main/java/com/rabbitmq/client/impl/UnknownChannelException.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/UpdateSecretExtension.java b/src/main/java/com/rabbitmq/client/impl/UpdateSecretExtension.java index 5edd65813c..3028a886ab 100644 --- a/src/main/java/com/rabbitmq/client/impl/UpdateSecretExtension.java +++ b/src/main/java/com/rabbitmq/client/impl/UpdateSecretExtension.java @@ -1,7 +1,7 @@ // Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/ValueReader.java b/src/main/java/com/rabbitmq/client/impl/ValueReader.java index 9611324f3a..83455bfe66 100644 --- a/src/main/java/com/rabbitmq/client/impl/ValueReader.java +++ b/src/main/java/com/rabbitmq/client/impl/ValueReader.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/ValueWriter.java b/src/main/java/com/rabbitmq/client/impl/ValueWriter.java index e6167cec7e..c167fc0475 100644 --- a/src/main/java/com/rabbitmq/client/impl/ValueWriter.java +++ b/src/main/java/com/rabbitmq/client/impl/ValueWriter.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java b/src/main/java/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java index 97be3a8270..60dbe04bb4 100644 --- a/src/main/java/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java +++ b/src/main/java/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/Version.java b/src/main/java/com/rabbitmq/client/impl/Version.java index 109359fe3d..3e64d51702 100644 --- a/src/main/java/com/rabbitmq/client/impl/Version.java +++ b/src/main/java/com/rabbitmq/client/impl/Version.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/WorkPool.java b/src/main/java/com/rabbitmq/client/impl/WorkPool.java index 39b8b743b7..e4d7dc8cfe 100644 --- a/src/main/java/com/rabbitmq/client/impl/WorkPool.java +++ b/src/main/java/com/rabbitmq/client/impl/WorkPool.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/WorkPoolFullException.java b/src/main/java/com/rabbitmq/client/impl/WorkPoolFullException.java index eba1fe14cf..68e7175f1a 100644 --- a/src/main/java/com/rabbitmq/client/impl/WorkPoolFullException.java +++ b/src/main/java/com/rabbitmq/client/impl/WorkPoolFullException.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/nio/ByteBufferOutputStream.java b/src/main/java/com/rabbitmq/client/impl/nio/ByteBufferOutputStream.java index 16fe3f2682..e8ed5ff841 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/ByteBufferOutputStream.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/ByteBufferOutputStream.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java b/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java index 9ffcd29e65..1eca94eb77 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/nio/FrameWriteRequest.java b/src/main/java/com/rabbitmq/client/impl/nio/FrameWriteRequest.java index 33a5ba5b74..d291a0d3f4 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/FrameWriteRequest.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/FrameWriteRequest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/nio/HeaderWriteRequest.java b/src/main/java/com/rabbitmq/client/impl/nio/HeaderWriteRequest.java index 79e34359c3..558f35e025 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/HeaderWriteRequest.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/HeaderWriteRequest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioHelper.java b/src/main/java/com/rabbitmq/client/impl/nio/NioHelper.java index 3438013c1f..ab8a49b71b 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioHelper.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioHelper.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java b/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java index f194eeef42..ae7fa970e9 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioLoopContext.java b/src/main/java/com/rabbitmq/client/impl/nio/NioLoopContext.java index a73a7a0420..55412e0908 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioLoopContext.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioLoopContext.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java b/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java index e4bb78de23..049fbb33ba 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SelectorHolder.java b/src/main/java/com/rabbitmq/client/impl/nio/SelectorHolder.java index 7426280acb..97b64b2be1 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SelectorHolder.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SelectorHolder.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandler.java b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandler.java index d46ce4e0bb..c17c5e9579 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandler.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java index f4473b8ae3..10f550d70a 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java index b5822fcd91..50f08a59f2 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelRegistration.java b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelRegistration.java index 2befb3d3a6..2c9d3f0d03 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelRegistration.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelRegistration.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferOutputStream.java b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferOutputStream.java index 8ec782613d..c861ad6e77 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferOutputStream.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferOutputStream.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineFrameBuilder.java b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineFrameBuilder.java index 141bb47293..c2f1923874 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineFrameBuilder.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineFrameBuilder.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java index 0de786c7b3..1e7e3a0793 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/nio/WriteRequest.java b/src/main/java/com/rabbitmq/client/impl/nio/WriteRequest.java index b696bc421f..c61731e18b 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/WriteRequest.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/WriteRequest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java index 969fb45593..f2afc9d04c 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index 785d98e5f4..94b24aa7c2 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/BackoffPolicy.java b/src/main/java/com/rabbitmq/client/impl/recovery/BackoffPolicy.java index 6ed2a2deef..08498683ab 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/BackoffPolicy.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/BackoffPolicy.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/ConsumerRecoveryListener.java b/src/main/java/com/rabbitmq/client/impl/recovery/ConsumerRecoveryListener.java index 291528af3e..8c87d86090 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/ConsumerRecoveryListener.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/ConsumerRecoveryListener.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java b/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java index 1fa64afa4e..dc55fc7ed4 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/QueueRecoveryListener.java b/src/main/java/com/rabbitmq/client/impl/recovery/QueueRecoveryListener.java index 55eef2d9f1..66f7f9248f 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/QueueRecoveryListener.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/QueueRecoveryListener.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedBinding.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedBinding.java index 2cdf188ed7..0ddf4e3bcf 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedBinding.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedBinding.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedConsumer.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedConsumer.java index 4aa87a2d0b..3b0d5009d5 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedConsumer.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedConsumer.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedEntity.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedEntity.java index c55a398563..a9fae4c3ae 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedEntity.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedEntity.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchange.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchange.java index d75530fad6..7625b5a870 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchange.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchange.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchangeBinding.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchangeBinding.java index 286b793185..d128b59bf0 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchangeBinding.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchangeBinding.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedNamedEntity.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedNamedEntity.java index b00a9c2df4..6ea8b6fa96 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedNamedEntity.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedNamedEntity.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java index 6cb43cfdae..3580fe091e 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java index 09d2636d32..12ed3d48bb 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnection.java index 94768de1db..251f0aaaa1 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnection.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java index 01a172fac3..ab23cc4494 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelManager.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelManager.java index b9daf354f2..d8aa7123cb 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelManager.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelManager.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java index 5373b6877f..82ae4cc283 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryCanBeginListener.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryCanBeginListener.java index 2c272198b4..cb5eae86fb 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryCanBeginListener.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryCanBeginListener.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RetryContext.java b/src/main/java/com/rabbitmq/client/impl/recovery/RetryContext.java index 60645e199a..6640a7e7c1 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RetryContext.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RetryContext.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RetryHandler.java b/src/main/java/com/rabbitmq/client/impl/recovery/RetryHandler.java index 459ca80080..a5eac40fab 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RetryHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RetryHandler.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RetryResult.java b/src/main/java/com/rabbitmq/client/impl/recovery/RetryResult.java index 6c4e693314..df1d6ae1df 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RetryResult.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RetryResult.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryFilter.java b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryFilter.java index 835249ec55..602b5452f5 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryFilter.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryFilter.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryHandlerBuilder.java b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryHandlerBuilder.java index c2ad1078d5..bed71f9f0b 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryHandlerBuilder.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryHandlerBuilder.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java index 8daa2ac33e..6a91a5202a 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/tools/json/JSONUtil.java b/src/main/java/com/rabbitmq/tools/json/JSONUtil.java index f814462e5e..55c2b695ed 100644 --- a/src/main/java/com/rabbitmq/tools/json/JSONUtil.java +++ b/src/main/java/com/rabbitmq/tools/json/JSONUtil.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java index 8b239eed5b..81a1f26b5b 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java index 16a938711c..76d2ef31df 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java index c46b95c259..d167d0318e 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java index 6e311dc6e4..980428612b 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMappingException.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMappingException.java index 6a764e6960..fc998b1b02 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMappingException.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMappingException.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java index f5ca1990e2..a37e957718 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/ParameterDescription.java b/src/main/java/com/rabbitmq/tools/jsonrpc/ParameterDescription.java index 6106cbf60c..cc58516b1c 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/ParameterDescription.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/ParameterDescription.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java b/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java index 44ac3a0b76..431d4e6e13 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java b/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java index af2029d98c..8986cc24e2 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/utility/BlockingCell.java b/src/main/java/com/rabbitmq/utility/BlockingCell.java index 9f9dce24a4..f9c588b7cf 100644 --- a/src/main/java/com/rabbitmq/utility/BlockingCell.java +++ b/src/main/java/com/rabbitmq/utility/BlockingCell.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/utility/BlockingValueOrException.java b/src/main/java/com/rabbitmq/utility/BlockingValueOrException.java index 77df219b72..5946ccbb4d 100644 --- a/src/main/java/com/rabbitmq/utility/BlockingValueOrException.java +++ b/src/main/java/com/rabbitmq/utility/BlockingValueOrException.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/utility/IntAllocator.java b/src/main/java/com/rabbitmq/utility/IntAllocator.java index 9c1e93cd1f..88d9f3efb8 100644 --- a/src/main/java/com/rabbitmq/utility/IntAllocator.java +++ b/src/main/java/com/rabbitmq/utility/IntAllocator.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/utility/SensibleClone.java b/src/main/java/com/rabbitmq/utility/SensibleClone.java index 50405ec0eb..78e68cb6a5 100644 --- a/src/main/java/com/rabbitmq/utility/SensibleClone.java +++ b/src/main/java/com/rabbitmq/utility/SensibleClone.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/utility/Utility.java b/src/main/java/com/rabbitmq/utility/Utility.java index 805e02835c..f8cdea8656 100644 --- a/src/main/java/com/rabbitmq/utility/Utility.java +++ b/src/main/java/com/rabbitmq/utility/Utility.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/utility/ValueOrException.java b/src/main/java/com/rabbitmq/utility/ValueOrException.java index 7be45ef8a2..93cb1fe563 100644 --- a/src/main/java/com/rabbitmq/utility/ValueOrException.java +++ b/src/main/java/com/rabbitmq/utility/ValueOrException.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/AbstractJsonRpcTest.java b/src/test/java/com/rabbitmq/client/AbstractJsonRpcTest.java index 017cb6e308..0b6bc20a68 100644 --- a/src/test/java/com/rabbitmq/client/AbstractJsonRpcTest.java +++ b/src/test/java/com/rabbitmq/client/AbstractJsonRpcTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/JacksonJsonRpcTest.java b/src/test/java/com/rabbitmq/client/JacksonJsonRpcTest.java index af9b827810..e7a57021d4 100644 --- a/src/test/java/com/rabbitmq/client/JacksonJsonRpcTest.java +++ b/src/test/java/com/rabbitmq/client/JacksonJsonRpcTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/QueueingConsumer.java b/src/test/java/com/rabbitmq/client/QueueingConsumer.java index 434e7a8d82..33a033008f 100644 --- a/src/test/java/com/rabbitmq/client/QueueingConsumer.java +++ b/src/test/java/com/rabbitmq/client/QueueingConsumer.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/impl/AMQConnectionRefreshCredentialsTest.java b/src/test/java/com/rabbitmq/client/impl/AMQConnectionRefreshCredentialsTest.java index 50493bcbd0..989ee69ffa 100644 --- a/src/test/java/com/rabbitmq/client/impl/AMQConnectionRefreshCredentialsTest.java +++ b/src/test/java/com/rabbitmq/client/impl/AMQConnectionRefreshCredentialsTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java b/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java index 21faa59b15..3bd0cca640 100644 --- a/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java +++ b/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java b/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java index d81722779d..bcf96c7f1c 100644 --- a/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java +++ b/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProviderTest.java b/src/test/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProviderTest.java index d273b3e70b..a65ed3b6ca 100644 --- a/src/test/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProviderTest.java +++ b/src/test/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProviderTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java b/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java index ead66ee8ad..ea0d94c683 100644 --- a/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java +++ b/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java b/src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java index 30141ef9f0..4cc054ca88 100644 --- a/src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java +++ b/src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/AMQBuilderApiTest.java b/src/test/java/com/rabbitmq/client/test/AMQBuilderApiTest.java index 9d6fb50abb..46241c38b3 100644 --- a/src/test/java/com/rabbitmq/client/test/AMQBuilderApiTest.java +++ b/src/test/java/com/rabbitmq/client/test/AMQBuilderApiTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/AMQChannelTest.java b/src/test/java/com/rabbitmq/client/test/AMQChannelTest.java index 73a8731eea..0ea1a89c60 100644 --- a/src/test/java/com/rabbitmq/client/test/AMQChannelTest.java +++ b/src/test/java/com/rabbitmq/client/test/AMQChannelTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java b/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java index c278b4cc13..e36631de7c 100644 --- a/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java +++ b/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java b/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java index 70fdbaaa6e..cd1a32a6aa 100644 --- a/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java +++ b/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/AddressTest.java b/src/test/java/com/rabbitmq/client/test/AddressTest.java index ca714b146b..631dc5d986 100644 --- a/src/test/java/com/rabbitmq/client/test/AddressTest.java +++ b/src/test/java/com/rabbitmq/client/test/AddressTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java b/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java index 9b4b467f9c..a57e92da4d 100644 --- a/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java +++ b/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/BlockingCellTest.java b/src/test/java/com/rabbitmq/client/test/BlockingCellTest.java index 7c4ef998b0..b5c7e9a3b0 100644 --- a/src/test/java/com/rabbitmq/client/test/BlockingCellTest.java +++ b/src/test/java/com/rabbitmq/client/test/BlockingCellTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java b/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java index 027a20cd35..cdd06d02d3 100644 --- a/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java +++ b/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java index cda8d3ca44..d61721ad8b 100644 --- a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java +++ b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/Bug20004Test.java b/src/test/java/com/rabbitmq/client/test/Bug20004Test.java index ac62af0095..63e237d4b1 100644 --- a/src/test/java/com/rabbitmq/client/test/Bug20004Test.java +++ b/src/test/java/com/rabbitmq/client/test/Bug20004Test.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/ChannelAsyncCompletableFutureTest.java b/src/test/java/com/rabbitmq/client/test/ChannelAsyncCompletableFutureTest.java index cc1141d116..a871d49455 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelAsyncCompletableFutureTest.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelAsyncCompletableFutureTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/ChannelNTest.java b/src/test/java/com/rabbitmq/client/test/ChannelNTest.java index 80c7902be4..b5f039cbf0 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelNTest.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelNTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/ChannelNumberAllocationTests.java b/src/test/java/com/rabbitmq/client/test/ChannelNumberAllocationTests.java index a3ec4b81f7..aa916529d7 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelNumberAllocationTests.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelNumberAllocationTests.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java b/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java index 948074580f..2e9c4bf9ed 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index 77e2a75f83..3f8945bebc 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/ClientVersionTest.java b/src/test/java/com/rabbitmq/client/test/ClientVersionTest.java index 9d7560adaf..c2c39284e3 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientVersionTest.java +++ b/src/test/java/com/rabbitmq/client/test/ClientVersionTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/ClonePropertiesTest.java b/src/test/java/com/rabbitmq/client/test/ClonePropertiesTest.java index 6e50f31e29..aae4d10e28 100644 --- a/src/test/java/com/rabbitmq/client/test/ClonePropertiesTest.java +++ b/src/test/java/com/rabbitmq/client/test/ClonePropertiesTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/CloseInMainLoop.java b/src/test/java/com/rabbitmq/client/test/CloseInMainLoop.java index 109f8200aa..00e9570136 100644 --- a/src/test/java/com/rabbitmq/client/test/CloseInMainLoop.java +++ b/src/test/java/com/rabbitmq/client/test/CloseInMainLoop.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/ConfirmBase.java b/src/test/java/com/rabbitmq/client/test/ConfirmBase.java index 2421bfed40..144ab68564 100644 --- a/src/test/java/com/rabbitmq/client/test/ConfirmBase.java +++ b/src/test/java/com/rabbitmq/client/test/ConfirmBase.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java b/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java index 7a9dd3d320..e98bbe1452 100644 --- a/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java +++ b/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/ConnectionTest.java b/src/test/java/com/rabbitmq/client/test/ConnectionTest.java index cef3e68a18..c7da088e79 100644 --- a/src/test/java/com/rabbitmq/client/test/ConnectionTest.java +++ b/src/test/java/com/rabbitmq/client/test/ConnectionTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/DefaultRetryHandlerTest.java b/src/test/java/com/rabbitmq/client/test/DefaultRetryHandlerTest.java index c6fe244c51..3aa28efdb9 100644 --- a/src/test/java/com/rabbitmq/client/test/DefaultRetryHandlerTest.java +++ b/src/test/java/com/rabbitmq/client/test/DefaultRetryHandlerTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/DnsSrvRecordAddressResolverTest.java b/src/test/java/com/rabbitmq/client/test/DnsSrvRecordAddressResolverTest.java index e315d1147c..4950cc2323 100644 --- a/src/test/java/com/rabbitmq/client/test/DnsSrvRecordAddressResolverTest.java +++ b/src/test/java/com/rabbitmq/client/test/DnsSrvRecordAddressResolverTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java b/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java index 9d2892e304..2b84a1e91a 100644 --- a/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java +++ b/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/GeneratedClassesTest.java b/src/test/java/com/rabbitmq/client/test/GeneratedClassesTest.java index c144e7e3d3..78919bbca6 100644 --- a/src/test/java/com/rabbitmq/client/test/GeneratedClassesTest.java +++ b/src/test/java/com/rabbitmq/client/test/GeneratedClassesTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/LambdaCallbackTest.java b/src/test/java/com/rabbitmq/client/test/LambdaCallbackTest.java index 29505b73ab..0f30f4f83a 100644 --- a/src/test/java/com/rabbitmq/client/test/LambdaCallbackTest.java +++ b/src/test/java/com/rabbitmq/client/test/LambdaCallbackTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/LongStringTest.java b/src/test/java/com/rabbitmq/client/test/LongStringTest.java index 59f9556e2c..7c711b4fe4 100644 --- a/src/test/java/com/rabbitmq/client/test/LongStringTest.java +++ b/src/test/java/com/rabbitmq/client/test/LongStringTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java b/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java index 72d6409774..c0d61404c4 100644 --- a/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java +++ b/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/MicrometerMetricsCollectorTest.java b/src/test/java/com/rabbitmq/client/test/MicrometerMetricsCollectorTest.java index 77798a0088..125d185160 100644 --- a/src/test/java/com/rabbitmq/client/test/MicrometerMetricsCollectorTest.java +++ b/src/test/java/com/rabbitmq/client/test/MicrometerMetricsCollectorTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/MultiThreadedChannel.java b/src/test/java/com/rabbitmq/client/test/MultiThreadedChannel.java index 4790016a40..93a2d1c837 100644 --- a/src/test/java/com/rabbitmq/client/test/MultiThreadedChannel.java +++ b/src/test/java/com/rabbitmq/client/test/MultiThreadedChannel.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/NioDeadlockOnConnectionClosing.java b/src/test/java/com/rabbitmq/client/test/NioDeadlockOnConnectionClosing.java index c9e1607653..0f3984ade7 100644 --- a/src/test/java/com/rabbitmq/client/test/NioDeadlockOnConnectionClosing.java +++ b/src/test/java/com/rabbitmq/client/test/NioDeadlockOnConnectionClosing.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java b/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java index 62a237cb83..c4edf038a7 100644 --- a/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java +++ b/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java b/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java index 2a140721a5..40138a26d6 100644 --- a/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java +++ b/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/QueueingConsumerTests.java b/src/test/java/com/rabbitmq/client/test/QueueingConsumerTests.java index 01676ade92..ba9d72e47b 100644 --- a/src/test/java/com/rabbitmq/client/test/QueueingConsumerTests.java +++ b/src/test/java/com/rabbitmq/client/test/QueueingConsumerTests.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/RecoveryAwareAMQConnectionFactoryTest.java b/src/test/java/com/rabbitmq/client/test/RecoveryAwareAMQConnectionFactoryTest.java index f09721a036..785b58ec53 100644 --- a/src/test/java/com/rabbitmq/client/test/RecoveryAwareAMQConnectionFactoryTest.java +++ b/src/test/java/com/rabbitmq/client/test/RecoveryAwareAMQConnectionFactoryTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/RecoveryDelayHandlerTest.java b/src/test/java/com/rabbitmq/client/test/RecoveryDelayHandlerTest.java index 7828b5eefe..be9958b487 100644 --- a/src/test/java/com/rabbitmq/client/test/RecoveryDelayHandlerTest.java +++ b/src/test/java/com/rabbitmq/client/test/RecoveryDelayHandlerTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java b/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java index b72c95ee1d..0a0100cbc6 100644 --- a/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java +++ b/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/RpcTest.java b/src/test/java/com/rabbitmq/client/test/RpcTest.java index a11544f2b4..eb8673183e 100644 --- a/src/test/java/com/rabbitmq/client/test/RpcTest.java +++ b/src/test/java/com/rabbitmq/client/test/RpcTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/RpcTopologyRecordingTest.java b/src/test/java/com/rabbitmq/client/test/RpcTopologyRecordingTest.java index 1f0f023018..3769218fd7 100644 --- a/src/test/java/com/rabbitmq/client/test/RpcTopologyRecordingTest.java +++ b/src/test/java/com/rabbitmq/client/test/RpcTopologyRecordingTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java b/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java index a1fe0175f5..747a2805e5 100644 --- a/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java +++ b/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/SslContextFactoryTest.java b/src/test/java/com/rabbitmq/client/test/SslContextFactoryTest.java index 4f591221ce..585e74f7a8 100644 --- a/src/test/java/com/rabbitmq/client/test/SslContextFactoryTest.java +++ b/src/test/java/com/rabbitmq/client/test/SslContextFactoryTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/StrictExceptionHandlerTest.java b/src/test/java/com/rabbitmq/client/test/StrictExceptionHandlerTest.java index 06bf5efe7c..fbb3ad984b 100644 --- a/src/test/java/com/rabbitmq/client/test/StrictExceptionHandlerTest.java +++ b/src/test/java/com/rabbitmq/client/test/StrictExceptionHandlerTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/TableTest.java b/src/test/java/com/rabbitmq/client/test/TableTest.java index e750301413..bb07a71f21 100644 --- a/src/test/java/com/rabbitmq/client/test/TableTest.java +++ b/src/test/java/com/rabbitmq/client/test/TableTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/TestUtils.java b/src/test/java/com/rabbitmq/client/test/TestUtils.java index b6cec91132..19d63d8d86 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtils.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtils.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/TestUtilsTest.java b/src/test/java/com/rabbitmq/client/test/TestUtilsTest.java index 76e5276d7d..b73e8033cc 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtilsTest.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtilsTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/TlsUtilsTest.java b/src/test/java/com/rabbitmq/client/test/TlsUtilsTest.java index 078989ca12..f04d22dc1c 100644 --- a/src/test/java/com/rabbitmq/client/test/TlsUtilsTest.java +++ b/src/test/java/com/rabbitmq/client/test/TlsUtilsTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/TrafficListenerTest.java b/src/test/java/com/rabbitmq/client/test/TrafficListenerTest.java index 69c223cf31..ebc25349d4 100644 --- a/src/test/java/com/rabbitmq/client/test/TrafficListenerTest.java +++ b/src/test/java/com/rabbitmq/client/test/TrafficListenerTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/TruncatedInputStreamTest.java b/src/test/java/com/rabbitmq/client/test/TruncatedInputStreamTest.java index 570f15c848..3adc9492a0 100644 --- a/src/test/java/com/rabbitmq/client/test/TruncatedInputStreamTest.java +++ b/src/test/java/com/rabbitmq/client/test/TruncatedInputStreamTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/ValueOrExceptionTest.java b/src/test/java/com/rabbitmq/client/test/ValueOrExceptionTest.java index 789dccfa29..1ae80029be 100644 --- a/src/test/java/com/rabbitmq/client/test/ValueOrExceptionTest.java +++ b/src/test/java/com/rabbitmq/client/test/ValueOrExceptionTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/AbstractRejectTest.java b/src/test/java/com/rabbitmq/client/test/functional/AbstractRejectTest.java index 470418c384..8c87db34f1 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/AbstractRejectTest.java +++ b/src/test/java/com/rabbitmq/client/test/functional/AbstractRejectTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/AlternateExchange.java b/src/test/java/com/rabbitmq/client/test/functional/AlternateExchange.java index fc620a5034..8f2dd6675a 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/AlternateExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/AlternateExchange.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/BasicGet.java b/src/test/java/com/rabbitmq/client/test/functional/BasicGet.java index 1e854ec495..e64dee9e9a 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/BasicGet.java +++ b/src/test/java/com/rabbitmq/client/test/functional/BasicGet.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java b/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java index 48c82a22ad..91a5c54d49 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java +++ b/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycleBase.java b/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycleBase.java index ae21a981f5..51c0e93585 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycleBase.java +++ b/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycleBase.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java b/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java index 4782459840..ebb54164a3 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java +++ b/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java b/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java index c3ae467c4f..06f53f715a 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/Confirm.java b/src/test/java/com/rabbitmq/client/test/functional/Confirm.java index 9f0860b820..0c427bd261 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Confirm.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Confirm.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionOpen.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionOpen.java index 9f99ba1797..22fe19e326 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionOpen.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionOpen.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java index 426e3c2c0f..ac43c15faf 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java b/src/test/java/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java index 082725531b..1c68176d76 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConsumerCount.java b/src/test/java/com/rabbitmq/client/test/functional/ConsumerCount.java index 73f91a5e10..b0ba1c3206 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConsumerCount.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConsumerCount.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConsumerPriorities.java b/src/test/java/com/rabbitmq/client/test/functional/ConsumerPriorities.java index a3eebd85bb..10bde1f0f1 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConsumerPriorities.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConsumerPriorities.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java index fa6124ce16..36c09add6a 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/DefaultExchange.java b/src/test/java/com/rabbitmq/client/test/functional/DefaultExchange.java index df2ceb5fdd..7d0e9f7899 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DefaultExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DefaultExchange.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/DirectReplyTo.java b/src/test/java/com/rabbitmq/client/test/functional/DirectReplyTo.java index c8d1befec1..2cef783ba1 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DirectReplyTo.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DirectReplyTo.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/DoubleDeletion.java b/src/test/java/com/rabbitmq/client/test/functional/DoubleDeletion.java index 20b87d7312..14f6dee293 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DoubleDeletion.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DoubleDeletion.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/DurableOnTransient.java b/src/test/java/com/rabbitmq/client/test/functional/DurableOnTransient.java index dc9f5d5155..cfc00d7b0a 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DurableOnTransient.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DurableOnTransient.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExceptionHandling.java b/src/test/java/com/rabbitmq/client/test/functional/ExceptionHandling.java index f0c73fcd17..611a8eea82 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExceptionHandling.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExceptionHandling.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExceptionMessages.java b/src/test/java/com/rabbitmq/client/test/functional/ExceptionMessages.java index d2810dcb94..68f4da2204 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExceptionMessages.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExceptionMessages.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java index 5578560302..7c1e6f2e76 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java index ec763486f0..bbaf6b323c 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeletePredeclared.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeletePredeclared.java index ee25ca6232..28d4d667f6 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeletePredeclared.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeletePredeclared.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java index f2f3916ca5..830a2b89e5 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java index b3ed2f5a3a..cc50182001 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java index 15f63fbd48..ff8cb0a846 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java b/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java index ac1e98e7e6..bfe1bcd826 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java +++ b/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java b/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java index 27083cd048..ebef7ff49e 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java +++ b/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java b/src/test/java/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java index 2ff1a36781..b2eeee7719 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java +++ b/src/test/java/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java b/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java index b4f9c9b756..62611f2a35 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/InternalExchange.java b/src/test/java/com/rabbitmq/client/test/functional/InternalExchange.java index cfb705b06b..43a571afc8 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/InternalExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/InternalExchange.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/InvalidAcks.java b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcks.java index dff81c600b..217c55e1c9 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/InvalidAcks.java +++ b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcks.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksBase.java b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksBase.java index 025954022f..1c249007bd 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksBase.java +++ b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksBase.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksTx.java b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksTx.java index 635929bb4b..81fc7e61f7 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksTx.java +++ b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksTx.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/MessageCount.java b/src/test/java/com/rabbitmq/client/test/functional/MessageCount.java index a8d302a55a..3cb81344af 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/MessageCount.java +++ b/src/test/java/com/rabbitmq/client/test/functional/MessageCount.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java index 3e2dc6df74..67e25960a7 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/Nack.java b/src/test/java/com/rabbitmq/client/test/functional/Nack.java index 5b39638d78..61c10e589a 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Nack.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Nack.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java b/src/test/java/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java index 829cf3d25f..41d68d94d5 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java +++ b/src/test/java/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/Nowait.java b/src/test/java/com/rabbitmq/client/test/functional/Nowait.java index af79b0d195..5f713fff61 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Nowait.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Nowait.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java b/src/test/java/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java index 16a1cfdf95..4a36a22052 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java +++ b/src/test/java/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/PerMessageTTL.java b/src/test/java/com/rabbitmq/client/test/functional/PerMessageTTL.java index 0b25fbe699..ab09bdbfdd 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/PerMessageTTL.java +++ b/src/test/java/com/rabbitmq/client/test/functional/PerMessageTTL.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/PerQueueTTL.java b/src/test/java/com/rabbitmq/client/test/functional/PerQueueTTL.java index 55c44e6cb3..506ea50c8f 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/PerQueueTTL.java +++ b/src/test/java/com/rabbitmq/client/test/functional/PerQueueTTL.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java b/src/test/java/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java index f4c9914bda..58475877be 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java +++ b/src/test/java/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/Policies.java b/src/test/java/com/rabbitmq/client/test/functional/Policies.java index 8f86294766..f4d1dd4988 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Policies.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Policies.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/QosTests.java b/src/test/java/com/rabbitmq/client/test/functional/QosTests.java index 1634741a83..276a363f4e 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QosTests.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QosTests.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/QueueExclusivity.java b/src/test/java/com/rabbitmq/client/test/functional/QueueExclusivity.java index 3351b1d1a6..6148ebab27 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QueueExclusivity.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QueueExclusivity.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/QueueLease.java b/src/test/java/com/rabbitmq/client/test/functional/QueueLease.java index 3ec1986792..284f6bd67d 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QueueLease.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QueueLease.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java b/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java index c082a91c41..8ee54671dc 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/QueueSizeLimit.java b/src/test/java/com/rabbitmq/client/test/functional/QueueSizeLimit.java index fd4c26343e..8d34862543 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QueueSizeLimit.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QueueSizeLimit.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/Recover.java b/src/test/java/com/rabbitmq/client/test/functional/Recover.java index 654846648f..61d48973ce 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Recover.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Recover.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/Reject.java b/src/test/java/com/rabbitmq/client/test/functional/Reject.java index 11f3d52d37..2d296a13ea 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Reject.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Reject.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java index 6b1eb781a0..8e6c0c6f9e 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java +++ b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/RequeueOnClose.java b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnClose.java index 1900f97218..e86ed31bdf 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/RequeueOnClose.java +++ b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnClose.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java index 6af8d01dd2..c212512a95 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java +++ b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/Routing.java b/src/test/java/com/rabbitmq/client/test/functional/Routing.java index cfaf9eb38b..050eb379b0 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Routing.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Routing.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/SaslMechanisms.java b/src/test/java/com/rabbitmq/client/test/functional/SaslMechanisms.java index 1d769f8a10..631d21a2a5 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/SaslMechanisms.java +++ b/src/test/java/com/rabbitmq/client/test/functional/SaslMechanisms.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/TTLHandling.java b/src/test/java/com/rabbitmq/client/test/functional/TTLHandling.java index 26d501e35f..4a2b23ae5c 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/TTLHandling.java +++ b/src/test/java/com/rabbitmq/client/test/functional/TTLHandling.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/Tables.java b/src/test/java/com/rabbitmq/client/test/functional/Tables.java index ad631596e9..6f8f1854a8 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Tables.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Tables.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java index 27c210639c..3798ddf70a 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java +++ b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java index 215645fcaf..ffc744bb86 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java +++ b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/Transactions.java b/src/test/java/com/rabbitmq/client/test/functional/Transactions.java index 25fb8410c5..3e3d66883b 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Transactions.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Transactions.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java b/src/test/java/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java index fcafc73ebb..29c4faa2b4 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java b/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java index 04d105b81e..5c4b707086 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java +++ b/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/UserIDHeader.java b/src/test/java/com/rabbitmq/client/test/functional/UserIDHeader.java index 17db1bc8a8..d776029df5 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/UserIDHeader.java +++ b/src/test/java/com/rabbitmq/client/test/functional/UserIDHeader.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java b/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java index 886820c094..a0e857d828 100644 --- a/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java +++ b/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java b/src/test/java/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java index fbc019b263..676dac7015 100644 --- a/src/test/java/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java +++ b/src/test/java/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java b/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java index 30e07d3a2c..4856ea151b 100644 --- a/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/server/Bug19219Test.java b/src/test/java/com/rabbitmq/client/test/server/Bug19219Test.java index 7f48b7aeb4..e16d40d731 100644 --- a/src/test/java/com/rabbitmq/client/test/server/Bug19219Test.java +++ b/src/test/java/com/rabbitmq/client/test/server/Bug19219Test.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java b/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java index cd8a99ed34..a890f2ca66 100644 --- a/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java +++ b/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java b/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java index 8ee7169797..312ce61810 100644 --- a/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java +++ b/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java b/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java index a8c4ff6b8d..5be557cd3d 100644 --- a/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java +++ b/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java b/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java index 0aa40943fe..b4c9a0bc6a 100644 --- a/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java +++ b/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java b/src/test/java/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java index 7d931f12cf..2be62c3c9e 100644 --- a/src/test/java/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java +++ b/src/test/java/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/server/Firehose.java b/src/test/java/com/rabbitmq/client/test/server/Firehose.java index 56b0cdcb10..28064a1383 100644 --- a/src/test/java/com/rabbitmq/client/test/server/Firehose.java +++ b/src/test/java/com/rabbitmq/client/test/server/Firehose.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/server/HATests.java b/src/test/java/com/rabbitmq/client/test/server/HATests.java index 8918098f5d..d4078c4ac2 100644 --- a/src/test/java/com/rabbitmq/client/test/server/HATests.java +++ b/src/test/java/com/rabbitmq/client/test/server/HATests.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/server/LoopbackUsers.java b/src/test/java/com/rabbitmq/client/test/server/LoopbackUsers.java index d9b7be93b1..44f323ab95 100644 --- a/src/test/java/com/rabbitmq/client/test/server/LoopbackUsers.java +++ b/src/test/java/com/rabbitmq/client/test/server/LoopbackUsers.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java b/src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java index b664e7b62e..690a77ddcd 100644 --- a/src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java +++ b/src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java b/src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java index 4080fdce8c..f59e4ced96 100644 --- a/src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/server/Permissions.java b/src/test/java/com/rabbitmq/client/test/server/Permissions.java index 24c25a4391..c67d0cc0c6 100644 --- a/src/test/java/com/rabbitmq/client/test/server/Permissions.java +++ b/src/test/java/com/rabbitmq/client/test/server/Permissions.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/server/PersistenceGuarantees.java b/src/test/java/com/rabbitmq/client/test/server/PersistenceGuarantees.java index 42846db2a1..69bc8093b4 100644 --- a/src/test/java/com/rabbitmq/client/test/server/PersistenceGuarantees.java +++ b/src/test/java/com/rabbitmq/client/test/server/PersistenceGuarantees.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/server/PriorityQueues.java b/src/test/java/com/rabbitmq/client/test/server/PriorityQueues.java index 805b5c6fc4..76c34dbbeb 100644 --- a/src/test/java/com/rabbitmq/client/test/server/PriorityQueues.java +++ b/src/test/java/com/rabbitmq/client/test/server/PriorityQueues.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/server/ServerTests.java b/src/test/java/com/rabbitmq/client/test/server/ServerTests.java index bda7cac3fd..a532586e40 100644 --- a/src/test/java/com/rabbitmq/client/test/server/ServerTests.java +++ b/src/test/java/com/rabbitmq/client/test/server/ServerTests.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/server/Shutdown.java b/src/test/java/com/rabbitmq/client/test/server/Shutdown.java index 53cd63c184..8d7194bd38 100644 --- a/src/test/java/com/rabbitmq/client/test/server/Shutdown.java +++ b/src/test/java/com/rabbitmq/client/test/server/Shutdown.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/server/TopicPermissions.java b/src/test/java/com/rabbitmq/client/test/server/TopicPermissions.java index c258e7a773..5b79de1387 100644 --- a/src/test/java/com/rabbitmq/client/test/server/TopicPermissions.java +++ b/src/test/java/com/rabbitmq/client/test/server/TopicPermissions.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java b/src/test/java/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java index 4aa0839f39..fb65d954b3 100644 --- a/src/test/java/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java +++ b/src/test/java/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java index 9b9e291314..9137213578 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java b/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java index 0ffbc52df5..dde98277d4 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java index 2158b5c347..36a66a940d 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java index 4c22736e8b..29fe35899e 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java index 1dddf62e38..3d629d15ea 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java b/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java index ee4e817612..3aa6fbe330 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java @@ -1,7 +1,7 @@ // Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java index dd041fef5c..a14a257c24 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java index 52c3763064..50d4d9003b 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/tools/Host.java b/src/test/java/com/rabbitmq/tools/Host.java index 91f4c68f50..f1adeded61 100644 --- a/src/test/java/com/rabbitmq/tools/Host.java +++ b/src/test/java/com/rabbitmq/tools/Host.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/utility/IntAllocatorTests.java b/src/test/java/com/rabbitmq/utility/IntAllocatorTests.java index 1dbdfa95a6..d29e134442 100644 --- a/src/test/java/com/rabbitmq/utility/IntAllocatorTests.java +++ b/src/test/java/com/rabbitmq/utility/IntAllocatorTests.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. From cd331898ea3791f2d4ef3ccbb17dc4e1c6a3f6c3 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 17 Jul 2020 16:28:44 +0300 Subject: [PATCH 1254/2114] Drop Exhibit B from our MPL2 file --- LICENSE-MPL-RabbitMQ | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/LICENSE-MPL-RabbitMQ b/LICENSE-MPL-RabbitMQ index 14e2f777f6..b30605c3b1 100644 --- a/LICENSE-MPL-RabbitMQ +++ b/LICENSE-MPL-RabbitMQ @@ -35,7 +35,7 @@ Mozilla Public License Version 2.0 means any form of the work other than Source Code Form. 1.7. "Larger Work" - means a work that combines Covered Software with other material, in + means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. 1.8. "License" @@ -364,10 +364,4 @@ file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. -You may add additional accurate notices of copyright ownership. - -Exhibit B - "Incompatible With Secondary Licenses" Notice ---------------------------------------------------------- - - This Source Code Form is "Incompatible With Secondary Licenses", as - defined by the Mozilla Public License, v. 2.0. +Copyright (c) 2007-2020 VMware, Inc. or its affiliates. From fee30250ee0cfae5ab693e97bf22d341762ed873 Mon Sep 17 00:00:00 2001 From: dcorbacho Date: Mon, 20 Jul 2020 16:59:43 +0100 Subject: [PATCH 1255/2114] Revert drop of Exhibit B on MPL 2.0 --- LICENSE-MPL-RabbitMQ | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/LICENSE-MPL-RabbitMQ b/LICENSE-MPL-RabbitMQ index b30605c3b1..14e2f777f6 100644 --- a/LICENSE-MPL-RabbitMQ +++ b/LICENSE-MPL-RabbitMQ @@ -35,7 +35,7 @@ Mozilla Public License Version 2.0 means any form of the work other than Source Code Form. 1.7. "Larger Work" - means a work that combines Covered Software with other material, in + means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. 1.8. "License" @@ -364,4 +364,10 @@ file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. -Copyright (c) 2007-2020 VMware, Inc. or its affiliates. +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. From 283902d3ed7e42098b60cbbf95154aa93a741dbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 21 Jul 2020 18:00:52 +0200 Subject: [PATCH 1256/2114] Use MPL 2.0 in pom.xml --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 335158c551..f373cbe5de 100644 --- a/pom.xml +++ b/pom.xml @@ -23,8 +23,8 @@ repo - MPL 1.1 - https://www.mozilla.org/MPL/MPL-1.1.txt + MPL 2.0 + https://www.mozilla.org/en-US/MPL/2.0/ repo From ed63367a63308893c04a0038e721f41a42272e39 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2020 23:15:29 +0000 Subject: [PATCH 1257/2114] Bump junit from 4.13 to 4.13.1 Bumps [junit](https://github.com/junit-team/junit4) from 4.13 to 4.13.1. - [Release notes](https://github.com/junit-team/junit4/releases) - [Changelog](https://github.com/junit-team/junit4/blob/main/doc/ReleaseNotes4.13.1.md) - [Commits](https://github.com/junit-team/junit4/compare/r4.13...r4.13.1) Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f373cbe5de..573d1b1b43 100644 --- a/pom.xml +++ b/pom.xml @@ -59,7 +59,7 @@ 1.3.2 2.10.1 1.2.3 - 4.13 + 4.13.1 3.3.3 3.15.0 9.4.27.v20200227 From 706c35a8f4a30de387de6e8f1bd0a7013fd9c69b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 14 Oct 2020 10:01:23 +0200 Subject: [PATCH 1258/2114] Remove MPL Exhibit B, the lib is triple-licensed --- LICENSE-MPL-RabbitMQ | 8 +------- .../java/com/rabbitmq/client/test/functional/Nack.java | 7 ++++--- .../java/com/rabbitmq/client/test/functional/Reject.java | 3 ++- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/LICENSE-MPL-RabbitMQ b/LICENSE-MPL-RabbitMQ index 14e2f777f6..999bf3ef87 100644 --- a/LICENSE-MPL-RabbitMQ +++ b/LICENSE-MPL-RabbitMQ @@ -364,10 +364,4 @@ file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. -You may add additional accurate notices of copyright ownership. - -Exhibit B - "Incompatible With Secondary Licenses" Notice ---------------------------------------------------------- - - This Source Code Form is "Incompatible With Secondary Licenses", as - defined by the Mozilla Public License, v. 2.0. +Copyright (c) 2007-2020 VMware, Inc. or its affiliates. \ No newline at end of file diff --git a/src/test/java/com/rabbitmq/client/test/functional/Nack.java b/src/test/java/com/rabbitmq/client/test/functional/Nack.java index 61c10e589a..409a8fe0cd 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Nack.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Nack.java @@ -19,6 +19,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import java.util.Collections; import java.util.HashSet; import java.util.Set; @@ -31,7 +32,7 @@ public class Nack extends AbstractRejectTest { @Test public void singleNack() throws Exception { String q = - channel.queueDeclare("", false, true, false, null).getQueue(); + channel.queueDeclare("", true, false, false, Collections.singletonMap("x-queue-type", "quorum")).getQueue(); byte[] m1 = "1".getBytes(); byte[] m2 = "2".getBytes(); @@ -63,7 +64,7 @@ public class Nack extends AbstractRejectTest { @Test public void multiNack() throws Exception { String q = - channel.queueDeclare("", false, true, false, null).getQueue(); + channel.queueDeclare("", true, false, false, Collections.singletonMap("x-queue-type", "quorum")).getQueue(); byte[] m1 = "1".getBytes(); byte[] m2 = "2".getBytes(); @@ -105,7 +106,7 @@ public class Nack extends AbstractRejectTest { @Test public void nackAll() throws Exception { String q = - channel.queueDeclare("", false, true, false, null).getQueue(); + channel.queueDeclare("", true, false, false, Collections.singletonMap("x-queue-type", "quorum")).getQueue(); byte[] m1 = "1".getBytes(); byte[] m2 = "2".getBytes(); diff --git a/src/test/java/com/rabbitmq/client/test/functional/Reject.java b/src/test/java/com/rabbitmq/client/test/functional/Reject.java index 2d296a13ea..8a3852551f 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Reject.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Reject.java @@ -19,6 +19,7 @@ import static org.junit.Assert.assertNull; import java.io.IOException; +import java.util.Collections; import org.junit.Test; @@ -30,7 +31,7 @@ public class Reject extends AbstractRejectTest @Test public void reject() throws IOException, InterruptedException { - String q = channel.queueDeclare("", false, true, false, null).getQueue(); + String q = channel.queueDeclare("", true, false, false, Collections.singletonMap("x-queue-type", "quorum")).getQueue(); byte[] m1 = "1".getBytes(); byte[] m2 = "2".getBytes(); From 5fcb48440552831696c1f8f721ec698697d3d2fd Mon Sep 17 00:00:00 2001 From: dcorbacho Date: Mon, 13 Jul 2020 12:00:04 +0100 Subject: [PATCH 1259/2114] Switch to Mozilla Public License 2.0 (MPL 2.0) (cherry picked from commit 0646231ff9d2022ba24cd1a5f2243fa71bbac39b) Conflicts: README.md --- LICENSE | 2 +- LICENSE-MPL-RabbitMQ | 840 ++++++++---------- README.md | 4 +- codegen.py | 4 +- .../java/com/rabbitmq/client/Address.java | 2 +- .../com/rabbitmq/client/AddressResolver.java | 2 +- .../client/AlreadyClosedException.java | 2 +- .../AuthenticationFailureException.java | 2 +- .../com/rabbitmq/client/BasicProperties.java | 2 +- .../com/rabbitmq/client/BlockedCallback.java | 2 +- .../com/rabbitmq/client/BlockedListener.java | 2 +- .../com/rabbitmq/client/CancelCallback.java | 2 +- .../java/com/rabbitmq/client/Channel.java | 2 +- .../java/com/rabbitmq/client/Command.java | 2 +- .../com/rabbitmq/client/ConfirmCallback.java | 2 +- .../com/rabbitmq/client/ConfirmListener.java | 2 +- .../java/com/rabbitmq/client/Connection.java | 2 +- .../rabbitmq/client/ConnectionFactory.java | 2 +- .../client/ConnectionFactoryConfigurator.java | 2 +- .../java/com/rabbitmq/client/Consumer.java | 2 +- .../client/ConsumerCancelledException.java | 2 +- .../ConsumerShutdownSignalCallback.java | 2 +- .../com/rabbitmq/client/ContentHeader.java | 2 +- .../com/rabbitmq/client/DefaultConsumer.java | 2 +- .../rabbitmq/client/DefaultSaslConfig.java | 2 +- .../DefaultSocketChannelConfigurator.java | 2 +- .../client/DefaultSocketConfigurator.java | 2 +- .../com/rabbitmq/client/DeliverCallback.java | 2 +- .../java/com/rabbitmq/client/Delivery.java | 2 +- .../client/DnsRecordIpAddressResolver.java | 2 +- .../client/DnsSrvRecordAddressResolver.java | 2 +- .../java/com/rabbitmq/client/Envelope.java | 2 +- .../com/rabbitmq/client/ExceptionHandler.java | 2 +- .../java/com/rabbitmq/client/GetResponse.java | 2 +- .../com/rabbitmq/client/JDKSaslConfig.java | 2 +- .../rabbitmq/client/ListAddressResolver.java | 2 +- .../java/com/rabbitmq/client/LongString.java | 2 +- .../client/MalformedFrameException.java | 2 +- .../com/rabbitmq/client/MapRpcServer.java | 2 +- .../rabbitmq/client/MessageProperties.java | 2 +- src/main/java/com/rabbitmq/client/Method.java | 2 +- .../com/rabbitmq/client/MetricsCollector.java | 2 +- .../client/MissedHeartbeatException.java | 2 +- .../rabbitmq/client/NoOpMetricsCollector.java | 2 +- ...ossibleAuthenticationFailureException.java | 2 +- .../ProtocolVersionMismatchException.java | 2 +- .../java/com/rabbitmq/client/Recoverable.java | 2 +- .../rabbitmq/client/RecoveryDelayHandler.java | 2 +- .../com/rabbitmq/client/RecoveryListener.java | 2 +- src/main/java/com/rabbitmq/client/Return.java | 2 +- .../com/rabbitmq/client/ReturnCallback.java | 2 +- .../com/rabbitmq/client/ReturnListener.java | 2 +- .../java/com/rabbitmq/client/RpcClient.java | 2 +- .../com/rabbitmq/client/RpcClientParams.java | 2 +- .../java/com/rabbitmq/client/RpcServer.java | 2 +- .../java/com/rabbitmq/client/SaslConfig.java | 2 +- .../com/rabbitmq/client/SaslMechanism.java | 2 +- .../com/rabbitmq/client/ShutdownListener.java | 2 +- .../com/rabbitmq/client/ShutdownNotifier.java | 2 +- .../client/ShutdownSignalException.java | 2 +- .../client/SocketChannelConfigurator.java | 2 +- .../client/SocketChannelConfigurators.java | 2 +- .../rabbitmq/client/SocketConfigurator.java | 2 +- .../rabbitmq/client/SocketConfigurators.java | 2 +- .../rabbitmq/client/SslContextFactory.java | 2 +- .../client/SslEngineConfigurator.java | 2 +- .../client/SslEngineConfigurators.java | 2 +- .../com/rabbitmq/client/StringRpcServer.java | 2 +- .../client/TopologyRecoveryException.java | 2 +- .../client/TrustEverythingTrustManager.java | 2 +- .../rabbitmq/client/UnblockedCallback.java | 2 +- .../rabbitmq/client/UnexpectedFrameError.java | 2 +- .../client/UnexpectedMethodError.java | 2 +- .../client/UnknownClassOrMethodId.java | 2 +- .../client/UnroutableRpcRequestException.java | 2 +- .../client/impl/AMQBasicProperties.java | 2 +- .../com/rabbitmq/client/impl/AMQChannel.java | 2 +- .../com/rabbitmq/client/impl/AMQCommand.java | 2 +- .../rabbitmq/client/impl/AMQConnection.java | 2 +- .../client/impl/AMQContentHeader.java | 2 +- .../client/impl/AbstractMetricsCollector.java | 2 +- .../rabbitmq/client/impl/CRDemoMechanism.java | 2 +- .../rabbitmq/client/impl/ChannelManager.java | 2 +- .../com/rabbitmq/client/impl/ChannelN.java | 2 +- .../rabbitmq/client/impl/ClientVersion.java | 2 +- .../client/impl/CommandAssembler.java | 2 +- .../impl/CompletableFutureRpcWrapper.java | 2 +- .../client/impl/ConnectionParams.java | 2 +- .../client/impl/ConsumerDispatcher.java | 2 +- .../client/impl/ConsumerWorkService.java | 2 +- .../impl/ContentHeaderPropertyReader.java | 2 +- .../impl/ContentHeaderPropertyWriter.java | 2 +- .../client/impl/CredentialsProvider.java | 4 +- .../impl/CredentialsRefreshService.java | 2 +- .../impl/DefaultCredentialsProvider.java | 2 +- .../DefaultCredentialsRefreshService.java | 2 +- .../client/impl/DefaultExceptionHandler.java | 2 +- .../com/rabbitmq/client/impl/Environment.java | 2 +- .../client/impl/ErrorOnWriteListener.java | 2 +- .../client/impl/ExternalMechanism.java | 2 +- .../impl/ForgivingExceptionHandler.java | 2 +- .../java/com/rabbitmq/client/impl/Frame.java | 2 +- .../rabbitmq/client/impl/FrameHandler.java | 2 +- .../rabbitmq/client/impl/HeartbeatSender.java | 2 +- .../client/impl/LongStringHelper.java | 2 +- .../java/com/rabbitmq/client/impl/Method.java | 2 +- .../client/impl/MethodArgumentReader.java | 2 +- .../client/impl/MethodArgumentWriter.java | 2 +- .../impl/MicrometerMetricsCollector.java | 2 +- .../client/impl/NetworkConnection.java | 2 +- ...ntCredentialsGrantCredentialsProvider.java | 2 +- .../impl/OAuthTokenManagementException.java | 2 +- .../rabbitmq/client/impl/PlainMechanism.java | 2 +- .../RefreshProtectedCredentialsProvider.java | 2 +- .../impl/RpcContinuationRpcWrapper.java | 2 +- .../com/rabbitmq/client/impl/RpcWrapper.java | 2 +- .../com/rabbitmq/client/impl/SetQueue.java | 2 +- .../impl/ShutdownNotifierComponent.java | 2 +- .../client/impl/SocketFrameHandler.java | 2 +- .../impl/SocketFrameHandlerFactory.java | 2 +- .../client/impl/StandardMetricsCollector.java | 2 +- .../client/impl/StrictExceptionHandler.java | 2 +- .../com/rabbitmq/client/impl/TlsUtils.java | 2 +- .../client/impl/TruncatedInputStream.java | 2 +- .../client/impl/UnknownChannelException.java | 2 +- .../client/impl/UpdateSecretExtension.java | 2 +- .../com/rabbitmq/client/impl/ValueReader.java | 2 +- .../com/rabbitmq/client/impl/ValueWriter.java | 2 +- .../impl/VariableLinkedBlockingQueue.java | 2 +- .../com/rabbitmq/client/impl/Version.java | 2 +- .../com/rabbitmq/client/impl/WorkPool.java | 2 +- .../client/impl/WorkPoolFullException.java | 2 +- .../impl/nio/ByteBufferOutputStream.java | 2 +- .../client/impl/nio/FrameBuilder.java | 2 +- .../client/impl/nio/FrameWriteRequest.java | 2 +- .../client/impl/nio/HeaderWriteRequest.java | 2 +- .../rabbitmq/client/impl/nio/NioHelper.java | 2 +- .../com/rabbitmq/client/impl/nio/NioLoop.java | 2 +- .../client/impl/nio/NioLoopContext.java | 2 +- .../rabbitmq/client/impl/nio/NioParams.java | 2 +- .../client/impl/nio/SelectorHolder.java | 2 +- .../impl/nio/SocketChannelFrameHandler.java | 2 +- .../nio/SocketChannelFrameHandlerFactory.java | 2 +- .../nio/SocketChannelFrameHandlerState.java | 2 +- .../impl/nio/SocketChannelRegistration.java | 2 +- .../nio/SslEngineByteBufferOutputStream.java | 2 +- .../impl/nio/SslEngineFrameBuilder.java | 2 +- .../client/impl/nio/SslEngineHelper.java | 2 +- .../client/impl/nio/WriteRequest.java | 2 +- .../impl/recovery/AutorecoveringChannel.java | 2 +- .../recovery/AutorecoveringConnection.java | 2 +- .../client/impl/recovery/BackoffPolicy.java | 2 +- .../recovery/ConsumerRecoveryListener.java | 2 +- .../impl/recovery/DefaultRetryHandler.java | 2 +- .../impl/recovery/QueueRecoveryListener.java | 2 +- .../client/impl/recovery/RecordedBinding.java | 2 +- .../impl/recovery/RecordedConsumer.java | 2 +- .../client/impl/recovery/RecordedEntity.java | 2 +- .../impl/recovery/RecordedExchange.java | 2 +- .../recovery/RecordedExchangeBinding.java | 2 +- .../impl/recovery/RecordedNamedEntity.java | 2 +- .../client/impl/recovery/RecordedQueue.java | 2 +- .../impl/recovery/RecordedQueueBinding.java | 2 +- .../recovery/RecoveryAwareAMQConnection.java | 2 +- .../RecoveryAwareAMQConnectionFactory.java | 2 +- .../recovery/RecoveryAwareChannelManager.java | 2 +- .../impl/recovery/RecoveryAwareChannelN.java | 2 +- .../recovery/RecoveryCanBeginListener.java | 2 +- .../client/impl/recovery/RetryContext.java | 2 +- .../client/impl/recovery/RetryHandler.java | 2 +- .../client/impl/recovery/RetryResult.java | 2 +- .../impl/recovery/TopologyRecoveryFilter.java | 2 +- .../TopologyRecoveryRetryHandlerBuilder.java | 2 +- .../recovery/TopologyRecoveryRetryLogic.java | 2 +- .../com/rabbitmq/tools/json/JSONUtil.java | 2 +- .../tools/jsonrpc/JacksonJsonRpcMapper.java | 2 +- .../rabbitmq/tools/jsonrpc/JsonRpcClient.java | 2 +- .../tools/jsonrpc/JsonRpcException.java | 2 +- .../rabbitmq/tools/jsonrpc/JsonRpcMapper.java | 2 +- .../jsonrpc/JsonRpcMappingException.java | 2 +- .../rabbitmq/tools/jsonrpc/JsonRpcServer.java | 2 +- .../tools/jsonrpc/ParameterDescription.java | 2 +- .../tools/jsonrpc/ProcedureDescription.java | 2 +- .../tools/jsonrpc/ServiceDescription.java | 2 +- .../com/rabbitmq/utility/BlockingCell.java | 2 +- .../utility/BlockingValueOrException.java | 2 +- .../com/rabbitmq/utility/IntAllocator.java | 2 +- .../com/rabbitmq/utility/SensibleClone.java | 2 +- .../java/com/rabbitmq/utility/Utility.java | 2 +- .../rabbitmq/utility/ValueOrException.java | 2 +- .../rabbitmq/client/AbstractJsonRpcTest.java | 2 +- .../rabbitmq/client/JacksonJsonRpcTest.java | 2 +- .../com/rabbitmq/client/QueueingConsumer.java | 2 +- .../AMQConnectionRefreshCredentialsTest.java | 2 +- .../DefaultCredentialsRefreshServiceTest.java | 2 +- ...edentialsGrantCredentialsProviderTest.java | 2 +- ...freshProtectedCredentialsProviderTest.java | 2 +- .../rabbitmq/client/impl/ValueWriterTest.java | 2 +- .../rabbitmq/client/impl/WorkPoolTests.java | 2 +- .../client/test/AMQBuilderApiTest.java | 2 +- .../rabbitmq/client/test/AMQChannelTest.java | 2 +- .../client/test/AMQConnectionTest.java | 2 +- .../client/test/AbstractRMQTestSuite.java | 2 +- .../com/rabbitmq/client/test/AddressTest.java | 2 +- .../com/rabbitmq/client/test/AmqpUriTest.java | 2 +- .../client/test/BlockingCellTest.java | 2 +- .../client/test/BrokenFramesTest.java | 2 +- .../rabbitmq/client/test/BrokerTestCase.java | 2 +- .../rabbitmq/client/test/Bug20004Test.java | 2 +- .../ChannelAsyncCompletableFutureTest.java | 2 +- .../rabbitmq/client/test/ChannelNTest.java | 2 +- .../test/ChannelNumberAllocationTests.java | 2 +- .../ChannelRpcTimeoutIntegrationTest.java | 2 +- .../com/rabbitmq/client/test/ClientTests.java | 2 +- .../client/test/ClientVersionTest.java | 2 +- .../client/test/ClonePropertiesTest.java | 2 +- .../rabbitmq/client/test/CloseInMainLoop.java | 2 +- .../com/rabbitmq/client/test/ConfirmBase.java | 2 +- .../client/test/ConnectionFactoryTest.java | 2 +- .../rabbitmq/client/test/ConnectionTest.java | 2 +- .../client/test/DefaultRetryHandlerTest.java | 2 +- .../test/DnsSrvRecordAddressResolverTest.java | 2 +- .../client/test/FrameBuilderTest.java | 2 +- .../client/test/GeneratedClassesTest.java | 2 +- .../client/test/LambdaCallbackTest.java | 2 +- .../rabbitmq/client/test/LongStringTest.java | 2 +- .../client/test/MetricsCollectorTest.java | 2 +- .../test/MicrometerMetricsCollectorTest.java | 2 +- .../client/test/MultiThreadedChannel.java | 2 +- .../test/NioDeadlockOnConnectionClosing.java | 2 +- ...NoAutoRecoveryWhenTcpWindowIsFullTest.java | 2 +- .../test/PropertyFileInitialisationTest.java | 2 +- .../client/test/QueueingConsumerTests.java | 2 +- ...RecoveryAwareAMQConnectionFactoryTest.java | 2 +- .../client/test/RecoveryDelayHandlerTest.java | 2 +- .../client/test/RefreshCredentialsTest.java | 2 +- .../com/rabbitmq/client/test/RpcTest.java | 2 +- .../client/test/RpcTopologyRecordingTest.java | 2 +- .../client/test/SharedThreadPoolTest.java | 2 +- .../client/test/SslContextFactoryTest.java | 2 +- .../test/StrictExceptionHandlerTest.java | 2 +- .../com/rabbitmq/client/test/TableTest.java | 2 +- .../com/rabbitmq/client/test/TestUtils.java | 2 +- .../rabbitmq/client/test/TestUtilsTest.java | 2 +- .../rabbitmq/client/test/TlsUtilsTest.java | 2 +- .../client/test/TrafficListenerTest.java | 2 +- .../client/test/TruncatedInputStreamTest.java | 2 +- .../client/test/ValueOrExceptionTest.java | 2 +- .../test/functional/AbstractRejectTest.java | 2 +- .../test/functional/AlternateExchange.java | 2 +- .../client/test/functional/BasicGet.java | 2 +- .../test/functional/BindingLifecycle.java | 2 +- .../test/functional/BindingLifecycleBase.java | 2 +- .../client/test/functional/CcRoutes.java | 2 +- .../test/functional/ClusteredTestBase.java | 2 +- .../client/test/functional/Confirm.java | 2 +- .../test/functional/ConnectionOpen.java | 2 +- .../test/functional/ConnectionRecovery.java | 2 +- .../ConsumerCancelNotification.java | 2 +- .../client/test/functional/ConsumerCount.java | 2 +- .../test/functional/ConsumerPriorities.java | 2 +- .../test/functional/DeadLetterExchange.java | 2 +- .../test/functional/DefaultExchange.java | 2 +- .../client/test/functional/DirectReplyTo.java | 2 +- .../test/functional/DoubleDeletion.java | 2 +- .../test/functional/DurableOnTransient.java | 2 +- .../test/functional/ExceptionHandling.java | 2 +- .../test/functional/ExceptionMessages.java | 2 +- .../test/functional/ExchangeDeclare.java | 2 +- .../functional/ExchangeDeleteIfUnused.java | 2 +- .../functional/ExchangeDeletePredeclared.java | 2 +- .../functional/ExchangeEquivalenceBase.java | 2 +- .../functional/ExchangeExchangeBindings.java | 2 +- .../ExchangeExchangeBindingsAutoDelete.java | 2 +- .../client/test/functional/FrameMax.java | 2 +- .../test/functional/FunctionalTests.java | 2 +- .../functional/HeadersExchangeValidation.java | 2 +- .../client/test/functional/Heartbeat.java | 2 +- .../test/functional/InternalExchange.java | 2 +- .../client/test/functional/InvalidAcks.java | 2 +- .../test/functional/InvalidAcksBase.java | 2 +- .../client/test/functional/InvalidAcksTx.java | 2 +- .../client/test/functional/MessageCount.java | 2 +- .../client/test/functional/Metrics.java | 2 +- .../rabbitmq/client/test/functional/Nack.java | 2 +- .../test/functional/NoRequeueOnCancel.java | 2 +- .../client/test/functional/Nowait.java | 2 +- .../test/functional/PerConsumerPrefetch.java | 2 +- .../client/test/functional/PerMessageTTL.java | 2 +- .../client/test/functional/PerQueueTTL.java | 2 +- .../functional/PerQueueVsPerMessageTTL.java | 2 +- .../client/test/functional/Policies.java | 2 +- .../client/test/functional/QosTests.java | 2 +- .../test/functional/QueueExclusivity.java | 2 +- .../client/test/functional/QueueLease.java | 2 +- .../test/functional/QueueLifecycle.java | 2 +- .../test/functional/QueueSizeLimit.java | 2 +- .../client/test/functional/Recover.java | 2 +- .../client/test/functional/Reject.java | 2 +- .../functional/RequeueOnChannelClose.java | 2 +- .../test/functional/RequeueOnClose.java | 2 +- .../functional/RequeueOnConnectionClose.java | 2 +- .../client/test/functional/Routing.java | 2 +- .../test/functional/SaslMechanisms.java | 2 +- .../client/test/functional/TTLHandling.java | 2 +- .../client/test/functional/Tables.java | 2 +- .../functional/TopologyRecoveryFiltering.java | 2 +- .../functional/TopologyRecoveryRetry.java | 2 +- .../client/test/functional/Transactions.java | 2 +- .../functional/UnbindAutoDeleteExchange.java | 2 +- .../test/functional/UnexpectedFrames.java | 2 +- .../client/test/functional/UserIDHeader.java | 2 +- .../client/test/server/AbsentQueue.java | 2 +- .../server/AlternateExchangeEquivalence.java | 2 +- .../client/test/server/BlockedConnection.java | 2 +- .../client/test/server/Bug19219Test.java | 2 +- .../test/server/ChannelLimitNegotiation.java | 2 +- .../server/DeadLetterExchangeDurable.java | 2 +- .../test/server/DurableBindingLifecycle.java | 2 +- .../server/EffectVisibilityCrossNodeTest.java | 2 +- .../test/server/ExclusiveQueueDurability.java | 2 +- .../rabbitmq/client/test/server/Firehose.java | 2 +- .../rabbitmq/client/test/server/HATests.java | 2 +- .../client/test/server/LoopbackUsers.java | 2 +- .../client/test/server/MemoryAlarms.java | 2 +- .../client/test/server/MessageRecovery.java | 2 +- .../client/test/server/Permissions.java | 2 +- .../test/server/PersistenceGuarantees.java | 2 +- .../client/test/server/PriorityQueues.java | 2 +- .../client/test/server/ServerTests.java | 2 +- .../rabbitmq/client/test/server/Shutdown.java | 2 +- .../client/test/server/TopicPermissions.java | 2 +- .../test/server/XDeathHeaderGrowth.java | 2 +- .../test/ssl/BadVerifiedConnection.java | 2 +- .../ConnectionFactoryDefaultTlsVersion.java | 2 +- .../client/test/ssl/HostnameVerification.java | 2 +- .../test/ssl/NioTlsUnverifiedConnection.java | 2 +- .../rabbitmq/client/test/ssl/SSLTests.java | 2 +- .../client/test/ssl/TlsConnectionLogging.java | 2 +- .../client/test/ssl/UnverifiedConnection.java | 2 +- .../client/test/ssl/VerifiedConnection.java | 2 +- src/test/java/com/rabbitmq/tools/Host.java | 2 +- .../rabbitmq/utility/IntAllocatorTests.java | 2 +- 343 files changed, 718 insertions(+), 812 deletions(-) diff --git a/LICENSE b/LICENSE index dc3c875662..53599f221a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,5 @@ This package, the RabbitMQ Java client library, is triple-licensed under -the Mozilla Public License 1.1 ("MPL"), the GNU General Public License +the Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, please see LICENSE-APACHE2. diff --git a/LICENSE-MPL-RabbitMQ b/LICENSE-MPL-RabbitMQ index 50770c2540..14e2f777f6 100644 --- a/LICENSE-MPL-RabbitMQ +++ b/LICENSE-MPL-RabbitMQ @@ -1,467 +1,373 @@ - MOZILLA PUBLIC LICENSE - Version 1.1 - - --------------- - -1. Definitions. - - 1.0.1. "Commercial Use" means distribution or otherwise making the - Covered Code available to a third party. - - 1.1. "Contributor" means each entity that creates or contributes to - the creation of Modifications. - - 1.2. "Contributor Version" means the combination of the Original - Code, prior Modifications used by a Contributor, and the Modifications - made by that particular Contributor. - - 1.3. "Covered Code" means the Original Code or Modifications or the - combination of the Original Code and Modifications, in each case - including portions thereof. - - 1.4. "Electronic Distribution Mechanism" means a mechanism generally - accepted in the software development community for the electronic - transfer of data. - - 1.5. "Executable" means Covered Code in any form other than Source - Code. - - 1.6. "Initial Developer" means the individual or entity identified - as the Initial Developer in the Source Code notice required by Exhibit - A. - - 1.7. "Larger Work" means a work which combines Covered Code or - portions thereof with code not governed by the terms of this License. - - 1.8. "License" means this document. - - 1.8.1. "Licensable" means having the right to grant, to the maximum - extent possible, whether at the time of the initial grant or - subsequently acquired, any and all of the rights conveyed herein. - - 1.9. "Modifications" means any addition to or deletion from the - substance or structure of either the Original Code or any previous - Modifications. When Covered Code is released as a series of files, a - Modification is: - A. Any addition to or deletion from the contents of a file - containing Original Code or previous Modifications. - - B. Any new file that contains any part of the Original Code or - previous Modifications. - - 1.10. "Original Code" means Source Code of computer software code - which is described in the Source Code notice required by Exhibit A as - Original Code, and which, at the time of its release under this - License is not already Covered Code governed by this License. - - 1.10.1. "Patent Claims" means any patent claim(s), now owned or - hereafter acquired, including without limitation, method, process, - and apparatus claims, in any patent Licensable by grantor. - - 1.11. "Source Code" means the preferred form of the Covered Code for - making modifications to it, including all modules it contains, plus - any associated interface definition files, scripts used to control - compilation and installation of an Executable, or source code - differential comparisons against either the Original Code or another - well known, available Covered Code of the Contributor's choice. The - Source Code can be in a compressed or archival form, provided the - appropriate decompression or de-archiving software is widely available - for no charge. - - 1.12. "You" (or "Your") means an individual or a legal entity - exercising rights under, and complying with all of the terms of, this - License or a future version of this License issued under Section 6.1. - For legal entities, "You" includes any entity which controls, is - controlled by, or is under common control with You. For purposes of - this definition, "control" means (a) the power, direct or indirect, - to cause the direction or management of such entity, whether by - contract or otherwise, or (b) ownership of more than fifty percent - (50%) of the outstanding shares or beneficial ownership of such - entity. - -2. Source Code License. - - 2.1. The Initial Developer Grant. - The Initial Developer hereby grants You a world-wide, royalty-free, - non-exclusive license, subject to third party intellectual property - claims: - (a) under intellectual property rights (other than patent or - trademark) Licensable by Initial Developer to use, reproduce, - modify, display, perform, sublicense and distribute the Original - Code (or portions thereof) with or without Modifications, and/or - as part of a Larger Work; and - - (b) under Patents Claims infringed by the making, using or - selling of Original Code, to make, have made, use, practice, - sell, and offer for sale, and/or otherwise dispose of the - Original Code (or portions thereof). - - (c) the licenses granted in this Section 2.1(a) and (b) are - effective on the date Initial Developer first distributes - Original Code under the terms of this License. - - (d) Notwithstanding Section 2.1(b) above, no patent license is - granted: 1) for code that You delete from the Original Code; 2) - separate from the Original Code; or 3) for infringements caused - by: i) the modification of the Original Code or ii) the - combination of the Original Code with other software or devices. - - 2.2. Contributor Grant. - Subject to third party intellectual property claims, each Contributor - hereby grants You a world-wide, royalty-free, non-exclusive license - - (a) under intellectual property rights (other than patent or - trademark) Licensable by Contributor, to use, reproduce, modify, - display, perform, sublicense and distribute the Modifications - created by such Contributor (or portions thereof) either on an - unmodified basis, with other Modifications, as Covered Code - and/or as part of a Larger Work; and - - (b) under Patent Claims infringed by the making, using, or - selling of Modifications made by that Contributor either alone - and/or in combination with its Contributor Version (or portions - of such combination), to make, use, sell, offer for sale, have - made, and/or otherwise dispose of: 1) Modifications made by that - Contributor (or portions thereof); and 2) the combination of - Modifications made by that Contributor with its Contributor - Version (or portions of such combination). - - (c) the licenses granted in Sections 2.2(a) and 2.2(b) are - effective on the date Contributor first makes Commercial Use of - the Covered Code. - - (d) Notwithstanding Section 2.2(b) above, no patent license is - granted: 1) for any code that Contributor has deleted from the - Contributor Version; 2) separate from the Contributor Version; - 3) for infringements caused by: i) third party modifications of - Contributor Version or ii) the combination of Modifications made - by that Contributor with other software (except as part of the - Contributor Version) or other devices; or 4) under Patent Claims - infringed by Covered Code in the absence of Modifications made by - that Contributor. - -3. Distribution Obligations. - - 3.1. Application of License. - The Modifications which You create or to which You contribute are - governed by the terms of this License, including without limitation - Section 2.2. The Source Code version of Covered Code may be - distributed only under the terms of this License or a future version - of this License released under Section 6.1, and You must include a - copy of this License with every copy of the Source Code You - distribute. You may not offer or impose any terms on any Source Code - version that alters or restricts the applicable version of this - License or the recipients' rights hereunder. However, You may include - an additional document offering the additional rights described in - Section 3.5. - - 3.2. Availability of Source Code. - Any Modification which You create or to which You contribute must be - made available in Source Code form under the terms of this License - either on the same media as an Executable version or via an accepted - Electronic Distribution Mechanism to anyone to whom you made an - Executable version available; and if made available via Electronic - Distribution Mechanism, must remain available for at least twelve (12) - months after the date it initially became available, or at least six - (6) months after a subsequent version of that particular Modification - has been made available to such recipients. You are responsible for - ensuring that the Source Code version remains available even if the - Electronic Distribution Mechanism is maintained by a third party. - - 3.3. Description of Modifications. - You must cause all Covered Code to which You contribute to contain a - file documenting the changes You made to create that Covered Code and - the date of any change. You must include a prominent statement that - the Modification is derived, directly or indirectly, from Original - Code provided by the Initial Developer and including the name of the - Initial Developer in (a) the Source Code, and (b) in any notice in an - Executable version or related documentation in which You describe the - origin or ownership of the Covered Code. - - 3.4. Intellectual Property Matters - (a) Third Party Claims. - If Contributor has knowledge that a license under a third party's - intellectual property rights is required to exercise the rights - granted by such Contributor under Sections 2.1 or 2.2, - Contributor must include a text file with the Source Code - distribution titled "LEGAL" which describes the claim and the - party making the claim in sufficient detail that a recipient will - know whom to contact. If Contributor obtains such knowledge after - the Modification is made available as described in Section 3.2, - Contributor shall promptly modify the LEGAL file in all copies - Contributor makes available thereafter and shall take other steps - (such as notifying appropriate mailing lists or newsgroups) - reasonably calculated to inform those who received the Covered - Code that new knowledge has been obtained. - - (b) Contributor APIs. - If Contributor's Modifications include an application programming - interface and Contributor has knowledge of patent licenses which - are reasonably necessary to implement that API, Contributor must - also include this information in the LEGAL file. - - (c) Representations. - Contributor represents that, except as disclosed pursuant to - Section 3.4(a) above, Contributor believes that Contributor's - Modifications are Contributor's original creation(s) and/or - Contributor has sufficient rights to grant the rights conveyed by - this License. - - 3.5. Required Notices. - You must duplicate the notice in Exhibit A in each file of the Source - Code. If it is not possible to put such notice in a particular Source - Code file due to its structure, then You must include such notice in a - location (such as a relevant directory) where a user would be likely - to look for such a notice. If You created one or more Modification(s) - You may add your name as a Contributor to the notice described in - Exhibit A. You must also duplicate this License in any documentation - for the Source Code where You describe recipients' rights or ownership - rights relating to Covered Code. You may choose to offer, and to - charge a fee for, warranty, support, indemnity or liability - obligations to one or more recipients of Covered Code. However, You - may do so only on Your own behalf, and not on behalf of the Initial - Developer or any Contributor. You must make it absolutely clear than - any such warranty, support, indemnity or liability obligation is - offered by You alone, and You hereby agree to indemnify the Initial - Developer and every Contributor for any liability incurred by the - Initial Developer or such Contributor as a result of warranty, - support, indemnity or liability terms You offer. - - 3.6. Distribution of Executable Versions. - You may distribute Covered Code in Executable form only if the - requirements of Section 3.1-3.5 have been met for that Covered Code, - and if You include a notice stating that the Source Code version of - the Covered Code is available under the terms of this License, - including a description of how and where You have fulfilled the - obligations of Section 3.2. The notice must be conspicuously included - in any notice in an Executable version, related documentation or - collateral in which You describe recipients' rights relating to the - Covered Code. You may distribute the Executable version of Covered - Code or ownership rights under a license of Your choice, which may - contain terms different from this License, provided that You are in - compliance with the terms of this License and that the license for the - Executable version does not attempt to limit or alter the recipient's - rights in the Source Code version from the rights set forth in this - License. If You distribute the Executable version under a different - license You must make it absolutely clear that any terms which differ - from this License are offered by You alone, not by the Initial - Developer or any Contributor. You hereby agree to indemnify the - Initial Developer and every Contributor for any liability incurred by - the Initial Developer or such Contributor as a result of any such - terms You offer. - - 3.7. Larger Works. - You may create a Larger Work by combining Covered Code with other code - not governed by the terms of this License and distribute the Larger - Work as a single product. In such a case, You must make sure the - requirements of this License are fulfilled for the Covered Code. - -4. Inability to Comply Due to Statute or Regulation. - - If it is impossible for You to comply with any of the terms of this - License with respect to some or all of the Covered Code due to - statute, judicial order, or regulation then You must: (a) comply with - the terms of this License to the maximum extent possible; and (b) - describe the limitations and the code they affect. Such description - must be included in the LEGAL file described in Section 3.4 and must - be included with all distributions of the Source Code. Except to the - extent prohibited by statute or regulation, such description must be - sufficiently detailed for a recipient of ordinary skill to be able to - understand it. - -5. Application of this License. - - This License applies to code to which the Initial Developer has - attached the notice in Exhibit A and to related Covered Code. - -6. Versions of the License. - - 6.1. New Versions. - Netscape Communications Corporation ("Netscape") may publish revised - and/or new versions of the License from time to time. Each version - will be given a distinguishing version number. - - 6.2. Effect of New Versions. - Once Covered Code has been published under a particular version of the - License, You may always continue to use it under the terms of that - version. You may also choose to use such Covered Code under the terms - of any subsequent version of the License published by Netscape. No one - other than Netscape has the right to modify the terms applicable to - Covered Code created under this License. - - 6.3. Derivative Works. - If You create or use a modified version of this License (which you may - only do in order to apply it to code which is not already Covered Code - governed by this License), You must (a) rename Your license so that - the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape", - "MPL", "NPL" or any confusingly similar phrase do not appear in your - license (except to note that your license differs from this License) - and (b) otherwise make it clear that Your version of the license - contains terms which differ from the Mozilla Public License and - Netscape Public License. (Filling in the name of the Initial - Developer, Original Code or Contributor in the notice described in - Exhibit A shall not of themselves be deemed to be modifications of - this License.) - -7. DISCLAIMER OF WARRANTY. - - COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, - WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF - DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. - THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE - IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, - YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE - COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER - OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF - ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. - -8. TERMINATION. - - 8.1. This License and the rights granted hereunder will terminate - automatically if You fail to comply with terms herein and fail to cure - such breach within 30 days of becoming aware of the breach. All - sublicenses to the Covered Code which are properly granted shall - survive any termination of this License. Provisions which, by their - nature, must remain in effect beyond the termination of this License - shall survive. - - 8.2. If You initiate litigation by asserting a patent infringement - claim (excluding declatory judgment actions) against Initial Developer - or a Contributor (the Initial Developer or Contributor against whom - You file such action is referred to as "Participant") alleging that: - - (a) such Participant's Contributor Version directly or indirectly - infringes any patent, then any and all rights granted by such - Participant to You under Sections 2.1 and/or 2.2 of this License - shall, upon 60 days notice from Participant terminate prospectively, - unless if within 60 days after receipt of notice You either: (i) - agree in writing to pay Participant a mutually agreeable reasonable - royalty for Your past and future use of Modifications made by such - Participant, or (ii) withdraw Your litigation claim with respect to - the Contributor Version against such Participant. If within 60 days - of notice, a reasonable royalty and payment arrangement are not - mutually agreed upon in writing by the parties or the litigation claim - is not withdrawn, the rights granted by Participant to You under - Sections 2.1 and/or 2.2 automatically terminate at the expiration of - the 60 day notice period specified above. - - (b) any software, hardware, or device, other than such Participant's - Contributor Version, directly or indirectly infringes any patent, then - any rights granted to You by such Participant under Sections 2.1(b) - and 2.2(b) are revoked effective as of the date You first made, used, - sold, distributed, or had made, Modifications made by that - Participant. - - 8.3. If You assert a patent infringement claim against Participant - alleging that such Participant's Contributor Version directly or - indirectly infringes any patent where such claim is resolved (such as - by license or settlement) prior to the initiation of patent - infringement litigation, then the reasonable value of the licenses - granted by such Participant under Sections 2.1 or 2.2 shall be taken - into account in determining the amount or value of any payment or - license. - - 8.4. In the event of termination under Sections 8.1 or 8.2 above, - all end user license agreements (excluding distributors and resellers) - which have been validly granted by You or any distributor hereunder - prior to termination shall survive termination. - -9. LIMITATION OF LIABILITY. - - UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT - (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL - DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE, - OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR - ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY - CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, - WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER - COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN - INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF - LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY - RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW - PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE - EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO - THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. - -10. U.S. GOVERNMENT END USERS. - - The Covered Code is a "commercial item," as that term is defined in - 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer - software" and "commercial computer software documentation," as such - terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 - C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), - all U.S. Government End Users acquire Covered Code with only those - rights set forth herein. - -11. MISCELLANEOUS. - - This License represents the complete agreement concerning subject - matter hereof. If any provision of this License is held to be - unenforceable, such provision shall be reformed only to the extent - necessary to make it enforceable. This License shall be governed by - California law provisions (except to the extent applicable law, if - any, provides otherwise), excluding its conflict-of-law provisions. - With respect to disputes in which at least one party is a citizen of, - or an entity chartered or registered to do business in the United - States of America, any litigation relating to this License shall be - subject to the jurisdiction of the Federal Courts of the Northern - District of California, with venue lying in Santa Clara County, - California, with the losing party responsible for costs, including - without limitation, court costs and reasonable attorneys' fees and - expenses. The application of the United Nations Convention on - Contracts for the International Sale of Goods is expressly excluded. - Any law or regulation which provides that the language of a contract - shall be construed against the drafter shall not apply to this - License. - -12. RESPONSIBILITY FOR CLAIMS. - - As between Initial Developer and the Contributors, each party is - responsible for claims and damages arising, directly or indirectly, - out of its utilization of rights under this License and You agree to - work with Initial Developer and Contributors to distribute such - responsibility on an equitable basis. Nothing herein is intended or - shall be deemed to constitute any admission of liability. - -13. MULTIPLE-LICENSED CODE. - - Initial Developer may designate portions of the Covered Code as - "Multiple-Licensed". "Multiple-Licensed" means that the Initial - Developer permits you to utilize portions of the Covered Code under - Your choice of the MPL or the alternative licenses, if any, specified - by the Initial Developer in the file described in Exhibit A. - -EXHIBIT A -Mozilla Public License. - - ``The contents of this file are subject to the Mozilla Public License - Version 1.1 (the "License"); you may not use this file except in - compliance with the License. You may obtain a copy of the License at - https://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - License for the specific language governing rights and limitations - under the License. - - The Original Code is RabbitMQ. - - The Initial Developer of the Original Code is GoPivotal, Inc. - Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. - - Alternatively, the contents of this file may be used under the terms - of the GNU General Public License version 2 (the "GPL2"), or - the Apache License version 2 (the "ASL2") in which case the - provisions of GPL2 or the ASL2 are applicable instead of those - above. If you wish to allow use of your version of this file only - under the terms of the GPL2 or the ASL2 and not to allow others to use - your version of this file under the MPL, indicate your decision by - deleting the provisions above and replace them with the notice and - other provisions required by the GPL2 or the ASL2. If you do not delete - the provisions above, a recipient may use your version of this file - under either the MPL, the GPL2 or the ASL2.'' - - [NOTE: The text of this Exhibit A may differ slightly from the text of - the notices in the Source Code files of the Original Code. You should - use the text of this Exhibit A rather than the text found in the - Original Code Source Code for Your Modifications.] +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/README.md b/README.md index 103c73d08d..cdc88f8d07 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,6 @@ See [Contributing](./CONTRIBUTING.md) and [How to Run Tests](./RUNNING_TESTS.md) ## License -This package, the RabbitMQ Java client library, is triple-licensed under -the Mozilla Public License 1.1 ("MPL"), the GNU General Public License +This package, the RabbitMQ Java client library, is [triple-licensed](https://www.rabbitmq.com/api-guide.html#license) under +the Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 ("GPL") and the Apache License version 2 ("ASL"). diff --git a/codegen.py b/codegen.py index 42c577a0d9..42e29eaab1 100755 --- a/codegen.py +++ b/codegen.py @@ -3,7 +3,7 @@ ## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. ## ## This software, the RabbitMQ Java client library, is triple-licensed under the -## Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +## Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 ## ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see ## LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, ## please see LICENSE-APACHE2. @@ -133,7 +133,7 @@ def printFileHeader(): // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/Address.java b/src/main/java/com/rabbitmq/client/Address.java index 26b9cd9d3e..394f5e7b60 100644 --- a/src/main/java/com/rabbitmq/client/Address.java +++ b/src/main/java/com/rabbitmq/client/Address.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/AddressResolver.java b/src/main/java/com/rabbitmq/client/AddressResolver.java index 4a4f0d8461..8350bac153 100644 --- a/src/main/java/com/rabbitmq/client/AddressResolver.java +++ b/src/main/java/com/rabbitmq/client/AddressResolver.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/AlreadyClosedException.java b/src/main/java/com/rabbitmq/client/AlreadyClosedException.java index 37060907f9..69a000847e 100644 --- a/src/main/java/com/rabbitmq/client/AlreadyClosedException.java +++ b/src/main/java/com/rabbitmq/client/AlreadyClosedException.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/AuthenticationFailureException.java b/src/main/java/com/rabbitmq/client/AuthenticationFailureException.java index 391be6d039..56f26561ca 100644 --- a/src/main/java/com/rabbitmq/client/AuthenticationFailureException.java +++ b/src/main/java/com/rabbitmq/client/AuthenticationFailureException.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/BasicProperties.java b/src/main/java/com/rabbitmq/client/BasicProperties.java index 4001508cfb..9a0b953698 100644 --- a/src/main/java/com/rabbitmq/client/BasicProperties.java +++ b/src/main/java/com/rabbitmq/client/BasicProperties.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/BlockedCallback.java b/src/main/java/com/rabbitmq/client/BlockedCallback.java index f679e79427..d9e22fbe88 100644 --- a/src/main/java/com/rabbitmq/client/BlockedCallback.java +++ b/src/main/java/com/rabbitmq/client/BlockedCallback.java @@ -1,7 +1,7 @@ // Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/BlockedListener.java b/src/main/java/com/rabbitmq/client/BlockedListener.java index 4e0f820615..521f8d19cd 100644 --- a/src/main/java/com/rabbitmq/client/BlockedListener.java +++ b/src/main/java/com/rabbitmq/client/BlockedListener.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/CancelCallback.java b/src/main/java/com/rabbitmq/client/CancelCallback.java index ee6df1964a..419f34a4bd 100644 --- a/src/main/java/com/rabbitmq/client/CancelCallback.java +++ b/src/main/java/com/rabbitmq/client/CancelCallback.java @@ -1,7 +1,7 @@ // Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/Channel.java b/src/main/java/com/rabbitmq/client/Channel.java index b84df3d95b..2520858b9e 100644 --- a/src/main/java/com/rabbitmq/client/Channel.java +++ b/src/main/java/com/rabbitmq/client/Channel.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/Command.java b/src/main/java/com/rabbitmq/client/Command.java index 2630773ecc..dad5c6aa64 100644 --- a/src/main/java/com/rabbitmq/client/Command.java +++ b/src/main/java/com/rabbitmq/client/Command.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/ConfirmCallback.java b/src/main/java/com/rabbitmq/client/ConfirmCallback.java index 41197874e3..e02355f957 100644 --- a/src/main/java/com/rabbitmq/client/ConfirmCallback.java +++ b/src/main/java/com/rabbitmq/client/ConfirmCallback.java @@ -1,7 +1,7 @@ // Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/ConfirmListener.java b/src/main/java/com/rabbitmq/client/ConfirmListener.java index 51162d9baf..50f25ad2c3 100644 --- a/src/main/java/com/rabbitmq/client/ConfirmListener.java +++ b/src/main/java/com/rabbitmq/client/ConfirmListener.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/Connection.java b/src/main/java/com/rabbitmq/client/Connection.java index d45c1b90ea..5004ac9372 100644 --- a/src/main/java/com/rabbitmq/client/Connection.java +++ b/src/main/java/com/rabbitmq/client/Connection.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 71286d3b3b..0b55ef7d34 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java b/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java index 9cd9c7ee31..d59770380e 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java @@ -1,7 +1,7 @@ // Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/Consumer.java b/src/main/java/com/rabbitmq/client/Consumer.java index 118ce0a8f3..cb57e9d956 100644 --- a/src/main/java/com/rabbitmq/client/Consumer.java +++ b/src/main/java/com/rabbitmq/client/Consumer.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/ConsumerCancelledException.java b/src/main/java/com/rabbitmq/client/ConsumerCancelledException.java index 7078cfcf99..44495fceb4 100644 --- a/src/main/java/com/rabbitmq/client/ConsumerCancelledException.java +++ b/src/main/java/com/rabbitmq/client/ConsumerCancelledException.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/ConsumerShutdownSignalCallback.java b/src/main/java/com/rabbitmq/client/ConsumerShutdownSignalCallback.java index fb055dde7e..0fe41694a4 100644 --- a/src/main/java/com/rabbitmq/client/ConsumerShutdownSignalCallback.java +++ b/src/main/java/com/rabbitmq/client/ConsumerShutdownSignalCallback.java @@ -1,7 +1,7 @@ // Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/ContentHeader.java b/src/main/java/com/rabbitmq/client/ContentHeader.java index ddb7d52b14..ff3f0f0a1e 100644 --- a/src/main/java/com/rabbitmq/client/ContentHeader.java +++ b/src/main/java/com/rabbitmq/client/ContentHeader.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/DefaultConsumer.java b/src/main/java/com/rabbitmq/client/DefaultConsumer.java index 0e1670d39a..b2b4644b3c 100644 --- a/src/main/java/com/rabbitmq/client/DefaultConsumer.java +++ b/src/main/java/com/rabbitmq/client/DefaultConsumer.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/DefaultSaslConfig.java b/src/main/java/com/rabbitmq/client/DefaultSaslConfig.java index 62ac85c4c1..0e4de02da1 100644 --- a/src/main/java/com/rabbitmq/client/DefaultSaslConfig.java +++ b/src/main/java/com/rabbitmq/client/DefaultSaslConfig.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/DefaultSocketChannelConfigurator.java b/src/main/java/com/rabbitmq/client/DefaultSocketChannelConfigurator.java index 38494da70e..470bd6f940 100644 --- a/src/main/java/com/rabbitmq/client/DefaultSocketChannelConfigurator.java +++ b/src/main/java/com/rabbitmq/client/DefaultSocketChannelConfigurator.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/DefaultSocketConfigurator.java b/src/main/java/com/rabbitmq/client/DefaultSocketConfigurator.java index 0c3118e049..57732f45c3 100644 --- a/src/main/java/com/rabbitmq/client/DefaultSocketConfigurator.java +++ b/src/main/java/com/rabbitmq/client/DefaultSocketConfigurator.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/DeliverCallback.java b/src/main/java/com/rabbitmq/client/DeliverCallback.java index 8e17dfb407..4760c7be1a 100644 --- a/src/main/java/com/rabbitmq/client/DeliverCallback.java +++ b/src/main/java/com/rabbitmq/client/DeliverCallback.java @@ -1,7 +1,7 @@ // Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/Delivery.java b/src/main/java/com/rabbitmq/client/Delivery.java index 3e99f20974..91c36ffa3d 100644 --- a/src/main/java/com/rabbitmq/client/Delivery.java +++ b/src/main/java/com/rabbitmq/client/Delivery.java @@ -1,7 +1,7 @@ // Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/DnsRecordIpAddressResolver.java b/src/main/java/com/rabbitmq/client/DnsRecordIpAddressResolver.java index fb28f16a41..2f9ce570a4 100644 --- a/src/main/java/com/rabbitmq/client/DnsRecordIpAddressResolver.java +++ b/src/main/java/com/rabbitmq/client/DnsRecordIpAddressResolver.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/DnsSrvRecordAddressResolver.java b/src/main/java/com/rabbitmq/client/DnsSrvRecordAddressResolver.java index 81775fc9f6..5c340c3347 100644 --- a/src/main/java/com/rabbitmq/client/DnsSrvRecordAddressResolver.java +++ b/src/main/java/com/rabbitmq/client/DnsSrvRecordAddressResolver.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/Envelope.java b/src/main/java/com/rabbitmq/client/Envelope.java index cc8e7ceda1..d8164f050d 100644 --- a/src/main/java/com/rabbitmq/client/Envelope.java +++ b/src/main/java/com/rabbitmq/client/Envelope.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/ExceptionHandler.java b/src/main/java/com/rabbitmq/client/ExceptionHandler.java index 3ed8183f28..90c982d11e 100644 --- a/src/main/java/com/rabbitmq/client/ExceptionHandler.java +++ b/src/main/java/com/rabbitmq/client/ExceptionHandler.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/GetResponse.java b/src/main/java/com/rabbitmq/client/GetResponse.java index ba157a0fb9..83ea3bc991 100644 --- a/src/main/java/com/rabbitmq/client/GetResponse.java +++ b/src/main/java/com/rabbitmq/client/GetResponse.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/JDKSaslConfig.java b/src/main/java/com/rabbitmq/client/JDKSaslConfig.java index d8a240a30e..e39beb2eec 100644 --- a/src/main/java/com/rabbitmq/client/JDKSaslConfig.java +++ b/src/main/java/com/rabbitmq/client/JDKSaslConfig.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/ListAddressResolver.java b/src/main/java/com/rabbitmq/client/ListAddressResolver.java index a7b3d96657..e04eaa4431 100644 --- a/src/main/java/com/rabbitmq/client/ListAddressResolver.java +++ b/src/main/java/com/rabbitmq/client/ListAddressResolver.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/LongString.java b/src/main/java/com/rabbitmq/client/LongString.java index 447ef1e510..3b091b98fc 100644 --- a/src/main/java/com/rabbitmq/client/LongString.java +++ b/src/main/java/com/rabbitmq/client/LongString.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/MalformedFrameException.java b/src/main/java/com/rabbitmq/client/MalformedFrameException.java index ae799f0f5d..a05dc95928 100644 --- a/src/main/java/com/rabbitmq/client/MalformedFrameException.java +++ b/src/main/java/com/rabbitmq/client/MalformedFrameException.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/MapRpcServer.java b/src/main/java/com/rabbitmq/client/MapRpcServer.java index 93ceaa10fe..5a65fe3126 100644 --- a/src/main/java/com/rabbitmq/client/MapRpcServer.java +++ b/src/main/java/com/rabbitmq/client/MapRpcServer.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/MessageProperties.java b/src/main/java/com/rabbitmq/client/MessageProperties.java index 8369eeb645..bd7b6cd71c 100644 --- a/src/main/java/com/rabbitmq/client/MessageProperties.java +++ b/src/main/java/com/rabbitmq/client/MessageProperties.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/Method.java b/src/main/java/com/rabbitmq/client/Method.java index bd7b8531e7..d6aa573ce0 100644 --- a/src/main/java/com/rabbitmq/client/Method.java +++ b/src/main/java/com/rabbitmq/client/Method.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/MetricsCollector.java b/src/main/java/com/rabbitmq/client/MetricsCollector.java index 9b289d87bd..3c4aada94d 100644 --- a/src/main/java/com/rabbitmq/client/MetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/MetricsCollector.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/MissedHeartbeatException.java b/src/main/java/com/rabbitmq/client/MissedHeartbeatException.java index 83400d2db5..ef3bf5335d 100644 --- a/src/main/java/com/rabbitmq/client/MissedHeartbeatException.java +++ b/src/main/java/com/rabbitmq/client/MissedHeartbeatException.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java b/src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java index 163fe8afe4..b2e9b703ef 100644 --- a/src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/PossibleAuthenticationFailureException.java b/src/main/java/com/rabbitmq/client/PossibleAuthenticationFailureException.java index d6cca886db..9c8876d8e4 100644 --- a/src/main/java/com/rabbitmq/client/PossibleAuthenticationFailureException.java +++ b/src/main/java/com/rabbitmq/client/PossibleAuthenticationFailureException.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/ProtocolVersionMismatchException.java b/src/main/java/com/rabbitmq/client/ProtocolVersionMismatchException.java index 8cd857545b..e15e5873e3 100644 --- a/src/main/java/com/rabbitmq/client/ProtocolVersionMismatchException.java +++ b/src/main/java/com/rabbitmq/client/ProtocolVersionMismatchException.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/Recoverable.java b/src/main/java/com/rabbitmq/client/Recoverable.java index c4b066f66c..30d68992ba 100644 --- a/src/main/java/com/rabbitmq/client/Recoverable.java +++ b/src/main/java/com/rabbitmq/client/Recoverable.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/RecoveryDelayHandler.java b/src/main/java/com/rabbitmq/client/RecoveryDelayHandler.java index e00c7d3940..84a2d577e7 100644 --- a/src/main/java/com/rabbitmq/client/RecoveryDelayHandler.java +++ b/src/main/java/com/rabbitmq/client/RecoveryDelayHandler.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/RecoveryListener.java b/src/main/java/com/rabbitmq/client/RecoveryListener.java index 968b828521..a3374414e2 100644 --- a/src/main/java/com/rabbitmq/client/RecoveryListener.java +++ b/src/main/java/com/rabbitmq/client/RecoveryListener.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/Return.java b/src/main/java/com/rabbitmq/client/Return.java index f441a69873..d25532b773 100644 --- a/src/main/java/com/rabbitmq/client/Return.java +++ b/src/main/java/com/rabbitmq/client/Return.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/ReturnCallback.java b/src/main/java/com/rabbitmq/client/ReturnCallback.java index 1eb1c99271..efa3ad6065 100644 --- a/src/main/java/com/rabbitmq/client/ReturnCallback.java +++ b/src/main/java/com/rabbitmq/client/ReturnCallback.java @@ -1,7 +1,7 @@ // Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/ReturnListener.java b/src/main/java/com/rabbitmq/client/ReturnListener.java index 2ec72fbc15..5f45f84ef4 100644 --- a/src/main/java/com/rabbitmq/client/ReturnListener.java +++ b/src/main/java/com/rabbitmq/client/ReturnListener.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/RpcClient.java b/src/main/java/com/rabbitmq/client/RpcClient.java index 7e5a4e4ef6..9d42e60d09 100644 --- a/src/main/java/com/rabbitmq/client/RpcClient.java +++ b/src/main/java/com/rabbitmq/client/RpcClient.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/RpcClientParams.java b/src/main/java/com/rabbitmq/client/RpcClientParams.java index ea1ab30d87..190792250f 100644 --- a/src/main/java/com/rabbitmq/client/RpcClientParams.java +++ b/src/main/java/com/rabbitmq/client/RpcClientParams.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/RpcServer.java b/src/main/java/com/rabbitmq/client/RpcServer.java index a1bc413c50..426c8d749f 100644 --- a/src/main/java/com/rabbitmq/client/RpcServer.java +++ b/src/main/java/com/rabbitmq/client/RpcServer.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/SaslConfig.java b/src/main/java/com/rabbitmq/client/SaslConfig.java index d8555cf6b2..5042f2c16f 100644 --- a/src/main/java/com/rabbitmq/client/SaslConfig.java +++ b/src/main/java/com/rabbitmq/client/SaslConfig.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/SaslMechanism.java b/src/main/java/com/rabbitmq/client/SaslMechanism.java index d411f2072e..9a11b5a27f 100644 --- a/src/main/java/com/rabbitmq/client/SaslMechanism.java +++ b/src/main/java/com/rabbitmq/client/SaslMechanism.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/ShutdownListener.java b/src/main/java/com/rabbitmq/client/ShutdownListener.java index 5a2427334f..9775e454b0 100644 --- a/src/main/java/com/rabbitmq/client/ShutdownListener.java +++ b/src/main/java/com/rabbitmq/client/ShutdownListener.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/ShutdownNotifier.java b/src/main/java/com/rabbitmq/client/ShutdownNotifier.java index 66aa021d7a..9c1e3e8bfc 100644 --- a/src/main/java/com/rabbitmq/client/ShutdownNotifier.java +++ b/src/main/java/com/rabbitmq/client/ShutdownNotifier.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/ShutdownSignalException.java b/src/main/java/com/rabbitmq/client/ShutdownSignalException.java index 769158198d..24be455978 100644 --- a/src/main/java/com/rabbitmq/client/ShutdownSignalException.java +++ b/src/main/java/com/rabbitmq/client/ShutdownSignalException.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/SocketChannelConfigurator.java b/src/main/java/com/rabbitmq/client/SocketChannelConfigurator.java index 43307caada..4571e707f9 100644 --- a/src/main/java/com/rabbitmq/client/SocketChannelConfigurator.java +++ b/src/main/java/com/rabbitmq/client/SocketChannelConfigurator.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/SocketChannelConfigurators.java b/src/main/java/com/rabbitmq/client/SocketChannelConfigurators.java index 0355528b4e..711af1cf58 100644 --- a/src/main/java/com/rabbitmq/client/SocketChannelConfigurators.java +++ b/src/main/java/com/rabbitmq/client/SocketChannelConfigurators.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/SocketConfigurator.java b/src/main/java/com/rabbitmq/client/SocketConfigurator.java index 8a49c57d96..151f572461 100644 --- a/src/main/java/com/rabbitmq/client/SocketConfigurator.java +++ b/src/main/java/com/rabbitmq/client/SocketConfigurator.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/SocketConfigurators.java b/src/main/java/com/rabbitmq/client/SocketConfigurators.java index 5d3ea0e280..23bc1b6a1b 100644 --- a/src/main/java/com/rabbitmq/client/SocketConfigurators.java +++ b/src/main/java/com/rabbitmq/client/SocketConfigurators.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/SslContextFactory.java b/src/main/java/com/rabbitmq/client/SslContextFactory.java index 468c1237cd..0b285a9bf9 100644 --- a/src/main/java/com/rabbitmq/client/SslContextFactory.java +++ b/src/main/java/com/rabbitmq/client/SslContextFactory.java @@ -1,7 +1,7 @@ // Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/SslEngineConfigurator.java b/src/main/java/com/rabbitmq/client/SslEngineConfigurator.java index 6f95bb392a..0ed04182f3 100644 --- a/src/main/java/com/rabbitmq/client/SslEngineConfigurator.java +++ b/src/main/java/com/rabbitmq/client/SslEngineConfigurator.java @@ -1,7 +1,7 @@ // Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/SslEngineConfigurators.java b/src/main/java/com/rabbitmq/client/SslEngineConfigurators.java index 0cb7b451d7..6e8ca36589 100644 --- a/src/main/java/com/rabbitmq/client/SslEngineConfigurators.java +++ b/src/main/java/com/rabbitmq/client/SslEngineConfigurators.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/StringRpcServer.java b/src/main/java/com/rabbitmq/client/StringRpcServer.java index 375079607a..d437cb28b4 100644 --- a/src/main/java/com/rabbitmq/client/StringRpcServer.java +++ b/src/main/java/com/rabbitmq/client/StringRpcServer.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/TopologyRecoveryException.java b/src/main/java/com/rabbitmq/client/TopologyRecoveryException.java index cf9d18d105..bdd8b7f807 100644 --- a/src/main/java/com/rabbitmq/client/TopologyRecoveryException.java +++ b/src/main/java/com/rabbitmq/client/TopologyRecoveryException.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/TrustEverythingTrustManager.java b/src/main/java/com/rabbitmq/client/TrustEverythingTrustManager.java index 9001d02507..e7913d048e 100644 --- a/src/main/java/com/rabbitmq/client/TrustEverythingTrustManager.java +++ b/src/main/java/com/rabbitmq/client/TrustEverythingTrustManager.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/UnblockedCallback.java b/src/main/java/com/rabbitmq/client/UnblockedCallback.java index 76ac083ac7..6d79423922 100644 --- a/src/main/java/com/rabbitmq/client/UnblockedCallback.java +++ b/src/main/java/com/rabbitmq/client/UnblockedCallback.java @@ -1,7 +1,7 @@ // Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/UnexpectedFrameError.java b/src/main/java/com/rabbitmq/client/UnexpectedFrameError.java index e8275aec3a..e15e449e5b 100644 --- a/src/main/java/com/rabbitmq/client/UnexpectedFrameError.java +++ b/src/main/java/com/rabbitmq/client/UnexpectedFrameError.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/UnexpectedMethodError.java b/src/main/java/com/rabbitmq/client/UnexpectedMethodError.java index ab30336a07..f5cde49379 100644 --- a/src/main/java/com/rabbitmq/client/UnexpectedMethodError.java +++ b/src/main/java/com/rabbitmq/client/UnexpectedMethodError.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/UnknownClassOrMethodId.java b/src/main/java/com/rabbitmq/client/UnknownClassOrMethodId.java index 1f0e3715f3..3ad973a7b6 100644 --- a/src/main/java/com/rabbitmq/client/UnknownClassOrMethodId.java +++ b/src/main/java/com/rabbitmq/client/UnknownClassOrMethodId.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/UnroutableRpcRequestException.java b/src/main/java/com/rabbitmq/client/UnroutableRpcRequestException.java index 89e9d059f0..1a2877e14a 100644 --- a/src/main/java/com/rabbitmq/client/UnroutableRpcRequestException.java +++ b/src/main/java/com/rabbitmq/client/UnroutableRpcRequestException.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/AMQBasicProperties.java b/src/main/java/com/rabbitmq/client/impl/AMQBasicProperties.java index 591713e706..54f312f06a 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQBasicProperties.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQBasicProperties.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java index 837fdef8d9..fe64ab370e 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/AMQCommand.java b/src/main/java/com/rabbitmq/client/impl/AMQCommand.java index 0395bb10f6..b8cb3c97dd 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQCommand.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQCommand.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index d99784f933..311391ba82 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/AMQContentHeader.java b/src/main/java/com/rabbitmq/client/impl/AMQContentHeader.java index 523336e0ca..e3bf4a479f 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQContentHeader.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQContentHeader.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java index c0a3c5eb6b..44cf1aff9e 100644 --- a/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/CRDemoMechanism.java b/src/main/java/com/rabbitmq/client/impl/CRDemoMechanism.java index e516750b6c..85f0d47cc4 100644 --- a/src/main/java/com/rabbitmq/client/impl/CRDemoMechanism.java +++ b/src/main/java/com/rabbitmq/client/impl/CRDemoMechanism.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelManager.java b/src/main/java/com/rabbitmq/client/impl/ChannelManager.java index 162c141f34..59f7bb3fee 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelManager.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelManager.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java index 2bbc37a3ca..8a769a0d45 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelN.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/ClientVersion.java b/src/main/java/com/rabbitmq/client/impl/ClientVersion.java index 53ec1b927c..556bd6dc48 100644 --- a/src/main/java/com/rabbitmq/client/impl/ClientVersion.java +++ b/src/main/java/com/rabbitmq/client/impl/ClientVersion.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/CommandAssembler.java b/src/main/java/com/rabbitmq/client/impl/CommandAssembler.java index 8a2915c0d7..f19294862f 100644 --- a/src/main/java/com/rabbitmq/client/impl/CommandAssembler.java +++ b/src/main/java/com/rabbitmq/client/impl/CommandAssembler.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/CompletableFutureRpcWrapper.java b/src/main/java/com/rabbitmq/client/impl/CompletableFutureRpcWrapper.java index 1f1b91f569..2157e15d71 100644 --- a/src/main/java/com/rabbitmq/client/impl/CompletableFutureRpcWrapper.java +++ b/src/main/java/com/rabbitmq/client/impl/CompletableFutureRpcWrapper.java @@ -1,7 +1,7 @@ // Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java b/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java index 92428fc436..a2b49d0f98 100644 --- a/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java +++ b/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/ConsumerDispatcher.java b/src/main/java/com/rabbitmq/client/impl/ConsumerDispatcher.java index bb22d9f626..fec98710fe 100644 --- a/src/main/java/com/rabbitmq/client/impl/ConsumerDispatcher.java +++ b/src/main/java/com/rabbitmq/client/impl/ConsumerDispatcher.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/ConsumerWorkService.java b/src/main/java/com/rabbitmq/client/impl/ConsumerWorkService.java index bb662d98e7..b3810aae2f 100644 --- a/src/main/java/com/rabbitmq/client/impl/ConsumerWorkService.java +++ b/src/main/java/com/rabbitmq/client/impl/ConsumerWorkService.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java b/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java index d3502e9fe2..115c3ef520 100644 --- a/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java +++ b/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java b/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java index 59440bc7e7..029329a13d 100644 --- a/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java +++ b/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java index abcfb6af17..19b159df78 100644 --- a/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. @@ -63,4 +63,4 @@ default void refresh() { // no need to refresh anything by default } -} \ No newline at end of file +} diff --git a/src/main/java/com/rabbitmq/client/impl/CredentialsRefreshService.java b/src/main/java/com/rabbitmq/client/impl/CredentialsRefreshService.java index d365053af1..a490a61a5b 100644 --- a/src/main/java/com/rabbitmq/client/impl/CredentialsRefreshService.java +++ b/src/main/java/com/rabbitmq/client/impl/CredentialsRefreshService.java @@ -1,7 +1,7 @@ // Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java index 6263524898..eaf8a90c0c 100644 --- a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java index 2beafaad74..f4edeae391 100644 --- a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java +++ b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java @@ -1,7 +1,7 @@ // Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/DefaultExceptionHandler.java b/src/main/java/com/rabbitmq/client/impl/DefaultExceptionHandler.java index f1a0def2f3..f521a37c14 100644 --- a/src/main/java/com/rabbitmq/client/impl/DefaultExceptionHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/DefaultExceptionHandler.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/Environment.java b/src/main/java/com/rabbitmq/client/impl/Environment.java index c7f6c528b0..149b9a102e 100644 --- a/src/main/java/com/rabbitmq/client/impl/Environment.java +++ b/src/main/java/com/rabbitmq/client/impl/Environment.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/ErrorOnWriteListener.java b/src/main/java/com/rabbitmq/client/impl/ErrorOnWriteListener.java index 7edf05e994..dd9de0ce1c 100644 --- a/src/main/java/com/rabbitmq/client/impl/ErrorOnWriteListener.java +++ b/src/main/java/com/rabbitmq/client/impl/ErrorOnWriteListener.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/ExternalMechanism.java b/src/main/java/com/rabbitmq/client/impl/ExternalMechanism.java index 5cddc69ac4..e50a0c17c7 100644 --- a/src/main/java/com/rabbitmq/client/impl/ExternalMechanism.java +++ b/src/main/java/com/rabbitmq/client/impl/ExternalMechanism.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/ForgivingExceptionHandler.java b/src/main/java/com/rabbitmq/client/impl/ForgivingExceptionHandler.java index e4c2648394..8a7d790382 100644 --- a/src/main/java/com/rabbitmq/client/impl/ForgivingExceptionHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/ForgivingExceptionHandler.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/Frame.java b/src/main/java/com/rabbitmq/client/impl/Frame.java index f99b9d1260..b1ecd916dd 100644 --- a/src/main/java/com/rabbitmq/client/impl/Frame.java +++ b/src/main/java/com/rabbitmq/client/impl/Frame.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/FrameHandler.java b/src/main/java/com/rabbitmq/client/impl/FrameHandler.java index 0e54b34435..8d49352cb5 100644 --- a/src/main/java/com/rabbitmq/client/impl/FrameHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/FrameHandler.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/HeartbeatSender.java b/src/main/java/com/rabbitmq/client/impl/HeartbeatSender.java index 998581d0a5..d682317fe3 100644 --- a/src/main/java/com/rabbitmq/client/impl/HeartbeatSender.java +++ b/src/main/java/com/rabbitmq/client/impl/HeartbeatSender.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/LongStringHelper.java b/src/main/java/com/rabbitmq/client/impl/LongStringHelper.java index d80d9a01f3..0a824db6de 100644 --- a/src/main/java/com/rabbitmq/client/impl/LongStringHelper.java +++ b/src/main/java/com/rabbitmq/client/impl/LongStringHelper.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/Method.java b/src/main/java/com/rabbitmq/client/impl/Method.java index 0b894416ac..73b0e5e0d5 100644 --- a/src/main/java/com/rabbitmq/client/impl/Method.java +++ b/src/main/java/com/rabbitmq/client/impl/Method.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/MethodArgumentReader.java b/src/main/java/com/rabbitmq/client/impl/MethodArgumentReader.java index 24ab627450..e5c3f437ee 100644 --- a/src/main/java/com/rabbitmq/client/impl/MethodArgumentReader.java +++ b/src/main/java/com/rabbitmq/client/impl/MethodArgumentReader.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/MethodArgumentWriter.java b/src/main/java/com/rabbitmq/client/impl/MethodArgumentWriter.java index 02317eec87..f452191413 100644 --- a/src/main/java/com/rabbitmq/client/impl/MethodArgumentWriter.java +++ b/src/main/java/com/rabbitmq/client/impl/MethodArgumentWriter.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java index ab910361df..cd8e7b829d 100644 --- a/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/NetworkConnection.java b/src/main/java/com/rabbitmq/client/impl/NetworkConnection.java index 747a1921a7..03ca1d2201 100644 --- a/src/main/java/com/rabbitmq/client/impl/NetworkConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/NetworkConnection.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java index da3ff81973..5e9618317d 100644 --- a/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java @@ -1,7 +1,7 @@ // Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/OAuthTokenManagementException.java b/src/main/java/com/rabbitmq/client/impl/OAuthTokenManagementException.java index cf17053b24..d3419189cb 100644 --- a/src/main/java/com/rabbitmq/client/impl/OAuthTokenManagementException.java +++ b/src/main/java/com/rabbitmq/client/impl/OAuthTokenManagementException.java @@ -1,7 +1,7 @@ // Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/PlainMechanism.java b/src/main/java/com/rabbitmq/client/impl/PlainMechanism.java index c586385299..75651d74b0 100644 --- a/src/main/java/com/rabbitmq/client/impl/PlainMechanism.java +++ b/src/main/java/com/rabbitmq/client/impl/PlainMechanism.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProvider.java index a4cc01c186..cd8f855b01 100644 --- a/src/main/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProvider.java @@ -1,7 +1,7 @@ // Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/RpcContinuationRpcWrapper.java b/src/main/java/com/rabbitmq/client/impl/RpcContinuationRpcWrapper.java index 8fcf901b55..71d60a4690 100644 --- a/src/main/java/com/rabbitmq/client/impl/RpcContinuationRpcWrapper.java +++ b/src/main/java/com/rabbitmq/client/impl/RpcContinuationRpcWrapper.java @@ -1,7 +1,7 @@ // Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/RpcWrapper.java b/src/main/java/com/rabbitmq/client/impl/RpcWrapper.java index 84c3bb0363..8d81258ffc 100644 --- a/src/main/java/com/rabbitmq/client/impl/RpcWrapper.java +++ b/src/main/java/com/rabbitmq/client/impl/RpcWrapper.java @@ -1,7 +1,7 @@ // Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/SetQueue.java b/src/main/java/com/rabbitmq/client/impl/SetQueue.java index 9ab2cd3526..6a5dc8db12 100644 --- a/src/main/java/com/rabbitmq/client/impl/SetQueue.java +++ b/src/main/java/com/rabbitmq/client/impl/SetQueue.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/ShutdownNotifierComponent.java b/src/main/java/com/rabbitmq/client/impl/ShutdownNotifierComponent.java index 0ee95e083c..e4ec15836b 100644 --- a/src/main/java/com/rabbitmq/client/impl/ShutdownNotifierComponent.java +++ b/src/main/java/com/rabbitmq/client/impl/ShutdownNotifierComponent.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java b/src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java index 8d1d2eee15..6efd6f83f9 100644 --- a/src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/SocketFrameHandlerFactory.java b/src/main/java/com/rabbitmq/client/impl/SocketFrameHandlerFactory.java index 0391b31297..1186b6ea93 100644 --- a/src/main/java/com/rabbitmq/client/impl/SocketFrameHandlerFactory.java +++ b/src/main/java/com/rabbitmq/client/impl/SocketFrameHandlerFactory.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java index f6273bef19..07e7780817 100644 --- a/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/StrictExceptionHandler.java b/src/main/java/com/rabbitmq/client/impl/StrictExceptionHandler.java index d1f54768b0..62f37d72b4 100644 --- a/src/main/java/com/rabbitmq/client/impl/StrictExceptionHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/StrictExceptionHandler.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/TlsUtils.java b/src/main/java/com/rabbitmq/client/impl/TlsUtils.java index 5b4290f79c..a11deddc2c 100644 --- a/src/main/java/com/rabbitmq/client/impl/TlsUtils.java +++ b/src/main/java/com/rabbitmq/client/impl/TlsUtils.java @@ -1,7 +1,7 @@ // Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/TruncatedInputStream.java b/src/main/java/com/rabbitmq/client/impl/TruncatedInputStream.java index a572952af8..dd35c3f2e6 100644 --- a/src/main/java/com/rabbitmq/client/impl/TruncatedInputStream.java +++ b/src/main/java/com/rabbitmq/client/impl/TruncatedInputStream.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/UnknownChannelException.java b/src/main/java/com/rabbitmq/client/impl/UnknownChannelException.java index 5e9474c5a9..ff59b907cf 100644 --- a/src/main/java/com/rabbitmq/client/impl/UnknownChannelException.java +++ b/src/main/java/com/rabbitmq/client/impl/UnknownChannelException.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/UpdateSecretExtension.java b/src/main/java/com/rabbitmq/client/impl/UpdateSecretExtension.java index 5edd65813c..3028a886ab 100644 --- a/src/main/java/com/rabbitmq/client/impl/UpdateSecretExtension.java +++ b/src/main/java/com/rabbitmq/client/impl/UpdateSecretExtension.java @@ -1,7 +1,7 @@ // Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/ValueReader.java b/src/main/java/com/rabbitmq/client/impl/ValueReader.java index 9611324f3a..83455bfe66 100644 --- a/src/main/java/com/rabbitmq/client/impl/ValueReader.java +++ b/src/main/java/com/rabbitmq/client/impl/ValueReader.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/ValueWriter.java b/src/main/java/com/rabbitmq/client/impl/ValueWriter.java index e6167cec7e..c167fc0475 100644 --- a/src/main/java/com/rabbitmq/client/impl/ValueWriter.java +++ b/src/main/java/com/rabbitmq/client/impl/ValueWriter.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java b/src/main/java/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java index 97be3a8270..60dbe04bb4 100644 --- a/src/main/java/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java +++ b/src/main/java/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/Version.java b/src/main/java/com/rabbitmq/client/impl/Version.java index 109359fe3d..3e64d51702 100644 --- a/src/main/java/com/rabbitmq/client/impl/Version.java +++ b/src/main/java/com/rabbitmq/client/impl/Version.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/WorkPool.java b/src/main/java/com/rabbitmq/client/impl/WorkPool.java index 39b8b743b7..e4d7dc8cfe 100644 --- a/src/main/java/com/rabbitmq/client/impl/WorkPool.java +++ b/src/main/java/com/rabbitmq/client/impl/WorkPool.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/WorkPoolFullException.java b/src/main/java/com/rabbitmq/client/impl/WorkPoolFullException.java index eba1fe14cf..68e7175f1a 100644 --- a/src/main/java/com/rabbitmq/client/impl/WorkPoolFullException.java +++ b/src/main/java/com/rabbitmq/client/impl/WorkPoolFullException.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/nio/ByteBufferOutputStream.java b/src/main/java/com/rabbitmq/client/impl/nio/ByteBufferOutputStream.java index 16fe3f2682..e8ed5ff841 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/ByteBufferOutputStream.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/ByteBufferOutputStream.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java b/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java index bc99531070..8352174360 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/nio/FrameWriteRequest.java b/src/main/java/com/rabbitmq/client/impl/nio/FrameWriteRequest.java index 33a5ba5b74..d291a0d3f4 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/FrameWriteRequest.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/FrameWriteRequest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/nio/HeaderWriteRequest.java b/src/main/java/com/rabbitmq/client/impl/nio/HeaderWriteRequest.java index 79e34359c3..558f35e025 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/HeaderWriteRequest.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/HeaderWriteRequest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioHelper.java b/src/main/java/com/rabbitmq/client/impl/nio/NioHelper.java index 3438013c1f..ab8a49b71b 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioHelper.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioHelper.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java b/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java index f194eeef42..ae7fa970e9 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioLoopContext.java b/src/main/java/com/rabbitmq/client/impl/nio/NioLoopContext.java index a73a7a0420..55412e0908 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioLoopContext.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioLoopContext.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java b/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java index fa0f545605..88eedf9145 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SelectorHolder.java b/src/main/java/com/rabbitmq/client/impl/nio/SelectorHolder.java index 7426280acb..97b64b2be1 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SelectorHolder.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SelectorHolder.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandler.java b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandler.java index d46ce4e0bb..c17c5e9579 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandler.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java index f4473b8ae3..10f550d70a 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java index b5822fcd91..50f08a59f2 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelRegistration.java b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelRegistration.java index 2befb3d3a6..2c9d3f0d03 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelRegistration.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelRegistration.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferOutputStream.java b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferOutputStream.java index 8ec782613d..c861ad6e77 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferOutputStream.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferOutputStream.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineFrameBuilder.java b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineFrameBuilder.java index 141bb47293..c2f1923874 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineFrameBuilder.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineFrameBuilder.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java index 0de786c7b3..1e7e3a0793 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/nio/WriteRequest.java b/src/main/java/com/rabbitmq/client/impl/nio/WriteRequest.java index b696bc421f..c61731e18b 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/WriteRequest.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/WriteRequest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java index 969fb45593..f2afc9d04c 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index 785d98e5f4..94b24aa7c2 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/BackoffPolicy.java b/src/main/java/com/rabbitmq/client/impl/recovery/BackoffPolicy.java index 6ed2a2deef..08498683ab 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/BackoffPolicy.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/BackoffPolicy.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/ConsumerRecoveryListener.java b/src/main/java/com/rabbitmq/client/impl/recovery/ConsumerRecoveryListener.java index 291528af3e..8c87d86090 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/ConsumerRecoveryListener.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/ConsumerRecoveryListener.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java b/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java index 1fa64afa4e..dc55fc7ed4 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/QueueRecoveryListener.java b/src/main/java/com/rabbitmq/client/impl/recovery/QueueRecoveryListener.java index 55eef2d9f1..66f7f9248f 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/QueueRecoveryListener.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/QueueRecoveryListener.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedBinding.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedBinding.java index 2cdf188ed7..0ddf4e3bcf 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedBinding.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedBinding.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedConsumer.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedConsumer.java index 4aa87a2d0b..3b0d5009d5 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedConsumer.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedConsumer.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedEntity.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedEntity.java index c55a398563..a9fae4c3ae 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedEntity.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedEntity.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchange.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchange.java index d75530fad6..7625b5a870 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchange.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchange.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchangeBinding.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchangeBinding.java index 286b793185..d128b59bf0 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchangeBinding.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchangeBinding.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedNamedEntity.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedNamedEntity.java index b00a9c2df4..6ea8b6fa96 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedNamedEntity.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedNamedEntity.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java index 6cb43cfdae..3580fe091e 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java index 09d2636d32..12ed3d48bb 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnection.java index 94768de1db..251f0aaaa1 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnection.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java index 01a172fac3..ab23cc4494 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelManager.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelManager.java index b9daf354f2..d8aa7123cb 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelManager.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelManager.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java index 206c20a1c7..01cf1c74ee 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryCanBeginListener.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryCanBeginListener.java index 2c272198b4..cb5eae86fb 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryCanBeginListener.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryCanBeginListener.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RetryContext.java b/src/main/java/com/rabbitmq/client/impl/recovery/RetryContext.java index 60645e199a..6640a7e7c1 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RetryContext.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RetryContext.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RetryHandler.java b/src/main/java/com/rabbitmq/client/impl/recovery/RetryHandler.java index 459ca80080..a5eac40fab 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RetryHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RetryHandler.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RetryResult.java b/src/main/java/com/rabbitmq/client/impl/recovery/RetryResult.java index 6c4e693314..df1d6ae1df 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RetryResult.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RetryResult.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryFilter.java b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryFilter.java index 835249ec55..602b5452f5 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryFilter.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryFilter.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryHandlerBuilder.java b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryHandlerBuilder.java index c2ad1078d5..bed71f9f0b 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryHandlerBuilder.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryHandlerBuilder.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java index 8daa2ac33e..6a91a5202a 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/tools/json/JSONUtil.java b/src/main/java/com/rabbitmq/tools/json/JSONUtil.java index f814462e5e..55c2b695ed 100644 --- a/src/main/java/com/rabbitmq/tools/json/JSONUtil.java +++ b/src/main/java/com/rabbitmq/tools/json/JSONUtil.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java index 8b239eed5b..81a1f26b5b 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java index bea5ccf690..da96560bd5 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java index c46b95c259..d167d0318e 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java index 6e311dc6e4..980428612b 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMappingException.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMappingException.java index 6a764e6960..fc998b1b02 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMappingException.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMappingException.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java index 6cfe8eec98..816ec9d879 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/ParameterDescription.java b/src/main/java/com/rabbitmq/tools/jsonrpc/ParameterDescription.java index 6106cbf60c..cc58516b1c 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/ParameterDescription.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/ParameterDescription.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java b/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java index 44ac3a0b76..431d4e6e13 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java b/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java index af2029d98c..8986cc24e2 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/utility/BlockingCell.java b/src/main/java/com/rabbitmq/utility/BlockingCell.java index 9f9dce24a4..f9c588b7cf 100644 --- a/src/main/java/com/rabbitmq/utility/BlockingCell.java +++ b/src/main/java/com/rabbitmq/utility/BlockingCell.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/utility/BlockingValueOrException.java b/src/main/java/com/rabbitmq/utility/BlockingValueOrException.java index 77df219b72..5946ccbb4d 100644 --- a/src/main/java/com/rabbitmq/utility/BlockingValueOrException.java +++ b/src/main/java/com/rabbitmq/utility/BlockingValueOrException.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/utility/IntAllocator.java b/src/main/java/com/rabbitmq/utility/IntAllocator.java index 9c1e93cd1f..88d9f3efb8 100644 --- a/src/main/java/com/rabbitmq/utility/IntAllocator.java +++ b/src/main/java/com/rabbitmq/utility/IntAllocator.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/utility/SensibleClone.java b/src/main/java/com/rabbitmq/utility/SensibleClone.java index 50405ec0eb..78e68cb6a5 100644 --- a/src/main/java/com/rabbitmq/utility/SensibleClone.java +++ b/src/main/java/com/rabbitmq/utility/SensibleClone.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/utility/Utility.java b/src/main/java/com/rabbitmq/utility/Utility.java index f4cbbf324d..b89639c7d6 100644 --- a/src/main/java/com/rabbitmq/utility/Utility.java +++ b/src/main/java/com/rabbitmq/utility/Utility.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/main/java/com/rabbitmq/utility/ValueOrException.java b/src/main/java/com/rabbitmq/utility/ValueOrException.java index 7be45ef8a2..93cb1fe563 100644 --- a/src/main/java/com/rabbitmq/utility/ValueOrException.java +++ b/src/main/java/com/rabbitmq/utility/ValueOrException.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/AbstractJsonRpcTest.java b/src/test/java/com/rabbitmq/client/AbstractJsonRpcTest.java index 017cb6e308..0b6bc20a68 100644 --- a/src/test/java/com/rabbitmq/client/AbstractJsonRpcTest.java +++ b/src/test/java/com/rabbitmq/client/AbstractJsonRpcTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/JacksonJsonRpcTest.java b/src/test/java/com/rabbitmq/client/JacksonJsonRpcTest.java index af9b827810..e7a57021d4 100644 --- a/src/test/java/com/rabbitmq/client/JacksonJsonRpcTest.java +++ b/src/test/java/com/rabbitmq/client/JacksonJsonRpcTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/QueueingConsumer.java b/src/test/java/com/rabbitmq/client/QueueingConsumer.java index 434e7a8d82..33a033008f 100644 --- a/src/test/java/com/rabbitmq/client/QueueingConsumer.java +++ b/src/test/java/com/rabbitmq/client/QueueingConsumer.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/impl/AMQConnectionRefreshCredentialsTest.java b/src/test/java/com/rabbitmq/client/impl/AMQConnectionRefreshCredentialsTest.java index 50493bcbd0..989ee69ffa 100644 --- a/src/test/java/com/rabbitmq/client/impl/AMQConnectionRefreshCredentialsTest.java +++ b/src/test/java/com/rabbitmq/client/impl/AMQConnectionRefreshCredentialsTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java b/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java index 21faa59b15..3bd0cca640 100644 --- a/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java +++ b/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java b/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java index d81722779d..bcf96c7f1c 100644 --- a/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java +++ b/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProviderTest.java b/src/test/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProviderTest.java index d273b3e70b..a65ed3b6ca 100644 --- a/src/test/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProviderTest.java +++ b/src/test/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProviderTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java b/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java index ead66ee8ad..ea0d94c683 100644 --- a/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java +++ b/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java b/src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java index 30141ef9f0..4cc054ca88 100644 --- a/src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java +++ b/src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/AMQBuilderApiTest.java b/src/test/java/com/rabbitmq/client/test/AMQBuilderApiTest.java index 9d6fb50abb..46241c38b3 100644 --- a/src/test/java/com/rabbitmq/client/test/AMQBuilderApiTest.java +++ b/src/test/java/com/rabbitmq/client/test/AMQBuilderApiTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/AMQChannelTest.java b/src/test/java/com/rabbitmq/client/test/AMQChannelTest.java index 73a8731eea..0ea1a89c60 100644 --- a/src/test/java/com/rabbitmq/client/test/AMQChannelTest.java +++ b/src/test/java/com/rabbitmq/client/test/AMQChannelTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java b/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java index c278b4cc13..e36631de7c 100644 --- a/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java +++ b/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java b/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java index 70fdbaaa6e..cd1a32a6aa 100644 --- a/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java +++ b/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/AddressTest.java b/src/test/java/com/rabbitmq/client/test/AddressTest.java index ca714b146b..631dc5d986 100644 --- a/src/test/java/com/rabbitmq/client/test/AddressTest.java +++ b/src/test/java/com/rabbitmq/client/test/AddressTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java b/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java index 9b4b467f9c..a57e92da4d 100644 --- a/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java +++ b/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/BlockingCellTest.java b/src/test/java/com/rabbitmq/client/test/BlockingCellTest.java index 7c4ef998b0..b5c7e9a3b0 100644 --- a/src/test/java/com/rabbitmq/client/test/BlockingCellTest.java +++ b/src/test/java/com/rabbitmq/client/test/BlockingCellTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java b/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java index 0d713308d2..0ea3a02793 100644 --- a/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java +++ b/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java index cda8d3ca44..d61721ad8b 100644 --- a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java +++ b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/Bug20004Test.java b/src/test/java/com/rabbitmq/client/test/Bug20004Test.java index ac62af0095..63e237d4b1 100644 --- a/src/test/java/com/rabbitmq/client/test/Bug20004Test.java +++ b/src/test/java/com/rabbitmq/client/test/Bug20004Test.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/ChannelAsyncCompletableFutureTest.java b/src/test/java/com/rabbitmq/client/test/ChannelAsyncCompletableFutureTest.java index cc1141d116..a871d49455 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelAsyncCompletableFutureTest.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelAsyncCompletableFutureTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/ChannelNTest.java b/src/test/java/com/rabbitmq/client/test/ChannelNTest.java index c955c28071..1568881016 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelNTest.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelNTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/ChannelNumberAllocationTests.java b/src/test/java/com/rabbitmq/client/test/ChannelNumberAllocationTests.java index a3ec4b81f7..aa916529d7 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelNumberAllocationTests.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelNumberAllocationTests.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java b/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java index 948074580f..2e9c4bf9ed 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index 601234b2db..681542ab70 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/ClientVersionTest.java b/src/test/java/com/rabbitmq/client/test/ClientVersionTest.java index 9d7560adaf..c2c39284e3 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientVersionTest.java +++ b/src/test/java/com/rabbitmq/client/test/ClientVersionTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/ClonePropertiesTest.java b/src/test/java/com/rabbitmq/client/test/ClonePropertiesTest.java index 6e50f31e29..aae4d10e28 100644 --- a/src/test/java/com/rabbitmq/client/test/ClonePropertiesTest.java +++ b/src/test/java/com/rabbitmq/client/test/ClonePropertiesTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/CloseInMainLoop.java b/src/test/java/com/rabbitmq/client/test/CloseInMainLoop.java index 109f8200aa..00e9570136 100644 --- a/src/test/java/com/rabbitmq/client/test/CloseInMainLoop.java +++ b/src/test/java/com/rabbitmq/client/test/CloseInMainLoop.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/ConfirmBase.java b/src/test/java/com/rabbitmq/client/test/ConfirmBase.java index 2421bfed40..144ab68564 100644 --- a/src/test/java/com/rabbitmq/client/test/ConfirmBase.java +++ b/src/test/java/com/rabbitmq/client/test/ConfirmBase.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java b/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java index 1846078ff2..a31a4b2ac4 100644 --- a/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java +++ b/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/ConnectionTest.java b/src/test/java/com/rabbitmq/client/test/ConnectionTest.java index cef3e68a18..c7da088e79 100644 --- a/src/test/java/com/rabbitmq/client/test/ConnectionTest.java +++ b/src/test/java/com/rabbitmq/client/test/ConnectionTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/DefaultRetryHandlerTest.java b/src/test/java/com/rabbitmq/client/test/DefaultRetryHandlerTest.java index c6fe244c51..3aa28efdb9 100644 --- a/src/test/java/com/rabbitmq/client/test/DefaultRetryHandlerTest.java +++ b/src/test/java/com/rabbitmq/client/test/DefaultRetryHandlerTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/DnsSrvRecordAddressResolverTest.java b/src/test/java/com/rabbitmq/client/test/DnsSrvRecordAddressResolverTest.java index e315d1147c..4950cc2323 100644 --- a/src/test/java/com/rabbitmq/client/test/DnsSrvRecordAddressResolverTest.java +++ b/src/test/java/com/rabbitmq/client/test/DnsSrvRecordAddressResolverTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java b/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java index 9c4c4197ec..38fd654f3f 100644 --- a/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java +++ b/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/GeneratedClassesTest.java b/src/test/java/com/rabbitmq/client/test/GeneratedClassesTest.java index c144e7e3d3..78919bbca6 100644 --- a/src/test/java/com/rabbitmq/client/test/GeneratedClassesTest.java +++ b/src/test/java/com/rabbitmq/client/test/GeneratedClassesTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/LambdaCallbackTest.java b/src/test/java/com/rabbitmq/client/test/LambdaCallbackTest.java index 29505b73ab..0f30f4f83a 100644 --- a/src/test/java/com/rabbitmq/client/test/LambdaCallbackTest.java +++ b/src/test/java/com/rabbitmq/client/test/LambdaCallbackTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/LongStringTest.java b/src/test/java/com/rabbitmq/client/test/LongStringTest.java index 59f9556e2c..7c711b4fe4 100644 --- a/src/test/java/com/rabbitmq/client/test/LongStringTest.java +++ b/src/test/java/com/rabbitmq/client/test/LongStringTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java b/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java index 5d424a69a3..9c18b2ac1f 100644 --- a/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java +++ b/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/MicrometerMetricsCollectorTest.java b/src/test/java/com/rabbitmq/client/test/MicrometerMetricsCollectorTest.java index 77798a0088..125d185160 100644 --- a/src/test/java/com/rabbitmq/client/test/MicrometerMetricsCollectorTest.java +++ b/src/test/java/com/rabbitmq/client/test/MicrometerMetricsCollectorTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/MultiThreadedChannel.java b/src/test/java/com/rabbitmq/client/test/MultiThreadedChannel.java index 4790016a40..93a2d1c837 100644 --- a/src/test/java/com/rabbitmq/client/test/MultiThreadedChannel.java +++ b/src/test/java/com/rabbitmq/client/test/MultiThreadedChannel.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/NioDeadlockOnConnectionClosing.java b/src/test/java/com/rabbitmq/client/test/NioDeadlockOnConnectionClosing.java index c9e1607653..0f3984ade7 100644 --- a/src/test/java/com/rabbitmq/client/test/NioDeadlockOnConnectionClosing.java +++ b/src/test/java/com/rabbitmq/client/test/NioDeadlockOnConnectionClosing.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java b/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java index 62a237cb83..c4edf038a7 100644 --- a/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java +++ b/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java b/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java index 2a140721a5..40138a26d6 100644 --- a/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java +++ b/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/QueueingConsumerTests.java b/src/test/java/com/rabbitmq/client/test/QueueingConsumerTests.java index 01676ade92..ba9d72e47b 100644 --- a/src/test/java/com/rabbitmq/client/test/QueueingConsumerTests.java +++ b/src/test/java/com/rabbitmq/client/test/QueueingConsumerTests.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/RecoveryAwareAMQConnectionFactoryTest.java b/src/test/java/com/rabbitmq/client/test/RecoveryAwareAMQConnectionFactoryTest.java index f09721a036..785b58ec53 100644 --- a/src/test/java/com/rabbitmq/client/test/RecoveryAwareAMQConnectionFactoryTest.java +++ b/src/test/java/com/rabbitmq/client/test/RecoveryAwareAMQConnectionFactoryTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/RecoveryDelayHandlerTest.java b/src/test/java/com/rabbitmq/client/test/RecoveryDelayHandlerTest.java index 7828b5eefe..be9958b487 100644 --- a/src/test/java/com/rabbitmq/client/test/RecoveryDelayHandlerTest.java +++ b/src/test/java/com/rabbitmq/client/test/RecoveryDelayHandlerTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java b/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java index b72c95ee1d..0a0100cbc6 100644 --- a/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java +++ b/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/RpcTest.java b/src/test/java/com/rabbitmq/client/test/RpcTest.java index a11544f2b4..eb8673183e 100644 --- a/src/test/java/com/rabbitmq/client/test/RpcTest.java +++ b/src/test/java/com/rabbitmq/client/test/RpcTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/RpcTopologyRecordingTest.java b/src/test/java/com/rabbitmq/client/test/RpcTopologyRecordingTest.java index 1f0f023018..3769218fd7 100644 --- a/src/test/java/com/rabbitmq/client/test/RpcTopologyRecordingTest.java +++ b/src/test/java/com/rabbitmq/client/test/RpcTopologyRecordingTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java b/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java index a1fe0175f5..747a2805e5 100644 --- a/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java +++ b/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/SslContextFactoryTest.java b/src/test/java/com/rabbitmq/client/test/SslContextFactoryTest.java index 4f591221ce..585e74f7a8 100644 --- a/src/test/java/com/rabbitmq/client/test/SslContextFactoryTest.java +++ b/src/test/java/com/rabbitmq/client/test/SslContextFactoryTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/StrictExceptionHandlerTest.java b/src/test/java/com/rabbitmq/client/test/StrictExceptionHandlerTest.java index 06bf5efe7c..fbb3ad984b 100644 --- a/src/test/java/com/rabbitmq/client/test/StrictExceptionHandlerTest.java +++ b/src/test/java/com/rabbitmq/client/test/StrictExceptionHandlerTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/TableTest.java b/src/test/java/com/rabbitmq/client/test/TableTest.java index e750301413..bb07a71f21 100644 --- a/src/test/java/com/rabbitmq/client/test/TableTest.java +++ b/src/test/java/com/rabbitmq/client/test/TableTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/TestUtils.java b/src/test/java/com/rabbitmq/client/test/TestUtils.java index b6cec91132..19d63d8d86 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtils.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtils.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/TestUtilsTest.java b/src/test/java/com/rabbitmq/client/test/TestUtilsTest.java index 76e5276d7d..b73e8033cc 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtilsTest.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtilsTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/TlsUtilsTest.java b/src/test/java/com/rabbitmq/client/test/TlsUtilsTest.java index 078989ca12..f04d22dc1c 100644 --- a/src/test/java/com/rabbitmq/client/test/TlsUtilsTest.java +++ b/src/test/java/com/rabbitmq/client/test/TlsUtilsTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/TrafficListenerTest.java b/src/test/java/com/rabbitmq/client/test/TrafficListenerTest.java index 69c223cf31..ebc25349d4 100644 --- a/src/test/java/com/rabbitmq/client/test/TrafficListenerTest.java +++ b/src/test/java/com/rabbitmq/client/test/TrafficListenerTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/TruncatedInputStreamTest.java b/src/test/java/com/rabbitmq/client/test/TruncatedInputStreamTest.java index 570f15c848..3adc9492a0 100644 --- a/src/test/java/com/rabbitmq/client/test/TruncatedInputStreamTest.java +++ b/src/test/java/com/rabbitmq/client/test/TruncatedInputStreamTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/ValueOrExceptionTest.java b/src/test/java/com/rabbitmq/client/test/ValueOrExceptionTest.java index 789dccfa29..1ae80029be 100644 --- a/src/test/java/com/rabbitmq/client/test/ValueOrExceptionTest.java +++ b/src/test/java/com/rabbitmq/client/test/ValueOrExceptionTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/AbstractRejectTest.java b/src/test/java/com/rabbitmq/client/test/functional/AbstractRejectTest.java index 470418c384..8c87db34f1 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/AbstractRejectTest.java +++ b/src/test/java/com/rabbitmq/client/test/functional/AbstractRejectTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/AlternateExchange.java b/src/test/java/com/rabbitmq/client/test/functional/AlternateExchange.java index fc620a5034..8f2dd6675a 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/AlternateExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/AlternateExchange.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/BasicGet.java b/src/test/java/com/rabbitmq/client/test/functional/BasicGet.java index 1e854ec495..e64dee9e9a 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/BasicGet.java +++ b/src/test/java/com/rabbitmq/client/test/functional/BasicGet.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java b/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java index 48c82a22ad..91a5c54d49 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java +++ b/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycleBase.java b/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycleBase.java index ae21a981f5..51c0e93585 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycleBase.java +++ b/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycleBase.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java b/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java index 4782459840..ebb54164a3 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java +++ b/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java b/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java index c3ae467c4f..06f53f715a 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/Confirm.java b/src/test/java/com/rabbitmq/client/test/functional/Confirm.java index 9f0860b820..0c427bd261 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Confirm.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Confirm.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionOpen.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionOpen.java index 9f99ba1797..22fe19e326 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionOpen.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionOpen.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java index 426e3c2c0f..ac43c15faf 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java b/src/test/java/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java index 082725531b..1c68176d76 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConsumerCount.java b/src/test/java/com/rabbitmq/client/test/functional/ConsumerCount.java index 73f91a5e10..b0ba1c3206 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConsumerCount.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConsumerCount.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConsumerPriorities.java b/src/test/java/com/rabbitmq/client/test/functional/ConsumerPriorities.java index a3eebd85bb..10bde1f0f1 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConsumerPriorities.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConsumerPriorities.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java index fa6124ce16..36c09add6a 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/DefaultExchange.java b/src/test/java/com/rabbitmq/client/test/functional/DefaultExchange.java index df2ceb5fdd..7d0e9f7899 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DefaultExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DefaultExchange.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/DirectReplyTo.java b/src/test/java/com/rabbitmq/client/test/functional/DirectReplyTo.java index c8d1befec1..2cef783ba1 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DirectReplyTo.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DirectReplyTo.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/DoubleDeletion.java b/src/test/java/com/rabbitmq/client/test/functional/DoubleDeletion.java index 20b87d7312..14f6dee293 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DoubleDeletion.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DoubleDeletion.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/DurableOnTransient.java b/src/test/java/com/rabbitmq/client/test/functional/DurableOnTransient.java index dc9f5d5155..cfc00d7b0a 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DurableOnTransient.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DurableOnTransient.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExceptionHandling.java b/src/test/java/com/rabbitmq/client/test/functional/ExceptionHandling.java index f0c73fcd17..611a8eea82 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExceptionHandling.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExceptionHandling.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExceptionMessages.java b/src/test/java/com/rabbitmq/client/test/functional/ExceptionMessages.java index d2810dcb94..68f4da2204 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExceptionMessages.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExceptionMessages.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java index 5578560302..7c1e6f2e76 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java index ec763486f0..bbaf6b323c 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeletePredeclared.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeletePredeclared.java index ee25ca6232..28d4d667f6 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeletePredeclared.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeletePredeclared.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java index f2f3916ca5..830a2b89e5 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java index b3ed2f5a3a..cc50182001 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java index 15f63fbd48..ff8cb0a846 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java b/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java index ac1e98e7e6..bfe1bcd826 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java +++ b/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java b/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java index f8a89554a5..db87a38695 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java +++ b/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java b/src/test/java/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java index 2ff1a36781..b2eeee7719 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java +++ b/src/test/java/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java b/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java index b4f9c9b756..62611f2a35 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/InternalExchange.java b/src/test/java/com/rabbitmq/client/test/functional/InternalExchange.java index cfb705b06b..43a571afc8 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/InternalExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/InternalExchange.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/InvalidAcks.java b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcks.java index dff81c600b..217c55e1c9 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/InvalidAcks.java +++ b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcks.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksBase.java b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksBase.java index 025954022f..1c249007bd 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksBase.java +++ b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksBase.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksTx.java b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksTx.java index 635929bb4b..81fc7e61f7 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksTx.java +++ b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksTx.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/MessageCount.java b/src/test/java/com/rabbitmq/client/test/functional/MessageCount.java index a8d302a55a..3cb81344af 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/MessageCount.java +++ b/src/test/java/com/rabbitmq/client/test/functional/MessageCount.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java index 3e2dc6df74..67e25960a7 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/Nack.java b/src/test/java/com/rabbitmq/client/test/functional/Nack.java index 5b39638d78..61c10e589a 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Nack.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Nack.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java b/src/test/java/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java index 829cf3d25f..41d68d94d5 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java +++ b/src/test/java/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/Nowait.java b/src/test/java/com/rabbitmq/client/test/functional/Nowait.java index af79b0d195..5f713fff61 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Nowait.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Nowait.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java b/src/test/java/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java index 16a1cfdf95..4a36a22052 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java +++ b/src/test/java/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/PerMessageTTL.java b/src/test/java/com/rabbitmq/client/test/functional/PerMessageTTL.java index 0b25fbe699..ab09bdbfdd 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/PerMessageTTL.java +++ b/src/test/java/com/rabbitmq/client/test/functional/PerMessageTTL.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/PerQueueTTL.java b/src/test/java/com/rabbitmq/client/test/functional/PerQueueTTL.java index 55c44e6cb3..506ea50c8f 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/PerQueueTTL.java +++ b/src/test/java/com/rabbitmq/client/test/functional/PerQueueTTL.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java b/src/test/java/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java index f4c9914bda..58475877be 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java +++ b/src/test/java/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/Policies.java b/src/test/java/com/rabbitmq/client/test/functional/Policies.java index 8f86294766..f4d1dd4988 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Policies.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Policies.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/QosTests.java b/src/test/java/com/rabbitmq/client/test/functional/QosTests.java index 1634741a83..276a363f4e 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QosTests.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QosTests.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/QueueExclusivity.java b/src/test/java/com/rabbitmq/client/test/functional/QueueExclusivity.java index 3351b1d1a6..6148ebab27 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QueueExclusivity.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QueueExclusivity.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/QueueLease.java b/src/test/java/com/rabbitmq/client/test/functional/QueueLease.java index 3ec1986792..284f6bd67d 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QueueLease.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QueueLease.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java b/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java index c082a91c41..8ee54671dc 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/QueueSizeLimit.java b/src/test/java/com/rabbitmq/client/test/functional/QueueSizeLimit.java index fd4c26343e..8d34862543 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QueueSizeLimit.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QueueSizeLimit.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/Recover.java b/src/test/java/com/rabbitmq/client/test/functional/Recover.java index 654846648f..61d48973ce 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Recover.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Recover.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/Reject.java b/src/test/java/com/rabbitmq/client/test/functional/Reject.java index 11f3d52d37..2d296a13ea 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Reject.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Reject.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java index 6b1eb781a0..8e6c0c6f9e 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java +++ b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/RequeueOnClose.java b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnClose.java index 1900f97218..e86ed31bdf 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/RequeueOnClose.java +++ b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnClose.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java index 6af8d01dd2..c212512a95 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java +++ b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/Routing.java b/src/test/java/com/rabbitmq/client/test/functional/Routing.java index cfaf9eb38b..050eb379b0 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Routing.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Routing.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/SaslMechanisms.java b/src/test/java/com/rabbitmq/client/test/functional/SaslMechanisms.java index 1d769f8a10..631d21a2a5 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/SaslMechanisms.java +++ b/src/test/java/com/rabbitmq/client/test/functional/SaslMechanisms.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/TTLHandling.java b/src/test/java/com/rabbitmq/client/test/functional/TTLHandling.java index 26d501e35f..4a2b23ae5c 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/TTLHandling.java +++ b/src/test/java/com/rabbitmq/client/test/functional/TTLHandling.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/Tables.java b/src/test/java/com/rabbitmq/client/test/functional/Tables.java index ad631596e9..6f8f1854a8 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Tables.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Tables.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java index 27c210639c..3798ddf70a 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java +++ b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java index 215645fcaf..ffc744bb86 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java +++ b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java @@ -1,7 +1,7 @@ // Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/Transactions.java b/src/test/java/com/rabbitmq/client/test/functional/Transactions.java index 25fb8410c5..3e3d66883b 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Transactions.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Transactions.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java b/src/test/java/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java index fcafc73ebb..29c4faa2b4 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java b/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java index de118e90dd..e028c3cf47 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java +++ b/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/functional/UserIDHeader.java b/src/test/java/com/rabbitmq/client/test/functional/UserIDHeader.java index 17db1bc8a8..d776029df5 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/UserIDHeader.java +++ b/src/test/java/com/rabbitmq/client/test/functional/UserIDHeader.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java b/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java index 886820c094..a0e857d828 100644 --- a/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java +++ b/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java b/src/test/java/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java index fbc019b263..676dac7015 100644 --- a/src/test/java/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java +++ b/src/test/java/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java b/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java index 30e07d3a2c..4856ea151b 100644 --- a/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/server/Bug19219Test.java b/src/test/java/com/rabbitmq/client/test/server/Bug19219Test.java index 7f48b7aeb4..e16d40d731 100644 --- a/src/test/java/com/rabbitmq/client/test/server/Bug19219Test.java +++ b/src/test/java/com/rabbitmq/client/test/server/Bug19219Test.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java b/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java index cd8a99ed34..a890f2ca66 100644 --- a/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java +++ b/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java b/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java index 8ee7169797..312ce61810 100644 --- a/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java +++ b/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java b/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java index a8c4ff6b8d..5be557cd3d 100644 --- a/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java +++ b/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java b/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java index 0aa40943fe..b4c9a0bc6a 100644 --- a/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java +++ b/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java b/src/test/java/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java index 7d931f12cf..2be62c3c9e 100644 --- a/src/test/java/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java +++ b/src/test/java/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/server/Firehose.java b/src/test/java/com/rabbitmq/client/test/server/Firehose.java index 56b0cdcb10..28064a1383 100644 --- a/src/test/java/com/rabbitmq/client/test/server/Firehose.java +++ b/src/test/java/com/rabbitmq/client/test/server/Firehose.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/server/HATests.java b/src/test/java/com/rabbitmq/client/test/server/HATests.java index 8918098f5d..d4078c4ac2 100644 --- a/src/test/java/com/rabbitmq/client/test/server/HATests.java +++ b/src/test/java/com/rabbitmq/client/test/server/HATests.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/server/LoopbackUsers.java b/src/test/java/com/rabbitmq/client/test/server/LoopbackUsers.java index d9b7be93b1..44f323ab95 100644 --- a/src/test/java/com/rabbitmq/client/test/server/LoopbackUsers.java +++ b/src/test/java/com/rabbitmq/client/test/server/LoopbackUsers.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java b/src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java index b664e7b62e..690a77ddcd 100644 --- a/src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java +++ b/src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java b/src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java index 4080fdce8c..f59e4ced96 100644 --- a/src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/server/Permissions.java b/src/test/java/com/rabbitmq/client/test/server/Permissions.java index 24c25a4391..c67d0cc0c6 100644 --- a/src/test/java/com/rabbitmq/client/test/server/Permissions.java +++ b/src/test/java/com/rabbitmq/client/test/server/Permissions.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/server/PersistenceGuarantees.java b/src/test/java/com/rabbitmq/client/test/server/PersistenceGuarantees.java index 42846db2a1..69bc8093b4 100644 --- a/src/test/java/com/rabbitmq/client/test/server/PersistenceGuarantees.java +++ b/src/test/java/com/rabbitmq/client/test/server/PersistenceGuarantees.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/server/PriorityQueues.java b/src/test/java/com/rabbitmq/client/test/server/PriorityQueues.java index 805b5c6fc4..76c34dbbeb 100644 --- a/src/test/java/com/rabbitmq/client/test/server/PriorityQueues.java +++ b/src/test/java/com/rabbitmq/client/test/server/PriorityQueues.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/server/ServerTests.java b/src/test/java/com/rabbitmq/client/test/server/ServerTests.java index bda7cac3fd..a532586e40 100644 --- a/src/test/java/com/rabbitmq/client/test/server/ServerTests.java +++ b/src/test/java/com/rabbitmq/client/test/server/ServerTests.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/server/Shutdown.java b/src/test/java/com/rabbitmq/client/test/server/Shutdown.java index 53cd63c184..8d7194bd38 100644 --- a/src/test/java/com/rabbitmq/client/test/server/Shutdown.java +++ b/src/test/java/com/rabbitmq/client/test/server/Shutdown.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/server/TopicPermissions.java b/src/test/java/com/rabbitmq/client/test/server/TopicPermissions.java index c258e7a773..5b79de1387 100644 --- a/src/test/java/com/rabbitmq/client/test/server/TopicPermissions.java +++ b/src/test/java/com/rabbitmq/client/test/server/TopicPermissions.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java b/src/test/java/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java index 4aa0839f39..fb65d954b3 100644 --- a/src/test/java/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java +++ b/src/test/java/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java index 9b9e291314..9137213578 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java b/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java index 0ffbc52df5..dde98277d4 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java index 9fef361381..014c02cfdd 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java index 4c22736e8b..29fe35899e 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java index 1dddf62e38..3d629d15ea 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java b/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java index 845e0a476c..49b9ac3ad9 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java @@ -1,7 +1,7 @@ // Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java index dd041fef5c..a14a257c24 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java index 52c3763064..50d4d9003b 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/tools/Host.java b/src/test/java/com/rabbitmq/tools/Host.java index 91f4c68f50..f1adeded61 100644 --- a/src/test/java/com/rabbitmq/tools/Host.java +++ b/src/test/java/com/rabbitmq/tools/Host.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. diff --git a/src/test/java/com/rabbitmq/utility/IntAllocatorTests.java b/src/test/java/com/rabbitmq/utility/IntAllocatorTests.java index 1dbdfa95a6..d29e134442 100644 --- a/src/test/java/com/rabbitmq/utility/IntAllocatorTests.java +++ b/src/test/java/com/rabbitmq/utility/IntAllocatorTests.java @@ -1,7 +1,7 @@ // Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. From 6da919044a1831d3f1a6f56d981f8f0e53b08284 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 17 Jul 2020 16:28:44 +0300 Subject: [PATCH 1260/2114] Drop Exhibit B from our MPL2 file (cherry picked from commit cd331898ea3791f2d4ef3ccbb17dc4e1c6a3f6c3) --- LICENSE-MPL-RabbitMQ | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/LICENSE-MPL-RabbitMQ b/LICENSE-MPL-RabbitMQ index 14e2f777f6..b30605c3b1 100644 --- a/LICENSE-MPL-RabbitMQ +++ b/LICENSE-MPL-RabbitMQ @@ -35,7 +35,7 @@ Mozilla Public License Version 2.0 means any form of the work other than Source Code Form. 1.7. "Larger Work" - means a work that combines Covered Software with other material, in + means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. 1.8. "License" @@ -364,10 +364,4 @@ file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. -You may add additional accurate notices of copyright ownership. - -Exhibit B - "Incompatible With Secondary Licenses" Notice ---------------------------------------------------------- - - This Source Code Form is "Incompatible With Secondary Licenses", as - defined by the Mozilla Public License, v. 2.0. +Copyright (c) 2007-2020 VMware, Inc. or its affiliates. From f149e482df3c56ed44b3ec4dc33a94e9332b3471 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 21 Jul 2020 18:00:52 +0200 Subject: [PATCH 1261/2114] Use MPL 2.0 in pom.xml (cherry picked from commit 283902d3ed7e42098b60cbbf95154aa93a741dbd) --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index f9f31bc6a5..3042444b47 100644 --- a/pom.xml +++ b/pom.xml @@ -23,8 +23,8 @@ repo - MPL 1.1 - https://www.mozilla.org/MPL/MPL-1.1.txt + MPL 2.0 + https://www.mozilla.org/en-US/MPL/2.0/ repo From 9d5f9e902cc066d858a2a50a2e19f8776d4b2114 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2020 23:15:29 +0000 Subject: [PATCH 1262/2114] Bump junit from 4.13 to 4.13.1 Bumps [junit](https://github.com/junit-team/junit4) from 4.13 to 4.13.1. - [Release notes](https://github.com/junit-team/junit4/releases) - [Changelog](https://github.com/junit-team/junit4/blob/main/doc/ReleaseNotes4.13.1.md) - [Commits](https://github.com/junit-team/junit4/compare/r4.13...r4.13.1) Signed-off-by: dependabot[bot] (cherry picked from commit ed63367a63308893c04a0038e721f41a42272e39) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3042444b47..0f2b9911e2 100644 --- a/pom.xml +++ b/pom.xml @@ -59,7 +59,7 @@ 1.4.1 2.10.3 1.2.3 - 4.13 + 4.13.1 3.3.3 3.15.0 9.4.27.v20200227 From 7feb61ebd84e2a09c4e9e1403c9f6a16e29d433e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 14 Oct 2020 10:16:22 +0200 Subject: [PATCH 1263/2114] Bump dependencies References #660 --- pom.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 573d1b1b43..07a3702b12 100644 --- a/pom.xml +++ b/pom.xml @@ -54,10 +54,10 @@ UTF-8 UTF-8 - 1.7.29 - 4.1.2 - 1.3.2 - 2.10.1 + 1.7.30 + 4.1.13 + 1.5.5 + 2.11.3 1.2.3 4.13.1 3.3.3 From 04a5e5c296e8b0a8df7e76940edf4255b3800045 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 14 Oct 2020 10:17:21 +0200 Subject: [PATCH 1264/2114] Bump test dependencies --- pom.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 07a3702b12..7fbbd89726 100644 --- a/pom.xml +++ b/pom.xml @@ -60,10 +60,10 @@ 2.11.3 1.2.3 4.13.1 - 3.3.3 - 3.15.0 - 9.4.27.v20200227 - 1.64 + 3.5.13 + 3.17.2 + 9.4.32.v20200930 + 1.66 3.2.0 2.5.3 From 6a686264aaec141790f1f0168d867b3c3e39819e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 14 Oct 2020 10:16:22 +0200 Subject: [PATCH 1265/2114] Bump dependencies References #660 (cherry picked from commit 7feb61ebd84e2a09c4e9e1403c9f6a16e29d433e) Conflicts: pom.xml --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 0f2b9911e2..2679eddad6 100644 --- a/pom.xml +++ b/pom.xml @@ -55,9 +55,9 @@ UTF-8 1.7.30 - 4.1.5 - 1.4.1 - 2.10.3 + 4.1.13 + 1.5.5 + 2.11.3 1.2.3 4.13.1 3.3.3 From cd182872defc4737a3ac62f83eb1c0bd15f112b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 14 Oct 2020 10:17:21 +0200 Subject: [PATCH 1266/2114] Bump test dependencies (cherry picked from commit 04a5e5c296e8b0a8df7e76940edf4255b3800045) --- pom.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 2679eddad6..5bf24198ed 100644 --- a/pom.xml +++ b/pom.xml @@ -60,10 +60,10 @@ 2.11.3 1.2.3 4.13.1 - 3.3.3 - 3.15.0 - 9.4.27.v20200227 - 1.64 + 3.5.13 + 3.17.2 + 9.4.32.v20200930 + 1.66 3.2.0 2.5.3 From d37a09f784255fe4e9f83b1dbd3fe837b59677b1 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Wed, 14 Oct 2020 13:52:25 +0000 Subject: [PATCH 1267/2114] [maven-release-plugin] prepare release v5.10.0.RC1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 5bf24198ed..54862f41d3 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.10.0-SNAPSHOT + 5.10.0.RC1 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v5.10.0.RC1 From 599e1e889cdf0e1e1416a6442b817b01c92952d8 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Wed, 14 Oct 2020 13:52:31 +0000 Subject: [PATCH 1268/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 54862f41d3..5bf24198ed 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.10.0.RC1 + 5.10.0-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v5.10.0.RC1 + HEAD From afbb7d32ddb5f9d545a62f43b82ee36212ad932b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 14 Oct 2020 16:14:12 +0200 Subject: [PATCH 1269/2114] Set release version to 5.10.0.RC2 --- release-versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-versions.txt b/release-versions.txt index 643407832b..f87d576a21 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,3 +1,3 @@ -RELEASE_VERSION="5.10.0.RC1" +RELEASE_VERSION="5.10.0.RC2" DEVELOPMENT_VERSION="5.10.0-SNAPSHOT" RELEASE_BRANCH="5.x.x-stable" From 4d6847f8573d19b64f15443895ad3413303ac1f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 19 Oct 2020 12:04:28 +0200 Subject: [PATCH 1270/2114] Clean state in AutorecoveringChannel#abort Fixes #661 --- .../impl/recovery/AutorecoveringChannel.java | 39 ++++++++++++------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java index f2afc9d04c..545b26c3ed 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java @@ -17,6 +17,7 @@ import com.rabbitmq.client.*; import com.rabbitmq.client.impl.AMQCommand; +import com.rabbitmq.client.impl.recovery.Utils.IoTimeoutExceptionRunnable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -69,33 +70,41 @@ public Channel getDelegate() { @Override public void close() throws IOException, TimeoutException { - try { - delegate.close(); - } finally { - for (String consumerTag : consumerTags) { - this.connection.deleteRecordedConsumer(consumerTag); - } - this.connection.unregisterChannel(this); - } + executeAndClean(() -> delegate.close()); } @Override public void close(int closeCode, String closeMessage) throws IOException, TimeoutException { - try { - delegate.close(closeCode, closeMessage); - } finally { - this.connection.unregisterChannel(this); - } + executeAndClean(() -> delegate.close(closeCode, closeMessage)); } @Override public void abort() throws IOException { - delegate.abort(); + try { + executeAndClean(() -> delegate.abort()); + } catch (TimeoutException e) { + // abort() ignores exceptions + } } @Override public void abort(int closeCode, String closeMessage) throws IOException { - delegate.abort(closeCode, closeMessage); + try { + executeAndClean(() -> delegate.abort(closeCode, closeMessage)); + } catch (TimeoutException e) { + // abort() ignores exceptions + } + } + + private void executeAndClean(IoTimeoutExceptionRunnable callback) throws IOException, TimeoutException { + try { + callback.run(); + } finally { + for (String consumerTag : consumerTags) { + this.connection.deleteRecordedConsumer(consumerTag); + } + this.connection.unregisterChannel(this); + } } @Override From 35739f24b578699760edbeddb7a7b6b9194cc371 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 19 Oct 2020 12:07:27 +0200 Subject: [PATCH 1271/2114] Add missing class --- .../rabbitmq/client/impl/recovery/Utils.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 src/main/java/com/rabbitmq/client/impl/recovery/Utils.java diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/Utils.java b/src/main/java/com/rabbitmq/client/impl/recovery/Utils.java new file mode 100644 index 0000000000..569f9da73a --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/recovery/Utils.java @@ -0,0 +1,32 @@ +// Copyright (c) 2020 VMware, Inc. or its affiliates. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl.recovery; + +import java.io.IOException; +import java.util.concurrent.TimeoutException; + +final class Utils { + + private Utils() {} + + @FunctionalInterface + interface IoTimeoutExceptionRunnable { + + void run() throws IOException, TimeoutException; + + } + +} From 700fe97e948ce98001323ed54ba4520d4db69fff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 19 Oct 2020 12:04:28 +0200 Subject: [PATCH 1272/2114] Clean state in AutorecoveringChannel#abort Fixes #661 (cherry picked from commit 4d6847f8573d19b64f15443895ad3413303ac1f5) --- .../impl/recovery/AutorecoveringChannel.java | 39 ++++++++++++------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java index f2afc9d04c..545b26c3ed 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java @@ -17,6 +17,7 @@ import com.rabbitmq.client.*; import com.rabbitmq.client.impl.AMQCommand; +import com.rabbitmq.client.impl.recovery.Utils.IoTimeoutExceptionRunnable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -69,33 +70,41 @@ public Channel getDelegate() { @Override public void close() throws IOException, TimeoutException { - try { - delegate.close(); - } finally { - for (String consumerTag : consumerTags) { - this.connection.deleteRecordedConsumer(consumerTag); - } - this.connection.unregisterChannel(this); - } + executeAndClean(() -> delegate.close()); } @Override public void close(int closeCode, String closeMessage) throws IOException, TimeoutException { - try { - delegate.close(closeCode, closeMessage); - } finally { - this.connection.unregisterChannel(this); - } + executeAndClean(() -> delegate.close(closeCode, closeMessage)); } @Override public void abort() throws IOException { - delegate.abort(); + try { + executeAndClean(() -> delegate.abort()); + } catch (TimeoutException e) { + // abort() ignores exceptions + } } @Override public void abort(int closeCode, String closeMessage) throws IOException { - delegate.abort(closeCode, closeMessage); + try { + executeAndClean(() -> delegate.abort(closeCode, closeMessage)); + } catch (TimeoutException e) { + // abort() ignores exceptions + } + } + + private void executeAndClean(IoTimeoutExceptionRunnable callback) throws IOException, TimeoutException { + try { + callback.run(); + } finally { + for (String consumerTag : consumerTags) { + this.connection.deleteRecordedConsumer(consumerTag); + } + this.connection.unregisterChannel(this); + } } @Override From 2f4d11236583fa5986f380b3d85800709a410c77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 19 Oct 2020 12:07:27 +0200 Subject: [PATCH 1273/2114] Add missing class (cherry picked from commit 35739f24b578699760edbeddb7a7b6b9194cc371) --- .../rabbitmq/client/impl/recovery/Utils.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 src/main/java/com/rabbitmq/client/impl/recovery/Utils.java diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/Utils.java b/src/main/java/com/rabbitmq/client/impl/recovery/Utils.java new file mode 100644 index 0000000000..569f9da73a --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/recovery/Utils.java @@ -0,0 +1,32 @@ +// Copyright (c) 2020 VMware, Inc. or its affiliates. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl.recovery; + +import java.io.IOException; +import java.util.concurrent.TimeoutException; + +final class Utils { + + private Utils() {} + + @FunctionalInterface + interface IoTimeoutExceptionRunnable { + + void run() throws IOException, TimeoutException; + + } + +} From e8e719ea51cfbf3b0ec880a1f5da7c064476db27 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Wed, 21 Oct 2020 08:19:19 +0000 Subject: [PATCH 1274/2114] [maven-release-plugin] prepare release v5.10.0.RC2 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 5bf24198ed..b3a844fc8f 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.10.0-SNAPSHOT + 5.10.0.RC2 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v5.10.0.RC2 From 37db0e876989afc607fbd9504bdb203c668ac2d0 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Wed, 21 Oct 2020 08:19:26 +0000 Subject: [PATCH 1275/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index b3a844fc8f..5bf24198ed 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.10.0.RC2 + 5.10.0-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v5.10.0.RC2 + HEAD From 42aaeda49d38f318ca4c492a88e6aa1f03b928b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 21 Oct 2020 10:23:55 +0200 Subject: [PATCH 1276/2114] Set release version to 5.10.0.RC3 --- release-versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-versions.txt b/release-versions.txt index f87d576a21..f39fade999 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,3 +1,3 @@ -RELEASE_VERSION="5.10.0.RC2" +RELEASE_VERSION="5.10.0.RC3" DEVELOPMENT_VERSION="5.10.0-SNAPSHOT" RELEASE_BRANCH="5.x.x-stable" From 82e9db804fdc691e273b105b3f53200009cc2664 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 23 Oct 2020 13:57:30 +0200 Subject: [PATCH 1277/2114] Set release version to 5.10.0 --- release-versions.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release-versions.txt b/release-versions.txt index f39fade999..382b6cd0ef 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,3 +1,3 @@ -RELEASE_VERSION="5.10.0.RC3" -DEVELOPMENT_VERSION="5.10.0-SNAPSHOT" +RELEASE_VERSION="5.10.0" +DEVELOPMENT_VERSION="5.11.0-SNAPSHOT" RELEASE_BRANCH="5.x.x-stable" From 0d95b0e4bbf740f959f6387ee7398fcc144924a6 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Fri, 23 Oct 2020 12:01:00 +0000 Subject: [PATCH 1278/2114] [maven-release-plugin] prepare release v5.10.0 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 5bf24198ed..11e7900be5 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.10.0-SNAPSHOT + 5.10.0 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v5.10.0 From f9fb1f2a8e65834dd6238bbc84eaaf788ba909f2 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Fri, 23 Oct 2020 12:01:06 +0000 Subject: [PATCH 1279/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 11e7900be5..a36f78c52d 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.10.0 + 5.11.0-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v5.10.0 + HEAD From 48a61952aabf59df50a9fe29587c9a0b8ee0a403 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 23 Oct 2020 14:04:05 +0200 Subject: [PATCH 1280/2114] Set release version to 5.11.0.RC1 --- release-versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-versions.txt b/release-versions.txt index 382b6cd0ef..0a6a0327d6 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,3 +1,3 @@ -RELEASE_VERSION="5.10.0" +RELEASE_VERSION="5.11.0.RC1" DEVELOPMENT_VERSION="5.11.0-SNAPSHOT" RELEASE_BRANCH="5.x.x-stable" From 34573a10ee30528e6ccac72148d48ff50459572c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 23 Oct 2020 14:32:17 +0200 Subject: [PATCH 1281/2114] Use 5.10.0 in readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 826f1837af..40d4e01790 100644 --- a/README.md +++ b/README.md @@ -23,14 +23,14 @@ They require Java 8 or higher. com.rabbitmq amqp-client - 5.9.0 + 5.10.0 ``` ### Gradle ``` groovy -compile 'com.rabbitmq:amqp-client:5.9.0' +compile 'com.rabbitmq:amqp-client:5.10.0' ``` #### 4.x Series From 661d6a1da71523dec3bf091075e8c192370e4d30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 23 Oct 2020 14:39:22 +0200 Subject: [PATCH 1282/2114] Bump metrics dependency References #662 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7fbbd89726..9ae3d02d11 100644 --- a/pom.xml +++ b/pom.xml @@ -55,7 +55,7 @@ UTF-8 1.7.30 - 4.1.13 + 4.1.14 1.5.5 2.11.3 1.2.3 From 0a82f8ec78c849ac5f2b758d003f8e2a88dd7c16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 23 Oct 2020 14:40:00 +0200 Subject: [PATCH 1283/2114] Bump test dependencies --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 9ae3d02d11..7c3c0f29fd 100644 --- a/pom.xml +++ b/pom.xml @@ -60,9 +60,9 @@ 2.11.3 1.2.3 4.13.1 - 3.5.13 + 3.5.15 3.17.2 - 9.4.32.v20200930 + 9.4.33.v20201020 1.66 3.2.0 From 7f81af288876d1a0a635701f8729ad1d11d0fda2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 23 Oct 2020 14:39:22 +0200 Subject: [PATCH 1284/2114] Bump metrics dependency References #662 (cherry picked from commit 661d6a1da71523dec3bf091075e8c192370e4d30) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a36f78c52d..bc4d5fc2fa 100644 --- a/pom.xml +++ b/pom.xml @@ -55,7 +55,7 @@ UTF-8 1.7.30 - 4.1.13 + 4.1.14 1.5.5 2.11.3 1.2.3 From 8153a007b8b0975ec44a876b96e916ff2eea072c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 23 Oct 2020 14:40:00 +0200 Subject: [PATCH 1285/2114] Bump test dependencies (cherry picked from commit 0a82f8ec78c849ac5f2b758d003f8e2a88dd7c16) --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index bc4d5fc2fa..0b51d5f5ea 100644 --- a/pom.xml +++ b/pom.xml @@ -60,9 +60,9 @@ 2.11.3 1.2.3 4.13.1 - 3.5.13 + 3.5.15 3.17.2 - 9.4.32.v20200930 + 9.4.33.v20201020 1.66 3.2.0 From 8777491622cdad8fd1edd92cc1e3b00e64f4fb69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 2 Nov 2020 15:40:38 +0100 Subject: [PATCH 1286/2114] Don't create server-named quorum queues in tests This is no longer allowed in 3.9. --- .../com/rabbitmq/client/test/TestUtils.java | 8 +++++ .../rabbitmq/client/test/functional/Nack.java | 33 +++++++++++++++---- .../client/test/functional/Reject.java | 30 +++++++++++++++-- 3 files changed, 62 insertions(+), 9 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/TestUtils.java b/src/test/java/com/rabbitmq/client/test/TestUtils.java index 19d63d8d86..5ead24e06e 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtils.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtils.java @@ -311,4 +311,12 @@ public void evaluate() throws Throwable { }; } } + + @FunctionalInterface + public interface CallableFunction { + + R apply(T t) throws Exception; + + } + } diff --git a/src/test/java/com/rabbitmq/client/test/functional/Nack.java b/src/test/java/com/rabbitmq/client/test/functional/Nack.java index 409a8fe0cd..ea0d6d9124 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Nack.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Nack.java @@ -19,20 +19,43 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.test.TestUtils; +import com.rabbitmq.client.test.TestUtils.CallableFunction; import java.util.Collections; import java.util.HashSet; import java.util.Set; +import java.util.UUID; import org.junit.Test; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.QueueingConsumer; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +@RunWith(Parameterized.class) public class Nack extends AbstractRejectTest { + @Parameterized.Parameters + public static Object[] queueCreators() { + return new Object[] { + (CallableFunction) channel -> { + String q = UUID.randomUUID().toString(); + channel.queueDeclare(q, true, false, false, Collections.singletonMap("x-queue-type", "quorum")); + return q; + }, + (CallableFunction) channel -> { + String q = UUID.randomUUID().toString(); + channel.queueDeclare(q, true, false, false, Collections.singletonMap("x-queue-type", "classic")); + return q; + }}; + } + + @Parameterized.Parameter public TestUtils.CallableFunction queueCreator; + @Test public void singleNack() throws Exception { - String q = - channel.queueDeclare("", true, false, false, Collections.singletonMap("x-queue-type", "quorum")).getQueue(); + String q = queueCreator.apply(channel); byte[] m1 = "1".getBytes(); byte[] m2 = "2".getBytes(); @@ -63,8 +86,7 @@ public class Nack extends AbstractRejectTest { } @Test public void multiNack() throws Exception { - String q = - channel.queueDeclare("", true, false, false, Collections.singletonMap("x-queue-type", "quorum")).getQueue(); + String q = queueCreator.apply(channel); byte[] m1 = "1".getBytes(); byte[] m2 = "2".getBytes(); @@ -105,8 +127,7 @@ public class Nack extends AbstractRejectTest { } @Test public void nackAll() throws Exception { - String q = - channel.queueDeclare("", true, false, false, Collections.singletonMap("x-queue-type", "quorum")).getQueue(); + String q = queueCreator.apply(channel); byte[] m1 = "1".getBytes(); byte[] m2 = "2".getBytes(); diff --git a/src/test/java/com/rabbitmq/client/test/functional/Reject.java b/src/test/java/com/rabbitmq/client/test/functional/Reject.java index 8a3852551f..aa3952b036 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Reject.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Reject.java @@ -18,20 +18,44 @@ import static org.junit.Assert.assertNull; -import java.io.IOException; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.test.TestUtils; +import com.rabbitmq.client.test.TestUtils.CallableFunction; import java.util.Collections; +import java.util.UUID; import org.junit.Test; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.QueueingConsumer; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +@RunWith(Parameterized.class) public class Reject extends AbstractRejectTest { + + @Parameterized.Parameters + public static Object[] queueCreators() { + return new Object[] { + (CallableFunction) channel -> { + String q = UUID.randomUUID().toString(); + channel.queueDeclare(q, true, false, false, Collections.singletonMap("x-queue-type", "quorum")); + return q; + }, + (CallableFunction) channel -> { + String q = UUID.randomUUID().toString(); + channel.queueDeclare(q, true, false, false, Collections.singletonMap("x-queue-type", "classic")); + return q; + }}; + } + + @Parameterized.Parameter public TestUtils.CallableFunction queueCreator; + @Test public void reject() - throws IOException, InterruptedException + throws Exception { - String q = channel.queueDeclare("", true, false, false, Collections.singletonMap("x-queue-type", "quorum")).getQueue(); + String q = queueCreator.apply(channel); byte[] m1 = "1".getBytes(); byte[] m2 = "2".getBytes(); From ebf83091291086a9949b2f1304917a0c0f43dbcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 2 Nov 2020 15:40:38 +0100 Subject: [PATCH 1287/2114] Don't create server-named quorum queues in tests This is no longer allowed in 3.9. (cherry picked from commit 8777491622cdad8fd1edd92cc1e3b00e64f4fb69) Conflicts: src/test/java/com/rabbitmq/client/test/functional/Nack.java src/test/java/com/rabbitmq/client/test/functional/Reject.java --- .../com/rabbitmq/client/test/TestUtils.java | 8 +++++ .../rabbitmq/client/test/functional/Nack.java | 34 +++++++++++++++---- .../client/test/functional/Reject.java | 31 +++++++++++++++-- 3 files changed, 64 insertions(+), 9 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/TestUtils.java b/src/test/java/com/rabbitmq/client/test/TestUtils.java index 19d63d8d86..5ead24e06e 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtils.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtils.java @@ -311,4 +311,12 @@ public void evaluate() throws Throwable { }; } } + + @FunctionalInterface + public interface CallableFunction { + + R apply(T t) throws Exception; + + } + } diff --git a/src/test/java/com/rabbitmq/client/test/functional/Nack.java b/src/test/java/com/rabbitmq/client/test/functional/Nack.java index 61c10e589a..ea0d6d9124 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Nack.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Nack.java @@ -19,19 +19,43 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.test.TestUtils; +import com.rabbitmq.client.test.TestUtils.CallableFunction; +import java.util.Collections; import java.util.HashSet; import java.util.Set; +import java.util.UUID; import org.junit.Test; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.QueueingConsumer; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +@RunWith(Parameterized.class) public class Nack extends AbstractRejectTest { + @Parameterized.Parameters + public static Object[] queueCreators() { + return new Object[] { + (CallableFunction) channel -> { + String q = UUID.randomUUID().toString(); + channel.queueDeclare(q, true, false, false, Collections.singletonMap("x-queue-type", "quorum")); + return q; + }, + (CallableFunction) channel -> { + String q = UUID.randomUUID().toString(); + channel.queueDeclare(q, true, false, false, Collections.singletonMap("x-queue-type", "classic")); + return q; + }}; + } + + @Parameterized.Parameter public TestUtils.CallableFunction queueCreator; + @Test public void singleNack() throws Exception { - String q = - channel.queueDeclare("", false, true, false, null).getQueue(); + String q = queueCreator.apply(channel); byte[] m1 = "1".getBytes(); byte[] m2 = "2".getBytes(); @@ -62,8 +86,7 @@ public class Nack extends AbstractRejectTest { } @Test public void multiNack() throws Exception { - String q = - channel.queueDeclare("", false, true, false, null).getQueue(); + String q = queueCreator.apply(channel); byte[] m1 = "1".getBytes(); byte[] m2 = "2".getBytes(); @@ -104,8 +127,7 @@ public class Nack extends AbstractRejectTest { } @Test public void nackAll() throws Exception { - String q = - channel.queueDeclare("", false, true, false, null).getQueue(); + String q = queueCreator.apply(channel); byte[] m1 = "1".getBytes(); byte[] m2 = "2".getBytes(); diff --git a/src/test/java/com/rabbitmq/client/test/functional/Reject.java b/src/test/java/com/rabbitmq/client/test/functional/Reject.java index 2d296a13ea..aa3952b036 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Reject.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Reject.java @@ -18,19 +18,44 @@ import static org.junit.Assert.assertNull; -import java.io.IOException; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.test.TestUtils; +import com.rabbitmq.client.test.TestUtils.CallableFunction; +import java.util.Collections; +import java.util.UUID; import org.junit.Test; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.QueueingConsumer; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +@RunWith(Parameterized.class) public class Reject extends AbstractRejectTest { + + @Parameterized.Parameters + public static Object[] queueCreators() { + return new Object[] { + (CallableFunction) channel -> { + String q = UUID.randomUUID().toString(); + channel.queueDeclare(q, true, false, false, Collections.singletonMap("x-queue-type", "quorum")); + return q; + }, + (CallableFunction) channel -> { + String q = UUID.randomUUID().toString(); + channel.queueDeclare(q, true, false, false, Collections.singletonMap("x-queue-type", "classic")); + return q; + }}; + } + + @Parameterized.Parameter public TestUtils.CallableFunction queueCreator; + @Test public void reject() - throws IOException, InterruptedException + throws Exception { - String q = channel.queueDeclare("", false, true, false, null).getQueue(); + String q = queueCreator.apply(channel); byte[] m1 = "1".getBytes(); byte[] m2 = "2".getBytes(); From 7a64d6d68dc6c8f592161863b1730ac60bc5b15f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 5 Nov 2020 11:38:53 +0100 Subject: [PATCH 1288/2114] Sync on publish confirm in reject/nack tests To avoid race conditions and test failures. --- .../com/rabbitmq/client/test/functional/Nack.java | 12 ++++++++++++ .../com/rabbitmq/client/test/functional/Reject.java | 4 ++++ 2 files changed, 16 insertions(+) diff --git a/src/test/java/com/rabbitmq/client/test/functional/Nack.java b/src/test/java/com/rabbitmq/client/test/functional/Nack.java index ea0d6d9124..ce9b70ddd0 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Nack.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Nack.java @@ -60,9 +60,13 @@ public static Object[] queueCreators() { byte[] m1 = "1".getBytes(); byte[] m2 = "2".getBytes(); + channel.confirmSelect(); + basicPublishVolatile(m1, q); basicPublishVolatile(m2, q); + channel.waitForConfirmsOrDie(1000); + long tag1 = checkDelivery(channel.basicGet(q, false), m1, false); long tag2 = checkDelivery(channel.basicGet(q, false), m2, false); @@ -93,11 +97,15 @@ public static Object[] queueCreators() { byte[] m3 = "3".getBytes(); byte[] m4 = "4".getBytes(); + channel.confirmSelect(); + basicPublishVolatile(m1, q); basicPublishVolatile(m2, q); basicPublishVolatile(m3, q); basicPublishVolatile(m4, q); + channel.waitForConfirmsOrDie(1000); + checkDelivery(channel.basicGet(q, false), m1, false); long tag1 = checkDelivery(channel.basicGet(q, false), m2, false); checkDelivery(channel.basicGet(q, false), m3, false); @@ -132,9 +140,13 @@ public static Object[] queueCreators() { byte[] m1 = "1".getBytes(); byte[] m2 = "2".getBytes(); + channel.confirmSelect(); + basicPublishVolatile(m1, q); basicPublishVolatile(m2, q); + channel.waitForConfirmsOrDie(1000); + checkDelivery(channel.basicGet(q, false), m1, false); checkDelivery(channel.basicGet(q, false), m2, false); diff --git a/src/test/java/com/rabbitmq/client/test/functional/Reject.java b/src/test/java/com/rabbitmq/client/test/functional/Reject.java index aa3952b036..c2c5dd76bd 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Reject.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Reject.java @@ -57,12 +57,16 @@ public static Object[] queueCreators() { { String q = queueCreator.apply(channel); + channel.confirmSelect(); + byte[] m1 = "1".getBytes(); byte[] m2 = "2".getBytes(); basicPublishVolatile(m1, q); basicPublishVolatile(m2, q); + channel.waitForConfirmsOrDie(1000); + long tag1 = checkDelivery(channel.basicGet(q, false), m1, false); long tag2 = checkDelivery(channel.basicGet(q, false), m2, false); QueueingConsumer c = new QueueingConsumer(secondaryChannel); From ce1eaaf89227d3bd8658d69ca8f1be389b964eec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 5 Nov 2020 11:38:53 +0100 Subject: [PATCH 1289/2114] Sync on publish confirm in reject/nack tests To avoid race conditions and test failures. (cherry picked from commit 7a64d6d68dc6c8f592161863b1730ac60bc5b15f) --- .../com/rabbitmq/client/test/functional/Nack.java | 12 ++++++++++++ .../com/rabbitmq/client/test/functional/Reject.java | 4 ++++ 2 files changed, 16 insertions(+) diff --git a/src/test/java/com/rabbitmq/client/test/functional/Nack.java b/src/test/java/com/rabbitmq/client/test/functional/Nack.java index ea0d6d9124..ce9b70ddd0 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Nack.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Nack.java @@ -60,9 +60,13 @@ public static Object[] queueCreators() { byte[] m1 = "1".getBytes(); byte[] m2 = "2".getBytes(); + channel.confirmSelect(); + basicPublishVolatile(m1, q); basicPublishVolatile(m2, q); + channel.waitForConfirmsOrDie(1000); + long tag1 = checkDelivery(channel.basicGet(q, false), m1, false); long tag2 = checkDelivery(channel.basicGet(q, false), m2, false); @@ -93,11 +97,15 @@ public static Object[] queueCreators() { byte[] m3 = "3".getBytes(); byte[] m4 = "4".getBytes(); + channel.confirmSelect(); + basicPublishVolatile(m1, q); basicPublishVolatile(m2, q); basicPublishVolatile(m3, q); basicPublishVolatile(m4, q); + channel.waitForConfirmsOrDie(1000); + checkDelivery(channel.basicGet(q, false), m1, false); long tag1 = checkDelivery(channel.basicGet(q, false), m2, false); checkDelivery(channel.basicGet(q, false), m3, false); @@ -132,9 +140,13 @@ public static Object[] queueCreators() { byte[] m1 = "1".getBytes(); byte[] m2 = "2".getBytes(); + channel.confirmSelect(); + basicPublishVolatile(m1, q); basicPublishVolatile(m2, q); + channel.waitForConfirmsOrDie(1000); + checkDelivery(channel.basicGet(q, false), m1, false); checkDelivery(channel.basicGet(q, false), m2, false); diff --git a/src/test/java/com/rabbitmq/client/test/functional/Reject.java b/src/test/java/com/rabbitmq/client/test/functional/Reject.java index aa3952b036..c2c5dd76bd 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Reject.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Reject.java @@ -57,12 +57,16 @@ public static Object[] queueCreators() { { String q = queueCreator.apply(channel); + channel.confirmSelect(); + byte[] m1 = "1".getBytes(); byte[] m2 = "2".getBytes(); basicPublishVolatile(m1, q); basicPublishVolatile(m2, q); + channel.waitForConfirmsOrDie(1000); + long tag1 = checkDelivery(channel.basicGet(q, false), m1, false); long tag2 = checkDelivery(channel.basicGet(q, false), m2, false); QueueingConsumer c = new QueueingConsumer(secondaryChannel); From 2854ee1685dc9b1a58f2ec890e5baaf628060654 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 5 Nov 2020 16:24:29 +0100 Subject: [PATCH 1290/2114] Bump Micrometer to 1.6.0 References #662 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7c3c0f29fd..4ad6e5a699 100644 --- a/pom.xml +++ b/pom.xml @@ -56,7 +56,7 @@ 1.7.30 4.1.14 - 1.5.5 + 1.6.0 2.11.3 1.2.3 4.13.1 From ff5a104b8b5e8621821d3b9c7bf0a28584d39159 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 5 Nov 2020 16:29:39 +0100 Subject: [PATCH 1291/2114] Bump test dependencies --- pom.xml | 8 ++++---- .../com/rabbitmq/client/test/ConnectionTest.java | 12 ++++++++++-- .../client/test/DefaultRetryHandlerTest.java | 12 ++++++++++-- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/pom.xml b/pom.xml index 4ad6e5a699..0c6042b77f 100644 --- a/pom.xml +++ b/pom.xml @@ -60,10 +60,10 @@ 2.11.3 1.2.3 4.13.1 - 3.5.15 - 3.17.2 - 9.4.33.v20201020 - 1.66 + 3.6.0 + 3.18.0 + 9.4.34.v20201102 + 1.67 3.2.0 2.5.3 diff --git a/src/test/java/com/rabbitmq/client/test/ConnectionTest.java b/src/test/java/com/rabbitmq/client/test/ConnectionTest.java index c7da088e79..8fb1c82059 100644 --- a/src/test/java/com/rabbitmq/client/test/ConnectionTest.java +++ b/src/test/java/com/rabbitmq/client/test/ConnectionTest.java @@ -17,6 +17,7 @@ import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -31,7 +32,7 @@ import static org.junit.Assert.*; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; +import static org.mockito.MockitoAnnotations.openMocks; @RunWith(Parameterized.class) public class ConnectionTest { @@ -43,6 +44,8 @@ public class ConnectionTest { @Mock Channel ch = mock(Channel.class); + AutoCloseable mocks; + @Parameterized.Parameters public static Object[] configurators() { return new Object[]{new NotNumberedChannelCreationCallback(), new NumberedChannelCreationCallback()}; @@ -50,7 +53,12 @@ public static Object[] configurators() { @Before public void init() { - initMocks(this); + mocks = openMocks(this); + } + + @After + public void tearDown() throws Exception { + mocks.close(); } @Test diff --git a/src/test/java/com/rabbitmq/client/test/DefaultRetryHandlerTest.java b/src/test/java/com/rabbitmq/client/test/DefaultRetryHandlerTest.java index 3aa28efdb9..ae841b430b 100644 --- a/src/test/java/com/rabbitmq/client/test/DefaultRetryHandlerTest.java +++ b/src/test/java/com/rabbitmq/client/test/DefaultRetryHandlerTest.java @@ -23,6 +23,7 @@ import com.rabbitmq.client.impl.recovery.RecordedQueue; import com.rabbitmq.client.impl.recovery.RetryContext; import com.rabbitmq.client.impl.recovery.RetryHandler; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; @@ -42,7 +43,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; +import static org.mockito.MockitoAnnotations.openMocks; /** * @@ -72,9 +73,16 @@ public class DefaultRetryHandlerTest { @Mock BackoffPolicy backoffPolicy; + AutoCloseable mocks; + @Before public void init() { - initMocks(this); + mocks = openMocks(this); + } + + @After + public void tearDown() throws Exception { + mocks.close(); } @Test From 1ac4011dd9e5e31088641738fa83eabecbc00872 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 5 Nov 2020 16:24:29 +0100 Subject: [PATCH 1292/2114] Bump Micrometer to 1.6.0 References #662 (cherry picked from commit 2854ee1685dc9b1a58f2ec890e5baaf628060654) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0b51d5f5ea..575a0c2690 100644 --- a/pom.xml +++ b/pom.xml @@ -56,7 +56,7 @@ 1.7.30 4.1.14 - 1.5.5 + 1.6.0 2.11.3 1.2.3 4.13.1 From eebf6d47d9490a98a299845d2862b6ab0c7cd50d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 5 Nov 2020 16:29:39 +0100 Subject: [PATCH 1293/2114] Bump test dependencies (cherry picked from commit ff5a104b8b5e8621821d3b9c7bf0a28584d39159) --- pom.xml | 8 ++++---- .../com/rabbitmq/client/test/ConnectionTest.java | 12 ++++++++++-- .../client/test/DefaultRetryHandlerTest.java | 12 ++++++++++-- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/pom.xml b/pom.xml index 575a0c2690..5e1a904adf 100644 --- a/pom.xml +++ b/pom.xml @@ -60,10 +60,10 @@ 2.11.3 1.2.3 4.13.1 - 3.5.15 - 3.17.2 - 9.4.33.v20201020 - 1.66 + 3.6.0 + 3.18.0 + 9.4.34.v20201102 + 1.67 3.2.0 2.5.3 diff --git a/src/test/java/com/rabbitmq/client/test/ConnectionTest.java b/src/test/java/com/rabbitmq/client/test/ConnectionTest.java index c7da088e79..8fb1c82059 100644 --- a/src/test/java/com/rabbitmq/client/test/ConnectionTest.java +++ b/src/test/java/com/rabbitmq/client/test/ConnectionTest.java @@ -17,6 +17,7 @@ import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -31,7 +32,7 @@ import static org.junit.Assert.*; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; +import static org.mockito.MockitoAnnotations.openMocks; @RunWith(Parameterized.class) public class ConnectionTest { @@ -43,6 +44,8 @@ public class ConnectionTest { @Mock Channel ch = mock(Channel.class); + AutoCloseable mocks; + @Parameterized.Parameters public static Object[] configurators() { return new Object[]{new NotNumberedChannelCreationCallback(), new NumberedChannelCreationCallback()}; @@ -50,7 +53,12 @@ public static Object[] configurators() { @Before public void init() { - initMocks(this); + mocks = openMocks(this); + } + + @After + public void tearDown() throws Exception { + mocks.close(); } @Test diff --git a/src/test/java/com/rabbitmq/client/test/DefaultRetryHandlerTest.java b/src/test/java/com/rabbitmq/client/test/DefaultRetryHandlerTest.java index 3aa28efdb9..ae841b430b 100644 --- a/src/test/java/com/rabbitmq/client/test/DefaultRetryHandlerTest.java +++ b/src/test/java/com/rabbitmq/client/test/DefaultRetryHandlerTest.java @@ -23,6 +23,7 @@ import com.rabbitmq.client.impl.recovery.RecordedQueue; import com.rabbitmq.client.impl.recovery.RetryContext; import com.rabbitmq.client.impl.recovery.RetryHandler; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; @@ -42,7 +43,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; +import static org.mockito.MockitoAnnotations.openMocks; /** * @@ -72,9 +73,16 @@ public class DefaultRetryHandlerTest { @Mock BackoffPolicy backoffPolicy; + AutoCloseable mocks; + @Before public void init() { - initMocks(this); + mocks = openMocks(this); + } + + @After + public void tearDown() throws Exception { + mocks.close(); } @Test From a9b186db22c98d23544fc302bee45ce7f8bddcab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 16 Nov 2020 11:04:24 +0100 Subject: [PATCH 1294/2114] Add JShell plugin for easy REPL usage --- README.md | 16 ++++++++++++++++ pom.xml | 10 ++++++++++ 2 files changed, 26 insertions(+) diff --git a/README.md b/README.md index 40d4e01790..df2ae533a2 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,22 @@ They require Java 6 or higher. compile 'com.rabbitmq:amqp-client:4.12.0' ``` +## Experimenting with JShell + +You can experiment with the client from JShell. This requires Java 9 or more. + +``` +git clone https://github.com/rabbitmq/rabbitmq-java-client.git +cd rabbitmq-java-client +./mvnw test-compile jshell:run +... +import com.rabbitmq.client.* +ConnectionFactory cf = new ConnectionFactory() +Connection c = cf.newConnection() +... +c.close() +/exit +``` ## Contributing diff --git a/pom.xml b/pom.xml index 0c6042b77f..d5a02302c5 100644 --- a/pom.xml +++ b/pom.xml @@ -82,6 +82,7 @@ 3.2.0 0.0.6 1.8 + 1.3 - ossrh-release + snapshots @@ -546,13 +547,25 @@ - bintray-release + release + + + org.sonatype.plugins + nexus-staging-maven-plugin + ${nexus-staging-maven-plugin.version} + true + + ossrh + https://oss.sonatype.org/ + false + + + org.apache.maven.plugins maven-javadoc-plugin @@ -593,9 +606,8 @@ - bintray-rabbitmq-maven - rabbitmq-maven - https://api.bintray.com/maven/rabbitmq/maven/com.rabbitmq:amqp-client/;publish=1 + ossrh + https://oss.sonatype.org/service/local/staging/deploy/maven2/ From 384c9eea8bb850fb9d4cfaa4d2eb415687768f0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 17 Feb 2021 13:50:21 +0100 Subject: [PATCH 1353/2114] Use OSSRH for release (cherry picked from commit 996a16148bdeb3bfa773faa334777dace5e2dd93) --- pom.xml | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/pom.xml b/pom.xml index ff4116c863..bed04347b4 100644 --- a/pom.xml +++ b/pom.xml @@ -81,6 +81,7 @@ 3.0.2 3.2.0 0.0.6 + 1.6.8 1.8 1.3 @@ -494,9 +495,9 @@ - ossrh-release + snapshots @@ -546,13 +547,25 @@ - bintray-release + release + + + org.sonatype.plugins + nexus-staging-maven-plugin + ${nexus-staging-maven-plugin.version} + true + + ossrh + https://oss.sonatype.org/ + false + + + org.apache.maven.plugins maven-javadoc-plugin @@ -593,9 +606,8 @@ - bintray-rabbitmq-maven - rabbitmq-maven - https://api.bintray.com/maven/rabbitmq/maven/com.rabbitmq:amqp-client/;publish=1 + ossrh + https://oss.sonatype.org/service/local/staging/deploy/maven2/ From 57e7beb469360145f258d2c58c1bf04ab93a1272 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 17 Feb 2021 13:55:18 +0100 Subject: [PATCH 1354/2114] Increase Nexus staging timeout --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index 8b1fed052d..db8771c4e9 100644 --- a/pom.xml +++ b/pom.xml @@ -563,6 +563,7 @@ ossrh https://oss.sonatype.org/ false + 10 From b353e320203dd5b1da2aee0df74ec0983fbeec64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 17 Feb 2021 13:55:18 +0100 Subject: [PATCH 1355/2114] Increase Nexus staging timeout (cherry picked from commit 57e7beb469360145f258d2c58c1bf04ab93a1272) --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index bed04347b4..9bd5129873 100644 --- a/pom.xml +++ b/pom.xml @@ -563,6 +563,7 @@ ossrh https://oss.sonatype.org/ false + 10 From b5fa7e9a289569ac0c91e4400ee8da941ca8e2f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 17 Feb 2021 14:59:33 +0100 Subject: [PATCH 1356/2114] Configure sanity check to use OSSRH staging repo --- src/main/scripts/sanity-check.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scripts/sanity-check.groovy b/src/main/scripts/sanity-check.groovy index 073650a360..11ef2ccb47 100644 --- a/src/main/scripts/sanity-check.groovy +++ b/src/main/scripts/sanity-check.groovy @@ -1,4 +1,4 @@ -@GrabResolver(name = 'rabbitmq-bintray', root = 'https://dl.bintray.com/rabbitmq/maven') +@GrabResolver(name = 'ossrh-staging', root = 'https://oss.sonatype.org/content/groups/staging/') @GrabResolver(name = 'rabbitmq-packagecloud-milestones', root = 'https://packagecloud.io/rabbitmq/maven-milestones/maven2') @Grab(group = 'com.rabbitmq', module = 'amqp-client', version = '${version}') @Grab(group = 'org.slf4j', module = 'slf4j-simple', version = '1.7.25') From 082b4cdd91ed2fa82dd4b1a2c14594a1819f5ee9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 19 Feb 2021 15:06:30 +0100 Subject: [PATCH 1357/2114] Fix profile name in comment --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index db8771c4e9..624653bb3f 100644 --- a/pom.xml +++ b/pom.xml @@ -494,7 +494,7 @@ snapshots From e2afbe33ca9dddcc3166f1359fb9e75397ee21e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 19 Feb 2021 15:06:30 +0100 Subject: [PATCH 1358/2114] Fix profile name in comment (cherry picked from commit 082b4cdd91ed2fa82dd4b1a2c14594a1819f5ee9) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9bd5129873..f1e37d58bf 100644 --- a/pom.xml +++ b/pom.xml @@ -494,7 +494,7 @@ snapshots From b970e5a74853228ac0becfd60ebc25d9accddcbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 19 Feb 2021 15:07:31 +0100 Subject: [PATCH 1359/2114] Set release version to 5.11.0 --- release-versions.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release-versions.txt b/release-versions.txt index 0399f4de78..847472b0cf 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,3 +1,3 @@ -RELEASE_VERSION="5.11.0.RC2" -DEVELOPMENT_VERSION="5.11.0-SNAPSHOT" +RELEASE_VERSION="5.11.0" +DEVELOPMENT_VERSION="5.12.0-SNAPSHOT" RELEASE_BRANCH="5.x.x-stable" From f95857097057aa5e614300246d3635643d8e8af4 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Fri, 19 Feb 2021 14:31:38 +0000 Subject: [PATCH 1360/2114] [maven-release-plugin] prepare release v5.11.0 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index f1e37d58bf..ca472d199c 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.11.0-SNAPSHOT + 5.11.0 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v5.11.0 From b96287257ace58c642167bb5cb6ba0b5ea914b45 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Fri, 19 Feb 2021 14:31:43 +0000 Subject: [PATCH 1361/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index ca472d199c..501162ec65 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.11.0 + 5.12.0-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v5.11.0 + HEAD From 44537c668c83a30880799cdfe30e235ddefc92b3 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Fri, 19 Feb 2021 14:37:06 +0000 Subject: [PATCH 1362/2114] [maven-release-plugin] prepare release v5.11.0 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 501162ec65..ca472d199c 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.12.0-SNAPSHOT + 5.11.0 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v5.11.0 From ce51568e7ca3a5e6bf9119df656f3c237b5cf3c5 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Fri, 19 Feb 2021 14:37:11 +0000 Subject: [PATCH 1363/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index ca472d199c..501162ec65 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.11.0 + 5.12.0-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v5.11.0 + HEAD From f0ce5f68456f33206671e8bbd886923848fe8608 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 19 Feb 2021 15:53:28 +0100 Subject: [PATCH 1364/2114] Increase deployment timeout --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 624653bb3f..75ec41d552 100644 --- a/pom.xml +++ b/pom.xml @@ -563,7 +563,7 @@ ossrh https://oss.sonatype.org/ false - 10 + 20 From 1f67e389b085a951b6364b010240b69c92b29dd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 19 Feb 2021 15:53:28 +0100 Subject: [PATCH 1365/2114] Increase deployment timeout (cherry picked from commit f0ce5f68456f33206671e8bbd886923848fe8608) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 501162ec65..9e8c3dcb1d 100644 --- a/pom.xml +++ b/pom.xml @@ -563,7 +563,7 @@ ossrh https://oss.sonatype.org/ false - 10 + 20 From e89f37e8b077bc6a9cc0bba58b8ebe2b1a899253 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Fri, 19 Feb 2021 14:55:39 +0000 Subject: [PATCH 1366/2114] [maven-release-plugin] prepare release v5.11.0 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 9e8c3dcb1d..8dfa4bbae5 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.12.0-SNAPSHOT + 5.11.0 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v5.11.0 From 4eefa9c3400f6de180411231c63d271367b3222a Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Fri, 19 Feb 2021 14:55:44 +0000 Subject: [PATCH 1367/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 8dfa4bbae5..9e8c3dcb1d 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.11.0 + 5.12.0-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v5.11.0 + HEAD From d90265ee3f8b8b4014254fb217cb785db7c5087d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 19 Feb 2021 16:15:34 +0100 Subject: [PATCH 1368/2114] Use 5.11.0 in readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a96f32c6c0..16cf3e80f5 100644 --- a/README.md +++ b/README.md @@ -25,14 +25,14 @@ They require Java 8 or higher. com.rabbitmq amqp-client - 5.10.0 + 5.11.0 ``` ### Gradle ``` groovy -compile 'com.rabbitmq:amqp-client:5.10.0' +compile 'com.rabbitmq:amqp-client:5.11.0' ``` #### 4.x Series From 7c6e0e256c7470b578f5aeaa7c0ccebc12a7ea05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 19 Feb 2021 16:16:05 +0100 Subject: [PATCH 1369/2114] Set release version to 5.12.0.RC1 --- release-versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-versions.txt b/release-versions.txt index 847472b0cf..7c74c0e65d 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,3 +1,3 @@ -RELEASE_VERSION="5.11.0" +RELEASE_VERSION="5.12.0.RC1" DEVELOPMENT_VERSION="5.12.0-SNAPSHOT" RELEASE_BRANCH="5.x.x-stable" From bf9220c0cf2221d96e154f98083c31f633d37522 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 19 Feb 2021 17:00:15 +0100 Subject: [PATCH 1370/2114] Deps are only codegen --- Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 13f9fa779c..2dc08da902 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ MVN_FLAGS += -Ddeps.dir="$(abspath $(DEPS_DIR))" all: deps $(MVN) $(MVN_FLAGS) compile -deps: $(DEPS_DIR)/rabbit $(DEPS_DIR)/rabbitmq_ct_helpers +deps: $(DEPS_DIR)/rabbitmq_codegen @: dist: clean @@ -29,6 +29,9 @@ $(DEPS_DIR)/rabbit: $(DEPS_DIR)/rabbitmq_ct_helpers: git clone https://github.com/rabbitmq/rabbitmq-ct-helpers.git "$@" +$(DEPS_DIR)/rabbitmq_codegen: + git clone https://github.com/rabbitmq/rabbitmq-codegen.git "$@" + tests: deps $(MVN) $(MVN_FLAGS) verify From 8252793927912c935c6605aa6d4ad5f2b497f74b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 19 Feb 2021 17:01:55 +0100 Subject: [PATCH 1371/2114] Retrieve deps before generating Javadoc --- deploy-javadoc.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/deploy-javadoc.sh b/deploy-javadoc.sh index af38def8ef..74878215e9 100755 --- a/deploy-javadoc.sh +++ b/deploy-javadoc.sh @@ -3,6 +3,7 @@ DEPLOY_DIRECTORY=api/current TAG=$(git describe --exact-match --tags $(git log -n1 --pretty='%h')) +make deps ./mvnw -q clean javadoc:javadoc -Dmaven.javadoc.failOnError=false git co gh-pages rm -rf $DEPLOY_DIRECTORY/* From 33c10920895bbe7c71e6535a214e829a8b0b2f30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 19 Feb 2021 17:01:55 +0100 Subject: [PATCH 1372/2114] Retrieve deps before generating Javadoc (cherry picked from commit 8252793927912c935c6605aa6d4ad5f2b497f74b) --- deploy-javadoc.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/deploy-javadoc.sh b/deploy-javadoc.sh index af38def8ef..74878215e9 100755 --- a/deploy-javadoc.sh +++ b/deploy-javadoc.sh @@ -3,6 +3,7 @@ DEPLOY_DIRECTORY=api/current TAG=$(git describe --exact-match --tags $(git log -n1 --pretty='%h')) +make deps ./mvnw -q clean javadoc:javadoc -Dmaven.javadoc.failOnError=false git co gh-pages rm -rf $DEPLOY_DIRECTORY/* From 4ffb6eaf3086635502f14fe13843a462faf84cad Mon Sep 17 00:00:00 2001 From: Julien Blondeau Date: Fri, 19 Feb 2021 17:09:40 +0100 Subject: [PATCH 1373/2114] Handle basic query parameters in connection URI --- .../rabbitmq/client/ConnectionFactory.java | 64 +++++++++++++ .../com/rabbitmq/client/test/AmqpUriTest.java | 89 +++++++++++++++---- 2 files changed, 136 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 195b3af2a8..1af4167270 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -348,6 +348,11 @@ public void setUri(URI uri) setVirtualHost(uriDecode(uri.getPath().substring(1))); } + + String rawQuery = uri.getRawQuery(); + if (rawQuery != null && rawQuery.length() > 0) { + setQuery(rawQuery); + } } /** @@ -377,6 +382,65 @@ private static String uriDecode(String s) { } } + /** + * Convenience method for setting some fields from query parameters + * Will handle only a subset of the query parameters supported by the + * official erlang client + * https://www.rabbitmq.com/uri-query-parameters.html + * @param rawQuery is the string containing the raw query parameters part from a URI + */ + private void setQuery(String rawQuery) { + Map parameters = new HashMap<>(); + + // parsing the query parameters + try { + for (String param : rawQuery.split("&")) { + String[] pair = param.split("="); + String key = URLDecoder.decode(pair[0], "US-ASCII"); + String value = null; + if (pair.length > 1) { + value = URLDecoder.decode(pair[1], "US-ASCII"); + } + parameters.put(key, value); + } + } catch (IOException e) { + throw new RuntimeException("Cannot parse the query parameters", e); + } + + // heartbeat + String heartbeat = parameters.get("heartbeat"); + if (heartbeat != null) { + try { + int heartbeatInt = Integer.parseInt(heartbeat); + setRequestedHeartbeat(heartbeatInt); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Requested heartbeat must an integer"); + } + } + + // connection_timeout + String connectionTimeout = parameters.get("connection_timeout"); + if (connectionTimeout != null) { + try { + int connectionTimeoutInt = Integer.parseInt(connectionTimeout); + setConnectionTimeout(connectionTimeoutInt); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("TCP connection timeout must an integer"); + } + } + + // channel_max + String channelMax = parameters.get("channel_max"); + if (channelMax != null) { + try { + int channelMaxInt = Integer.parseInt(channelMax); + setRequestedChannelMax(channelMaxInt); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Requested channel max must an integer"); + } + } + } + /** * Retrieve the requested maximum channel number * @return the initially requested maximum channel number; zero for unlimited diff --git a/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java b/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java index a57e92da4d..19aad24954 100644 --- a/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java +++ b/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java @@ -32,35 +32,63 @@ public class AmqpUriTest extends BrokerTestCase { /* From the spec (subset of the tests) */ parseSuccess("amqp://user:pass@host:10000/vhost", - "user", "pass", "host", 10000, "vhost"); + "user", "pass", "host", 10000, "vhost", false); parseSuccess("aMQps://user%61:%61pass@host:10000/v%2fhost", - "usera", "apass", "host", 10000, "v/host"); - parseSuccess("amqp://host", "guest", "guest", "host", 5672, "/"); + "usera", "apass", "host", 10000, "v/host", true); + parseSuccess("amqp://host", "guest", "guest", "host", 5672, "/", false); parseSuccess("amqp:///vhost", - "guest", "guest", "localhost", 5672, "vhost"); - parseSuccess("amqp://host/", "guest", "guest", "host", 5672, ""); - parseSuccess("amqp://host/%2f", "guest", "guest", "host", 5672, "/"); - parseSuccess("amqp://[::1]", "guest", "guest", "[::1]", 5672, "/"); + "guest", "guest", "localhost", 5672, "vhost", false); + parseSuccess("amqp://host/", "guest", "guest", "host", 5672, "", false); + parseSuccess("amqp://host/%2f", "guest", "guest", "host", 5672, "/", false); + parseSuccess("amqp://[::1]", "guest", "guest", "[::1]", 5672, "/", false); /* Various other success cases */ - parseSuccess("amqp://host:100", "guest", "guest", "host", 100, "/"); - parseSuccess("amqp://[::1]:100", "guest", "guest", "[::1]", 100, "/"); + parseSuccess("amqp://host:100", "guest", "guest", "host", 100, "/", false); + parseSuccess("amqp://[::1]:100", "guest", "guest", "[::1]", 100, "/", false); parseSuccess("amqp://host/blah", - "guest", "guest", "host", 5672, "blah"); + "guest", "guest", "host", 5672, "blah", false); parseSuccess("amqp://host:100/blah", - "guest", "guest", "host", 100, "blah"); + "guest", "guest", "host", 100, "blah", false); parseSuccess("amqp://[::1]/blah", - "guest", "guest", "[::1]", 5672, "blah"); + "guest", "guest", "[::1]", 5672, "blah", false); parseSuccess("amqp://[::1]:100/blah", - "guest", "guest", "[::1]", 100, "blah"); + "guest", "guest", "[::1]", 100, "blah", false); parseSuccess("amqp://user:pass@host", - "user", "pass", "host", 5672, "/"); + "user", "pass", "host", 5672, "/", false); parseSuccess("amqp://user:pass@[::1]", - "user", "pass", "[::1]", 5672, "/"); + "user", "pass", "[::1]", 5672, "/", false); parseSuccess("amqp://user:pass@[::1]:100", - "user", "pass", "[::1]", 100, "/"); + "user", "pass", "[::1]", 100, "/", false); + + /* using query parameters */ + parseSuccess("amqp://user:pass@host:10000/vhost?", + "user", "pass", "host", 10000, "vhost", false); + parseSuccess("amqp://user:pass@host:10000/vhost?&", + "user", "pass", "host", 10000, "vhost", false); + parseSuccess("amqp://user:pass@host:10000/vhost?unknown_parameter", + "user", "pass", "host", 10000, "vhost", false); + parseSuccess("amqp://user:pass@host:10000/vhost?unknown_parameter=value", + "user", "pass", "host", 10000, "vhost", false); + parseSuccess("amqp://user:pass@host:10000/vhost?unknown%2fparameter=value", + "user", "pass", "host", 10000, "vhost", false); + + parseSuccess("amqp://user:pass@host:10000/vhost?heartbeat=342", + "user", "pass", "host", 10000, "vhost", false, + 342, null, null); + parseSuccess("amqp://user:pass@host:10000/vhost?connection_timeout=442", + "user", "pass", "host", 10000, "vhost", false, + null, 442, null); + parseSuccess("amqp://user:pass@host:10000/vhost?channel_max=542", + "user", "pass", "host", 10000, "vhost", false, + null, null, 542); + parseSuccess("amqp://user:pass@host:10000/vhost?heartbeat=342&connection_timeout=442&channel_max=542", + "user", "pass", "host", 10000, "vhost", false, + 342, 442, 542); + parseSuccess("amqp://user:pass@host:10000/vhost?heartbeat=342&connection_timeout=442&channel_max=542&a=b", + "user", "pass", "host", 10000, "vhost", false, + 342, 442, 542); /* Various failure cases */ parseFail("https://www.rabbitmq.com"); @@ -71,10 +99,26 @@ public class AmqpUriTest extends BrokerTestCase parseFail("amqp://foo%1"); parseFail("amqp://foo%1x"); parseFail("amqp://foo%xy"); + + parseFail("amqp://user:pass@host:10000/vhost?heartbeat=not_an_integer"); + parseFail("amqp://user:pass@host:10000/vhost?heartbeat=-1"); + parseFail("amqp://user:pass@host:10000/vhost?connection_timeout=not_an_integer"); + parseFail("amqp://user:pass@host:10000/vhost?connection_timeout=-1"); + parseFail("amqp://user:pass@host:10000/vhost?channel_max=not_an_integer"); + parseFail("amqp://user:pass@host:10000/vhost?channel_max=-1"); + parseFail("amqp://user:pass@host:10000/vhost?heartbeat=342?connection_timeout=442"); } private void parseSuccess(String uri, String user, String password, - String host, int port, String vhost) + String host, int port, String vhost, boolean secured) + throws URISyntaxException, NoSuchAlgorithmException, KeyManagementException + { + parseSuccess(uri, user, password, host, port, vhost, secured, null, null, null); + } + + private void parseSuccess(String uri, String user, String password, + String host, int port, String vhost, boolean secured, + Integer heartbeat, Integer connectionTimeout, Integer channelMax) throws URISyntaxException, NoSuchAlgorithmException, KeyManagementException { ConnectionFactory cf = TestUtils.connectionFactory(); @@ -85,6 +129,17 @@ private void parseSuccess(String uri, String user, String password, assertEquals(host, cf.getHost()); assertEquals(port, cf.getPort()); assertEquals(vhost, cf.getVirtualHost()); + assertEquals(secured, cf.isSSL()); + + if(heartbeat != null) { + assertEquals(heartbeat.intValue(), cf.getRequestedHeartbeat()); + } + if(connectionTimeout != null) { + assertEquals(connectionTimeout.intValue(), cf.getConnectionTimeout()); + } + if(channelMax != null) { + assertEquals(channelMax.intValue(), cf.getRequestedChannelMax()); + } } private void parseFail(String uri) { From b3edb1e6f60a9a62caaf2c710bd9b104479b1ea3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 22 Feb 2021 10:01:28 +0100 Subject: [PATCH 1374/2114] Handle URI query parameters in chain of responsibility With fallback hook, by default empty. References #672 --- .../rabbitmq/client/ConnectionFactory.java | 83 ++++++++++++------- .../com/rabbitmq/client/test/AmqpUriTest.java | 18 +++- 2 files changed, 68 insertions(+), 33 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 1af4167270..ef70124f55 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -22,6 +22,8 @@ import com.rabbitmq.client.impl.recovery.RetryHandler; import com.rabbitmq.client.impl.recovery.TopologyRecoveryFilter; +import java.util.Map.Entry; +import java.util.function.BiConsumer; import javax.net.SocketFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; @@ -382,6 +384,36 @@ private static String uriDecode(String s) { } } + private static final Map> URI_QUERY_PARAMETER_HANDLERS = + new HashMap>() { + { + put("heartbeat", (value, cf) -> { + try { + int heartbeatInt = Integer.parseInt(value); + cf.setRequestedHeartbeat(heartbeatInt); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Requested heartbeat must an integer"); + } + }); + put("connection_timeout", (value, cf) -> { + try { + int connectionTimeoutInt = Integer.parseInt(value); + cf.setConnectionTimeout(connectionTimeoutInt); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("TCP connection timeout must an integer"); + } + }); + put("channel_max", (value, cf) -> { + try { + int channelMaxInt = Integer.parseInt(value); + cf.setRequestedChannelMax(channelMaxInt); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Requested channel max must an integer"); + } + }); + } + }; + /** * Convenience method for setting some fields from query parameters * Will handle only a subset of the query parameters supported by the @@ -391,7 +423,6 @@ private static String uriDecode(String s) { */ private void setQuery(String rawQuery) { Map parameters = new HashMap<>(); - // parsing the query parameters try { for (String param : rawQuery.split("&")) { @@ -404,43 +435,31 @@ private void setQuery(String rawQuery) { parameters.put(key, value); } } catch (IOException e) { - throw new RuntimeException("Cannot parse the query parameters", e); + throw new IllegalArgumentException("Cannot parse the query parameters", e); } - // heartbeat - String heartbeat = parameters.get("heartbeat"); - if (heartbeat != null) { - try { - int heartbeatInt = Integer.parseInt(heartbeat); - setRequestedHeartbeat(heartbeatInt); - } catch (NumberFormatException e) { - throw new IllegalArgumentException("Requested heartbeat must an integer"); - } - } - - // connection_timeout - String connectionTimeout = parameters.get("connection_timeout"); - if (connectionTimeout != null) { - try { - int connectionTimeoutInt = Integer.parseInt(connectionTimeout); - setConnectionTimeout(connectionTimeoutInt); - } catch (NumberFormatException e) { - throw new IllegalArgumentException("TCP connection timeout must an integer"); - } - } - - // channel_max - String channelMax = parameters.get("channel_max"); - if (channelMax != null) { - try { - int channelMaxInt = Integer.parseInt(channelMax); - setRequestedChannelMax(channelMaxInt); - } catch (NumberFormatException e) { - throw new IllegalArgumentException("Requested channel max must an integer"); + for (Entry entry : parameters.entrySet()) { + BiConsumer handler = URI_QUERY_PARAMETER_HANDLERS + .get(entry.getKey()); + if (handler != null) { + handler.accept(entry.getValue(), this); + } else { + processUriQueryParameter(entry.getKey(), entry.getValue()); } } } + /** + * Hook to process query parameters not handled natively. + * Handled natively: heartbeat, connection_timeout, + * channel_max. + * @param key + * @param value + */ + protected void processUriQueryParameter(String key, String value) { + + } + /** * Retrieve the requested maximum channel number * @return the initially requested maximum channel number; zero for unlimited diff --git a/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java b/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java index 19aad24954..92d4232934 100644 --- a/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java +++ b/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java @@ -14,6 +14,7 @@ // info@rabbitmq.com. package com.rabbitmq.client.test; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; @@ -21,11 +22,13 @@ import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; +import java.util.HashMap; +import java.util.Map; import org.junit.Test; import com.rabbitmq.client.ConnectionFactory; -public class AmqpUriTest extends BrokerTestCase +public class AmqpUriTest { @Test public void uriParsing() throws URISyntaxException, NoSuchAlgorithmException, KeyManagementException @@ -109,6 +112,19 @@ public class AmqpUriTest extends BrokerTestCase parseFail("amqp://user:pass@host:10000/vhost?heartbeat=342?connection_timeout=442"); } + @Test + public void processUriQueryParameterShouldBeCalledForNotHandledParameter() throws Exception { + Map processedParameters = new HashMap<>(); + ConnectionFactory cf = new ConnectionFactory() { + @Override + protected void processUriQueryParameter(String key, String value) { + processedParameters.put(key, value); + } + }; + cf.setUri("amqp://user:pass@host:10000/vhost?heartbeat=60&key=value"); + assertThat(processedParameters).hasSize(1).containsEntry("key", "value"); + } + private void parseSuccess(String uri, String user, String password, String host, int port, String vhost, boolean secured) throws URISyntaxException, NoSuchAlgorithmException, KeyManagementException From 7401a4b292ca8e3043328fa668935583a628d41c Mon Sep 17 00:00:00 2001 From: Julien Blondeau Date: Fri, 19 Feb 2021 17:09:40 +0100 Subject: [PATCH 1375/2114] Handle basic query parameters in connection URI (cherry picked from commit 4ffb6eaf3086635502f14fe13843a462faf84cad) --- .../rabbitmq/client/ConnectionFactory.java | 64 +++++++++++++ .../com/rabbitmq/client/test/AmqpUriTest.java | 89 +++++++++++++++---- 2 files changed, 136 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 0b55ef7d34..b69094ac17 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -352,6 +352,11 @@ public void setUri(URI uri) setVirtualHost(uriDecode(uri.getPath().substring(1))); } + + String rawQuery = uri.getRawQuery(); + if (rawQuery != null && rawQuery.length() > 0) { + setQuery(rawQuery); + } } /** @@ -381,6 +386,65 @@ private static String uriDecode(String s) { } } + /** + * Convenience method for setting some fields from query parameters + * Will handle only a subset of the query parameters supported by the + * official erlang client + * https://www.rabbitmq.com/uri-query-parameters.html + * @param rawQuery is the string containing the raw query parameters part from a URI + */ + private void setQuery(String rawQuery) { + Map parameters = new HashMap<>(); + + // parsing the query parameters + try { + for (String param : rawQuery.split("&")) { + String[] pair = param.split("="); + String key = URLDecoder.decode(pair[0], "US-ASCII"); + String value = null; + if (pair.length > 1) { + value = URLDecoder.decode(pair[1], "US-ASCII"); + } + parameters.put(key, value); + } + } catch (IOException e) { + throw new RuntimeException("Cannot parse the query parameters", e); + } + + // heartbeat + String heartbeat = parameters.get("heartbeat"); + if (heartbeat != null) { + try { + int heartbeatInt = Integer.parseInt(heartbeat); + setRequestedHeartbeat(heartbeatInt); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Requested heartbeat must an integer"); + } + } + + // connection_timeout + String connectionTimeout = parameters.get("connection_timeout"); + if (connectionTimeout != null) { + try { + int connectionTimeoutInt = Integer.parseInt(connectionTimeout); + setConnectionTimeout(connectionTimeoutInt); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("TCP connection timeout must an integer"); + } + } + + // channel_max + String channelMax = parameters.get("channel_max"); + if (channelMax != null) { + try { + int channelMaxInt = Integer.parseInt(channelMax); + setRequestedChannelMax(channelMaxInt); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Requested channel max must an integer"); + } + } + } + /** * Retrieve the requested maximum channel number * @return the initially requested maximum channel number; zero for unlimited diff --git a/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java b/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java index a57e92da4d..19aad24954 100644 --- a/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java +++ b/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java @@ -32,35 +32,63 @@ public class AmqpUriTest extends BrokerTestCase { /* From the spec (subset of the tests) */ parseSuccess("amqp://user:pass@host:10000/vhost", - "user", "pass", "host", 10000, "vhost"); + "user", "pass", "host", 10000, "vhost", false); parseSuccess("aMQps://user%61:%61pass@host:10000/v%2fhost", - "usera", "apass", "host", 10000, "v/host"); - parseSuccess("amqp://host", "guest", "guest", "host", 5672, "/"); + "usera", "apass", "host", 10000, "v/host", true); + parseSuccess("amqp://host", "guest", "guest", "host", 5672, "/", false); parseSuccess("amqp:///vhost", - "guest", "guest", "localhost", 5672, "vhost"); - parseSuccess("amqp://host/", "guest", "guest", "host", 5672, ""); - parseSuccess("amqp://host/%2f", "guest", "guest", "host", 5672, "/"); - parseSuccess("amqp://[::1]", "guest", "guest", "[::1]", 5672, "/"); + "guest", "guest", "localhost", 5672, "vhost", false); + parseSuccess("amqp://host/", "guest", "guest", "host", 5672, "", false); + parseSuccess("amqp://host/%2f", "guest", "guest", "host", 5672, "/", false); + parseSuccess("amqp://[::1]", "guest", "guest", "[::1]", 5672, "/", false); /* Various other success cases */ - parseSuccess("amqp://host:100", "guest", "guest", "host", 100, "/"); - parseSuccess("amqp://[::1]:100", "guest", "guest", "[::1]", 100, "/"); + parseSuccess("amqp://host:100", "guest", "guest", "host", 100, "/", false); + parseSuccess("amqp://[::1]:100", "guest", "guest", "[::1]", 100, "/", false); parseSuccess("amqp://host/blah", - "guest", "guest", "host", 5672, "blah"); + "guest", "guest", "host", 5672, "blah", false); parseSuccess("amqp://host:100/blah", - "guest", "guest", "host", 100, "blah"); + "guest", "guest", "host", 100, "blah", false); parseSuccess("amqp://[::1]/blah", - "guest", "guest", "[::1]", 5672, "blah"); + "guest", "guest", "[::1]", 5672, "blah", false); parseSuccess("amqp://[::1]:100/blah", - "guest", "guest", "[::1]", 100, "blah"); + "guest", "guest", "[::1]", 100, "blah", false); parseSuccess("amqp://user:pass@host", - "user", "pass", "host", 5672, "/"); + "user", "pass", "host", 5672, "/", false); parseSuccess("amqp://user:pass@[::1]", - "user", "pass", "[::1]", 5672, "/"); + "user", "pass", "[::1]", 5672, "/", false); parseSuccess("amqp://user:pass@[::1]:100", - "user", "pass", "[::1]", 100, "/"); + "user", "pass", "[::1]", 100, "/", false); + + /* using query parameters */ + parseSuccess("amqp://user:pass@host:10000/vhost?", + "user", "pass", "host", 10000, "vhost", false); + parseSuccess("amqp://user:pass@host:10000/vhost?&", + "user", "pass", "host", 10000, "vhost", false); + parseSuccess("amqp://user:pass@host:10000/vhost?unknown_parameter", + "user", "pass", "host", 10000, "vhost", false); + parseSuccess("amqp://user:pass@host:10000/vhost?unknown_parameter=value", + "user", "pass", "host", 10000, "vhost", false); + parseSuccess("amqp://user:pass@host:10000/vhost?unknown%2fparameter=value", + "user", "pass", "host", 10000, "vhost", false); + + parseSuccess("amqp://user:pass@host:10000/vhost?heartbeat=342", + "user", "pass", "host", 10000, "vhost", false, + 342, null, null); + parseSuccess("amqp://user:pass@host:10000/vhost?connection_timeout=442", + "user", "pass", "host", 10000, "vhost", false, + null, 442, null); + parseSuccess("amqp://user:pass@host:10000/vhost?channel_max=542", + "user", "pass", "host", 10000, "vhost", false, + null, null, 542); + parseSuccess("amqp://user:pass@host:10000/vhost?heartbeat=342&connection_timeout=442&channel_max=542", + "user", "pass", "host", 10000, "vhost", false, + 342, 442, 542); + parseSuccess("amqp://user:pass@host:10000/vhost?heartbeat=342&connection_timeout=442&channel_max=542&a=b", + "user", "pass", "host", 10000, "vhost", false, + 342, 442, 542); /* Various failure cases */ parseFail("https://www.rabbitmq.com"); @@ -71,10 +99,26 @@ public class AmqpUriTest extends BrokerTestCase parseFail("amqp://foo%1"); parseFail("amqp://foo%1x"); parseFail("amqp://foo%xy"); + + parseFail("amqp://user:pass@host:10000/vhost?heartbeat=not_an_integer"); + parseFail("amqp://user:pass@host:10000/vhost?heartbeat=-1"); + parseFail("amqp://user:pass@host:10000/vhost?connection_timeout=not_an_integer"); + parseFail("amqp://user:pass@host:10000/vhost?connection_timeout=-1"); + parseFail("amqp://user:pass@host:10000/vhost?channel_max=not_an_integer"); + parseFail("amqp://user:pass@host:10000/vhost?channel_max=-1"); + parseFail("amqp://user:pass@host:10000/vhost?heartbeat=342?connection_timeout=442"); } private void parseSuccess(String uri, String user, String password, - String host, int port, String vhost) + String host, int port, String vhost, boolean secured) + throws URISyntaxException, NoSuchAlgorithmException, KeyManagementException + { + parseSuccess(uri, user, password, host, port, vhost, secured, null, null, null); + } + + private void parseSuccess(String uri, String user, String password, + String host, int port, String vhost, boolean secured, + Integer heartbeat, Integer connectionTimeout, Integer channelMax) throws URISyntaxException, NoSuchAlgorithmException, KeyManagementException { ConnectionFactory cf = TestUtils.connectionFactory(); @@ -85,6 +129,17 @@ private void parseSuccess(String uri, String user, String password, assertEquals(host, cf.getHost()); assertEquals(port, cf.getPort()); assertEquals(vhost, cf.getVirtualHost()); + assertEquals(secured, cf.isSSL()); + + if(heartbeat != null) { + assertEquals(heartbeat.intValue(), cf.getRequestedHeartbeat()); + } + if(connectionTimeout != null) { + assertEquals(connectionTimeout.intValue(), cf.getConnectionTimeout()); + } + if(channelMax != null) { + assertEquals(channelMax.intValue(), cf.getRequestedChannelMax()); + } } private void parseFail(String uri) { From d9108eca3e99c080cb34c9c87a4151e178e98292 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 22 Feb 2021 10:01:28 +0100 Subject: [PATCH 1376/2114] Handle URI query parameters in chain of responsibility With fallback hook, by default empty. References #672 (cherry picked from commit b3edb1e6f60a9a62caaf2c710bd9b104479b1ea3) --- .../rabbitmq/client/ConnectionFactory.java | 83 ++++++++++++------- .../com/rabbitmq/client/test/AmqpUriTest.java | 18 +++- 2 files changed, 68 insertions(+), 33 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index b69094ac17..b3b8612b59 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -24,6 +24,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Map.Entry; +import java.util.function.BiConsumer; import javax.net.SocketFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; @@ -386,6 +388,36 @@ private static String uriDecode(String s) { } } + private static final Map> URI_QUERY_PARAMETER_HANDLERS = + new HashMap>() { + { + put("heartbeat", (value, cf) -> { + try { + int heartbeatInt = Integer.parseInt(value); + cf.setRequestedHeartbeat(heartbeatInt); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Requested heartbeat must an integer"); + } + }); + put("connection_timeout", (value, cf) -> { + try { + int connectionTimeoutInt = Integer.parseInt(value); + cf.setConnectionTimeout(connectionTimeoutInt); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("TCP connection timeout must an integer"); + } + }); + put("channel_max", (value, cf) -> { + try { + int channelMaxInt = Integer.parseInt(value); + cf.setRequestedChannelMax(channelMaxInt); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Requested channel max must an integer"); + } + }); + } + }; + /** * Convenience method for setting some fields from query parameters * Will handle only a subset of the query parameters supported by the @@ -395,7 +427,6 @@ private static String uriDecode(String s) { */ private void setQuery(String rawQuery) { Map parameters = new HashMap<>(); - // parsing the query parameters try { for (String param : rawQuery.split("&")) { @@ -408,43 +439,31 @@ private void setQuery(String rawQuery) { parameters.put(key, value); } } catch (IOException e) { - throw new RuntimeException("Cannot parse the query parameters", e); + throw new IllegalArgumentException("Cannot parse the query parameters", e); } - // heartbeat - String heartbeat = parameters.get("heartbeat"); - if (heartbeat != null) { - try { - int heartbeatInt = Integer.parseInt(heartbeat); - setRequestedHeartbeat(heartbeatInt); - } catch (NumberFormatException e) { - throw new IllegalArgumentException("Requested heartbeat must an integer"); - } - } - - // connection_timeout - String connectionTimeout = parameters.get("connection_timeout"); - if (connectionTimeout != null) { - try { - int connectionTimeoutInt = Integer.parseInt(connectionTimeout); - setConnectionTimeout(connectionTimeoutInt); - } catch (NumberFormatException e) { - throw new IllegalArgumentException("TCP connection timeout must an integer"); - } - } - - // channel_max - String channelMax = parameters.get("channel_max"); - if (channelMax != null) { - try { - int channelMaxInt = Integer.parseInt(channelMax); - setRequestedChannelMax(channelMaxInt); - } catch (NumberFormatException e) { - throw new IllegalArgumentException("Requested channel max must an integer"); + for (Entry entry : parameters.entrySet()) { + BiConsumer handler = URI_QUERY_PARAMETER_HANDLERS + .get(entry.getKey()); + if (handler != null) { + handler.accept(entry.getValue(), this); + } else { + processUriQueryParameter(entry.getKey(), entry.getValue()); } } } + /** + * Hook to process query parameters not handled natively. + * Handled natively: heartbeat, connection_timeout, + * channel_max. + * @param key + * @param value + */ + protected void processUriQueryParameter(String key, String value) { + + } + /** * Retrieve the requested maximum channel number * @return the initially requested maximum channel number; zero for unlimited diff --git a/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java b/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java index 19aad24954..92d4232934 100644 --- a/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java +++ b/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java @@ -14,6 +14,7 @@ // info@rabbitmq.com. package com.rabbitmq.client.test; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; @@ -21,11 +22,13 @@ import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; +import java.util.HashMap; +import java.util.Map; import org.junit.Test; import com.rabbitmq.client.ConnectionFactory; -public class AmqpUriTest extends BrokerTestCase +public class AmqpUriTest { @Test public void uriParsing() throws URISyntaxException, NoSuchAlgorithmException, KeyManagementException @@ -109,6 +112,19 @@ public class AmqpUriTest extends BrokerTestCase parseFail("amqp://user:pass@host:10000/vhost?heartbeat=342?connection_timeout=442"); } + @Test + public void processUriQueryParameterShouldBeCalledForNotHandledParameter() throws Exception { + Map processedParameters = new HashMap<>(); + ConnectionFactory cf = new ConnectionFactory() { + @Override + protected void processUriQueryParameter(String key, String value) { + processedParameters.put(key, value); + } + }; + cf.setUri("amqp://user:pass@host:10000/vhost?heartbeat=60&key=value"); + assertThat(processedParameters).hasSize(1).containsEntry("key", "value"); + } + private void parseSuccess(String uri, String user, String password, String host, int port, String vhost, boolean secured) throws URISyntaxException, NoSuchAlgorithmException, KeyManagementException From bf362d5d765beb6206d5c2c7b2949ce2cb01df4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 22 Feb 2021 10:58:41 +0100 Subject: [PATCH 1377/2114] Fix AMQP parsing test Difference between 6.x and 5.x. References #640, #642, #672 --- src/test/java/com/rabbitmq/client/test/AmqpUriTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java b/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java index 92d4232934..d5be86e4ee 100644 --- a/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java +++ b/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java @@ -104,11 +104,9 @@ public class AmqpUriTest parseFail("amqp://foo%xy"); parseFail("amqp://user:pass@host:10000/vhost?heartbeat=not_an_integer"); - parseFail("amqp://user:pass@host:10000/vhost?heartbeat=-1"); parseFail("amqp://user:pass@host:10000/vhost?connection_timeout=not_an_integer"); parseFail("amqp://user:pass@host:10000/vhost?connection_timeout=-1"); parseFail("amqp://user:pass@host:10000/vhost?channel_max=not_an_integer"); - parseFail("amqp://user:pass@host:10000/vhost?channel_max=-1"); parseFail("amqp://user:pass@host:10000/vhost?heartbeat=342?connection_timeout=442"); } From 7812ebf0705eb6291d6b4fcc87c3443ab1617a7b Mon Sep 17 00:00:00 2001 From: Gustaf Andersson Date: Mon, 22 Mar 2021 14:04:54 +0100 Subject: [PATCH 1378/2114] Add support for reading unsigned short "u". Add support for reading unsigned short "u". https://www.rabbitmq.com/amqp-0-9-1-errata.html#section_3 --- src/main/java/com/rabbitmq/client/impl/ValueReader.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/com/rabbitmq/client/impl/ValueReader.java b/src/main/java/com/rabbitmq/client/impl/ValueReader.java index 83455bfe66..3e80f8853e 100644 --- a/src/main/java/com/rabbitmq/client/impl/ValueReader.java +++ b/src/main/java/com/rabbitmq/client/impl/ValueReader.java @@ -194,6 +194,9 @@ static Object readFieldValue(DataInputStream in) case 's': value = in.readShort(); break; + case 'u': + value = in.readUnsignedShort(); + break; case 't': value = in.readBoolean(); break; From 5971e42e97f80df4d0228a6a9669c8c1a4d725cd Mon Sep 17 00:00:00 2001 From: Gustaf Andersson Date: Mon, 22 Mar 2021 16:00:21 +0100 Subject: [PATCH 1379/2114] Add support for reading unsigned int "i" Add support for reading unsigned int "I" https://www.rabbitmq.com/amqp-0-9-1-errata.html#section_3 --- .../java/com/rabbitmq/client/impl/ValueReader.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main/java/com/rabbitmq/client/impl/ValueReader.java b/src/main/java/com/rabbitmq/client/impl/ValueReader.java index 3e80f8853e..4912c8541d 100644 --- a/src/main/java/com/rabbitmq/client/impl/ValueReader.java +++ b/src/main/java/com/rabbitmq/client/impl/ValueReader.java @@ -164,6 +164,9 @@ static Object readFieldValue(DataInputStream in) case 'I': value = in.readInt(); break; + case 'i': + value = readUnsignedInt(in); + break; case 'D': int scale = in.readUnsignedByte(); byte [] unscaled = new byte[4]; @@ -213,6 +216,17 @@ static Object readFieldValue(DataInputStream in) return value; } + /** Read an unsigned int */ + private static long readUnsignedInt(DataInputStream in) throws IOException { + long ch1 = in.read(); + long ch2 = in.read(); + long ch3 = in.read(); + long ch4 = in.read(); + if ((ch1 | ch2 | ch3 | ch4) < 0) + throw new EOFException(); + return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + ch4); + } + /** Read a field-array */ private static List readArray(DataInputStream in) throws IOException From 4895aa2d6d5d5774674075663ea6fa751e48e86e Mon Sep 17 00:00:00 2001 From: Gustaf Andersson Date: Mon, 22 Mar 2021 16:07:36 +0100 Subject: [PATCH 1380/2114] code style --- src/main/java/com/rabbitmq/client/impl/ValueReader.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/impl/ValueReader.java b/src/main/java/com/rabbitmq/client/impl/ValueReader.java index 4912c8541d..7c708f73d2 100644 --- a/src/main/java/com/rabbitmq/client/impl/ValueReader.java +++ b/src/main/java/com/rabbitmq/client/impl/ValueReader.java @@ -217,7 +217,9 @@ static Object readFieldValue(DataInputStream in) } /** Read an unsigned int */ - private static long readUnsignedInt(DataInputStream in) throws IOException { + private static long readUnsignedInt(DataInputStream in) + throws IOException + { long ch1 = in.read(); long ch2 = in.read(); long ch3 = in.read(); From 3db2425473a53c7546362beb26fd14eab1a5ef4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 29 Mar 2021 09:56:02 +0200 Subject: [PATCH 1381/2114] Add missing import References #675 --- src/main/java/com/rabbitmq/client/impl/ValueReader.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/rabbitmq/client/impl/ValueReader.java b/src/main/java/com/rabbitmq/client/impl/ValueReader.java index 7c708f73d2..1162cc8af0 100644 --- a/src/main/java/com/rabbitmq/client/impl/ValueReader.java +++ b/src/main/java/com/rabbitmq/client/impl/ValueReader.java @@ -17,6 +17,7 @@ package com.rabbitmq.client.impl; import java.io.DataInputStream; +import java.io.EOFException; import java.io.IOException; import java.math.BigDecimal; import java.math.BigInteger; From 24d96bddfc96badf68dc7df6bd7b469f0c5699ae Mon Sep 17 00:00:00 2001 From: Gustaf Andersson Date: Mon, 22 Mar 2021 14:04:54 +0100 Subject: [PATCH 1382/2114] Add support for reading unsigned short "u". Add support for reading unsigned short "u". https://www.rabbitmq.com/amqp-0-9-1-errata.html#section_3 (cherry picked from commit 7812ebf0705eb6291d6b4fcc87c3443ab1617a7b) --- src/main/java/com/rabbitmq/client/impl/ValueReader.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/com/rabbitmq/client/impl/ValueReader.java b/src/main/java/com/rabbitmq/client/impl/ValueReader.java index 83455bfe66..3e80f8853e 100644 --- a/src/main/java/com/rabbitmq/client/impl/ValueReader.java +++ b/src/main/java/com/rabbitmq/client/impl/ValueReader.java @@ -194,6 +194,9 @@ static Object readFieldValue(DataInputStream in) case 's': value = in.readShort(); break; + case 'u': + value = in.readUnsignedShort(); + break; case 't': value = in.readBoolean(); break; From 11dce898a4e0ff96db8bd36bc12a388f6072baf9 Mon Sep 17 00:00:00 2001 From: Gustaf Andersson Date: Mon, 22 Mar 2021 16:00:21 +0100 Subject: [PATCH 1383/2114] Add support for reading unsigned int "i" Add support for reading unsigned int "I" https://www.rabbitmq.com/amqp-0-9-1-errata.html#section_3 (cherry picked from commit 5971e42e97f80df4d0228a6a9669c8c1a4d725cd) --- .../java/com/rabbitmq/client/impl/ValueReader.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main/java/com/rabbitmq/client/impl/ValueReader.java b/src/main/java/com/rabbitmq/client/impl/ValueReader.java index 3e80f8853e..4912c8541d 100644 --- a/src/main/java/com/rabbitmq/client/impl/ValueReader.java +++ b/src/main/java/com/rabbitmq/client/impl/ValueReader.java @@ -164,6 +164,9 @@ static Object readFieldValue(DataInputStream in) case 'I': value = in.readInt(); break; + case 'i': + value = readUnsignedInt(in); + break; case 'D': int scale = in.readUnsignedByte(); byte [] unscaled = new byte[4]; @@ -213,6 +216,17 @@ static Object readFieldValue(DataInputStream in) return value; } + /** Read an unsigned int */ + private static long readUnsignedInt(DataInputStream in) throws IOException { + long ch1 = in.read(); + long ch2 = in.read(); + long ch3 = in.read(); + long ch4 = in.read(); + if ((ch1 | ch2 | ch3 | ch4) < 0) + throw new EOFException(); + return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + ch4); + } + /** Read a field-array */ private static List readArray(DataInputStream in) throws IOException From 4d0ba6d2d3bf015d1629e1ae56f50b7a0c2ad85c Mon Sep 17 00:00:00 2001 From: Gustaf Andersson Date: Mon, 22 Mar 2021 16:07:36 +0100 Subject: [PATCH 1384/2114] code style (cherry picked from commit 4895aa2d6d5d5774674075663ea6fa751e48e86e) --- src/main/java/com/rabbitmq/client/impl/ValueReader.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/impl/ValueReader.java b/src/main/java/com/rabbitmq/client/impl/ValueReader.java index 4912c8541d..7c708f73d2 100644 --- a/src/main/java/com/rabbitmq/client/impl/ValueReader.java +++ b/src/main/java/com/rabbitmq/client/impl/ValueReader.java @@ -217,7 +217,9 @@ static Object readFieldValue(DataInputStream in) } /** Read an unsigned int */ - private static long readUnsignedInt(DataInputStream in) throws IOException { + private static long readUnsignedInt(DataInputStream in) + throws IOException + { long ch1 = in.read(); long ch2 = in.read(); long ch3 = in.read(); From a53f600f849eaa71a90854caa28711b298dae85c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 29 Mar 2021 09:56:02 +0200 Subject: [PATCH 1385/2114] Add missing import References #675 (cherry picked from commit 3db2425473a53c7546362beb26fd14eab1a5ef4e) --- src/main/java/com/rabbitmq/client/impl/ValueReader.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/rabbitmq/client/impl/ValueReader.java b/src/main/java/com/rabbitmq/client/impl/ValueReader.java index 7c708f73d2..1162cc8af0 100644 --- a/src/main/java/com/rabbitmq/client/impl/ValueReader.java +++ b/src/main/java/com/rabbitmq/client/impl/ValueReader.java @@ -17,6 +17,7 @@ package com.rabbitmq.client.impl; import java.io.DataInputStream; +import java.io.EOFException; import java.io.IOException; import java.math.BigDecimal; import java.math.BigInteger; From af322a76761e4fcf8a8103d8fdbb24012fa03911 Mon Sep 17 00:00:00 2001 From: Michael Dent Date: Thu, 1 Apr 2021 14:20:29 -0500 Subject: [PATCH 1386/2114] topology recovery updates --- .../client/TopologyRecoveryException.java | 14 +++++ .../impl/recovery/AutorecoveringChannel.java | 6 +- .../recovery/AutorecoveringConnection.java | 60 ++++++++++++++----- .../impl/recovery/DefaultRetryHandler.java | 20 +++---- .../TopologyRecoveryRetryHandlerBuilder.java | 20 +++---- .../recovery/TopologyRecoveryRetryLogic.java | 53 ++++++++++++++-- 6 files changed, 132 insertions(+), 41 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/TopologyRecoveryException.java b/src/main/java/com/rabbitmq/client/TopologyRecoveryException.java index bdd8b7f807..bb8163a096 100644 --- a/src/main/java/com/rabbitmq/client/TopologyRecoveryException.java +++ b/src/main/java/com/rabbitmq/client/TopologyRecoveryException.java @@ -15,6 +15,8 @@ package com.rabbitmq.client; +import com.rabbitmq.client.impl.recovery.RecordedEntity; + /** * Indicates an exception thrown during topology recovery. * @@ -22,7 +24,19 @@ * @since 3.3.0 */ public class TopologyRecoveryException extends Exception { + + private final RecordedEntity recordedEntity; + public TopologyRecoveryException(String message, Throwable cause) { + this(message, cause, null); + } + + public TopologyRecoveryException(String message, Throwable cause, final RecordedEntity recordedEntity) { super(message, cause); + this.recordedEntity = recordedEntity; + } + + public RecordedEntity getRecordedEntity() { + return recordedEntity; } } diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java index 52e100ad57..97cacc81b0 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java @@ -900,7 +900,11 @@ private void recordConsumer(String result, this.connection.recordConsumer(result, consumer); } - private void deleteRecordedConsumer(String consumerTag) { + /** + * Delete the recorded consumer from this channel and accompanying connection + * @param consumerTag consumer tag to delete + */ + public void deleteRecordedConsumer(String consumerTag) { this.consumerTags.remove(consumerTag); RecordedConsumer c = this.connection.deleteRecordedConsumer(consumerTag); if (c != null) { diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index f217bd4dc4..98d5a4d610 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -143,7 +143,7 @@ private void setupErrorOnWriteListenerForPotentialRecovery() { }); } - private TopologyRecoveryFilter letAllPassFilter() { + private static TopologyRecoveryFilter letAllPassFilter() { return new TopologyRecoveryFilter() {}; } @@ -644,7 +644,7 @@ private void recoverChannels(final RecoveryAwareAMQConnection newConn) { } } - void recoverChannel(AutorecoveringChannel channel) throws IOException { + public void recoverChannel(AutorecoveringChannel channel) throws IOException { channel.automaticallyRecover(this, this.delegate); } @@ -666,6 +666,38 @@ private void notifyTopologyRecoveryListenersStarted() { } } + /** + * Recover a closed channel and all topology (i.e. RecordedEntities) associated to it. + * Any errors will be sent to the {@link #getExceptionHandler()}. + * @param channel channel to recover + * @throws IllegalArgumentException if this channel is not owned by this connection + */ + public void recoverChannelAndTopology(final AutorecoveringChannel channel) { + if (!channels.containsValue(channel)) { + throw new IllegalArgumentException("This channel is not owned by this connection"); + } + try { + LOGGER.debug("Recovering channel={}", channel); + recoverChannel(channel); + LOGGER.debug("Recovered channel={}. Now recovering its topology", channel); + Utility.copy(recordedExchanges).values().stream() + .filter(e -> e.getChannel() == channel) + .forEach(e -> recoverExchange(e, false)); + Utility.copy(recordedQueues).values().stream() + .filter(q -> q.getChannel() == channel) + .forEach(q -> recoverQueue(q.getName(), q, false)); + Utility.copy(recordedBindings).stream() + .filter(b -> b.getChannel() == channel) + .forEach(b -> recoverBinding(b, false)); + Utility.copy(consumers).values().stream() + .filter(c -> c.getChannel() == channel) + .forEach(c -> recoverConsumer(c.getConsumerTag(), c, false)); + LOGGER.debug("Recovered topology for channel={}", channel); + } catch (Exception e) { + getExceptionHandler().handleChannelRecoveryException(channel, e); + } + } + private void recoverTopology(final ExecutorService executor) { // The recovery sequence is the following: // 1. Recover exchanges @@ -704,7 +736,7 @@ private void recoverTopology(final ExecutorService executor) { } } - private void recoverExchange(RecordedExchange x, boolean retry) { + public void recoverExchange(RecordedExchange x, boolean retry) { // recorded exchanges are guaranteed to be non-predefined (we filter out predefined ones in exchangeDeclare). MK. try { if (topologyRecoveryFilter.filterExchange(x)) { @@ -722,7 +754,7 @@ private void recoverExchange(RecordedExchange x, boolean retry) { } catch (Exception cause) { final String message = "Caught an exception while recovering exchange " + x.getName() + ": " + cause.getMessage(); - TopologyRecoveryException e = new TopologyRecoveryException(message, cause); + TopologyRecoveryException e = new TopologyRecoveryException(message, cause, x); this.getExceptionHandler().handleTopologyRecoveryException(delegate, x.getDelegateChannel(), e); } } @@ -766,12 +798,12 @@ public void recoverQueue(final String oldName, RecordedQueue q, boolean retry) { } catch (Exception cause) { final String message = "Caught an exception while recovering queue " + oldName + ": " + cause.getMessage(); - TopologyRecoveryException e = new TopologyRecoveryException(message, cause); + TopologyRecoveryException e = new TopologyRecoveryException(message, cause, q); this.getExceptionHandler().handleTopologyRecoveryException(delegate, q.getDelegateChannel(), e); } } - private void recoverBinding(RecordedBinding b, boolean retry) { + public void recoverBinding(RecordedBinding b, boolean retry) { try { if (this.topologyRecoveryFilter.filterBinding(b)) { if (retry) { @@ -788,7 +820,7 @@ private void recoverBinding(RecordedBinding b, boolean retry) { } catch (Exception cause) { String message = "Caught an exception while recovering binding between " + b.getSource() + " and " + b.getDestination() + ": " + cause.getMessage(); - TopologyRecoveryException e = new TopologyRecoveryException(message, cause); + TopologyRecoveryException e = new TopologyRecoveryException(message, cause, b); this.getExceptionHandler().handleTopologyRecoveryException(delegate, b.getDelegateChannel(), e); } } @@ -800,7 +832,7 @@ public void recoverConsumer(final String tag, RecordedConsumer consumer, boolean String newTag = null; if (retry) { final RecordedConsumer entity = consumer; - RetryResult retryResult = wrapRetryIfNecessary(consumer, () -> entity.recover()); + RetryResult retryResult = wrapRetryIfNecessary(consumer, entity::recover); consumer = (RecordedConsumer) retryResult.getRecordedEntity(); newTag = (String) retryResult.getResult(); } else { @@ -824,7 +856,7 @@ public void recoverConsumer(final String tag, RecordedConsumer consumer, boolean } catch (Exception cause) { final String message = "Caught an exception while recovering consumer " + tag + ": " + cause.getMessage(); - TopologyRecoveryException e = new TopologyRecoveryException(message, cause); + TopologyRecoveryException e = new TopologyRecoveryException(message, cause, consumer); this.getExceptionHandler().handleTopologyRecoveryException(delegate, consumer.getDelegateChannel(), e); } } @@ -889,14 +921,10 @@ private void recoverEntitiesAsynchronously(ExecutorService executor, Collection< private List> groupEntitiesByChannel(final Collection entities) { // map entities by channel - final Map> map = new LinkedHashMap>(); + final Map> map = new LinkedHashMap<>(); for (final E entity : entities) { final AutorecoveringChannel channel = entity.getChannel(); - List list = map.get(channel); - if (list == null) { - map.put(channel, list = new ArrayList()); - } - list.add(entity); + map.computeIfAbsent(channel, c -> new ArrayList<>()).add(entity); } // now create a runnable per channel final List> callables = new ArrayList<>(); @@ -1083,7 +1111,7 @@ boolean hasMoreConsumersOnQueue(Collection consumers, String q } Set removeBindingsWithDestination(String s) { - final Set result = new HashSet(); + final Set result = new LinkedHashSet<>(); synchronized (this.recordedBindings) { for (Iterator it = this.recordedBindings.iterator(); it.hasNext(); ) { RecordedBinding b = it.next(); diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java b/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java index dc55fc7ed4..2e2890c05b 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java @@ -40,19 +40,19 @@ public class DefaultRetryHandler implements RetryHandler { private static final Logger LOGGER = LoggerFactory.getLogger(DefaultRetryHandler.class); - private final BiPredicate queueRecoveryRetryCondition; - private final BiPredicate exchangeRecoveryRetryCondition; - private final BiPredicate bindingRecoveryRetryCondition; - private final BiPredicate consumerRecoveryRetryCondition; + protected final BiPredicate queueRecoveryRetryCondition; + protected final BiPredicate exchangeRecoveryRetryCondition; + protected final BiPredicate bindingRecoveryRetryCondition; + protected final BiPredicate consumerRecoveryRetryCondition; - private final RetryOperation queueRecoveryRetryOperation; - private final RetryOperation exchangeRecoveryRetryOperation; - private final RetryOperation bindingRecoveryRetryOperation; - private final RetryOperation consumerRecoveryRetryOperation; + protected final RetryOperation queueRecoveryRetryOperation; + protected final RetryOperation exchangeRecoveryRetryOperation; + protected final RetryOperation bindingRecoveryRetryOperation; + protected final RetryOperation consumerRecoveryRetryOperation; - private final int retryAttempts; + protected final int retryAttempts; - private final BackoffPolicy backoffPolicy; + protected final BackoffPolicy backoffPolicy; public DefaultRetryHandler(BiPredicate queueRecoveryRetryCondition, BiPredicate exchangeRecoveryRetryCondition, diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryHandlerBuilder.java b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryHandlerBuilder.java index bed71f9f0b..b8dfdff7bc 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryHandlerBuilder.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryHandlerBuilder.java @@ -30,19 +30,19 @@ */ public class TopologyRecoveryRetryHandlerBuilder { - private BiPredicate queueRecoveryRetryCondition = (q, e) -> false; - private BiPredicate exchangeRecoveryRetryCondition = (ex, e) -> false; - private BiPredicate bindingRecoveryRetryCondition = (b, e) -> false; - private BiPredicate consumerRecoveryRetryCondition = (c, e) -> false; + protected BiPredicate queueRecoveryRetryCondition = (q, e) -> false; + protected BiPredicate exchangeRecoveryRetryCondition = (ex, e) -> false; + protected BiPredicate bindingRecoveryRetryCondition = (b, e) -> false; + protected BiPredicate consumerRecoveryRetryCondition = (c, e) -> false; - private DefaultRetryHandler.RetryOperation queueRecoveryRetryOperation = context -> null; - private DefaultRetryHandler.RetryOperation exchangeRecoveryRetryOperation = context -> null; - private DefaultRetryHandler.RetryOperation bindingRecoveryRetryOperation = context -> null; - private DefaultRetryHandler.RetryOperation consumerRecoveryRetryOperation = context -> null; + protected DefaultRetryHandler.RetryOperation queueRecoveryRetryOperation = context -> null; + protected DefaultRetryHandler.RetryOperation exchangeRecoveryRetryOperation = context -> null; + protected DefaultRetryHandler.RetryOperation bindingRecoveryRetryOperation = context -> null; + protected DefaultRetryHandler.RetryOperation consumerRecoveryRetryOperation = context -> null; - private int retryAttempts = 2; + protected int retryAttempts = 2; - private BackoffPolicy backoffPolicy = nbAttempts -> { + protected BackoffPolicy backoffPolicy = nbAttempts -> { }; public static TopologyRecoveryRetryHandlerBuilder builder() { diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java index 94c347f7fa..b93ba7a647 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java @@ -18,7 +18,6 @@ import com.rabbitmq.client.AMQP; import com.rabbitmq.client.ShutdownSignalException; import com.rabbitmq.utility.Utility; - import java.util.function.BiPredicate; import static com.rabbitmq.client.impl.recovery.TopologyRecoveryRetryHandlerBuilder.builder; @@ -55,6 +54,18 @@ public abstract class TopologyRecoveryRetryLogic { } return null; }; + + /** + * Recover a queue + */ + public static final DefaultRetryHandler.RetryOperation RECOVER_QUEUE = context -> { + if (context.entity() instanceof RecordedQueue) { + final RecordedQueue recordedQueue = context.queue(); + AutorecoveringConnection connection = context.connection(); + connection.recoverQueue(recordedQueue.getName(), recordedQueue, false); + } + return null; + }; /** * Recover the destination queue of a binding. @@ -138,18 +149,52 @@ public abstract class TopologyRecoveryRetryLogic { * Recover a consumer. */ public static final DefaultRetryHandler.RetryOperation RECOVER_CONSUMER = context -> context.consumer().recover(); + + /** + * Recover earlier consumers that share the same channel as this retry context + */ + public static final DefaultRetryHandler.RetryOperation RECOVER_PREVIOUS_CONSUMERS = context -> { + if (context.entity() instanceof RecordedConsumer) { + // recover all consumers for the same channel that were recovered before this current + // consumer. need to do this incase some consumers had already been recovered + // successfully on a different queue before this one failed + final AutorecoveringChannel channel = context.consumer().getChannel(); + for (RecordedConsumer consumer : Utility.copy(context.connection().getRecordedConsumers()).values()) { + if (consumer == context.entity()) { + break; + } else if (consumer.getChannel() == channel) { + final RetryContext retryContext = new RetryContext(consumer, context.exception(), context.connection()); + RECOVER_CONSUMER_QUEUE.call(retryContext); + consumer.recover(); + RECOVER_CONSUMER_QUEUE_BINDINGS.call(retryContext); + } + } + } + return null; + }; /** * Pre-configured {@link TopologyRecoveryRetryHandlerBuilder} that retries recovery of bindings and consumers * when their respective queue is not found. + * * This retry handler can be useful for long recovery processes, whereby auto-delete queues * can be deleted between queue recovery and binding/consumer recovery. + * + * Also useful to retry channel-closed 404 errors that may arise with auto-delete queues during a cluster cycle. */ public static final TopologyRecoveryRetryHandlerBuilder RETRY_ON_QUEUE_NOT_FOUND_RETRY_HANDLER = builder() + .queueRecoveryRetryCondition(CHANNEL_CLOSED_NOT_FOUND) .bindingRecoveryRetryCondition(CHANNEL_CLOSED_NOT_FOUND) .consumerRecoveryRetryCondition(CHANNEL_CLOSED_NOT_FOUND) - .bindingRecoveryRetryOperation(RECOVER_CHANNEL.andThen(RECOVER_BINDING_QUEUE).andThen(RECOVER_BINDING) + .queueRecoveryRetryOperation(RECOVER_CHANNEL + .andThen(RECOVER_QUEUE)) + .bindingRecoveryRetryOperation(RECOVER_CHANNEL + .andThen(RECOVER_BINDING_QUEUE) + .andThen(RECOVER_BINDING) .andThen(RECOVER_PREVIOUS_QUEUE_BINDINGS)) - .consumerRecoveryRetryOperation(RECOVER_CHANNEL.andThen(RECOVER_CONSUMER_QUEUE.andThen(RECOVER_CONSUMER) - .andThen(RECOVER_CONSUMER_QUEUE_BINDINGS))); + .consumerRecoveryRetryOperation(RECOVER_CHANNEL + .andThen(RECOVER_CONSUMER_QUEUE) + .andThen(RECOVER_CONSUMER) + .andThen(RECOVER_CONSUMER_QUEUE_BINDINGS) + .andThen(RECOVER_PREVIOUS_CONSUMERS)); } From c7750431c445b565a5b99d298fcb828bddb4636c Mon Sep 17 00:00:00 2001 From: Michael Dent Date: Thu, 1 Apr 2021 16:54:55 -0500 Subject: [PATCH 1387/2114] updates --- .../client/TopologyRecoveryException.java | 14 +++++ .../impl/recovery/AutorecoveringChannel.java | 6 +- .../recovery/AutorecoveringConnection.java | 60 ++++++++++++++----- .../impl/recovery/DefaultRetryHandler.java | 20 +++---- .../TopologyRecoveryRetryHandlerBuilder.java | 20 +++---- .../recovery/TopologyRecoveryRetryLogic.java | 52 +++++++++++++++- 6 files changed, 132 insertions(+), 40 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/TopologyRecoveryException.java b/src/main/java/com/rabbitmq/client/TopologyRecoveryException.java index bdd8b7f807..77b305c2e3 100644 --- a/src/main/java/com/rabbitmq/client/TopologyRecoveryException.java +++ b/src/main/java/com/rabbitmq/client/TopologyRecoveryException.java @@ -15,6 +15,8 @@ package com.rabbitmq.client; +import com.rabbitmq.client.impl.recovery.RecordedEntity; + /** * Indicates an exception thrown during topology recovery. * @@ -22,7 +24,19 @@ * @since 3.3.0 */ public class TopologyRecoveryException extends Exception { + + private final RecordedEntity recordedEntity; + public TopologyRecoveryException(String message, Throwable cause) { + this(message, cause, null); + } + + public TopologyRecoveryException(String message, Throwable cause, final RecordedEntity recordedEntity) { super(message, cause); + this.recordedEntity = recordedEntity; + } + + public RecordedEntity getRecordedEntity() { + return recordedEntity; } } diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java index 52e100ad57..97cacc81b0 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java @@ -900,7 +900,11 @@ private void recordConsumer(String result, this.connection.recordConsumer(result, consumer); } - private void deleteRecordedConsumer(String consumerTag) { + /** + * Delete the recorded consumer from this channel and accompanying connection + * @param consumerTag consumer tag to delete + */ + public void deleteRecordedConsumer(String consumerTag) { this.consumerTags.remove(consumerTag); RecordedConsumer c = this.connection.deleteRecordedConsumer(consumerTag); if (c != null) { diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index f217bd4dc4..98d5a4d610 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -143,7 +143,7 @@ private void setupErrorOnWriteListenerForPotentialRecovery() { }); } - private TopologyRecoveryFilter letAllPassFilter() { + private static TopologyRecoveryFilter letAllPassFilter() { return new TopologyRecoveryFilter() {}; } @@ -644,7 +644,7 @@ private void recoverChannels(final RecoveryAwareAMQConnection newConn) { } } - void recoverChannel(AutorecoveringChannel channel) throws IOException { + public void recoverChannel(AutorecoveringChannel channel) throws IOException { channel.automaticallyRecover(this, this.delegate); } @@ -666,6 +666,38 @@ private void notifyTopologyRecoveryListenersStarted() { } } + /** + * Recover a closed channel and all topology (i.e. RecordedEntities) associated to it. + * Any errors will be sent to the {@link #getExceptionHandler()}. + * @param channel channel to recover + * @throws IllegalArgumentException if this channel is not owned by this connection + */ + public void recoverChannelAndTopology(final AutorecoveringChannel channel) { + if (!channels.containsValue(channel)) { + throw new IllegalArgumentException("This channel is not owned by this connection"); + } + try { + LOGGER.debug("Recovering channel={}", channel); + recoverChannel(channel); + LOGGER.debug("Recovered channel={}. Now recovering its topology", channel); + Utility.copy(recordedExchanges).values().stream() + .filter(e -> e.getChannel() == channel) + .forEach(e -> recoverExchange(e, false)); + Utility.copy(recordedQueues).values().stream() + .filter(q -> q.getChannel() == channel) + .forEach(q -> recoverQueue(q.getName(), q, false)); + Utility.copy(recordedBindings).stream() + .filter(b -> b.getChannel() == channel) + .forEach(b -> recoverBinding(b, false)); + Utility.copy(consumers).values().stream() + .filter(c -> c.getChannel() == channel) + .forEach(c -> recoverConsumer(c.getConsumerTag(), c, false)); + LOGGER.debug("Recovered topology for channel={}", channel); + } catch (Exception e) { + getExceptionHandler().handleChannelRecoveryException(channel, e); + } + } + private void recoverTopology(final ExecutorService executor) { // The recovery sequence is the following: // 1. Recover exchanges @@ -704,7 +736,7 @@ private void recoverTopology(final ExecutorService executor) { } } - private void recoverExchange(RecordedExchange x, boolean retry) { + public void recoverExchange(RecordedExchange x, boolean retry) { // recorded exchanges are guaranteed to be non-predefined (we filter out predefined ones in exchangeDeclare). MK. try { if (topologyRecoveryFilter.filterExchange(x)) { @@ -722,7 +754,7 @@ private void recoverExchange(RecordedExchange x, boolean retry) { } catch (Exception cause) { final String message = "Caught an exception while recovering exchange " + x.getName() + ": " + cause.getMessage(); - TopologyRecoveryException e = new TopologyRecoveryException(message, cause); + TopologyRecoveryException e = new TopologyRecoveryException(message, cause, x); this.getExceptionHandler().handleTopologyRecoveryException(delegate, x.getDelegateChannel(), e); } } @@ -766,12 +798,12 @@ public void recoverQueue(final String oldName, RecordedQueue q, boolean retry) { } catch (Exception cause) { final String message = "Caught an exception while recovering queue " + oldName + ": " + cause.getMessage(); - TopologyRecoveryException e = new TopologyRecoveryException(message, cause); + TopologyRecoveryException e = new TopologyRecoveryException(message, cause, q); this.getExceptionHandler().handleTopologyRecoveryException(delegate, q.getDelegateChannel(), e); } } - private void recoverBinding(RecordedBinding b, boolean retry) { + public void recoverBinding(RecordedBinding b, boolean retry) { try { if (this.topologyRecoveryFilter.filterBinding(b)) { if (retry) { @@ -788,7 +820,7 @@ private void recoverBinding(RecordedBinding b, boolean retry) { } catch (Exception cause) { String message = "Caught an exception while recovering binding between " + b.getSource() + " and " + b.getDestination() + ": " + cause.getMessage(); - TopologyRecoveryException e = new TopologyRecoveryException(message, cause); + TopologyRecoveryException e = new TopologyRecoveryException(message, cause, b); this.getExceptionHandler().handleTopologyRecoveryException(delegate, b.getDelegateChannel(), e); } } @@ -800,7 +832,7 @@ public void recoverConsumer(final String tag, RecordedConsumer consumer, boolean String newTag = null; if (retry) { final RecordedConsumer entity = consumer; - RetryResult retryResult = wrapRetryIfNecessary(consumer, () -> entity.recover()); + RetryResult retryResult = wrapRetryIfNecessary(consumer, entity::recover); consumer = (RecordedConsumer) retryResult.getRecordedEntity(); newTag = (String) retryResult.getResult(); } else { @@ -824,7 +856,7 @@ public void recoverConsumer(final String tag, RecordedConsumer consumer, boolean } catch (Exception cause) { final String message = "Caught an exception while recovering consumer " + tag + ": " + cause.getMessage(); - TopologyRecoveryException e = new TopologyRecoveryException(message, cause); + TopologyRecoveryException e = new TopologyRecoveryException(message, cause, consumer); this.getExceptionHandler().handleTopologyRecoveryException(delegate, consumer.getDelegateChannel(), e); } } @@ -889,14 +921,10 @@ private void recoverEntitiesAsynchronously(ExecutorService executor, Collection< private List> groupEntitiesByChannel(final Collection entities) { // map entities by channel - final Map> map = new LinkedHashMap>(); + final Map> map = new LinkedHashMap<>(); for (final E entity : entities) { final AutorecoveringChannel channel = entity.getChannel(); - List list = map.get(channel); - if (list == null) { - map.put(channel, list = new ArrayList()); - } - list.add(entity); + map.computeIfAbsent(channel, c -> new ArrayList<>()).add(entity); } // now create a runnable per channel final List> callables = new ArrayList<>(); @@ -1083,7 +1111,7 @@ boolean hasMoreConsumersOnQueue(Collection consumers, String q } Set removeBindingsWithDestination(String s) { - final Set result = new HashSet(); + final Set result = new LinkedHashSet<>(); synchronized (this.recordedBindings) { for (Iterator it = this.recordedBindings.iterator(); it.hasNext(); ) { RecordedBinding b = it.next(); diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java b/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java index dc55fc7ed4..2e2890c05b 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java @@ -40,19 +40,19 @@ public class DefaultRetryHandler implements RetryHandler { private static final Logger LOGGER = LoggerFactory.getLogger(DefaultRetryHandler.class); - private final BiPredicate queueRecoveryRetryCondition; - private final BiPredicate exchangeRecoveryRetryCondition; - private final BiPredicate bindingRecoveryRetryCondition; - private final BiPredicate consumerRecoveryRetryCondition; + protected final BiPredicate queueRecoveryRetryCondition; + protected final BiPredicate exchangeRecoveryRetryCondition; + protected final BiPredicate bindingRecoveryRetryCondition; + protected final BiPredicate consumerRecoveryRetryCondition; - private final RetryOperation queueRecoveryRetryOperation; - private final RetryOperation exchangeRecoveryRetryOperation; - private final RetryOperation bindingRecoveryRetryOperation; - private final RetryOperation consumerRecoveryRetryOperation; + protected final RetryOperation queueRecoveryRetryOperation; + protected final RetryOperation exchangeRecoveryRetryOperation; + protected final RetryOperation bindingRecoveryRetryOperation; + protected final RetryOperation consumerRecoveryRetryOperation; - private final int retryAttempts; + protected final int retryAttempts; - private final BackoffPolicy backoffPolicy; + protected final BackoffPolicy backoffPolicy; public DefaultRetryHandler(BiPredicate queueRecoveryRetryCondition, BiPredicate exchangeRecoveryRetryCondition, diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryHandlerBuilder.java b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryHandlerBuilder.java index bed71f9f0b..b8dfdff7bc 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryHandlerBuilder.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryHandlerBuilder.java @@ -30,19 +30,19 @@ */ public class TopologyRecoveryRetryHandlerBuilder { - private BiPredicate queueRecoveryRetryCondition = (q, e) -> false; - private BiPredicate exchangeRecoveryRetryCondition = (ex, e) -> false; - private BiPredicate bindingRecoveryRetryCondition = (b, e) -> false; - private BiPredicate consumerRecoveryRetryCondition = (c, e) -> false; + protected BiPredicate queueRecoveryRetryCondition = (q, e) -> false; + protected BiPredicate exchangeRecoveryRetryCondition = (ex, e) -> false; + protected BiPredicate bindingRecoveryRetryCondition = (b, e) -> false; + protected BiPredicate consumerRecoveryRetryCondition = (c, e) -> false; - private DefaultRetryHandler.RetryOperation queueRecoveryRetryOperation = context -> null; - private DefaultRetryHandler.RetryOperation exchangeRecoveryRetryOperation = context -> null; - private DefaultRetryHandler.RetryOperation bindingRecoveryRetryOperation = context -> null; - private DefaultRetryHandler.RetryOperation consumerRecoveryRetryOperation = context -> null; + protected DefaultRetryHandler.RetryOperation queueRecoveryRetryOperation = context -> null; + protected DefaultRetryHandler.RetryOperation exchangeRecoveryRetryOperation = context -> null; + protected DefaultRetryHandler.RetryOperation bindingRecoveryRetryOperation = context -> null; + protected DefaultRetryHandler.RetryOperation consumerRecoveryRetryOperation = context -> null; - private int retryAttempts = 2; + protected int retryAttempts = 2; - private BackoffPolicy backoffPolicy = nbAttempts -> { + protected BackoffPolicy backoffPolicy = nbAttempts -> { }; public static TopologyRecoveryRetryHandlerBuilder builder() { diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java index 94c347f7fa..f379fffef1 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java @@ -55,6 +55,18 @@ public abstract class TopologyRecoveryRetryLogic { } return null; }; + + /** + * Recover a queue + */ + public static final DefaultRetryHandler.RetryOperation RECOVER_QUEUE = context -> { + if (context.entity() instanceof RecordedQueue) { + final RecordedQueue recordedQueue = context.queue(); + AutorecoveringConnection connection = context.connection(); + connection.recoverQueue(recordedQueue.getName(), recordedQueue, false); + } + return null; + }; /** * Recover the destination queue of a binding. @@ -138,18 +150,52 @@ public abstract class TopologyRecoveryRetryLogic { * Recover a consumer. */ public static final DefaultRetryHandler.RetryOperation RECOVER_CONSUMER = context -> context.consumer().recover(); + + /** + * Recover earlier consumers that share the same channel as this retry context + */ + public static final DefaultRetryHandler.RetryOperation RECOVER_PREVIOUS_CONSUMERS = context -> { + if (context.entity() instanceof RecordedConsumer) { + // recover all consumers for the same channel that were recovered before this current + // consumer. need to do this incase some consumers had already been recovered + // successfully on a different queue before this one failed + final AutorecoveringChannel channel = context.consumer().getChannel(); + for (RecordedConsumer consumer : Utility.copy(context.connection().getRecordedConsumers()).values()) { + if (consumer == context.entity()) { + break; + } else if (consumer.getChannel() == channel) { + final RetryContext retryContext = new RetryContext(consumer, context.exception(), context.connection()); + RECOVER_CONSUMER_QUEUE.call(retryContext); + consumer.recover(); + RECOVER_CONSUMER_QUEUE_BINDINGS.call(retryContext); + } + } + } + return null; + }; /** * Pre-configured {@link TopologyRecoveryRetryHandlerBuilder} that retries recovery of bindings and consumers * when their respective queue is not found. + * * This retry handler can be useful for long recovery processes, whereby auto-delete queues * can be deleted between queue recovery and binding/consumer recovery. + * + * Also useful to retry channel-closed 404 errors that may arise with auto-delete queues during a cluster cycle. */ public static final TopologyRecoveryRetryHandlerBuilder RETRY_ON_QUEUE_NOT_FOUND_RETRY_HANDLER = builder() + .queueRecoveryRetryCondition(CHANNEL_CLOSED_NOT_FOUND) .bindingRecoveryRetryCondition(CHANNEL_CLOSED_NOT_FOUND) .consumerRecoveryRetryCondition(CHANNEL_CLOSED_NOT_FOUND) - .bindingRecoveryRetryOperation(RECOVER_CHANNEL.andThen(RECOVER_BINDING_QUEUE).andThen(RECOVER_BINDING) + .queueRecoveryRetryOperation(RECOVER_CHANNEL + .andThen(RECOVER_QUEUE)) + .bindingRecoveryRetryOperation(RECOVER_CHANNEL + .andThen(RECOVER_BINDING_QUEUE) + .andThen(RECOVER_BINDING) .andThen(RECOVER_PREVIOUS_QUEUE_BINDINGS)) - .consumerRecoveryRetryOperation(RECOVER_CHANNEL.andThen(RECOVER_CONSUMER_QUEUE.andThen(RECOVER_CONSUMER) - .andThen(RECOVER_CONSUMER_QUEUE_BINDINGS))); + .consumerRecoveryRetryOperation(RECOVER_CHANNEL + .andThen(RECOVER_CONSUMER_QUEUE) + .andThen(RECOVER_CONSUMER) + .andThen(RECOVER_CONSUMER_QUEUE_BINDINGS) + .andThen(RECOVER_PREVIOUS_CONSUMERS)); } From 2d988ee5b30ad68745b8fb74b475553ea1c97549 Mon Sep 17 00:00:00 2001 From: Michael Dent Date: Fri, 2 Apr 2021 09:15:56 -0500 Subject: [PATCH 1388/2114] consumer recovery needs to return the new consumer tag --- .../client/impl/recovery/TopologyRecoveryRetryLogic.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java index b93ba7a647..f947d2fd4f 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java @@ -165,10 +165,11 @@ public abstract class TopologyRecoveryRetryLogic { } else if (consumer.getChannel() == channel) { final RetryContext retryContext = new RetryContext(consumer, context.exception(), context.connection()); RECOVER_CONSUMER_QUEUE.call(retryContext); - consumer.recover(); + context.connection().recoverConsumer(consumer.getConsumerTag(), consumer, false); RECOVER_CONSUMER_QUEUE_BINDINGS.call(retryContext); } } + return context.consumer().getConsumerTag(); } return null; }; From 59223780692154606d992ce625ac19794c698264 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 2 Apr 2021 18:08:37 +0300 Subject: [PATCH 1389/2114] Merge pull request #680 from vikinghawk/consumerRecoveryRetryFix consumer recovery retry needs to return the new consumer tag (cherry picked from commit 9b7baa871c692d8b55a0e828cfedbbe1a0815563) --- .../client/impl/recovery/TopologyRecoveryRetryLogic.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java index f379fffef1..28a8f3cb99 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java @@ -166,10 +166,11 @@ public abstract class TopologyRecoveryRetryLogic { } else if (consumer.getChannel() == channel) { final RetryContext retryContext = new RetryContext(consumer, context.exception(), context.connection()); RECOVER_CONSUMER_QUEUE.call(retryContext); - consumer.recover(); + context.connection().recoverConsumer(consumer.getConsumerTag(), consumer, false); RECOVER_CONSUMER_QUEUE_BINDINGS.call(retryContext); } } + return context.consumer().getConsumerTag(); } return null; }; From cc759a922ddd2d98289289b908997f26d5e83ceb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 6 Apr 2021 08:50:37 +0200 Subject: [PATCH 1390/2114] Bump dependencies Fixes #681 --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 75ec41d552..6f1529671a 100644 --- a/pom.xml +++ b/pom.xml @@ -55,9 +55,9 @@ UTF-8 1.7.30 - 4.1.17 - 1.6.3 - 2.12.1 + 4.1.18 + 1.6.5 + 2.12.2 1.2.3 4.13.2 3.7.7 From ca0b059da2ce0a4927413ae1532473d39bc6a40e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 6 Apr 2021 08:51:29 +0200 Subject: [PATCH 1391/2114] Bump test dependencies --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 6f1529671a..8eb52420f1 100644 --- a/pom.xml +++ b/pom.xml @@ -60,9 +60,9 @@ 2.12.2 1.2.3 4.13.2 - 3.7.7 + 3.8.0 3.19.0 - 9.4.36.v20210114 + 9.4.39.v20210325 1.68 3.2.0 From c5dfe559aed5163a785e78c94b55c826f1f17a60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 6 Apr 2021 08:50:37 +0200 Subject: [PATCH 1392/2114] Bump dependencies Fixes #681 (cherry picked from commit cc759a922ddd2d98289289b908997f26d5e83ceb) --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 9e8c3dcb1d..b6ea067b42 100644 --- a/pom.xml +++ b/pom.xml @@ -55,9 +55,9 @@ UTF-8 1.7.30 - 4.1.17 - 1.6.3 - 2.12.1 + 4.1.18 + 1.6.5 + 2.12.2 1.2.3 4.13.2 3.7.7 From c46b6b0cd490b772ebe9263adc40ac03900c5ffb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 6 Apr 2021 08:51:29 +0200 Subject: [PATCH 1393/2114] Bump test dependencies (cherry picked from commit ca0b059da2ce0a4927413ae1532473d39bc6a40e) --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index b6ea067b42..72929ae352 100644 --- a/pom.xml +++ b/pom.xml @@ -60,9 +60,9 @@ 2.12.2 1.2.3 4.13.2 - 3.7.7 + 3.8.0 3.19.0 - 9.4.36.v20210114 + 9.4.39.v20210325 1.68 3.2.0 From 4407bfa41edfd1982e408bb44c0dcc1d6acd0000 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Tue, 6 Apr 2021 11:29:35 +0000 Subject: [PATCH 1394/2114] [maven-release-plugin] prepare release v5.12.0.RC1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 72929ae352..ec71b3a5ca 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.12.0-SNAPSHOT + 5.12.0.RC1 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v5.12.0.RC1 From 7ddb1ddf78919f00807c4f38fe0b721a3dc235f3 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Tue, 6 Apr 2021 11:29:38 +0000 Subject: [PATCH 1395/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index ec71b3a5ca..72929ae352 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.12.0.RC1 + 5.12.0-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v5.12.0.RC1 + HEAD From 9020188119c90aebcdebcbfa71811d6962c877ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 6 Apr 2021 13:49:45 +0200 Subject: [PATCH 1396/2114] Set release version to 5.12.0.RC2 --- release-versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-versions.txt b/release-versions.txt index 7c74c0e65d..f74d8c8579 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,3 +1,3 @@ -RELEASE_VERSION="5.12.0.RC1" +RELEASE_VERSION="5.12.0.RC2" DEVELOPMENT_VERSION="5.12.0-SNAPSHOT" RELEASE_BRANCH="5.x.x-stable" From e0a00aec06462c6b2a1473bb40eba1faed322be3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 7 Apr 2021 17:41:13 +0200 Subject: [PATCH 1397/2114] Bump mockito --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8eb52420f1..f650c7747b 100644 --- a/pom.xml +++ b/pom.xml @@ -60,7 +60,7 @@ 2.12.2 1.2.3 4.13.2 - 3.8.0 + 3.9.0 3.19.0 9.4.39.v20210325 1.68 From d3a74633822268080b67cf0745f65601a78f6c5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 7 Apr 2021 17:41:13 +0200 Subject: [PATCH 1398/2114] Bump mockito (cherry picked from commit e0a00aec06462c6b2a1473bb40eba1faed322be3) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 72929ae352..a41a16e2cb 100644 --- a/pom.xml +++ b/pom.xml @@ -60,7 +60,7 @@ 2.12.2 1.2.3 4.13.2 - 3.8.0 + 3.9.0 3.19.0 9.4.39.v20210325 1.68 From 079c2c866f2f3e82cdd8c1a64f0d94e4283cd640 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 9 Apr 2021 08:41:35 +0200 Subject: [PATCH 1399/2114] Set release version to 5.12.0 --- release-versions.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release-versions.txt b/release-versions.txt index f74d8c8579..60a3b95880 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,3 +1,3 @@ -RELEASE_VERSION="5.12.0.RC2" -DEVELOPMENT_VERSION="5.12.0-SNAPSHOT" +RELEASE_VERSION="5.12.0" +DEVELOPMENT_VERSION="5.13.0-SNAPSHOT" RELEASE_BRANCH="5.x.x-stable" From a969598816bcc39a56bfa6b5cb4bf9fc549cfc50 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Fri, 9 Apr 2021 06:44:12 +0000 Subject: [PATCH 1400/2114] [maven-release-plugin] prepare release v5.12.0 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index a41a16e2cb..2eb5bf8db8 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.12.0-SNAPSHOT + 5.12.0 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v5.12.0 From 3731fb1b56746a5ba9db27deb4968407d9b21c26 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Fri, 9 Apr 2021 06:44:15 +0000 Subject: [PATCH 1401/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 2eb5bf8db8..56e1e85742 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.12.0 + 5.13.0-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v5.12.0 + HEAD From 08c0761cde7ead0d3faa183aa78da1d695cc1106 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 9 Apr 2021 08:53:42 +0200 Subject: [PATCH 1402/2114] Set release version to 5.13.0.RC1 --- release-versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-versions.txt b/release-versions.txt index 60a3b95880..6444570f66 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,3 +1,3 @@ -RELEASE_VERSION="5.12.0" +RELEASE_VERSION="5.13.0.RC1" DEVELOPMENT_VERSION="5.13.0-SNAPSHOT" RELEASE_BRANCH="5.x.x-stable" From e80b98c59e7aef483f3f2d92e5e9426f2713727c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 9 Apr 2021 09:10:06 +0200 Subject: [PATCH 1403/2114] Use 5.12.0 in readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 16cf3e80f5..ba44586dee 100644 --- a/README.md +++ b/README.md @@ -25,14 +25,14 @@ They require Java 8 or higher. com.rabbitmq amqp-client - 5.11.0 + 5.12.0 ``` ### Gradle ``` groovy -compile 'com.rabbitmq:amqp-client:5.11.0' +compile 'com.rabbitmq:amqp-client:5.12.0' ``` #### 4.x Series From 28fa4db06324c4ece1d512bfe674df106e75a7a8 Mon Sep 17 00:00:00 2001 From: Lauri Oherd Date: Wed, 14 Apr 2021 10:26:46 +0300 Subject: [PATCH 1404/2114] fix typo in ForgivingExceptionHandler.java fix a minor typo --- .../com/rabbitmq/client/impl/ForgivingExceptionHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/impl/ForgivingExceptionHandler.java b/src/main/java/com/rabbitmq/client/impl/ForgivingExceptionHandler.java index 8a7d790382..1c99f0a390 100644 --- a/src/main/java/com/rabbitmq/client/impl/ForgivingExceptionHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/ForgivingExceptionHandler.java @@ -33,7 +33,7 @@ public class ForgivingExceptionHandler implements ExceptionHandler { @Override public void handleUnexpectedConnectionDriverException(Connection conn, Throwable exception) { - log("An unexpected connection driver error occured", exception); + log("An unexpected connection driver error occurred", exception); } @Override From 21a77a62c6859808d128767aaa2b25850dd4caf2 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Wed, 14 Apr 2021 15:31:12 +0300 Subject: [PATCH 1405/2114] Merge pull request #682 from laurio/patch-1 fix typo in ForgivingExceptionHandler.java (cherry picked from commit 05a87e1cb8f7dc587c26243131896822f983e277) --- .../com/rabbitmq/client/impl/ForgivingExceptionHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/impl/ForgivingExceptionHandler.java b/src/main/java/com/rabbitmq/client/impl/ForgivingExceptionHandler.java index 8a7d790382..1c99f0a390 100644 --- a/src/main/java/com/rabbitmq/client/impl/ForgivingExceptionHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/ForgivingExceptionHandler.java @@ -33,7 +33,7 @@ public class ForgivingExceptionHandler implements ExceptionHandler { @Override public void handleUnexpectedConnectionDriverException(Connection conn, Throwable exception) { - log("An unexpected connection driver error occured", exception); + log("An unexpected connection driver error occurred", exception); } @Override From 8b37859321ae8102c42be3c66f1b1aa7e06a3abf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 19 Apr 2021 14:53:23 +0200 Subject: [PATCH 1406/2114] Bump optional dependencies References #683 --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index f650c7747b..fdf8fd287f 100644 --- a/pom.xml +++ b/pom.xml @@ -55,9 +55,9 @@ UTF-8 1.7.30 - 4.1.18 - 1.6.5 - 2.12.2 + 4.1.19 + 1.6.6 + 2.12.3 1.2.3 4.13.2 3.9.0 From b7fe5206f8e1163c3b41484a5b30ee738ac48bc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 19 Apr 2021 14:54:34 +0200 Subject: [PATCH 1407/2114] Bump test dependency --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index fdf8fd287f..43f4479529 100644 --- a/pom.xml +++ b/pom.xml @@ -62,7 +62,7 @@ 4.13.2 3.9.0 3.19.0 - 9.4.39.v20210325 + 9.4.40.v20210413 1.68 3.2.0 From c5bfe2d89449580f63b8ae9299d205a9f6fa9f63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 19 Apr 2021 14:53:23 +0200 Subject: [PATCH 1408/2114] Bump optional dependencies References #683 (cherry picked from commit 8b37859321ae8102c42be3c66f1b1aa7e06a3abf) --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 56e1e85742..831e088764 100644 --- a/pom.xml +++ b/pom.xml @@ -55,9 +55,9 @@ UTF-8 1.7.30 - 4.1.18 - 1.6.5 - 2.12.2 + 4.1.19 + 1.6.6 + 2.12.3 1.2.3 4.13.2 3.9.0 From d0fd731908a17719b5d8a97abdce59acfc6e103d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 19 Apr 2021 14:54:34 +0200 Subject: [PATCH 1409/2114] Bump test dependency (cherry picked from commit b7fe5206f8e1163c3b41484a5b30ee738ac48bc5) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 831e088764..447e8aafa7 100644 --- a/pom.xml +++ b/pom.xml @@ -62,7 +62,7 @@ 4.13.2 3.9.0 3.19.0 - 9.4.39.v20210325 + 9.4.40.v20210413 1.68 3.2.0 From 8ccbc13a442f0a8e9f269e45d2a1406215fcae46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 29 Apr 2021 17:24:47 +0200 Subject: [PATCH 1410/2114] Bump metrics References #683 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 43f4479529..e895eb8c6c 100644 --- a/pom.xml +++ b/pom.xml @@ -55,7 +55,7 @@ UTF-8 1.7.30 - 4.1.19 + 4.1.20 1.6.6 2.12.3 1.2.3 From a3470e91c534ba4c10c1e0364afc9d8c004dfbe1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 29 Apr 2021 17:24:47 +0200 Subject: [PATCH 1411/2114] Bump metrics References #683 (cherry picked from commit 8ccbc13a442f0a8e9f269e45d2a1406215fcae46) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 447e8aafa7..985478d5eb 100644 --- a/pom.xml +++ b/pom.xml @@ -55,7 +55,7 @@ UTF-8 1.7.30 - 4.1.19 + 4.1.20 1.6.6 2.12.3 1.2.3 From 518f6db5054c6ae62173c4fedcd0fd39c76a8fdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 7 May 2021 14:27:44 +0200 Subject: [PATCH 1412/2114] Bump metrics References #683 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e895eb8c6c..3a794a204b 100644 --- a/pom.xml +++ b/pom.xml @@ -55,7 +55,7 @@ UTF-8 1.7.30 - 4.1.20 + 4.1.21 1.6.6 2.12.3 1.2.3 From 19bd212dcd61c8ca28b3df02e8fefaf327298739 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 7 May 2021 14:27:44 +0200 Subject: [PATCH 1413/2114] Bump metrics References #683 (cherry picked from commit 518f6db5054c6ae62173c4fedcd0fd39c76a8fdf) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 985478d5eb..7b233380d7 100644 --- a/pom.xml +++ b/pom.xml @@ -55,7 +55,7 @@ UTF-8 1.7.30 - 4.1.20 + 4.1.21 1.6.6 2.12.3 1.2.3 From f2853a394acda365ef5fc0d90e75d7cce03f014d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 17 May 2021 09:15:06 +0200 Subject: [PATCH 1414/2114] Bump dependencies References #683 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 3a794a204b..c75f68b313 100644 --- a/pom.xml +++ b/pom.xml @@ -55,8 +55,8 @@ UTF-8 1.7.30 - 4.1.21 - 1.6.6 + 4.2.0 + 1.7.0 2.12.3 1.2.3 4.13.2 From e3ae28cd3e8aa8bf9a487a352fac561586fff367 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 17 May 2021 09:15:52 +0200 Subject: [PATCH 1415/2114] Bump Mockito --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c75f68b313..5ad5a5ab35 100644 --- a/pom.xml +++ b/pom.xml @@ -60,7 +60,7 @@ 2.12.3 1.2.3 4.13.2 - 3.9.0 + 3.10.0 3.19.0 9.4.40.v20210413 1.68 From c52f2f07e488b038ab9412efb2a7b83b802835e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 17 May 2021 09:15:06 +0200 Subject: [PATCH 1416/2114] Bump dependencies References #683 (cherry picked from commit f2853a394acda365ef5fc0d90e75d7cce03f014d) --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 7b233380d7..e9dbd1c121 100644 --- a/pom.xml +++ b/pom.xml @@ -55,8 +55,8 @@ UTF-8 1.7.30 - 4.1.21 - 1.6.6 + 4.2.0 + 1.7.0 2.12.3 1.2.3 4.13.2 From 339ca7279a158b318722e3882fdf6de2cc568aab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 17 May 2021 09:15:52 +0200 Subject: [PATCH 1417/2114] Bump Mockito (cherry picked from commit e3ae28cd3e8aa8bf9a487a352fac561586fff367) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e9dbd1c121..e54a1336b0 100644 --- a/pom.xml +++ b/pom.xml @@ -60,7 +60,7 @@ 2.12.3 1.2.3 4.13.2 - 3.9.0 + 3.10.0 3.19.0 9.4.40.v20210413 1.68 From cc7c86773e439d4244cf1a6a6be3ef9bf86be44e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 17 May 2021 10:07:54 +0200 Subject: [PATCH 1418/2114] Fix TLS configuration for Java 13.0.7 --- ...CredentialsGrantCredentialsProviderTest.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java b/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java index bcf96c7f1c..0a08125d8f 100644 --- a/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java +++ b/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java @@ -28,6 +28,7 @@ import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.util.ssl.SslContextFactory; import org.junit.After; +import org.junit.Before; import org.junit.Test; import javax.net.ssl.SSLContext; @@ -56,8 +57,24 @@ public class OAuth2ClientCredentialsGrantCredentialsProviderTest { Server server; + static boolean isJava13() { + String javaVersion = System.getProperty("java.version"); + return javaVersion != null && javaVersion.startsWith("13."); + } + + @Before + public void init() { + if (isJava13()) { + // for Java 13.0.7, see https://github.com/bcgit/bc-java/issues/941 + System.setProperty("keystore.pkcs12.keyProtectionAlgorithm", "PBEWithHmacSHA256AndAES_256"); + } + } + @After public void tearDown() throws Exception { + if (isJava13()) { + System.setProperty("keystore.pkcs12.keyProtectionAlgorithm", ""); + } if (server != null) { server.stop(); } From c76be10eeab9e76e597d81bb36ce59c851ad51f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 17 May 2021 10:07:54 +0200 Subject: [PATCH 1419/2114] Fix TLS configuration for Java 13.0.7 (cherry picked from commit cc7c86773e439d4244cf1a6a6be3ef9bf86be44e) --- ...CredentialsGrantCredentialsProviderTest.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java b/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java index bcf96c7f1c..0a08125d8f 100644 --- a/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java +++ b/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java @@ -28,6 +28,7 @@ import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.util.ssl.SslContextFactory; import org.junit.After; +import org.junit.Before; import org.junit.Test; import javax.net.ssl.SSLContext; @@ -56,8 +57,24 @@ public class OAuth2ClientCredentialsGrantCredentialsProviderTest { Server server; + static boolean isJava13() { + String javaVersion = System.getProperty("java.version"); + return javaVersion != null && javaVersion.startsWith("13."); + } + + @Before + public void init() { + if (isJava13()) { + // for Java 13.0.7, see https://github.com/bcgit/bc-java/issues/941 + System.setProperty("keystore.pkcs12.keyProtectionAlgorithm", "PBEWithHmacSHA256AndAES_256"); + } + } + @After public void tearDown() throws Exception { + if (isJava13()) { + System.setProperty("keystore.pkcs12.keyProtectionAlgorithm", ""); + } if (server != null) { server.stop(); } From 4dde118ff77b5e210e5569db15b4cc757800d92b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 7 Jun 2021 15:08:29 +0200 Subject: [PATCH 1420/2114] Bump test dependencies --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 5ad5a5ab35..cd3910c836 100644 --- a/pom.xml +++ b/pom.xml @@ -60,9 +60,9 @@ 2.12.3 1.2.3 4.13.2 - 3.10.0 + 3.11.0 3.19.0 - 9.4.40.v20210413 + 9.4.41.v20210516 1.68 3.2.0 From d7d100ab5e308c6090ddb5cb0e95979b99c632a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 7 Jun 2021 15:08:29 +0200 Subject: [PATCH 1421/2114] Bump test dependencies (cherry picked from commit 4dde118ff77b5e210e5569db15b4cc757800d92b) --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index e54a1336b0..9ac502476c 100644 --- a/pom.xml +++ b/pom.xml @@ -60,9 +60,9 @@ 2.12.3 1.2.3 4.13.2 - 3.10.0 + 3.11.0 3.19.0 - 9.4.40.v20210413 + 9.4.41.v20210516 1.68 3.2.0 From 39fe12273feef0f0e18b221628fae60a780cce26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 14 Jun 2021 10:13:58 +0200 Subject: [PATCH 1422/2114] Bump test dependencies --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index cd3910c836..f0ed3a8791 100644 --- a/pom.xml +++ b/pom.xml @@ -60,10 +60,10 @@ 2.12.3 1.2.3 4.13.2 - 3.11.0 + 3.11.1 3.19.0 - 9.4.41.v20210516 - 1.68 + 9.4.42.v20210604 + 1.69 3.2.0 2.5.3 From ecbc577846b1a3f8ff1c56d590b6e68014ead86e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 14 Jun 2021 10:13:58 +0200 Subject: [PATCH 1423/2114] Bump test dependencies (cherry picked from commit 39fe12273feef0f0e18b221628fae60a780cce26) --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 9ac502476c..eb91c16cf6 100644 --- a/pom.xml +++ b/pom.xml @@ -60,10 +60,10 @@ 2.12.3 1.2.3 4.13.2 - 3.11.0 + 3.11.1 3.19.0 - 9.4.41.v20210516 - 1.68 + 9.4.42.v20210604 + 1.69 3.2.0 2.5.3 From a4e76fb49e8b7676e4ba4ab3acb2e95a9282de38 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Sun, 20 Jun 2021 10:35:47 +0800 Subject: [PATCH 1424/2114] Move resolved address shuffling to AddressResolver so that it can be overridden by implementations, e.g. to perform no shuffling at all. References #690. --- src/main/java/com/rabbitmq/client/AddressResolver.java | 7 +++++++ .../impl/recovery/RecoveryAwareAMQConnectionFactory.java | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/AddressResolver.java b/src/main/java/com/rabbitmq/client/AddressResolver.java index 8350bac153..2451912845 100644 --- a/src/main/java/com/rabbitmq/client/AddressResolver.java +++ b/src/main/java/com/rabbitmq/client/AddressResolver.java @@ -16,6 +16,8 @@ package com.rabbitmq.client; import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; /** @@ -30,4 +32,9 @@ public interface AddressResolver { */ List
getAddresses() throws IOException; + default List
maybeShuffle(List
input) { + List
list = new ArrayList
(input); + Collections.shuffle(list); + return list; + } } diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java index ab23cc4494..6c1b56b121 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java @@ -55,7 +55,8 @@ public RecoveryAwareAMQConnectionFactory(ConnectionParams params, FrameHandlerFa // package protected API, made public for testing only public RecoveryAwareAMQConnection newConnection() throws IOException, TimeoutException { Exception lastException = null; - List
shuffled = shuffle(addressResolver.getAddresses()); + List
resolved = addressResolver.getAddresses(); + List
shuffled = addressResolver.maybeShuffle(resolved); for (Address addr : shuffled) { try { From 3415f888fcc4955483c937a76e225403db161488 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 21 Jun 2021 09:08:51 +0200 Subject: [PATCH 1425/2114] Document optional shuffling in AddressResolver References #691. --- .../com/rabbitmq/client/AddressResolver.java | 40 ++++++++++++------- .../RecoveryAwareAMQConnectionFactory.java | 6 --- 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/AddressResolver.java b/src/main/java/com/rabbitmq/client/AddressResolver.java index 2451912845..4a90a8e014 100644 --- a/src/main/java/com/rabbitmq/client/AddressResolver.java +++ b/src/main/java/com/rabbitmq/client/AddressResolver.java @@ -20,21 +20,33 @@ import java.util.Collections; import java.util.List; -/** - * Strategy interface to get the potential servers to connect to. - */ +/** Strategy interface to get the potential servers to connect to. */ public interface AddressResolver { - /** - * Get the potential {@link Address}es to connect to. - * @return candidate {@link Address}es - * @throws IOException if it encounters a problem - */ - List
getAddresses() throws IOException; + /** + * Get the potential {@link Address}es to connect to. + * + * @return candidate {@link Address}es + * @throws IOException if it encounters a problem + */ + List
getAddresses() throws IOException; - default List
maybeShuffle(List
input) { - List
list = new ArrayList
(input); - Collections.shuffle(list); - return list; - } + /** + * Optionally shuffle the list of addresses returned by {@link #getAddresses()}. + * + *

The automatic connection recovery calls this method after {@link #getAddresses()} to pick a + * random address for reconnecting. + * + *

The default method implementation calls {@link Collections#shuffle(List)}. Custom + * implementations can choose to not do any shuffling to have more predictability in the + * reconnection. + * + * @param input + * @return potentially shuffled list of addresses. + */ + default List

maybeShuffle(List
input) { + List
list = new ArrayList
(input); + Collections.shuffle(list); + return list; + } } diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java index 6c1b56b121..0dc677363f 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java @@ -82,12 +82,6 @@ public RecoveryAwareAMQConnection newConnection() throws IOException, TimeoutExc throw new IOException("failed to connect"); } - private static List
shuffle(List
addrs) { - List
list = new ArrayList
(addrs); - Collections.shuffle(list); - return list; - } - protected RecoveryAwareAMQConnection createConnection(ConnectionParams params, FrameHandler handler, MetricsCollector metricsCollector) { return new RecoveryAwareAMQConnection(params, handler, metricsCollector); } From d366c987634d8e2a3ed0a43a8b78e7e365fb14b2 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Sun, 20 Jun 2021 10:35:47 +0800 Subject: [PATCH 1426/2114] Move resolved address shuffling to AddressResolver so that it can be overridden by implementations, e.g. to perform no shuffling at all. References #690. (cherry picked from commit a4e76fb49e8b7676e4ba4ab3acb2e95a9282de38) --- src/main/java/com/rabbitmq/client/AddressResolver.java | 7 +++++++ .../impl/recovery/RecoveryAwareAMQConnectionFactory.java | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/AddressResolver.java b/src/main/java/com/rabbitmq/client/AddressResolver.java index 8350bac153..2451912845 100644 --- a/src/main/java/com/rabbitmq/client/AddressResolver.java +++ b/src/main/java/com/rabbitmq/client/AddressResolver.java @@ -16,6 +16,8 @@ package com.rabbitmq.client; import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; /** @@ -30,4 +32,9 @@ public interface AddressResolver { */ List
getAddresses() throws IOException; + default List
maybeShuffle(List
input) { + List
list = new ArrayList
(input); + Collections.shuffle(list); + return list; + } } diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java index ab23cc4494..6c1b56b121 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java @@ -55,7 +55,8 @@ public RecoveryAwareAMQConnectionFactory(ConnectionParams params, FrameHandlerFa // package protected API, made public for testing only public RecoveryAwareAMQConnection newConnection() throws IOException, TimeoutException { Exception lastException = null; - List
shuffled = shuffle(addressResolver.getAddresses()); + List
resolved = addressResolver.getAddresses(); + List
shuffled = addressResolver.maybeShuffle(resolved); for (Address addr : shuffled) { try { From f04572f79964c5c47dfe2ccfc469b205fb252e68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 21 Jun 2021 09:08:51 +0200 Subject: [PATCH 1427/2114] Document optional shuffling in AddressResolver References #691. (cherry picked from commit 3415f888fcc4955483c937a76e225403db161488) --- .../com/rabbitmq/client/AddressResolver.java | 40 ++++++++++++------- .../RecoveryAwareAMQConnectionFactory.java | 6 --- 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/AddressResolver.java b/src/main/java/com/rabbitmq/client/AddressResolver.java index 2451912845..4a90a8e014 100644 --- a/src/main/java/com/rabbitmq/client/AddressResolver.java +++ b/src/main/java/com/rabbitmq/client/AddressResolver.java @@ -20,21 +20,33 @@ import java.util.Collections; import java.util.List; -/** - * Strategy interface to get the potential servers to connect to. - */ +/** Strategy interface to get the potential servers to connect to. */ public interface AddressResolver { - /** - * Get the potential {@link Address}es to connect to. - * @return candidate {@link Address}es - * @throws IOException if it encounters a problem - */ - List
getAddresses() throws IOException; + /** + * Get the potential {@link Address}es to connect to. + * + * @return candidate {@link Address}es + * @throws IOException if it encounters a problem + */ + List
getAddresses() throws IOException; - default List
maybeShuffle(List
input) { - List
list = new ArrayList
(input); - Collections.shuffle(list); - return list; - } + /** + * Optionally shuffle the list of addresses returned by {@link #getAddresses()}. + * + *

The automatic connection recovery calls this method after {@link #getAddresses()} to pick a + * random address for reconnecting. + * + *

The default method implementation calls {@link Collections#shuffle(List)}. Custom + * implementations can choose to not do any shuffling to have more predictability in the + * reconnection. + * + * @param input + * @return potentially shuffled list of addresses. + */ + default List

maybeShuffle(List
input) { + List
list = new ArrayList
(input); + Collections.shuffle(list); + return list; + } } diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java index 6c1b56b121..0dc677363f 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java @@ -82,12 +82,6 @@ public RecoveryAwareAMQConnection newConnection() throws IOException, TimeoutExc throw new IOException("failed to connect"); } - private static List
shuffle(List
addrs) { - List
list = new ArrayList
(addrs); - Collections.shuffle(list); - return list; - } - protected RecoveryAwareAMQConnection createConnection(ConnectionParams params, FrameHandler handler, MetricsCollector metricsCollector) { return new RecoveryAwareAMQConnection(params, handler, metricsCollector); } From c8a3fa5dcff93947a20d8cd4b52b75c58d87599b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 21 Jun 2021 09:26:05 +0200 Subject: [PATCH 1428/2114] Bump dependencies References #683 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index f0ed3a8791..8d6e392db4 100644 --- a/pom.xml +++ b/pom.xml @@ -54,8 +54,8 @@ UTF-8 UTF-8 - 1.7.30 - 4.2.0 + 1.7.31 + 4.2.1 1.7.0 2.12.3 1.2.3 From e32bcbb2824f7616a13acd5827a87ca92e54f08f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 21 Jun 2021 09:26:49 +0200 Subject: [PATCH 1429/2114] Bump assertj --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8d6e392db4..19fa945be7 100644 --- a/pom.xml +++ b/pom.xml @@ -61,7 +61,7 @@ 1.2.3 4.13.2 3.11.1 - 3.19.0 + 3.20.2 9.4.42.v20210604 1.69 From 60cefd002e3fbc0a2c04a439fce5d32264ae28df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 21 Jun 2021 09:26:05 +0200 Subject: [PATCH 1430/2114] Bump dependencies References #683 (cherry picked from commit c8a3fa5dcff93947a20d8cd4b52b75c58d87599b) --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index eb91c16cf6..e0b76ff6ea 100644 --- a/pom.xml +++ b/pom.xml @@ -54,8 +54,8 @@ UTF-8 UTF-8 - 1.7.30 - 4.2.0 + 1.7.31 + 4.2.1 1.7.0 2.12.3 1.2.3 From b56e8f7367eae6ad14b406f15bca16fcd0d45891 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 21 Jun 2021 09:26:49 +0200 Subject: [PATCH 1431/2114] Bump assertj (cherry picked from commit e32bcbb2824f7616a13acd5827a87ca92e54f08f) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e0b76ff6ea..3bf0a89ff9 100644 --- a/pom.xml +++ b/pom.xml @@ -61,7 +61,7 @@ 1.2.3 4.13.2 3.11.1 - 3.19.0 + 3.20.2 9.4.42.v20210604 1.69 From 22b9a4afb57b329e7d6d14ee64eee8126b50061c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 24 Jun 2021 14:09:02 +0200 Subject: [PATCH 1432/2114] Use main as main branch --- .travis.yml | 57 -------------------------------------------- release-versions.txt | 2 +- 2 files changed, 1 insertion(+), 58 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 4bf2802d96..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,57 +0,0 @@ -# vim:sw=2:et: - -dist: xenial -sudo: false -language: erlang -notifications: - email: - recipients: - - alerts@rabbitmq.com - on_success: never - on_failure: always -addons: - apt: - packages: - - awscli -cache: - apt: true -env: - global: - - secure: Tu26VJ9BsXxL20xxwWk4cbCkZyqyxYmNpSSqco5r3FLeU5hk5Vkk+s2BareRvqKhKHFlvyxu8GwsKtajMvsieP6y5J99gSeub6fDOIskPz61bo0aKA9nbDuBFSG1Z5wgXx1XRo0yDatLxXCXe3FbThRsylG7XNjtRaru1/lwuVxfxPtBGQ1opvQX71sST3GYSPoBYR+JlcVpU+uDHMAzsP8J0m5rEpxcl821aTMk3iz90hBQMsoLTBmSQePPcNqOA/1OH75VfjuXR8JBXHvA9njrUBrsyxgHf2uOh3jAXdIrHZwZg/17+y7gNVqByfx/UpGb8XEpVkncg/cRyVIHMk7/gFCZkeVC1QkIN5+EPiGLF7u32x9QaT7Zqz57iLh3IJzED2dj12qWaeX8QypF1K1r5qq4pRrN6iEZx76stpZbyFT4XnExHRdzPuouy7yz1gDHF0HOxbNLowzc/jk7tuTp+qmDSR5tRvegAIH3TONegxXyB7smdbvdI6MCN5/GP2bGK7HiqYWCmTGHtJwgxBKc5XoV8ZjpXfKxG98WbK5RsSP1miRnmxSbxaV0Gai1hfFlanJFFxTA9584O+NVRXNNFMfnnt20Ts6OwoXTcJ/boIPjF5Mcm0eJ4nz4R18TArXE4B5S4pTk3eQkG1ACDigkYZ3fc6ws4cWrt8BZASI= - - secure: fNEx9OXi2UisiYu0FiHJpV9+vWLB9DIUAIKG24GfUHVgZqFQOInBf5fEYrjlVgm5zNezSBS3hFNHXd/EXJF8KNgbf6mI0z4h4RyyQY98N+78tWvINoIawEeYpgC6NTI52MdaCfV+fTVWhiL0uP7mqWhLmll2bKXIy6HA6I9PnmiQSloNe64vUPF+UsVZHzzeabK4DR2VdI3h+BGXzOY9FG8Kt2voiXOLd2RFpVeN86FDTp+uVZY/K9e/MsktoK+XaZZ4qMAgm6lB32LVkzl3KA9ki6y6BY7le1m2c90hxAtBJGWZptkMb+VL0Fem39nEBnLjE0a0vIddp32PLJQmv6eopMfLay5BIkwtkRwv3P0uCwYd0bgYQSHF/gdTCcK1nr7fMhkQveBh6vmnbhrca7OeQRHz08+jo6EquUgNQZKmTZPWXQn9lS9mU/0EDLJJhn4KhJezGw6DcAAqB0KqmQedxtHMUT87by7LzhINwKZnm4y5WKA/W/zLI6dNqvIgc5C6UJh0EVgxa13GRmrnGmttV1dtLRQhiMJCbJykaekjPMULUmli0RbFz7bSFqFqEUsF+wwovyD+Y6D8KGOJdvvEYPdPIFpRPnhGUvH86JzsFdVKNJBicGI9LpCtlXlWNRbQIQ8uV5ze2HhxSJhtM6e6dB4d9yzpp6a81uR77bk= - -otp_release: - - "20.3" - - "21.3" - -before_script: - - elixir --version - # The checkout made by Travis is a "detached HEAD" and branches - # information is missing. Our Erlang.mk's git_rmq fetch method relies - # on it, so we need to restore it. - # - # We simply fetch master and, if it exists, v3.7.x branches. A branch - # is created, pointing to the detached HEAD. - - | - git checkout -B "${TRAVIS_TAG:-${TRAVIS_BRANCH}}" - git remote add upstream https://github.com/$TRAVIS_REPO_SLUG.git - git fetch upstream v3.7.x:v3.7.x || : - git fetch upstream master:master || : - -script: - - make xref - - make tests - -after_failure: - - | - cd "$TRAVIS_BUILD_DIR" - if test -d logs && test "$AWS_ACCESS_KEY_ID" && test "$AWS_SECRET_ACCESS_KEY"; then - archive_name="$(basename "$TRAVIS_REPO_SLUG")-$TRAVIS_JOB_NUMBER" - - tar -c --transform "s/^logs/${archive_name}/" -f - logs | \ - xz > "${archive_name}.tar.xz" - - aws s3 cp "${archive_name}.tar.xz" s3://server-release-pipeline/travis-ci-logs/ \ - --region eu-west-1 \ - --acl public-read - fi diff --git a/release-versions.txt b/release-versions.txt index 9f435a6f93..8a9d479d3a 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,3 +1,3 @@ RELEASE_VERSION="6.0.0.M2" DEVELOPMENT_VERSION="6.0.0-SNAPSHOT" -RELEASE_BRANCH="master" +RELEASE_BRANCH="main" From 3841e6bcd572dc1d5137d032b8f4caee4c6099bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 24 Jun 2021 15:08:57 +0200 Subject: [PATCH 1433/2114] Bump dependencies References #683 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 19fa945be7..69e2222b9b 100644 --- a/pom.xml +++ b/pom.xml @@ -55,8 +55,8 @@ UTF-8 1.7.31 - 4.2.1 - 1.7.0 + 4.2.2 + 1.7.1 2.12.3 1.2.3 4.13.2 From 83d5fc35070931cf71e4606c67cfd4c5d30cf31d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 24 Jun 2021 15:09:36 +0200 Subject: [PATCH 1434/2114] Bump Mockito to 3.11.2 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 69e2222b9b..75b98ea911 100644 --- a/pom.xml +++ b/pom.xml @@ -60,7 +60,7 @@ 2.12.3 1.2.3 4.13.2 - 3.11.1 + 3.11.2 3.20.2 9.4.42.v20210604 1.69 From 1f8ddcce84c150d18e22362493659d599718cf86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 24 Jun 2021 15:08:57 +0200 Subject: [PATCH 1435/2114] Bump dependencies References #683 (cherry picked from commit 3841e6bcd572dc1d5137d032b8f4caee4c6099bf) --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 3bf0a89ff9..ac3f52f7cc 100644 --- a/pom.xml +++ b/pom.xml @@ -55,8 +55,8 @@ UTF-8 1.7.31 - 4.2.1 - 1.7.0 + 4.2.2 + 1.7.1 2.12.3 1.2.3 4.13.2 From e935a34a5072dd5efaa20b569dc2dd88e6350bcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 24 Jun 2021 15:09:36 +0200 Subject: [PATCH 1436/2114] Bump Mockito to 3.11.2 (cherry picked from commit 83d5fc35070931cf71e4606c67cfd4c5d30cf31d) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ac3f52f7cc..f9c92a513d 100644 --- a/pom.xml +++ b/pom.xml @@ -60,7 +60,7 @@ 2.12.3 1.2.3 4.13.2 - 3.11.1 + 3.11.2 3.20.2 9.4.42.v20210604 1.69 From 11204feb0c0cdd7997477ccbf04673c79a5f98b3 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Wed, 30 Jun 2021 07:44:09 +0000 Subject: [PATCH 1437/2114] [maven-release-plugin] prepare release v5.13.0.RC1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index f9c92a513d..8a563cc01e 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.13.0-SNAPSHOT + 5.13.0.RC1 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v5.13.0.RC1 From 2bc3e555520df81d30ceba203ee8170ab3498413 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Wed, 30 Jun 2021 07:44:14 +0000 Subject: [PATCH 1438/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 8a563cc01e..f9c92a513d 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.13.0.RC1 + 5.13.0-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v5.13.0.RC1 + HEAD From f8763929210da59cdf710a4db6e3b8b4305c33e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 30 Jun 2021 09:49:09 +0200 Subject: [PATCH 1439/2114] Set release version to 5.13.0.RC2 --- release-versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-versions.txt b/release-versions.txt index 6444570f66..b350937ea3 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,3 +1,3 @@ -RELEASE_VERSION="5.13.0.RC1" +RELEASE_VERSION="5.13.0.RC2" DEVELOPMENT_VERSION="5.13.0-SNAPSHOT" RELEASE_BRANCH="5.x.x-stable" From e88962d6359d47fe6292ce122e972088e5d93557 Mon Sep 17 00:00:00 2001 From: Michael Dent Date: Wed, 30 Jun 2021 12:15:30 -0500 Subject: [PATCH 1440/2114] Topology recovery retry fixes --- .../recovery/AutorecoveringConnection.java | 159 +++++++++++------- .../client/impl/recovery/RecordedQueue.java | 18 +- .../recovery/TopologyRecoveryRetryLogic.java | 59 +++++-- 3 files changed, 164 insertions(+), 72 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index 98d5a4d610..7b5a1e16af 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -759,42 +759,15 @@ public void recoverExchange(RecordedExchange x, boolean retry) { } } - + /** + * Recover the queue. Any exceptions during recovery will be delivered to the connection's {@link ExceptionHandler}. + * @param oldName queue name + * @param q recorded queue + * @param retry whether to retry the recovery if an error occurs and a RetryHandler was configured on the connection + */ public void recoverQueue(final String oldName, RecordedQueue q, boolean retry) { try { - if (topologyRecoveryFilter.filterQueue(q)) { - LOGGER.debug("Recovering {}", q); - if (retry) { - final RecordedQueue entity = q; - q = (RecordedQueue) wrapRetryIfNecessary(q, () -> { - entity.recover(); - return null; - }).getRecordedEntity(); - } else { - q.recover(); - } - String newName = q.getName(); - if (!oldName.equals(newName)) { - // make sure server-named queues are re-added with - // their new names. MK. - synchronized (this.recordedQueues) { - this.propagateQueueNameChangeToBindings(oldName, newName); - this.propagateQueueNameChangeToConsumers(oldName, newName); - // bug26552: - // remove old name after we've updated the bindings and consumers, - // plus only for server-named queues, both to make sure we don't lose - // anything to recover. MK. - if(q.isServerNamed()) { - deleteRecordedQueue(oldName); - } - this.recordedQueues.put(newName, q); - } - } - for (QueueRecoveryListener qrl : Utility.copy(this.queueRecoveryListeners)) { - qrl.queueRecovered(oldName, newName); - } - LOGGER.debug("{} has recovered", q); - } + internalRecoverQueue(oldName, q, retry); } catch (Exception cause) { final String message = "Caught an exception while recovering queue " + oldName + ": " + cause.getMessage(); @@ -802,6 +775,52 @@ public void recoverQueue(final String oldName, RecordedQueue q, boolean retry) { this.getExceptionHandler().handleTopologyRecoveryException(delegate, q.getDelegateChannel(), e); } } + + /** + * Recover the queue. Errors are not retried and not delivered to the connection's {@link ExceptionHandler} + * @param oldName queue name + * @param q recorded queue + * @throws Exception if an error occurs recovering the queue + */ + void recoverQueue(final String oldName, RecordedQueue q) throws Exception { + internalRecoverQueue(oldName, q, false); + } + + private void internalRecoverQueue(final String oldName, RecordedQueue q, boolean retry) throws Exception { + if (topologyRecoveryFilter.filterQueue(q)) { + LOGGER.debug("Recovering {}", q); + if (retry) { + final RecordedQueue entity = q; + q = (RecordedQueue) wrapRetryIfNecessary(q, () -> { + entity.recover(); + return null; + }).getRecordedEntity(); + } else { + q.recover(); + } + String newName = q.getName(); + if (!oldName.equals(newName)) { + // make sure server-named queues are re-added with + // their new names. MK. + synchronized (this.recordedQueues) { + this.propagateQueueNameChangeToBindings(oldName, newName); + this.propagateQueueNameChangeToConsumers(oldName, newName); + // bug26552: + // remove old name after we've updated the bindings and consumers, + // plus only for server-named queues, both to make sure we don't lose + // anything to recover. MK. + if(q.isServerNamed()) { + deleteRecordedQueue(oldName); + } + this.recordedQueues.put(newName, q); + } + } + for (QueueRecoveryListener qrl : Utility.copy(this.queueRecoveryListeners)) { + qrl.queueRecovered(oldName, newName); + } + LOGGER.debug("{} has recovered", q); + } + } public void recoverBinding(RecordedBinding b, boolean retry) { try { @@ -825,34 +844,15 @@ public void recoverBinding(RecordedBinding b, boolean retry) { } } + /** + * Recover the consumer. Any exceptions during recovery will be delivered to the connection's {@link ExceptionHandler}. + * @param tag consumer tag + * @param consumer recorded consumer + * @param retry whether to retry the recovery if an error occurs and a RetryHandler was configured on the connection + */ public void recoverConsumer(final String tag, RecordedConsumer consumer, boolean retry) { try { - if (this.topologyRecoveryFilter.filterConsumer(consumer)) { - LOGGER.debug("Recovering {}", consumer); - String newTag = null; - if (retry) { - final RecordedConsumer entity = consumer; - RetryResult retryResult = wrapRetryIfNecessary(consumer, entity::recover); - consumer = (RecordedConsumer) retryResult.getRecordedEntity(); - newTag = (String) retryResult.getResult(); - } else { - newTag = consumer.recover(); - } - - // make sure server-generated tags are re-added. MK. - if(tag != null && !tag.equals(newTag)) { - synchronized (this.consumers) { - this.consumers.remove(tag); - this.consumers.put(newTag, consumer); - } - consumer.getChannel().updateConsumerTag(tag, newTag); - } - - for (ConsumerRecoveryListener crl : Utility.copy(this.consumerRecoveryListeners)) { - crl.consumerRecovered(tag, newTag); - } - LOGGER.debug("{} has recovered", consumer); - } + internalRecoverConsumer(tag, consumer, retry); } catch (Exception cause) { final String message = "Caught an exception while recovering consumer " + tag + ": " + cause.getMessage(); @@ -860,6 +860,45 @@ public void recoverConsumer(final String tag, RecordedConsumer consumer, boolean this.getExceptionHandler().handleTopologyRecoveryException(delegate, consumer.getDelegateChannel(), e); } } + + /** + * Recover the consumer. Errors are not retried and not delivered to the connection's {@link ExceptionHandler} + * @param tag consumer tag + * @param consumer recorded consumer + * @throws Exception if an error occurs recovering the consumer + */ + void recoverConsumer(final String tag, RecordedConsumer consumer) throws Exception { + internalRecoverConsumer(tag, consumer, false); + } + + private void internalRecoverConsumer(final String tag, RecordedConsumer consumer, boolean retry) throws Exception { + if (this.topologyRecoveryFilter.filterConsumer(consumer)) { + LOGGER.debug("Recovering {}", consumer); + String newTag = null; + if (retry) { + final RecordedConsumer entity = consumer; + RetryResult retryResult = wrapRetryIfNecessary(consumer, entity::recover); + consumer = (RecordedConsumer) retryResult.getRecordedEntity(); + newTag = (String) retryResult.getResult(); + } else { + newTag = consumer.recover(); + } + + // make sure server-generated tags are re-added. MK. + if(tag != null && !tag.equals(newTag)) { + synchronized (this.consumers) { + this.consumers.remove(tag); + this.consumers.put(newTag, consumer); + } + consumer.getChannel().updateConsumerTag(tag, newTag); + } + + for (ConsumerRecoveryListener crl : Utility.copy(this.consumerRecoveryListeners)) { + crl.consumerRecovered(tag, newTag); + } + LOGGER.debug("{} has recovered", consumer); + } + } private RetryResult wrapRetryIfNecessary(RecordedEntity entity, Callable recoveryAction) throws Exception { if (this.retryHandler == null) { diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java index 3580fe091e..14dd3f69d4 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java @@ -37,6 +37,10 @@ public RecordedQueue exclusive(boolean value) { this.exclusive = value; return this; } + + public boolean isExclusive() { + return this.exclusive; + } public RecordedQueue serverNamed(boolean value) { this.serverNamed = value; @@ -47,8 +51,6 @@ public boolean isServerNamed() { return this.serverNamed; } - public boolean isAutoDelete() { return this.autoDelete; } - public void recover() throws IOException { this.name = this.channel.getDelegate().queueDeclare(this.getNameToUseForRecovery(), this.durable, @@ -69,17 +71,29 @@ public RecordedQueue durable(boolean value) { this.durable = value; return this; } + + public boolean isDurable() { + return this.durable; + } public RecordedQueue autoDelete(boolean value) { this.autoDelete = value; return this; } + + public boolean isAutoDelete() { + return this.autoDelete; + } public RecordedQueue arguments(Map value) { this.arguments = value; return this; } + public Map getArguments() { + return arguments; + } + @Override public String toString() { return "RecordedQueue[name=" + name + ", durable=" + durable + ", autoDelete=" + autoDelete + ", exclusive=" + exclusive + ", arguments=" + arguments + "serverNamed=" + serverNamed + ", channel=" + channel + "]"; diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java index f947d2fd4f..5781c54d36 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java @@ -18,6 +18,9 @@ import com.rabbitmq.client.AMQP; import com.rabbitmq.client.ShutdownSignalException; import com.rabbitmq.utility.Utility; +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.Map.Entry; import java.util.function.BiPredicate; import static com.rabbitmq.client.impl.recovery.TopologyRecoveryRetryHandlerBuilder.builder; @@ -62,7 +65,7 @@ public abstract class TopologyRecoveryRetryLogic { if (context.entity() instanceof RecordedQueue) { final RecordedQueue recordedQueue = context.queue(); AutorecoveringConnection connection = context.connection(); - connection.recoverQueue(recordedQueue.getName(), recordedQueue, false); + connection.recoverQueue(recordedQueue.getName(), recordedQueue); } return null; }; @@ -76,9 +79,7 @@ public abstract class TopologyRecoveryRetryLogic { AutorecoveringConnection connection = context.connection(); RecordedQueue recordedQueue = connection.getRecordedQueues().get(binding.getDestination()); if (recordedQueue != null) { - connection.recoverQueue( - recordedQueue.getName(), recordedQueue, false - ); + connection.recoverQueue(recordedQueue.getName(), recordedQueue); } } return null; @@ -122,9 +123,7 @@ public abstract class TopologyRecoveryRetryLogic { AutorecoveringConnection connection = context.connection(); RecordedQueue recordedQueue = connection.getRecordedQueues().get(consumer.getQueue()); if (recordedQueue != null) { - connection.recoverQueue( - recordedQueue.getName(), recordedQueue, false - ); + connection.recoverQueue(recordedQueue.getName(), recordedQueue); } } return null; @@ -165,7 +164,7 @@ public abstract class TopologyRecoveryRetryLogic { } else if (consumer.getChannel() == channel) { final RetryContext retryContext = new RetryContext(consumer, context.exception(), context.connection()); RECOVER_CONSUMER_QUEUE.call(retryContext); - context.connection().recoverConsumer(consumer.getConsumerTag(), consumer, false); + context.connection().recoverConsumer(consumer.getConsumerTag(), consumer); RECOVER_CONSUMER_QUEUE_BINDINGS.call(retryContext); } } @@ -173,6 +172,44 @@ public abstract class TopologyRecoveryRetryLogic { } return null; }; + + /** + * Recover earlier auto-delete or exclusive queues that share the same channel as this retry context + */ + public static final DefaultRetryHandler.RetryOperation RECOVER_PREVIOUS_AUTO_DELETE_QUEUES = context -> { + if (context.entity() instanceof RecordedQueue) { + AutorecoveringConnection connection = context.connection(); + RecordedQueue queue = context.queue(); + // recover all queues for the same channel that had already been recovered successfully before this queue failed. + // If the previous ones were auto-delete or exclusive, they need recovered again + for (Entry entry : Utility.copy(connection.getRecordedQueues()).entrySet()) { + if (entry.getValue() == queue) { + // we have gotten to the queue in this context. Since this is an ordered map we can now break + // as we know we have recovered all the earlier queues on this channel + break; + } else if (queue.getChannel() == entry.getValue().getChannel() + && (entry.getValue().isAutoDelete() || entry.getValue().isExclusive())) { + connection.recoverQueue(entry.getKey(), entry.getValue()); + } + } + } else if (context.entity() instanceof RecordedQueueBinding) { + AutorecoveringConnection connection = context.connection(); + Set queues = new LinkedHashSet<>(); + for (Entry entry : Utility.copy(connection.getRecordedQueues()).entrySet()) { + if (context.entity().getChannel() == entry.getValue().getChannel() + && (entry.getValue().isAutoDelete() || entry.getValue().isExclusive())) { + connection.recoverQueue(entry.getKey(), entry.getValue()); + queues.add(entry.getValue().getName()); + } + } + for (final RecordedBinding binding : Utility.copy(connection.getRecordedBindings())) { + if (binding instanceof RecordedQueueBinding && queues.contains(binding.getDestination())) { + binding.recover(); + } + } + } + return null; + }; /** * Pre-configured {@link TopologyRecoveryRetryHandlerBuilder} that retries recovery of bindings and consumers @@ -188,11 +225,13 @@ public abstract class TopologyRecoveryRetryLogic { .bindingRecoveryRetryCondition(CHANNEL_CLOSED_NOT_FOUND) .consumerRecoveryRetryCondition(CHANNEL_CLOSED_NOT_FOUND) .queueRecoveryRetryOperation(RECOVER_CHANNEL - .andThen(RECOVER_QUEUE)) + .andThen(RECOVER_QUEUE) + .andThen(RECOVER_PREVIOUS_AUTO_DELETE_QUEUES)) .bindingRecoveryRetryOperation(RECOVER_CHANNEL .andThen(RECOVER_BINDING_QUEUE) .andThen(RECOVER_BINDING) - .andThen(RECOVER_PREVIOUS_QUEUE_BINDINGS)) + .andThen(RECOVER_PREVIOUS_QUEUE_BINDINGS) + .andThen(RECOVER_PREVIOUS_AUTO_DELETE_QUEUES)) .consumerRecoveryRetryOperation(RECOVER_CHANNEL .andThen(RECOVER_CONSUMER_QUEUE) .andThen(RECOVER_CONSUMER) From a19879ba07b5bab42c3574010ba39da0f9e44e52 Mon Sep 17 00:00:00 2001 From: Michael Dent Date: Fri, 2 Jul 2021 13:46:13 -0500 Subject: [PATCH 1441/2114] Allow changing queue name during recovery --- .../com/rabbitmq/client/ConnectionFactory.java | 13 +++++++++++++ .../rabbitmq/client/impl/ConnectionParams.java | 12 +++++++++++- .../impl/recovery/AutorecoveringChannel.java | 6 ++++-- .../recovery/AutorecoveringConnection.java | 14 +++++++++----- .../client/impl/recovery/RecordedQueue.java | 15 ++++++++++----- .../recovery/RecoveredQueueNameSupplier.java | 18 ++++++++++++++++++ 6 files changed, 65 insertions(+), 13 deletions(-) create mode 100644 src/main/java/com/rabbitmq/client/impl/recovery/RecoveredQueueNameSupplier.java diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index b3b8612b59..6488be4838 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -19,6 +19,7 @@ import com.rabbitmq.client.impl.nio.NioParams; import com.rabbitmq.client.impl.nio.SocketChannelFrameHandlerFactory; import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; +import com.rabbitmq.client.impl.recovery.RecoveredQueueNameSupplier; import com.rabbitmq.client.impl.recovery.RetryHandler; import com.rabbitmq.client.impl.recovery.TopologyRecoveryFilter; import org.slf4j.Logger; @@ -190,6 +191,8 @@ public class ConnectionFactory implements Cloneable { * @since 5.4.0 */ private RetryHandler topologyRecoveryRetryHandler; + + private RecoveredQueueNameSupplier recoveredQueueNameSupplier; /** * Traffic listener notified of inbound and outbound {@link Command}s. @@ -1267,6 +1270,7 @@ public ConnectionParams params(ExecutorService consumerWorkServiceExecutor) { result.setTopologyRecoveryFilter(topologyRecoveryFilter); result.setConnectionRecoveryTriggeringCondition(connectionRecoveryTriggeringCondition); result.setTopologyRecoveryRetryHandler(topologyRecoveryRetryHandler); + result.setRecoveredQueueNameSupplier(recoveredQueueNameSupplier); result.setTrafficListener(trafficListener); result.setCredentialsRefreshService(credentialsRefreshService); return result; @@ -1648,6 +1652,15 @@ public void setConnectionRecoveryTriggeringCondition(Predicate connectionRecoveryTriggeringCondition; private RetryHandler topologyRecoveryRetryHandler; - + private RecoveredQueueNameSupplier recoveredQueueNameSupplier; + private ExceptionHandler exceptionHandler; private ThreadFactory threadFactory; @@ -271,6 +273,14 @@ public void setTopologyRecoveryRetryHandler(RetryHandler topologyRecoveryRetryHa public RetryHandler getTopologyRecoveryRetryHandler() { return topologyRecoveryRetryHandler; } + + public void setRecoveredQueueNameSupplier(RecoveredQueueNameSupplier recoveredQueueNameSupplier) { + this.recoveredQueueNameSupplier = recoveredQueueNameSupplier; + } + + public RecoveredQueueNameSupplier getRecoveredQueueNameSupplier() { + return recoveredQueueNameSupplier; + } public void setTrafficListener(TrafficListener trafficListener) { this.trafficListener = trafficListener; diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java index 97cacc81b0..cfba283dd2 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java @@ -355,7 +355,8 @@ public void queueDeclareNoWait(String queue, durable(durable). exclusive(exclusive). autoDelete(autoDelete). - arguments(arguments); + arguments(arguments). + recoveredQueueNameSupplier(connection.getRecoveredQueueNameSupplier()); delegate.queueDeclareNoWait(queue, durable, exclusive, autoDelete, arguments); recordQueue(queue, meta); @@ -848,7 +849,8 @@ private void recordQueue(AMQP.Queue.DeclareOk ok, String queue, boolean durable, durable(durable). exclusive(exclusive). autoDelete(autoDelete). - arguments(arguments); + arguments(arguments). + recoveredQueueNameSupplier(connection.getRecoveredQueueNameSupplier()); if (queue.equals(RecordedQueue.EMPTY_STRING)) { q.serverNamed(true); } diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index 98d5a4d610..c332e06fc4 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -96,6 +96,8 @@ public class AutorecoveringConnection implements RecoverableConnection, NetworkC private final Predicate connectionRecoveryTriggeringCondition; private final RetryHandler retryHandler; + + private final RecoveredQueueNameSupplier recoveredQueueNameSupplier; public AutorecoveringConnection(ConnectionParams params, FrameHandlerFactory f, List
addrs) { this(params, f, new ListAddressResolver(addrs)); @@ -119,6 +121,8 @@ public AutorecoveringConnection(ConnectionParams params, FrameHandlerFactory f, letAllPassFilter() : params.getTopologyRecoveryFilter(); this.retryHandler = params.getTopologyRecoveryRetryHandler(); + this.recoveredQueueNameSupplier = params.getRecoveredQueueNameSupplier() == null ? + RecordedQueue.DEFAULT_QUEUE_NAME_SUPPLIER : params.getRecoveredQueueNameSupplier(); } private void setupErrorOnWriteListenerForPotentialRecovery() { @@ -564,6 +568,10 @@ public void addConsumerRecoveryListener(ConsumerRecoveryListener listener) { public void removeConsumerRecoveryListener(ConsumerRecoveryListener listener) { this.consumerRecoveryListeners.remove(listener); } + + RecoveredQueueNameSupplier getRecoveredQueueNameSupplier() { + return this.recoveredQueueNameSupplier; + } private synchronized void beginAutomaticRecovery() throws InterruptedException { final long delay = this.params.getRecoveryDelayHandler().getDelay(0); @@ -782,11 +790,7 @@ public void recoverQueue(final String oldName, RecordedQueue q, boolean retry) { this.propagateQueueNameChangeToConsumers(oldName, newName); // bug26552: // remove old name after we've updated the bindings and consumers, - // plus only for server-named queues, both to make sure we don't lose - // anything to recover. MK. - if(q.isServerNamed()) { - deleteRecordedQueue(oldName); - } + deleteRecordedQueue(oldName); this.recordedQueues.put(newName, q); } } diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java index 3580fe091e..d18fe8c99d 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java @@ -23,6 +23,10 @@ */ public class RecordedQueue extends RecordedNamedEntity { public static final String EMPTY_STRING = ""; + + static final RecoveredQueueNameSupplier DEFAULT_QUEUE_NAME_SUPPLIER = q -> q.isServerNamed() ? EMPTY_STRING : q.name; + + private RecoveredQueueNameSupplier recoveredQueueNameSupplier = DEFAULT_QUEUE_NAME_SUPPLIER; private boolean durable; private boolean autoDelete; private Map arguments; @@ -58,11 +62,7 @@ public void recover() throws IOException { } public String getNameToUseForRecovery() { - if(isServerNamed()) { - return EMPTY_STRING; - } else { - return this.name; - } + return recoveredQueueNameSupplier.getNameToUseForRecovery(this); } public RecordedQueue durable(boolean value) { @@ -80,6 +80,11 @@ public RecordedQueue arguments(Map value) { return this; } + public RecordedQueue recoveredQueueNameSupplier(RecoveredQueueNameSupplier recoveredQueueNameSupplier) { + this.recoveredQueueNameSupplier = recoveredQueueNameSupplier; + return this; + } + @Override public String toString() { return "RecordedQueue[name=" + name + ", durable=" + durable + ", autoDelete=" + autoDelete + ", exclusive=" + exclusive + ", arguments=" + arguments + "serverNamed=" + serverNamed + ", channel=" + channel + "]"; diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveredQueueNameSupplier.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveredQueueNameSupplier.java new file mode 100644 index 0000000000..c1fb3bd930 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveredQueueNameSupplier.java @@ -0,0 +1,18 @@ +package com.rabbitmq.client.impl.recovery; + +/** + * Functional callback interface that can be used to rename a queue during topology recovery. + * Can use along with {@link QueueRecoveryListener} to know when such a queue has been recovered successfully. + * + * @see QueueRecoveryListener + */ +@FunctionalInterface +public interface RecoveredQueueNameSupplier { + + /** + * Get the queue name to use when recovering this RecordedQueue entity + * @param recordedQueue the queue to be recovered + * @return new queue name + */ + String getNameToUseForRecovery(final RecordedQueue recordedQueue); +} \ No newline at end of file From 3b6dbbb17f2d5cbd4d5f0ace6e02927558a9cdc2 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Wed, 30 Jun 2021 07:44:09 +0000 Subject: [PATCH 1442/2114] [maven-release-plugin] prepare release v5.13.0.RC1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index f9c92a513d..8a563cc01e 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.13.0-SNAPSHOT + 5.13.0.RC1 jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - HEAD + v5.13.0.RC1 From eb1d711f0659a7aca37e605cd86531c4bc6419c4 Mon Sep 17 00:00:00 2001 From: pivotal-rabbitmq-ci Date: Wed, 30 Jun 2021 07:44:14 +0000 Subject: [PATCH 1443/2114] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 8a563cc01e..f9c92a513d 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.rabbitmq amqp-client - 5.13.0.RC1 + 5.13.0-SNAPSHOT jar RabbitMQ Java Client @@ -42,7 +42,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git - v5.13.0.RC1 + HEAD From 318b784888305303b393c61328495749ecc39c4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 30 Jun 2021 09:49:09 +0200 Subject: [PATCH 1444/2114] Set release version to 5.13.0.RC2 --- release-versions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-versions.txt b/release-versions.txt index 6444570f66..b350937ea3 100644 --- a/release-versions.txt +++ b/release-versions.txt @@ -1,3 +1,3 @@ -RELEASE_VERSION="5.13.0.RC1" +RELEASE_VERSION="5.13.0.RC2" DEVELOPMENT_VERSION="5.13.0-SNAPSHOT" RELEASE_BRANCH="5.x.x-stable" From f3af73e9dd76d4e1d0fb2f0bd619838567f57fb2 Mon Sep 17 00:00:00 2001 From: Michael Dent Date: Fri, 2 Jul 2021 13:46:13 -0500 Subject: [PATCH 1445/2114] Allow changing queue name during recovery Author: Michael Dent --- .../com/rabbitmq/client/ConnectionFactory.java | 13 +++++++++++++ .../rabbitmq/client/impl/ConnectionParams.java | 12 +++++++++++- .../impl/recovery/AutorecoveringChannel.java | 6 ++++-- .../recovery/AutorecoveringConnection.java | 18 +++++++++++------- .../client/impl/recovery/RecordedQueue.java | 17 +++++++++++------ .../recovery/RecoveredQueueNameSupplier.java | 18 ++++++++++++++++++ 6 files changed, 68 insertions(+), 16 deletions(-) create mode 100644 src/main/java/com/rabbitmq/client/impl/recovery/RecoveredQueueNameSupplier.java diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index b3b8612b59..6488be4838 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -19,6 +19,7 @@ import com.rabbitmq.client.impl.nio.NioParams; import com.rabbitmq.client.impl.nio.SocketChannelFrameHandlerFactory; import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; +import com.rabbitmq.client.impl.recovery.RecoveredQueueNameSupplier; import com.rabbitmq.client.impl.recovery.RetryHandler; import com.rabbitmq.client.impl.recovery.TopologyRecoveryFilter; import org.slf4j.Logger; @@ -190,6 +191,8 @@ public class ConnectionFactory implements Cloneable { * @since 5.4.0 */ private RetryHandler topologyRecoveryRetryHandler; + + private RecoveredQueueNameSupplier recoveredQueueNameSupplier; /** * Traffic listener notified of inbound and outbound {@link Command}s. @@ -1267,6 +1270,7 @@ public ConnectionParams params(ExecutorService consumerWorkServiceExecutor) { result.setTopologyRecoveryFilter(topologyRecoveryFilter); result.setConnectionRecoveryTriggeringCondition(connectionRecoveryTriggeringCondition); result.setTopologyRecoveryRetryHandler(topologyRecoveryRetryHandler); + result.setRecoveredQueueNameSupplier(recoveredQueueNameSupplier); result.setTrafficListener(trafficListener); result.setCredentialsRefreshService(credentialsRefreshService); return result; @@ -1648,6 +1652,15 @@ public void setConnectionRecoveryTriggeringCondition(Predicate connectionRecoveryTriggeringCondition; private RetryHandler topologyRecoveryRetryHandler; - + private RecoveredQueueNameSupplier recoveredQueueNameSupplier; + private ExceptionHandler exceptionHandler; private ThreadFactory threadFactory; @@ -271,6 +273,14 @@ public void setTopologyRecoveryRetryHandler(RetryHandler topologyRecoveryRetryHa public RetryHandler getTopologyRecoveryRetryHandler() { return topologyRecoveryRetryHandler; } + + public void setRecoveredQueueNameSupplier(RecoveredQueueNameSupplier recoveredQueueNameSupplier) { + this.recoveredQueueNameSupplier = recoveredQueueNameSupplier; + } + + public RecoveredQueueNameSupplier getRecoveredQueueNameSupplier() { + return recoveredQueueNameSupplier; + } public void setTrafficListener(TrafficListener trafficListener) { this.trafficListener = trafficListener; diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java index 97cacc81b0..cfba283dd2 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java @@ -355,7 +355,8 @@ public void queueDeclareNoWait(String queue, durable(durable). exclusive(exclusive). autoDelete(autoDelete). - arguments(arguments); + arguments(arguments). + recoveredQueueNameSupplier(connection.getRecoveredQueueNameSupplier()); delegate.queueDeclareNoWait(queue, durable, exclusive, autoDelete, arguments); recordQueue(queue, meta); @@ -848,7 +849,8 @@ private void recordQueue(AMQP.Queue.DeclareOk ok, String queue, boolean durable, durable(durable). exclusive(exclusive). autoDelete(autoDelete). - arguments(arguments); + arguments(arguments). + recoveredQueueNameSupplier(connection.getRecoveredQueueNameSupplier()); if (queue.equals(RecordedQueue.EMPTY_STRING)) { q.serverNamed(true); } diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index 7b5a1e16af..9cb0dbff59 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -96,6 +96,8 @@ public class AutorecoveringConnection implements RecoverableConnection, NetworkC private final Predicate connectionRecoveryTriggeringCondition; private final RetryHandler retryHandler; + + private final RecoveredQueueNameSupplier recoveredQueueNameSupplier; public AutorecoveringConnection(ConnectionParams params, FrameHandlerFactory f, List
addrs) { this(params, f, new ListAddressResolver(addrs)); @@ -119,6 +121,8 @@ public AutorecoveringConnection(ConnectionParams params, FrameHandlerFactory f, letAllPassFilter() : params.getTopologyRecoveryFilter(); this.retryHandler = params.getTopologyRecoveryRetryHandler(); + this.recoveredQueueNameSupplier = params.getRecoveredQueueNameSupplier() == null ? + RecordedQueue.DEFAULT_QUEUE_NAME_SUPPLIER : params.getRecoveredQueueNameSupplier(); } private void setupErrorOnWriteListenerForPotentialRecovery() { @@ -564,6 +568,10 @@ public void addConsumerRecoveryListener(ConsumerRecoveryListener listener) { public void removeConsumerRecoveryListener(ConsumerRecoveryListener listener) { this.consumerRecoveryListeners.remove(listener); } + + RecoveredQueueNameSupplier getRecoveredQueueNameSupplier() { + return this.recoveredQueueNameSupplier; + } private synchronized void beginAutomaticRecovery() throws InterruptedException { final long delay = this.params.getRecoveryDelayHandler().getDelay(0); @@ -800,18 +808,14 @@ private void internalRecoverQueue(final String oldName, RecordedQueue q, boolean } String newName = q.getName(); if (!oldName.equals(newName)) { - // make sure server-named queues are re-added with - // their new names. MK. + // make sure queues are re-added with + // their new names, if applicable. MK. synchronized (this.recordedQueues) { this.propagateQueueNameChangeToBindings(oldName, newName); this.propagateQueueNameChangeToConsumers(oldName, newName); // bug26552: // remove old name after we've updated the bindings and consumers, - // plus only for server-named queues, both to make sure we don't lose - // anything to recover. MK. - if(q.isServerNamed()) { - deleteRecordedQueue(oldName); - } + deleteRecordedQueue(oldName); this.recordedQueues.put(newName, q); } } diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java index 14dd3f69d4..52caced2af 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java @@ -23,6 +23,10 @@ */ public class RecordedQueue extends RecordedNamedEntity { public static final String EMPTY_STRING = ""; + + static final RecoveredQueueNameSupplier DEFAULT_QUEUE_NAME_SUPPLIER = q -> q.isServerNamed() ? EMPTY_STRING : q.name; + + private RecoveredQueueNameSupplier recoveredQueueNameSupplier = DEFAULT_QUEUE_NAME_SUPPLIER; private boolean durable; private boolean autoDelete; private Map arguments; @@ -60,11 +64,7 @@ public void recover() throws IOException { } public String getNameToUseForRecovery() { - if(isServerNamed()) { - return EMPTY_STRING; - } else { - return this.name; - } + return recoveredQueueNameSupplier.getNameToUseForRecovery(this); } public RecordedQueue durable(boolean value) { @@ -89,10 +89,15 @@ public RecordedQueue arguments(Map value) { this.arguments = value; return this; } - + public Map getArguments() { return arguments; } + + public RecordedQueue recoveredQueueNameSupplier(RecoveredQueueNameSupplier recoveredQueueNameSupplier) { + this.recoveredQueueNameSupplier = recoveredQueueNameSupplier; + return this; + } @Override public String toString() { diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveredQueueNameSupplier.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveredQueueNameSupplier.java new file mode 100644 index 0000000000..c1fb3bd930 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveredQueueNameSupplier.java @@ -0,0 +1,18 @@ +package com.rabbitmq.client.impl.recovery; + +/** + * Functional callback interface that can be used to rename a queue during topology recovery. + * Can use along with {@link QueueRecoveryListener} to know when such a queue has been recovered successfully. + * + * @see QueueRecoveryListener + */ +@FunctionalInterface +public interface RecoveredQueueNameSupplier { + + /** + * Get the queue name to use when recovering this RecordedQueue entity + * @param recordedQueue the queue to be recovered + * @return new queue name + */ + String getNameToUseForRecovery(final RecordedQueue recordedQueue); +} \ No newline at end of file From c80afcfb2f88fa6989ca2c3470fe1af62acbb938 Mon Sep 17 00:00:00 2001 From: madun Date: Tue, 6 Jul 2021 20:34:12 +0800 Subject: [PATCH 1446/2114] =?UTF-8?q?style:=201=E3=80=81format=20two=20lin?= =?UTF-8?q?e=20align=202=E3=80=81add=20channelMax=20<=200=20condition,=20f?= =?UTF-8?q?riendly=20tips?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/rabbitmq/client/impl/ChannelManager.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelManager.java b/src/main/java/com/rabbitmq/client/impl/ChannelManager.java index 59f7bb3fee..0264adeb92 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelManager.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelManager.java @@ -39,9 +39,9 @@ public class ChannelManager { /** Monitor for _channelMap and channelNumberAllocator */ private final Object monitor = new Object(); - /** Mapping from 1.._channelMax to {@link ChannelN} instance */ - private final Map _channelMap = new HashMap(); - private final IntAllocator channelNumberAllocator; + /** Mapping from 1.._channelMax to {@link ChannelN} instance */ + private final Map _channelMap = new HashMap(); + private final IntAllocator channelNumberAllocator; private final ConsumerWorkService workService; @@ -70,6 +70,8 @@ public ChannelManager(ConsumerWorkService workService, int channelMax, ThreadFac public ChannelManager(ConsumerWorkService workService, int channelMax, ThreadFactory threadFactory, MetricsCollector metricsCollector) { + if (channelMax < 0) + throw new IllegalStateException("create ChannelManager: 'channelMax' must be greater or equal to 0."); if (channelMax == 0) { // The framing encoding only allows for unsigned 16-bit integers // for the channel number From 0a4f08bddf61efbe0625d95e03eedf00b17d6b39 Mon Sep 17 00:00:00 2001 From: madun Date: Thu, 8 Jul 2021 09:15:21 +0800 Subject: [PATCH 1447/2114] =?UTF-8?q?style:=201=E3=80=81modify=20IllegalSt?= =?UTF-8?q?ateException=20to=20IllegalArgumentException?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/rabbitmq/client/impl/ChannelManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelManager.java b/src/main/java/com/rabbitmq/client/impl/ChannelManager.java index 0264adeb92..fb0490eade 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelManager.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelManager.java @@ -71,7 +71,7 @@ public ChannelManager(ConsumerWorkService workService, int channelMax, ThreadFac public ChannelManager(ConsumerWorkService workService, int channelMax, ThreadFactory threadFactory, MetricsCollector metricsCollector) { if (channelMax < 0) - throw new IllegalStateException("create ChannelManager: 'channelMax' must be greater or equal to 0."); + throw new IllegalArgumentException("create ChannelManager: 'channelMax' must be greater or equal to 0."); if (channelMax == 0) { // The framing encoding only allows for unsigned 16-bit integers // for the channel number From 430412d3c6439d4745adf1ae5617153ccaaf7d73 Mon Sep 17 00:00:00 2001 From: madun Date: Fri, 9 Jul 2021 16:47:42 +0800 Subject: [PATCH 1448/2114] =?UTF-8?q?refactor:=201=E3=80=81optimize=20clas?= =?UTF-8?q?s=20code=20structure?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/rabbitmq/client/impl/recovery/RecordedEntity.java | 2 +- .../com/rabbitmq/client/impl/recovery/RecordedExchange.java | 1 + .../rabbitmq/client/impl/recovery/RecordedNamedEntity.java | 5 ++++- .../com/rabbitmq/client/impl/recovery/RecordedQueue.java | 5 +++-- .../rabbitmq/client/impl/recovery/RecordedQueueBinding.java | 2 +- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedEntity.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedEntity.java index a9fae4c3ae..a56f58b88a 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedEntity.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedEntity.java @@ -20,7 +20,7 @@ /** * @since 3.3.0 */ -public class RecordedEntity { +public abstract class RecordedEntity { protected final AutorecoveringChannel channel; public RecordedEntity(AutorecoveringChannel channel) { diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchange.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchange.java index 7625b5a870..aaedcbbf58 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchange.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchange.java @@ -31,6 +31,7 @@ public RecordedExchange(AutorecoveringChannel channel, String name) { super(channel, name); } + @Override public void recover() throws IOException { this.channel.getDelegate().exchangeDeclare(this.name, this.type, this.durable, this.autoDelete, this.arguments); } diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedNamedEntity.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedNamedEntity.java index 6ea8b6fa96..7b5a86a8f9 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedNamedEntity.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedNamedEntity.java @@ -15,10 +15,11 @@ package com.rabbitmq.client.impl.recovery; +import java.io.IOException; /** * @since 3.3.0 */ -public class RecordedNamedEntity extends RecordedEntity { +public abstract class RecordedNamedEntity extends RecordedEntity { protected String name; public RecordedNamedEntity(AutorecoveringChannel channel, String name) { @@ -26,6 +27,8 @@ public RecordedNamedEntity(AutorecoveringChannel channel, String name) { this.name = name; } + public abstract void recover() throws IOException; + public String getName() { return name; } diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java index 52caced2af..b41ecdc302 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java @@ -55,6 +55,7 @@ public boolean isServerNamed() { return this.serverNamed; } + @Override public void recover() throws IOException { this.name = this.channel.getDelegate().queueDeclare(this.getNameToUseForRecovery(), this.durable, @@ -71,7 +72,7 @@ public RecordedQueue durable(boolean value) { this.durable = value; return this; } - + public boolean isDurable() { return this.durable; } @@ -80,7 +81,7 @@ public RecordedQueue autoDelete(boolean value) { this.autoDelete = value; return this; } - + public boolean isAutoDelete() { return this.autoDelete; } diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java index 12ed3d48bb..37bbb14fe5 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java @@ -27,7 +27,7 @@ public RecordedQueueBinding(AutorecoveringChannel channel) { @Override public void recover() throws IOException { - this.channel.getDelegate().queueBind(this.getDestination(), this.getSource(), this.routingKey, this.arguments); + this.channel.getDelegate().queueBind(this.destination, this.source, this.routingKey, this.arguments); } @Override From 559c4cb3e9803b2144e7900c13d26a0250da66cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 26 Jul 2021 14:17:20 +0200 Subject: [PATCH 1449/2114] Disable global QoS temporarily Because of a regression in 3.9.x. References rabbitmq/rabbitmq-server#3230 --- .../client/test/functional/FunctionalTests.java | 2 +- .../com/rabbitmq/client/test/functional/QosTests.java | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java b/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java index ebef7ff49e..db87a38695 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java +++ b/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java @@ -40,7 +40,7 @@ NoRequeueOnCancel.class, Bug20004Test.class, ExchangeDeleteIfUnused.class, - //QosTests.class, + QosTests.class, AlternateExchange.class, ExchangeExchangeBindings.class, ExchangeExchangeBindingsAutoDelete.class, diff --git a/src/test/java/com/rabbitmq/client/test/functional/QosTests.java b/src/test/java/com/rabbitmq/client/test/functional/QosTests.java index 276a363f4e..b347382f0d 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QosTests.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QosTests.java @@ -31,6 +31,7 @@ import java.util.Map; import java.util.concurrent.TimeoutException; +import org.junit.Ignore; import org.junit.Test; import com.rabbitmq.client.AMQP; @@ -119,6 +120,7 @@ public static List drain(QueueingConsumer c, int n) drain(c, 2); } + @Ignore @Test public void noAckObeysLimit() throws IOException { @@ -142,6 +144,7 @@ public static List drain(QueueingConsumer c, int n) drain(c2, 1); } + @Ignore @Test public void permutations() throws IOException { @@ -159,6 +162,7 @@ public static List drain(QueueingConsumer c, int n) } } + @Ignore @Test public void fairness() throws IOException { @@ -188,6 +192,7 @@ public static List drain(QueueingConsumer c, int n) } + @Ignore @Test public void singleChannelAndQueueFairness() throws IOException { @@ -237,6 +242,7 @@ public static List drain(QueueingConsumer c, int n) assertTrue(counts.get("c2").intValue() > 0); } + @Ignore @Test public void consumerLifecycle() throws IOException { @@ -258,6 +264,7 @@ public static List drain(QueueingConsumer c, int n) channel.queueDelete(queue); } + @Ignore @Test public void setLimitAfterConsume() throws IOException { @@ -282,6 +289,7 @@ public static List drain(QueueingConsumer c, int n) drain(c, 1); } + @Ignore @Test public void limitDecrease() throws IOException { @@ -302,6 +310,7 @@ public static List drain(QueueingConsumer c, int n) drain(c, 2); } + @Ignore @Test public void limitingMultipleChannels() throws IOException { @@ -338,6 +347,7 @@ public static List drain(QueueingConsumer c, int n) drain(c, 1); } + @Ignore @Test public void recoverReducesLimit() throws Exception { channel.basicQos(2, true); QueueingConsumer c = new QueueingConsumer(channel); From 5653e1cac355fee3cc6c8e1ce3bc82197b5ab7cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 28 Jul 2021 09:46:16 +0200 Subject: [PATCH 1450/2114] Bump dependencies References #699 --- pom.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 75b98ea911..26eda4c83e 100644 --- a/pom.xml +++ b/pom.xml @@ -54,10 +54,10 @@ UTF-8 UTF-8 - 1.7.31 - 4.2.2 - 1.7.1 - 2.12.3 + 1.7.32 + 4.2.3 + 1.7.2 + 2.12.4 1.2.3 4.13.2 3.11.2 From 281b679d3f076b9d2adbb8c8eeb983958eb1e3f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 28 Jul 2021 09:46:56 +0200 Subject: [PATCH 1451/2114] Bump test dependencies --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 26eda4c83e..1dc43a8320 100644 --- a/pom.xml +++ b/pom.xml @@ -58,11 +58,11 @@ 4.2.3 1.7.2 2.12.4 - 1.2.3 + 1.2.5 4.13.2 3.11.2 3.20.2 - 9.4.42.v20210604 + 9.4.43.v20210629 1.69 3.2.0 From ba696986acad8aaee7365aa56e90ccef08bce4bc Mon Sep 17 00:00:00 2001 From: yandryakov Date: Thu, 29 Jul 2021 16:07:02 +0300 Subject: [PATCH 1452/2114] support underflow handling without thread sleep --- .../nio/SocketChannelFrameHandlerState.java | 24 ++++++++++++++--- .../impl/nio/SslEngineFrameBuilder.java | 27 ++++++++++++------- 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java index 50f08a59f2..87c1d08928 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java @@ -26,6 +26,8 @@ import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.SocketChannel; +import java.util.concurrent.atomic.AtomicBoolean; + /** * @@ -70,6 +72,8 @@ public class SocketChannelFrameHandlerState { final FrameBuilder frameBuilder; + private final AtomicBoolean isUnderflowHandlingEnabled = new AtomicBoolean(false); + public SocketChannelFrameHandlerState(SocketChannel channel, NioLoopContext nioLoopsState, NioParams nioParams, SSLEngine sslEngine) { this.channel = channel; this.readSelectorState = nioLoopsState.readSelectorState; @@ -105,7 +109,7 @@ public SocketChannelFrameHandlerState(SocketChannel channel, NioLoopContext nioL this.outputStream = new DataOutputStream( new SslEngineByteBufferOutputStream(sslEngine, plainOut, cipherOut, channel) ); - this.frameBuilder = new SslEngineFrameBuilder(sslEngine, plainIn, cipherIn, channel); + this.frameBuilder = new SslEngineFrameBuilder(sslEngine, plainIn, cipherIn, channel, isUnderflowHandlingEnabled); } } @@ -176,11 +180,14 @@ void endWriteSequence() { void prepareForReadSequence() throws IOException { if(ssl) { - cipherIn.clear(); - plainIn.clear(); + if (!isUnderflowHandlingEnabled.get()) { + cipherIn.clear(); + cipherIn.flip(); + } - cipherIn.flip(); + plainIn.clear(); plainIn.flip(); + } else { NioHelper.read(channel, plainIn); plainIn.flip(); @@ -189,6 +196,15 @@ void prepareForReadSequence() throws IOException { boolean continueReading() throws IOException { if(ssl) { + if (isUnderflowHandlingEnabled.get()) { + int bytesRead = NioHelper.read(channel, cipherIn); + if (bytesRead == 0) { + return false; + } else { + cipherIn.flip(); + return true; + } + } if (!plainIn.hasRemaining() && !cipherIn.hasRemaining()) { // need to try to read something cipherIn.clear(); diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineFrameBuilder.java b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineFrameBuilder.java index c2f1923874..34295fb36a 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineFrameBuilder.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineFrameBuilder.java @@ -21,6 +21,8 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.ReadableByteChannel; +import java.util.concurrent.atomic.AtomicBoolean; + /** * Sub-class of {@link FrameBuilder} that unwraps crypted data from the network. @@ -32,20 +34,25 @@ public class SslEngineFrameBuilder extends FrameBuilder { private final ByteBuffer cipherBuffer; - public SslEngineFrameBuilder(SSLEngine sslEngine, ByteBuffer plainIn, ByteBuffer cipherIn, ReadableByteChannel channel) { + private final AtomicBoolean isUnderflowHandlingEnabled; + + public SslEngineFrameBuilder(SSLEngine sslEngine, ByteBuffer plainIn, ByteBuffer cipherIn, ReadableByteChannel channel, final AtomicBoolean isUnderflowHandlingEnabled) { super(channel, plainIn); this.sslEngine = sslEngine; this.cipherBuffer = cipherIn; + this.isUnderflowHandlingEnabled = isUnderflowHandlingEnabled; } @Override protected boolean somethingToRead() throws IOException { - if (applicationBuffer.hasRemaining()) { + if (applicationBuffer.hasRemaining() && !isUnderflowHandlingEnabled.get()) { return true; } else { applicationBuffer.clear(); - while (true) { + boolean underflowHandling = false; + + try { SSLEngineResult result = sslEngine.unwrap(cipherBuffer, applicationBuffer); switch (result.getStatus()) { case OK: @@ -59,18 +66,18 @@ protected boolean somethingToRead() throws IOException { throw new SSLException("buffer overflow in read"); case BUFFER_UNDERFLOW: cipherBuffer.compact(); - int read = NioHelper.read(channel, cipherBuffer); - if (read == 0) { - return false; - } - cipherBuffer.flip(); - break; + underflowHandling = true; + return false; case CLOSED: throw new SSLException("closed in read"); default: throw new IllegalStateException("Invalid SSL status: " + result.getStatus()); - } + } + } finally { + isUnderflowHandlingEnabled.set(underflowHandling); } + + return false; } } From 217a5e8c2a8e42748b6a33dadae9443ea7f7119a Mon Sep 17 00:00:00 2001 From: yandryakov Date: Thu, 29 Jul 2021 18:34:47 +0300 Subject: [PATCH 1453/2114] refactoring - make isUnderflowHandlingEnabled private property --- .../com/rabbitmq/client/impl/nio/FrameBuilder.java | 5 +++++ .../impl/nio/SocketChannelFrameHandlerState.java | 9 +++------ .../client/impl/nio/SslEngineFrameBuilder.java | 14 ++++++++------ 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java b/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java index 1eca94eb77..29dba1df54 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java @@ -200,4 +200,9 @@ private void handleProtocolVersionMismatch() throws IOException { } throw x; } + + //Indicates ssl underflow state - means that cipherBuffer should aggregate next chunks of bytes + public boolean isUnderflowHandlingEnabled() { + return false; + } } diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java index 87c1d08928..4f1e4dc885 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java @@ -26,7 +26,6 @@ import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.SocketChannel; -import java.util.concurrent.atomic.AtomicBoolean; /** @@ -72,8 +71,6 @@ public class SocketChannelFrameHandlerState { final FrameBuilder frameBuilder; - private final AtomicBoolean isUnderflowHandlingEnabled = new AtomicBoolean(false); - public SocketChannelFrameHandlerState(SocketChannel channel, NioLoopContext nioLoopsState, NioParams nioParams, SSLEngine sslEngine) { this.channel = channel; this.readSelectorState = nioLoopsState.readSelectorState; @@ -109,7 +106,7 @@ public SocketChannelFrameHandlerState(SocketChannel channel, NioLoopContext nioL this.outputStream = new DataOutputStream( new SslEngineByteBufferOutputStream(sslEngine, plainOut, cipherOut, channel) ); - this.frameBuilder = new SslEngineFrameBuilder(sslEngine, plainIn, cipherIn, channel, isUnderflowHandlingEnabled); + this.frameBuilder = new SslEngineFrameBuilder(sslEngine, plainIn, cipherIn, channel); } } @@ -180,7 +177,7 @@ void endWriteSequence() { void prepareForReadSequence() throws IOException { if(ssl) { - if (!isUnderflowHandlingEnabled.get()) { + if (!frameBuilder.isUnderflowHandlingEnabled()) { cipherIn.clear(); cipherIn.flip(); } @@ -196,7 +193,7 @@ void prepareForReadSequence() throws IOException { boolean continueReading() throws IOException { if(ssl) { - if (isUnderflowHandlingEnabled.get()) { + if (frameBuilder.isUnderflowHandlingEnabled()) { int bytesRead = NioHelper.read(channel, cipherIn); if (bytesRead == 0) { return false; diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineFrameBuilder.java b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineFrameBuilder.java index 34295fb36a..8b6ecaf8ab 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineFrameBuilder.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineFrameBuilder.java @@ -21,7 +21,6 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.ReadableByteChannel; -import java.util.concurrent.atomic.AtomicBoolean; /** @@ -34,18 +33,17 @@ public class SslEngineFrameBuilder extends FrameBuilder { private final ByteBuffer cipherBuffer; - private final AtomicBoolean isUnderflowHandlingEnabled; + private boolean isUnderflowHandlingEnabled = false; - public SslEngineFrameBuilder(SSLEngine sslEngine, ByteBuffer plainIn, ByteBuffer cipherIn, ReadableByteChannel channel, final AtomicBoolean isUnderflowHandlingEnabled) { + public SslEngineFrameBuilder(SSLEngine sslEngine, ByteBuffer plainIn, ByteBuffer cipherIn, ReadableByteChannel channel) { super(channel, plainIn); this.sslEngine = sslEngine; this.cipherBuffer = cipherIn; - this.isUnderflowHandlingEnabled = isUnderflowHandlingEnabled; } @Override protected boolean somethingToRead() throws IOException { - if (applicationBuffer.hasRemaining() && !isUnderflowHandlingEnabled.get()) { + if (applicationBuffer.hasRemaining() && !isUnderflowHandlingEnabled) { return true; } else { applicationBuffer.clear(); @@ -74,11 +72,15 @@ protected boolean somethingToRead() throws IOException { throw new IllegalStateException("Invalid SSL status: " + result.getStatus()); } } finally { - isUnderflowHandlingEnabled.set(underflowHandling); + isUnderflowHandlingEnabled = underflowHandling; } return false; } } + @Override + public boolean isUnderflowHandlingEnabled() { + return isUnderflowHandlingEnabled; + } } From 12f9f75bdf973ed74082df5a0fc5d664610c1595 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 30 Jul 2021 17:39:41 +0200 Subject: [PATCH 1454/2114] Re-enable QoS tests Now fix is in master and 3.9.x. --- .../com/rabbitmq/client/test/functional/QosTests.java | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/QosTests.java b/src/test/java/com/rabbitmq/client/test/functional/QosTests.java index b347382f0d..276a363f4e 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QosTests.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QosTests.java @@ -31,7 +31,6 @@ import java.util.Map; import java.util.concurrent.TimeoutException; -import org.junit.Ignore; import org.junit.Test; import com.rabbitmq.client.AMQP; @@ -120,7 +119,6 @@ public static List drain(QueueingConsumer c, int n) drain(c, 2); } - @Ignore @Test public void noAckObeysLimit() throws IOException { @@ -144,7 +142,6 @@ public static List drain(QueueingConsumer c, int n) drain(c2, 1); } - @Ignore @Test public void permutations() throws IOException { @@ -162,7 +159,6 @@ public static List drain(QueueingConsumer c, int n) } } - @Ignore @Test public void fairness() throws IOException { @@ -192,7 +188,6 @@ public static List drain(QueueingConsumer c, int n) } - @Ignore @Test public void singleChannelAndQueueFairness() throws IOException { @@ -242,7 +237,6 @@ public static List drain(QueueingConsumer c, int n) assertTrue(counts.get("c2").intValue() > 0); } - @Ignore @Test public void consumerLifecycle() throws IOException { @@ -264,7 +258,6 @@ public static List drain(QueueingConsumer c, int n) channel.queueDelete(queue); } - @Ignore @Test public void setLimitAfterConsume() throws IOException { @@ -289,7 +282,6 @@ public static List drain(QueueingConsumer c, int n) drain(c, 1); } - @Ignore @Test public void limitDecrease() throws IOException { @@ -310,7 +302,6 @@ public static List drain(QueueingConsumer c, int n) drain(c, 2); } - @Ignore @Test public void limitingMultipleChannels() throws IOException { @@ -347,7 +338,6 @@ public static List drain(QueueingConsumer c, int n) drain(c, 1); } - @Ignore @Test public void recoverReducesLimit() throws Exception { channel.basicQos(2, true); QueueingConsumer c = new QueueingConsumer(channel); From 2e098ffa521f29236a9c0ac3152bd534a9081bd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 30 Aug 2021 10:51:44 +0200 Subject: [PATCH 1455/2114] Bump dependencies References #699 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 1dc43a8320..2e2501a825 100644 --- a/pom.xml +++ b/pom.xml @@ -56,8 +56,8 @@ 1.7.32 4.2.3 - 1.7.2 - 2.12.4 + 1.7.3 + 2.12.5 1.2.5 4.13.2 3.11.2 From 1a11d9fef88e14776554839142b07454903e9a05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 30 Aug 2021 10:52:51 +0200 Subject: [PATCH 1456/2114] Bump test dependencies --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2e2501a825..11e31f114e 100644 --- a/pom.xml +++ b/pom.xml @@ -60,7 +60,7 @@ 2.12.5 1.2.5 4.13.2 - 3.11.2 + 3.12.4 3.20.2 9.4.43.v20210629 1.69 From 831d145feba7ef3a61d4d5a50efddad882dad6bf Mon Sep 17 00:00:00 2001 From: Mirah Gary Date: Fri, 17 Sep 2021 14:22:45 +0200 Subject: [PATCH 1457/2114] Add CodeQL code security analysis workflow --- .github/workflows/codeql-analysis.yml | 71 +++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 .github/workflows/codeql-analysis.yml diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 0000000000..269c2918e5 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,71 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: [ main ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ main ] + schedule: + - cron: '21 11 * * 6' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'java', 'python' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] + # Learn more: + # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v1 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 From cb724b3ec3389fee0e32ec9e72d207225c968c6f Mon Sep 17 00:00:00 2001 From: Mirah Gary Date: Fri, 17 Sep 2021 14:38:29 +0200 Subject: [PATCH 1458/2114] Replace autobuild with make. --- .github/workflows/codeql-analysis.yml | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 269c2918e5..b5f7df029a 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -53,19 +53,9 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v1 - # ℹ️ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl - - # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language - - #- run: | - # make bootstrap - # make release + - run: | + make - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v1 From c879d7a0404e49242623f101a1e861400602df9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 28 Sep 2021 16:53:59 +0200 Subject: [PATCH 1459/2114] Bump Micrometer to 1.7.4 References #699 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 11e31f114e..564b72e45a 100644 --- a/pom.xml +++ b/pom.xml @@ -56,7 +56,7 @@ 1.7.32 4.2.3 - 1.7.3 + 1.7.4 2.12.5 1.2.5 4.13.2 From 2da7a4acbf9a80b7e0e00e167a9992713f8bb88d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 28 Sep 2021 16:54:54 +0200 Subject: [PATCH 1460/2114] Bump test dependencies --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 564b72e45a..3d77800113 100644 --- a/pom.xml +++ b/pom.xml @@ -58,10 +58,10 @@ 4.2.3 1.7.4 2.12.5 - 1.2.5 + 1.2.6 4.13.2 3.12.4 - 3.20.2 + 3.21.0 9.4.43.v20210629 1.69 From e01c208d21318371e755b91a072f47fb12981de2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 4 Oct 2021 09:20:51 +0200 Subject: [PATCH 1461/2114] Bump Maven to 3.8.3 --- .mvn/wrapper/maven-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index 642d572ce9..a9f1ef87bb 100644 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -1,2 +1,2 @@ -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.3/apache-maven-3.8.3-bin.zip wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar From 54fa481d31a552a05b60791347c973784b4a7ec9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 5 Oct 2021 14:45:46 +0200 Subject: [PATCH 1462/2114] Bump optional dependencies References #699 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 3d77800113..5db3a4bce1 100644 --- a/pom.xml +++ b/pom.xml @@ -55,9 +55,9 @@ UTF-8 1.7.32 - 4.2.3 + 4.2.4 1.7.4 - 2.12.5 + 2.13.0 1.2.6 4.13.2 3.12.4 From 3e5e2789baf8c9172a48474fdfd712cde9c2128f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 5 Oct 2021 14:46:10 +0200 Subject: [PATCH 1463/2114] Bump test dependency --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5db3a4bce1..f369a7eab4 100644 --- a/pom.xml +++ b/pom.xml @@ -62,7 +62,7 @@ 4.13.2 3.12.4 3.21.0 - 9.4.43.v20210629 + 9.4.44.v20210927 1.69 3.2.0 From 4de6eb709330644e7707b3e0a9652b5f09c16c70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 21 Oct 2021 09:30:52 +0200 Subject: [PATCH 1464/2114] Bump Micrometer to 1.7.5 References #699 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f369a7eab4..7d608525d2 100644 --- a/pom.xml +++ b/pom.xml @@ -56,7 +56,7 @@ 1.7.32 4.2.4 - 1.7.4 + 1.7.5 2.13.0 1.2.6 4.13.2 From 15068a4d569e67a66cac7534270fe8e97761f741 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 21 Oct 2021 09:31:43 +0200 Subject: [PATCH 1465/2114] Bump Mockito to 4.0.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7d608525d2..a73d43b6f9 100644 --- a/pom.xml +++ b/pom.xml @@ -60,7 +60,7 @@ 2.13.0 1.2.6 4.13.2 - 3.12.4 + 4.0.0 3.21.0 9.4.44.v20210927 1.69 From ac2fe3bef8f06ac425b8cdf106394ad7b818f68e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 25 Oct 2021 09:40:03 +0200 Subject: [PATCH 1466/2114] Use 5.13.1 version in readme --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ba44586dee..a23e89e307 100644 --- a/README.md +++ b/README.md @@ -25,19 +25,19 @@ They require Java 8 or higher. com.rabbitmq amqp-client - 5.12.0 + 5.13.1 ``` ### Gradle ``` groovy -compile 'com.rabbitmq:amqp-client:5.12.0' +compile 'com.rabbitmq:amqp-client:5.13.1' ``` #### 4.x Series -As of 1 January 2021 the 4.x branch is no longer supported. +**As of 1 January 2021 the 4.x branch is no longer supported**. This client releases are independent from RabbitMQ server releases and can be used with RabbitMQ server `3.x`. They require Java 6 or higher. From ea8aa89fafbb96260a31b63898d93128ed23adea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 25 Oct 2021 10:01:04 +0200 Subject: [PATCH 1467/2114] Fix dead lettering flaky test It was using Thread.sleep() statements, which are not reliable, using polling for assertion instead. --- .../com/rabbitmq/client/test/TestUtils.java | 25 +++++++++--- .../test/functional/DeadLetterExchange.java | 39 +++++++++++++++---- 2 files changed, 51 insertions(+), 13 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/TestUtils.java b/src/test/java/com/rabbitmq/client/test/TestUtils.java index e16bca6f40..72e0b56cea 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtils.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtils.java @@ -56,9 +56,20 @@ public static ConnectionFactory connectionFactory() { return connectionFactory; } - public static void waitAtMost(Duration timeout, BooleanSupplier condition) { - if (condition.getAsBoolean()) { - return; + @FunctionalInterface + public interface CallableBooleanSupplier { + + boolean getAsBoolean() throws Exception; + + } + + public static void waitAtMost(Duration timeout, CallableBooleanSupplier condition) { + try { + if (condition.getAsBoolean()) { + return; + } + } catch (Exception e) { + throw new RuntimeException(e); } int waitTime = 100; int waitedTime = 0; @@ -70,8 +81,12 @@ public static void waitAtMost(Duration timeout, BooleanSupplier condition) { Thread.currentThread().interrupt(); throw new RuntimeException(e); } - if (condition.getAsBoolean()) { - return; + try { + if (condition.getAsBoolean()) { + return; + } + } catch (Exception e) { + throw new RuntimeException(e); } waitedTime += waitTime; } diff --git a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java index 36c09add6a..d7244c7845 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java @@ -19,12 +19,15 @@ import com.rabbitmq.client.AMQP.BasicProperties; import com.rabbitmq.client.test.BrokerTestCase; import com.rabbitmq.client.test.TestUtils; +import java.util.concurrent.atomic.AtomicReference; import org.junit.Test; import java.io.IOException; import java.util.*; import java.util.concurrent.*; +import static com.rabbitmq.client.test.TestUtils.waitAtMost; +import static java.time.Duration.ofSeconds; import static org.junit.Assert.*; public class DeadLetterExchange extends BrokerTestCase { @@ -403,9 +406,15 @@ public void handleDelivery(String consumerTag, Envelope envelope, channel.queueBind(DLQ, DLX, "test"); publishN(1); - sleep(200); - - GetResponse getResponse = channel.basicGet(DLQ, true); + AtomicReference responseRefeference = new AtomicReference<>(); + waitAtMost( + ofSeconds(1), + () -> { + GetResponse response = channel.basicGet(DLQ, true); + responseRefeference.set(response); + return responseRefeference.get() != null; + }); + GetResponse getResponse = responseRefeference.get(); assertNotNull("Message not dead-lettered", getResponse); assertEquals("test message", new String(getResponse.getBody())); @@ -432,9 +441,15 @@ public void handleDelivery(String consumerTag, Envelope envelope, .headers(headers) .build(), "test message".getBytes()); - sleep(100); - - getResponse = channel.basicGet(DLQ, true); + responseRefeference.set(null); + waitAtMost( + ofSeconds(1), + () -> { + GetResponse response = channel.basicGet(DLQ, true); + responseRefeference.set(response); + return responseRefeference.get() != null; + }); + getResponse = responseRefeference.get(); assertNotNull("Message not dead-lettered", getResponse); assertEquals("test message", new String(getResponse.getBody())); headers = getResponse.getProps().getHeaders(); @@ -453,9 +468,17 @@ public void handleDelivery(String consumerTag, Envelope envelope, new AMQP.BasicProperties.Builder() .headers(headers) .build(), "test message".getBytes()); - sleep(100); - getResponse = channel.basicGet(DLQ, true); + responseRefeference.set(null); + waitAtMost( + ofSeconds(1), + () -> { + GetResponse response = channel.basicGet(DLQ, true); + responseRefeference.set(response); + return responseRefeference.get() != null; + }); + getResponse = responseRefeference.get(); + assertNotNull("Message not dead-lettered", getResponse); assertEquals("test message", new String(getResponse.getBody())); headers = getResponse.getProps().getHeaders(); From 761628ee1ea4f1a90942110d22bb4407ab861549 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 25 Oct 2021 11:02:31 +0200 Subject: [PATCH 1468/2114] Fix test rule --- src/test/java/com/rabbitmq/client/test/TestUtils.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/java/com/rabbitmq/client/test/TestUtils.java b/src/test/java/com/rabbitmq/client/test/TestUtils.java index 72e0b56cea..7544893760 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtils.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtils.java @@ -343,6 +343,8 @@ public void evaluate() throws Throwable { if (Host.isOnDocker()) { throw new AssumptionViolatedException("Broker is running on Docker"); } + } catch (AssumptionViolatedException e) { + throw e; } catch (Exception e) { throw new AssumptionViolatedException("Could not check whether broker is running on Docker or not", e); } From 57b61d82dc441d3779547c918f179026d94b5d51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 25 Oct 2021 11:21:44 +0200 Subject: [PATCH 1469/2114] Change/remove usage of some deprecated JDK API API deprecated in Java 16 or more. There are alternatives (e.g. for certificate subject and issuer) for some, but not for all (e.g. usage of the security manager to change thread, which is no big deal as the changes to thread are minor and it is likely nobody cares about such checks nowadays). Fixes #709 --- .../com/rabbitmq/client/impl/Environment.java | 29 +++++++++---------- .../com/rabbitmq/client/impl/TlsUtils.java | 2 +- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/Environment.java b/src/main/java/com/rabbitmq/client/impl/Environment.java index 149b9a102e..2676311322 100644 --- a/src/main/java/com/rabbitmq/client/impl/Environment.java +++ b/src/main/java/com/rabbitmq/client/impl/Environment.java @@ -23,32 +23,29 @@ * Package-protected API. */ public class Environment { + + /** + * This method is deprecated and subject to removal in the next major release. + * + * There is no replacement for this method, as it used to use the + * {@link SecurityManager}, which is itself deprecated and subject to removal. + * @deprecated + * @return always returns true + */ + @Deprecated public static boolean isAllowedToModifyThreads() { - try { - SecurityManager sm = System.getSecurityManager(); - if(sm != null) { - sm.checkPermission(new RuntimePermission("modifyThread")); - sm.checkPermission(new RuntimePermission("modifyThreadGroup")); - } - return true; - } catch (SecurityException se) { - return false; - } + return true; } public static Thread newThread(ThreadFactory factory, Runnable runnable, String name) { Thread t = factory.newThread(runnable); - if(isAllowedToModifyThreads()) { - t.setName(name); - } + t.setName(name); return t; } public static Thread newThread(ThreadFactory factory, Runnable runnable, String name, boolean isDaemon) { Thread t = newThread(factory, runnable, name); - if(isAllowedToModifyThreads()) { - t.setDaemon(isDaemon); - } + t.setDaemon(isDaemon); return t; } } diff --git a/src/main/java/com/rabbitmq/client/impl/TlsUtils.java b/src/main/java/com/rabbitmq/client/impl/TlsUtils.java index a11deddc2c..aa103607ec 100644 --- a/src/main/java/com/rabbitmq/client/impl/TlsUtils.java +++ b/src/main/java/com/rabbitmq/client/impl/TlsUtils.java @@ -104,7 +104,7 @@ public static String peerCertificateInfo(Certificate certificate, String prefix) try { return String.format("%s subject: %s, subject alternative names: %s, " + "issuer: %s, not valid after: %s, X.509 usage extensions: %s", - stripCRLF(prefix), stripCRLF(c.getSubjectDN().getName()), stripCRLF(sans(c, ",")), stripCRLF(c.getIssuerDN().getName()), + stripCRLF(prefix), stripCRLF(c.getSubjectX500Principal().getName()), stripCRLF(sans(c, ",")), stripCRLF(c.getIssuerX500Principal().getName()), c.getNotAfter(), stripCRLF(extensions(c))); } catch (Exception e) { return "Error while retrieving " + prefix + " certificate information"; From 3d91f3c995125af4063a6c2e8daea6cc185e36ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 25 Oct 2021 11:33:50 +0200 Subject: [PATCH 1470/2114] Add GHA test workflow --- .github/workflows/test-linux.yml | 38 ++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 .github/workflows/test-linux.yml diff --git a/.github/workflows/test-linux.yml b/.github/workflows/test-linux.yml new file mode 100644 index 0000000000..bdf3f1a855 --- /dev/null +++ b/.github/workflows/test-linux.yml @@ -0,0 +1,38 @@ +name: Build (Linux) + +on: + push: + branches: + - main + pull_request: + branches: + - main + +jobs: + build: + runs-on: ubuntu-20.04 + + services: + rabbitmq: + image: rabbitmq + ports: + - 5672:5672 + + steps: + - uses: actions/checkout@v2 + + - name: Set up JDK 1.8 + uses: actions/setup-java@v2 + with: + distribution: 'zulu' + java-version: '11' + - name: Cache Maven packages + uses: actions/cache@v2 + with: + path: ~/.m2 + key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} + restore-keys: ${{ runner.os }}-m2 + - name: Test with NIO + run: ./mvnw verify -P '!setup-test-cluster,use-nio' -Drabbitmqctl.bin=DOCKER:rabbitmq -Dit.test=ClientTests,FunctionalTests,ServerTests + - name: Test with blocking IO + run: ./mvnw verify -P '!setup-test-cluster' -Drabbitmqctl.bin=DOCKER:rabbitmq -Dit.test=ClientTests,FunctionalTests,ServerTests \ No newline at end of file From 0f3f8f6a29efe10745af88fb83121ae95d82ecdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 25 Oct 2021 12:01:30 +0200 Subject: [PATCH 1471/2114] Add Python to GHA build To generate code. --- .github/workflows/test-linux.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-linux.yml b/.github/workflows/test-linux.yml index bdf3f1a855..b599b89386 100644 --- a/.github/workflows/test-linux.yml +++ b/.github/workflows/test-linux.yml @@ -20,8 +20,11 @@ jobs: steps: - uses: actions/checkout@v2 - - - name: Set up JDK 1.8 + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.x' + - name: Set up JDK uses: actions/setup-java@v2 with: distribution: 'zulu' From 9ef188da31ec9f740a2766d5ce8ac8219b96ef6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 25 Oct 2021 12:51:48 +0200 Subject: [PATCH 1472/2114] Get dependencies in GHA test build --- .github/workflows/test-linux.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/test-linux.yml b/.github/workflows/test-linux.yml index b599b89386..3fd9935c43 100644 --- a/.github/workflows/test-linux.yml +++ b/.github/workflows/test-linux.yml @@ -35,6 +35,8 @@ jobs: path: ~/.m2 key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} restore-keys: ${{ runner.os }}-m2 + - name: Get dependencies + run: make deps - name: Test with NIO run: ./mvnw verify -P '!setup-test-cluster,use-nio' -Drabbitmqctl.bin=DOCKER:rabbitmq -Dit.test=ClientTests,FunctionalTests,ServerTests - name: Test with blocking IO From 23181a8bde3f62bbe5c6cc940b50bb44b6c37d16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 25 Oct 2021 13:37:08 +0200 Subject: [PATCH 1473/2114] Fix command for Docker container ID in GHA build --- .github/workflows/test-linux.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-linux.yml b/.github/workflows/test-linux.yml index 3fd9935c43..4a74447b91 100644 --- a/.github/workflows/test-linux.yml +++ b/.github/workflows/test-linux.yml @@ -40,4 +40,4 @@ jobs: - name: Test with NIO run: ./mvnw verify -P '!setup-test-cluster,use-nio' -Drabbitmqctl.bin=DOCKER:rabbitmq -Dit.test=ClientTests,FunctionalTests,ServerTests - name: Test with blocking IO - run: ./mvnw verify -P '!setup-test-cluster' -Drabbitmqctl.bin=DOCKER:rabbitmq -Dit.test=ClientTests,FunctionalTests,ServerTests \ No newline at end of file + run: ./mvnw verify -P '!setup-test-cluster' -Drabbitmqctl.bin=DOCKER:${{job.services.rabbitmq.id}} -Dit.test=ClientTests,FunctionalTests,ServerTests \ No newline at end of file From edd664c9b21205d6752f891948832a89910e3e7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 25 Oct 2021 13:48:18 +0200 Subject: [PATCH 1474/2114] Fix command for Docker container ID in GHA build --- .github/workflows/test-linux.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-linux.yml b/.github/workflows/test-linux.yml index 4a74447b91..0e36b5d641 100644 --- a/.github/workflows/test-linux.yml +++ b/.github/workflows/test-linux.yml @@ -38,6 +38,6 @@ jobs: - name: Get dependencies run: make deps - name: Test with NIO - run: ./mvnw verify -P '!setup-test-cluster,use-nio' -Drabbitmqctl.bin=DOCKER:rabbitmq -Dit.test=ClientTests,FunctionalTests,ServerTests + run: ./mvnw verify -P '!setup-test-cluster,use-nio' -Drabbitmqctl.bin=DOCKER:${{job.services.rabbitmq.id}} -Dit.test=ClientTests,FunctionalTests,ServerTests - name: Test with blocking IO run: ./mvnw verify -P '!setup-test-cluster' -Drabbitmqctl.bin=DOCKER:${{job.services.rabbitmq.id}} -Dit.test=ClientTests,FunctionalTests,ServerTests \ No newline at end of file From 15ed3d151e8c8747cd1beb17931eb06d1281d3e7 Mon Sep 17 00:00:00 2001 From: ByteAlex Date: Fri, 5 Nov 2021 11:09:45 +0100 Subject: [PATCH 1475/2114] Parse unsigned byte `B` in ValueReader --- src/main/java/com/rabbitmq/client/impl/ValueReader.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/com/rabbitmq/client/impl/ValueReader.java b/src/main/java/com/rabbitmq/client/impl/ValueReader.java index 1162cc8af0..ed7f41284c 100644 --- a/src/main/java/com/rabbitmq/client/impl/ValueReader.java +++ b/src/main/java/com/rabbitmq/client/impl/ValueReader.java @@ -186,6 +186,9 @@ static Object readFieldValue(DataInputStream in) case 'b': value = in.readByte(); break; + case 'B': + value = in.readUnsignedByte(); + break; case 'd': value = in.readDouble(); break; From 448d3dd0ccb9755db2fccb11f433ddf5b55ca48f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 5 Nov 2021 13:41:55 +0100 Subject: [PATCH 1476/2114] Fix handshake with NIO on TLS 1.3 The unwrapping does not work the same way between TLS 1.2 and 1.3. This commit makes the unwrapping more reliable by getting the number of bytes consumed in the unwrapping and then set the position of the reading ByteBuffer accordingly to the number of bytes. With TLS 1.3, the unwrapping seems to read the whole content of the buffer and to extract only the first record, so the rewinding is necessary. The commit also adds some debug logging, adds tests on TLS 1.2 and 1.3, and re-arranges the TLS test (add utility class). Fixes #715 --- .../client/impl/nio/SslEngineHelper.java | 101 +++++++++++---- .../rabbitmq/client/test/BrokerTestCase.java | 7 +- .../com/rabbitmq/client/test/TestUtils.java | 45 +++---- .../test/ssl/BadVerifiedConnection.java | 49 +------- .../client/test/ssl/HostnameVerification.java | 35 +----- .../test/ssl/NioTlsUnverifiedConnection.java | 55 +++++---- .../client/test/ssl/TlsConnectionLogging.java | 4 +- .../client/test/ssl/TlsTestUtils.java | 115 ++++++++++++++++++ .../client/test/ssl/UnverifiedConnection.java | 10 +- .../client/test/ssl/VerifiedConnection.java | 93 +++++++------- src/test/resources/logback-test.xml | 2 +- 11 files changed, 302 insertions(+), 214 deletions(-) create mode 100644 src/test/java/com/rabbitmq/client/test/ssl/TlsTestUtils.java diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java index 1e7e3a0793..bcefe8b205 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2021 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -23,8 +23,12 @@ import java.nio.channels.ReadableByteChannel; import java.nio.channels.SocketChannel; import java.nio.channels.WritableByteChannel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import static javax.net.ssl.SSLEngineResult.HandshakeStatus.FINISHED; +import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NEED_TASK; +import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NEED_WRAP; import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING; /** @@ -32,6 +36,8 @@ */ public class SslEngineHelper { + private static final Logger LOGGER = LoggerFactory.getLogger(SslEngineHelper.class); + public static boolean doHandshake(SocketChannel socketChannel, SSLEngine engine) throws IOException { ByteBuffer plainOut = ByteBuffer.allocate(engine.getSession().getApplicationBufferSize()); @@ -39,20 +45,36 @@ public static boolean doHandshake(SocketChannel socketChannel, SSLEngine engine) ByteBuffer cipherOut = ByteBuffer.allocate(engine.getSession().getPacketBufferSize()); ByteBuffer cipherIn = ByteBuffer.allocate(engine.getSession().getPacketBufferSize()); + LOGGER.debug("Starting TLS handshake"); + SSLEngineResult.HandshakeStatus handshakeStatus = engine.getHandshakeStatus(); + LOGGER.debug("Initial handshake status is {}", handshakeStatus); while (handshakeStatus != FINISHED && handshakeStatus != NOT_HANDSHAKING) { + LOGGER.debug("Handshake status is {}", handshakeStatus); switch (handshakeStatus) { case NEED_TASK: + LOGGER.debug("Running tasks"); handshakeStatus = runDelegatedTasks(engine); break; case NEED_UNWRAP: + LOGGER.debug("Unwrapping..."); handshakeStatus = unwrap(cipherIn, plainIn, socketChannel, engine); break; case NEED_WRAP: + LOGGER.debug("Wrapping..."); handshakeStatus = wrap(plainOut, cipherOut, socketChannel, engine); break; + case FINISHED: + break; + case NOT_HANDSHAKING: + break; + default: + throw new SSLException("Unexpected handshake status " + handshakeStatus); } } + + + LOGGER.debug("TLS handshake completed"); return true; } @@ -60,6 +82,7 @@ private static SSLEngineResult.HandshakeStatus runDelegatedTasks(SSLEngine sslEn // FIXME run in executor? Runnable runnable; while ((runnable = sslEngine.getDelegatedTask()) != null) { + LOGGER.debug("Running delegated task"); runnable.run(); } return sslEngine.getHandshakeStatus(); @@ -68,29 +91,57 @@ private static SSLEngineResult.HandshakeStatus runDelegatedTasks(SSLEngine sslEn private static SSLEngineResult.HandshakeStatus unwrap(ByteBuffer cipherIn, ByteBuffer plainIn, ReadableByteChannel channel, SSLEngine sslEngine) throws IOException { SSLEngineResult.HandshakeStatus handshakeStatus = sslEngine.getHandshakeStatus(); - - if (channel.read(cipherIn) < 0) { - throw new SSLException("Could not read from socket channel"); + LOGGER.debug("Handshake status is {} before unwrapping", handshakeStatus); + + LOGGER.debug("Cipher in position {}", cipherIn.position()); + int read; + if (cipherIn.position() == 0) { + LOGGER.debug("Reading from channel"); + read = channel.read(cipherIn); + LOGGER.debug("Read {} byte(s) from channel", read); + if (read < 0) { + throw new SSLException("Could not read from socket channel"); + } + cipherIn.flip(); + } else { + LOGGER.debug("Not reading"); } - cipherIn.flip(); SSLEngineResult.Status status; + SSLEngineResult unwrapResult; do { - SSLEngineResult unwrapResult = sslEngine.unwrap(cipherIn, plainIn); + int positionBeforeUnwrapping = cipherIn.position(); + unwrapResult = sslEngine.unwrap(cipherIn, plainIn); + LOGGER.debug("SSL engine result is {} after unwrapping", unwrapResult); status = unwrapResult.getStatus(); switch (status) { case OK: plainIn.clear(); - handshakeStatus = runDelegatedTasks(sslEngine); + if (unwrapResult.getHandshakeStatus() == NEED_TASK) { + handshakeStatus = runDelegatedTasks(sslEngine); + int newPosition = positionBeforeUnwrapping + unwrapResult.bytesConsumed(); + if (newPosition == cipherIn.limit()) { + LOGGER.debug("Clearing cipherIn because all bytes have been read and unwrapped"); + cipherIn.clear(); + } else { + LOGGER.debug("Setting cipherIn position to {} (limit is {})", newPosition, cipherIn.limit()); + cipherIn.position(positionBeforeUnwrapping + unwrapResult.bytesConsumed()); + } + } else { + handshakeStatus = unwrapResult.getHandshakeStatus(); + } break; case BUFFER_OVERFLOW: throw new SSLException("Buffer overflow during handshake"); case BUFFER_UNDERFLOW: + LOGGER.debug("Buffer underflow"); cipherIn.compact(); - int read = NioHelper.read(channel, cipherIn); + LOGGER.debug("Reading from channel..."); + read = NioHelper.read(channel, cipherIn); if(read <= 0) { retryRead(channel, cipherIn); } + LOGGER.debug("Done reading from channel..."); cipherIn.flip(); break; case CLOSED: @@ -100,9 +151,9 @@ private static SSLEngineResult.HandshakeStatus unwrap(ByteBuffer cipherIn, ByteB throw new SSLException("Unexpected status from " + unwrapResult); } } - while (cipherIn.hasRemaining()); + while (unwrapResult.getHandshakeStatus() != NEED_WRAP && unwrapResult.getHandshakeStatus() != FINISHED); - cipherIn.compact(); + LOGGER.debug("cipherIn position after unwrap {}", cipherIn.position()); return handshakeStatus; } @@ -127,36 +178,32 @@ private static int retryRead(ReadableByteChannel channel, ByteBuffer buffer) thr private static SSLEngineResult.HandshakeStatus wrap(ByteBuffer plainOut, ByteBuffer cipherOut, WritableByteChannel channel, SSLEngine sslEngine) throws IOException { SSLEngineResult.HandshakeStatus handshakeStatus = sslEngine.getHandshakeStatus(); - SSLEngineResult.Status status = sslEngine.wrap(plainOut, cipherOut).getStatus(); - switch (status) { + LOGGER.debug("Handshake status is {} before wrapping", handshakeStatus); + SSLEngineResult result = sslEngine.wrap(plainOut, cipherOut); + LOGGER.debug("SSL engine result is {} after wrapping", result); + switch (result.getStatus()) { case OK: - handshakeStatus = runDelegatedTasks(sslEngine); cipherOut.flip(); while (cipherOut.hasRemaining()) { - channel.write(cipherOut); + int written = channel.write(cipherOut); + LOGGER.debug("Wrote {} byte(s)", written); } cipherOut.clear(); + if (result.getHandshakeStatus() == NEED_TASK) { + handshakeStatus = runDelegatedTasks(sslEngine); + } else { + handshakeStatus = result.getHandshakeStatus(); + } + break; case BUFFER_OVERFLOW: throw new SSLException("Buffer overflow during handshake"); default: - throw new SSLException("Unexpected status " + status); + throw new SSLException("Unexpected status " + result.getStatus()); } return handshakeStatus; } - static int bufferCopy(ByteBuffer from, ByteBuffer to) { - int maxTransfer = Math.min(to.remaining(), from.remaining()); - - ByteBuffer temporaryBuffer = from.duplicate(); - temporaryBuffer.limit(temporaryBuffer.position() + maxTransfer); - to.put(temporaryBuffer); - - from.position(from.position() + maxTransfer); - - return maxTransfer; - } - public static void write(WritableByteChannel socketChannel, SSLEngine engine, ByteBuffer plainOut, ByteBuffer cypherOut) throws IOException { while (plainOut.hasRemaining()) { cypherOut.clear(); diff --git a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java index 7c23a3c0e6..37cf436db4 100644 --- a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java +++ b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2021 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -28,9 +28,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.net.ssl.SSLContext; import java.io.IOException; -import java.security.NoSuchAlgorithmException; import java.util.Map; import java.util.UUID; import java.util.concurrent.TimeoutException; @@ -348,7 +346,4 @@ protected String generateExchangeName() { return "exchange" + UUID.randomUUID().toString(); } - protected SSLContext getSSLContext() throws NoSuchAlgorithmException { - return TestUtils.getSSLContext(); - } } diff --git a/src/test/java/com/rabbitmq/client/test/TestUtils.java b/src/test/java/com/rabbitmq/client/test/TestUtils.java index 7544893760..c488fcff6d 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtils.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtils.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2021 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -26,19 +26,15 @@ import org.junit.runners.model.Statement; import org.slf4j.LoggerFactory; -import javax.net.ssl.SSLContext; import java.io.IOException; import java.net.ServerSocket; -import java.security.NoSuchAlgorithmException; import java.time.Duration; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.concurrent.Callable; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import java.util.function.BooleanSupplier; import static org.junit.Assert.assertTrue; @@ -109,22 +105,6 @@ public static void abort(Connection connection) { } } - public static SSLContext getSSLContext() throws NoSuchAlgorithmException { - SSLContext c = null; - - // pick the first protocol available, preferring TLSv1.2, then TLSv1, - // falling back to SSLv3 if running on an ancient/crippled JDK - for (String proto : Arrays.asList("TLSv1.2", "TLSv1", "SSLv3")) { - try { - c = SSLContext.getInstance(proto); - return c; - } catch (NoSuchAlgorithmException x) { - // keep trying - } - } - throw new NoSuchAlgorithmException(); - } - public static TestRule atLeast38() { return new BrokerVersionTestRule("3.8.0"); } @@ -361,4 +341,27 @@ public interface CallableFunction { } + public static boolean basicGetBasicConsume(Connection connection, String queue, final CountDownLatch latch, int msgSize) + throws Exception { + Channel channel = connection.createChannel(); + channel.queueDeclare(queue, false, true, false, null); + channel.queuePurge(queue); + + channel.basicPublish("", queue, null, new byte[msgSize]); + + String tag = channel.basicConsume(queue, false, new DefaultConsumer(channel) { + + @Override + public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { + getChannel().basicAck(envelope.getDeliveryTag(), false); + latch.countDown(); + } + }); + + boolean messageReceived = latch.await(20, TimeUnit.SECONDS); + + channel.basicCancel(tag); + + return messageReceived; + } } diff --git a/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java index 9137213578..fe33af7dec 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2021 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,20 +15,13 @@ package com.rabbitmq.client.test.ssl; -import com.rabbitmq.client.test.TestUtils; import org.junit.Test; -import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLHandshakeException; -import javax.net.ssl.TrustManagerFactory; -import java.io.FileInputStream; import java.io.IOException; -import java.security.*; -import java.security.cert.CertificateException; import java.util.concurrent.TimeoutException; -import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; /** @@ -39,44 +32,10 @@ public class BadVerifiedConnection extends UnverifiedConnection { public void openConnection() throws IOException, TimeoutException { try { - String keystorePath = System.getProperty("test-keystore.empty"); - assertNotNull(keystorePath); - String keystorePasswd = System.getProperty("test-keystore.password"); - assertNotNull(keystorePasswd); - char [] keystorePassword = keystorePasswd.toCharArray(); - - KeyStore tks = KeyStore.getInstance("JKS"); - tks.load(new FileInputStream(keystorePath), keystorePassword); - - TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); - tmf.init(tks); - - String p12Path = System.getProperty("test-client-cert.path"); - assertNotNull(p12Path); - String p12Passwd = System.getProperty("test-client-cert.password"); - assertNotNull(p12Passwd); - KeyStore ks = KeyStore.getInstance("PKCS12"); - char [] p12Password = p12Passwd.toCharArray(); - ks.load(new FileInputStream(p12Path), p12Password); - - KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); - kmf.init(ks, p12Password); - - SSLContext c = getSSLContext(); - c.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); - - connectionFactory = TestUtils.connectionFactory(); + SSLContext c = TlsTestUtils.badVerifiedSslContext(); connectionFactory.useSslProtocol(c); - } catch (NoSuchAlgorithmException ex) { - throw new IOException(ex.toString()); - } catch (KeyManagementException ex) { - throw new IOException(ex.toString()); - } catch (KeyStoreException ex) { - throw new IOException(ex.toString()); - } catch (CertificateException ex) { - throw new IOException(ex.toString()); - } catch (UnrecoverableKeyException ex) { - throw new IOException(ex.toString()); + } catch (Exception ex) { + throw new IOException(ex); } try { diff --git a/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java index 36a66a940d..acbfe48260 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2021 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -24,17 +24,11 @@ import org.junit.runner.RunWith; import org.junit.runners.Parameterized; -import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLHandshakeException; -import javax.net.ssl.TrustManagerFactory; -import java.io.FileInputStream; -import java.security.KeyStore; import java.util.function.Consumer; -import static com.rabbitmq.client.test.TestUtils.getSSLContext; import static java.util.Collections.singletonList; -import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -73,32 +67,7 @@ private static Consumer enableHostnameVerification() { @BeforeClass public static void initCrypto() throws Exception { - String keystorePath = System.getProperty("test-keystore.ca"); - assertNotNull(keystorePath); - String keystorePasswd = System.getProperty("test-keystore.password"); - assertNotNull(keystorePasswd); - char[] keystorePassword = keystorePasswd.toCharArray(); - - KeyStore tks = KeyStore.getInstance("JKS"); - tks.load(new FileInputStream(keystorePath), keystorePassword); - - TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); - tmf.init(tks); - - String p12Path = System.getProperty("test-client-cert.path"); - assertNotNull(p12Path); - String p12Passwd = System.getProperty("test-client-cert.password"); - assertNotNull(p12Passwd); - - KeyStore ks = KeyStore.getInstance("PKCS12"); - char[] p12Password = p12Passwd.toCharArray(); - ks.load(new FileInputStream(p12Path), p12Password); - - KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); - kmf.init(ks, p12Password); - - sslContext = getSSLContext(); - sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); + sslContext = TlsTestUtils.verifiedSslContext(); } @Test(expected = SSLHandshakeException.class) diff --git a/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java index 29fe35899e..37048739e2 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2021 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -18,6 +18,10 @@ import com.rabbitmq.client.*; import com.rabbitmq.client.impl.nio.NioParams; import com.rabbitmq.client.test.BrokerTestCase; +import com.rabbitmq.client.test.TestUtils; +import java.util.concurrent.atomic.AtomicReference; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; import org.junit.Test; import org.slf4j.LoggerFactory; @@ -28,6 +32,8 @@ import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; +import static com.rabbitmq.client.test.TestUtils.basicGetBasicConsume; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -76,6 +82,29 @@ public void connectionGetConsume() throws Exception { assertTrue("Message has not been received", messagesReceived); } + @Test + public void connectionGetConsumeProtocols() throws Exception { + String [] protocols = new String[] {"TLSv1.2", "TLSv1.3"}; + for (String protocol : protocols) { + SSLContext sslContext = SSLContext.getInstance(protocol); + sslContext.init(null, new TrustManager[] {new TrustEverythingTrustManager()}, null); + ConnectionFactory cf = TestUtils.connectionFactory(); + cf.useSslProtocol(sslContext); + cf.useNio(); + AtomicReference engine = new AtomicReference<>(); + cf.setNioParams(new NioParams() + .setSslEngineConfigurator(sslEngine -> engine.set(sslEngine))); + try (Connection c = cf.newConnection()) { + CountDownLatch latch = new CountDownLatch(1); + basicGetBasicConsume(c, QUEUE, latch, 100); + boolean messagesReceived = latch.await(5, TimeUnit.SECONDS); + assertTrue("Message has not been received", messagesReceived); + assertThat(engine.get()).isNotNull(); + assertThat(engine.get().getEnabledProtocols()).contains(protocol); + } + } + } + @Test public void socketChannelConfigurator() throws Exception { ConnectionFactory connectionFactory = new ConnectionFactory(); connectionFactory.useNio(); @@ -119,28 +148,4 @@ private void sendAndVerifyMessage(int size) throws Exception { assertTrue("Message has not been received", messageReceived); } - private boolean basicGetBasicConsume(Connection connection, String queue, final CountDownLatch latch, int msgSize) - throws Exception { - Channel channel = connection.createChannel(); - channel.queueDeclare(queue, false, false, false, null); - channel.queuePurge(queue); - - channel.basicPublish("", queue, null, new byte[msgSize]); - - String tag = channel.basicConsume(queue, false, new DefaultConsumer(channel) { - - @Override - public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { - getChannel().basicAck(envelope.getDeliveryTag(), false); - latch.countDown(); - } - }); - - boolean messageReceived = latch.await(20, TimeUnit.SECONDS); - - channel.basicCancel(tag); - - return messageReceived; - } - } diff --git a/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java b/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java index 3aa6fbe330..4693525ea3 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2019-2021 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -65,7 +65,7 @@ public static Function> nio() { @Test public void certificateInfoAreProperlyExtracted() throws Exception { - SSLContext sslContext = TestUtils.getSSLContext(); + SSLContext sslContext = TlsTestUtils.getSSLContext(); sslContext.init(null, new TrustManager[]{new AlwaysTrustTrustManager()}, null); ConnectionFactory connectionFactory = TestUtils.connectionFactory(); connectionFactory.useSslProtocol(sslContext); diff --git a/src/test/java/com/rabbitmq/client/test/ssl/TlsTestUtils.java b/src/test/java/com/rabbitmq/client/test/ssl/TlsTestUtils.java new file mode 100644 index 0000000000..891bec7f04 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/ssl/TlsTestUtils.java @@ -0,0 +1,115 @@ +// Copyright (c) 2021 VMware, Inc. or its affiliates. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.test.ssl; + +import static org.junit.Assert.assertNotNull; + +import java.io.FileInputStream; +import java.security.KeyStore; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManagerFactory; + +class TlsTestUtils { + + private TlsTestUtils() {} + + static SSLContext badVerifiedSslContext() throws Exception { + return verifiedSslContext(() -> getSSLContext(), emptyKeystoreCa()); + } + + static SSLContext verifiedSslContext() throws Exception { + return verifiedSslContext(() -> getSSLContext(), keystoreCa()); + } + + static SSLContext verifiedSslContext(CallableSupplier sslContextSupplier) throws Exception { + return verifiedSslContext(sslContextSupplier, keystoreCa()); + } + + static SSLContext verifiedSslContext(CallableSupplier sslContextSupplier, String keystorePath) throws Exception { + // for local testing, run ./mvnw test-compile -Dtest-tls-certs.dir=/tmp/tls-gen/basic + // (generates the Java keystores) + assertNotNull(keystorePath); + String keystorePasswd = keystorePassword(); + assertNotNull(keystorePasswd); + char [] keystorePassword = keystorePasswd.toCharArray(); + + KeyStore tks = KeyStore.getInstance("JKS"); + tks.load(new FileInputStream(keystorePath), keystorePassword); + + TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); + tmf.init(tks); + + String p12Path = clientCertPath(); + assertNotNull(p12Path); + String p12Passwd = clientCertPassword(); + assertNotNull(p12Passwd); + KeyStore ks = KeyStore.getInstance("PKCS12"); + char [] p12Password = p12Passwd.toCharArray(); + ks.load(new FileInputStream(p12Path), p12Password); + + KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); + kmf.init(ks, p12Password); + + SSLContext c = sslContextSupplier.get(); + c.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); + return c; + } + + static String keystoreCa() { + return System.getProperty("test-keystore.ca", "./target/ca.keystore"); + } + + static String emptyKeystoreCa() { + return System.getProperty("test-keystore.empty", "./target/empty.keystore"); + } + + static String keystorePassword() { + return System.getProperty("test-keystore.password", "bunnies"); + } + + static String clientCertPath() { + return System.getProperty("test-client-cert.path", "/tmp/tls-gen/basic/client/keycert.p12"); + } + + static String clientCertPassword() { + return System.getProperty("test-client-cert.password", ""); + } + + public static SSLContext getSSLContext() throws NoSuchAlgorithmException { + SSLContext c; + + // pick the first protocol available, preferring TLSv1.2, then TLSv1, + // falling back to SSLv3 if running on an ancient/crippled JDK + for (String proto : Arrays.asList("TLSv1.3", "TLSv1.2", "TLSv1", "SSLv3")) { + try { + c = SSLContext.getInstance(proto); + return c; + } catch (NoSuchAlgorithmException x) { + // keep trying + } + } + throw new NoSuchAlgorithmException(); + } + + @FunctionalInterface + interface CallableSupplier { + + T get() throws Exception; + } +} diff --git a/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java index a14a257c24..39e1e90ba5 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2021 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -21,8 +21,6 @@ import org.slf4j.LoggerFactory; import java.io.IOException; -import java.security.KeyManagementException; -import java.security.NoSuchAlgorithmException; import java.util.concurrent.TimeoutException; import static org.junit.Assert.*; @@ -37,10 +35,8 @@ public void openConnection() throws IOException, TimeoutException { try { connectionFactory.useSslProtocol(); - } catch (NoSuchAlgorithmException ex) { - throw new IOException(ex.toString()); - } catch (KeyManagementException ex) { - throw new IOException(ex.toString()); + } catch (Exception ex) { + throw new IOException(ex); } int attempt = 0; diff --git a/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java index 50d4d9003b..0f82fb1194 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2021 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,25 +15,25 @@ package com.rabbitmq.client.test.ssl; -import static org.junit.Assert.assertNotNull; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import java.io.FileInputStream; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.impl.nio.NioParams; import java.io.IOException; -import java.security.KeyManagementException; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.UnrecoverableKeyException; -import java.security.cert.CertificateException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import javax.net.ssl.KeyManagerFactory; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Supplier; import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.SSLSocket; import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.test.TestUtils; +import org.junit.Test; import org.slf4j.LoggerFactory; /** @@ -45,44 +45,11 @@ public class VerifiedConnection extends UnverifiedConnection { public void openConnection() throws IOException, TimeoutException { try { - String keystorePath = System.getProperty("test-keystore.ca"); - assertNotNull(keystorePath); - String keystorePasswd = System.getProperty("test-keystore.password"); - assertNotNull(keystorePasswd); - char [] keystorePassword = keystorePasswd.toCharArray(); - - KeyStore tks = KeyStore.getInstance("JKS"); - tks.load(new FileInputStream(keystorePath), keystorePassword); - - TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); - tmf.init(tks); - - String p12Path = System.getProperty("test-client-cert.path"); - assertNotNull(p12Path); - String p12Passwd = System.getProperty("test-client-cert.password"); - assertNotNull(p12Passwd); - KeyStore ks = KeyStore.getInstance("PKCS12"); - char [] p12Password = p12Passwd.toCharArray(); - ks.load(new FileInputStream(p12Path), p12Password); - - KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); - kmf.init(ks, p12Password); - - SSLContext c = getSSLContext(); - c.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); - + SSLContext c = TlsTestUtils.verifiedSslContext(); connectionFactory = TestUtils.connectionFactory(); connectionFactory.useSslProtocol(c); - } catch (NoSuchAlgorithmException ex) { - throw new IOException(ex.toString()); - } catch (KeyManagementException ex) { - throw new IOException(ex.toString()); - } catch (KeyStoreException ex) { - throw new IOException(ex.toString()); - } catch (CertificateException ex) { - throw new IOException(ex.toString()); - } catch (UnrecoverableKeyException ex) { - throw new IOException(ex.toString()); + } catch (Exception ex) { + throw new IOException(ex); } int attempt = 0; @@ -99,4 +66,36 @@ public void openConnection() fail("Couldn't open TLS connection after 3 attempts"); } } + + @Test + public void connectionGetConsumeProtocols() throws Exception { + String [] protocols = new String[] {"TLSv1.2", "TLSv1.3"}; + for (String protocol : protocols) { + SSLContext sslContext = SSLContext.getInstance(protocol); + ConnectionFactory cf = TestUtils.connectionFactory(); + cf.useSslProtocol(TlsTestUtils.verifiedSslContext(() -> sslContext)); + AtomicReference> protocolsSupplier = new AtomicReference<>(); + if (TestUtils.USE_NIO) { + cf.useNio(); + cf.setNioParams(new NioParams() + .setSslEngineConfigurator(sslEngine -> { + protocolsSupplier.set(() -> sslEngine.getEnabledProtocols()); + })); + } else { + cf.setSocketConfigurator(socket -> { + SSLSocket s = (SSLSocket) socket; + protocolsSupplier.set(() -> s.getEnabledProtocols()); + }); + } + try (Connection c = cf.newConnection()) { + CountDownLatch latch = new CountDownLatch(1); + TestUtils.basicGetBasicConsume(c, VerifiedConnection.class.getName(), latch, 100); + boolean messagesReceived = latch.await(5, TimeUnit.SECONDS); + assertTrue("Message has not been received", messagesReceived); + assertThat(protocolsSupplier.get()).isNotNull(); + assertThat(protocolsSupplier.get().get()).contains(protocol); + } + } + } + } diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml index 4bd2e37606..ee88f442c2 100644 --- a/src/test/resources/logback-test.xml +++ b/src/test/resources/logback-test.xml @@ -5,7 +5,7 @@ - + \ No newline at end of file From 23961d5d0557a13105e099d2a90d90c4e96ab006 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 8 Nov 2021 09:32:24 +0100 Subject: [PATCH 1477/2114] Test TLS 1.3 only if available TLS 1.3 has not been backported to all Java version (e.g. on 9 and 10), so this commit checks if the protocol is available before running the test. References #715 --- .../client/test/ssl/NioTlsUnverifiedConnection.java | 8 +++++++- .../com/rabbitmq/client/test/ssl/TlsTestUtils.java | 12 ++++++++++++ .../rabbitmq/client/test/ssl/VerifiedConnection.java | 8 +++++++- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java index 37048739e2..bc143bc811 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java @@ -19,7 +19,10 @@ import com.rabbitmq.client.impl.nio.NioParams; import com.rabbitmq.client.test.BrokerTestCase; import com.rabbitmq.client.test.TestUtils; +import java.util.Collection; import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; +import java.util.stream.Stream; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import org.junit.Test; @@ -84,7 +87,10 @@ public void connectionGetConsume() throws Exception { @Test public void connectionGetConsumeProtocols() throws Exception { - String [] protocols = new String[] {"TLSv1.2", "TLSv1.3"}; + Collection availableProtocols = TlsTestUtils.availableTlsProtocols(); + Collection protocols = Stream.of("TLSv1.2", "TLSv1.3") + .filter(p -> availableProtocols.contains(p)) + .collect(Collectors.toList()); for (String protocol : protocols) { SSLContext sslContext = SSLContext.getInstance(protocol); sslContext.init(null, new TrustManager[] {new TrustEverythingTrustManager()}, null); diff --git a/src/test/java/com/rabbitmq/client/test/ssl/TlsTestUtils.java b/src/test/java/com/rabbitmq/client/test/ssl/TlsTestUtils.java index 891bec7f04..6e633ce664 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/TlsTestUtils.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/TlsTestUtils.java @@ -21,6 +21,8 @@ import java.security.KeyStore; import java.security.NoSuchAlgorithmException; import java.util.Arrays; +import java.util.Collection; +import java.util.stream.Collectors; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManagerFactory; @@ -107,6 +109,16 @@ public static SSLContext getSSLContext() throws NoSuchAlgorithmException { throw new NoSuchAlgorithmException(); } + static Collection availableTlsProtocols() { + try { + String[] protocols = SSLContext.getDefault().getSupportedSSLParameters().getProtocols(); + return Arrays.stream(protocols).filter(p -> p.toLowerCase().startsWith("tls")).collect( + Collectors.toList()); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + } + @FunctionalInterface interface CallableSupplier { diff --git a/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java index 0f82fb1194..9accac4459 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java @@ -22,12 +22,15 @@ import com.rabbitmq.client.Connection; import com.rabbitmq.client.impl.nio.NioParams; import java.io.IOException; +import java.util.Collection; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; +import java.util.stream.Collectors; +import java.util.stream.Stream; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocket; @@ -69,7 +72,10 @@ public void openConnection() @Test public void connectionGetConsumeProtocols() throws Exception { - String [] protocols = new String[] {"TLSv1.2", "TLSv1.3"}; + Collection availableProtocols = TlsTestUtils.availableTlsProtocols(); + Collection protocols = Stream.of("TLSv1.2", "TLSv1.3") + .filter(p -> availableProtocols.contains(p)) + .collect(Collectors.toList()); for (String protocol : protocols) { SSLContext sslContext = SSLContext.getInstance(protocol); ConnectionFactory cf = TestUtils.connectionFactory(); From b225fa9c3f0708991495d29e67db53348c977d87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 15 Nov 2021 10:28:03 +0100 Subject: [PATCH 1478/2114] Use 5.14.0 in readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a23e89e307..e525fba1e7 100644 --- a/README.md +++ b/README.md @@ -25,14 +25,14 @@ They require Java 8 or higher. com.rabbitmq amqp-client - 5.13.1 + 5.14.0 ``` ### Gradle ``` groovy -compile 'com.rabbitmq:amqp-client:5.13.1' +compile 'com.rabbitmq:amqp-client:5.14.0' ``` #### 4.x Series From 3d1c55c4c82ca112d304f4f9e87582d7052be07d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 15 Nov 2021 15:56:45 +0100 Subject: [PATCH 1479/2114] Bump Micrometer to 1.8.0 References #717 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a73d43b6f9..d6076abf43 100644 --- a/pom.xml +++ b/pom.xml @@ -56,7 +56,7 @@ 1.7.32 4.2.4 - 1.7.5 + 1.8.0 2.13.0 1.2.6 4.13.2 From 45f761eb7ce041bb1fd0eaf88282e68f0a3d2d4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 15 Nov 2021 15:57:28 +0100 Subject: [PATCH 1480/2114] Bump logback to 1.2.7 (test dependency) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d6076abf43..8327a2590f 100644 --- a/pom.xml +++ b/pom.xml @@ -58,7 +58,7 @@ 4.2.4 1.8.0 2.13.0 - 1.2.6 + 1.2.7 4.13.2 4.0.0 3.21.0 From ba4ebbaaf17bad8ebc7503bc01a38fc711930bf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 13 Dec 2021 11:23:34 +0100 Subject: [PATCH 1481/2114] Bump Maven Groovy Plugin to 2.1.1 To avoid error on Java 18, it fails because of the usage of the SecurityManager (deprecated). --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8327a2590f..9881e57609 100644 --- a/pom.xml +++ b/pom.xml @@ -70,7 +70,7 @@ 2.3 3.1.0 3.0.1 - 2.0 + 2.1.1 2.4.8 1.5 1.12 From 6aaa203aa979307e7dc9326b7d9f0f077d8cc390 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 13 Dec 2021 13:57:40 +0100 Subject: [PATCH 1482/2114] Use count down latch in test To avoid using Thread#stop(), which is deprecated since 1998. The test does not explain why or if Thread#stop() is necessary to the test. It's unlikely as the target thread has stopped already when stop is called in the test. --- .../rabbitmq/client/test/Bug20004Test.java | 89 ++++++++----------- 1 file changed, 39 insertions(+), 50 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/Bug20004Test.java b/src/test/java/com/rabbitmq/client/test/Bug20004Test.java index 63e237d4b1..d14e1d3e74 100644 --- a/src/test/java/com/rabbitmq/client/test/Bug20004Test.java +++ b/src/test/java/com/rabbitmq/client/test/Bug20004Test.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2021 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,66 +15,55 @@ package com.rabbitmq.client.test; -import org.junit.Test; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import java.io.IOException; - -import static org.junit.Assert.*; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import org.junit.Test; /** - * Test for bug 20004 - deadlock through internal synchronization on - * the channel object. This is more properly a unit test, but since it - * requires a connection to a broker, it's grouped with the functional - * tests. - *

- * Test calls channel.queueDeclare, while synchronising on channel, from - * an independent thread. + * Test for bug 20004 - deadlock through internal synchronization on the channel object. This is + * more properly a unit test, but since it requires a connection to a broker, it's grouped with the + * functional tests. + * + *

Test calls channel.queueDeclare, while synchronising on channel, from an independent thread. */ public class Bug20004Test extends BrokerTestCase { - private volatile Exception caughtException = null; - private volatile boolean completed = false; - private volatile boolean created = false; + private volatile Exception caughtException = null; + private volatile boolean created = false; - protected void releaseResources() - throws IOException - { - if (created) { - channel.queueDelete("Bug20004Test"); - } + protected void releaseResources() throws IOException { + if (created) { + channel.queueDelete("Bug20004Test"); } + } - @SuppressWarnings("deprecation") - @Test public void bug20004() throws IOException - { - final Bug20004Test testInstance = this; + @Test + public void bug20004() throws InterruptedException { + final Bug20004Test testInstance = this; + CountDownLatch completedLatch = new CountDownLatch(1); - Thread declaringThread = new Thread(new Runnable() { - public void run() { - try { - synchronized (channel) { - channel.queueDeclare("Bug20004Test", false, false, false, null); - testInstance.created = true; - } - } catch (Exception e) { - testInstance.caughtException = e; + Thread declaringThread = + new Thread( + () -> { + try { + synchronized (channel) { + channel.queueDeclare("Bug20004Test", false, false, false, null); + testInstance.created = true; } - testInstance.completed = true; - } - }); - declaringThread.start(); + } catch (Exception e) { + testInstance.caughtException = e; + } + completedLatch.countDown(); + }); + declaringThread.start(); - // poll (100ms) for `completed`, up to 5s - long endTime = System.currentTimeMillis() + 5000; - while (!completed && (System.currentTimeMillis() < endTime)) { - try { - Thread.sleep(100); - } catch (InterruptedException ie) {} - } + boolean completed = completedLatch.await(5, TimeUnit.SECONDS); - declaringThread.stop(); // see bug 20012. - - assertTrue("Deadlock detected?", completed); - assertNull("queueDeclare threw an exception", caughtException); - assertTrue("unknown sequence of events", created); - } + assertTrue("Deadlock detected?", completed); + assertNull("queueDeclare threw an exception", caughtException); + assertTrue("unknown sequence of events", created); + } } From 7eb4d3fe32a85234c629ef4493238fc677be0655 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 3 Jan 2022 10:53:02 +0100 Subject: [PATCH 1483/2114] Bump dependencies References #717 --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 9881e57609..0446db69a9 100644 --- a/pom.xml +++ b/pom.xml @@ -55,9 +55,9 @@ UTF-8 1.7.32 - 4.2.4 - 1.8.0 - 2.13.0 + 4.2.7 + 1.8.1 + 2.13.1 1.2.7 4.13.2 4.0.0 From 32dfd0fb338a3ff1db2c79dfeb42c9fd451284a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 3 Jan 2022 10:53:51 +0100 Subject: [PATCH 1484/2114] Bump test dependencies --- pom.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 0446db69a9..04b5aa8db7 100644 --- a/pom.xml +++ b/pom.xml @@ -58,12 +58,12 @@ 4.2.7 1.8.1 2.13.1 - 1.2.7 + 1.2.10 4.13.2 - 4.0.0 - 3.21.0 + 4.2.0 + 3.22.0 9.4.44.v20210927 - 1.69 + 1.70 3.2.0 2.5.3 From 2751d463918b201f36afd1356408272f544816ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 12 Jan 2022 16:56:41 +0100 Subject: [PATCH 1485/2114] Enforce connection timeout in NIO TLS handshake The handshake is in blocking mode and reading from a channel in this mode does not honor so_timeout but using temporary channels based on the socket input/output streams offers a decent workaround for this stage. Fixes #719 --- pom.xml | 8 ++ .../nio/SocketChannelFrameHandlerFactory.java | 16 +++- .../client/impl/nio/SslEngineHelper.java | 9 +- .../test/ssl/NioTlsUnverifiedConnection.java | 89 ++++++++++++++++--- 4 files changed, 101 insertions(+), 21 deletions(-) diff --git a/pom.xml b/pom.xml index 04b5aa8db7..5e5da78c9f 100644 --- a/pom.xml +++ b/pom.xml @@ -64,6 +64,7 @@ 3.22.0 9.4.44.v20210927 1.70 + 0.10 3.2.0 2.5.3 @@ -759,6 +760,13 @@ ${bouncycastle.version} test + + com.github.netcrusherorg + netcrusher-core + ${netcrusher.version} + test + + diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java index 10f550d70a..5e5b9016d1 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2022 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -21,6 +21,9 @@ import com.rabbitmq.client.impl.AbstractFrameHandlerFactory; import com.rabbitmq.client.impl.FrameHandler; import com.rabbitmq.client.impl.TlsUtils; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.WritableByteChannel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -95,14 +98,23 @@ public FrameHandler create(Address addr, String connectionName) throws IOExcepti channel.connect(address); + if (ssl) { + int initialSoTimeout = channel.socket().getSoTimeout(); + channel.socket().setSoTimeout(this.connectionTimeout); sslEngine.beginHandshake(); try { - boolean handshake = SslEngineHelper.doHandshake(channel, sslEngine); + ReadableByteChannel wrappedReadChannel = Channels.newChannel( + channel.socket().getInputStream()); + WritableByteChannel wrappedWriteChannel = Channels.newChannel( + channel.socket().getOutputStream()); + boolean handshake = SslEngineHelper.doHandshake( + wrappedWriteChannel, wrappedReadChannel, sslEngine); if (!handshake) { LOGGER.error("TLS connection failed"); throw new SSLException("TLS handshake failed"); } + channel.socket().setSoTimeout(initialSoTimeout); } catch (SSLHandshakeException e) { LOGGER.error("TLS connection failed: {}", e.getMessage()); throw e; diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java index bcefe8b205..b7a535da87 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2021 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2022 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -21,7 +21,6 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.ReadableByteChannel; -import java.nio.channels.SocketChannel; import java.nio.channels.WritableByteChannel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -38,7 +37,7 @@ public class SslEngineHelper { private static final Logger LOGGER = LoggerFactory.getLogger(SslEngineHelper.class); - public static boolean doHandshake(SocketChannel socketChannel, SSLEngine engine) throws IOException { + public static boolean doHandshake(WritableByteChannel writeChannel, ReadableByteChannel readChannel, SSLEngine engine) throws IOException { ByteBuffer plainOut = ByteBuffer.allocate(engine.getSession().getApplicationBufferSize()); ByteBuffer plainIn = ByteBuffer.allocate(engine.getSession().getApplicationBufferSize()); @@ -58,11 +57,11 @@ public static boolean doHandshake(SocketChannel socketChannel, SSLEngine engine) break; case NEED_UNWRAP: LOGGER.debug("Unwrapping..."); - handshakeStatus = unwrap(cipherIn, plainIn, socketChannel, engine); + handshakeStatus = unwrap(cipherIn, plainIn, readChannel, engine); break; case NEED_WRAP: LOGGER.debug("Wrapping..."); - handshakeStatus = wrap(plainOut, cipherOut, socketChannel, engine); + handshakeStatus = wrap(plainOut, cipherOut, writeChannel, engine); break; case FINISHED: break; diff --git a/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java index bc143bc811..522aa9b49b 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2021 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2022 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,31 +15,39 @@ package com.rabbitmq.client.test.ssl; -import com.rabbitmq.client.*; +import static com.rabbitmq.client.test.TestUtils.basicGetBasicConsume; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.TrustEverythingTrustManager; import com.rabbitmq.client.impl.nio.NioParams; import com.rabbitmq.client.test.BrokerTestCase; import com.rabbitmq.client.test.TestUtils; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.SocketTimeoutException; import java.util.Collection; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; import java.util.stream.Stream; import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; import javax.net.ssl.TrustManager; import org.junit.Test; +import org.netcrusher.core.reactor.NioReactor; +import org.netcrusher.tcp.TcpCrusher; +import org.netcrusher.tcp.TcpCrusherBuilder; import org.slf4j.LoggerFactory; -import javax.net.ssl.SSLEngine; -import java.io.IOException; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicBoolean; - -import static com.rabbitmq.client.test.TestUtils.basicGetBasicConsume; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - /** * */ @@ -148,6 +156,59 @@ public void connectionGetConsumeProtocols() throws Exception { } } + @Test + public void connectionShouldEnforceConnectionTimeout() throws Exception { + int amqpPort = 5671; // assumes RabbitMQ server running on localhost; + int amqpProxyPort = TestUtils.randomNetworkPort(); + + int connectionTimeout = 3_000; + int handshakeTimeout = 1_000; + + try (NioReactor reactor = new NioReactor(); + TcpCrusher tcpProxy = + TcpCrusherBuilder.builder() + .withReactor(reactor) + .withBindAddress(new InetSocketAddress(amqpProxyPort)) + .withConnectAddress("localhost", amqpPort) + .build()) { + + tcpProxy.open(); + tcpProxy.freeze(); + + ConnectionFactory factory = new ConnectionFactory(); + factory.setHost("localhost"); + factory.setPort(amqpProxyPort); + + factory.useSslProtocol(); + factory.useNio(); + + factory.setConnectionTimeout(connectionTimeout); + factory.setHandshakeTimeout(handshakeTimeout); + + ExecutorService executorService = Executors.newSingleThreadExecutor(); + try { + CountDownLatch latch = new CountDownLatch(1); + executorService.submit( + () -> { + try { + factory.newConnection(); + latch.countDown(); + } catch (SocketTimeoutException e) { + latch.countDown(); + } catch (Exception e) { + // not supposed to happen + } + }); + + boolean connectionCreatedTimedOut = latch.await(10, TimeUnit.SECONDS); + assertThat(connectionCreatedTimedOut).isTrue(); + + } finally { + executorService.shutdownNow(); + } + } + } + private void sendAndVerifyMessage(int size) throws Exception { CountDownLatch latch = new CountDownLatch(1); boolean messageReceived = basicGetBasicConsume(connection, QUEUE, latch, size); From 510389efde7a206dc29e6de70ca4e01764ac4c68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 12 Jan 2022 17:03:48 +0100 Subject: [PATCH 1486/2114] Set timeout on NIO connection Fixes #720 --- .../client/impl/nio/SocketChannelFrameHandlerFactory.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java index 5e5b9016d1..a482ace825 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java @@ -58,12 +58,11 @@ public class SocketChannelFrameHandlerFactory extends AbstractFrameHandlerFactor private final List nioLoopContexts; - public SocketChannelFrameHandlerFactory(int connectionTimeout, NioParams nioParams, boolean ssl, SslContextFactory sslContextFactory) - throws IOException { + public SocketChannelFrameHandlerFactory(int connectionTimeout, NioParams nioParams, boolean ssl, SslContextFactory sslContextFactory) { super(connectionTimeout, null, ssl); this.nioParams = new NioParams(nioParams); this.sslContextFactory = sslContextFactory; - this.nioLoopContexts = new ArrayList(this.nioParams.getNbIoThreads()); + this.nioLoopContexts = new ArrayList<>(this.nioParams.getNbIoThreads()); for (int i = 0; i < this.nioParams.getNbIoThreads(); i++) { this.nioLoopContexts.add(new NioLoopContext(this, this.nioParams)); } @@ -96,7 +95,7 @@ public FrameHandler create(Address addr, String connectionName) throws IOExcepti nioParams.getSocketChannelConfigurator().configure(channel); } - channel.connect(address); + channel.socket().connect(address, this.connectionTimeout); if (ssl) { From 42c4d613c0111a7500b769d04905a5c35773d953 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 13 Jan 2022 14:52:24 +0100 Subject: [PATCH 1487/2114] Bump dependencies References #717 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5e5da78c9f..2891a9c5e6 100644 --- a/pom.xml +++ b/pom.xml @@ -56,7 +56,7 @@ 1.7.32 4.2.7 - 1.8.1 + 1.8.2 2.13.1 1.2.10 4.13.2 From 96693b2ab81785d5394de92eb53317310b224f19 Mon Sep 17 00:00:00 2001 From: Chirag Date: Sat, 22 Jan 2022 23:54:06 -0500 Subject: [PATCH 1488/2114] added build status to readme.md Adding a build status to readme to give a quick glance information. --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index e525fba1e7..64ee6dde0d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,8 @@ # RabbitMQ Java Client +![Build Status](https://github.com/rabbitmq/rabbitmq-java-client/workflows/Build%20(Linux)/badge.svg?branch=main) + + This repository contains source code of the [RabbitMQ Java client](https://www.rabbitmq.com/api-guide.html). The client is maintained by the [RabbitMQ team at Pivotal](https://github.com/rabbitmq/). From 24fd5953bf81de43066d72a149c73b70b6c02edc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 3 Feb 2022 10:43:53 +0100 Subject: [PATCH 1489/2114] Use publish confirms in visibility effect test The test started to fail on a 2-node 3.10 cluster while it was OK before. The test expected messages to be almost immediately available in the queues after publishing, which is not realistic, as publishing is asynchronous. This commit enables publish confirms and waits for the confirms to arrive before purging and checking the content of the queues, which is more realistic in terms of expectations. The bulk of the test remains asynchronous in case it would hang like it used to do sometimes. --- .../server/EffectVisibilityCrossNodeTest.java | 43 ++++++++++++++++--- 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java b/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java index b4c9a0bc6a..0070d38c73 100644 --- a/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java +++ b/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java @@ -15,11 +15,15 @@ package com.rabbitmq.client.test.server; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; import java.io.IOException; +import java.util.Iterator; +import java.util.Set; import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicReference; import org.junit.Test; import com.rabbitmq.client.test.functional.ClusteredTestBase; @@ -31,16 +35,20 @@ public class EffectVisibilityCrossNodeTest extends ClusteredTestBase { private final String[] queues = new String[QUEUES]; + ExecutorService executorService; + @Override protected void createResources() throws IOException { for (int i = 0; i < queues.length ; i++) { queues[i] = alternateChannel.queueDeclare("", false, false, true, null).getQueue(); alternateChannel.queueBind(queues[i], "amq.fanout", ""); } + executorService = Executors.newSingleThreadExecutor(); } @Override protected void releaseResources() throws IOException { + executorService.shutdownNow(); for (int i = 0; i < queues.length ; i++) { alternateChannel.queueDelete(queues[i]); } @@ -53,14 +61,41 @@ protected void releaseResources() throws IOException { private static final byte[] msg = "".getBytes(); @Test public void effectVisibility() throws Exception { - ExecutorService executorService = Executors.newSingleThreadExecutor(); - try { + AtomicReference confirmLatch = new AtomicReference<>(); + Set publishIds = ConcurrentHashMap.newKeySet(); + channel.addConfirmListener( + (deliveryTag, multiple) -> { + if (multiple) { + Iterator iterator = publishIds.iterator(); + while (iterator.hasNext()) { + long publishId = iterator.next(); + if (publishId <= deliveryTag) { + iterator.remove(); + } + } + } else { + publishIds.remove(deliveryTag); + } + if (publishIds.isEmpty()) { + confirmLatch.get().countDown(); + } + }, + (deliveryTag, multiple) -> {}); + // the test bulk is asynchronous because this test has a history of hanging Future task = executorService.submit(() -> { + // we use publish confirm to make sure messages made it to the queues + // before checking their content + channel.confirmSelect(); for (int i = 0; i < BATCHES; i++) { Thread.sleep(10); // to avoid flow control for the connection + confirmLatch.set(new CountDownLatch(1)); for (int j = 0; j < MESSAGES_PER_BATCH; j++) { + long publishId = channel.getNextPublishSeqNo(); channel.basicPublish("amq.fanout", "", null, msg); + publishIds.add(publishId); } + assertThat(confirmLatch.get().await(10, TimeUnit.SECONDS)).isTrue(); + publishIds.clear(); for (int j = 0; j < queues.length; j++) { assertEquals(MESSAGES_PER_BATCH, channel.queuePurge(queues[j]).getMessageCount()); } @@ -68,9 +103,5 @@ protected void releaseResources() throws IOException { return null; }); task.get(1, TimeUnit.MINUTES); - } finally { - executorService.shutdownNow(); - executorService.awaitTermination(1, TimeUnit.SECONDS); - } } } From e237496c8eb08965d54b3c25d3866cdaedf31a16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 3 Feb 2022 11:30:47 +0100 Subject: [PATCH 1490/2114] Report unconfirmed messages in test --- .../client/test/server/EffectVisibilityCrossNodeTest.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java b/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java index 0070d38c73..17ac78e5d2 100644 --- a/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java +++ b/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java @@ -24,6 +24,7 @@ import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicReference; +import org.junit.Assert; import org.junit.Test; import com.rabbitmq.client.test.functional.ClusteredTestBase; @@ -94,7 +95,10 @@ protected void releaseResources() throws IOException { channel.basicPublish("amq.fanout", "", null, msg); publishIds.add(publishId); } - assertThat(confirmLatch.get().await(10, TimeUnit.SECONDS)).isTrue(); + boolean confirmed = confirmLatch.get().await(10, TimeUnit.SECONDS); + if (!confirmed) { + Assert.fail("Messages not confirmed in 10 seconds: " + publishIds); + } publishIds.clear(); for (int j = 0; j < queues.length; j++) { assertEquals(MESSAGES_PER_BATCH, channel.queuePurge(queues[j]).getMessageCount()); From 34b2f30a4bf6dac9cc3c24af752bd3de54aa4ce6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 3 Feb 2022 14:29:59 +0100 Subject: [PATCH 1491/2114] Register publish ID before sending message --- .../client/test/server/EffectVisibilityCrossNodeTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java b/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java index 17ac78e5d2..2a8dbe1df3 100644 --- a/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java +++ b/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java @@ -92,8 +92,8 @@ protected void releaseResources() throws IOException { confirmLatch.set(new CountDownLatch(1)); for (int j = 0; j < MESSAGES_PER_BATCH; j++) { long publishId = channel.getNextPublishSeqNo(); - channel.basicPublish("amq.fanout", "", null, msg); publishIds.add(publishId); + channel.basicPublish("amq.fanout", "", null, msg); } boolean confirmed = confirmLatch.get().await(10, TimeUnit.SECONDS); if (!confirmed) { From faeed579f4ecbed0664f10dbed04c774f8687aeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 3 Feb 2022 14:52:20 +0100 Subject: [PATCH 1492/2114] Retry until queue is fully purged The test remains flaky even with publish confirms. Purging the queue repeatedly until all published messages have been purged serves the same purpose of eventual visibility. --- .../server/EffectVisibilityCrossNodeTest.java | 69 +++++++------------ 1 file changed, 24 insertions(+), 45 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java b/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java index 2a8dbe1df3..bf3c56bf58 100644 --- a/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java +++ b/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java @@ -15,16 +15,11 @@ package com.rabbitmq.client.test.server; -import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; import java.io.IOException; -import java.util.Iterator; -import java.util.Set; import java.util.concurrent.*; -import java.util.concurrent.atomic.AtomicReference; -import org.junit.Assert; import org.junit.Test; import com.rabbitmq.client.test.functional.ClusteredTestBase; @@ -62,49 +57,33 @@ protected void releaseResources() throws IOException { private static final byte[] msg = "".getBytes(); @Test public void effectVisibility() throws Exception { - AtomicReference confirmLatch = new AtomicReference<>(); - Set publishIds = ConcurrentHashMap.newKeySet(); - channel.addConfirmListener( - (deliveryTag, multiple) -> { - if (multiple) { - Iterator iterator = publishIds.iterator(); - while (iterator.hasNext()) { - long publishId = iterator.next(); - if (publishId <= deliveryTag) { - iterator.remove(); - } - } - } else { - publishIds.remove(deliveryTag); - } - if (publishIds.isEmpty()) { - confirmLatch.get().countDown(); + // the test bulk is asynchronous because this test has a history of hanging + Future task = + executorService.submit( + () -> { + for (int i = 0; i < BATCHES; i++) { + Thread.sleep(10); // to avoid flow control for the connection + for (int j = 0; j < MESSAGES_PER_BATCH; j++) { + channel.basicPublish("amq.fanout", "", null, msg); } - }, - (deliveryTag, multiple) -> {}); - // the test bulk is asynchronous because this test has a history of hanging - Future task = executorService.submit(() -> { - // we use publish confirm to make sure messages made it to the queues - // before checking their content - channel.confirmSelect(); - for (int i = 0; i < BATCHES; i++) { - Thread.sleep(10); // to avoid flow control for the connection - confirmLatch.set(new CountDownLatch(1)); - for (int j = 0; j < MESSAGES_PER_BATCH; j++) { - long publishId = channel.getNextPublishSeqNo(); - publishIds.add(publishId); - channel.basicPublish("amq.fanout", "", null, msg); - } - boolean confirmed = confirmLatch.get().await(10, TimeUnit.SECONDS); - if (!confirmed) { - Assert.fail("Messages not confirmed in 10 seconds: " + publishIds); - } - publishIds.clear(); - for (int j = 0; j < queues.length; j++) { - assertEquals(MESSAGES_PER_BATCH, channel.queuePurge(queues[j]).getMessageCount()); + for (int j = 0; j < queues.length; j++) { + String queue = queues[j]; + long timeout = 10 * 1000; + long waited = 0; + int purged = 0; + while (waited < timeout) { + purged += channel.queuePurge(queue).getMessageCount(); + if (purged == MESSAGES_PER_BATCH) { + break; } + Thread.sleep(10); + waited += 10; + } + assertEquals("Queue " + queue + " should have been purged after 10 seconds", + MESSAGES_PER_BATCH, purged); } - return null; + } + return null; }); task.get(1, TimeUnit.MINUTES); } From 8d9f1ff8ce115cf719b571a10281403870e7966d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 4 Feb 2022 09:05:36 +0100 Subject: [PATCH 1493/2114] Log test execution start and end CI jobs hang regularly, this could help to tell whether the cause is the tests themselves or something in the CI environment. --- src/test/resources/logback-test.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml index ee88f442c2..596182704c 100644 --- a/src/test/resources/logback-test.xml +++ b/src/test/resources/logback-test.xml @@ -5,6 +5,8 @@ + + From f2e5a24bf078bfb3d95cc68dee221080bca7704f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 7 Feb 2022 11:18:22 +0100 Subject: [PATCH 1494/2114] Add logging to topic permissions test Test tends to hang on CI. --- .../client/test/server/TopicPermissions.java | 15 +++++++++++++++ src/test/resources/logback-test.xml | 1 + 2 files changed, 16 insertions(+) diff --git a/src/test/java/com/rabbitmq/client/test/server/TopicPermissions.java b/src/test/java/com/rabbitmq/client/test/server/TopicPermissions.java index 5b79de1387..323b9cba65 100644 --- a/src/test/java/com/rabbitmq/client/test/server/TopicPermissions.java +++ b/src/test/java/com/rabbitmq/client/test/server/TopicPermissions.java @@ -25,36 +25,45 @@ import java.io.IOException; import java.util.concurrent.Callable; import java.util.concurrent.TimeoutException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import static org.junit.Assert.fail; public class TopicPermissions extends BrokerTestCase { + private static final Logger LOGGER = LoggerFactory.getLogger(TopicPermissions.class); + String protectedTopic = "protected.topic"; String notProtectedTopic = "not.protected.topic"; String noneTopicExchange = "not.a.topic"; @Override protected boolean shouldRun() throws IOException { + LOGGER.debug("Checking if test should run"); return Host.isRabbitMqCtlCommandAvailable("set_topic_permissions"); } @Override protected void createResources() throws IOException, TimeoutException { + LOGGER.debug("Creating AMQP resources"); channel.exchangeDeclare(protectedTopic, BuiltinExchangeType.TOPIC); channel.exchangeDeclare(notProtectedTopic, BuiltinExchangeType.TOPIC); channel.exchangeDeclare(noneTopicExchange, BuiltinExchangeType.DIRECT); + LOGGER.debug("Setting permissions"); Host.rabbitmqctl("set_topic_permissions -p / guest " + protectedTopic + " \"^{username}\" \"^{username}\""); Host.rabbitmqctl("set_topic_permissions -p / guest " + noneTopicExchange + " \"^{username}\" \"^{username}\""); } @Override protected void releaseResources() throws IOException { + LOGGER.debug("Deleting AMQP resources"); channel.exchangeDelete(protectedTopic); channel.exchangeDelete(notProtectedTopic); channel.exchangeDelete(noneTopicExchange); + LOGGER.debug("Clearing permissions"); Host.rabbitmqctl("clear_topic_permissions -p / guest"); } @@ -107,14 +116,18 @@ public void topicPermissions() throws IOException { } void assertAccessOk(String description, Callable action) { + LOGGER.debug("Running '" + description + "'"); try { action.call(); } catch(Exception e) { fail(description + " (" + e.getMessage()+")"); + } finally { + LOGGER.debug("'" + description + "' done"); } } void assertAccessRefused(String description, Callable action) throws IOException { + LOGGER.debug("Running '" + description + "'"); try { action.call(); fail(description); @@ -126,6 +139,8 @@ void assertAccessRefused(String description, Callable action) throws IOExc openChannel(); } catch(Exception e) { fail("Unexpected exception: " + e.getMessage()); + } finally { + LOGGER.debug("'" + description + "' done"); } } } diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml index 596182704c..90ebf5307e 100644 --- a/src/test/resources/logback-test.xml +++ b/src/test/resources/logback-test.xml @@ -6,6 +6,7 @@ + From 6b2251fe05684f39eca99eb846179df4c0d91e7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 7 Feb 2022 12:04:20 +0100 Subject: [PATCH 1495/2114] Handle process better in Host The method to check if a command exists asks for the help of this command now (instead of checking if the command name is in the output of rabbitmqctl). This way we just have to check the exit code (0 if the command exists). We also use a timeout to wait for the end of the process. A test hangs on the CI environment, these changes try to fix this. --- src/test/java/com/rabbitmq/tools/Host.java | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/test/java/com/rabbitmq/tools/Host.java b/src/test/java/com/rabbitmq/tools/Host.java index e81aef9a93..74be79b66c 100644 --- a/src/test/java/com/rabbitmq/tools/Host.java +++ b/src/test/java/com/rabbitmq/tools/Host.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2022 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -28,12 +28,17 @@ import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.impl.NetworkConnection; import com.rabbitmq.client.test.TestUtils; +import java.util.concurrent.TimeUnit; import java.util.function.Predicate; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class Host { + private static final Logger LOGGER = LoggerFactory.getLogger(Host.class); + private static final String DOCKER_PREFIX = "DOCKER:"; private static final Pattern CONNECTION_NAME_PATTERN = Pattern.compile("\"connection_name\",\"(?[a-zA-Z0-9\\-]+)?\""); @@ -78,7 +83,14 @@ private static int waitForExitValue(Process pr) { public static Process executeCommandIgnoringErrors(String command) throws IOException { Process pr = executeCommandProcess(command); - waitForExitValue(pr); + boolean exited = false; + try { + exited = pr.waitFor(30, TimeUnit.SECONDS); + } catch (InterruptedException e) { + } + if (!exited) { + LOGGER.warn("Command '{}' did not finish in 30 seconds", command); + } return pr; } @@ -101,9 +113,9 @@ private static Process executeCommandProcess(String command) throws IOException } public static boolean isRabbitMqCtlCommandAvailable(String command) throws IOException { - Process process = rabbitmqctlIgnoreErrors(""); - String stderr = capture(process.getErrorStream()); - return stderr.contains(command); + Process process = rabbitmqctlIgnoreErrors(command + " --help"); + int exitValue = process.exitValue(); + return exitValue == 0; } public static Process rabbitmqctl(String command) throws IOException { From 17afacafdb58c37d987a5ad1eb1457c9ffbb7824 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 7 Feb 2022 14:30:53 +0100 Subject: [PATCH 1496/2114] Pump process inputs before checking completion Process completion methods can hang because internal buffers are full. This commit "pumps" the inputs before calling the completion method, which should help to finish properly the command call. --- src/test/java/com/rabbitmq/tools/Host.java | 69 ++++++++++++++++++---- 1 file changed, 58 insertions(+), 11 deletions(-) diff --git a/src/test/java/com/rabbitmq/tools/Host.java b/src/test/java/com/rabbitmq/tools/Host.java index 74be79b66c..ee3b6a59f3 100644 --- a/src/test/java/com/rabbitmq/tools/Host.java +++ b/src/test/java/com/rabbitmq/tools/Host.java @@ -54,25 +54,68 @@ public static String capture(InputStream is) return buff.toString(); } - public static Process executeCommand(String command) throws IOException + public static ProcessState executeCommand(String command) throws IOException { Process pr = executeCommandProcess(command); + InputStreamPumpState inputState = new InputStreamPumpState(pr.getInputStream()); + InputStreamPumpState errorState = new InputStreamPumpState(pr.getErrorStream()); - int ev = waitForExitValue(pr); + int ev = waitForExitValue(pr, inputState, errorState); + inputState.pump(); + errorState.pump(); if (ev != 0) { - String stdout = capture(pr.getInputStream()); - String stderr = capture(pr.getErrorStream()); throw new IOException("unexpected command exit value: " + ev + "\ncommand: " + command + "\n" + - "\nstdout:\n" + stdout + - "\nstderr:\n" + stderr + "\n"); + "\nstdout:\n" + inputState.buffer.toString() + + "\nstderr:\n" + errorState.buffer.toString() + "\n"); } - return pr; + return new ProcessState(pr, inputState, errorState); + } + + static class ProcessState { + + private final Process process; + private final InputStreamPumpState inputState; + private final InputStreamPumpState errorState; + + ProcessState(Process process, InputStreamPumpState inputState, + InputStreamPumpState errorState) { + this.process = process; + this.inputState = inputState; + this.errorState = errorState; + } + + private String output() { + return inputState.buffer.toString(); + } + + } + + private static class InputStreamPumpState { + + private final BufferedReader reader; + private final StringBuilder buffer; + + private InputStreamPumpState(InputStream in) { + this.reader = new BufferedReader(new InputStreamReader(in)); + this.buffer = new StringBuilder(); + } + + void pump() throws IOException { + String line; + while ((line = reader.readLine()) != null) { + buffer.append(line).append("\n"); + } + } + } - private static int waitForExitValue(Process pr) { + private static int waitForExitValue(Process pr, InputStreamPumpState inputState, + InputStreamPumpState errorState) throws IOException { while(true) { try { + inputState.pump(); + errorState.pump(); pr.waitFor(); break; } catch (InterruptedException ignored) {} @@ -83,6 +126,10 @@ private static int waitForExitValue(Process pr) { public static Process executeCommandIgnoringErrors(String command) throws IOException { Process pr = executeCommandProcess(command); + InputStreamPumpState inputState = new InputStreamPumpState(pr.getInputStream()); + InputStreamPumpState errorState = new InputStreamPumpState(pr.getErrorStream()); + inputState.pump(); + errorState.pump(); boolean exited = false; try { exited = pr.waitFor(30, TimeUnit.SECONDS); @@ -118,7 +165,7 @@ public static boolean isRabbitMqCtlCommandAvailable(String command) throws IOExc return exitValue == 0; } - public static Process rabbitmqctl(String command) throws IOException { + public static ProcessState rabbitmqctl(String command) throws IOException { return executeCommand(rabbitmqctlCommand() + rabbitmqctlNodenameArgument() + " " + command); @@ -142,7 +189,7 @@ public static void clearResourceAlarm(String source) throws IOException { rabbitmqctl("eval 'rabbit_alarm:clear_alarm({resource_limit, " + source + ", node()}).'"); } - public static Process invokeMakeTarget(String command) throws IOException { + public static ProcessState invokeMakeTarget(String command) throws IOException { File rabbitmqctl = new File(rabbitmqctlCommand()); return executeCommand(makeCommand() + " -C \'" + rabbitmqDir() + "\'" + @@ -307,7 +354,7 @@ public String toString() { } public static List listConnections() throws IOException { - String output = capture(rabbitmqctl("list_connections -q pid peer_port client_properties").getInputStream()); + String output = rabbitmqctl("list_connections -q pid peer_port client_properties").output(); // output (header line presence depends on broker version): // pid peer_port // 58713 From ed7a83aa1abe584025383f43ec6625b9cffa9cb3 Mon Sep 17 00:00:00 2001 From: Laurent Perez Date: Wed, 9 Feb 2022 15:14:19 +0100 Subject: [PATCH 1497/2114] topology : fix connection factory property evaluation --- .../java/com/rabbitmq/client/ConnectionFactoryConfigurator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java b/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java index d59770380e..66f4a3742d 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java @@ -210,7 +210,7 @@ public static void load(ConnectionFactory cf, Map properties, St } String topologyRecovery = lookUp(TOPOLOGY_RECOVERY_ENABLED, properties, prefix); if (topologyRecovery != null) { - cf.setTopologyRecoveryEnabled(Boolean.getBoolean(topologyRecovery)); + cf.setTopologyRecoveryEnabled(Boolean.valueOf(topologyRecovery)); } String networkRecoveryInterval = lookUp(CONNECTION_RECOVERY_INTERVAL, properties, prefix); if (networkRecoveryInterval != null) { From 5f4f49e7502177f1c7386647a2d4dd67a73df176 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 10 Feb 2022 10:36:31 +0100 Subject: [PATCH 1498/2114] Use 5.14.2 in readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 64ee6dde0d..8f6c466c54 100644 --- a/README.md +++ b/README.md @@ -28,14 +28,14 @@ They require Java 8 or higher. com.rabbitmq amqp-client - 5.14.0 + 5.14.2 ``` ### Gradle ``` groovy -compile 'com.rabbitmq:amqp-client:5.14.0' +compile 'com.rabbitmq:amqp-client:5.14.2' ``` #### 4.x Series From b613dc1f277de28de63caa6cd6e5bcdf2a0c0c10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 16 Feb 2022 09:24:57 +0100 Subject: [PATCH 1499/2114] Bump dependencies References #717 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 2891a9c5e6..6d3e5e843d 100644 --- a/pom.xml +++ b/pom.xml @@ -54,8 +54,8 @@ UTF-8 UTF-8 - 1.7.32 - 4.2.7 + 1.7.36 + 4.2.8 1.8.2 2.13.1 1.2.10 From 99c4e738b037a00b9eb1878847f4cc75e1188ccb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 16 Feb 2022 09:25:57 +0100 Subject: [PATCH 1500/2114] Bump test dependencies --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 6d3e5e843d..550a131b08 100644 --- a/pom.xml +++ b/pom.xml @@ -60,9 +60,9 @@ 2.13.1 1.2.10 4.13.2 - 4.2.0 + 4.3.1 3.22.0 - 9.4.44.v20210927 + 9.4.45.v20220203 1.70 0.10 From 02fba0c106c6f3fe4ff6d4ec505a27c09bc78aca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 21 Feb 2022 10:26:59 +0100 Subject: [PATCH 1501/2114] Add log before starting each test CI environment hangs sometimes, this should help diagnose if a test in particular is hanging. --- .../com/rabbitmq/client/test/ClientTests.java | 4 +- .../client/test/RequiredPropertiesSuite.java | 11 +++++ .../com/rabbitmq/client/test/TestUtils.java | 46 ++++++++++++++++++- .../test/functional/FunctionalTests.java | 2 +- .../rabbitmq/client/test/ssl/SSLTests.java | 15 +++++- src/test/resources/logback-test.xml | 3 ++ 6 files changed, 75 insertions(+), 6 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTests.java index 3f8945bebc..41d3d33393 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTests.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2022 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -23,7 +23,7 @@ import org.junit.runner.RunWith; import org.junit.runners.Suite; -@RunWith(Suite.class) +@RunWith(TestUtils.DefaultTestSuite.class) @Suite.SuiteClasses({ TableTest.class, LongStringTest.class, diff --git a/src/test/java/com/rabbitmq/client/test/RequiredPropertiesSuite.java b/src/test/java/com/rabbitmq/client/test/RequiredPropertiesSuite.java index b97a0b0af6..f8ab431800 100644 --- a/src/test/java/com/rabbitmq/client/test/RequiredPropertiesSuite.java +++ b/src/test/java/com/rabbitmq/client/test/RequiredPropertiesSuite.java @@ -1,18 +1,23 @@ package com.rabbitmq.client.test; import org.junit.runner.Runner; +import org.junit.runner.notification.RunNotifier; import org.junit.runners.Suite; import org.junit.runners.model.InitializationError; import org.junit.runners.model.RunnerBuilder; import java.util.ArrayList; import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * */ public class RequiredPropertiesSuite extends Suite { + private static final Logger LOGGER = LoggerFactory.getLogger(RequiredPropertiesSuite.class); + public RequiredPropertiesSuite(Class klass, RunnerBuilder builder) throws InitializationError { super(klass, builder); } @@ -41,4 +46,10 @@ protected List getChildren() { return super.getChildren(); } } + + @Override + protected void runChild(Runner runner, RunNotifier notifier) { + LOGGER.info("Running test {}", runner.getDescription().getDisplayName()); + super.runChild(runner, notifier); + } } diff --git a/src/test/java/com/rabbitmq/client/test/TestUtils.java b/src/test/java/com/rabbitmq/client/test/TestUtils.java index c488fcff6d..0c0ea49a89 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtils.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtils.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2021 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2022 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -19,11 +19,18 @@ import com.rabbitmq.client.impl.NetworkConnection; import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; import com.rabbitmq.tools.Host; +import java.util.List; import org.assertj.core.api.Assertions; import org.junit.AssumptionViolatedException; import org.junit.rules.TestRule; import org.junit.runner.Description; +import org.junit.runner.Runner; +import org.junit.runner.notification.RunNotifier; +import org.junit.runners.Suite; +import org.junit.runners.model.InitializationError; +import org.junit.runners.model.RunnerBuilder; import org.junit.runners.model.Statement; +import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; @@ -40,6 +47,8 @@ public class TestUtils { + private static final Logger LOGGER = LoggerFactory.getLogger(TestUtils.class); + public static final boolean USE_NIO = System.getProperty("use.nio") != null; public static ConnectionFactory connectionFactory() { @@ -364,4 +373,39 @@ public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProp return messageReceived; } + + public static class DefaultTestSuite extends Suite { + + + public DefaultTestSuite(Class klass, RunnerBuilder builder) + throws InitializationError { + super(klass, builder); + } + + public DefaultTestSuite(RunnerBuilder builder, Class[] classes) + throws InitializationError { + super(builder, classes); + } + + protected DefaultTestSuite(Class klass, Class[] suiteClasses) + throws InitializationError { + super(klass, suiteClasses); + } + + protected DefaultTestSuite(RunnerBuilder builder, Class klass, Class[] suiteClasses) + throws InitializationError { + super(builder, klass, suiteClasses); + } + + @Override + protected void runChild(Runner runner, RunNotifier notifier) { + LOGGER.info("Running test {}", runner.getDescription().getDisplayName()); + super.runChild(runner, notifier); + } + + protected DefaultTestSuite(Class klass, List runners) + throws InitializationError { + super(klass, runners); + } + } } diff --git a/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java b/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java index db87a38695..892f4977ba 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java +++ b/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2022 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java index 3d629d15ea..758d87118a 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2022 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -20,12 +20,15 @@ import com.rabbitmq.client.test.SslContextFactoryTest; import org.junit.runner.RunWith; import org.junit.runner.Runner; +import org.junit.runner.notification.RunNotifier; import org.junit.runners.Suite; import org.junit.runners.model.InitializationError; import org.junit.runners.model.RunnerBuilder; import java.util.ArrayList; import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; @RunWith(SSLTests.SslSuite.class) @Suite.SuiteClasses({ @@ -40,6 +43,8 @@ }) public class SSLTests { + private static final Logger LOGGER = LoggerFactory.getLogger(SSLTests.class); + // initialize system properties static{ new AbstractRMQTestSuite(){}; @@ -70,11 +75,17 @@ protected SslSuite(Class klass, List runners) throws InitializationEr @Override protected List getChildren() { if(!AbstractRMQTestSuite.requiredProperties() && !AbstractRMQTestSuite.isSSLAvailable()) { - return new ArrayList(); + return new ArrayList<>(); } else { return super.getChildren(); } } + + @Override + protected void runChild(Runner runner, RunNotifier notifier) { + LOGGER.info("Running test {}", runner.getDescription().getDisplayName()); + super.runChild(runner, notifier); + } } } diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml index 90ebf5307e..5874c1c8c4 100644 --- a/src/test/resources/logback-test.xml +++ b/src/test/resources/logback-test.xml @@ -5,6 +5,9 @@ + + + From 04bc4caed4a89b9da8e8815d1771e00ed189a79d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 25 Feb 2022 16:24:33 +0100 Subject: [PATCH 1502/2114] Copy element-list to package-list in Javadoc deployment For Java8-generated Javadoc to link correctly to the library Javadoc whatever Java version used to generate it. See https://bugs.openjdk.java.net/browse/JDK-8211194. --- deploy-javadoc.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/deploy-javadoc.sh b/deploy-javadoc.sh index 74878215e9..46cdb09398 100755 --- a/deploy-javadoc.sh +++ b/deploy-javadoc.sh @@ -5,6 +5,11 @@ TAG=$(git describe --exact-match --tags $(git log -n1 --pretty='%h')) make deps ./mvnw -q clean javadoc:javadoc -Dmaven.javadoc.failOnError=false + +if [ -e target/site/apidocs/element-list ] + then cp target/site/apidocs/element-list target/site/apidocs/package-list +fi + git co gh-pages rm -rf $DEPLOY_DIRECTORY/* cp -r target/site/apidocs/* $DEPLOY_DIRECTORY From 7e92c2df240f326c4afff3eb803cf1efeda65f9f Mon Sep 17 00:00:00 2001 From: David Ansari Date: Sun, 27 Feb 2022 15:19:59 +0100 Subject: [PATCH 1503/2114] Add tests for any-with-x and all-with-x for x-match binding argument in headers exchange --- .../functional/HeadersExchangeValidation.java | 6 +++ .../client/test/functional/Routing.java | 45 +++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/src/test/java/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java b/src/test/java/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java index b2eeee7719..e62dd04d0b 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java +++ b/src/test/java/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java @@ -47,6 +47,12 @@ public class HeadersExchangeValidation extends BrokerTestCase { arguments.put("x-match", "any"); succeedBind(queue, arguments); + + arguments.put("x-match", "all-with-x"); + succeedBind(queue, arguments); + + arguments.put("x-match", "any-with-x"); + succeedBind(queue, arguments); } private void failBind(String queue, HashMap arguments) { diff --git a/src/test/java/com/rabbitmq/client/test/functional/Routing.java b/src/test/java/com/rabbitmq/client/test/functional/Routing.java index 050eb379b0..45161acddc 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Routing.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Routing.java @@ -170,6 +170,7 @@ private void checkGet(String queue, boolean messageExpected) spec.put("h1", "12345"); spec.put("h2", "bar"); spec.put("h3", null); + spec.put("x-key-1", "bindings starting with x- get filtered out"); spec.put("x-match", "all"); channel.queueBind(Q1, "amq.match", "", spec); spec.put("x-match", "any"); @@ -226,6 +227,10 @@ private void checkGet(String queue, boolean messageExpected) map.put("h2", "quux"); channel.basicPublish("amq.match", "", props.build(), "8".getBytes()); + map.clear(); + map.put("x-key-1", "bindings starting with x- get filtered out"); + channel.basicPublish("amq.match", "", props.build(), "9".getBytes()); + checkGet(Q1, true); // 4 checkGet(Q1, false); @@ -240,6 +245,46 @@ private void checkGet(String queue, boolean messageExpected) checkGet(Q2, false); } + @Test public void headersWithXRouting() throws Exception { + Map spec = new HashMap(); + spec.put("x-key-1", "value-1"); + spec.put("x-key-2", "value-2"); + spec.put("x-match", "all-with-x"); + channel.queueBind(Q1, "amq.match", "", spec); + spec.put("x-match", "any-with-x"); + channel.queueBind(Q2, "amq.match", "", spec); + + AMQP.BasicProperties.Builder props = new AMQP.BasicProperties.Builder(); + channel.basicPublish("amq.match", "", props.build(), "0".getBytes()); + + Map map = new HashMap(); + props.headers(map); + + map.clear(); + map.put("x-key-1", "value-1"); + channel.basicPublish("amq.match", "", props.build(), "1".getBytes()); + + map.clear(); + map.put("x-key-1", "value-1"); + map.put("x-key-2", "value-2"); + channel.basicPublish("amq.match", "", props.build(), "2".getBytes()); + + map.clear(); + map.put("x-key-1", "value-1"); + map.put("x-key-2", "value-2"); + map.put("x-key-3", "value-3"); + channel.basicPublish("amq.match", "", props.build(), "3".getBytes()); + + checkGet(Q1, true); // 2 + checkGet(Q1, true); // 3 + checkGet(Q1, false); + + checkGet(Q2, true); // 1 + checkGet(Q2, true); // 2 + checkGet(Q2, true); // 3 + checkGet(Q2, false); + } + @Test public void basicReturn() throws IOException { channel.addReturnListener(makeReturnListener()); returnCell = new BlockingCell(); From 0b7d8f0b778aa1bbd7eb13e517abf84b2782fafe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 28 Feb 2022 09:57:24 +0100 Subject: [PATCH 1504/2114] Add test condition to test x-match=all-with-x Broker version >= 3.10. References #725 --- .../com/rabbitmq/client/test/TestUtils.java | 57 +++++++++++++++++++ .../functional/HeadersExchangeValidation.java | 13 +++-- .../client/test/functional/Routing.java | 13 ++++- 3 files changed, 76 insertions(+), 7 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/TestUtils.java b/src/test/java/com/rabbitmq/client/test/TestUtils.java index 0c0ea49a89..86605d71f9 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtils.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtils.java @@ -19,6 +19,11 @@ import com.rabbitmq.client.impl.NetworkConnection; import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; import com.rabbitmq.tools.Host; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.reflect.Method; import java.util.List; import org.assertj.core.api.Assertions; import org.junit.AssumptionViolatedException; @@ -130,6 +135,10 @@ public static boolean isVersion38orLater(Connection connection) { return atLeastVersion("3.8.0", connection); } + public static boolean isVersion310orLater(Connection connection) { + return atLeastVersion("3.10.0", connection); + } + private static boolean atLeastVersion(String expectedVersion, Connection connection) { String currentVersion = null; try { @@ -408,4 +417,52 @@ protected DefaultTestSuite(Class klass, List runners) super(klass, runners); } } + + @Target({ElementType.METHOD}) + @Retention(RetentionPolicy.RUNTIME) + public @interface TestExecutionCondition { + + Class[] value(); + + } + + interface ExecutionCondition { + + void check(Description description) throws Exception; + + } + + public static class BrokerAtLeast310Condition implements ExecutionCondition { + + private static final String VERSION = "3.10.0"; + + @Override + public void check(Description description) throws Exception { + try (Connection c = TestUtils.connectionFactory().newConnection()) { + if (!TestUtils.atLeastVersion(VERSION, c)) { + throw new AssumptionViolatedException("Broker version < " + VERSION + ", skipping."); + } + } + } + } + + public static class ExecutionConditionRule implements TestRule { + + @Override + public Statement apply(Statement base, Description description) { + return new Statement() { + @Override + public void evaluate() throws Throwable { + Method testMethod = description.getTestClass().getDeclaredMethod(description.getMethodName()); + TestExecutionCondition conditionAnnotation = testMethod.getAnnotation( + TestExecutionCondition.class); + if (conditionAnnotation != null) { + conditionAnnotation.value()[0].getConstructor().newInstance() + .check(description); + } + base.evaluate(); + } + }; + } + } } diff --git a/src/test/java/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java b/src/test/java/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java index e62dd04d0b..c82ed749b6 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java +++ b/src/test/java/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2022 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -17,6 +17,7 @@ import static org.junit.Assert.fail; +import com.rabbitmq.client.test.TestUtils; import java.io.IOException; import java.util.HashMap; @@ -48,11 +49,13 @@ public class HeadersExchangeValidation extends BrokerTestCase { arguments.put("x-match", "any"); succeedBind(queue, arguments); - arguments.put("x-match", "all-with-x"); - succeedBind(queue, arguments); + if (TestUtils.isVersion310orLater(connection)) { + arguments.put("x-match", "all-with-x"); + succeedBind(queue, arguments); - arguments.put("x-match", "any-with-x"); - succeedBind(queue, arguments); + arguments.put("x-match", "any-with-x"); + succeedBind(queue, arguments); + } } private void failBind(String queue, HashMap arguments) { diff --git a/src/test/java/com/rabbitmq/client/test/functional/Routing.java b/src/test/java/com/rabbitmq/client/test/functional/Routing.java index 45161acddc..30a643a918 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Routing.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Routing.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2022 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -21,6 +21,9 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.fail; +import com.rabbitmq.client.test.TestUtils.BrokerAtLeast310Condition; +import com.rabbitmq.client.test.TestUtils.ExecutionConditionRule; +import com.rabbitmq.client.test.TestUtils.TestExecutionCondition; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; @@ -28,6 +31,7 @@ import java.util.Map; import java.util.concurrent.TimeoutException; +import org.junit.Rule; import org.junit.Test; import com.rabbitmq.client.AMQP; @@ -36,10 +40,13 @@ import com.rabbitmq.client.ReturnListener; import com.rabbitmq.client.test.BrokerTestCase; import com.rabbitmq.utility.BlockingCell; +import org.junit.rules.TestRule; public class Routing extends BrokerTestCase { + @Rule public TestRule executionConditionRule = new ExecutionConditionRule(); + protected final String E = "MRDQ"; protected final String Q1 = "foo"; protected final String Q2 = "bar"; @@ -245,7 +252,9 @@ private void checkGet(String queue, boolean messageExpected) checkGet(Q2, false); } - @Test public void headersWithXRouting() throws Exception { + @Test + @TestExecutionCondition(BrokerAtLeast310Condition.class) + public void headersWithXRouting() throws Exception { Map spec = new HashMap(); spec.put("x-key-1", "value-1"); spec.put("x-key-2", "value-2"); From 357226bdcce67c1a2c2137270cac6bb13decab79 Mon Sep 17 00:00:00 2001 From: laststem Date: Thu, 10 Mar 2022 20:35:24 +0900 Subject: [PATCH 1505/2114] Add host description when throwing MissedHeartbeatException --- src/main/java/com/rabbitmq/client/impl/AMQConnection.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index e21f58447e..38bf8a8faf 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -742,7 +742,7 @@ private void readFrame(Frame frame) throws IOException { /** private API */ public void handleHeartbeatFailure() { Exception ex = new MissedHeartbeatException("Heartbeat missing with heartbeat = " + - _heartbeat + " seconds"); + _heartbeat + " seconds, for " + this.getHostAddress()); try { _exceptionHandler.handleUnexpectedConnectionDriverException(this, ex); shutdown(null, false, ex, true); @@ -837,7 +837,7 @@ private void handleSocketTimeout() throws SocketTimeoutException { // of the heartbeat setting in setHeartbeat above. if (++_missedHeartbeats > (2 * 4)) { throw new MissedHeartbeatException("Heartbeat missing with heartbeat = " + - _heartbeat + " seconds"); + _heartbeat + " seconds, for " + this.getHostAddress()); } } From 80440298e3179c28fcb1c4a398bd95b1858ce42b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 11 Mar 2022 11:38:17 +0100 Subject: [PATCH 1506/2114] Set -Dmaven.wagon.http.retryHandler.count=10 in .mvn/maven.config Trying to help download dependencing from CI. --- .mvn/maven.config | 1 + 1 file changed, 1 insertion(+) create mode 100644 .mvn/maven.config diff --git a/.mvn/maven.config b/.mvn/maven.config new file mode 100644 index 0000000000..f373d1de10 --- /dev/null +++ b/.mvn/maven.config @@ -0,0 +1 @@ +-Dmaven.wagon.http.retryHandler.count=10 From 1c8e421f82fe4a2397750f157b1c2dcd1a714e04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 11 Mar 2022 11:38:17 +0100 Subject: [PATCH 1507/2114] Set -Dmaven.wagon.http.retryHandler.count=10 in .mvn/maven.config Trying to help download dependencing from CI. --- .mvn/maven.config | 1 + 1 file changed, 1 insertion(+) create mode 100644 .mvn/maven.config diff --git a/.mvn/maven.config b/.mvn/maven.config new file mode 100644 index 0000000000..f373d1de10 --- /dev/null +++ b/.mvn/maven.config @@ -0,0 +1 @@ +-Dmaven.wagon.http.retryHandler.count=10 From 0c933cb2c659e014df60e07352f163ecbae1641a Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 11 Mar 2022 18:50:23 +0400 Subject: [PATCH 1508/2114] Wording --- src/main/java/com/rabbitmq/client/impl/AMQConnection.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index 38bf8a8faf..5d5fe414eb 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -741,8 +741,8 @@ private void readFrame(Frame frame) throws IOException { /** private API */ public void handleHeartbeatFailure() { - Exception ex = new MissedHeartbeatException("Heartbeat missing with heartbeat = " + - _heartbeat + " seconds, for " + this.getHostAddress()); + Exception ex = new MissedHeartbeatException("Detected missed server heartbeats, heartbeat interval: " + + _heartbeat + " seconds, RabbitMQ node hostname: " + this.getHostAddress()); try { _exceptionHandler.handleUnexpectedConnectionDriverException(this, ex); shutdown(null, false, ex, true); From 49c5e2cf5c55bf0a775550004a7e168eeea6d413 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 30 Mar 2022 15:15:13 +0200 Subject: [PATCH 1509/2114] Use available processor number for default thread count in consumer work service The current value is available processors times 2, which may be overkill nowadays. The commit also allows using the rabbitmq.amqp.client.availableProcessors system property value, which is convenient as it's configuration-based (no code changes required). Fixes #730 --- .../client/impl/ConsumerWorkService.java | 15 ++++++--- .../java/com/rabbitmq/client/impl/Utils.java | 31 +++++++++++++++++++ 2 files changed, 42 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/rabbitmq/client/impl/Utils.java diff --git a/src/main/java/com/rabbitmq/client/impl/ConsumerWorkService.java b/src/main/java/com/rabbitmq/client/impl/ConsumerWorkService.java index b3810aae2f..f607e816e3 100644 --- a/src/main/java/com/rabbitmq/client/impl/ConsumerWorkService.java +++ b/src/main/java/com/rabbitmq/client/impl/ConsumerWorkService.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2022 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -22,10 +22,13 @@ import java.util.concurrent.ThreadFactory; import com.rabbitmq.client.Channel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; final public class ConsumerWorkService { + private static final Logger LOGGER = LoggerFactory.getLogger(ConsumerWorkService.class); private static final int MAX_RUNNABLE_BLOCK_SIZE = 16; - private static final int DEFAULT_NUM_THREADS = Runtime.getRuntime().availableProcessors() * 2; + private static final int DEFAULT_NUM_THREADS = Math.max(1, Utils.availableProcessors()); private final ExecutorService executor; private final boolean privateExecutor; private final WorkPool workPool; @@ -33,8 +36,12 @@ final public class ConsumerWorkService { public ConsumerWorkService(ExecutorService executor, ThreadFactory threadFactory, int queueingTimeout, int shutdownTimeout) { this.privateExecutor = (executor == null); - this.executor = (executor == null) ? Executors.newFixedThreadPool(DEFAULT_NUM_THREADS, threadFactory) - : executor; + if (executor == null) { + LOGGER.debug("Creating executor service with {} thread(s) for consumer work service", DEFAULT_NUM_THREADS); + this.executor = Executors.newFixedThreadPool(DEFAULT_NUM_THREADS, threadFactory); + } else { + this.executor = executor; + } this.workPool = new WorkPool<>(queueingTimeout); this.shutdownTimeout = shutdownTimeout; } diff --git a/src/main/java/com/rabbitmq/client/impl/Utils.java b/src/main/java/com/rabbitmq/client/impl/Utils.java new file mode 100644 index 0000000000..d3e3412ee4 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/Utils.java @@ -0,0 +1,31 @@ +// Copyright (c) 2022 VMware, Inc. or its affiliates. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl; + +final class Utils { + + private static final int AVAILABLE_PROCESSORS = + Integer.parseInt( + System.getProperty( + "rabbitmq.amqp.client.availableProcessors", + String.valueOf(Runtime.getRuntime().availableProcessors()))); + + static int availableProcessors() { + return AVAILABLE_PROCESSORS; + } + + private Utils() {} +} From a2cd69c2335c4bb6268d89462a69b837f12b4ba3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 8 Apr 2022 14:28:54 +0200 Subject: [PATCH 1510/2114] Add dependabot --- .github/dependabot.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000..e17467e5f6 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +# Please see the documentation for all configuration options: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates +version: 2 +updates: + - package-ecosystem: "maven" + directory: "/" + schedule: + interval: "daily" + open-pull-requests-limit: 20 + ignore: + - dependency-name: "org.eclipse.jetty:jetty-servlet" + versions: ["[10.0,)"] From 2e7c0b67765af35ade4a34ef7dd3ab2126d8886b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Apr 2022 12:29:36 +0000 Subject: [PATCH 1511/2114] Bump groovy-all from 2.4.8 to 2.4.21 Bumps [groovy-all](https://github.com/apache/groovy) from 2.4.8 to 2.4.21. - [Release notes](https://github.com/apache/groovy/releases) - [Commits](https://github.com/apache/groovy/commits) --- updated-dependencies: - dependency-name: org.codehaus.groovy:groovy-all dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 550a131b08..f6ba1a1176 100644 --- a/pom.xml +++ b/pom.xml @@ -72,7 +72,7 @@ 3.1.0 3.0.1 2.1.1 - 2.4.8 + 2.4.21 1.5 1.12 3.8.1 From b5efec3aa54c2917abb580e09a69b8b6a42549db Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Apr 2022 12:29:38 +0000 Subject: [PATCH 1512/2114] Bump build-helper-maven-plugin from 1.12 to 3.3.0 Bumps [build-helper-maven-plugin](https://github.com/mojohaus/build-helper-maven-plugin) from 1.12 to 3.3.0. - [Release notes](https://github.com/mojohaus/build-helper-maven-plugin/releases) - [Commits](https://github.com/mojohaus/build-helper-maven-plugin/compare/build-helper-maven-plugin-1.12...build-helper-maven-plugin-3.3.0) --- updated-dependencies: - dependency-name: org.codehaus.mojo:build-helper-maven-plugin dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 550a131b08..9186dbe3a1 100644 --- a/pom.xml +++ b/pom.xml @@ -74,7 +74,7 @@ 2.1.1 2.4.8 1.5 - 1.12 + 3.3.0 3.8.1 2.22.2 2.22.2 From 62bd6694346cb6ec0ba5f74d1ff36a51ce5745b2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Apr 2022 12:29:42 +0000 Subject: [PATCH 1513/2114] Bump maven-gpg-plugin from 1.6 to 3.0.1 Bumps [maven-gpg-plugin](https://github.com/apache/maven-gpg-plugin) from 1.6 to 3.0.1. - [Release notes](https://github.com/apache/maven-gpg-plugin/releases) - [Commits](https://github.com/apache/maven-gpg-plugin/compare/maven-gpg-plugin-1.6...maven-gpg-plugin-3.0.1) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-gpg-plugin dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 550a131b08..db8e09d780 100644 --- a/pom.xml +++ b/pom.xml @@ -78,7 +78,7 @@ 3.8.1 2.22.2 2.22.2 - 1.6 + 3.0.1 3.0.2 3.2.0 0.0.6 From c3003452e604aa2307979bf5f1c21e432355f1c1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Apr 2022 12:30:46 +0000 Subject: [PATCH 1514/2114] Bump maven-source-plugin from 3.0.1 to 3.2.1 Bumps [maven-source-plugin](https://github.com/apache/maven-source-plugin) from 3.0.1 to 3.2.1. - [Release notes](https://github.com/apache/maven-source-plugin/releases) - [Commits](https://github.com/apache/maven-source-plugin/compare/maven-source-plugin-3.0.1...maven-source-plugin-3.2.1) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-source-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 550a131b08..de506ca164 100644 --- a/pom.xml +++ b/pom.xml @@ -70,7 +70,7 @@ 2.5.3 2.3 3.1.0 - 3.0.1 + 3.2.1 2.1.1 2.4.8 1.5 From 88b27c2cf36e7911f561cb01f61487b6e91b556f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Apr 2022 12:30:49 +0000 Subject: [PATCH 1515/2114] Bump sonar-maven-plugin from 3.5.0.1254 to 3.9.1.2184 Bumps [sonar-maven-plugin](https://github.com/SonarSource/sonar-scanner-maven) from 3.5.0.1254 to 3.9.1.2184. - [Release notes](https://github.com/SonarSource/sonar-scanner-maven/releases) - [Commits](https://github.com/SonarSource/sonar-scanner-maven/compare/3.5.0.1254...3.9.1.2184) --- updated-dependencies: - dependency-name: org.sonarsource.scanner.maven:sonar-maven-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 550a131b08..ab182ecabc 100644 --- a/pom.xml +++ b/pom.xml @@ -776,7 +776,7 @@ org.sonarsource.scanner.maven sonar-maven-plugin - 3.5.0.1254 + 3.9.1.2184 From 35c9fa41b7fb4a41d7c05f75dc2d04e8f0ae6e26 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Apr 2022 12:30:51 +0000 Subject: [PATCH 1516/2114] Bump logback-classic from 1.2.10 to 1.2.11 Bumps logback-classic from 1.2.10 to 1.2.11. --- updated-dependencies: - dependency-name: ch.qos.logback:logback-classic dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 550a131b08..fbf841eb9a 100644 --- a/pom.xml +++ b/pom.xml @@ -58,7 +58,7 @@ 4.2.8 1.8.2 2.13.1 - 1.2.10 + 1.2.11 4.13.2 4.3.1 3.22.0 From b488b5c5ea0203ca654924cdcde98a641da1ade0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Apr 2022 12:30:54 +0000 Subject: [PATCH 1517/2114] Bump checksum-maven-plugin from 1.8 to 1.11 Bumps [checksum-maven-plugin](https://github.com/nicoulaj/checksum-maven-plugin) from 1.8 to 1.11. - [Release notes](https://github.com/nicoulaj/checksum-maven-plugin/releases) - [Commits](https://github.com/nicoulaj/checksum-maven-plugin/compare/1.8...1.11) --- updated-dependencies: - dependency-name: net.nicoulaj.maven.plugins:checksum-maven-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 550a131b08..b2b0834d4e 100644 --- a/pom.xml +++ b/pom.xml @@ -83,7 +83,7 @@ 3.2.0 0.0.6 1.6.8 - 1.8 + 1.11 1.3 - javadoc-no-module-dir-java-11 - - [11,) - - - --no-module-directories - - - + + org.junit.jupiter + junit-jupiter-params test @@ -768,6 +778,18 @@ + + + + + org.junit + junit-bom + ${junit.jupiter.version} + pom + import + + + diff --git a/src/test/java/com/rabbitmq/client/AbstractJsonRpcTest.java b/src/test/java/com/rabbitmq/client/AbstractJsonRpcTest.java index 0b6bc20a68..ec9fbd2f39 100644 --- a/src/test/java/com/rabbitmq/client/AbstractJsonRpcTest.java +++ b/src/test/java/com/rabbitmq/client/AbstractJsonRpcTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2018-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -19,8 +19,8 @@ import com.rabbitmq.tools.jsonrpc.JsonRpcClient; import com.rabbitmq.tools.jsonrpc.JsonRpcMapper; import com.rabbitmq.tools.jsonrpc.JsonRpcServer; -import org.junit.After; -import org.junit.Before; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import java.util.Date; @@ -35,7 +35,7 @@ public abstract class AbstractJsonRpcTest { abstract JsonRpcMapper createMapper(); - @Before + @BeforeEach public void init() throws Exception { clientConnection = TestUtils.connectionFactory().newConnection(); clientChannel = clientConnection.createChannel(); @@ -57,7 +57,7 @@ public void init() throws Exception { service = client.createProxy(RpcService.class); } - @After + @AfterEach public void tearDown() throws Exception { if (server != null) { server.terminateMainloop(); diff --git a/src/test/java/com/rabbitmq/client/AmqpClientTestExtension.java b/src/test/java/com/rabbitmq/client/AmqpClientTestExtension.java new file mode 100644 index 0000000000..07e27a6838 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/AmqpClientTestExtension.java @@ -0,0 +1,237 @@ +// Copyright (c) 2023 VMware, Inc. or its affiliates. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client; + +import static org.junit.jupiter.api.extension.ConditionEvaluationResult.disabled; +import static org.junit.jupiter.api.extension.ConditionEvaluationResult.enabled; + +import com.rabbitmq.client.test.TestUtils; +import com.rabbitmq.client.test.functional.FunctionalTestSuite; +import com.rabbitmq.client.test.server.HaTestSuite; +import com.rabbitmq.client.test.server.LastHaTestSuite; +import com.rabbitmq.client.test.server.ServerTestSuite; +import com.rabbitmq.client.test.ssl.SslTestSuite; +import com.rabbitmq.tools.Host; +import java.io.File; +import java.lang.reflect.Field; +import java.net.Socket; +import java.util.Properties; +import org.junit.jupiter.api.extension.AfterEachCallback; +import org.junit.jupiter.api.extension.BeforeAllCallback; +import org.junit.jupiter.api.extension.BeforeEachCallback; +import org.junit.jupiter.api.extension.ConditionEvaluationResult; +import org.junit.jupiter.api.extension.ExecutionCondition; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ExtensionContext.Namespace; +import org.junit.jupiter.api.extension.ExtensionContext.Store; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AmqpClientTestExtension implements ExecutionCondition, BeforeAllCallback, + BeforeEachCallback, + AfterEachCallback { + + private static final Logger LOGGER = LoggerFactory.getLogger(AmqpClientTestExtension.class); + private static final Namespace NAMESPACE = Namespace.create(AmqpClientTestExtension.class); + + static { + Properties TESTS_PROPS = new Properties(System.getProperties()); + String make = System.getenv("MAKE"); + if (make != null) { + TESTS_PROPS.setProperty("make.bin", make); + } + try { + TESTS_PROPS.load(Host.class.getClassLoader().getResourceAsStream("config.properties")); + } catch (Exception e) { + System.out.println( + "\"build.properties\" or \"config.properties\" not found" + + " in classpath. Please copy \"build.properties\" and" + + " \"config.properties\" into src/test/resources. Ignore" + + " this message if running with ant."); + } finally { + System.setProperties(TESTS_PROPS); + } + } + + private static void maybeSetHaFieldValue(ExtensionContext context, boolean value) { + if (context.getTestClass().isPresent() && context.getTestInstance().isPresent()) { + try { + Field haField = findField(context.getTestClass().get(), "ha"); + if (haField != null) { + haField.setAccessible(true); + haField.set(context.getTestInstance().get(), value); + } + } catch (Exception e) { + // OK + } + } + } + + private static Field findField(Class clazz, String fieldName) { + try { + return clazz.getDeclaredField(fieldName); + } catch (NoSuchFieldException e) { + if (clazz.getSuperclass() != null) { + return findField(clazz.getSuperclass(), fieldName); + } + } + return null; + } + + private static boolean isFunctionalSuite(ExtensionContext context) { + return isTestSuite(context, FunctionalTestSuite.class); + } + + private static boolean isSslSuite(ExtensionContext context) { + return isTestSuite(context, SslTestSuite.class); + } + + private static boolean isServerSuite(ExtensionContext context) { + return isTestSuite(context, ServerTestSuite.class); + } + + private static boolean isHaSuite(ExtensionContext context) { + return isTestSuite(context, HaTestSuite.class); + } + + private static boolean isLastHaSuite(ExtensionContext context) { + return isTestSuite(context, LastHaTestSuite.class); + } + + private static boolean isTestSuite(ExtensionContext context, Class clazz) { + return context.getUniqueId().contains(clazz.getName()); + } + + public static boolean requiredProperties() { + /* Path to rabbitmqctl. */ + String rabbitmqctl = Host.rabbitmqctlCommand(); + if (rabbitmqctl == null) { + System.err.println( + "rabbitmqctl required; please set \"rabbitmqctl.bin\" system" + + " property"); + return false; + } + + return true; + } + + public static boolean isSSLAvailable() { + String sslClientCertsDir = System.getProperty("test-client-cert.path"); + String hostname = System.getProperty("broker.hostname"); + String port = System.getProperty("broker.sslport"); + if (sslClientCertsDir == null || hostname == null || port == null) { + return false; + } + + // If certificate is present and some server is listening on port 5671 + if (new File(sslClientCertsDir).exists() && + checkServerListening(hostname, Integer.parseInt(port))) { + return true; + } else { + return false; + } + } + + private static boolean checkServerListening(String host, int port) { + Socket s = null; + try { + s = new Socket(host, port); + return true; + } catch (Exception e) { + return false; + } finally { + if (s != null) { + try { + s.close(); + } catch (Exception e) { + } + } + } + } + + private static Store store(ExtensionContext context) { + return context.getRoot().getStore(NAMESPACE); + } + + private static boolean hasHaSuiteStarted(ExtensionContext context) { + return "true".equals(store(context).get("ha")); + } + + private static void markHaSuiteStarted(ExtensionContext context) { + store(context).put("ha", "true"); + } + + private static void markHaSuiteFinished(ExtensionContext context) { + store(context).remove("ha"); + } + + @Override + public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) { + // HA test suite must be checked first because it contains other test suites + if (isHaSuite(context)) { + return requiredProperties() ? enabled("Required properties available") + : disabled("Required properties not available"); + } else if (isServerSuite(context)) { + return requiredProperties() ? enabled("Required properties available") + : disabled("Required properties not available"); + } else if (isFunctionalSuite(context)) { + return requiredProperties() ? enabled("Required properties available") + : disabled("Required properties not available"); + } else if (isSslSuite(context)) { + return requiredProperties() && isSSLAvailable() ? enabled( + "Required properties and TLS available") + : disabled("Required properties or TLS not available"); + } + return enabled("ok"); + } + + @Override + public void beforeAll(ExtensionContext context) throws Exception { + if (isHaSuite(context) && !hasHaSuiteStarted(context)) { + LOGGER.info("Starting HA test suite"); + Host.rabbitmqctl("set_policy HA '.*' '{\"ha-mode\":\"all\"}'"); + markHaSuiteStarted(context); + } + if (isLastHaSuite(context)) { + LOGGER.info("HA suite done, clearing HA state"); + Host.rabbitmqctl("clear_policy HA"); + markHaSuiteFinished(context); + } + } + + @Override + public void beforeEach(ExtensionContext context) { + LOGGER.info( + "Starting test: {}.{} (nio? {}, HA? {})", + context.getTestClass().get().getSimpleName(), context.getTestMethod().get().getName(), + TestUtils.USE_NIO, + hasHaSuiteStarted(context) + ); + if (isHaSuite(context)) { + maybeSetHaFieldValue(context, true); + } + } + + @Override + public void afterEach(ExtensionContext context) { + LOGGER.info("Test finished: {}.{}", + context.getTestClass().get().getSimpleName(), context.getTestMethod().get().getName()); + if (isHaSuite(context)) { + maybeSetHaFieldValue(context, false); + } + } + +} diff --git a/src/test/java/com/rabbitmq/client/JacksonJsonRpcTest.java b/src/test/java/com/rabbitmq/client/JacksonJsonRpcTest.java index e7a57021d4..f926061f94 100644 --- a/src/test/java/com/rabbitmq/client/JacksonJsonRpcTest.java +++ b/src/test/java/com/rabbitmq/client/JacksonJsonRpcTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2018-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -18,16 +18,16 @@ import com.rabbitmq.tools.jsonrpc.JacksonJsonRpcMapper; import com.rabbitmq.tools.jsonrpc.JsonRpcException; import com.rabbitmq.tools.jsonrpc.JsonRpcMapper; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.lang.reflect.UndeclaredThrowableException; import java.util.Calendar; import java.util.Date; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; public class JacksonJsonRpcTest extends AbstractJsonRpcTest { diff --git a/src/test/java/com/rabbitmq/client/QueueingConsumer.java b/src/test/java/com/rabbitmq/client/QueueingConsumer.java index 33a033008f..9ecddaa67b 100644 --- a/src/test/java/com/rabbitmq/client/QueueingConsumer.java +++ b/src/test/java/com/rabbitmq/client/QueueingConsumer.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/impl/AMQConnectionRefreshCredentialsTest.java b/src/test/java/com/rabbitmq/client/impl/AMQConnectionRefreshCredentialsTest.java index 989ee69ffa..a5fce8a561 100644 --- a/src/test/java/com/rabbitmq/client/impl/AMQConnectionRefreshCredentialsTest.java +++ b/src/test/java/com/rabbitmq/client/impl/AMQConnectionRefreshCredentialsTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2019-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -18,12 +18,13 @@ import com.rabbitmq.client.Method; import com.rabbitmq.client.*; import com.rabbitmq.client.test.TestUtils; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.rules.TestRule; -import org.junit.runner.RunWith; +import com.rabbitmq.client.test.TestUtils.BrokerVersion; +import com.rabbitmq.client.test.TestUtils.BrokerVersionAtLeast; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.MockitoAnnotations; import java.io.IOException; import java.time.Duration; @@ -38,18 +39,27 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.*; -@RunWith(MockitoJUnitRunner.class) +@BrokerVersionAtLeast(BrokerVersion.RABBITMQ_3_8) public class AMQConnectionRefreshCredentialsTest { - @ClassRule - public static TestRule brokerVersionTestRule = TestUtils.atLeast38(); - @Mock CredentialsProvider credentialsProvider; @Mock CredentialsRefreshService refreshService; + AutoCloseable mocks; + + @BeforeEach + void init() { + mocks = MockitoAnnotations.openMocks(this); + } + + @AfterEach + void tearDown() throws Exception { + mocks.close(); + } + private static ConnectionFactory connectionFactoryThatSendsGarbageAfterUpdateSecret() { ConnectionFactory cf = new ConnectionFactory() { @Override diff --git a/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java b/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java index 3bd0cca640..2ad3681c52 100644 --- a/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java +++ b/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2019-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,10 +15,11 @@ package com.rabbitmq.client.impl; -import org.junit.After; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import org.mockito.junit.MockitoJUnitRunner; import org.mockito.stubbing.Answer; @@ -38,7 +39,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.*; -@RunWith(MockitoJUnitRunner.class) public class DefaultCredentialsRefreshServiceTest { @Mock @@ -49,11 +49,19 @@ public class DefaultCredentialsRefreshServiceTest { DefaultCredentialsRefreshService refreshService; - @After - public void tearDown() { + AutoCloseable mocks; + + @BeforeEach + void init() { + this.mocks = MockitoAnnotations.openMocks(this); + } + + @AfterEach + public void tearDown() throws Exception { if (refreshService != null) { refreshService.close(); } + mocks.close(); } @Test diff --git a/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java b/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java index 0a08125d8f..33614d78bd 100644 --- a/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java +++ b/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2019-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -27,9 +27,9 @@ import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.util.ssl.SslContextFactory; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManagerFactory; @@ -62,7 +62,7 @@ static boolean isJava13() { return javaVersion != null && javaVersion.startsWith("13."); } - @Before + @BeforeEach public void init() { if (isJava13()) { // for Java 13.0.7, see https://github.com/bcgit/bc-java/issues/941 @@ -70,7 +70,7 @@ public void init() { } } - @After + @AfterEach public void tearDown() throws Exception { if (isJava13()) { System.setProperty("keystore.pkcs12.keyProtectionAlgorithm", ""); diff --git a/src/test/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProviderTest.java b/src/test/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProviderTest.java index a65ed3b6ca..dfed27341d 100644 --- a/src/test/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProviderTest.java +++ b/src/test/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProviderTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2019-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,7 +15,7 @@ package com.rabbitmq.client.impl; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.time.Duration; import java.util.Set; diff --git a/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java b/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java index ea0d94c683..54a9acfe55 100644 --- a/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java +++ b/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2019-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,49 +15,43 @@ package com.rabbitmq.client.impl; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.io.*; import java.math.BigDecimal; import java.math.BigInteger; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; public class ValueWriterTest { - @Test(expected = IllegalArgumentException.class) - public void writingOverlyLargeBigDecimalShouldFail() - throws IOException { - - OutputStream outputStream = new OutputStream() { - @Override - public void write(int b) { - } - }; - - DataOutputStream dataOutputStream = new DataOutputStream(outputStream); - - ValueWriter valueWriter = new ValueWriter(dataOutputStream); - - valueWriter.writeFieldValue(new BigDecimal(Integer.MAX_VALUE).add(new BigDecimal(1))); - + @Test + public void writingOverlyLargeBigDecimalShouldFail() { + assertThatThrownBy(() -> { + OutputStream outputStream = new OutputStream() { + @Override + public void write(int b) { + } + }; + DataOutputStream dataOutputStream = new DataOutputStream(outputStream); + ValueWriter valueWriter = new ValueWriter(dataOutputStream); + valueWriter.writeFieldValue(new BigDecimal(Integer.MAX_VALUE).add(new BigDecimal(1))); + }).isInstanceOf(IllegalArgumentException.class); } - @Test(expected = IllegalArgumentException.class) - public void writingOverlyLargeScaleInBigDecimalShouldFail() - throws IOException { - - OutputStream outputStream = new OutputStream() { - @Override - public void write(int b) { - } - }; - - DataOutputStream dataOutputStream = new DataOutputStream(outputStream); - - ValueWriter valueWriter = new ValueWriter(dataOutputStream); - - valueWriter.writeFieldValue(new BigDecimal(BigInteger.ONE, 500)); + @Test + public void writingOverlyLargeScaleInBigDecimalShouldFail() { + assertThatThrownBy(() -> { + OutputStream outputStream = new OutputStream() { + @Override + public void write(int b) { + } + }; + DataOutputStream dataOutputStream = new DataOutputStream(outputStream); + ValueWriter valueWriter = new ValueWriter(dataOutputStream); + valueWriter.writeFieldValue(new BigDecimal(BigInteger.ONE, 500)); + }).isInstanceOf(IllegalArgumentException.class); } @Test diff --git a/src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java b/src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java index 4cc054ca88..54a49da485 100644 --- a/src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java +++ b/src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,15 +15,15 @@ package com.rabbitmq.client.impl; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.ArrayList; import java.util.List; -import org.junit.Test; +import org.junit.jupiter.api.Test; /** * Unit tests for {@link WorkPool} @@ -34,9 +34,8 @@ public class WorkPoolTests { /** * Test unknown key tolerated silently - * @throws Exception untested */ - @Test public void unknownKey() throws Exception{ + @Test public void unknownKey() { assertFalse(this.pool.addWorkItem("test", new Object())); } @@ -58,16 +57,15 @@ public class WorkPoolTests { assertEquals(1, workList.size()); assertEquals(one, workList.get(0)); - assertTrue("Should be made ready", this.pool.finishWorkBlock(key)); + assertTrue(this.pool.finishWorkBlock(key), "Should be made ready"); workList.clear(); key = this.pool.nextWorkBlock(workList, 1); - assertEquals("Work client key wrong", "test", key); - assertEquals("Wrong work delivered", two, workList.get(0)); - - assertFalse("Should not be made ready after this.", this.pool.finishWorkBlock(key)); + assertEquals("test", key, "Work client key wrong"); + assertEquals(two, workList.get(0), "Wrong work delivered"); - assertNull("Shouldn't be more work", this.pool.nextWorkBlock(workList, 1)); + assertFalse(this.pool.finishWorkBlock(key), "Should not be made ready after this."); + assertNull(this.pool.nextWorkBlock(workList, 1), "Shouldn't be more work"); } /** diff --git a/src/test/java/com/rabbitmq/client/test/AMQBuilderApiTest.java b/src/test/java/com/rabbitmq/client/test/AMQBuilderApiTest.java index 46241c38b3..a4b54c9fa7 100644 --- a/src/test/java/com/rabbitmq/client/test/AMQBuilderApiTest.java +++ b/src/test/java/com/rabbitmq/client/test/AMQBuilderApiTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -14,12 +14,12 @@ // info@rabbitmq.com. package com.rabbitmq.client.test; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; import java.io.IOException; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Method; @@ -38,7 +38,7 @@ public class AMQBuilderApiTest extends BrokerTestCase .build() ).getMethod(); - assertTrue("Channel should still be open.", channel.isOpen()); + assertTrue(channel.isOpen(), "Channel should still be open."); assertTrue(retVal instanceof AMQP.Exchange.DeclareOk); retVal = channel.rpc(new AMQP.Exchange.Delete.Builder() @@ -46,7 +46,7 @@ public class AMQBuilderApiTest extends BrokerTestCase .build() ).getMethod(); - assertTrue("Channel should still be open.", channel.isOpen()); + assertTrue(channel.isOpen(), "Channel should still be open."); assertTrue(retVal instanceof AMQP.Exchange.DeleteOk); } @@ -59,14 +59,14 @@ public class AMQBuilderApiTest extends BrokerTestCase .build() ); - assertTrue("Channel should still be open.", channel.isOpen()); + assertTrue(channel.isOpen(), "Channel should still be open."); channel.asyncRpc(new AMQP.Exchange.Delete.Builder() .exchange(XCHG_NAME) .build() ); - assertTrue("Channel should still be open.", channel.isOpen()); + assertTrue(channel.isOpen(), "Channel should still be open."); } @Test public void illFormedBuilder() diff --git a/src/test/java/com/rabbitmq/client/test/AMQChannelTest.java b/src/test/java/com/rabbitmq/client/test/AMQChannelTest.java index 0ea1a89c60..091e1b14c2 100644 --- a/src/test/java/com/rabbitmq/client/test/AMQChannelTest.java +++ b/src/test/java/com/rabbitmq/client/test/AMQChannelTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -23,9 +23,9 @@ import com.rabbitmq.client.impl.AMQCommand; import com.rabbitmq.client.impl.AMQConnection; import com.rabbitmq.client.impl.AMQImpl; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.util.concurrent.Callable; @@ -41,11 +41,11 @@ public class AMQChannelTest { ScheduledExecutorService scheduler; - @Before public void init() { + @BeforeEach public void init() { scheduler = Executors.newSingleThreadScheduledExecutor(); } - @After public void tearDown() { + @AfterEach public void tearDown() { scheduler.shutdownNow(); } diff --git a/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java b/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java index e36631de7c..de50c74542 100644 --- a/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java +++ b/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -20,9 +20,9 @@ import com.rabbitmq.client.impl.ConnectionParams; import com.rabbitmq.client.impl.Frame; import com.rabbitmq.client.impl.FrameHandler; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.net.InetAddress; @@ -36,8 +36,8 @@ import java.util.concurrent.Executors; import java.util.concurrent.TimeoutException; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; /** * Test suite for AMQConnection. @@ -51,14 +51,14 @@ public class AMQConnectionTest { private ConnectionFactory factory; private MyExceptionHandler exceptionHandler; - @Before public void setUp() { + @BeforeEach public void setUp() { _mockFrameHandler = new MockFrameHandler(); factory = TestUtils.connectionFactory(); exceptionHandler = new MyExceptionHandler(); factory.setExceptionHandler(exceptionHandler); } - @After public void tearDown() { + @AfterEach public void tearDown() { factory = null; _mockFrameHandler = null; } @@ -159,8 +159,8 @@ public class AMQConnectionTest { } assertEquals(1, this._mockFrameHandler.countHeadersSent()); List exceptionList = exceptionHandler.getHandledExceptions(); - assertEquals("Only one exception expected", 1, exceptionList.size()); - assertEquals("Wrong type of exception returned.", SocketTimeoutException.class, exceptionList.get(0).getClass()); + assertEquals(1, exceptionList.size(), "Only one exception expected"); + assertEquals(SocketTimeoutException.class, exceptionList.get(0).getClass(), "Wrong type of exception returned."); } @Test public void clientProvidedConnectionName() throws IOException, TimeoutException { diff --git a/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java b/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java deleted file mode 100644 index 922b6b9931..0000000000 --- a/src/test/java/com/rabbitmq/client/test/AbstractRMQTestSuite.java +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - -package com.rabbitmq.client.test; - -import com.rabbitmq.tools.Host; - -import java.io.File; -import java.io.IOException; -import java.net.Socket; -import java.util.Properties; - -public abstract class AbstractRMQTestSuite { - - static { - Properties TESTS_PROPS = new Properties(System.getProperties()); - String make = System.getenv("MAKE"); - if (make != null) - TESTS_PROPS.setProperty("make.bin", make); - try { - TESTS_PROPS.load(Host.class.getClassLoader().getResourceAsStream("config.properties")); - } catch (Exception e) { - System.out.println( - "\"build.properties\" or \"config.properties\" not found" + - " in classpath. Please copy \"build.properties\" and" + - " \"config.properties\" into src/test/resources. Ignore" + - " this message if running with ant."); - } finally { - System.setProperties(TESTS_PROPS); - } - } - - public static boolean requiredProperties() { - /* Path to rabbitmqctl. */ - String rabbitmqctl = Host.rabbitmqctlCommand(); - if (rabbitmqctl == null) { - System.err.println( - "rabbitmqctl required; please set \"rabbitmqctl.bin\" system" + - " property"); - return false; - } - - return true; - } - - public static boolean isSSLAvailable() { - String sslClientCertsDir = System.getProperty("test-client-cert.path"); - String hostname = System.getProperty("broker.hostname"); - String port = System.getProperty("broker.sslport"); - if (sslClientCertsDir == null || hostname == null || port == null) - return false; - - // If certificate is present and some server is listening on port 5671 - if (new File(sslClientCertsDir).exists() && - checkServerListening(hostname, Integer.parseInt(port))) { - return true; - } else - return false; - } - - private static boolean checkServerListening(String host, int port) { - Socket s = null; - try { - s = new Socket(host, port); - return true; - } catch (Exception e) { - return false; - } finally { - if (s != null) - try { - s.close(); - } catch (Exception e) { - } - } - } -} diff --git a/src/test/java/com/rabbitmq/client/test/AddressTest.java b/src/test/java/com/rabbitmq/client/test/AddressTest.java index 631dc5d986..bc9e860e8b 100644 --- a/src/test/java/com/rabbitmq/client/test/AddressTest.java +++ b/src/test/java/com/rabbitmq/client/test/AddressTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2018-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -16,11 +16,12 @@ package com.rabbitmq.client.test; import com.rabbitmq.client.Address; -import org.junit.Test; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * @@ -73,10 +74,11 @@ public class AddressTest { assertEquals(addr("[::1]", 5673), Address.parseAddress("[::1]:5673")); } - @Test(expected = IllegalArgumentException.class) + @Test public void parseUnquotedIPv6() { // using a non-quoted IPv6 addresses with a port - Address.parseAddress("::1:5673"); + Assertions.assertThatThrownBy(() -> Address.parseAddress("::1:5673")) + .isInstanceOf(IllegalArgumentException.class); } private Address addr(String addr) { diff --git a/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java b/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java index 92d4232934..5e41dfed3b 100644 --- a/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java +++ b/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,8 +15,8 @@ package com.rabbitmq.client.test; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; import java.net.URISyntaxException; import java.security.KeyManagementException; @@ -24,7 +24,7 @@ import java.util.HashMap; import java.util.Map; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.ConnectionFactory; diff --git a/src/test/java/com/rabbitmq/client/test/BlockingCellTest.java b/src/test/java/com/rabbitmq/client/test/BlockingCellTest.java index b5c7e9a3b0..03334570a6 100644 --- a/src/test/java/com/rabbitmq/client/test/BlockingCellTest.java +++ b/src/test/java/com/rabbitmq/client/test/BlockingCellTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -17,12 +17,12 @@ package com.rabbitmq.client.test; import com.rabbitmq.utility.BlockingCell; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; public class BlockingCellTest { diff --git a/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java b/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java index cdd06d02d3..069ee4dd98 100644 --- a/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java +++ b/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -23,9 +23,9 @@ import com.rabbitmq.client.impl.AMQImpl.Basic.Publish; import com.rabbitmq.client.impl.Frame; import com.rabbitmq.client.impl.FrameHandler; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.net.InetAddress; @@ -35,19 +35,19 @@ import java.util.List; import java.util.concurrent.Executors; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; public class BrokenFramesTest { private MyFrameHandler myFrameHandler; private ConnectionFactory factory; - @Before public void setUp() { + @BeforeEach public void setUp() { myFrameHandler = new MyFrameHandler(); factory = TestUtils.connectionFactory(); } - @After public void tearDown() { + @AfterEach public void tearDown() { factory = null; myFrameHandler = null; } diff --git a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java index 871a157b6b..46763e78cc 100644 --- a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java +++ b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java @@ -17,46 +17,24 @@ import com.rabbitmq.client.*; import com.rabbitmq.client.impl.nio.NioParams; -import com.rabbitmq.client.test.TestUtils.TestDescription; import com.rabbitmq.tools.Host; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.rules.TestRule; -import org.junit.rules.TestWatcher; -import org.junit.runner.Description; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.TestInfo; import java.io.IOException; import java.util.Map; import java.util.UUID; import java.util.concurrent.TimeoutException; -import static org.junit.Assert.*; -import static org.junit.Assume.*; +import static org.junit.jupiter.api.Assertions.*; public class BrokerTestCase { - @Rule - public TestDescription testDescription = new TestDescription(); + private boolean ha = false; - private static final Logger LOGGER = LoggerFactory.getLogger(BrokerTestCase.class); - - @Rule - public TestRule watcher = new TestWatcher() { - protected void starting(Description description) { - LOGGER.info( - "Starting test: {}.{} (nio? {})", - description.getTestClass().getSimpleName(), description.getMethodName(), TestUtils.USE_NIO - ); - } - - @Override - protected void finished(Description description) { - LOGGER.info("Test finished: {}.{}", description.getTestClass().getSimpleName(), description.getMethodName()); - } - }; + protected volatile TestInfo testInfo; protected ConnectionFactory connectionFactory = newConnectionFactory(); @@ -80,16 +58,19 @@ protected boolean isAutomaticRecoveryEnabled() { protected Connection connection; protected Channel channel; - @Before public void setUp() - throws IOException, TimeoutException { - assumeTrue(shouldRun()); + @BeforeEach + public void setUp(TestInfo testInfo) throws IOException, TimeoutException { + + + Assumptions.assumeTrue(shouldRun()); + this.testInfo = testInfo; openConnection(); openChannel(); createResources(); } - @After public void tearDown() + @AfterEach public void tearDown(TestInfo testInfo) throws IOException, TimeoutException { if(shouldRun()) { closeChannel(); @@ -135,9 +116,9 @@ protected void releaseResources() protected void restart() throws IOException, TimeoutException { - tearDown(); + tearDown(this.testInfo); bareRestart(); - setUp(); + setUp(this.testInfo); } protected void bareRestart() @@ -342,13 +323,13 @@ protected void unblock() throws IOException, InterruptedException { } protected String generateQueueName() { - return name("queue", this.testDescription.getDescription().getTestClass(), - this.testDescription.getDescription().getMethodName()); + return name("queue", this.testInfo.getTestClass().get(), + this.testInfo.getTestMethod().get().getName()); } protected String generateExchangeName() { - return name("exchange", this.testDescription.getDescription().getTestClass(), - this.testDescription.getDescription().getMethodName()); + return name("exchange", this.testInfo.getTestClass().get(), + this.testInfo.getTestMethod().get().getName()); } private static String name(String prefix, Class testClass, String testMethodName) { @@ -358,6 +339,8 @@ private static String name(String prefix, Class testClass, String testMethodN prefix, testClass.getSimpleName(), testMethodName, uuid.substring(uuid.length() / 2)); } - + protected boolean ha() { + return this.ha; + } } diff --git a/src/test/java/com/rabbitmq/client/test/Bug20004Test.java b/src/test/java/com/rabbitmq/client/test/Bug20004Test.java index d14e1d3e74..a62598165b 100644 --- a/src/test/java/com/rabbitmq/client/test/Bug20004Test.java +++ b/src/test/java/com/rabbitmq/client/test/Bug20004Test.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2021 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,13 +15,13 @@ package com.rabbitmq.client.test; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; -import org.junit.Test; +import org.junit.jupiter.api.Test; /** * Test for bug 20004 - deadlock through internal synchronization on the channel object. This is @@ -62,8 +62,8 @@ public void bug20004() throws InterruptedException { boolean completed = completedLatch.await(5, TimeUnit.SECONDS); - assertTrue("Deadlock detected?", completed); - assertNull("queueDeclare threw an exception", caughtException); - assertTrue("unknown sequence of events", created); + assertTrue(completed, "Deadlock detected?"); + assertNull(caughtException, "queueDeclare threw an exception"); + assertTrue(created, "unknown sequence of events"); } } diff --git a/src/test/java/com/rabbitmq/client/test/ChannelAsyncCompletableFutureTest.java b/src/test/java/com/rabbitmq/client/test/ChannelAsyncCompletableFutureTest.java index a871d49455..b3e5592dd4 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelAsyncCompletableFutureTest.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelAsyncCompletableFutureTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2017-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -19,15 +19,15 @@ import com.rabbitmq.client.DefaultConsumer; import com.rabbitmq.client.Envelope; import com.rabbitmq.client.impl.AMQImpl; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.util.UUID; import java.util.concurrent.*; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertTrue; public class ChannelAsyncCompletableFutureTest extends BrokerTestCase { diff --git a/src/test/java/com/rabbitmq/client/test/ChannelNTest.java b/src/test/java/com/rabbitmq/client/test/ChannelNTest.java index b1c9360ea5..76d44c816e 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelNTest.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelNTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2019-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -17,9 +17,9 @@ import com.rabbitmq.client.Method; import com.rabbitmq.client.impl.*; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.Mockito; import java.util.concurrent.ExecutorService; @@ -32,13 +32,13 @@ public class ChannelNTest { ConsumerWorkService consumerWorkService; ExecutorService executorService; - @Before + @BeforeEach public void init() { executorService = Executors.newSingleThreadExecutor(); consumerWorkService = new ConsumerWorkService(executorService, null, 1000, 1000); } - @After + @AfterEach public void tearDown() { consumerWorkService.shutdown(); executorService.shutdownNow(); diff --git a/src/test/java/com/rabbitmq/client/test/ChannelNumberAllocationTests.java b/src/test/java/com/rabbitmq/client/test/ChannelNumberAllocationTests.java index aa916529d7..76ecd0abda 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelNumberAllocationTests.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelNumberAllocationTests.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -18,16 +18,16 @@ import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; public class ChannelNumberAllocationTests { static final int CHANNEL_COUNT = 100; @@ -41,11 +41,11 @@ public int compare(Channel x, Channel y){ Connection connection; - @Before public void setUp() throws Exception{ + @BeforeEach public void setUp() throws Exception{ connection = TestUtils.connectionFactory().newConnection(); } - @After public void tearDown() throws Exception{ + @AfterEach public void tearDown() throws Exception{ connection.close(); connection = null; } @@ -81,10 +81,10 @@ public int compare(Channel x, Channel y){ // In the current implementation the allocated numbers need not be increasing Collections.sort(channels, COMPARATOR); - assertEquals("Didn't create the right number of channels!", CHANNEL_COUNT, channels.size()); + assertEquals(CHANNEL_COUNT, channels.size(), "Didn't create the right number of channels!"); for(int i = 1; i < CHANNEL_COUNT; ++i) { - assertTrue("Channel numbers should be distinct." - , channels.get(i-1).getChannelNumber() < channels.get(i).getChannelNumber() + assertTrue(channels.get(i-1).getChannelNumber() < channels.get(i).getChannelNumber(), + "Channel numbers should be distinct." ); } } diff --git a/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java b/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java index 2e9c4bf9ed..d2f3aafcba 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -17,9 +17,9 @@ import com.rabbitmq.client.*; import com.rabbitmq.client.impl.*; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import javax.net.SocketFactory; import java.io.IOException; @@ -36,12 +36,12 @@ public class ChannelRpcTimeoutIntegrationTest { ConnectionFactory factory; - @Before + @BeforeEach public void setUp() { factory = TestUtils.connectionFactory(); } - @After + @AfterEach public void tearDown() { factory = null; } diff --git a/src/test/java/com/rabbitmq/client/test/ClientTests.java b/src/test/java/com/rabbitmq/client/test/ClientTestSuite.java similarity index 89% rename from src/test/java/com/rabbitmq/client/test/ClientTests.java rename to src/test/java/com/rabbitmq/client/test/ClientTestSuite.java index 41d3d33393..33eb4aa8ed 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTests.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTestSuite.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2022 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -13,18 +13,16 @@ // If you have any questions regarding licensing, please contact us at // info@rabbitmq.com. - package com.rabbitmq.client.test; import com.rabbitmq.client.JacksonJsonRpcTest; import com.rabbitmq.client.impl.*; import com.rabbitmq.utility.IntAllocatorTests; +import org.junit.platform.suite.api.SelectClasses; +import org.junit.platform.suite.api.Suite; -import org.junit.runner.RunWith; -import org.junit.runners.Suite; - -@RunWith(TestUtils.DefaultTestSuite.class) -@Suite.SuiteClasses({ +@Suite +@SelectClasses({ TableTest.class, LongStringTest.class, BlockingCellTest.class, @@ -77,11 +75,6 @@ AMQConnectionRefreshCredentialsTest.class, ValueWriterTest.class }) -public class ClientTests { - - // initialize system properties - static{ - new AbstractRMQTestSuite(){}; - } +public class ClientTestSuite { } diff --git a/src/test/java/com/rabbitmq/client/test/ClientVersionTest.java b/src/test/java/com/rabbitmq/client/test/ClientVersionTest.java index c2c39284e3..3b66ec34fa 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientVersionTest.java +++ b/src/test/java/com/rabbitmq/client/test/ClientVersionTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2017-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -16,7 +16,7 @@ package com.rabbitmq.client.test; import com.rabbitmq.client.impl.ClientVersion; -import org.junit.Test; +import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/rabbitmq/client/test/ClonePropertiesTest.java b/src/test/java/com/rabbitmq/client/test/ClonePropertiesTest.java index aae4d10e28..0ba413e9e8 100644 --- a/src/test/java/com/rabbitmq/client/test/ClonePropertiesTest.java +++ b/src/test/java/com/rabbitmq/client/test/ClonePropertiesTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -17,10 +17,10 @@ import com.rabbitmq.client.AMQP.BasicProperties; import com.rabbitmq.client.MessageProperties; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; public class ClonePropertiesTest { diff --git a/src/test/java/com/rabbitmq/client/test/CloseInMainLoop.java b/src/test/java/com/rabbitmq/client/test/CloseInMainLoop.java index 00e9570136..b340f472c4 100644 --- a/src/test/java/com/rabbitmq/client/test/CloseInMainLoop.java +++ b/src/test/java/com/rabbitmq/client/test/CloseInMainLoop.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,7 +15,7 @@ package com.rabbitmq.client.test; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; import java.util.concurrent.CountDownLatch; @@ -25,7 +25,7 @@ import javax.net.SocketFactory; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; diff --git a/src/test/java/com/rabbitmq/client/test/ConfirmBase.java b/src/test/java/com/rabbitmq/client/test/ConfirmBase.java index 144ab68564..425965b17a 100644 --- a/src/test/java/com/rabbitmq/client/test/ConfirmBase.java +++ b/src/test/java/com/rabbitmq/client/test/ConfirmBase.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,7 +15,7 @@ package com.rabbitmq.client.test; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.fail; import java.io.IOException; import java.util.concurrent.ExecutionException; @@ -25,8 +25,8 @@ import java.util.concurrent.TimeoutException; import com.rabbitmq.client.ShutdownSignalException; +import org.opentest4j.AssertionFailedError; -import junit.framework.AssertionFailedError; public class ConfirmBase extends BrokerTestCase { protected void waitForConfirms() throws Exception diff --git a/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java b/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java index 54d2c2181c..e5aeccaacf 100644 --- a/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java +++ b/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -17,7 +17,7 @@ import com.rabbitmq.client.*; import com.rabbitmq.client.impl.*; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.util.List; diff --git a/src/test/java/com/rabbitmq/client/test/ConnectionTest.java b/src/test/java/com/rabbitmq/client/test/ConnectionTest.java index 8fb1c82059..e7233d6e86 100644 --- a/src/test/java/com/rabbitmq/client/test/ConnectionTest.java +++ b/src/test/java/com/rabbitmq/client/test/ConnectionTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2018-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -17,11 +17,12 @@ import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import org.mockito.Mock; import org.mockito.stubbing.OngoingStubbing; @@ -29,16 +30,13 @@ import java.util.NoSuchElementException; import java.util.Optional; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.mockito.MockitoAnnotations.openMocks; -@RunWith(Parameterized.class) public class ConnectionTest { - @Parameterized.Parameter - public TestConfigurator configurator; @Mock MyConnection c = mock(MyConnection.class); @Mock @@ -46,23 +44,23 @@ public class ConnectionTest { AutoCloseable mocks; - @Parameterized.Parameters public static Object[] configurators() { return new Object[]{new NotNumberedChannelCreationCallback(), new NumberedChannelCreationCallback()}; } - @Before + @BeforeEach public void init() { mocks = openMocks(this); } - @After + @AfterEach public void tearDown() throws Exception { mocks.close(); } - @Test - public void openChannelWithNonNullChannelShouldReturnNonEmptyOptional() throws Exception { + @ParameterizedTest + @MethodSource("configurators") + public void openChannelWithNonNullChannelShouldReturnNonEmptyOptional(TestConfigurator configurator) throws Exception { configurator.mockAndWhenChannel(c).thenReturn(ch); configurator.mockAndWhenOptional(c).thenCallRealMethod(); Optional optional = configurator.open(c); @@ -70,20 +68,24 @@ public void openChannelWithNonNullChannelShouldReturnNonEmptyOptional() throws E assertSame(ch, optional.get()); } - @Test(expected = NoSuchElementException.class) - public void openChannelWithNullChannelShouldReturnEmptyOptional() throws Exception { + @ParameterizedTest + @MethodSource("configurators") + public void openChannelWithNullChannelShouldReturnEmptyOptional(TestConfigurator configurator) throws Exception { configurator.mockAndWhenChannel(c).thenReturn(null); configurator.mockAndWhenOptional(c).thenCallRealMethod(); - Optional optional = configurator.open(c); - assertFalse(optional.isPresent()); - optional.get(); + Assertions.assertThatThrownBy(() -> { + Optional optional = configurator.open(c); + assertFalse(optional.isPresent()); + optional.get(); + }).isInstanceOf(NoSuchElementException.class); } - @Test(expected = IOException.class) - public void openChannelShouldPropagateIoException() throws Exception { + @ParameterizedTest + @MethodSource("configurators") + public void openChannelShouldPropagateIoException(TestConfigurator configurator) throws Exception { configurator.mockAndWhenChannel(c).thenThrow(IOException.class); configurator.mockAndWhenOptional(c).thenCallRealMethod(); - configurator.open(c); + Assertions.assertThatThrownBy(() -> configurator.open(c)).isInstanceOf(IOException.class); } interface TestConfigurator { diff --git a/src/test/java/com/rabbitmq/client/test/DefaultRetryHandlerTest.java b/src/test/java/com/rabbitmq/client/test/DefaultRetryHandlerTest.java index ae841b430b..363c7285c8 100644 --- a/src/test/java/com/rabbitmq/client/test/DefaultRetryHandlerTest.java +++ b/src/test/java/com/rabbitmq/client/test/DefaultRetryHandlerTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2018-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -23,9 +23,9 @@ import com.rabbitmq.client.impl.recovery.RecordedQueue; import com.rabbitmq.client.impl.recovery.RetryContext; import com.rabbitmq.client.impl.recovery.RetryHandler; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.Mock; import org.mockito.verification.VerificationMode; @@ -33,8 +33,8 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.function.BiPredicate; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.intThat; @@ -75,12 +75,12 @@ public class DefaultRetryHandlerTest { AutoCloseable mocks; - @Before + @BeforeEach public void init() { mocks = openMocks(this); } - @After + @AfterEach public void tearDown() throws Exception { mocks.close(); } diff --git a/src/test/java/com/rabbitmq/client/test/DnsRecordIpAddressResolverTests.java b/src/test/java/com/rabbitmq/client/test/DnsRecordIpAddressResolverTests.java index 5c38d5c8da..c339bf34e8 100644 --- a/src/test/java/com/rabbitmq/client/test/DnsRecordIpAddressResolverTests.java +++ b/src/test/java/com/rabbitmq/client/test/DnsRecordIpAddressResolverTests.java @@ -3,13 +3,13 @@ import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.DnsRecordIpAddressResolver; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.net.UnknownHostException; import java.util.concurrent.TimeoutException; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.fail; /** * diff --git a/src/test/java/com/rabbitmq/client/test/DnsSrvRecordAddressResolverTest.java b/src/test/java/com/rabbitmq/client/test/DnsSrvRecordAddressResolverTest.java index 4950cc2323..839fb16fe4 100644 --- a/src/test/java/com/rabbitmq/client/test/DnsSrvRecordAddressResolverTest.java +++ b/src/test/java/com/rabbitmq/client/test/DnsSrvRecordAddressResolverTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -17,7 +17,7 @@ import com.rabbitmq.client.Address; import com.rabbitmq.client.DnsSrvRecordAddressResolver; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.util.Arrays; diff --git a/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java b/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java index 2b84a1e91a..db10bd696b 100644 --- a/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java +++ b/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -19,10 +19,11 @@ import com.rabbitmq.client.MalformedFrameException; import com.rabbitmq.client.impl.Frame; import com.rabbitmq.client.impl.nio.FrameBuilder; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.MockitoAnnotations; import java.io.IOException; import java.nio.ByteBuffer; @@ -34,7 +35,6 @@ /** * */ -@RunWith(MockitoJUnitRunner.class) public class FrameBuilderTest { @Mock @@ -44,6 +44,18 @@ public class FrameBuilderTest { FrameBuilder builder; + AutoCloseable mocks; + + @BeforeEach + void init() { + this.mocks = MockitoAnnotations.openMocks(this); + } + + @AfterEach + void tearDown() throws Exception { + mocks.close(); + } + @Test public void buildFrameInOneGo() throws IOException { buffer = ByteBuffer.wrap(new byte[] { 1, 0, 0, 0, 0, 0, 3, 1, 2, 3, end() }); diff --git a/src/test/java/com/rabbitmq/client/test/FrameTest.java b/src/test/java/com/rabbitmq/client/test/FrameTest.java index e78ec48a70..fae132263b 100644 --- a/src/test/java/com/rabbitmq/client/test/FrameTest.java +++ b/src/test/java/com/rabbitmq/client/test/FrameTest.java @@ -3,7 +3,7 @@ import com.rabbitmq.client.AMQP; import com.rabbitmq.client.impl.Frame; import com.rabbitmq.client.impl.nio.ByteBufferOutputStream; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.io.DataOutputStream; import java.io.IOException; diff --git a/src/test/java/com/rabbitmq/client/test/GeneratedClassesTest.java b/src/test/java/com/rabbitmq/client/test/GeneratedClassesTest.java index 78919bbca6..d8b139e7d7 100644 --- a/src/test/java/com/rabbitmq/client/test/GeneratedClassesTest.java +++ b/src/test/java/com/rabbitmq/client/test/GeneratedClassesTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2018-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -17,14 +17,14 @@ import com.rabbitmq.client.AMQP; import com.rabbitmq.client.impl.AMQImpl; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.util.Calendar; import java.util.Date; import static java.util.Collections.singletonMap; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; /** * diff --git a/src/test/java/com/rabbitmq/client/test/JavaNioTest.java b/src/test/java/com/rabbitmq/client/test/JavaNioTest.java index 0d143e86e8..925c31ed55 100644 --- a/src/test/java/com/rabbitmq/client/test/JavaNioTest.java +++ b/src/test/java/com/rabbitmq/client/test/JavaNioTest.java @@ -5,9 +5,9 @@ import com.rabbitmq.client.impl.nio.DefaultByteBufferFactory; import com.rabbitmq.client.impl.nio.NioParams; import org.assertj.core.api.Condition; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.nio.ByteBuffer; @@ -16,8 +16,8 @@ import java.util.concurrent.atomic.AtomicInteger; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * @@ -28,14 +28,14 @@ public class JavaNioTest { private Connection testConnection; - @Before + @BeforeEach public void init() throws Exception { ConnectionFactory connectionFactory = new ConnectionFactory(); connectionFactory.useNio(); testConnection = connectionFactory.newConnection(); } - @After + @AfterEach public void tearDown() throws Exception { if (testConnection != null) { testConnection.createChannel().queueDelete(QUEUE); @@ -52,7 +52,7 @@ public void connection() throws Exception { try { connection = basicGetBasicConsume(connectionFactory, "nio.queue", latch); boolean messagesReceived = latch.await(5, TimeUnit.SECONDS); - assertTrue("Message has not been received", messagesReceived); + assertTrue(messagesReceived, "Message has not been received"); } finally { safeClose(connection); } @@ -71,7 +71,7 @@ public void twoConnections() throws IOException, TimeoutException, InterruptedEx connection2 = basicGetBasicConsume(connectionFactory, "nio.queue.2", latch); boolean messagesReceived = latch.await(5, TimeUnit.SECONDS); - assertTrue("Messages have not been received", messagesReceived); + assertTrue(messagesReceived, "Messages have not been received"); } finally { safeClose(connection1); safeClose(connection2); @@ -91,7 +91,7 @@ public void twoConnectionsWithNioExecutor() throws IOException, TimeoutException connection2 = basicGetBasicConsume(connectionFactory, "nio.queue.2", latch); boolean messagesReceived = latch.await(5, TimeUnit.SECONDS); - assertTrue("Messages have not been received", messagesReceived); + assertTrue(messagesReceived, "Messages have not been received"); } finally { safeClose(connection1); safeClose(connection2); @@ -114,7 +114,7 @@ public void shutdownCompleted(ShutdownSignalException cause) { } }); safeClose(connection); - assertTrue("Shutdown listener should have been called", latch.await(5, TimeUnit.SECONDS)); + assertTrue(latch.await(5, TimeUnit.SECONDS), "Shutdown listener should have been called"); } finally { safeClose(connection); } @@ -194,7 +194,7 @@ public void customWriteQueue() throws Exception { private void sendAndVerifyMessage(Connection connection, int size) throws Exception { CountDownLatch latch = new CountDownLatch(1); boolean messageReceived = basicGetBasicConsume(connection, QUEUE, latch, size); - assertTrue("Message has not been received", messageReceived); + assertTrue(messageReceived, "Message has not been received"); } private Connection basicGetBasicConsume(ConnectionFactory connectionFactory, String queue, final CountDownLatch latch) diff --git a/src/test/java/com/rabbitmq/client/test/LambdaCallbackTest.java b/src/test/java/com/rabbitmq/client/test/LambdaCallbackTest.java index 0f30f4f83a..68390b0631 100644 --- a/src/test/java/com/rabbitmq/client/test/LambdaCallbackTest.java +++ b/src/test/java/com/rabbitmq/client/test/LambdaCallbackTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2017-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -17,7 +17,7 @@ import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.util.UUID; @@ -25,7 +25,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertTrue; public class LambdaCallbackTest extends BrokerTestCase { @@ -53,7 +53,7 @@ protected void releaseResources() throws IOException { Channel channel = connection.createChannel(); channel.addShutdownListener(cause -> latch.countDown()); } - assertTrue("Connection closed, shutdown listeners should have been called", latch.await(1, TimeUnit.SECONDS)); + assertTrue(latch.await(1, TimeUnit.SECONDS), "Connection closed, shutdown listeners should have been called"); } @Test public void confirmListener() throws Exception { @@ -64,14 +64,14 @@ protected void releaseResources() throws IOException { (deliveryTag, multiple) -> {} ); channel.basicPublish("", "whatever", null, "dummy".getBytes()); - assertTrue("Should have received publisher confirm", latch.await(1, TimeUnit.SECONDS)); + assertTrue(latch.await(1, TimeUnit.SECONDS), "Should have received publisher confirm"); } @Test public void returnListener() throws Exception { CountDownLatch latch = new CountDownLatch(1); channel.addReturnListener(returnMessage -> latch.countDown()); channel.basicPublish("", "notlikelytoexist", true, null, "dummy".getBytes()); - assertTrue("Should have received returned message", latch.await(1, TimeUnit.SECONDS)); + assertTrue(latch.await(1, TimeUnit.SECONDS), "Should have received returned message"); } @Test public void blockedListener() throws Exception { @@ -90,7 +90,7 @@ protected void releaseResources() throws IOException { block(); Channel ch = connection.createChannel(); ch.basicPublish("", "", null, "dummy".getBytes()); - assertTrue("Should have been blocked and unblocked", latch.await(10, TimeUnit.SECONDS)); + assertTrue(latch.await(10, TimeUnit.SECONDS), "Should have been blocked and unblocked"); } } @@ -104,9 +104,9 @@ protected void releaseResources() throws IOException { consumerTag -> cancelLatch.countDown() ); this.channel.basicPublish("", queue, null, "dummy".getBytes()); - assertTrue("deliver callback should have been called", consumingLatch.await(1, TimeUnit.SECONDS)); + assertTrue(consumingLatch.await(1, TimeUnit.SECONDS), "deliver callback should have been called"); this.channel.queueDelete(queue); - assertTrue("cancel callback should have been called", cancelLatch.await(1, TimeUnit.SECONDS)); + assertTrue(cancelLatch.await(1, TimeUnit.SECONDS), "cancel callback should have been called"); } } @@ -120,9 +120,9 @@ protected void releaseResources() throws IOException { (consumerTag, sig) -> shutdownLatch.countDown() ); this.channel.basicPublish("", queue, null, "dummy".getBytes()); - assertTrue("deliver callback should have been called", consumingLatch.await(1, TimeUnit.SECONDS)); + assertTrue(consumingLatch.await(1, TimeUnit.SECONDS), "deliver callback should have been called"); } - assertTrue("shutdown callback should have been called", shutdownLatch.await(1, TimeUnit.SECONDS)); + assertTrue(shutdownLatch.await(1, TimeUnit.SECONDS), "shutdown callback should have been called"); } @Test public void basicConsumeCancelDeliverShutdown() throws Exception { @@ -138,9 +138,9 @@ protected void releaseResources() throws IOException { (consumerTag, sig) -> shutdownLatch.countDown() ); this.channel.basicPublish("", queue, null, "dummy".getBytes()); - assertTrue("deliver callback should have been called", consumingLatch.await(1, TimeUnit.SECONDS)); + assertTrue(consumingLatch.await(1, TimeUnit.SECONDS), "deliver callback should have been called"); } - assertTrue("shutdown callback should have been called", shutdownLatch.await(1, TimeUnit.SECONDS)); + assertTrue(shutdownLatch.await(1, TimeUnit.SECONDS), "shutdown callback should have been called"); } } diff --git a/src/test/java/com/rabbitmq/client/test/LongStringTest.java b/src/test/java/com/rabbitmq/client/test/LongStringTest.java index 7c711b4fe4..82c6053116 100644 --- a/src/test/java/com/rabbitmq/client/test/LongStringTest.java +++ b/src/test/java/com/rabbitmq/client/test/LongStringTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -17,11 +17,11 @@ import com.rabbitmq.client.LongString; import com.rabbitmq.client.impl.LongStringHelper; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.io.UnsupportedEncodingException; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertTrue; public class LongStringTest { diff --git a/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java b/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java index 43ad9cd33b..8404a25d03 100644 --- a/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java +++ b/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2022 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -26,11 +26,11 @@ import io.opentelemetry.sdk.metrics.data.LongPointData; import io.opentelemetry.sdk.metrics.data.MetricData; import io.opentelemetry.sdk.testing.junit4.OpenTelemetryRule; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; +import io.opentelemetry.sdk.testing.junit5.OpenTelemetryExtension; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import java.io.IOException; import java.util.List; @@ -42,13 +42,11 @@ /** * */ -@RunWith(Parameterized.class) public class MetricsCollectorTest { - @ClassRule - public static final OpenTelemetryRule openTelemetryRule = OpenTelemetryRule.create(); + @RegisterExtension + static final OpenTelemetryExtension otelTesting = OpenTelemetryExtension.create(); - @Parameterized.Parameters public static Object[] data() { // need to resort to a factory, as this method is called only once // if creating the collector instance, it's reused across the test methods @@ -56,17 +54,15 @@ public static Object[] data() { return new Object[]{new StandardMetricsCollectorFactory(), new MicrometerMetricsCollectorFactory(), new OpenTelemetryMetricsCollectorFactory()}; } - @Parameterized.Parameter - public MetricsCollectorFactory factory; - - @Before + @BeforeEach public void reset() { // reset metrics - openTelemetryRule.clearMetrics(); + otelTesting.clearMetrics(); } - @Test - public void basicGetAndAck() { + @ParameterizedTest + @MethodSource("data") + public void basicGetAndAck(MetricsCollectorFactory factory) { AbstractMetricsCollector metrics = factory.create(); Connection connection = mock(Connection.class); when(connection.getId()).thenReturn("connection-1"); @@ -97,7 +93,9 @@ public void basicGetAndAck() { assertThat(acknowledgedMessages(metrics)).isEqualTo(1L+2L+1L); } - @Test public void basicConsumeAndAck() { + @ParameterizedTest + @MethodSource("data") + public void basicConsumeAndAck(MetricsCollectorFactory factory) { AbstractMetricsCollector metrics = factory.create(); Connection connection = mock(Connection.class); when(connection.getId()).thenReturn("connection-1"); @@ -136,7 +134,9 @@ public void basicGetAndAck() { assertThat(acknowledgedMessages(metrics)).isEqualTo(1L+2L+1L); } - @Test public void publishingAndPublishingFailures() { + @ParameterizedTest + @MethodSource("data") + public void publishingAndPublishingFailures(MetricsCollectorFactory factory) { AbstractMetricsCollector metrics = factory.create(); Channel channel = mock(Channel.class); @@ -164,7 +164,9 @@ public void basicGetAndAck() { assertThat(publishedMessages(metrics)).isEqualTo(2L); } - @Test public void publishingAcknowledgements() { + @ParameterizedTest + @MethodSource("data") + public void publishingAcknowledgements(MetricsCollectorFactory factory) { AbstractMetricsCollector metrics = factory.create(); Connection connection = mock(Connection.class); when(connection.getId()).thenReturn("connection-1"); @@ -210,7 +212,9 @@ public void basicGetAndAck() { assertThat(publishAck(metrics)).isEqualTo(6L); } - @Test public void publishingNotAcknowledgements() { + @ParameterizedTest + @MethodSource("data") + public void publishingNotAcknowledgements(MetricsCollectorFactory factory) { AbstractMetricsCollector metrics = factory.create(); Connection connection = mock(Connection.class); when(connection.getId()).thenReturn("connection-1"); @@ -251,7 +255,9 @@ public void basicGetAndAck() { assertThat(publishNack(metrics)).isEqualTo(5L); } - @Test public void publishingUnrouted() { + @ParameterizedTest + @MethodSource("data") + public void publishingUnrouted(MetricsCollectorFactory factory) { AbstractMetricsCollector metrics = factory.create(); Channel channel = mock(Channel.class); // begins with no messages not-acknowledged @@ -267,7 +273,9 @@ public void basicGetAndAck() { assertThat(publishUnrouted(metrics)).isEqualTo(2L); } - @Test public void cleanStaleState() { + @ParameterizedTest + @MethodSource("data") + public void cleanStaleState(MetricsCollectorFactory factory) { AbstractMetricsCollector metrics = factory.create(); Connection openConnection = mock(Connection.class); when(openConnection.getId()).thenReturn("connection-1"); @@ -437,13 +445,13 @@ public AbstractMetricsCollector create() { static class OpenTelemetryMetricsCollectorFactory implements MetricsCollectorFactory { @Override public AbstractMetricsCollector create() { - return new OpenTelemetryMetricsCollector(openTelemetryRule.getOpenTelemetry()); + return new OpenTelemetryMetricsCollector(otelTesting.getOpenTelemetry()); } } static long getOpenTelemetryCounterMeterValue(String name) { // open telemetry metrics - List metrics = openTelemetryRule.getMetrics(); + List metrics = otelTesting.getMetrics(); // metric value return metrics.stream() .filter(metric -> metric.getName().equals(name)) diff --git a/src/test/java/com/rabbitmq/client/test/MicrometerMetricsCollectorTest.java b/src/test/java/com/rabbitmq/client/test/MicrometerMetricsCollectorTest.java index 125d185160..16c7fc12df 100644 --- a/src/test/java/com/rabbitmq/client/test/MicrometerMetricsCollectorTest.java +++ b/src/test/java/com/rabbitmq/client/test/MicrometerMetricsCollectorTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2018-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,12 +15,14 @@ package com.rabbitmq.client.test; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + import com.rabbitmq.client.impl.MicrometerMetricsCollector; import io.micrometer.core.instrument.Meter; import io.micrometer.core.instrument.simple.SimpleMeterRegistry; import org.assertj.core.api.Assertions; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; /** * @@ -31,7 +33,7 @@ public class MicrometerMetricsCollectorTest { MicrometerMetricsCollector collector; - @Before + @BeforeEach public void init() { registry = new SimpleMeterRegistry(); } @@ -52,9 +54,10 @@ public void tags() { } } - @Test(expected = IllegalArgumentException.class) + @Test public void tagsMustBeKeyValuePairs() { - collector = new MicrometerMetricsCollector(registry, "rabbitmq", "uri"); + assertThatThrownBy(() -> new MicrometerMetricsCollector(registry, "rabbitmq", "uri")) + .isInstanceOf(IllegalArgumentException.class); } } diff --git a/src/test/java/com/rabbitmq/client/test/MultiThreadedChannel.java b/src/test/java/com/rabbitmq/client/test/MultiThreadedChannel.java index 93a2d1c837..7893ab056b 100644 --- a/src/test/java/com/rabbitmq/client/test/MultiThreadedChannel.java +++ b/src/test/java/com/rabbitmq/client/test/MultiThreadedChannel.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -17,7 +17,7 @@ import java.util.concurrent.atomic.AtomicReference; -import org.junit.Test; +import org.junit.jupiter.api.Test; /** * Tests whether a Channel is safe for multi-threaded access diff --git a/src/test/java/com/rabbitmq/client/test/NioDeadlockOnConnectionClosing.java b/src/test/java/com/rabbitmq/client/test/NioDeadlockOnConnectionClosing.java index 0f3984ade7..9ca7dd156a 100644 --- a/src/test/java/com/rabbitmq/client/test/NioDeadlockOnConnectionClosing.java +++ b/src/test/java/com/rabbitmq/client/test/NioDeadlockOnConnectionClosing.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -18,9 +18,9 @@ import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.impl.nio.NioParams; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -31,7 +31,7 @@ import java.util.concurrent.TimeUnit; import static com.rabbitmq.client.test.TestUtils.closeAllConnectionsAndWaitForRecovery; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * @@ -44,7 +44,7 @@ public class NioDeadlockOnConnectionClosing { ConnectionFactory cf; List connections; - @Before + @BeforeEach public void setUp() { nioExecutorService = Executors.newFixedThreadPool(2); connectionShutdownExecutorService = Executors.newFixedThreadPool(2); @@ -60,7 +60,7 @@ public void setUp() { connections = new ArrayList<>(); } - @After + @AfterEach public void tearDown() throws Exception { for (Connection connection : connections) { try { diff --git a/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java b/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java index 247fdcfd57..ea0bf72c74 100644 --- a/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java +++ b/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2018-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -27,10 +27,10 @@ import com.rabbitmq.client.impl.nio.NioParams; import com.rabbitmq.client.impl.recovery.AutorecoveringChannel; import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; -import org.junit.After; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Test; +import com.rabbitmq.client.test.TestUtils.DisabledIfBrokerRunningOnDocker; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.net.Socket; @@ -42,7 +42,6 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; -import org.junit.rules.TestRule; import static org.assertj.core.api.Assertions.assertThat; @@ -66,11 +65,9 @@ * to the socket fails. *

*/ +@DisabledIfBrokerRunningOnDocker public class NoAutoRecoveryWhenTcpWindowIsFullTest { - @ClassRule - public static TestRule brokerOnDockerTestRule = TestUtils.brokerIsNotRunningOnDocker(); - private static final int NUM_MESSAGES_TO_PRODUCE = 50000; private static final int MESSAGE_PROCESSING_TIME_MS = 3000; private static final byte[] MESSAGE_CONTENT = ("MESSAGE CONTENT " + NUM_MESSAGES_TO_PRODUCE).getBytes(); @@ -83,7 +80,7 @@ public class NoAutoRecoveryWhenTcpWindowIsFullTest { private CountDownLatch consumerOkLatch; - @Before + @BeforeEach public void setUp() throws Exception { // we need several threads to publish, dispatch deliveries, handle RPC responses, etc. executorService = Executors.newFixedThreadPool(10); @@ -123,7 +120,7 @@ public void configure(Socket socket) throws IOException { consumerOkLatch = new CountDownLatch(2); } - @After + @AfterEach public void tearDown() throws IOException { closeConnectionIfOpen(consumingConnection); closeConnectionIfOpen(producingConnection); diff --git a/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java b/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java index 40138a26d6..24d3f808d8 100644 --- a/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java +++ b/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -17,7 +17,7 @@ import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.ConnectionFactoryConfigurator; -import org.junit.Test; +import org.junit.jupiter.api.Test; import javax.net.ssl.SSLContext; import java.io.FileReader; diff --git a/src/test/java/com/rabbitmq/client/test/QueueingConsumerTests.java b/src/test/java/com/rabbitmq/client/test/QueueingConsumerTests.java index ba9d72e47b..4a4793952f 100644 --- a/src/test/java/com/rabbitmq/client/test/QueueingConsumerTests.java +++ b/src/test/java/com/rabbitmq/client/test/QueueingConsumerTests.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,10 +15,10 @@ package com.rabbitmq.client.test; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import com.rabbitmq.client.ConsumerCancelledException; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.util.concurrent.ArrayBlockingQueue; diff --git a/src/test/java/com/rabbitmq/client/test/RecoveryAwareAMQConnectionFactoryTest.java b/src/test/java/com/rabbitmq/client/test/RecoveryAwareAMQConnectionFactoryTest.java index 785b58ec53..2b40553778 100644 --- a/src/test/java/com/rabbitmq/client/test/RecoveryAwareAMQConnectionFactoryTest.java +++ b/src/test/java/com/rabbitmq/client/test/RecoveryAwareAMQConnectionFactoryTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -24,7 +24,7 @@ import com.rabbitmq.client.impl.FrameHandlerFactory; import com.rabbitmq.client.impl.recovery.RecoveryAwareAMQConnection; import com.rabbitmq.client.impl.recovery.RecoveryAwareAMQConnectionFactory; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.util.Arrays; @@ -32,7 +32,7 @@ import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.TimeoutException; -import static org.junit.Assert.assertSame; +import static org.junit.jupiter.api.Assertions.assertSame; import static org.mockito.Mockito.*; public class RecoveryAwareAMQConnectionFactoryTest { diff --git a/src/test/java/com/rabbitmq/client/test/RecoveryDelayHandlerTest.java b/src/test/java/com/rabbitmq/client/test/RecoveryDelayHandlerTest.java index be9958b487..035b96191d 100644 --- a/src/test/java/com/rabbitmq/client/test/RecoveryDelayHandlerTest.java +++ b/src/test/java/com/rabbitmq/client/test/RecoveryDelayHandlerTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,7 +15,8 @@ package com.rabbitmq.client.test; -import static org.junit.Assert.assertEquals; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.Arrays; import java.util.Collections; @@ -24,7 +25,7 @@ import com.rabbitmq.client.RecoveryDelayHandler.DefaultRecoveryDelayHandler; import com.rabbitmq.client.RecoveryDelayHandler.ExponentialBackoffDelayHandler; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class RecoveryDelayHandlerTest { @@ -61,13 +62,15 @@ public void testExponentialBackoffDelayHandlerSequence() { assertEquals(2, handler.getDelay(Integer.MAX_VALUE)); } - @Test(expected=IllegalArgumentException.class) + @Test public void testExponentialBackoffDelayHandlerWithNullSequence() { - new ExponentialBackoffDelayHandler(null); + assertThatThrownBy(() -> new ExponentialBackoffDelayHandler(null)) + .isInstanceOf(IllegalArgumentException.class); } - @Test(expected=IllegalArgumentException.class) + @Test public void testExponentialBackoffDelayHandlerWithEmptySequence() { - new ExponentialBackoffDelayHandler(Collections.emptyList()); + assertThatThrownBy(() -> new ExponentialBackoffDelayHandler(Collections.emptyList())) + .isInstanceOf(IllegalArgumentException.class); } } diff --git a/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java b/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java index 0a0100cbc6..8e32dbc6c3 100644 --- a/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java +++ b/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2019-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -20,10 +20,10 @@ import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.impl.DefaultCredentialsRefreshService; import com.rabbitmq.client.impl.RefreshProtectedCredentialsProvider; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.rules.TestRule; +import com.rabbitmq.client.test.TestUtils.BrokerVersion; +import com.rabbitmq.client.test.TestUtils.BrokerVersionAtLeast; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.time.Duration; import java.time.Instant; @@ -33,13 +33,12 @@ import static org.assertj.core.api.Assertions.assertThat; +@BrokerVersionAtLeast(BrokerVersion.RABBITMQ_3_8) public class RefreshCredentialsTest { - @ClassRule - public static TestRule brokerVersionTestRule = TestUtils.atLeast38(); DefaultCredentialsRefreshService refreshService; - @Before + @BeforeEach public void tearDown() { if (refreshService != null) { refreshService.close(); diff --git a/src/test/java/com/rabbitmq/client/test/RequiredPropertiesSuite.java b/src/test/java/com/rabbitmq/client/test/RequiredPropertiesSuite.java index f8ab431800..f0040e43ab 100644 --- a/src/test/java/com/rabbitmq/client/test/RequiredPropertiesSuite.java +++ b/src/test/java/com/rabbitmq/client/test/RequiredPropertiesSuite.java @@ -1,10 +1,5 @@ package com.rabbitmq.client.test; -import org.junit.runner.Runner; -import org.junit.runner.notification.RunNotifier; -import org.junit.runners.Suite; -import org.junit.runners.model.InitializationError; -import org.junit.runners.model.RunnerBuilder; import java.util.ArrayList; import java.util.List; @@ -14,8 +9,9 @@ /** * */ -public class RequiredPropertiesSuite extends Suite { +public class RequiredPropertiesSuite { //extends Suite { +/* private static final Logger LOGGER = LoggerFactory.getLogger(RequiredPropertiesSuite.class); public RequiredPropertiesSuite(Class klass, RunnerBuilder builder) throws InitializationError { @@ -52,4 +48,6 @@ protected void runChild(Runner runner, RunNotifier notifier) { LOGGER.info("Running test {}", runner.getDescription().getDisplayName()); super.runChild(runner, notifier); } + + */ } diff --git a/src/test/java/com/rabbitmq/client/test/RpcTest.java b/src/test/java/com/rabbitmq/client/test/RpcTest.java index d535d9c8f7..5d95d0d448 100644 --- a/src/test/java/com/rabbitmq/client/test/RpcTest.java +++ b/src/test/java/com/rabbitmq/client/test/RpcTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2017-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -25,9 +25,9 @@ import com.rabbitmq.client.impl.recovery.TopologyRecoveryFilter; import com.rabbitmq.tools.Host; import org.assertj.core.api.Assertions; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.time.Duration; @@ -40,7 +40,7 @@ import java.util.concurrent.atomic.AtomicInteger; import static com.rabbitmq.client.test.TestUtils.waitAtMost; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; public class RpcTest { @@ -49,7 +49,7 @@ public class RpcTest { String queue = "rpc.queue"; RpcServer rpcServer; - @Before + @BeforeEach public void init() throws Exception { clientConnection = TestUtils.connectionFactory().newConnection(); clientChannel = clientConnection.createChannel(); @@ -58,7 +58,7 @@ public void init() throws Exception { serverChannel.queueDeclare(queue, false, false, false, null); } - @After + @AfterEach public void tearDown() throws Exception { if (rpcServer != null) { rpcServer.terminateMainloop(); @@ -241,7 +241,7 @@ public void handleRecoveryStarted(Recoverable recoverable) { } }); Host.closeConnection((NetworkConnection) connection); - assertTrue("Connection should have recovered by now", recoveryLatch.await(10, TimeUnit.SECONDS)); + assertTrue(recoveryLatch.await(10, TimeUnit.SECONDS), "Connection should have recovered by now"); client = new RpcClient(new RpcClientParams() .channel(channel).exchange("").routingKey(queue).timeout(1000)); response = client.doCall(null, "hello".getBytes()); @@ -289,7 +289,7 @@ public void handleRecoveryStarted(Recoverable recoverable) { } }); Host.closeConnection((NetworkConnection) connection); - assertTrue("Connection should have recovered by now", recoveryLatch.await(10, TimeUnit.SECONDS)); + assertTrue(recoveryLatch.await(10, TimeUnit.SECONDS), "Connection should have recovered by now"); try { new RpcClient(new RpcClientParams() .channel(channel).exchange("").routingKey(queue).timeout(1000)); diff --git a/src/test/java/com/rabbitmq/client/test/RpcTopologyRecordingTest.java b/src/test/java/com/rabbitmq/client/test/RpcTopologyRecordingTest.java index 3769218fd7..249eeb3f1b 100644 --- a/src/test/java/com/rabbitmq/client/test/RpcTopologyRecordingTest.java +++ b/src/test/java/com/rabbitmq/client/test/RpcTopologyRecordingTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2018-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -17,9 +17,6 @@ import com.rabbitmq.client.*; import com.rabbitmq.client.impl.AMQImpl; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; import java.io.IOException; import java.util.UUID; @@ -27,20 +24,18 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicReference; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import static com.rabbitmq.client.test.TestUtils.closeAndWaitForRecovery; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; -@RunWith(Parameterized.class) public class RpcTopologyRecordingTest extends BrokerTestCase { - @Parameterized.Parameter - public RpcCall rpcCall; String exchange, queue, routingKey; String exchange2, queue2, routingKey2; - @Parameterized.Parameters public static Object[] data() { return new Object[]{ (RpcCall) (channel, method) -> channel.asyncCompletableRpc(method).get(5, TimeUnit.SECONDS), @@ -73,9 +68,10 @@ protected void releaseResources() throws IOException { channel.exchangeDelete(exchange2); } - @Test - public void topologyRecovery() throws Exception { - createTopology(); + @ParameterizedTest + @MethodSource("data") + public void topologyRecovery(RpcCall rpcCall) throws Exception { + createTopology(rpcCall); AtomicReference latch = new AtomicReference<>(new CountDownLatch(2)); DeliverCallback countDown = (ctag, message) -> latch.get().countDown(); @@ -98,9 +94,10 @@ public void topologyRecovery() throws Exception { assertTrue(latch.get().await(5, TimeUnit.SECONDS)); } - @Test - public void deletionAreProperlyRecorded() throws Exception { - createTopology(); + @ParameterizedTest + @MethodSource("data") + public void deletionAreProperlyRecorded(RpcCall rpcCall) throws Exception { + createTopology(rpcCall); AtomicReference latch = new AtomicReference<>(new CountDownLatch(2)); DeliverCallback countDown = (ctag, message) -> latch.get().countDown(); @@ -151,9 +148,10 @@ boolean exchangeExists(String exchange) throws TimeoutException { } } - @Test - public void bindingDeletionAreProperlyRecorded() throws Exception { - createTopology(); + @ParameterizedTest + @MethodSource("data") + public void bindingDeletionAreProperlyRecorded(RpcCall rpcCall) throws Exception { + createTopology(rpcCall); AtomicReference latch = new AtomicReference<>(new CountDownLatch(2)); DeliverCallback countDown = (ctag, message) -> latch.get().countDown(); @@ -167,7 +165,7 @@ public void bindingDeletionAreProperlyRecorded() throws Exception { assertTrue(latch.get().await(5, TimeUnit.SECONDS)); - unbind(); + unbind(rpcCall); latch.set(new CountDownLatch(2)); @@ -178,9 +176,9 @@ public void bindingDeletionAreProperlyRecorded() throws Exception { assertFalse(latch.get().await(2, TimeUnit.SECONDS)); } - private void createTopology() throws Exception { - createAndBind(exchange, queue, routingKey); - createAndBind(exchange2, queue2, routingKey2); + private void createTopology(RpcCall rpcCall) throws Exception { + createAndBind(rpcCall, exchange, queue, routingKey); + createAndBind(rpcCall, exchange2, queue2, routingKey2); rpcCall.call(channel, new AMQImpl.Exchange.Bind.Builder() .source(exchange) .destination(exchange2) @@ -189,7 +187,7 @@ private void createTopology() throws Exception { .build()); } - private void createAndBind(String e, String q, String rk) throws Exception { + private void createAndBind(RpcCall rpcCall, String e, String q, String rk) throws Exception { rpcCall.call(channel, new AMQImpl.Queue.Declare.Builder() .queue(q) .durable(false) @@ -212,7 +210,7 @@ private void createAndBind(String e, String q, String rk) throws Exception { .build()); } - private void unbind() throws Exception { + private void unbind(RpcCall rpcCall) throws Exception { rpcCall.call(channel, new AMQImpl.Queue.Unbind.Builder() .exchange(exchange) .queue(queue) diff --git a/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java b/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java index 747a2805e5..0e8317b987 100644 --- a/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java +++ b/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,8 +15,8 @@ package com.rabbitmq.client.test; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; import java.util.concurrent.ExecutorService; @@ -24,7 +24,7 @@ import java.util.concurrent.TimeoutException; import com.rabbitmq.client.Connection; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.impl.AMQConnection; diff --git a/src/test/java/com/rabbitmq/client/test/SslContextFactoryTest.java b/src/test/java/com/rabbitmq/client/test/SslContextFactoryTest.java index 585e74f7a8..69a3eee1e8 100644 --- a/src/test/java/com/rabbitmq/client/test/SslContextFactoryTest.java +++ b/src/test/java/com/rabbitmq/client/test/SslContextFactoryTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -19,7 +19,7 @@ import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.SslContextFactory; import com.rabbitmq.client.TrustEverythingTrustManager; -import org.junit.Test; +import org.junit.jupiter.api.Test; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLHandshakeException; @@ -32,7 +32,7 @@ import java.util.Map; import java.util.function.Supplier; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.fail; /** * diff --git a/src/test/java/com/rabbitmq/client/test/StrictExceptionHandlerTest.java b/src/test/java/com/rabbitmq/client/test/StrictExceptionHandlerTest.java index fbb3ad984b..c2a3f28aa9 100644 --- a/src/test/java/com/rabbitmq/client/test/StrictExceptionHandlerTest.java +++ b/src/test/java/com/rabbitmq/client/test/StrictExceptionHandlerTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2018-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -23,7 +23,7 @@ import com.rabbitmq.client.DefaultConsumer; import com.rabbitmq.client.Envelope; import com.rabbitmq.client.impl.StrictExceptionHandler; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; diff --git a/src/test/java/com/rabbitmq/client/test/TableTest.java b/src/test/java/com/rabbitmq/client/test/TableTest.java index d39e871760..be808fa262 100644 --- a/src/test/java/com/rabbitmq/client/test/TableTest.java +++ b/src/test/java/com/rabbitmq/client/test/TableTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2022 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -18,7 +18,8 @@ import com.rabbitmq.client.impl.*; import java.sql.Timestamp; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.io.*; import java.math.BigDecimal; @@ -26,12 +27,12 @@ import java.util.HashMap; import java.util.Map; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class TableTest { - public byte [] marshal(Map table) + public byte [] marshal(Map table) throws IOException { ByteArrayOutputStream buffer = new ByteArrayOutputStream(); diff --git a/src/test/java/com/rabbitmq/client/test/TestUtils.java b/src/test/java/com/rabbitmq/client/test/TestUtils.java index 2afffd8d33..8897bf23a9 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtils.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtils.java @@ -19,23 +19,17 @@ import com.rabbitmq.client.impl.NetworkConnection; import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; import com.rabbitmq.tools.Host; +import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import java.lang.reflect.Method; -import java.util.List; +import java.util.function.Function; import org.assertj.core.api.Assertions; -import org.junit.AssumptionViolatedException; -import org.junit.rules.TestRule; -import org.junit.rules.TestWatcher; -import org.junit.runner.Description; -import org.junit.runner.Runner; -import org.junit.runner.notification.RunNotifier; -import org.junit.runners.Suite; -import org.junit.runners.model.InitializationError; -import org.junit.runners.model.RunnerBuilder; -import org.junit.runners.model.Statement; +import org.junit.jupiter.api.extension.ConditionEvaluationResult; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ExtensionContext.Namespace; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -49,7 +43,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertTrue; public class TestUtils { @@ -124,14 +118,6 @@ public static void abort(Connection connection) { } } - public static TestRule atLeast38() { - return new BrokerVersionTestRule("3.8.0"); - } - - public static TestRule brokerIsNotRunningOnDocker() { - return new BrokerIsNotOnDocker(); - } - public static boolean isVersion37orLater(Connection connection) { return atLeastVersion("3.7.0", connection); } @@ -145,11 +131,11 @@ public static boolean isVersion310orLater(Connection connection) { } private static boolean atLeastVersion(String expectedVersion, Connection connection) { - String currentVersion = null; + return atLeastVersion(expectedVersion, currentVersion(connection.getServerProperties().get("version").toString())); + } + + private static boolean atLeastVersion(String expectedVersion, String currentVersion) { try { - currentVersion = currentVersion( - connection.getServerProperties().get("version").toString() - ); return "0.0.0".equals(currentVersion) || versionCompare(currentVersion, expectedVersion) >= 0; } catch (RuntimeException e) { LoggerFactory.getLogger(TestUtils.class).warn("Unable to parse broker version {}", currentVersion, e); @@ -310,52 +296,6 @@ public static int randomNetworkPort() throws IOException { return port; } - private static class BrokerVersionTestRule implements TestRule { - - private final String version; - - public BrokerVersionTestRule(String version) { - this.version = version; - } - - @Override - public Statement apply(Statement base, Description description) { - return new Statement() { - @Override - public void evaluate() throws Throwable { - try (Connection c = TestUtils.connectionFactory().newConnection()) { - if (!TestUtils.atLeastVersion(version, c)) { - throw new AssumptionViolatedException("Broker version < " + version + ", skipping."); - } - } - base.evaluate(); - } - }; - } - } - - private static class BrokerIsNotOnDocker implements TestRule { - - @Override - public Statement apply(Statement base, Description description) { - return new Statement() { - @Override - public void evaluate() throws Throwable { - try { - if (Host.isOnDocker()) { - throw new AssumptionViolatedException("Broker is running on Docker"); - } - } catch (AssumptionViolatedException e) { - throw e; - } catch (Exception e) { - throw new AssumptionViolatedException("Could not check whether broker is running on Docker or not", e); - } - base.evaluate(); - } - }; - } - } - @FunctionalInterface public interface CallableFunction { @@ -387,6 +327,7 @@ public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProp return messageReceived; } + /* public static class DefaultTestSuite extends Suite { @@ -422,140 +363,132 @@ protected DefaultTestSuite(Class klass, List runners) } } - @Target({ElementType.METHOD}) - @Retention(RetentionPolicy.RUNTIME) - public @interface TestExecutionCondition { - - Class[] value(); + */ + public static void safeDelete(Connection connection, String queue) { + try { + Channel ch = connection.createChannel(); + ch.queueDelete(queue); + ch.close(); + } catch (Exception e) { + // OK + } } - interface ExecutionCondition { - - void check(Description description) throws Exception; - - } + private static class BaseBrokerVersionAtLeastCondition implements + org.junit.jupiter.api.extension.ExecutionCondition { - public static class BrokerAtLeast310Condition implements ExecutionCondition { + private final Function versionProvider; - private static final String VERSION = "3.10.0"; + private BaseBrokerVersionAtLeastCondition(Function versionProvider) { + this.versionProvider = versionProvider; + } @Override - public void check(Description description) throws Exception { - try (Connection c = TestUtils.connectionFactory().newConnection()) { - if (!TestUtils.atLeastVersion(VERSION, c)) { - throw new AssumptionViolatedException("Broker version < " + VERSION + ", skipping."); + public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) { + if (!context.getTestMethod().isPresent()) { + return ConditionEvaluationResult.enabled("Apply only to methods"); + } + String expectedVersion = versionProvider.apply(context); + if (expectedVersion == null) { + return ConditionEvaluationResult.enabled("No broker version requirement"); + } else { + String brokerVersion = + context + .getRoot() + .getStore(Namespace.GLOBAL) + .getOrComputeIfAbsent( + "brokerVersion", + k -> { + try (Connection c = TestUtils.connectionFactory().newConnection()) { + return currentVersion( + c.getServerProperties().get("version").toString() + ); + } catch (Exception e) { + throw new RuntimeException(e); + } + }, + String.class); + + if (atLeastVersion(expectedVersion, brokerVersion)) { + return ConditionEvaluationResult.enabled( + "Broker version requirement met, expected " + + expectedVersion + + ", actual " + + brokerVersion); + } else { + return ConditionEvaluationResult.disabled( + "Broker version requirement not met, expected " + + expectedVersion + + ", actual " + + brokerVersion); } } } } - public static class ExecutionConditionRule implements TestRule { + private static class AnnotationBrokerVersionAtLeastCondition + extends BaseBrokerVersionAtLeastCondition { - @Override - public Statement apply(Statement base, Description description) { - return new Statement() { - @Override - public void evaluate() throws Throwable { - Method testMethod = description.getTestClass().getDeclaredMethod(description.getMethodName()); - TestExecutionCondition conditionAnnotation = testMethod.getAnnotation( - TestExecutionCondition.class); - if (conditionAnnotation != null) { - conditionAnnotation.value()[0].getConstructor().newInstance() - .check(description); - } - base.evaluate(); - } - }; + private AnnotationBrokerVersionAtLeastCondition() { + super( + context -> { + BrokerVersionAtLeast annotation = + context.getElement().get().getAnnotation(BrokerVersionAtLeast.class); + return annotation == null ? null : annotation.value().toString(); + }); } } - public static TestRule atLeastJava11() { - return new AtLeastJavaVersion(11); - } - - private static class AtLeastJavaVersion implements TestRule { + static class BrokerVersionAtLeast310Condition extends BaseBrokerVersionAtLeastCondition { - private final int expectedMinVersion; - - private AtLeastJavaVersion(int expectedMinVersion) { - this.expectedMinVersion = expectedMinVersion; + private BrokerVersionAtLeast310Condition() { + super(context -> "3.10.0"); } + } - @Override - public Statement apply(Statement base, Description description) { - return new Statement() { - @Override - public void evaluate() throws Throwable { - try { - int javaMajorVersion = javaMajorVersion(); - if (javaMajorVersion < expectedMinVersion) { - throw new AssumptionViolatedException("Java version is " + javaMajorVersion - + ", expecting at least " + expectedMinVersion); - } - } catch (AssumptionViolatedException e) { - throw e; - } catch (Exception e) { - throw new AssumptionViolatedException("Could determine Java version", e); - } - base.evaluate(); - } - }; - } + @Target({ElementType.TYPE, ElementType.METHOD}) + @Retention(RetentionPolicy.RUNTIME) + @Documented + @ExtendWith(AnnotationBrokerVersionAtLeastCondition.class) + public @interface BrokerVersionAtLeast { + + BrokerVersion value(); } - private static int javaMajorVersion() { - String javaVersion = System.getProperty("java.version"); - if (javaVersion == null || javaVersion.trim().isEmpty()) { - throw new IllegalStateException("JVM system property 'java.version' is undefined"); - } + public enum BrokerVersion { + RABBITMQ_3_8("3.8.0"), + RABBITMQ_3_10("3.10.0"); - if (javaVersion.startsWith("1.8")) { - return 8; - } + final String value; - try { - // from JUnit 5 JRE class - // java.lang.Runtime.version() is a static method available on Java 9+ - // that returns an instance of java.lang.Runtime.Version which has the - // following method: public int major() - Method versionMethod = Runtime.class.getMethod("version"); - Object version = versionMethod.invoke(null); - Method majorMethod = version.getClass().getMethod("major"); - int major = (int) majorMethod.invoke(version); - if (major < 9) { - throw new IllegalStateException("Invalid Java major version: " + major); - } - return major; - } catch (Exception ex) { - LOGGER.warn("Error while computing Java major version", ex); + BrokerVersion(String value) { + this.value = value; } - throw new IllegalStateException("Could not determine Java major version"); - } - public static void safeDelete(Connection connection, String queue) { - try { - Channel ch = connection.createChannel(); - ch.queueDelete(queue); - ch.close(); - } catch (Exception e) { - // OK + @Override + public String toString() { + return this.value; } } - public static class TestDescription extends TestWatcher { - - private volatile Description description; + static class DisabledIfBrokerRunningOnDockerCondition implements + org.junit.jupiter.api.extension.ExecutionCondition { @Override - protected void starting(Description d) { - description = d; - } - - public Description getDescription() { - return description; + public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) { + if (Host.isOnDocker()) { + return ConditionEvaluationResult.enabled("Broker running on Docker"); + } else { + return ConditionEvaluationResult.enabled("Broker not running on Docker"); + } } } + @Target({ElementType.TYPE, ElementType.METHOD}) + @Retention(RetentionPolicy.RUNTIME) + @Documented + @ExtendWith(DisabledIfBrokerRunningOnDockerCondition.class) + @interface DisabledIfBrokerRunningOnDocker {} } diff --git a/src/test/java/com/rabbitmq/client/test/TestUtilsTest.java b/src/test/java/com/rabbitmq/client/test/TestUtilsTest.java index b73e8033cc..897296938d 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtilsTest.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtilsTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2017-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -17,7 +17,7 @@ import com.rabbitmq.client.Connection; import org.assertj.core.api.Assertions; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.util.HashMap; import java.util.Map; diff --git a/src/test/java/com/rabbitmq/client/test/TlsUtilsTest.java b/src/test/java/com/rabbitmq/client/test/TlsUtilsTest.java index f04d22dc1c..51a1b691e1 100644 --- a/src/test/java/com/rabbitmq/client/test/TlsUtilsTest.java +++ b/src/test/java/com/rabbitmq/client/test/TlsUtilsTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2019-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,7 +15,7 @@ package com.rabbitmq.client.test; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.mockito.Mockito; import java.security.cert.CertificateParsingException; diff --git a/src/test/java/com/rabbitmq/client/test/TrafficListenerTest.java b/src/test/java/com/rabbitmq/client/test/TrafficListenerTest.java index ebc25349d4..db8d021194 100644 --- a/src/test/java/com/rabbitmq/client/test/TrafficListenerTest.java +++ b/src/test/java/com/rabbitmq/client/test/TrafficListenerTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2018-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -21,9 +21,8 @@ import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.TrafficListener; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import java.util.List; import java.util.UUID; @@ -32,20 +31,16 @@ import java.util.concurrent.TimeUnit; import java.util.function.Consumer; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * */ -@RunWith(Parameterized.class) public class TrafficListenerTest { - @Parameterized.Parameter - public Consumer configurator; - @Parameterized.Parameters - public static Object[] data() { + static Object[] trafficListenerIsCalled() { return new Object[] { automaticRecoveryEnabled(), automaticRecoveryDisabled() }; } @@ -57,8 +52,9 @@ static Consumer automaticRecoveryDisabled() { return cf -> cf.setAutomaticRecoveryEnabled(false); } - @Test - public void trafficListenerIsCalled() throws Exception { + @ParameterizedTest + @MethodSource + public void trafficListenerIsCalled(Consumer configurator) throws Exception { ConnectionFactory cf = TestUtils.connectionFactory(); TestTrafficListener testTrafficListener = new TestTrafficListener(); cf.setTrafficListener(testTrafficListener); diff --git a/src/test/java/com/rabbitmq/client/test/TruncatedInputStreamTest.java b/src/test/java/com/rabbitmq/client/test/TruncatedInputStreamTest.java index 3adc9492a0..5d4a9d1273 100644 --- a/src/test/java/com/rabbitmq/client/test/TruncatedInputStreamTest.java +++ b/src/test/java/com/rabbitmq/client/test/TruncatedInputStreamTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -16,15 +16,15 @@ package com.rabbitmq.client.test; import com.rabbitmq.client.impl.TruncatedInputStream; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; /** * Some basic (retroactive) tests for TruncatedInputStream. @@ -40,12 +40,12 @@ public class TruncatedInputStreamTest { /** what length to truncate it to */ private static final int TRUNCATED_LENGTH = 3; - @Before public void setUp() throws Exception { + @BeforeEach public void setUp() throws Exception { InputStream baseStream = new ByteArrayInputStream(TEST_BYTES); _truncStream = new TruncatedInputStream(baseStream, TRUNCATED_LENGTH); } - @After public void tearDown() throws Exception { + @AfterEach public void tearDown() throws Exception { _truncStream = null; } diff --git a/src/test/java/com/rabbitmq/client/test/ValueOrExceptionTest.java b/src/test/java/com/rabbitmq/client/test/ValueOrExceptionTest.java index 1ae80029be..ac9a38b767 100644 --- a/src/test/java/com/rabbitmq/client/test/ValueOrExceptionTest.java +++ b/src/test/java/com/rabbitmq/client/test/ValueOrExceptionTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -17,9 +17,9 @@ import com.rabbitmq.utility.SensibleClone; import com.rabbitmq.utility.ValueOrException; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; public class ValueOrExceptionTest { diff --git a/src/test/java/com/rabbitmq/client/test/functional/AbstractRejectTest.java b/src/test/java/com/rabbitmq/client/test/functional/AbstractRejectTest.java index 8c87db34f1..82b8b78035 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/AbstractRejectTest.java +++ b/src/test/java/com/rabbitmq/client/test/functional/AbstractRejectTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -16,9 +16,9 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; import java.util.Arrays; @@ -29,27 +29,32 @@ import com.rabbitmq.client.GetResponse; import com.rabbitmq.client.QueueingConsumer; import com.rabbitmq.client.test.BrokerTestCase; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.TestInfo; abstract class AbstractRejectTest extends BrokerTestCase { protected Channel secondaryChannel; + @BeforeEach @Override - public void setUp() + public void setUp(TestInfo info) throws IOException, TimeoutException { - super.setUp(); + super.setUp(info); secondaryChannel = connection.createChannel(); } + @AfterEach @Override - public void tearDown() + public void tearDown(TestInfo info) throws IOException, TimeoutException { if (secondaryChannel != null) { secondaryChannel.abort(); secondaryChannel = null; } - super.tearDown(); + super.tearDown(info); } protected long checkDelivery(QueueingConsumer.Delivery d, diff --git a/src/test/java/com/rabbitmq/client/test/functional/AlternateExchange.java b/src/test/java/com/rabbitmq/client/test/functional/AlternateExchange.java index 8f2dd6675a..816d9f70f5 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/AlternateExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/AlternateExchange.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -16,7 +16,7 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import java.io.IOException; import java.util.HashMap; @@ -24,12 +24,14 @@ import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.GetResponse; import com.rabbitmq.client.ReturnListener; import com.rabbitmq.client.test.BrokerTestCase; +import org.junit.jupiter.api.TestInfo; public class AlternateExchange extends BrokerTestCase { @@ -59,8 +61,9 @@ private static boolean[] expected(String key) { return expected; } - @Override public void setUp() throws IOException, TimeoutException { - super.setUp(); + @BeforeEach + @Override public void setUp(TestInfo info) throws IOException, TimeoutException { + super.setUp(info); channel.addReturnListener(new ReturnListener() { public void handleReturn(int replyCode, String replyText, @@ -131,7 +134,7 @@ protected void checkGet(boolean[] expected) throws IOException { for (int i = 0; i < resources.length; i++) { String q = resources[i]; GetResponse r = channel.basicGet(q, true); - assertEquals("check " + q , expected[i], r != null); + assertEquals(expected[i], r != null, "check " + q); } } diff --git a/src/test/java/com/rabbitmq/client/test/functional/BasicConsume.java b/src/test/java/com/rabbitmq/client/test/functional/BasicConsume.java index 06b5fb588f..38adbf71ee 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/BasicConsume.java +++ b/src/test/java/com/rabbitmq/client/test/functional/BasicConsume.java @@ -5,13 +5,13 @@ import com.rabbitmq.client.DefaultConsumer; import com.rabbitmq.client.Envelope; import com.rabbitmq.client.test.BrokerTestCase; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * @@ -27,7 +27,7 @@ public class BasicConsume extends BrokerTestCase { channel.basicConsume(q, new CountDownLatchConsumer(channel, latch)); boolean nbOfExpectedMessagesHasBeenConsumed = latch.await(1, TimeUnit.SECONDS); - assertTrue("Not all the messages have been received", nbOfExpectedMessagesHasBeenConsumed); + assertTrue(nbOfExpectedMessagesHasBeenConsumed, "Not all the messages have been received"); } static class CountDownLatchConsumer extends DefaultConsumer { diff --git a/src/test/java/com/rabbitmq/client/test/functional/BasicGet.java b/src/test/java/com/rabbitmq/client/test/functional/BasicGet.java index e64dee9e9a..0956e8cc35 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/BasicGet.java +++ b/src/test/java/com/rabbitmq/client/test/functional/BasicGet.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,16 +15,16 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; import java.io.IOException; import java.util.concurrent.TimeoutException; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.AlreadyClosedException; import com.rabbitmq.client.Channel; diff --git a/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java b/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java index 91a5c54d49..a478748a7d 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java +++ b/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -16,16 +16,16 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; import java.io.IOException; import java.util.concurrent.TimeoutException; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.GetResponse; @@ -53,7 +53,7 @@ public class BindingLifecycle extends BindingLifecycleBase { channel.queuePurge(binding.q); GetResponse response = channel.basicGet(binding.q, true); - assertNull("The response SHOULD BE null", response); + assertNull(response, "The response SHOULD BE null"); deleteExchangeAndQueue(binding); } @@ -71,24 +71,24 @@ public class BindingLifecycle extends BindingLifecycleBase { GetResponse response = channel.basicGet(binding.q, false); assertFalse(response.getEnvelope().isRedeliver()); - assertNotNull("The response SHOULD NOT BE null", response); + assertNotNull(response, "The response SHOULD NOT BE null"); // If we purge the queue the unacked message should still be there on // recover. channel.queuePurge(binding.q); response = channel.basicGet(binding.q, true); - assertNull("The response SHOULD BE null", response); + assertNull(response, "The response SHOULD BE null"); channel.basicRecover(); response = channel.basicGet(binding.q, false); channel.basicRecover(); assertTrue(response.getEnvelope().isRedeliver()); - assertNotNull("The response SHOULD NOT BE null", response); + assertNotNull(response, "The response SHOULD NOT BE null"); // If we recover then purge the message should go away channel.queuePurge(binding.q); response = channel.basicGet(binding.q, true); - assertNull("The response SHOULD BE null", response); + assertNull(response, "The response SHOULD BE null"); deleteExchangeAndQueue(binding); } diff --git a/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycleBase.java b/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycleBase.java index 51c0e93585..c3b7995c27 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycleBase.java +++ b/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycleBase.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -16,9 +16,9 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.fail; import java.io.IOException; import java.util.concurrent.TimeoutException; @@ -120,13 +120,13 @@ protected void restart() throws IOException, TimeoutException { protected void sendRoutable(Binding binding) throws IOException { channel.basicPublish(binding.x, binding.k, null, payload); GetResponse response = channel.basicGet(binding.q, true); - assertNotNull("The response should not be null", response); + assertNotNull(response, "The response should not be null"); } protected void sendUnroutable(Binding binding) throws IOException { channel.basicPublish(binding.x, binding.k, null, payload); GetResponse response = channel.basicGet(binding.q, true); - assertNull("The response SHOULD BE null", response); + assertNull(response, "The response SHOULD BE null"); } protected Binding setupExchangeAndRouteMessage(boolean durable) throws IOException { diff --git a/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java b/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java index ebb54164a3..b65d2ad740 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java +++ b/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,11 +15,11 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.fail; import java.io.IOException; import java.util.*; @@ -27,12 +27,14 @@ import java.util.stream.Collectors; import java.util.stream.IntStream; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.AMQP.BasicProperties; import com.rabbitmq.client.GetResponse; import com.rabbitmq.client.test.BrokerTestCase; +import org.junit.jupiter.api.TestInfo; public class CcRoutes extends BrokerTestCase { @@ -44,8 +46,9 @@ public class CcRoutes extends BrokerTestCase { private List ccList; private List bccList; - @Override public void setUp() throws IOException, TimeoutException { - super.setUp(); + @BeforeEach + @Override public void setUp(TestInfo info) throws IOException, TimeoutException { + super.setUp(info); propsBuilder = new BasicProperties.Builder(); headers = new HashMap<>(); ccList = new ArrayList<>(); diff --git a/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java b/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java index 06f53f715a..2580ed0daf 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/Confirm.java b/src/test/java/com/rabbitmq/client/test/functional/Confirm.java index 0c427bd261..0dbf5950c8 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Confirm.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Confirm.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -16,8 +16,10 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.*; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.AMQP; @@ -35,6 +37,7 @@ import java.util.SortedSet; import java.util.TreeSet; import java.util.concurrent.TimeoutException; +import org.junit.jupiter.api.TestInfo; public class Confirm extends BrokerTestCase { @@ -42,9 +45,10 @@ public class Confirm extends BrokerTestCase private static final String TTL_ARG = "x-message-ttl"; + @BeforeEach @Override - public void setUp() throws IOException, TimeoutException { - super.setUp(); + public void setUp(TestInfo info) throws IOException, TimeoutException { + super.setUp(info); channel.confirmSelect(); channel.queueDeclare("confirm-test", true, true, false, null); channel.queueDeclare("confirm-durable-nonexclusive", true, false, diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionOpen.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionOpen.java index 22fe19e326..646f9e054d 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionOpen.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionOpen.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -16,9 +16,9 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; import java.io.DataInputStream; import java.io.IOException; @@ -26,7 +26,7 @@ import java.util.concurrent.TimeoutException; import com.rabbitmq.client.test.TestUtils; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.ConnectionFactory; @@ -49,13 +49,12 @@ public class ConnectionOpen { while (!command.handleFrame(fh.readFrame())) { } Method m = command.getMethod(); - assertTrue("First command must be Connection.start", - m instanceof AMQP.Connection.Start); + assertTrue(m instanceof AMQP.Connection.Start, "First command must be Connection.start"); AMQP.Connection.Start start = (AMQP.Connection.Start) m; - assertTrue("Version in Connection.start is <= what we sent", - start.getVersionMajor() < AMQP.PROTOCOL.MAJOR || + assertTrue(start.getVersionMajor() < AMQP.PROTOCOL.MAJOR || (start.getVersionMajor() == AMQP.PROTOCOL.MAJOR && - start.getVersionMinor() <= AMQP.PROTOCOL.MINOR)); + start.getVersionMinor() <= AMQP.PROTOCOL.MINOR), + "Version in Connection.start is <= what we sent"); } @Test public void crazyProtocolHeader() throws IOException { diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java index f74ca5e3ae..0f9ff4a055 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -23,7 +23,7 @@ import com.rabbitmq.client.test.BrokerTestCase; import com.rabbitmq.client.test.TestUtils; import com.rabbitmq.tools.Host; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.io.IOException; diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java b/src/test/java/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java index 1c68176d76..7d8631a100 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -20,7 +20,7 @@ import com.rabbitmq.client.DefaultConsumer; import com.rabbitmq.client.ShutdownSignalException; import com.rabbitmq.client.test.BrokerTestCase; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.util.concurrent.ArrayBlockingQueue; @@ -28,8 +28,8 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; public class ConsumerCancelNotification extends BrokerTestCase { diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConsumerCount.java b/src/test/java/com/rabbitmq/client/test/functional/ConsumerCount.java index b0ba1c3206..eca4b57c48 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConsumerCount.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConsumerCount.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,11 +15,11 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import java.io.IOException; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.DefaultConsumer; import com.rabbitmq.client.test.BrokerTestCase; diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConsumerPriorities.java b/src/test/java/com/rabbitmq/client/test/functional/ConsumerPriorities.java index 10bde1f0f1..db0ebc1212 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConsumerPriorities.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConsumerPriorities.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -16,10 +16,10 @@ package com.rabbitmq.client.test.functional; import com.rabbitmq.client.test.BrokerTestCase; -import org.junit.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; import java.io.IOException; import java.util.Arrays; @@ -75,15 +75,15 @@ private void assertFailValidation(Map args) throws IOException { assertContents(highConsumer, COUNT, "high"); channel.basicCancel(high); assertTrue( - "High priority consumer should have been cancelled", - highConsumer.cancelLatch.await(CANCEL_OK_TIMEOUT_MS, TimeUnit.MILLISECONDS) + highConsumer.cancelLatch.await(CANCEL_OK_TIMEOUT_MS, TimeUnit.MILLISECONDS), + "High priority consumer should have been cancelled" ); publish(queue, COUNT, "med"); assertContents(medConsumer, COUNT, "med"); channel.basicCancel(med); assertTrue( - "Medium priority consumer should have been cancelled", - medConsumer.cancelLatch.await(CANCEL_OK_TIMEOUT_MS, TimeUnit.MILLISECONDS) + medConsumer.cancelLatch.await(CANCEL_OK_TIMEOUT_MS, TimeUnit.MILLISECONDS), + "Medium priority consumer should have been cancelled" ); publish(queue, COUNT, "low"); assertContents(lowConsumer, COUNT, "low"); diff --git a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java index b88794cc06..5ac9e20895 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java @@ -20,7 +20,7 @@ import com.rabbitmq.client.test.BrokerTestCase; import com.rabbitmq.client.test.TestUtils; import java.util.concurrent.atomic.AtomicReference; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.util.*; @@ -29,7 +29,7 @@ import static com.rabbitmq.client.test.TestUtils.safeDelete; import static com.rabbitmq.client.test.TestUtils.waitAtMost; import static java.time.Duration.ofSeconds; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; public class DeadLetterExchange extends BrokerTestCase { @@ -424,8 +424,7 @@ public void handleDelivery(String consumerTag, Envelope envelope, return responseRefeference.get() != null; }); GetResponse getResponse = responseRefeference.get(); - assertNotNull("Message not dead-lettered", - getResponse); + assertNotNull(getResponse, "Message not dead-lettered"); assertEquals("test message", new String(getResponse.getBody())); BasicProperties props = getResponse.getProps(); Map headers = props.getHeaders(); @@ -459,7 +458,7 @@ public void handleDelivery(String consumerTag, Envelope envelope, return responseRefeference.get() != null; }); getResponse = responseRefeference.get(); - assertNotNull("Message not dead-lettered", getResponse); + assertNotNull(getResponse, "Message not dead-lettered"); assertEquals("test message", new String(getResponse.getBody())); headers = getResponse.getProps().getHeaders(); assertNotNull(headers); @@ -488,7 +487,7 @@ public void handleDelivery(String consumerTag, Envelope envelope, }); getResponse = responseRefeference.get(); - assertNotNull("Message not dead-lettered", getResponse); + assertNotNull(getResponse, "Message not dead-lettered"); assertEquals("test message", new String(getResponse.getBody())); headers = getResponse.getProps().getHeaders(); assertNotNull(headers); @@ -587,14 +586,14 @@ private void checkPromptArrival(AccumulatingMessageConsumer c, long epsilon = TTL / 5; for (int i = 0; i < count; i++) { byte[] body = c.nextDelivery(TTL + TTL + latency + epsilon); - assertNotNull("message #" + i + " did not expire", body); + assertNotNull(body, "message #" + i + " did not expire"); long now = System.currentTimeMillis(); long publishTime = Long.valueOf(new String(body)); long targetTime = publishTime + TTL + latency; - assertTrue("expiry outside bounds (+/- " + epsilon + "): " + - (now - targetTime), - (now >= targetTime - epsilon) && - (now <= targetTime + epsilon)); + assertTrue((now >= targetTime - epsilon) && + (now <= targetTime + epsilon), + "expiry outside bounds (+/- " + epsilon + "): " + + (now - targetTime)); } } @@ -666,13 +665,12 @@ private static void consumeN(Channel channel, String queue, int n, WithResponse for(int x = 0; x < n; x++) { GetResponse getResponse = channel.basicGet(queue, true); - assertNotNull("Messages not dead-lettered (" + (n-x) + " left)", - getResponse); + assertNotNull(getResponse, "Messages not dead-lettered (" + (n-x) + " left)"); assertEquals("test message", new String(getResponse.getBody())); withResponse.process(getResponse); } GetResponse getResponse = channel.basicGet(queue, true); - assertNull("expected empty queue", getResponse); + assertNull(getResponse, "expected empty queue"); } @SuppressWarnings("unchecked") diff --git a/src/test/java/com/rabbitmq/client/test/functional/DefaultExchange.java b/src/test/java/com/rabbitmq/client/test/functional/DefaultExchange.java index 7d0e9f7899..72c2793f9b 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DefaultExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DefaultExchange.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,11 +15,11 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.fail; import java.io.IOException; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.test.BrokerTestCase; diff --git a/src/test/java/com/rabbitmq/client/test/functional/DirectReplyTo.java b/src/test/java/com/rabbitmq/client/test/functional/DirectReplyTo.java index 2cef783ba1..84911f447c 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DirectReplyTo.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DirectReplyTo.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,11 +15,11 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotSame; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotSame; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; import java.util.concurrent.BlockingQueue; @@ -27,7 +27,7 @@ import java.util.concurrent.TimeUnit; import com.rabbitmq.client.*; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.test.BrokerTestCase; @@ -92,7 +92,7 @@ private void declare(Connection connection, String q, boolean expectedExists) th } } - @Test public void consumeSuccess() throws IOException, InterruptedException { + @Test public void consumeSuccess() throws IOException { DefaultConsumer c = new DefaultConsumer(channel); String ctag = channel.basicConsume(QUEUE, true, c); channel.basicCancel(ctag); diff --git a/src/test/java/com/rabbitmq/client/test/functional/DoubleDeletion.java b/src/test/java/com/rabbitmq/client/test/functional/DoubleDeletion.java index 14f6dee293..c28bab794c 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DoubleDeletion.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DoubleDeletion.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -18,7 +18,7 @@ import java.io.IOException; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.test.BrokerTestCase; diff --git a/src/test/java/com/rabbitmq/client/test/functional/DurableOnTransient.java b/src/test/java/com/rabbitmq/client/test/functional/DurableOnTransient.java index cfc00d7b0a..3732ff55ac 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DurableOnTransient.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DurableOnTransient.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -16,11 +16,11 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNotNull; import java.io.IOException; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.GetResponse; import com.rabbitmq.client.MessageProperties; diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExceptionHandling.java b/src/test/java/com/rabbitmq/client/test/functional/ExceptionHandling.java index 611a8eea82..700a6dda52 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExceptionHandling.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExceptionHandling.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,8 +15,8 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; import java.io.IOException; import java.util.concurrent.CountDownLatch; @@ -24,7 +24,7 @@ import java.util.concurrent.TimeoutException; import com.rabbitmq.client.test.TestUtils; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExceptionMessages.java b/src/test/java/com/rabbitmq/client/test/functional/ExceptionMessages.java index 68f4da2204..672db4dfa8 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExceptionMessages.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExceptionMessages.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,13 +15,13 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; import java.io.IOException; import java.util.UUID; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.AlreadyClosedException; import com.rabbitmq.client.test.BrokerTestCase; diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java index 7c1e6f2e76..b6976ee873 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -16,7 +16,7 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import java.io.IOException; import java.util.HashMap; @@ -24,7 +24,7 @@ import java.util.concurrent.TimeoutException; import com.rabbitmq.client.test.TestUtils; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.BuiltinExchangeType; import com.rabbitmq.client.Channel; @@ -101,7 +101,7 @@ public void releaseResources() throws IOException { } private void doTestExchangeDeclaredWithEnumerationEquivalent(Channel channel) throws IOException, InterruptedException { - assertEquals("There are 4 standard exchange types", 4, BuiltinExchangeType.values().length); + assertEquals(4, BuiltinExchangeType.values().length, "There are 4 standard exchange types"); for (BuiltinExchangeType exchangeType : BuiltinExchangeType.values()) { channel.exchangeDeclare(NAME, exchangeType); verifyEquivalent(NAME, exchangeType.getType(), false, false, null); diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java index bbaf6b323c..299d95567f 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -16,12 +16,12 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.fail; import java.io.IOException; import java.util.concurrent.TimeoutException; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.test.BrokerTestCase; diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeletePredeclared.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeletePredeclared.java index 28d4d667f6..4229c888ed 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeletePredeclared.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeletePredeclared.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java index 830a2b89e5..cfeed037d4 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,7 +15,7 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.fail; import java.io.IOException; import java.util.Map; diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java index cc50182001..3416b334d6 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -16,12 +16,12 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import java.io.IOException; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.QueueingConsumer; import com.rabbitmq.client.QueueingConsumer.Delivery; diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java index ff8cb0a846..a6f01e20c4 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -16,11 +16,11 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.fail; import java.io.IOException; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.test.BrokerTestCase; diff --git a/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java b/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java index bfe1bcd826..bafceed32d 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java +++ b/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -16,9 +16,9 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; @@ -32,7 +32,7 @@ import com.rabbitmq.client.impl.AMQBasicProperties; import com.rabbitmq.client.test.TestUtils; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Address; diff --git a/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java b/src/test/java/com/rabbitmq/client/test/functional/FunctionalTestSuite.java similarity index 84% rename from src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java rename to src/test/java/com/rabbitmq/client/test/functional/FunctionalTestSuite.java index 892f4977ba..bbf06691e1 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/FunctionalTests.java +++ b/src/test/java/com/rabbitmq/client/test/functional/FunctionalTestSuite.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2022 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -17,14 +17,12 @@ package com.rabbitmq.client.test.functional; import com.rabbitmq.client.impl.WorkPoolTests; -import com.rabbitmq.client.test.AbstractRMQTestSuite; import com.rabbitmq.client.test.Bug20004Test; -import com.rabbitmq.client.test.RequiredPropertiesSuite; -import org.junit.runner.RunWith; -import org.junit.runners.Suite; +import org.junit.platform.suite.api.SelectClasses; +import org.junit.platform.suite.api.Suite; -@RunWith(RequiredPropertiesSuite.class) -@Suite.SuiteClasses({ +@Suite +@SelectClasses({ ConnectionOpen.class, Heartbeat.class, Tables.class, @@ -81,11 +79,6 @@ TopologyRecoveryFiltering.class, TopologyRecoveryRetry.class }) -public class FunctionalTests { - - // initialize system properties - static{ - new AbstractRMQTestSuite(){}; - } +public class FunctionalTestSuite { } diff --git a/src/test/java/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java b/src/test/java/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java index c82ed749b6..49b0779c8c 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java +++ b/src/test/java/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2022 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,13 +15,13 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.fail; import com.rabbitmq.client.test.TestUtils; import java.io.IOException; import java.util.HashMap; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; diff --git a/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java b/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java index 62611f2a35..002c60b487 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -19,11 +19,11 @@ import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; import com.rabbitmq.client.test.BrokerTestCase; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.io.IOException; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; public class Heartbeat extends BrokerTestCase { diff --git a/src/test/java/com/rabbitmq/client/test/functional/InternalExchange.java b/src/test/java/com/rabbitmq/client/test/functional/InternalExchange.java index 43a571afc8..12bfc7c76d 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/InternalExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/InternalExchange.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -16,12 +16,12 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; import java.util.Arrays; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.GetResponse; diff --git a/src/test/java/com/rabbitmq/client/test/functional/InvalidAcks.java b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcks.java index 217c55e1c9..08dc083f6f 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/InvalidAcks.java +++ b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcks.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksBase.java b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksBase.java index 1c249007bd..f24e848c63 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksBase.java +++ b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksBase.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -20,7 +20,7 @@ import java.io.IOException; -import org.junit.Test; +import org.junit.jupiter.api.Test; /** * See bug 21846: diff --git a/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksTx.java b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksTx.java index 81fc7e61f7..2df62e23ed 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksTx.java +++ b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksTx.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/MessageCount.java b/src/test/java/com/rabbitmq/client/test/functional/MessageCount.java index 3cb81344af..8ccef02846 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/MessageCount.java +++ b/src/test/java/com/rabbitmq/client/test/functional/MessageCount.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,11 +15,11 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import java.io.IOException; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.test.BrokerTestCase; diff --git a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java index ab3d7f717f..95e47cb9f9 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java @@ -17,7 +17,6 @@ import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; -import com.rabbitmq.client.ConfirmCallback; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.DefaultConsumer; @@ -32,9 +31,7 @@ import com.rabbitmq.client.test.TestUtils; import com.rabbitmq.tools.Host; import java.util.UUID; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.lang.reflect.Field; @@ -50,6 +47,8 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import static com.rabbitmq.client.test.TestUtils.waitAtMost; import static org.assertj.core.api.Assertions.assertThat; @@ -57,17 +56,12 @@ /** * */ -@RunWith(Parameterized.class) public class Metrics extends BrokerTestCase { - @Parameterized.Parameters public static Object[] data() { return new Object[] { createConnectionFactory(), createAutoRecoveryConnectionFactory() }; } - @Parameterized.Parameter - public ConnectionFactory connectionFactory; - static final String QUEUE = "metrics.queue"; @Override @@ -80,7 +74,9 @@ protected void releaseResources() throws IOException { channel.queueDelete(QUEUE); } - @Test public void metrics() throws IOException, TimeoutException { + @ParameterizedTest + @MethodSource("data") + public void metrics(ConnectionFactory connectionFactory) throws IOException, TimeoutException { StandardMetricsCollector metrics = new StandardMetricsCollector(); connectionFactory.setMetricsCollector(metrics); Connection connection1 = null; @@ -139,7 +135,9 @@ protected void releaseResources() throws IOException { } } - @Test public void metricsPublisherUnrouted() throws IOException, TimeoutException { + @ParameterizedTest + @MethodSource("data") + public void metricsPublisherUnrouted(ConnectionFactory connectionFactory) throws IOException, TimeoutException { StandardMetricsCollector metrics = new StandardMetricsCollector(); connectionFactory.setMetricsCollector(metrics); Connection connection = null; @@ -163,7 +161,9 @@ protected void releaseResources() throws IOException { } } - @Test public void metricsPublisherAck() throws IOException, TimeoutException, InterruptedException { + @ParameterizedTest + @MethodSource("data") + public void metricsPublisherAck(ConnectionFactory connectionFactory) throws IOException, TimeoutException, InterruptedException { StandardMetricsCollector metrics = new StandardMetricsCollector(); connectionFactory.setMetricsCollector(metrics); Connection connection = null; @@ -188,7 +188,9 @@ protected void releaseResources() throws IOException { } } - @Test public void metricsAck() throws IOException, TimeoutException { + @ParameterizedTest + @MethodSource("data") + public void metricsAck(ConnectionFactory connectionFactory) throws IOException, TimeoutException { StandardMetricsCollector metrics = new StandardMetricsCollector(); connectionFactory.setMetricsCollector(metrics); @@ -254,7 +256,9 @@ protected void releaseResources() throws IOException { } } - @Test public void metricsReject() throws IOException, TimeoutException { + @ParameterizedTest + @MethodSource("data") + public void metricsReject(ConnectionFactory connectionFactory) throws IOException, TimeoutException { StandardMetricsCollector metrics = new StandardMetricsCollector(); connectionFactory.setMetricsCollector(metrics); @@ -281,7 +285,9 @@ protected void releaseResources() throws IOException { } } - @Test public void multiThreadedMetricsStandardConnection() throws InterruptedException, TimeoutException, IOException { + @ParameterizedTest + @MethodSource("data") + public void multiThreadedMetricsStandardConnection(ConnectionFactory connectionFactory) throws InterruptedException, TimeoutException, IOException { StandardMetricsCollector metrics = new StandardMetricsCollector(); connectionFactory.setMetricsCollector(metrics); int nbConnections = 3; @@ -391,7 +397,9 @@ protected void releaseResources() throws IOException { } } - @Test public void errorInChannel() throws IOException, TimeoutException { + @ParameterizedTest + @MethodSource("data") + public void errorInChannel(ConnectionFactory connectionFactory) throws IOException, TimeoutException { StandardMetricsCollector metrics = new StandardMetricsCollector(); connectionFactory.setMetricsCollector(metrics); diff --git a/src/test/java/com/rabbitmq/client/test/functional/Nack.java b/src/test/java/com/rabbitmq/client/test/functional/Nack.java index ce9b70ddd0..6bd47e6067 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Nack.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Nack.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -16,8 +16,8 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import com.rabbitmq.client.Channel; import com.rabbitmq.client.test.TestUtils; @@ -27,17 +27,14 @@ import java.util.Set; import java.util.UUID; -import org.junit.Test; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.QueueingConsumer; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; -@RunWith(Parameterized.class) public class Nack extends AbstractRejectTest { - @Parameterized.Parameters public static Object[] queueCreators() { return new Object[] { (CallableFunction) channel -> { @@ -52,9 +49,9 @@ public static Object[] queueCreators() { }}; } - @Parameterized.Parameter public TestUtils.CallableFunction queueCreator; - - @Test public void singleNack() throws Exception { + @ParameterizedTest + @MethodSource("queueCreators") + public void singleNack(TestUtils.CallableFunction queueCreator) throws Exception { String q = queueCreator.apply(channel); byte[] m1 = "1".getBytes(); @@ -89,7 +86,9 @@ public static Object[] queueCreators() { expectError(AMQP.PRECONDITION_FAILED); } - @Test public void multiNack() throws Exception { + @ParameterizedTest + @MethodSource("queueCreators") + public void multiNack(TestUtils.CallableFunction queueCreator) throws Exception { String q = queueCreator.apply(channel); byte[] m1 = "1".getBytes(); @@ -134,7 +133,9 @@ public static Object[] queueCreators() { expectError(AMQP.PRECONDITION_FAILED); } - @Test public void nackAll() throws Exception { + @ParameterizedTest + @MethodSource("queueCreators") + public void nackAll(TestUtils.CallableFunction queueCreator) throws Exception { String q = queueCreator.apply(channel); byte[] m1 = "1".getBytes(); @@ -173,7 +174,7 @@ private long checkDeliveries(QueueingConsumer c, byte[]... messages) for(int x = 0; x < messages.length; x++) { QueueingConsumer.Delivery delivery = c.nextDelivery(); String m = new String(delivery.getBody()); - assertTrue("Unexpected message", msgSet.remove(m)); + assertTrue(msgSet.remove(m), "Unexpected message"); checkDelivery(delivery, m.getBytes(), true); lastTag = delivery.getEnvelope().getDeliveryTag(); } diff --git a/src/test/java/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java b/src/test/java/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java index 41d68d94d5..f93f8f591b 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java +++ b/src/test/java/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -16,16 +16,16 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import com.rabbitmq.client.*; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.test.BrokerTestCase; diff --git a/src/test/java/com/rabbitmq/client/test/functional/Nowait.java b/src/test/java/com/rabbitmq/client/test/functional/Nowait.java index 5f713fff61..b795f02482 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Nowait.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Nowait.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java b/src/test/java/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java index 4a36a22052..51149c613f 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java +++ b/src/test/java/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -21,7 +21,7 @@ import java.util.Arrays; import java.util.List; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.GetResponse; import com.rabbitmq.client.QueueingConsumer; diff --git a/src/test/java/com/rabbitmq/client/test/functional/PerMessageTTL.java b/src/test/java/com/rabbitmq/client/test/functional/PerMessageTTL.java index 1a93e6abe4..2b6bb3ed99 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/PerMessageTTL.java +++ b/src/test/java/com/rabbitmq/client/test/functional/PerMessageTTL.java @@ -16,12 +16,12 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; import java.io.IOException; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.MessageProperties; @@ -58,8 +58,8 @@ protected AMQP.Queue.DeclareOk declareQueue(String name, Object ttlValue) throws QueueingConsumer c = new QueueingConsumer(channel); channel.basicConsume(TTL_QUEUE_NAME, c); - assertNotNull("Message unexpectedly expired", c.nextDelivery(100)); - assertNull("Message should have been expired!!", c.nextDelivery(100)); + assertNotNull(c.nextDelivery(100), "Message unexpectedly expired"); + assertNull(c.nextDelivery(100), "Message should have been expired!!"); } @Test public void restartingExpiry() throws Exception { @@ -74,7 +74,7 @@ protected AMQP.Queue.DeclareOk declareQueue(String name, Object ttlValue) throws restart(); Thread.sleep(Integer.parseInt(expiryDelay)); try { - assertNull("Message should have expired after broker restart", get()); + assertNull(get(), "Message should have expired after broker restart"); } finally { deleteQueue(TTL_QUEUE_NAME); } diff --git a/src/test/java/com/rabbitmq/client/test/functional/PerQueueTTL.java b/src/test/java/com/rabbitmq/client/test/functional/PerQueueTTL.java index 506ea50c8f..177a67cd58 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/PerQueueTTL.java +++ b/src/test/java/com/rabbitmq/client/test/functional/PerQueueTTL.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -16,13 +16,13 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.fail; import java.io.IOException; import java.util.Collections; import java.util.Map; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.MessageProperties; diff --git a/src/test/java/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java b/src/test/java/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java index 58475877be..e835b42c0f 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java +++ b/src/test/java/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,13 +15,13 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.assertNull; +import static org.junit.jupiter.api.Assertions.assertNull; import java.io.IOException; import java.util.Collections; import java.util.Map; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.AMQP; @@ -35,7 +35,7 @@ public class PerQueueVsPerMessageTTL extends PerMessageTTL { Thread.sleep(100); - assertNull("per-queue ttl should have removed message after 10ms!", get()); + assertNull(get(), "per-queue ttl should have removed message after 10ms"); } @Override diff --git a/src/test/java/com/rabbitmq/client/test/functional/Policies.java b/src/test/java/com/rabbitmq/client/test/functional/Policies.java index f4d1dd4988..602e2b57c4 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Policies.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Policies.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,9 +15,9 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; import java.util.HashMap; @@ -25,12 +25,11 @@ import java.util.Map; import java.util.Set; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.Channel; import com.rabbitmq.client.GetResponse; import com.rabbitmq.client.test.BrokerTestCase; -import com.rabbitmq.client.test.server.HATests; import com.rabbitmq.tools.Host; public class Policies extends BrokerTestCase { @@ -184,7 +183,7 @@ private void setPolicy(String name, String pattern, String definition) throws IO // We need to override the HA policy that we use in HATests, so // priority 1. But we still want a valid test of HA, so add the // ha-mode definition. - if (HATests.HA_TESTS_RUNNING) { + if (ha()) { definition += ",\"ha-mode\":\"all\""; } Host.rabbitmqctl("set_policy --priority 1 " + name + " " + pattern + diff --git a/src/test/java/com/rabbitmq/client/test/functional/QosTests.java b/src/test/java/com/rabbitmq/client/test/functional/QosTests.java index 276a363f4e..b14d5526c3 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QosTests.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QosTests.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -16,10 +16,10 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; import java.io.IOException; import java.util.ArrayList; @@ -31,7 +31,7 @@ import java.util.Map; import java.util.concurrent.TimeoutException; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; diff --git a/src/test/java/com/rabbitmq/client/test/functional/QueueExclusivity.java b/src/test/java/com/rabbitmq/client/test/functional/QueueExclusivity.java index 6148ebab27..83df293a10 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QueueExclusivity.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QueueExclusivity.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -16,13 +16,13 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.fail; import java.io.IOException; import java.util.HashMap; import java.util.concurrent.TimeoutException; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; diff --git a/src/test/java/com/rabbitmq/client/test/functional/QueueLease.java b/src/test/java/com/rabbitmq/client/test/functional/QueueLease.java index 284f6bd67d..46a31f8b3e 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QueueLease.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QueueLease.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -16,13 +16,13 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.fail; import java.io.IOException; import java.util.HashMap; import java.util.Map; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Consumer; diff --git a/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java b/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java index 8ee54671dc..ceedb520ad 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -20,14 +20,14 @@ import com.rabbitmq.client.Consumer; import com.rabbitmq.client.DefaultConsumer; import com.rabbitmq.client.test.BrokerTestCase; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeoutException; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.fail; /** * Test queue auto-delete and exclusive semantics. diff --git a/src/test/java/com/rabbitmq/client/test/functional/QueueSizeLimit.java b/src/test/java/com/rabbitmq/client/test/functional/QueueSizeLimit.java index 8d34862543..c0c9350173 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QueueSizeLimit.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QueueSizeLimit.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -16,9 +16,9 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; import java.io.IOException; import java.util.ArrayList; @@ -26,7 +26,7 @@ import java.util.List; import java.util.Map; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.GetResponse; import com.rabbitmq.client.test.BrokerTestCase; diff --git a/src/test/java/com/rabbitmq/client/test/functional/Recover.java b/src/test/java/com/rabbitmq/client/test/functional/Recover.java index 61d48973ce..a83c75c9ca 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Recover.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Recover.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -16,10 +16,10 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; import java.io.IOException; import java.util.Arrays; @@ -28,7 +28,7 @@ import java.util.concurrent.atomic.AtomicReference; import com.rabbitmq.client.*; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.test.BrokerTestCase; @@ -56,14 +56,12 @@ void verifyRedeliverOnRecover(RecoverCallback call) channel.basicConsume(queue, false, consumer); // require acks. channel.basicPublish("", queue, new AMQP.BasicProperties.Builder().build(), body); QueueingConsumer.Delivery delivery = consumer.nextDelivery(); - assertTrue("consumed message body not as sent", - Arrays.equals(body, delivery.getBody())); + assertTrue(Arrays.equals(body, delivery.getBody()), "consumed message body not as sent"); // Don't ack it, and get it redelivered to the same consumer call.recover(channel); QueueingConsumer.Delivery secondDelivery = consumer.nextDelivery(5000); - assertNotNull("timed out waiting for redelivered message", secondDelivery); - assertTrue("consumed (redelivered) message body not as sent", - Arrays.equals(body, delivery.getBody())); + assertNotNull(secondDelivery, "timed out waiting for redelivered message"); + assertTrue(Arrays.equals(body, delivery.getBody()), "consumed (redelivered) message body not as sent"); } void verifyNoRedeliveryWithAutoAck(RecoverCallback call) @@ -80,10 +78,9 @@ public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProp channel.basicConsume(queue, true, consumer); // auto ack. channel.basicPublish("", queue, new AMQP.BasicProperties.Builder().build(), body); assertTrue(latch.await(5, TimeUnit.SECONDS)); - assertTrue("consumed message body not as sent", - Arrays.equals(body, bodyReference.get())); + assertTrue(Arrays.equals(body, bodyReference.get()), "consumed message body not as sent"); call.recover(channel); - assertNull("should be no message available", channel.basicGet(queue, true)); + assertNull(channel.basicGet(queue, true), "should be no message available"); } final RecoverCallback recoverSync = new RecoverCallback() { diff --git a/src/test/java/com/rabbitmq/client/test/functional/Reject.java b/src/test/java/com/rabbitmq/client/test/functional/Reject.java index c2c5dd76bd..b8abaf0779 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Reject.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Reject.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -16,7 +16,7 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.assertNull; +import static org.junit.jupiter.api.Assertions.assertNull; import com.rabbitmq.client.Channel; import com.rabbitmq.client.test.TestUtils; @@ -24,19 +24,16 @@ import java.util.Collections; import java.util.UUID; -import org.junit.Test; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.QueueingConsumer; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; -@RunWith(Parameterized.class) public class Reject extends AbstractRejectTest { - @Parameterized.Parameters - public static Object[] queueCreators() { + public static Object[] reject() { return new Object[] { (CallableFunction) channel -> { String q = UUID.randomUUID().toString(); @@ -50,9 +47,9 @@ public static Object[] queueCreators() { }}; } - @Parameterized.Parameter public TestUtils.CallableFunction queueCreator; - - @Test public void reject() + @ParameterizedTest + @MethodSource + public void reject(TestUtils.CallableFunction queueCreator) throws Exception { String q = queueCreator.apply(channel); diff --git a/src/test/java/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java index 8e6c0c6f9e..250b74acf0 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java +++ b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/RequeueOnClose.java b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnClose.java index e86ed31bdf..7fee64f715 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/RequeueOnClose.java +++ b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnClose.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,8 +15,8 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.*; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.test.BrokerTestCase; @@ -84,9 +84,9 @@ private void publishAndGet(int count, boolean doAck) close(); open(); if (doAck) { - assertNull("Expected missing second basicGet (repeat="+repeat+")", getMessage()); + assertNull(getMessage(), "Expected missing second basicGet (repeat="+repeat+")"); } else { - assertNotNull("Expected present second basicGet (repeat="+repeat+")", getMessage()); + assertNotNull(getMessage(), "Expected present second basicGet (repeat="+repeat+")"); } close(); } @@ -146,10 +146,10 @@ private void publishLotsAndGet() close(); open(); for (int i = 0; i < MESSAGE_COUNT; i++) { - assertNotNull("only got " + i + " out of " + MESSAGE_COUNT + - " messages", channel.basicGet(Q, true)); + assertNotNull(channel.basicGet(Q, true), "only got " + i + " out of " + MESSAGE_COUNT + + " messages"); } - assertNull("got more messages than " + MESSAGE_COUNT + " expected", channel.basicGet(Q, true)); + assertNull(channel.basicGet(Q, true), "got more messages than " + MESSAGE_COUNT + " expected"); channel.queueDelete(Q); close(); closeConnection(); @@ -232,14 +232,13 @@ private void publishLotsAndConsumeSome(boolean ack, boolean cancelBeforeFinish) open(); int requeuedMsgCount = (ack) ? MESSAGE_COUNT - MESSAGES_TO_CONSUME : MESSAGE_COUNT; for (int i = 0; i < requeuedMsgCount; i++) { - assertNotNull("only got " + i + " out of " + requeuedMsgCount + " messages", - channel.basicGet(Q, true)); + assertNotNull(channel.basicGet(Q, true), "only got " + i + " out of " + requeuedMsgCount + " messages"); } int countMoreMsgs = 0; while (null != channel.basicGet(Q, true)) { countMoreMsgs++; } - assertTrue("got " + countMoreMsgs + " more messages than " + requeuedMsgCount + " expected", 0==countMoreMsgs); + assertTrue(0==countMoreMsgs, "got " + countMoreMsgs + " more messages than " + requeuedMsgCount + " expected"); channel.queueDelete(Q); close(); closeConnection(); diff --git a/src/test/java/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java index c212512a95..126c1bd71a 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java +++ b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/Routing.java b/src/test/java/com/rabbitmq/client/test/functional/Routing.java index 30a643a918..9f681d75e6 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Routing.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Routing.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2022 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -16,14 +16,13 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.fail; -import com.rabbitmq.client.test.TestUtils.BrokerAtLeast310Condition; -import com.rabbitmq.client.test.TestUtils.ExecutionConditionRule; -import com.rabbitmq.client.test.TestUtils.TestExecutionCondition; +import com.rabbitmq.client.test.TestUtils.BrokerVersion; +import com.rabbitmq.client.test.TestUtils.BrokerVersionAtLeast; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; @@ -31,8 +30,7 @@ import java.util.Map; import java.util.concurrent.TimeoutException; -import org.junit.Rule; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.AlreadyClosedException; @@ -40,13 +38,10 @@ import com.rabbitmq.client.ReturnListener; import com.rabbitmq.client.test.BrokerTestCase; import com.rabbitmq.utility.BlockingCell; -import org.junit.rules.TestRule; public class Routing extends BrokerTestCase { - @Rule public TestRule executionConditionRule = new ExecutionConditionRule(); - protected final String E = "MRDQ"; protected final String Q1 = "foo"; protected final String Q2 = "bar"; @@ -253,7 +248,7 @@ private void checkGet(String queue, boolean messageExpected) } @Test - @TestExecutionCondition(BrokerAtLeast310Condition.class) + @BrokerVersionAtLeast(BrokerVersion.RABBITMQ_3_10) public void headersWithXRouting() throws Exception { Map spec = new HashMap(); spec.put("x-key-1", "value-1"); diff --git a/src/test/java/com/rabbitmq/client/test/functional/SaslMechanisms.java b/src/test/java/com/rabbitmq/client/test/functional/SaslMechanisms.java index 631d21a2a5..c40718f732 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/SaslMechanisms.java +++ b/src/test/java/com/rabbitmq/client/test/functional/SaslMechanisms.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,7 +15,7 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.fail; import java.io.IOException; import java.util.Arrays; @@ -23,7 +23,7 @@ import java.util.concurrent.TimeoutException; import com.rabbitmq.client.test.TestUtils; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.AuthenticationFailureException; import com.rabbitmq.client.Connection; diff --git a/src/test/java/com/rabbitmq/client/test/functional/TTLHandling.java b/src/test/java/com/rabbitmq/client/test/functional/TTLHandling.java index c07a675882..8d50b7e059 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/TTLHandling.java +++ b/src/test/java/com/rabbitmq/client/test/functional/TTLHandling.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,15 +15,15 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.fail; import com.rabbitmq.client.ShutdownSignalException; import java.io.IOException; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.GetResponse; @@ -112,7 +112,7 @@ protected void releaseResources() throws IOException { Thread.sleep(1000); String what = get(); - assertNull("expected message " + what + " to have been removed", what); + assertNull(what, "expected message " + what + " to have been removed"); } @Test public void publishAndGetWithExpiry() throws Exception { @@ -183,7 +183,7 @@ protected void releaseResources() throws IOException { Thread.sleep(150); openChannel(); - assertNull("Re-queued message not expired", get()); + assertNull(get(), "Re-queued message not expired"); } @Test public void zeroTTLDelivery() throws Exception { diff --git a/src/test/java/com/rabbitmq/client/test/functional/Tables.java b/src/test/java/com/rabbitmq/client/test/functional/Tables.java index 6f8f1854a8..a1e405c7f8 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Tables.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Tables.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -16,8 +16,8 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; import java.math.BigDecimal; @@ -29,7 +29,7 @@ import java.util.Map; import java.util.Set; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.AMQP.BasicProperties; @@ -87,18 +87,17 @@ private static void assertMapsEqual(Map a, Object va = a.get(k); Object vb = b.get(k); if (va instanceof byte[] && vb instanceof byte[]) { - assertTrue("unequal entry for key " + k, - Arrays.equals((byte[])va, (byte[])vb)); + assertTrue(Arrays.equals((byte[])va, (byte[])vb), "unequal entry for key " + k); } else if (va instanceof List && vb instanceof List) { Iterator vbi = ((List)vb).iterator(); for (Object vaEntry : (List)va) { Object vbEntry = vbi.next(); - assertEquals("arrays unequal at key " + k, vaEntry, vbEntry); + assertEquals(vaEntry, vbEntry, "arrays unequal at key " + k); } } else { - assertEquals("unequal entry for key " + k, va, vb); + assertEquals(va, vb, "unequal entry for key " + k); } } } diff --git a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java index 3879359959..1af68242b4 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java +++ b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2018-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -30,7 +30,7 @@ import com.rabbitmq.client.test.BrokerTestCase; import com.rabbitmq.client.test.TestUtils; import java.util.UUID; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.time.Duration; @@ -40,8 +40,8 @@ import java.util.concurrent.atomic.AtomicInteger; import static com.rabbitmq.client.test.TestUtils.*; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * @@ -117,12 +117,12 @@ public void topologyRecoveryFilteringBindings() throws Exception { closeAndWaitForRecovery((RecoverableConnection) c); - assertTrue("The message should have been received by now", sendAndConsumeMessage( + assertTrue(sendAndConsumeMessage( "topology.recovery.exchange", "recovered.binding", "topology.recovery.queue.1", c - )); - assertFalse("Binding shouldn't recover, no messages should have been received", sendAndConsumeMessage( + ), "The message should have been received by now"); + assertFalse(sendAndConsumeMessage( "topology.recovery.exchange", "filtered.binding", "topology.recovery.queue.2", c - )); + ), "Binding shouldn't recover, no messages should have been received"); } @Test @@ -166,8 +166,8 @@ public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProp waitAtMost(Duration.ofSeconds(5), () -> recoveredConsumerMessageCount.get() == initialCount + 1); ch.basicPublish("topology.recovery.exchange", "filtered.consumer", null, "".getBytes()); - assertFalse("Consumer shouldn't recover, no extra messages should have been received", - filteredConsumerLatch.await(5, TimeUnit.SECONDS)); + assertFalse(filteredConsumerLatch.await(5, TimeUnit.SECONDS), + "Consumer shouldn't recover, no extra messages should have been received"); } private static class SimpleTopologyRecoveryFilter implements TopologyRecoveryFilter { diff --git a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java index c8d9c894a9..91a777ad1b 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java +++ b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2018-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -27,9 +27,9 @@ import com.rabbitmq.client.test.BrokerTestCase; import com.rabbitmq.client.test.TestUtils; import com.rabbitmq.tools.Host; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.util.HashMap; import java.util.UUID; @@ -39,7 +39,7 @@ import static com.rabbitmq.client.impl.recovery.TopologyRecoveryRetryLogic.RETRY_ON_QUEUE_NOT_FOUND_RETRY_HANDLER; import static com.rabbitmq.client.test.TestUtils.closeAllConnectionsAndWaitForRecovery; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * @@ -48,7 +48,7 @@ public class TopologyRecoveryRetry extends BrokerTestCase { private volatile Consumer backoffConsumer; - @Before + @BeforeEach public void init() { this.backoffConsumer = attempt -> { }; } diff --git a/src/test/java/com/rabbitmq/client/test/functional/Transactions.java b/src/test/java/com/rabbitmq/client/test/functional/Transactions.java index 3e3d66883b..b7890aed45 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Transactions.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Transactions.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -16,14 +16,14 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.fail; import java.io.IOException; import java.util.concurrent.TimeoutException; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.GetResponse; @@ -324,8 +324,7 @@ private long[] publishSelectAndGet(int n) basicAck(); channel.basicRecover(true); - assertNull("Acked uncommitted message redelivered", - basicGet(true)); + assertNull(basicGet(true), "Acked uncommitted message redelivered"); } @Test public void commitWithDeletedQueue() diff --git a/src/test/java/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java b/src/test/java/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java index 29c4faa2b4..08e0b8fbac 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,11 +15,11 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.fail; import java.io.IOException; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.test.BrokerTestCase; diff --git a/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java b/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java index 5c4b707086..d97d520f0f 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java +++ b/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -22,7 +22,7 @@ import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; import com.rabbitmq.client.test.BrokerTestCase; import com.rabbitmq.client.test.TestUtils; -import org.junit.Test; +import org.junit.jupiter.api.Test; import javax.net.SocketFactory; import java.io.IOException; diff --git a/src/test/java/com/rabbitmq/client/test/functional/UserIDHeader.java b/src/test/java/com/rabbitmq/client/test/functional/UserIDHeader.java index d776029df5..1f0383fbde 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/UserIDHeader.java +++ b/src/test/java/com/rabbitmq/client/test/functional/UserIDHeader.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,14 +15,14 @@ package com.rabbitmq.client.test.functional; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.fail; import java.io.IOException; import java.util.concurrent.TimeoutException; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.AlreadyClosedException; diff --git a/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java b/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java index a0e857d828..e304a71db6 100644 --- a/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java +++ b/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -19,14 +19,17 @@ import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; import com.rabbitmq.client.test.functional.ClusteredTestBase; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.util.concurrent.Callable; import java.util.concurrent.TimeoutException; +import org.junit.jupiter.api.TestInfo; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.fail; /** * This tests whether 'absent' queues - durable queues whose home node @@ -36,16 +39,18 @@ public class AbsentQueue extends ClusteredTestBase { private static final String Q = "absent-queue"; - @Override public void setUp() throws IOException, TimeoutException { - super.setUp(); + @BeforeEach + @Override public void setUp(TestInfo info) throws IOException, TimeoutException { + super.setUp(info); if (clusteredConnection != null) stopSecondary(); } - @Override public void tearDown() throws IOException, TimeoutException { + @AfterEach + @Override public void tearDown(TestInfo info) throws IOException, TimeoutException { if (clusteredConnection != null) startSecondary(); - super.tearDown(); + super.tearDown(info); } @Override protected void createResources() throws IOException { @@ -57,7 +62,7 @@ public class AbsentQueue extends ClusteredTestBase { } @Test public void notFound() throws Exception { - if (!HATests.HA_TESTS_RUNNING) { + if (!ha()) { // we don't care about this test in normal mode return; } @@ -73,9 +78,9 @@ protected void assertNotFound(Callable t) throws Exception { if (clusteredChannel == null) return; try { t.call(); - if (!HATests.HA_TESTS_RUNNING) fail("expected not_found"); + if (!ha()) fail("expected not_found"); } catch (IOException ioe) { - assertFalse(HATests.HA_TESTS_RUNNING); + assertFalse(ha()); checkShutdownSignal(AMQP.NOT_FOUND, ioe); channel = connection.createChannel(); } @@ -84,7 +89,7 @@ protected void assertNotFound(Callable t) throws Exception { private void waitPropagationInHa() throws IOException, InterruptedException { // can be necessary to wait a bit in HA mode - if (HATests.HA_TESTS_RUNNING) { + if (ha()) { long waited = 0; while(waited < 5000) { Channel tempChannel = connection.createChannel(); diff --git a/src/test/java/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java b/src/test/java/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java index 676dac7015..a978d06a48 100644 --- a/src/test/java/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java +++ b/src/test/java/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -20,7 +20,7 @@ import java.util.HashMap; import java.util.Map; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.test.functional.ExchangeEquivalenceBase; diff --git a/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java b/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java index 4856ea151b..a80b12387d 100644 --- a/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -16,7 +16,7 @@ package com.rabbitmq.client.test.server; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; import java.util.concurrent.CountDownLatch; @@ -24,7 +24,7 @@ import java.util.concurrent.TimeoutException; import com.rabbitmq.client.test.TestUtils; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.BlockedListener; import com.rabbitmq.client.Channel; diff --git a/src/test/java/com/rabbitmq/client/test/server/Bug19219Test.java b/src/test/java/com/rabbitmq/client/test/server/Bug19219Test.java index e16d40d731..2506ef075a 100644 --- a/src/test/java/com/rabbitmq/client/test/server/Bug19219Test.java +++ b/src/test/java/com/rabbitmq/client/test/server/Bug19219Test.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,14 +15,14 @@ package com.rabbitmq.client.test.server; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeoutException; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; diff --git a/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java b/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java index a890f2ca66..a008c5b44d 100644 --- a/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java +++ b/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,10 +15,10 @@ package com.rabbitmq.client.test.server; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.fail; import java.io.IOException; import java.util.concurrent.Executors; @@ -27,7 +27,7 @@ import com.rabbitmq.client.impl.recovery.AutorecoveringConnection; import com.rabbitmq.client.test.TestUtils; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Connection; diff --git a/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java b/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java index 312ce61810..f280408fa8 100644 --- a/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java +++ b/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,13 +15,13 @@ package com.rabbitmq.client.test.server; -import static org.junit.Assert.assertNull; +import static org.junit.jupiter.api.Assertions.assertNull; import java.io.IOException; import java.util.HashMap; import java.util.Map; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.MessageProperties; import com.rabbitmq.client.test.BrokerTestCase; @@ -51,7 +51,7 @@ protected void releaseResources() throws IOException { @Test public void deadLetterQueueTTLExpiredWhileDown() throws Exception { // This test is nonsensical (and often breaks) in HA mode. - if (HATests.HA_TESTS_RUNNING) return; + if (ha()) return; for(int x = 0; x < DeadLetterExchange.MSG_COUNT; x++) { channel.basicPublish("amq.direct", "test", MessageProperties.MINIMAL_PERSISTENT_BASIC, "test message".getBytes()); diff --git a/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java b/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java index 5146cac8fb..0b5d19d529 100644 --- a/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java +++ b/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2022 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -18,13 +18,13 @@ import static com.rabbitmq.client.test.TestUtils.waitAtMost; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.assertNull; +import static org.junit.jupiter.api.Assertions.assertNull; import java.io.IOException; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.GetResponse; import com.rabbitmq.client.test.functional.BindingLifecycleBase; @@ -55,9 +55,9 @@ protected void restart() throws IOException, TimeoutException { } private void restartPrimary() throws IOException, TimeoutException { - tearDown(); + tearDown(this.testInfo); bareRestart(); - setUp(); + setUp(this.testInfo); } /** @@ -120,7 +120,7 @@ private void restartPrimary() throws IOException, TimeoutException { } GetResponse response = channel.basicGet(Q, true); - assertNull("The initial response SHOULD BE null", response); + assertNull(response, "The initial response SHOULD BE null"); deleteQueue(Q); deleteExchange(X); diff --git a/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java b/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java index bf3c56bf58..db5d63ef7a 100644 --- a/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java +++ b/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,12 +15,12 @@ package com.rabbitmq.client.test.server; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import java.io.IOException; import java.util.concurrent.*; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.test.functional.ClusteredTestBase; @@ -79,8 +79,7 @@ protected void releaseResources() throws IOException { Thread.sleep(10); waited += 10; } - assertEquals("Queue " + queue + " should have been purged after 10 seconds", - MESSAGES_PER_BATCH, purged); + assertEquals(MESSAGES_PER_BATCH, purged, "Queue " + queue + " should have been purged after 10 seconds"); } } return null; diff --git a/src/test/java/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java b/src/test/java/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java index 7bae91467b..6671be803c 100644 --- a/src/test/java/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java +++ b/src/test/java/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java @@ -17,12 +17,12 @@ package com.rabbitmq.client.test.server; import static com.rabbitmq.client.test.TestUtils.safeDelete; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.fail; import java.io.IOException; import java.util.concurrent.TimeoutException; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; @@ -69,7 +69,7 @@ private void restartPrimaryAbruptly() throws IOException, TimeoutException { connection = null; channel = null; bareRestart(); - setUp(); + setUp(this.testInfo); } /* diff --git a/src/test/java/com/rabbitmq/client/test/server/Firehose.java b/src/test/java/com/rabbitmq/client/test/server/Firehose.java index 28064a1383..63389b5384 100644 --- a/src/test/java/com/rabbitmq/client/test/server/Firehose.java +++ b/src/test/java/com/rabbitmq/client/test/server/Firehose.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,15 +15,15 @@ package com.rabbitmq.client.test.server; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import java.io.IOException; import java.util.List; import java.util.Map; import java.util.concurrent.TimeoutException; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.GetResponse; import com.rabbitmq.client.test.BrokerTestCase; diff --git a/src/test/java/com/rabbitmq/client/test/server/HATests.java b/src/test/java/com/rabbitmq/client/test/server/HATests.java deleted file mode 100644 index d4078c4ac2..0000000000 --- a/src/test/java/com/rabbitmq/client/test/server/HATests.java +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - -package com.rabbitmq.client.test.server; - -import com.rabbitmq.client.test.AbstractRMQTestSuite; -import com.rabbitmq.client.test.RequiredPropertiesSuite; -import com.rabbitmq.client.test.functional.FunctionalTests; -import com.rabbitmq.tools.Host; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Suite; - -@RunWith(RequiredPropertiesSuite.class) -@Suite.SuiteClasses({ - HATests.SetUp.class, - FunctionalTests.class, - ServerTests.class, - HATests.TearDown.class -}) -public class HATests { - - // initialize system properties - static{ - new AbstractRMQTestSuite(){}; - } - - // this is horrific - public static boolean HA_TESTS_RUNNING = false; - - // This is of course an abuse of the TestCase concept - but I don't want to - // run this command on every test case. And there's no hook for "before / - // after this test suite". - public static class SetUp { - - @Test public void setUp() throws Exception { - Host.rabbitmqctl("set_policy HA '.*' '{\"ha-mode\":\"all\"}'"); - HA_TESTS_RUNNING = true; - } - - @Test public void testNothing() {} - } - - public static class TearDown { - - @Test public void tearDown() throws Exception { - Host.rabbitmqctl("clear_policy HA"); - HA_TESTS_RUNNING = false; - } - - @Test public void testNothing() {} - } -} diff --git a/src/test/java/com/rabbitmq/client/test/server/HaTestSuite.java b/src/test/java/com/rabbitmq/client/test/server/HaTestSuite.java new file mode 100644 index 0000000000..12f88c6612 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/server/HaTestSuite.java @@ -0,0 +1,30 @@ +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.test.server; + +import com.rabbitmq.client.test.functional.FunctionalTestSuite; +import org.junit.platform.suite.api.SelectClasses; +import org.junit.platform.suite.api.Suite; + +@Suite +@SelectClasses({ + FunctionalTestSuite.class, + ServerTestSuite.class, + LastHaTestSuite.class, +}) +public class HaTestSuite { + +} diff --git a/src/test/java/com/rabbitmq/client/test/server/LastHaTestSuite.java b/src/test/java/com/rabbitmq/client/test/server/LastHaTestSuite.java new file mode 100644 index 0000000000..12aa495ae0 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/server/LastHaTestSuite.java @@ -0,0 +1,37 @@ +// Copyright (c) 2023 VMware, Inc. or its affiliates. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.test.server; + +import com.rabbitmq.client.test.server.LastHaTestSuite.DummyTest; +import org.junit.jupiter.api.Test; +import org.junit.platform.suite.api.SelectClasses; +import org.junit.platform.suite.api.Suite; + +/** + * Marker test suite to signal the end of the HA test suite. + */ +@Suite +@SelectClasses(DummyTest.class) +public class LastHaTestSuite { + + static class DummyTest { + @Test + void noOp() { + + } + } + +} diff --git a/src/test/java/com/rabbitmq/client/test/server/LoopbackUsers.java b/src/test/java/com/rabbitmq/client/test/server/LoopbackUsers.java index a1e26b3d1b..e758b65c9e 100644 --- a/src/test/java/com/rabbitmq/client/test/server/LoopbackUsers.java +++ b/src/test/java/com/rabbitmq/client/test/server/LoopbackUsers.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,7 +15,7 @@ package com.rabbitmq.client.test.server; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.fail; import java.io.IOException; import java.net.Inet4Address; @@ -26,9 +26,9 @@ import java.util.concurrent.TimeoutException; import com.rabbitmq.client.test.TestUtils; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.AuthenticationFailureException; import com.rabbitmq.client.ConnectionFactory; @@ -36,12 +36,12 @@ public class LoopbackUsers { - @Before public void setUp() throws IOException { + @BeforeEach public void setUp() throws IOException { Host.rabbitmqctl("add_user test test"); Host.rabbitmqctl("set_permissions test '.*' '.*' '.*'"); } - @After public void tearDown() throws IOException { + @AfterEach public void tearDown() throws IOException { Host.rabbitmqctl("delete_user test"); } diff --git a/src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java b/src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java index 690a77ddcd..d6be4534de 100644 --- a/src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java +++ b/src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,18 +15,21 @@ package com.rabbitmq.client.test.server; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; import java.io.IOException; import java.util.concurrent.TimeoutException; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.QueueingConsumer; import com.rabbitmq.client.test.BrokerTestCase; +import org.junit.jupiter.api.TestInfo; public class MemoryAlarms extends BrokerTestCase { @@ -35,18 +38,20 @@ public class MemoryAlarms extends BrokerTestCase { private Connection connection2; private Channel channel2; + @BeforeEach @Override - public void setUp() throws IOException, TimeoutException { + public void setUp(TestInfo info) throws IOException, TimeoutException { connectionFactory.setRequestedHeartbeat(1); - super.setUp(); + super.setUp(info); if (connection2 == null) { connection2 = connectionFactory.newConnection(); } channel2 = connection2.createChannel(); } + @AfterEach @Override - public void tearDown() throws IOException, TimeoutException { + public void tearDown(TestInfo info) throws IOException, TimeoutException { clearAllResourceAlarms(); if (channel2 != null) { channel2.abort(); @@ -56,7 +61,7 @@ public void tearDown() throws IOException, TimeoutException { connection2.abort(); connection2 = null; } - super.tearDown(); + super.tearDown(info); connectionFactory.setRequestedHeartbeat(0); } diff --git a/src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java b/src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java index f59e4ced96..c17ef018c9 100644 --- a/src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -17,12 +17,12 @@ import java.io.IOException; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.MessageProperties; import com.rabbitmq.client.test.ConfirmBase; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class MessageRecovery extends ConfirmBase { @@ -56,7 +56,7 @@ public class MessageRecovery extends ConfirmBase // with slave(s). // NB: this wont work when running against a single node broker // and running the test individually outside of the HA suite - boolean expectDelivered = HATests.HA_TESTS_RUNNING; + boolean expectDelivered = ha(); try { channel.queueDeclarePassive(Q2); channel.queueDelete(Q2); diff --git a/src/test/java/com/rabbitmq/client/test/server/Permissions.java b/src/test/java/com/rabbitmq/client/test/server/Permissions.java index c67d0cc0c6..2204f9c9ce 100644 --- a/src/test/java/com/rabbitmq/client/test/server/Permissions.java +++ b/src/test/java/com/rabbitmq/client/test/server/Permissions.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -22,14 +22,17 @@ import com.rabbitmq.client.test.BrokerTestCase; import com.rabbitmq.client.test.TestUtils; import com.rabbitmq.tools.Host; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeoutException; +import org.junit.jupiter.api.TestInfo; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; public class Permissions extends BrokerTestCase { @@ -45,16 +48,20 @@ public Permissions() connectionFactory = factory; } - public void setUp() + @BeforeEach + @Override + public void setUp(TestInfo info) throws IOException, TimeoutException { deleteRestrictedAccount(); addRestrictedAccount(); - super.setUp(); + super.setUp(info); } - public void tearDown() + @AfterEach + @Override + public void tearDown(TestInfo info) throws IOException, TimeoutException { - super.tearDown(); + super.tearDown(info); deleteRestrictedAccount(); } @@ -124,8 +131,7 @@ protected void withNames(WithName action) } catch (IOException e) { assertTrue(e instanceof AuthenticationFailureException); String msg = e.getMessage(); - assertTrue("Exception message should contain 'auth'", - msg.toLowerCase().contains("auth")); + assertTrue(msg.toLowerCase().contains("auth"), "Exception message should contain 'auth'"); } } @@ -366,13 +372,13 @@ protected void runTest(boolean exp, String name, WithName test) String msg = "'" + name + "' -> " + exp; try { test.with(name); - assertTrue(msg, exp); + assertTrue(exp, msg); } catch (IOException e) { - assertFalse(msg, exp); + assertFalse(exp, msg); checkShutdownSignal(AMQP.ACCESS_REFUSED, e); openChannel(); } catch (AlreadyClosedException e) { - assertFalse(msg, exp); + assertFalse(exp, msg); checkShutdownSignal(AMQP.ACCESS_REFUSED, e); openChannel(); } diff --git a/src/test/java/com/rabbitmq/client/test/server/PersistenceGuarantees.java b/src/test/java/com/rabbitmq/client/test/server/PersistenceGuarantees.java index 69bc8093b4..e0547ca786 100644 --- a/src/test/java/com/rabbitmq/client/test/server/PersistenceGuarantees.java +++ b/src/test/java/com/rabbitmq/client/test/server/PersistenceGuarantees.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,12 +15,12 @@ package com.rabbitmq.client.test.server; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import java.io.IOException; import com.rabbitmq.client.impl.nio.NioParams; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.MessageProperties; import com.rabbitmq.client.test.BrokerTestCase; diff --git a/src/test/java/com/rabbitmq/client/test/server/PriorityQueues.java b/src/test/java/com/rabbitmq/client/test/server/PriorityQueues.java index 76c34dbbeb..1fba1684d7 100644 --- a/src/test/java/com/rabbitmq/client/test/server/PriorityQueues.java +++ b/src/test/java/com/rabbitmq/client/test/server/PriorityQueues.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,8 +15,8 @@ package com.rabbitmq.client.test.server; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; import java.io.IOException; import java.util.ArrayList; @@ -27,7 +27,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.DefaultConsumer; diff --git a/src/test/java/com/rabbitmq/client/test/server/ServerTests.java b/src/test/java/com/rabbitmq/client/test/server/ServerTestSuite.java similarity index 69% rename from src/test/java/com/rabbitmq/client/test/server/ServerTests.java rename to src/test/java/com/rabbitmq/client/test/server/ServerTestSuite.java index a532586e40..c850a31faf 100644 --- a/src/test/java/com/rabbitmq/client/test/server/ServerTests.java +++ b/src/test/java/com/rabbitmq/client/test/server/ServerTestSuite.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -16,14 +16,12 @@ package com.rabbitmq.client.test.server; -import com.rabbitmq.client.test.AbstractRMQTestSuite; -import com.rabbitmq.client.test.RequiredPropertiesSuite; -import org.junit.runner.RunWith; -import org.junit.runners.Suite; +import org.junit.platform.suite.api.SelectClasses; +import org.junit.platform.suite.api.Suite; -@RunWith(RequiredPropertiesSuite.class) -@Suite.SuiteClasses({ - Permissions.class, +@Suite +@SelectClasses({ + Permissions.class, DurableBindingLifecycle.class, DeadLetterExchangeDurable.class, EffectVisibilityCrossNodeTest.class, @@ -38,15 +36,10 @@ BlockedConnection.class, ChannelLimitNegotiation.class, LoopbackUsers.class, - XDeathHeaderGrowth.class, - PriorityQueues.class, - TopicPermissions.class + XDeathHeaderGrowth.class, + PriorityQueues.class, + TopicPermissions.class }) -public class ServerTests { - - // initialize system properties - static{ - new AbstractRMQTestSuite(){}; - } +public class ServerTestSuite { } diff --git a/src/test/java/com/rabbitmq/client/test/server/Shutdown.java b/src/test/java/com/rabbitmq/client/test/server/Shutdown.java index 8d7194bd38..9e861bdc9e 100644 --- a/src/test/java/com/rabbitmq/client/test/server/Shutdown.java +++ b/src/test/java/com/rabbitmq/client/test/server/Shutdown.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,7 +15,7 @@ package com.rabbitmq.client.test.server; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.test.BrokerTestCase; diff --git a/src/test/java/com/rabbitmq/client/test/server/TopicPermissions.java b/src/test/java/com/rabbitmq/client/test/server/TopicPermissions.java index 323b9cba65..d48f6ea952 100644 --- a/src/test/java/com/rabbitmq/client/test/server/TopicPermissions.java +++ b/src/test/java/com/rabbitmq/client/test/server/TopicPermissions.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -20,7 +20,7 @@ import com.rabbitmq.client.BuiltinExchangeType; import com.rabbitmq.client.test.BrokerTestCase; import com.rabbitmq.tools.Host; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.util.concurrent.Callable; @@ -28,7 +28,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.fail; public class TopicPermissions extends BrokerTestCase { diff --git a/src/test/java/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java b/src/test/java/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java index fb65d954b3..0a0537330d 100644 --- a/src/test/java/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java +++ b/src/test/java/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,8 +15,8 @@ package com.rabbitmq.client.test.server; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; import java.util.ArrayList; @@ -30,7 +30,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; diff --git a/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java index f5af43b4d6..748bb9f883 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2022 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,27 +15,24 @@ package com.rabbitmq.client.test.ssl; -import com.rabbitmq.client.test.TestUtils; -import org.junit.ClassRule; -import org.junit.Test; +import org.junit.jupiter.api.Test; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLHandshakeException; import java.io.IOException; import java.util.concurrent.TimeoutException; -import org.junit.rules.TestRule; +import org.junit.jupiter.api.condition.EnabledForJreRange; +import org.junit.jupiter.api.condition.JRE; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.fail; /** * Test for bug 19356 - SSL Support in rabbitmq * */ +@EnabledForJreRange(min = JRE.JAVA_11) public class BadVerifiedConnection extends UnverifiedConnection { - @ClassRule - public static TestRule atLeastJava11TestRule = TestUtils.atLeastJava11(); - public void openConnection() throws IOException, TimeoutException { try { diff --git a/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java b/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java index dde98277d4..1a03a02420 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -16,28 +16,27 @@ package com.rabbitmq.client.test.ssl; import com.rabbitmq.client.ConnectionFactory; -import junit.framework.TestCase; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; public class ConnectionFactoryDefaultTlsVersion { @Test public void defaultTlsVersionJdk16ShouldTakeFallback() { String [] supportedProtocols = {"SSLv2Hello", "SSLv3", "TLSv1"}; String tlsProtocol = ConnectionFactory.computeDefaultTlsProtocol(supportedProtocols); - Assert.assertEquals("TLSv1",tlsProtocol); + Assertions.assertEquals("TLSv1",tlsProtocol); } @Test public void defaultTlsVersionJdk17ShouldTakePrefered() { String [] supportedProtocols = {"SSLv2Hello", "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2"}; String tlsProtocol = ConnectionFactory.computeDefaultTlsProtocol(supportedProtocols); - Assert.assertEquals("TLSv1.2",tlsProtocol); + Assertions.assertEquals("TLSv1.2",tlsProtocol); } @Test public void defaultTlsVersionJdk18ShouldTakePrefered() { String [] supportedProtocols = {"SSLv2Hello", "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2"}; String tlsProtocol = ConnectionFactory.computeDefaultTlsProtocol(supportedProtocols); - Assert.assertEquals("TLSv1.2",tlsProtocol); + Assertions.assertEquals("TLSv1.2",tlsProtocol); } } diff --git a/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java index 46ad6c5a2a..f8febe4614 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2022 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -19,32 +19,25 @@ import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.test.TestUtils; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.rules.TestRule; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.condition.EnabledForJreRange; +import org.junit.jupiter.api.condition.JRE; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLHandshakeException; import java.util.function.Consumer; import static java.util.Collections.singletonList; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertTrue; -@RunWith(Parameterized.class) +@EnabledForJreRange(min = JRE.JAVA_11) public class HostnameVerification { - @ClassRule - public static TestRule atLeastJava11TestRule = TestUtils.atLeastJava11(); - static SSLContext sslContext; - @Parameterized.Parameter - public Consumer customizer; - @Parameterized.Parameters public static Object[] data() { return new Object[] { blockingIo(enableHostnameVerification()), @@ -70,23 +63,26 @@ private static Consumer enableHostnameVerification() { return connectionFactory -> connectionFactory.enableHostnameVerification(); } - @BeforeClass + @BeforeAll public static void initCrypto() throws Exception { sslContext = TlsTestUtils.verifiedSslContext(); } - @Test(expected = SSLHandshakeException.class) - public void hostnameVerificationFailsBecauseCertificateNotIssuedForLoopbackInterface() throws Exception { + @ParameterizedTest + @MethodSource("data") + public void hostnameVerificationFailsBecauseCertificateNotIssuedForLoopbackInterface(Consumer customizer) throws Exception { ConnectionFactory connectionFactory = TestUtils.connectionFactory(); connectionFactory.useSslProtocol(sslContext); customizer.accept(connectionFactory); - connectionFactory.newConnection( - () -> singletonList(new Address("127.0.0.1", ConnectionFactory.DEFAULT_AMQP_OVER_SSL_PORT))); - fail("The server certificate isn't issued for 127.0.0.1, the TLS handshake should have failed"); + Assertions.assertThatThrownBy(() -> connectionFactory.newConnection( + () -> singletonList(new Address("127.0.0.1", ConnectionFactory.DEFAULT_AMQP_OVER_SSL_PORT)))) + .isInstanceOf(SSLHandshakeException.class) + .as("The server certificate isn't issued for 127.0.0.1, the TLS handshake should have failed"); } - @Test - public void hostnameVerificationSucceeds() throws Exception { + @ParameterizedTest + @MethodSource("data") + public void hostnameVerificationSucceeds(Consumer customizer) throws Exception { ConnectionFactory connectionFactory = TestUtils.connectionFactory(); connectionFactory.useSslProtocol(sslContext); customizer.accept(connectionFactory); diff --git a/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java index 522aa9b49b..768795fe65 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2022 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -17,8 +17,8 @@ import static com.rabbitmq.client.test.TestUtils.basicGetBasicConsume; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; @@ -42,7 +42,7 @@ import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; import javax.net.ssl.TrustManager; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.netcrusher.core.reactor.NioReactor; import org.netcrusher.tcp.TcpCrusher; import org.netcrusher.tcp.TcpCrusherBuilder; @@ -90,7 +90,7 @@ public void connectionGetConsume() throws Exception { CountDownLatch latch = new CountDownLatch(1); basicGetBasicConsume(connection, QUEUE, latch, 100 * 1000); boolean messagesReceived = latch.await(5, TimeUnit.SECONDS); - assertTrue("Message has not been received", messagesReceived); + assertTrue(messagesReceived, "Message has not been received"); } @Test @@ -112,7 +112,7 @@ public void connectionGetConsumeProtocols() throws Exception { CountDownLatch latch = new CountDownLatch(1); basicGetBasicConsume(c, QUEUE, latch, 100); boolean messagesReceived = latch.await(5, TimeUnit.SECONDS); - assertTrue("Message has not been received", messagesReceived); + assertTrue(messagesReceived, "Message has not been received"); assertThat(engine.get()).isNotNull(); assertThat(engine.get().getEnabledProtocols()).contains(protocol); } @@ -132,7 +132,7 @@ public void connectionGetConsumeProtocols() throws Exception { Connection connection = null; try { connection = connectionFactory.newConnection(); - assertTrue("The SSL engine configurator should have called", sslEngineHasBeenCalled.get()); + assertTrue(sslEngineHasBeenCalled.get(), "The SSL engine configurator should have called"); } finally { if (connection != null) { connection.close(); @@ -212,7 +212,7 @@ public void connectionShouldEnforceConnectionTimeout() throws Exception { private void sendAndVerifyMessage(int size) throws Exception { CountDownLatch latch = new CountDownLatch(1); boolean messageReceived = basicGetBasicConsume(connection, QUEUE, latch, size); - assertTrue("Message has not been received", messageReceived); + assertTrue(messageReceived, "Message has not been received"); } } diff --git a/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java b/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java deleted file mode 100644 index 758d87118a..0000000000 --- a/src/test/java/com/rabbitmq/client/test/ssl/SSLTests.java +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (c) 2007-2022 VMware, Inc. or its affiliates. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - - -package com.rabbitmq.client.test.ssl; - -import com.rabbitmq.client.test.AbstractRMQTestSuite; -import com.rabbitmq.client.test.SslContextFactoryTest; -import org.junit.runner.RunWith; -import org.junit.runner.Runner; -import org.junit.runner.notification.RunNotifier; -import org.junit.runners.Suite; -import org.junit.runners.model.InitializationError; -import org.junit.runners.model.RunnerBuilder; - -import java.util.ArrayList; -import java.util.List; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -@RunWith(SSLTests.SslSuite.class) -@Suite.SuiteClasses({ - UnverifiedConnection.class, - VerifiedConnection.class, - BadVerifiedConnection.class, - ConnectionFactoryDefaultTlsVersion.class, - NioTlsUnverifiedConnection.class, - HostnameVerification.class, - TlsConnectionLogging.class, - SslContextFactoryTest.class -}) -public class SSLTests { - - private static final Logger LOGGER = LoggerFactory.getLogger(SSLTests.class); - - // initialize system properties - static{ - new AbstractRMQTestSuite(){}; - } - - public static class SslSuite extends Suite { - - public SslSuite(Class klass, RunnerBuilder builder) throws InitializationError { - super(klass, builder); - } - - public SslSuite(RunnerBuilder builder, Class[] classes) throws InitializationError { - super(builder, classes); - } - - protected SslSuite(Class klass, Class[] suiteClasses) throws InitializationError { - super(klass, suiteClasses); - } - - protected SslSuite(RunnerBuilder builder, Class klass, Class[] suiteClasses) throws InitializationError { - super(builder, klass, suiteClasses); - } - - protected SslSuite(Class klass, List runners) throws InitializationError { - super(klass, runners); - } - - @Override - protected List getChildren() { - if(!AbstractRMQTestSuite.requiredProperties() && !AbstractRMQTestSuite.isSSLAvailable()) { - return new ArrayList<>(); - } else { - return super.getChildren(); - } - } - - @Override - protected void runChild(Runner runner, RunNotifier notifier) { - LOGGER.info("Running test {}", runner.getDescription().getDisplayName()); - super.runChild(runner, notifier); - } - } - -} diff --git a/src/test/java/com/rabbitmq/client/test/ssl/SslTestSuite.java b/src/test/java/com/rabbitmq/client/test/ssl/SslTestSuite.java new file mode 100644 index 0000000000..05160db0f9 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/ssl/SslTestSuite.java @@ -0,0 +1,37 @@ +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + + +package com.rabbitmq.client.test.ssl; + +import com.rabbitmq.client.test.SslContextFactoryTest; + +import org.junit.platform.suite.api.SelectClasses; +import org.junit.platform.suite.api.Suite; + +@Suite +@SelectClasses({ + UnverifiedConnection.class, + VerifiedConnection.class, + BadVerifiedConnection.class, + ConnectionFactoryDefaultTlsVersion.class, + NioTlsUnverifiedConnection.class, + HostnameVerification.class, + TlsConnectionLogging.class, + SslContextFactoryTest.class +}) +public class SslTestSuite { + +} diff --git a/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java b/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java index 4693525ea3..1558eeda71 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2021 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2019-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -21,9 +21,8 @@ import com.rabbitmq.client.impl.nio.NioParams; import com.rabbitmq.client.test.TestUtils; import org.assertj.core.api.Assertions; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import javax.net.ssl.*; import java.security.cert.X509Certificate; @@ -31,16 +30,11 @@ import java.util.function.Function; import java.util.function.Supplier; -import static org.junit.Assert.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNotNull; -@RunWith(Parameterized.class) public class TlsConnectionLogging { - @Parameterized.Parameter - public Function> configurer; - - @Parameterized.Parameters - public static Object[] data() { + public static Object[] certificateInfoAreProperlyExtracted() { return new Object[]{blockingIo(), nio()}; } @@ -63,8 +57,9 @@ public static Function> nio() { }; } - @Test - public void certificateInfoAreProperlyExtracted() throws Exception { + @ParameterizedTest + @MethodSource + public void certificateInfoAreProperlyExtracted(Function> configurer) throws Exception { SSLContext sslContext = TlsTestUtils.getSSLContext(); sslContext.init(null, new TrustManager[]{new AlwaysTrustTrustManager()}, null); ConnectionFactory connectionFactory = TestUtils.connectionFactory(); diff --git a/src/test/java/com/rabbitmq/client/test/ssl/TlsTestUtils.java b/src/test/java/com/rabbitmq/client/test/ssl/TlsTestUtils.java index 6e633ce664..51702c4a6e 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/TlsTestUtils.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/TlsTestUtils.java @@ -15,7 +15,7 @@ package com.rabbitmq.client.test.ssl; -import static org.junit.Assert.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNotNull; import java.io.FileInputStream; import java.security.KeyStore; diff --git a/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java index 39e1e90ba5..5a0af90463 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2021 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -17,13 +17,13 @@ import com.rabbitmq.client.GetResponse; import com.rabbitmq.client.test.BrokerTestCase; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.concurrent.TimeoutException; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; /** * Test for bug 19356 - SSL Support in rabbitmq diff --git a/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java index 1e66c9d9c6..32ac3a2ca9 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2022 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -16,8 +16,8 @@ package com.rabbitmq.client.test.ssl; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; import com.rabbitmq.client.Connection; import com.rabbitmq.client.impl.nio.NioParams; @@ -36,20 +36,18 @@ import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.test.TestUtils; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.rules.TestRule; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledForJreRange; +import org.junit.jupiter.api.condition.JRE; import org.slf4j.LoggerFactory; /** * Test for bug 19356 - SSL Support in rabbitmq * */ +@EnabledForJreRange(min = JRE.JAVA_11) public class VerifiedConnection extends UnverifiedConnection { - @ClassRule - public static TestRule atLeastJava11TestRule = TestUtils.atLeastJava11(); - public void openConnection() throws IOException, TimeoutException { try { @@ -102,7 +100,7 @@ public void connectionGetConsumeProtocols() throws Exception { CountDownLatch latch = new CountDownLatch(1); TestUtils.basicGetBasicConsume(c, VerifiedConnection.class.getName(), latch, 100); boolean messagesReceived = latch.await(5, TimeUnit.SECONDS); - assertTrue("Message has not been received", messagesReceived); + assertTrue(messagesReceived, "Message has not been received"); assertThat(protocolsSupplier.get()).isNotNull(); assertThat(protocolsSupplier.get().get()).contains(protocol); } diff --git a/src/test/java/com/rabbitmq/tools/Host.java b/src/test/java/com/rabbitmq/tools/Host.java index ee3b6a59f3..8e950cb27e 100644 --- a/src/test/java/com/rabbitmq/tools/Host.java +++ b/src/test/java/com/rabbitmq/tools/Host.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2022 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/utility/IntAllocatorTests.java b/src/test/java/com/rabbitmq/utility/IntAllocatorTests.java index d29e134442..5e468a60e3 100644 --- a/src/test/java/com/rabbitmq/utility/IntAllocatorTests.java +++ b/src/test/java/com/rabbitmq/utility/IntAllocatorTests.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,14 +15,14 @@ package com.rabbitmq.utility; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.util.HashSet; import java.util.Iterator; import java.util.Random; import java.util.Set; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; public class IntAllocatorTests { @@ -41,38 +41,38 @@ public class IntAllocatorTests { iAll.free(trial); set.remove(trial); } else { - assertTrue("Did not reserve free integer " + trial, iAll.reserve(trial)); + assertTrue(iAll.reserve(trial), "Did not reserve free integer " + trial); set.add(trial); } } for (int trial : set) { - assertFalse("Integer " + trial + " not allocated!", iAll.reserve(trial)); + assertFalse(iAll.reserve(trial), "Integer " + trial + " not allocated!"); } } - @Test public void allocateAndFree() throws Exception { + @Test public void allocateAndFree() { Set set = new HashSet(); for (int i=0; i < TEST_ITERATIONS; ++i) { if (getBool(rand)) { int trial = iAll.allocate(); - assertFalse("Already allocated " + trial, set.contains(trial)); + assertFalse(set.contains(trial), "Already allocated " + trial); set.add(trial); } else { if (!set.isEmpty()) { int trial = extractOne(set); - assertFalse("Allocator agreed to reserve " + trial, iAll.reserve(trial)); + assertFalse(iAll.reserve(trial), "Allocator agreed to reserve " + trial); iAll.free(trial); } } } for (int trial : set) { - assertFalse("Integer " + trial + " should be allocated!", iAll.reserve(trial)); + assertFalse(iAll.reserve(trial), "Integer " + trial + " should be allocated!"); } } - @Test public void testToString() throws Exception { + @Test public void testToString() { IntAllocator ibs = new IntAllocator(LO_RANGE, HI_RANGE); assertEquals("IntAllocator{allocated = []}", ibs.toString()); ibs.allocate(); diff --git a/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension b/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension new file mode 100644 index 0000000000..5d5a5c135a --- /dev/null +++ b/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension @@ -0,0 +1 @@ +com.rabbitmq.client.AmqpClientTestExtension \ No newline at end of file diff --git a/src/test/resources/junit-platform.properties b/src/test/resources/junit-platform.properties new file mode 100644 index 0000000000..b059a65dc4 --- /dev/null +++ b/src/test/resources/junit-platform.properties @@ -0,0 +1 @@ +junit.jupiter.extensions.autodetection.enabled=true \ No newline at end of file diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml index 2ddadf938e..3e3340923e 100644 --- a/src/test/resources/logback-test.xml +++ b/src/test/resources/logback-test.xml @@ -5,10 +5,8 @@ - - - + From 41f0804052d62140065ba8466c3c05189161fbff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 6 Jan 2023 11:04:36 +0100 Subject: [PATCH 1655/2114] Fix test condition --- src/test/java/com/rabbitmq/client/test/TestUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/client/test/TestUtils.java b/src/test/java/com/rabbitmq/client/test/TestUtils.java index 8897bf23a9..cbb2885f22 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtils.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtils.java @@ -478,7 +478,7 @@ static class DisabledIfBrokerRunningOnDockerCondition implements @Override public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) { if (Host.isOnDocker()) { - return ConditionEvaluationResult.enabled("Broker running on Docker"); + return ConditionEvaluationResult.disabled("Broker running on Docker"); } else { return ConditionEvaluationResult.enabled("Broker not running on Docker"); } From 9c2c5836d9bdf60950609d328f821aafdc362b87 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Jan 2023 01:18:27 +0000 Subject: [PATCH 1656/2114] Bump opentelemetry.version from 1.21.0 to 1.22.0 Bumps `opentelemetry.version` from 1.21.0 to 1.22.0. Updates `opentelemetry-api` from 1.21.0 to 1.22.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-java/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-java/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-java/compare/v1.21.0...v1.22.0) Updates `opentelemetry-sdk-testing` from 1.21.0 to 1.22.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-java/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-java/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-java/compare/v1.21.0...v1.22.0) --- updated-dependencies: - dependency-name: io.opentelemetry:opentelemetry-api dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: io.opentelemetry:opentelemetry-sdk-testing dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5cf291a173..d13dee8dc8 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,7 @@ 1.7.36 4.2.15 1.10.2 - 1.21.0 + 1.22.0 2.14.1 1.2.11 5.9.1 From 9494d039708f0a2b2d6857128765c3bdbc89c206 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Jan 2023 01:18:32 +0000 Subject: [PATCH 1657/2114] Bump assertj-core from 3.24.0 to 3.24.1 Bumps assertj-core from 3.24.0 to 3.24.1. --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5cf291a173..73282f99f2 100644 --- a/pom.xml +++ b/pom.xml @@ -62,7 +62,7 @@ 1.2.11 5.9.1 4.11.0 - 3.24.0 + 3.24.1 9.4.50.v20221201 1.70 0.10 From 18e2c0d70a3b7d0cf61cc122b3d5d3123625c122 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Jan 2023 00:28:33 +0000 Subject: [PATCH 1658/2114] Bump junit-bom from 5.9.1 to 5.9.2 Bumps [junit-bom](https://github.com/junit-team/junit5) from 5.9.1 to 5.9.2. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.9.1...r5.9.2) --- updated-dependencies: - dependency-name: org.junit:junit-bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2c61d61fa8..c869c9c401 100644 --- a/pom.xml +++ b/pom.xml @@ -60,7 +60,7 @@ 1.22.0 2.14.1 1.2.11 - 5.9.1 + 5.9.2 4.11.0 3.24.1 9.4.50.v20221201 From c8a68b45f4e5653e3be113d4cd295008d8f5078e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Jan 2023 00:28:43 +0000 Subject: [PATCH 1659/2114] Bump micrometer-core from 1.10.2 to 1.10.3 Bumps [micrometer-core](https://github.com/micrometer-metrics/micrometer) from 1.10.2 to 1.10.3. - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.10.2...v1.10.3) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2c61d61fa8..cf9d47a5c9 100644 --- a/pom.xml +++ b/pom.xml @@ -56,7 +56,7 @@ 1.7.36 4.2.15 - 1.10.2 + 1.10.3 1.22.0 2.14.1 1.2.11 From 17ceeec0989f68cbf45be7eedda16dac34bbd444 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 Jan 2023 00:45:56 +0000 Subject: [PATCH 1660/2114] Bump maven-surefire-plugin from 3.0.0-M7 to 3.0.0-M8 Bumps [maven-surefire-plugin](https://github.com/apache/maven-surefire) from 3.0.0-M7 to 3.0.0-M8. - [Release notes](https://github.com/apache/maven-surefire/releases) - [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.0.0-M7...surefire-3.0.0-M8) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-surefire-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3f814a100e..be5d1f83fe 100644 --- a/pom.xml +++ b/pom.xml @@ -77,7 +77,7 @@ 1.6 3.3.0 3.10.1 - 3.0.0-M7 + 3.0.0-M8 3.0.0-M7 3.0.1 3.3.0 From 6c56995c4d050351f344aad8787fcf273ad5e647 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 Jan 2023 02:10:03 +0000 Subject: [PATCH 1661/2114] Bump maven-failsafe-plugin from 3.0.0-M7 to 3.0.0-M8 Bumps [maven-failsafe-plugin](https://github.com/apache/maven-surefire) from 3.0.0-M7 to 3.0.0-M8. - [Release notes](https://github.com/apache/maven-surefire/releases) - [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.0.0-M7...surefire-3.0.0-M8) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-failsafe-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index be5d1f83fe..b0bf779d53 100644 --- a/pom.xml +++ b/pom.xml @@ -78,7 +78,7 @@ 3.3.0 3.10.1 3.0.0-M8 - 3.0.0-M7 + 3.0.0-M8 3.0.1 3.3.0 5.1.8 From 18d9daa3b49c7e3bad1e07630c2269f5bb6050c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 16 Jan 2023 09:21:53 +0100 Subject: [PATCH 1662/2114] Exclude Mockito 5.0 from dependabot It requires Java 11. --- .github/dependabot.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 71544d2951..bc94ed0878 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -15,6 +15,8 @@ updates: versions: [ "[2.0,)" ] - dependency-name: "ch.qos.logback:logback-classic" versions: [ "[1.3,)" ] + - dependency-name: "org.mockito:mockito-core" + versions: [ "[5.0,)" ] - package-ecosystem: "maven" directory: "/" schedule: @@ -28,6 +30,8 @@ updates: versions: [ "[2.0,)" ] - dependency-name: "ch.qos.logback:logback-classic" versions: [ "[1.3,)" ] + - dependency-name: "org.mockito:mockito-core" + versions: [ "[5.0,)" ] - package-ecosystem: "github-actions" directory: "/" schedule: From 28d59d2cbc102ef01bf7a356c1db6d87176fd215 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 16 Jan 2023 09:52:37 +0100 Subject: [PATCH 1663/2114] Bump Mockito to 5.0.0, stick to 4.x on Java 8 --- .github/dependabot.yml | 4 ---- pom.xml | 11 ++++++++++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index bc94ed0878..71544d2951 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -15,8 +15,6 @@ updates: versions: [ "[2.0,)" ] - dependency-name: "ch.qos.logback:logback-classic" versions: [ "[1.3,)" ] - - dependency-name: "org.mockito:mockito-core" - versions: [ "[5.0,)" ] - package-ecosystem: "maven" directory: "/" schedule: @@ -30,8 +28,6 @@ updates: versions: [ "[2.0,)" ] - dependency-name: "ch.qos.logback:logback-classic" versions: [ "[1.3,)" ] - - dependency-name: "org.mockito:mockito-core" - versions: [ "[5.0,)" ] - package-ecosystem: "github-actions" directory: "/" schedule: diff --git a/pom.xml b/pom.xml index b0bf779d53..e6fda2c815 100644 --- a/pom.xml +++ b/pom.xml @@ -61,7 +61,7 @@ 2.14.1 1.2.11 5.9.2 - 4.11.0 + 5.0.0 3.24.1 9.4.50.v20221201 1.70 @@ -684,6 +684,15 @@ + + mockito-4-on-java-8 + + 1.8 + + + 4.11.0 + + From c6710f0a064215cb1c07a8790d884c5f5844f3dd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Jan 2023 00:15:29 +0000 Subject: [PATCH 1664/2114] Bump assertj-core from 3.24.1 to 3.24.2 Bumps assertj-core from 3.24.1 to 3.24.2. --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e6fda2c815..56545d1259 100644 --- a/pom.xml +++ b/pom.xml @@ -62,7 +62,7 @@ 1.2.11 5.9.2 5.0.0 - 3.24.1 + 3.24.2 9.4.50.v20221201 1.70 0.10 From a1860788d38a6caf30702531ddb596c23df83cb3 Mon Sep 17 00:00:00 2001 From: Nikita Nefedov Date: Mon, 23 Jan 2023 15:18:27 +0100 Subject: [PATCH 1665/2114] Report publish failures for the closed channel as well --- src/main/java/com/rabbitmq/client/impl/ChannelN.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java index 8dc19f4ad6..428224a4bc 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelN.java @@ -710,7 +710,7 @@ public void basicPublish(String exchange, String routingKey, .build(), props, body); try { transmit(command); - } catch (IOException e) { + } catch (IOException | AlreadyClosedException e) { metricsCollector.basicPublishFailure(this, e); throw e; } @@ -1493,7 +1493,7 @@ public Consumer transformReply(AMQCommand replyCommand) { rpc(m, k); - + try { if(_rpcTimeout == NO_RPC_TIMEOUT) { k.getReply(); // discard result From 84ddee03c25392bd449bc9d34135d026761f26e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 30 Jan 2023 09:40:12 +0100 Subject: [PATCH 1666/2114] Execute multi-Java test suite on Wednesday and Sunday only Used to be every day. It may be too much for our GHA quota, so we reduce the frequency. It should do the job as well. --- .github/workflows/test-3.11-alpha.yml | 2 +- .github/workflows/test-native-image.yml | 2 +- .github/workflows/test-supported-java-versions-5.x.yml | 2 +- .github/workflows/test-supported-java-versions-main.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test-3.11-alpha.yml b/.github/workflows/test-3.11-alpha.yml index 3462b88977..9cac56c0a6 100644 --- a/.github/workflows/test-3.11-alpha.yml +++ b/.github/workflows/test-3.11-alpha.yml @@ -2,7 +2,7 @@ name: Test against RabbitMQ 3.11 alpha on: schedule: - - cron: '0 4 * * *' + - cron: '0 4 ? * SUN,WED' pull_request: branches: - main diff --git a/.github/workflows/test-native-image.yml b/.github/workflows/test-native-image.yml index 05737ba90b..d1390252b3 100644 --- a/.github/workflows/test-native-image.yml +++ b/.github/workflows/test-native-image.yml @@ -2,7 +2,7 @@ name: Test GraalVM native image on: schedule: - - cron: '0 4 * * *' + - cron: '0 4 ? * SUN,WED' workflow_dispatch: env: diff --git a/.github/workflows/test-supported-java-versions-5.x.yml b/.github/workflows/test-supported-java-versions-5.x.yml index 1885402a4b..b9b906254d 100644 --- a/.github/workflows/test-supported-java-versions-5.x.yml +++ b/.github/workflows/test-supported-java-versions-5.x.yml @@ -2,7 +2,7 @@ name: Test against supported Java versions (5.x) on: schedule: - - cron: '0 4 * * *' + - cron: '0 4 ? * SUN,WED' workflow_dispatch: env: diff --git a/.github/workflows/test-supported-java-versions-main.yml b/.github/workflows/test-supported-java-versions-main.yml index d1ead48e7c..21667df7e1 100644 --- a/.github/workflows/test-supported-java-versions-main.yml +++ b/.github/workflows/test-supported-java-versions-main.yml @@ -2,7 +2,7 @@ name: Test against supported Java versions (main) on: schedule: - - cron: '0 4 * * *' + - cron: '0 4 ? * SUN,WED' workflow_dispatch: env: From 9e59da93ff24ef04caa9bcc6478b4400b278509a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 31 Jan 2023 00:09:28 +0000 Subject: [PATCH 1667/2114] Bump mockito-core from 5.0.0 to 5.1.1 Bumps [mockito-core](https://github.com/mockito/mockito) from 5.0.0 to 5.1.1. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.0.0...v5.1.1) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 56545d1259..da02933d41 100644 --- a/pom.xml +++ b/pom.xml @@ -61,7 +61,7 @@ 2.14.1 1.2.11 5.9.2 - 5.0.0 + 5.1.1 3.24.2 9.4.50.v20221201 1.70 From 20e641e1b53dec785b4da9b5f65fb6423b5d16aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 31 Jan 2023 14:41:43 +0100 Subject: [PATCH 1668/2114] Fix NPE in metrics collector if channel is null Fixes #944 --- .../com/rabbitmq/client/impl/AMQConnection.java | 10 +++++++--- .../client/impl/AbstractMetricsCollector.java | 14 ++++++++------ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index 5d5fe414eb..79ab385c15 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -596,7 +596,9 @@ public Channel createChannel(int channelNumber) throws IOException { ChannelManager cm = _channelManager; if (cm == null) return null; Channel channel = cm.createChannel(this, channelNumber); - metricsCollector.newChannel(channel); + if (channel != null) { + metricsCollector.newChannel(channel); + } return channel; } @@ -607,7 +609,9 @@ public Channel createChannel() throws IOException { ChannelManager cm = _channelManager; if (cm == null) return null; Channel channel = cm.createChannel(this); - metricsCollector.newChannel(channel); + if (channel != null) { + metricsCollector.newChannel(channel); + } return channel; } diff --git a/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java index ce41a2ae80..0d8f8e2939 100644 --- a/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java @@ -81,12 +81,14 @@ public void closeConnection(Connection connection) { @Override public void newChannel(final Channel channel) { - try { - incrementChannelCount(channel); - channel.addShutdownListener(cause -> closeChannel(channel)); - connectionState(channel.getConnection()).channelState.put(channel.getChannelNumber(), new ChannelState(channel)); - } catch(Exception e) { - LOGGER.info("Error while computing metrics in newChannel: " + e.getMessage()); + if (channel != null) { + try { + incrementChannelCount(channel); + channel.addShutdownListener(cause -> closeChannel(channel)); + connectionState(channel.getConnection()).channelState.put(channel.getChannelNumber(), new ChannelState(channel)); + } catch(Exception e) { + LOGGER.info("Error while computing metrics in newChannel: " + e.getMessage()); + } } } From cc44e222ced8b76e14240dc9d5a92e702e5fce89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 1 Feb 2023 09:44:26 +0100 Subject: [PATCH 1669/2114] Execute multi-Java test suite on Thursday morning Better balanced in the week than on Wednesday morning. --- .github/workflows/test-3.11-alpha.yml | 2 +- .github/workflows/test-native-image.yml | 2 +- .github/workflows/test-supported-java-versions-5.x.yml | 2 +- .github/workflows/test-supported-java-versions-main.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test-3.11-alpha.yml b/.github/workflows/test-3.11-alpha.yml index 9cac56c0a6..3fcd69f089 100644 --- a/.github/workflows/test-3.11-alpha.yml +++ b/.github/workflows/test-3.11-alpha.yml @@ -2,7 +2,7 @@ name: Test against RabbitMQ 3.11 alpha on: schedule: - - cron: '0 4 ? * SUN,WED' + - cron: '0 4 ? * SUN,THU' pull_request: branches: - main diff --git a/.github/workflows/test-native-image.yml b/.github/workflows/test-native-image.yml index d1390252b3..0a7fc33e9e 100644 --- a/.github/workflows/test-native-image.yml +++ b/.github/workflows/test-native-image.yml @@ -2,7 +2,7 @@ name: Test GraalVM native image on: schedule: - - cron: '0 4 ? * SUN,WED' + - cron: '0 4 ? * SUN,THU' workflow_dispatch: env: diff --git a/.github/workflows/test-supported-java-versions-5.x.yml b/.github/workflows/test-supported-java-versions-5.x.yml index b9b906254d..7b24cd3406 100644 --- a/.github/workflows/test-supported-java-versions-5.x.yml +++ b/.github/workflows/test-supported-java-versions-5.x.yml @@ -2,7 +2,7 @@ name: Test against supported Java versions (5.x) on: schedule: - - cron: '0 4 ? * SUN,WED' + - cron: '0 4 ? * SUN,THU' workflow_dispatch: env: diff --git a/.github/workflows/test-supported-java-versions-main.yml b/.github/workflows/test-supported-java-versions-main.yml index 21667df7e1..8687dbdd32 100644 --- a/.github/workflows/test-supported-java-versions-main.yml +++ b/.github/workflows/test-supported-java-versions-main.yml @@ -2,7 +2,7 @@ name: Test against supported Java versions (main) on: schedule: - - cron: '0 4 ? * SUN,WED' + - cron: '0 4 ? * SUN,THU' workflow_dispatch: env: From d693dbbbbc7d75240de994c447cf9ef201d265c4 Mon Sep 17 00:00:00 2001 From: hogimn Date: Sun, 5 Feb 2023 01:07:25 +0900 Subject: [PATCH 1670/2114] Update documents for test --- README.md | 4 ++-- RUNNING_TESTS.md | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index ba0e2bd9b2..fa7573357d 100644 --- a/README.md +++ b/README.md @@ -105,7 +105,7 @@ Launch "essential" tests (takes about 10 minutes): ``` ./mvnw verify -P '!setup-test-cluster' \ -Drabbitmqctl.bin=DOCKER:rabbitmq \ - -Dit.test=ClientTests,FunctionalTests,ServerTests + -Dit.test=ClientTestSuite,FunctionalTestSuite,ServerTestSuite ``` Launch a single test: @@ -125,7 +125,7 @@ system property must point to the `rabbitmqctl` program: ./mvnw verify -P '!setup-test-cluster' \ -Dtest-broker.A.nodename=rabbit@$(hostname) \ -Drabbitmqctl.bin=/path/to/rabbitmqctl \ - -Dit.test=ClientTests,FunctionalTests,ServerTests + -Dit.test=ClientTestSuite,FunctionalTestSuite,ServerTestSuite ``` To launch a single test: diff --git a/RUNNING_TESTS.md b/RUNNING_TESTS.md index b7241210ca..a4750ea245 100644 --- a/RUNNING_TESTS.md +++ b/RUNNING_TESTS.md @@ -37,7 +37,7 @@ To run a subset of the test suite (do not forget to start a local RabbitMQ node) ./mvnw verify -P '!setup-test-cluster' \ -Dtest-broker.A.nodename=rabbit@$(hostname) \ -Drabbitmqctl.bin=/path/to/rabbitmqctl \ - -Dit.test=ClientTests,FunctionalTests,ServerTests + -Dit.test=ClientTestSuite,FunctionalTestSuite,ServerTestSuite ``` The test suite subset does not include TLS tests, which is fine for most @@ -50,7 +50,7 @@ To run the tests against the NIO connector, add `-P use-nio` to the command line ./mvnw verify -P '!setup-test-cluster',use-nio \ -Dtest-broker.A.nodename=rabbit@$(hostname) \ -Drabbitmqctl.bin=/path/to/rabbitmqctl \ - -Dit.test=ClientTests,FunctionalTests,ServerTests + -Dit.test=ClientTestSuite,FunctionalTestSuite,ServerTestSuite ``` For details on running specific tests, see below. @@ -67,7 +67,7 @@ top-level directory of the source tree: ./mvnw verify -P '!setup-test-cluster',use-nio \ -Dtest-broker.A.nodename=rabbit@$(hostname) \ -Drabbitmqctl.bin=/path/to/rabbitmqctl \ - -Dit.test=ClientTests + -Dit.test=ClientTestSuite ``` * To run the functional tests: @@ -76,7 +76,7 @@ top-level directory of the source tree: ./mvnw verify -P '!setup-test-cluster',use-nio \ -Dtest-broker.A.nodename=rabbit@$(hostname) \ -Drabbitmqctl.bin=/path/to/rabbitmqctl \ - -Dit.test=FunctionalTests + -Dit.test=FunctionalTestSuite ``` * To run a single test: @@ -103,7 +103,7 @@ Launch the tests: ``` ./mvnw verify -P '!setup-test-cluster' \ -Drabbitmqctl.bin=DOCKER:rabbitmq \ - -Dit.test=ClientTests,FunctionalTests,ServerTests + -Dit.test=ClientTestSuite,FunctionalTestSuite,ServerTestSuite ``` Note the `rabbitmqctl.bin` system property uses the syntax From 03c1fc743a90bf355eecce68c0555371bc5a03a5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Feb 2023 02:19:22 +0000 Subject: [PATCH 1671/2114] Bump opentelemetry.version from 1.22.0 to 1.23.0 Bumps `opentelemetry.version` from 1.22.0 to 1.23.0. Updates `opentelemetry-api` from 1.22.0 to 1.23.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-java/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-java/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-java/compare/v1.22.0...v1.23.0) Updates `opentelemetry-sdk-testing` from 1.22.0 to 1.23.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-java/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-java/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-java/compare/v1.22.0...v1.23.0) --- updated-dependencies: - dependency-name: io.opentelemetry:opentelemetry-api dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: io.opentelemetry:opentelemetry-sdk-testing dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index da02933d41..68e5cec7b0 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,7 @@ 1.7.36 4.2.15 1.10.3 - 1.22.0 + 1.23.0 2.14.1 1.2.11 5.9.2 From c6b004f25566e79f9bab36391f92e750059e92f1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Feb 2023 01:05:42 +0000 Subject: [PATCH 1672/2114] Bump metrics-core from 4.2.15 to 4.2.16 Bumps [metrics-core](https://github.com/dropwizard/metrics) from 4.2.15 to 4.2.16. - [Release notes](https://github.com/dropwizard/metrics/releases) - [Commits](https://github.com/dropwizard/metrics/compare/v4.2.15...v4.2.16) --- updated-dependencies: - dependency-name: io.dropwizard.metrics:metrics-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 68e5cec7b0..c963f6d946 100644 --- a/pom.xml +++ b/pom.xml @@ -55,7 +55,7 @@ UTF-8 1.7.36 - 4.2.15 + 4.2.16 1.10.3 1.23.0 2.14.1 From 9803654efcad11413c54ed994d5c3c9d0e0fc4e0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Feb 2023 01:06:02 +0000 Subject: [PATCH 1673/2114] Bump maven-failsafe-plugin from 3.0.0-M8 to 3.0.0-M9 Bumps [maven-failsafe-plugin](https://github.com/apache/maven-surefire) from 3.0.0-M8 to 3.0.0-M9. - [Release notes](https://github.com/apache/maven-surefire/releases) - [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.0.0-M8...surefire-3.0.0-M9) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-failsafe-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 68e5cec7b0..bf1d0c7948 100644 --- a/pom.xml +++ b/pom.xml @@ -78,7 +78,7 @@ 3.3.0 3.10.1 3.0.0-M8 - 3.0.0-M8 + 3.0.0-M9 3.0.1 3.3.0 5.1.8 From 404e2d7c624fb45e1335d86aadc106dd822bd98e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Feb 2023 01:21:45 +0000 Subject: [PATCH 1674/2114] Bump maven-surefire-plugin from 3.0.0-M8 to 3.0.0-M9 Bumps [maven-surefire-plugin](https://github.com/apache/maven-surefire) from 3.0.0-M8 to 3.0.0-M9. - [Release notes](https://github.com/apache/maven-surefire/releases) - [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.0.0-M8...surefire-3.0.0-M9) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-surefire-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index dbdb26c4c8..7796975120 100644 --- a/pom.xml +++ b/pom.xml @@ -77,7 +77,7 @@ 1.6 3.3.0 3.10.1 - 3.0.0-M8 + 3.0.0-M9 3.0.0-M9 3.0.1 3.3.0 From ff46bc1ca5f84d4e870ba47c385515c269fb368b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 15 Feb 2023 01:06:55 +0000 Subject: [PATCH 1675/2114] Bump micrometer-core from 1.10.3 to 1.10.4 Bumps [micrometer-core](https://github.com/micrometer-metrics/micrometer) from 1.10.3 to 1.10.4. - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.10.3...v1.10.4) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7796975120..9fca97b284 100644 --- a/pom.xml +++ b/pom.xml @@ -56,7 +56,7 @@ 1.7.36 4.2.16 - 1.10.3 + 1.10.4 1.23.0 2.14.1 1.2.11 From 3e9b4dea708ded3e9c5260f5a8838f44ee80e957 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 16 Feb 2023 01:08:26 +0000 Subject: [PATCH 1676/2114] Bump maven-javadoc-plugin from 3.4.1 to 3.5.0 Bumps [maven-javadoc-plugin](https://github.com/apache/maven-javadoc-plugin) from 3.4.1 to 3.5.0. - [Release notes](https://github.com/apache/maven-javadoc-plugin/releases) - [Commits](https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.4.1...maven-javadoc-plugin-3.5.0) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-javadoc-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9fca97b284..823c8ed2af 100644 --- a/pom.xml +++ b/pom.xml @@ -67,7 +67,7 @@ 1.70 0.10 - 3.4.1 + 3.5.0 2.5.3 2.14.2 3.3.0 From 395cae9702207434a155d4e5ad6cef2744c96f1f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 16 Feb 2023 01:08:47 +0000 Subject: [PATCH 1677/2114] Bump opentelemetry.version from 1.23.0 to 1.23.1 Bumps `opentelemetry.version` from 1.23.0 to 1.23.1. Updates `opentelemetry-api` from 1.23.0 to 1.23.1 - [Release notes](https://github.com/open-telemetry/opentelemetry-java/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-java/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-java/compare/v1.23.0...v1.23.1) Updates `opentelemetry-sdk-testing` from 1.23.0 to 1.23.1 - [Release notes](https://github.com/open-telemetry/opentelemetry-java/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-java/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-java/compare/v1.23.0...v1.23.1) --- updated-dependencies: - dependency-name: io.opentelemetry:opentelemetry-api dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.opentelemetry:opentelemetry-sdk-testing dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9fca97b284..6c56d37bfc 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,7 @@ 1.7.36 4.2.16 1.10.4 - 1.23.0 + 1.23.1 2.14.1 1.2.11 5.9.2 From bbfcca96c02c19f3301ccdbce279f3a59fb190a7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 22 Feb 2023 00:54:15 +0000 Subject: [PATCH 1678/2114] Bump versions-maven-plugin from 2.14.2 to 2.15.0 Bumps [versions-maven-plugin](https://github.com/mojohaus/versions) from 2.14.2 to 2.15.0. - [Release notes](https://github.com/mojohaus/versions/releases) - [Changelog](https://github.com/mojohaus/versions/blob/master/ReleaseNotes.md) - [Commits](https://github.com/mojohaus/versions/compare/2.14.2...2.15.0) --- updated-dependencies: - dependency-name: org.codehaus.mojo:versions-maven-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1cca978562..264f7ff918 100644 --- a/pom.xml +++ b/pom.xml @@ -69,7 +69,7 @@ 3.5.0 2.5.3 - 2.14.2 + 2.15.0 3.3.0 3.2.1 2.1.1 From af8036d1a6e4853582152559d1910708f19f7ca3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 23 Feb 2023 09:23:20 +0100 Subject: [PATCH 1679/2114] Add test to parse OAuth2 token with GSON Instead of Jackson. The requirement is very small, and GSON is a much smaller dependency than Jackson. --- pom.xml | 7 ++++ ...edentialsGrantCredentialsProviderTest.java | 33 ++++++++++++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 264f7ff918..ce452c2eb2 100644 --- a/pom.xml +++ b/pom.xml @@ -66,6 +66,7 @@ 9.4.50.v20221201 1.70 0.10 + 2.10.1 3.5.0 2.5.3 @@ -784,6 +785,12 @@ ${opentelemetry.version} test + + com.google.code.gson + gson + ${gson.version} + test + diff --git a/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java b/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java index 33614d78bd..f717cbcf27 100644 --- a/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java +++ b/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java @@ -15,6 +15,7 @@ package com.rabbitmq.client.impl; +import com.google.gson.Gson; import com.rabbitmq.client.test.TestUtils; import org.bouncycastle.asn1.x500.X500NameBuilder; import org.bouncycastle.asn1.x500.style.BCStyle; @@ -195,7 +196,7 @@ public void handle(String target, Request baseRequest, HttpServletRequest reques } @Test - public void parseToken() { + public void parseTokenDefault() { OAuth2ClientCredentialsGrantCredentialsProvider provider = new OAuth2ClientCredentialsGrantCredentialsProvider( "http://localhost:8080/uaa/oauth/token/", "rabbit_client", "rabbit_secret", @@ -211,6 +212,36 @@ public void parseToken() { assertThat(token.getTimeBeforeExpiration()).isBetween(Duration.ofSeconds(expiresIn - 10), Duration.ofSeconds(expiresIn + 1)); } + @Test + public void parseTokenGson() { + Gson gson = new Gson(); + OAuth2ClientCredentialsGrantCredentialsProvider provider = new OAuth2ClientCredentialsGrantCredentialsProvider( + "http://localhost:8080/uaa/oauth/token/", + "rabbit_client", "rabbit_secret", + "client_credentials" + ) { + @Override + protected Token parseToken(String response) { + try { + Map map = gson.fromJson(response, Map.class); + int expiresIn = ((Number) map.get("expires_in")).intValue(); + Instant receivedAt = Instant.now(); + return new Token(map.get("access_token").toString(), expiresIn, receivedAt); + } catch (Exception e) { + throw new OAuthTokenManagementException("Error while parsing OAuth 2 token", e); + } + } + }; + + String accessToken = "18c1b1dfdda04382a8bcc14d077b71dd"; + int expiresIn = 43199; + String response = sampleJsonToken(accessToken, expiresIn); + + OAuth2ClientCredentialsGrantCredentialsProvider.Token token = provider.parseToken(response); + assertThat(token.getAccess()).isEqualTo("18c1b1dfdda04382a8bcc14d077b71dd"); + assertThat(token.getTimeBeforeExpiration()).isBetween(Duration.ofSeconds(expiresIn - 10), Duration.ofSeconds(expiresIn + 1)); + } + String sampleJsonToken(String accessToken, int expiresIn) { String json = "{\n" + " \"access_token\" : \"{accessToken}\",\n" + From c0811fa13b02883166630d299bc48a21640cef55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 23 Feb 2023 14:12:08 +0100 Subject: [PATCH 1680/2114] Remove hard dependency on Jackson in OAuth 2 support It's possible to override the token parsing method, to avoid using Jackson, but the class would have a Jackson mapper in its properties. This commit introduces an abstraction to parse the token and the default Jackson implementation is instantianted on the fly. --- ...ntCredentialsGrantCredentialsProvider.java | 33 +++++++++++++------ 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java index a76fb81dfd..3d6c699baa 100644 --- a/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java @@ -18,6 +18,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.rabbitmq.client.TrustEverythingTrustManager; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; import javax.net.ssl.*; import java.io.*; import java.net.HttpURLConnection; @@ -72,7 +74,7 @@ public class OAuth2ClientCredentialsGrantCredentialsProvider extends RefreshProt private final Map parameters; - private final ObjectMapper objectMapper = new ObjectMapper(); + private final AtomicReference> tokenExtractor = new AtomicReference<>(); private final String id; @@ -214,14 +216,8 @@ protected String usernameFromToken(Token token) { } protected Token parseToken(String response) { - try { - Map map = objectMapper.readValue(response, Map.class); - int expiresIn = ((Number) map.get("expires_in")).intValue(); - Instant receivedAt = Instant.now(); - return new Token(map.get("access_token").toString(), expiresIn, receivedAt); - } catch (IOException e) { - throw new OAuthTokenManagementException("Error while parsing OAuth 2 token", e); - } + return this.tokenExtractor.updateAndGet(current -> + current == null ? new JacksonTokenLookup() : current).apply(response); } @Override @@ -595,4 +591,21 @@ private SSLSocketFactory sslSocketFactory() { } } -} + + private static class JacksonTokenLookup implements Function { + + private final ObjectMapper objectMapper = new ObjectMapper(); + + @Override + public Token apply(String response) { + try { + Map map = objectMapper.readValue(response, Map.class); + int expiresIn = ((Number) map.get("expires_in")).intValue(); + Instant receivedAt = Instant.now(); + return new Token(map.get("access_token").toString(), expiresIn, receivedAt); + } catch (IOException e) { + throw new OAuthTokenManagementException("Error while parsing OAuth 2 token", e); + } + } + } +} \ No newline at end of file From 2dd331f1a8f4677bff9b187b6057ed79433a24ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 23 Feb 2023 15:43:54 +0100 Subject: [PATCH 1681/2114] Add GHA release scripts --- .github/workflows/release.yml | 50 +++++++++++++++++++++++++++++++++++ ci/evaluate-release.sh | 14 ++++++++++ ci/release-java-client.sh | 27 +++++++++++++++++++ 3 files changed, 91 insertions(+) create mode 100644 .github/workflows/release.yml create mode 100755 ci/evaluate-release.sh create mode 100755 ci/release-java-client.sh diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000000..f69d596fd4 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,50 @@ +name: Release AMQP Java Client + +on: + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-22.04 + + steps: + - uses: actions/checkout@v3 + - name: Evaluate release type + run: ci/evaluate-release.sh + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.x' + - name: Set up JDK + uses: actions/setup-java@v3 + with: + distribution: 'temurin' + java-version: '8' + cache: 'maven' + server-id: ${{ env.maven_server_id }} + server-username: MAVEN_USERNAME + server-password: MAVEN_PASSWORD + gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} + gpg-passphrase: MAVEN_GPG_PASSPHRASE + - name: Get dependencies + run: make deps + - name: Release AMQP Java Client (GA) + if: ${{ env.ga_release == 'true' }} + run: | + git config user.name "rabbitmq-ci" + git config user.email "rabbitmq-ci@users.noreply.github.com" + ci/release-java-client.sh + env: + MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }} + MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }} + MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }} + - name: Release AMQP Java Client (Milestone/RC) + if: ${{ env.ga_release != 'true' }} + run: | + git config user.name "rabbitmq-ci" + git config user.email "rabbitmq-ci@users.noreply.github.com" + ci/release-java-client.sh + env: + MAVEN_USERNAME: '' + MAVEN_PASSWORD: ${{ secrets.PACKAGECLOUD_TOKEN }} + MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }} \ No newline at end of file diff --git a/ci/evaluate-release.sh b/ci/evaluate-release.sh new file mode 100755 index 0000000000..4ad656d7a0 --- /dev/null +++ b/ci/evaluate-release.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +source ./release-versions.txt + +if [[ $RELEASE_VERSION == *[RCM]* ]] +then + echo "prerelease=true" >> $GITHUB_ENV + echo "ga_release=false" >> $GITHUB_ENV + echo "maven_server_id=packagecloud-rabbitmq-maven-milestones" >> $GITHUB_ENV +else + echo "prerelease=false" >> $GITHUB_ENV + echo "ga_release=true" >> $GITHUB_ENV + echo "maven_server_id=ossrh" >> $GITHUB_ENV +fi \ No newline at end of file diff --git a/ci/release-java-client.sh b/ci/release-java-client.sh new file mode 100755 index 0000000000..d3fd7df952 --- /dev/null +++ b/ci/release-java-client.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +source ./release-versions.txt +git checkout $RELEASE_BRANCH + +./mvnw release:clean release:prepare -DdryRun=true -Darguments="-DskipTests" --no-transfer-progress \ + --batch-mode -Dtag="v$RELEASE_VERSION" \ + -DreleaseVersion=$RELEASE_VERSION \ + -DdevelopmentVersion=$DEVELOPMENT_VERSION \ + +./mvnw release:clean release:prepare -Darguments="-DskipTests" --no-transfer-progress \ + --batch-mode -Dtag="v$RELEASE_VERSION" \ + -DreleaseVersion=$RELEASE_VERSION \ + -DdevelopmentVersion=$DEVELOPMENT_VERSION + +git checkout "v$RELEASE_VERSION" + +if [[ $RELEASE_VERSION == *[RCM]* ]] +then + MAVEN_PROFILE="milestone" + echo "prerelease=true" >> $GITHUB_ENV +else + MAVEN_PROFILE="release" + echo "prerelease=false" >> $GITHUB_ENV +fi + +./mvnw clean deploy -P $MAVEN_PROFILE -DskipTests --no-transfer-progress \ No newline at end of file From bcf93a8297070c8b8ed94aaaafbbce52bea8fee7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 23 Feb 2023 16:32:40 +0100 Subject: [PATCH 1682/2114] Use HTTPS in Maven dev connection To avoid key exchange in GHA. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ce452c2eb2..f4ce3b7795 100644 --- a/pom.xml +++ b/pom.xml @@ -41,7 +41,7 @@ https://github.com/rabbitmq/rabbitmq-java-client scm:git:git://github.com/rabbitmq/rabbitmq-java-client.git - scm:git:git@github.com:rabbitmq/rabbitmq-java-client.git + scm:git:https://github.com/rabbitmq/rabbitmq-java-client.git HEAD From 94462e3f042cda4434b3c5fbc06f3833aed0006a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 Feb 2023 00:53:09 +0000 Subject: [PATCH 1683/2114] Bump metrics-core from 4.2.16 to 4.2.17 Bumps [metrics-core](https://github.com/dropwizard/metrics) from 4.2.16 to 4.2.17. - [Release notes](https://github.com/dropwizard/metrics/releases) - [Commits](https://github.com/dropwizard/metrics/compare/v4.2.16...v4.2.17) --- updated-dependencies: - dependency-name: io.dropwizard.metrics:metrics-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f4ce3b7795..b92d9d1c26 100644 --- a/pom.xml +++ b/pom.xml @@ -55,7 +55,7 @@ UTF-8 1.7.36 - 4.2.16 + 4.2.17 1.10.4 1.23.1 2.14.1 From d421db7f665c9cd0c0cc0e9ecdef842dbbbf9cfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 24 Feb 2023 10:47:23 +0100 Subject: [PATCH 1684/2114] Add Java 21-ea to tested Java versions --- .github/workflows/test-supported-java-versions-5.x.yml | 8 +++++--- .github/workflows/test-supported-java-versions-main.yml | 8 +++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test-supported-java-versions-5.x.yml b/.github/workflows/test-supported-java-versions-5.x.yml index 7b24cd3406..73e6a56119 100644 --- a/.github/workflows/test-supported-java-versions-5.x.yml +++ b/.github/workflows/test-supported-java-versions-5.x.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-22.04 strategy: matrix: - java: [ '8', '11', '17', '19', '20-ea' ] + java: [ '8', '11', '17', '19', '20-ea', '21-ea' ] name: Test against Java ${{ matrix.java }} steps: - uses: actions/checkout@v3 @@ -47,13 +47,15 @@ jobs: -Dtest-broker.A.nodename=rabbit@$(hostname) -Dmaven.javadoc.skip=true \ -Dtest-client-cert.password= -Dtest-tls-certs.dir=rabbitmq-configuration/tls \ -Dit.test=ClientTestSuite,FunctionalTestSuite,ServerTestSuite,SslTestSuite \ - --no-transfer-progress + --no-transfer-progress \ + -Dnet.bytebuddy.experimental=true - name: Test with blocking IO run: | ./mvnw verify -P '!setup-test-cluster' -Drabbitmqctl.bin=DOCKER:rabbitmq \ -Dtest-broker.A.nodename=rabbit@$(hostname) -Dmaven.javadoc.skip=true \ -Dtest-client-cert.password= -Dtest-tls-certs.dir=rabbitmq-configuration/tls \ -Dit.test=ClientTestSuite,FunctionalTestSuite,ServerTestSuite,SslTestSuite \ - --no-transfer-progress + --no-transfer-progress \ + -Dnet.bytebuddy.experimental=true - name: Stop broker run: docker stop rabbitmq && docker rm rabbitmq \ No newline at end of file diff --git a/.github/workflows/test-supported-java-versions-main.yml b/.github/workflows/test-supported-java-versions-main.yml index 8687dbdd32..77afc9dc50 100644 --- a/.github/workflows/test-supported-java-versions-main.yml +++ b/.github/workflows/test-supported-java-versions-main.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-22.04 strategy: matrix: - java: [ '8', '11', '17', '19', '20-ea' ] + java: [ '8', '11', '17', '19', '20-ea', '21-ea' ] name: Test against Java ${{ matrix.java }} steps: - uses: actions/checkout@v3 @@ -45,13 +45,15 @@ jobs: -Dtest-broker.A.nodename=rabbit@$(hostname) -Dmaven.javadoc.skip=true \ -Dtest-client-cert.password= -Dtest-tls-certs.dir=rabbitmq-configuration/tls \ -Dit.test=ClientTestSuite,FunctionalTestSuite,ServerTestSuite,SslTestSuite \ - --no-transfer-progress + --no-transfer-progress \ + -Dnet.bytebuddy.experimental=true - name: Test with blocking IO run: | ./mvnw verify -P '!setup-test-cluster' -Drabbitmqctl.bin=DOCKER:rabbitmq \ -Dtest-broker.A.nodename=rabbit@$(hostname) -Dmaven.javadoc.skip=true \ -Dtest-client-cert.password= -Dtest-tls-certs.dir=rabbitmq-configuration/tls \ -Dit.test=ClientTestSuite,FunctionalTestSuite,ServerTestSuite,SslTestSuite \ - --no-transfer-progress + --no-transfer-progress \ + -Dnet.bytebuddy.experimental=true - name: Stop broker run: docker stop rabbitmq && docker rm rabbitmq \ No newline at end of file From 6d6778c6636d69564e85364b6d0fe3e1f8cb36e8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Feb 2023 01:07:23 +0000 Subject: [PATCH 1685/2114] Bump maven-compiler-plugin from 3.10.1 to 3.11.0 Bumps [maven-compiler-plugin](https://github.com/apache/maven-compiler-plugin) from 3.10.1 to 3.11.0. - [Release notes](https://github.com/apache/maven-compiler-plugin/releases) - [Commits](https://github.com/apache/maven-compiler-plugin/compare/maven-compiler-plugin-3.10.1...maven-compiler-plugin-3.11.0) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-compiler-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b92d9d1c26..d3a4a4a9f1 100644 --- a/pom.xml +++ b/pom.xml @@ -77,7 +77,7 @@ 2.4.21 1.6 3.3.0 - 3.10.1 + 3.11.0 3.0.0-M9 3.0.0-M9 3.0.1 From dcae5eebc3fff4d444472bdb89f9dc249b53bc79 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Feb 2023 01:07:33 +0000 Subject: [PATCH 1686/2114] Bump jetty-servlet from 9.4.50.v20221201 to 9.4.51.v20230217 Bumps [jetty-servlet](https://github.com/eclipse/jetty.project) from 9.4.50.v20221201 to 9.4.51.v20230217. - [Release notes](https://github.com/eclipse/jetty.project/releases) - [Commits](https://github.com/eclipse/jetty.project/compare/jetty-9.4.50.v20221201...jetty-9.4.51.v20230217) --- updated-dependencies: - dependency-name: org.eclipse.jetty:jetty-servlet dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b92d9d1c26..4f24cd9709 100644 --- a/pom.xml +++ b/pom.xml @@ -63,7 +63,7 @@ 5.9.2 5.1.1 3.24.2 - 9.4.50.v20221201 + 9.4.51.v20230217 1.70 0.10 2.10.1 From aeb3efa4471c6403646b6af301ce72acb6641e22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 8 Mar 2023 16:55:03 +0100 Subject: [PATCH 1687/2114] Use matrix to test broker alphas --- .github/workflows/test-native-image.yml | 5 ++--- ...test-3.11-alpha.yml => test-rabbitmq-alphas.yml} | 13 +++++++------ .../workflows/test-supported-java-versions-5.x.yml | 5 ++--- .../workflows/test-supported-java-versions-main.yml | 5 ++--- .../workflows/{test-3.11-stable.yml => test.yml} | 5 ++--- ci/start-broker.sh | 9 ++++----- ci/start-cluster.sh | 11 +++++------ 7 files changed, 24 insertions(+), 29 deletions(-) rename .github/workflows/{test-3.11-alpha.yml => test-rabbitmq-alphas.yml} (84%) rename .github/workflows/{test-3.11-stable.yml => test.yml} (97%) diff --git a/.github/workflows/test-native-image.yml b/.github/workflows/test-native-image.yml index 0a7fc33e9e..e92fe19b11 100644 --- a/.github/workflows/test-native-image.yml +++ b/.github/workflows/test-native-image.yml @@ -6,8 +6,7 @@ on: workflow_dispatch: env: - RABBITMQ_IMAGE_TAG: 3.11 - RABBITMQ_IMAGE: rabbitmq + RABBITMQ_IMAGE: 'rabbitmq:3.11' jobs: build: @@ -64,4 +63,4 @@ jobs: working-directory: rabbitmq-graal-vm-test run: ./rabbitmq-graal-vm-test-full - name: Stop broker - run: docker stop rabbitmq && docker rm rabbitmq \ No newline at end of file + run: docker stop rabbitmq && docker rm rabbitmq diff --git a/.github/workflows/test-3.11-alpha.yml b/.github/workflows/test-rabbitmq-alphas.yml similarity index 84% rename from .github/workflows/test-3.11-alpha.yml rename to .github/workflows/test-rabbitmq-alphas.yml index 3fcd69f089..6746d4141b 100644 --- a/.github/workflows/test-3.11-alpha.yml +++ b/.github/workflows/test-rabbitmq-alphas.yml @@ -11,14 +11,13 @@ on: - main workflow_dispatch: -env: - RABBITMQ_IMAGE_TAG: 3.11 - RABBITMQ_IMAGE: pivotalrabbitmq/rabbitmq-dev - jobs: build: runs-on: ubuntu-22.04 - + strategy: + matrix: + rabbitmq-image: [ 'pivotalrabbitmq/rabbitmq:v3.11.x-otp-max-bazel', 'pivotalrabbitmq/rabbitmq:v3.12.x-otp-max-bazel' ] + name: Test against ${{ matrix.rabbitmq-image }} steps: - uses: actions/checkout@v3 - name: Checkout tls-gen @@ -38,6 +37,8 @@ jobs: cache: 'maven' - name: Start cluster run: ci/start-cluster.sh + env: + RABBITMQ_IMAGE: ${{ matrix.rabbitmq-image }} - name: Get dependencies run: make deps - name: Test with NIO @@ -57,4 +58,4 @@ jobs: - name: Stop broker A run: docker stop rabbitmq && docker rm rabbitmq - name: Stop broker B - run: docker stop hare && docker rm hare \ No newline at end of file + run: docker stop hare && docker rm hare diff --git a/.github/workflows/test-supported-java-versions-5.x.yml b/.github/workflows/test-supported-java-versions-5.x.yml index 73e6a56119..6ff4ee2322 100644 --- a/.github/workflows/test-supported-java-versions-5.x.yml +++ b/.github/workflows/test-supported-java-versions-5.x.yml @@ -6,8 +6,7 @@ on: workflow_dispatch: env: - RABBITMQ_IMAGE_TAG: 3.11 - RABBITMQ_IMAGE: rabbitmq + RABBITMQ_IMAGE: 'rabbitmq:3.11' jobs: build: @@ -58,4 +57,4 @@ jobs: --no-transfer-progress \ -Dnet.bytebuddy.experimental=true - name: Stop broker - run: docker stop rabbitmq && docker rm rabbitmq \ No newline at end of file + run: docker stop rabbitmq && docker rm rabbitmq diff --git a/.github/workflows/test-supported-java-versions-main.yml b/.github/workflows/test-supported-java-versions-main.yml index 77afc9dc50..ffccc7a516 100644 --- a/.github/workflows/test-supported-java-versions-main.yml +++ b/.github/workflows/test-supported-java-versions-main.yml @@ -6,8 +6,7 @@ on: workflow_dispatch: env: - RABBITMQ_IMAGE_TAG: 3.11 - RABBITMQ_IMAGE: rabbitmq + RABBITMQ_IMAGE: 'rabbitmq:3.11' jobs: build: @@ -56,4 +55,4 @@ jobs: --no-transfer-progress \ -Dnet.bytebuddy.experimental=true - name: Stop broker - run: docker stop rabbitmq && docker rm rabbitmq \ No newline at end of file + run: docker stop rabbitmq && docker rm rabbitmq diff --git a/.github/workflows/test-3.11-stable.yml b/.github/workflows/test.yml similarity index 97% rename from .github/workflows/test-3.11-stable.yml rename to .github/workflows/test.yml index 544a18707e..4ebf82081d 100644 --- a/.github/workflows/test-3.11-stable.yml +++ b/.github/workflows/test.yml @@ -10,8 +10,7 @@ on: workflow_dispatch: env: - RABBITMQ_IMAGE_TAG: 3.11 - RABBITMQ_IMAGE: rabbitmq + RABBITMQ_IMAGE: 'rabbitmq:3.11' jobs: build: @@ -67,4 +66,4 @@ jobs: env: MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }} MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }} - MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }} \ No newline at end of file + MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }} diff --git a/ci/start-broker.sh b/ci/start-broker.sh index 17e4987ff4..c178e63784 100755 --- a/ci/start-broker.sh +++ b/ci/start-broker.sh @@ -2,8 +2,7 @@ LOCAL_SCRIPT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -RABBITMQ_IMAGE_TAG=${RABBITMQ_IMAGE_TAG:-3.11} -RABBITMQ_IMAGE=${RABBITMQ_IMAGE:-rabbitmq} +RABBITMQ_IMAGE=${RABBITMQ_IMAGE:-rabbitmq:3.11} wait_for_message() { while ! docker logs "$1" | grep -q "$2"; @@ -27,15 +26,15 @@ chmod -R o+r rabbitmq-configuration/tls/* ./mvnw -q clean resources:testResources -Dtest-tls-certs.dir=/etc/rabbitmq/tls cp target/test-classes/rabbit@localhost.config rabbitmq-configuration/rabbitmq.config -echo "Running RabbitMQ ${RABBITMQ_IMAGE}:${RABBITMQ_IMAGE_TAG}" +echo "Running RabbitMQ ${RABBITMQ_IMAGE}" docker rm -f rabbitmq 2>/dev/null || echo "rabbitmq was not running" docker run -d --name rabbitmq \ --network host \ -v "${PWD}"/rabbitmq-configuration:/etc/rabbitmq \ - "${RABBITMQ_IMAGE}":"${RABBITMQ_IMAGE_TAG}" + "${RABBITMQ_IMAGE}" wait_for_message rabbitmq "completed with" docker exec rabbitmq rabbitmq-diagnostics erlang_version -docker exec rabbitmq rabbitmqctl version \ No newline at end of file +docker exec rabbitmq rabbitmqctl version diff --git a/ci/start-cluster.sh b/ci/start-cluster.sh index d397d97212..c1dbac0786 100755 --- a/ci/start-cluster.sh +++ b/ci/start-cluster.sh @@ -2,8 +2,7 @@ LOCAL_SCRIPT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -RABBITMQ_IMAGE_TAG=${RABBITMQ_IMAGE_TAG:-3.11} -RABBITMQ_IMAGE=${RABBITMQ_IMAGE:-rabbitmq} +RABBITMQ_IMAGE=${RABBITMQ_IMAGE:-rabbitmq:3.11} wait_for_message() { while ! docker logs "$1" | grep -q "$2"; @@ -28,7 +27,7 @@ chmod -R o+r rabbitmq-configuration/tls/* cp target/test-classes/rabbit@localhost.config rabbitmq-configuration/rabbit@localhost.config cp target/test-classes/hare@localhost.config rabbitmq-configuration/hare@localhost.config -echo "Running RabbitMQ ${RABBITMQ_IMAGE}:${RABBITMQ_IMAGE_TAG}" +echo "Running RabbitMQ ${RABBITMQ_IMAGE}" docker rm -f rabbitmq 2>/dev/null || echo "rabbitmq was not running" docker run -d --name rabbitmq \ @@ -38,7 +37,7 @@ docker run -d --name rabbitmq \ --env RABBITMQ_NODENAME=rabbit@$(hostname) \ --env RABBITMQ_NODE_PORT=5672 \ --env RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS="-setcookie do-not-do-this-in-production" \ - "${RABBITMQ_IMAGE}":"${RABBITMQ_IMAGE_TAG}" + "${RABBITMQ_IMAGE}" # for CLI commands to share the same cookie docker exec rabbitmq bash -c "echo 'do-not-do-this-in-production' > /var/lib/rabbitmq/.erlang.cookie" @@ -53,7 +52,7 @@ docker run -d --name hare \ --env RABBITMQ_NODENAME=hare@$(hostname) \ --env RABBITMQ_NODE_PORT=5673 \ --env RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS="-setcookie do-not-do-this-in-production" \ - "${RABBITMQ_IMAGE}":"${RABBITMQ_IMAGE_TAG}" + "${RABBITMQ_IMAGE}" # for CLI commands to share the same cookie docker exec hare bash -c "echo 'do-not-do-this-in-production' > /var/lib/rabbitmq/.erlang.cookie" @@ -77,4 +76,4 @@ docker exec hare rabbitmqctl --node hare@$(hostname) await_startup docker exec rabbitmq rabbitmq-diagnostics --node rabbit@$(hostname) erlang_version docker exec rabbitmq rabbitmqctl --node rabbit@$(hostname) version docker exec rabbitmq rabbitmqctl --node rabbit@$(hostname) status -docker exec rabbitmq rabbitmqctl --node rabbit@$(hostname) cluster_status \ No newline at end of file +docker exec rabbitmq rabbitmqctl --node rabbit@$(hostname) cluster_status From 04b02d2fdd6f46500fd2fcc3ed034716cbfdc672 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 8 Mar 2023 16:57:19 +0100 Subject: [PATCH 1688/2114] Change GHA job label --- .github/workflows/test-rabbitmq-alphas.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-rabbitmq-alphas.yml b/.github/workflows/test-rabbitmq-alphas.yml index 6746d4141b..05688d479a 100644 --- a/.github/workflows/test-rabbitmq-alphas.yml +++ b/.github/workflows/test-rabbitmq-alphas.yml @@ -1,4 +1,4 @@ -name: Test against RabbitMQ 3.11 alpha +name: Test against RabbitMQ alphas on: schedule: From ac6ae46ee90969951606257f8198035de0ad2214 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Mar 2023 01:04:30 +0000 Subject: [PATCH 1689/2114] Bump mockito-core from 5.1.1 to 5.2.0 Bumps [mockito-core](https://github.com/mockito/mockito) from 5.1.1 to 5.2.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.1.1...v5.2.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6637c8d5b1..0d401eaacf 100644 --- a/pom.xml +++ b/pom.xml @@ -61,7 +61,7 @@ 2.14.1 1.2.11 5.9.2 - 5.1.1 + 5.2.0 3.24.2 9.4.51.v20230217 1.70 From ba1d8be354ad0c52ef19080080f06e178dd2807a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Mar 2023 01:38:17 +0000 Subject: [PATCH 1690/2114] Bump opentelemetry.version from 1.23.1 to 1.24.0 Bumps `opentelemetry.version` from 1.23.1 to 1.24.0. Updates `opentelemetry-api` from 1.23.1 to 1.24.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-java/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-java/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-java/compare/v1.23.1...v1.24.0) Updates `opentelemetry-sdk-testing` from 1.23.1 to 1.24.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-java/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-java/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-java/compare/v1.23.1...v1.24.0) --- updated-dependencies: - dependency-name: io.opentelemetry:opentelemetry-api dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: io.opentelemetry:opentelemetry-sdk-testing dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0d401eaacf..653288f2fe 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,7 @@ 1.7.36 4.2.17 1.10.4 - 1.23.1 + 1.24.0 2.14.1 1.2.11 5.9.2 From cf9e6c762d7a99bf42ccc81c51c5df141bc5d0a4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 15 Mar 2023 01:02:36 +0000 Subject: [PATCH 1691/2114] Bump micrometer-core from 1.10.4 to 1.10.5 Bumps [micrometer-core](https://github.com/micrometer-metrics/micrometer) from 1.10.4 to 1.10.5. - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.10.4...v1.10.5) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 653288f2fe..d696566a00 100644 --- a/pom.xml +++ b/pom.xml @@ -56,7 +56,7 @@ 1.7.36 4.2.17 - 1.10.4 + 1.10.5 1.24.0 2.14.1 1.2.11 From b3ec44ccee30e9c81354482bc601d3195308e98a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 15 Mar 2023 01:02:45 +0000 Subject: [PATCH 1692/2114] Bump keytool-maven-plugin from 1.6 to 1.7 Bumps [keytool-maven-plugin](https://github.com/mojohaus/keytool) from 1.6 to 1.7. - [Release notes](https://github.com/mojohaus/keytool/releases) - [Commits](https://github.com/mojohaus/keytool/compare/keytool-1.6...keytool-1.7) --- updated-dependencies: - dependency-name: org.codehaus.mojo:keytool-maven-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 653288f2fe..a1f1f8fe0a 100644 --- a/pom.xml +++ b/pom.xml @@ -75,7 +75,7 @@ 3.2.1 2.1.1 2.4.21 - 1.6 + 1.7 3.3.0 3.11.0 3.0.0-M9 From 52f5d66719ee104ba2e05d8b86fbab8b2f7a36e8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 15 Mar 2023 01:02:56 +0000 Subject: [PATCH 1693/2114] Bump maven-surefire-plugin from 3.0.0-M9 to 3.0.0 Bumps [maven-surefire-plugin](https://github.com/apache/maven-surefire) from 3.0.0-M9 to 3.0.0. - [Release notes](https://github.com/apache/maven-surefire/releases) - [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.0.0-M9...surefire-3.0.0) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-surefire-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 653288f2fe..640425f051 100644 --- a/pom.xml +++ b/pom.xml @@ -78,7 +78,7 @@ 1.6 3.3.0 3.11.0 - 3.0.0-M9 + 3.0.0 3.0.0-M9 3.0.1 3.3.0 From a54c95bdebe3fd737703698815892d92e5602b54 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 15 Mar 2023 03:18:09 +0000 Subject: [PATCH 1694/2114] Bump maven-failsafe-plugin from 3.0.0-M9 to 3.0.0 Bumps [maven-failsafe-plugin](https://github.com/apache/maven-surefire) from 3.0.0-M9 to 3.0.0. - [Release notes](https://github.com/apache/maven-surefire/releases) - [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.0.0-M9...surefire-3.0.0) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-failsafe-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 63665e4f9f..b2df0a0b93 100644 --- a/pom.xml +++ b/pom.xml @@ -79,7 +79,7 @@ 3.3.0 3.11.0 3.0.0 - 3.0.0-M9 + 3.0.0 3.0.1 3.3.0 5.1.8 From 0bd7cc0884b3e9f02833628ec78bac70dfc19897 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 17 Mar 2023 08:53:08 +0100 Subject: [PATCH 1695/2114] Disable dependabot on 5.x.x-stable RC phase. --- .github/dependabot.yml | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 71544d2951..c89ceb86a4 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -15,19 +15,19 @@ updates: versions: [ "[2.0,)" ] - dependency-name: "ch.qos.logback:logback-classic" versions: [ "[1.3,)" ] - - package-ecosystem: "maven" - directory: "/" - schedule: - interval: "daily" - open-pull-requests-limit: 20 - target-branch: "5.x.x-stable" - ignore: - - dependency-name: "org.eclipse.jetty:jetty-servlet" - versions: ["[10.0,)"] - - dependency-name: "org.slf4j:slf4j-api" - versions: [ "[2.0,)" ] - - dependency-name: "ch.qos.logback:logback-classic" - versions: [ "[1.3,)" ] + # - package-ecosystem: "maven" + # directory: "/" + # schedule: + # interval: "daily" + # open-pull-requests-limit: 20 + # target-branch: "5.x.x-stable" + # ignore: + # - dependency-name: "org.eclipse.jetty:jetty-servlet" + # versions: ["[10.0,)"] + # - dependency-name: "org.slf4j:slf4j-api" + # versions: [ "[2.0,)" ] + # - dependency-name: "ch.qos.logback:logback-classic" + # versions: [ "[1.3,)" ] - package-ecosystem: "github-actions" directory: "/" schedule: @@ -37,4 +37,4 @@ updates: directory: "/" schedule: interval: "daily" - target-branch: "5.x.x-stable" \ No newline at end of file + target-branch: "5.x.x-stable" From 97a873b575f436ce97d7ce2c3e5d443e6e8673a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 17 Mar 2023 10:07:17 +0100 Subject: [PATCH 1696/2114] Convert readme to AsciiDoc --- README.adoc | 151 ++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 161 ---------------------------------------------------- 2 files changed, 151 insertions(+), 161 deletions(-) create mode 100644 README.adoc delete mode 100644 README.md diff --git a/README.adoc b/README.adoc new file mode 100644 index 0000000000..bad30f8e36 --- /dev/null +++ b/README.adoc @@ -0,0 +1,151 @@ += RabbitMQ Java Client + +image:https://maven-badges.herokuapp.com/maven-central/com.rabbitmq/amqp-client/badge.svg["Maven Central", link="https://maven-badges.herokuapp.com/maven-central/com.rabbitmq/amqp-client"] +image:https://github.com/rabbitmq/rabbitmq-java-client/actions/workflows/test.yml/badge.svg["Build Status", link="https://github.com/rabbitmq/rabbitmq-java-client/actions/workflows/test.yml"] + +This repository contains source code of the https://www.rabbitmq.com/api-guide.html[RabbitMQ Java client]. +The client is maintained by the https://github.com/rabbitmq/[RabbitMQ team at VMware]. + +== Dependency (Maven Artifact) + +This package is published to several Maven package repositories: + +* https://search.maven.org/#search%7Cga%7C1%7Cg%3Acom.rabbitmq%20a%3Aamqp-client[Maven Central] +* https://packagecloud.io/rabbitmq/maven-milestones[RabbitMQ Maven Milestones repository] +* https://oss.sonatype.org/content/repositories/snapshots/com/rabbitmq/amqp-client/[Sonatype OSS snapshot repository] + +This client releases are independent of RabbitMQ server releases and can be used with RabbitMQ server `3.x`. +They require Java 8 or higher. + +=== Maven + +.pom.xml +[source,xml,subs="attributes,specialcharacters"] +---- + + com.rabbitmq + amqp-client + 5.16.0 + +---- + +=== Gradle + +.build.gradle +[source,groovy,subs="attributes,specialcharacters"] +---- +compile 'com.rabbitmq:amqp-client:5.16.0' +---- + +=== 4.x Series + +**As of 1 January 2021 the 4.x branch is no longer supported**. + +== Experimenting with JShell + +You can experiment with the client from JShell. This requires Java 9 or more. + +[source,shell] +---- +git clone https://github.com/rabbitmq/rabbitmq-java-client.git +cd rabbitmq-java-client +./mvnw test-compile jshell:run +... +import com.rabbitmq.client.* +ConnectionFactory cf = new ConnectionFactory() +Connection c = cf.newConnection() +... +c.close() +/exit +---- + +== Building from Source + +=== Getting the Project and its Dependencies + +[source,shell] +---- +git clone git@github.com:rabbitmq/rabbitmq-java-client.git +cd rabbitmq-java-client +make deps +---- + +=== Building the JAR File + +[source,shell] +---- +./mvnw clean package -Dmaven.test.skip -P '!setup-test-cluster' +---- + +=== Launching Tests with the Broker Running in a Docker Container + +Run the broker: + +[source,shell] +---- +docker run -it --rm --name rabbitmq -p 5672:5672 rabbitmq +---- + +Launch "essential" tests (takes about 10 minutes): + +[source,shell] +---- +./mvnw verify -P '!setup-test-cluster' \ + -Drabbitmqctl.bin=DOCKER:rabbitmq \ + -Dit.test=ClientTestSuite,FunctionalTestSuite,ServerTestSuite +---- + +Launch a single test: + +[source,shell] +---- +./mvnw verify -P '!setup-test-cluster' \ + -Drabbitmqctl.bin=DOCKER:rabbitmq \ + -Dit.test=DeadLetterExchange +---- + +=== Launching Tests with a Local Broker + +The tests can run against a local broker as well. The `rabbitmqctl.bin` +system property must point to the `rabbitmqctl` program: + +[source,shell] +---- +./mvnw verify -P '!setup-test-cluster' \ + -Dtest-broker.A.nodename=rabbit@$(hostname) \ + -Drabbitmqctl.bin=/path/to/rabbitmqctl \ + -Dit.test=ClientTestSuite,FunctionalTestSuite,ServerTestSuite +---- + +To launch a single test: + +[source,shell] +---- +./mvnw verify -P '!setup-test-cluster' \ + -Dtest-broker.A.nodename=rabbit@$(hostname) \ + -Drabbitmqctl.bin=/path/to/rabbitmqctl \ + -Dit.test=DeadLetterExchange +---- + +== Contributing + +See link:CONTRIBUTING.md[Contributing] and link:RUNNING_TESTS.md[How to Run Tests]. + +== Versioning + +This library uses https://semver.org/[semantic versioning]. + +== Support + +See the https://www.rabbitmq.com/java-versions.html[RabbitMQ Java libraries support page] +for the support timeline of this library. + +== License + +This package, the RabbitMQ Java client library, is https://www.rabbitmq.com/api-guide.html#license[triple-licensed] under +the Mozilla Public License 2.0 ("MPL"), the GNU General Public License +version 2 ("GPL") and the Apache License version 2 ("AL"). + +This means that the user can consider the library to be licensed under **any of the licenses from the list** above. +For example, you may choose the Apache Public License 2.0 and include this client into a commercial product. +Projects that are licensed under the GPLv2 may choose GPLv2, and so on. diff --git a/README.md b/README.md deleted file mode 100644 index fa7573357d..0000000000 --- a/README.md +++ /dev/null @@ -1,161 +0,0 @@ -# RabbitMQ Java Client - -[![Build Status](https://github.com/rabbitmq/rabbitmq-java-client/actions/workflows/test-3.11-stable.yml/badge.svg)](https://github.com/rabbitmq/rabbitmq-java-client/actions/workflows/test-3.11-stable.yml) - - -This repository contains source code of the [RabbitMQ Java client](https://www.rabbitmq.com/api-guide.html). -The client is maintained by the [RabbitMQ team at VMware](https://github.com/rabbitmq/). - - -## Dependency (Maven Artifact) - -This package is published to several Maven package repositories: - -* [Maven Central](https://search.maven.org/#search%7Cga%7C1%7Cg%3Acom.rabbitmq%20a%3Aamqp-client) -* [RabbitMQ Maven Milestones repository](https://packagecloud.io/rabbitmq/maven-milestones) -* [Sonatype OSS snapshot repository](https://oss.sonatype.org/content/repositories/snapshots/com/rabbitmq/amqp-client/) - -### Maven - -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.rabbitmq/amqp-client/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.rabbitmq/amqp-client) - -#### 5.x Series - -This client releases are independent from RabbitMQ server releases and can be used with RabbitMQ server `3.x`. -They require Java 8 or higher. - -``` xml - - com.rabbitmq - amqp-client - 5.16.0 - -``` - -### Gradle - -``` groovy -compile 'com.rabbitmq:amqp-client:5.16.0' -``` - -#### 4.x Series - -**As of 1 January 2021 the 4.x branch is no longer supported**. - -This client releases are independent from RabbitMQ server releases and can be used with RabbitMQ server `3.x`. -They require Java 6 or higher. - -``` xml - - com.rabbitmq - amqp-client - 4.12.0 - -``` - -### Gradle - -``` groovy -compile 'com.rabbitmq:amqp-client:4.12.0' -``` - -## Experimenting with JShell - -You can experiment with the client from JShell. This requires Java 9 or more. - -``` -git clone https://github.com/rabbitmq/rabbitmq-java-client.git -cd rabbitmq-java-client -./mvnw test-compile jshell:run -... -import com.rabbitmq.client.* -ConnectionFactory cf = new ConnectionFactory() -Connection c = cf.newConnection() -... -c.close() -/exit -``` - -## Building from Source - -### Getting the Project and its Dependencies - -``` -git clone git@github.com:rabbitmq/rabbitmq-java-client.git -cd rabbitmq-java-client -make deps -``` - -### Building the JAR File - -``` -./mvnw clean package -Dmaven.test.skip -P '!setup-test-cluster' -``` - -### Launching Tests with the Broker Running in a Docker Container - -Run the broker: - -``` -docker run -it --rm --name rabbitmq -p 5672:5672 rabbitmq:3.8 -``` - -Launch "essential" tests (takes about 10 minutes): - -``` -./mvnw verify -P '!setup-test-cluster' \ - -Drabbitmqctl.bin=DOCKER:rabbitmq \ - -Dit.test=ClientTestSuite,FunctionalTestSuite,ServerTestSuite -``` - -Launch a single test: - -``` -./mvnw verify -P '!setup-test-cluster' \ - -Drabbitmqctl.bin=DOCKER:rabbitmq \ - -Dit.test=DeadLetterExchange -``` - -### Launching Tests with a Local Broker - -The tests can run against a local broker as well. The `rabbitmqctl.bin` -system property must point to the `rabbitmqctl` program: - -``` -./mvnw verify -P '!setup-test-cluster' \ - -Dtest-broker.A.nodename=rabbit@$(hostname) \ - -Drabbitmqctl.bin=/path/to/rabbitmqctl \ - -Dit.test=ClientTestSuite,FunctionalTestSuite,ServerTestSuite -``` - -To launch a single test: - -``` -./mvnw verify -P '!setup-test-cluster' \ - -Dtest-broker.A.nodename=rabbit@$(hostname) \ - -Drabbitmqctl.bin=/path/to/rabbitmqctl \ - -Dit.test=DeadLetterExchange -``` - -## Contributing - -See [Contributing](./CONTRIBUTING.md) and [How to Run Tests](./RUNNING_TESTS.md). - -## Versioning - -This library uses [semantic versioning](https://semver.org/). - -## Support - -See the [RabbitMQ Java libraries support page](https://www.rabbitmq.com/java-versions.html) -for the support timeline of this library. - -## License - -This package, the RabbitMQ Java client library, is [triple-licensed](https://www.rabbitmq.com/api-guide.html#license) under -the Mozilla Public License 2.0 ("MPL"), the GNU General Public License -version 2 ("GPL") and the Apache License version 2 ("AL"). - -This means that the user can consider the library to be licensed under **any of the licenses from the list** above. -For example, you may choose the Apache Public License 2.0 and include this client into a commercial product. -Projects that are licensed under the GPLv2 may choose GPLv2, and so on. From b80a2fa0aa97c3718e3dae44d67b3ea3c01d7bba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 17 Mar 2023 10:30:58 +0100 Subject: [PATCH 1697/2114] Add version info to readme --- README.adoc | 125 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 115 insertions(+), 10 deletions(-) diff --git a/README.adoc b/README.adoc index bad30f8e36..5cd8bdd629 100644 --- a/README.adoc +++ b/README.adoc @@ -1,3 +1,7 @@ +:client-stable: 5.16.0 +:client-rc: 5.17.0.RC2 +:client-snapshot: 5.17.0-SNAPSHOT + = RabbitMQ Java Client image:https://maven-badges.herokuapp.com/maven-central/com.rabbitmq/amqp-client/badge.svg["Maven Central", link="https://maven-badges.herokuapp.com/maven-central/com.rabbitmq/amqp-client"] @@ -8,16 +12,87 @@ The client is maintained by the https://github.com/rabbitmq/[RabbitMQ team at VM == Dependency (Maven Artifact) -This package is published to several Maven package repositories: - -* https://search.maven.org/#search%7Cga%7C1%7Cg%3Acom.rabbitmq%20a%3Aamqp-client[Maven Central] -* https://packagecloud.io/rabbitmq/maven-milestones[RabbitMQ Maven Milestones repository] -* https://oss.sonatype.org/content/repositories/snapshots/com/rabbitmq/amqp-client/[Sonatype OSS snapshot repository] - This client releases are independent of RabbitMQ server releases and can be used with RabbitMQ server `3.x`. They require Java 8 or higher. -=== Maven +=== Stable + +==== Maven + +.pom.xml +[source,xml,subs="attributes,specialcharacters"] +---- + + com.rabbitmq + amqp-client + {client-stable} + +---- + +==== Gradle + +.build.gradle +[source,groovy,subs="attributes,specialcharacters"] +---- +compile 'com.rabbitmq:amqp-client:{client-stable}' +---- + +=== Milestones and Release Candidates + +==== Maven + +.pom.xml +[source,xml,subs="attributes,specialcharacters"] +---- + + com.rabbitmq + amqp-client + {client-rc} + +---- + +Milestones and release candidates are available on the RabbitMQ Milestone Repository: + +.pom.xml +[source,xml,subs="attributes,specialcharacters"] +---- + + + packagecloud-rabbitmq-maven-milestones + https://packagecloud.io/rabbitmq/maven-milestones/maven2 + + true + + + false + + + +---- + +==== Gradle + +.build.gradle +[source,groovy,subs="attributes,specialcharacters"] +---- +compile 'com.rabbitmq:amqp-client:{client-rc}' +---- + +Milestones and release candidates are available on the RabbitMQ Milestone Repository: + +.build.gradle +[source,groovy,subs="attributes,specialcharacters"] +---- +repositories { + maven { + url "https://packagecloud.io/rabbitmq/maven-milestones/maven2" + } +} +---- + +=== Snapshots + +==== Maven .pom.xml [source,xml,subs="attributes,specialcharacters"] @@ -25,16 +100,46 @@ They require Java 8 or higher. com.rabbitmq amqp-client - 5.16.0 + {client-snapshot} ---- -=== Gradle +Snapshots are available on the Sonatype OSS snapshot repository: + +.pom.xml +[source,xml,subs="attributes,specialcharacters"] +---- + + + ossrh + https://oss.sonatype.org/content/repositories/snapshots + + true + + + false + + + +---- + +==== Gradle + +.build.gradle +[source,groovy,subs="attributes,specialcharacters"] +---- +compile 'com.rabbitmq:amqp-client:{client-snapshot}' +---- + +Snapshots are available on the Sonatype OSS snapshot repository: .build.gradle [source,groovy,subs="attributes,specialcharacters"] ---- -compile 'com.rabbitmq:amqp-client:5.16.0' +repositories { + maven { url 'https://oss.sonatype.org/content/repositories/snapshots' } + mavenCentral() +} ---- === 4.x Series From 97d05dafb863268bc86f8175d9082264ddfd807a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Mar 2023 01:38:30 +0000 Subject: [PATCH 1698/2114] Bump metrics-core from 4.2.17 to 4.2.18 Bumps [metrics-core](https://github.com/dropwizard/metrics) from 4.2.17 to 4.2.18. - [Release notes](https://github.com/dropwizard/metrics/releases) - [Commits](https://github.com/dropwizard/metrics/compare/v4.2.17...v4.2.18) --- updated-dependencies: - dependency-name: io.dropwizard.metrics:metrics-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b2df0a0b93..c925fa33fc 100644 --- a/pom.xml +++ b/pom.xml @@ -55,7 +55,7 @@ UTF-8 1.7.36 - 4.2.17 + 4.2.18 1.10.5 1.24.0 2.14.1 From 0db5101664982aab61b164a0dd88f0a1dc74370e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 Mar 2023 01:01:23 +0000 Subject: [PATCH 1699/2114] Bump maven-release-plugin from 2.5.3 to 3.0.0 Bumps [maven-release-plugin](https://github.com/apache/maven-release) from 2.5.3 to 3.0.0. - [Release notes](https://github.com/apache/maven-release/releases) - [Commits](https://github.com/apache/maven-release/compare/maven-release-2.5.3...maven-release-3.0.0) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-release-plugin dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c925fa33fc..1c19d299f1 100644 --- a/pom.xml +++ b/pom.xml @@ -69,7 +69,7 @@ 2.10.1 3.5.0 - 2.5.3 + 3.0.0 2.15.0 3.3.0 3.2.1 From 2b2fd17e027dd11a3a8f3542d7597c8710a5cb51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 21 Mar 2023 17:50:59 +0100 Subject: [PATCH 1700/2114] Use 5.17.0 in readme --- README.adoc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.adoc b/README.adoc index 5cd8bdd629..a3944d22fd 100644 --- a/README.adoc +++ b/README.adoc @@ -1,6 +1,6 @@ -:client-stable: 5.16.0 +:client-stable: 5.17.0 :client-rc: 5.17.0.RC2 -:client-snapshot: 5.17.0-SNAPSHOT +:client-snapshot: 5.18.0-SNAPSHOT = RabbitMQ Java Client @@ -37,6 +37,7 @@ They require Java 8 or higher. compile 'com.rabbitmq:amqp-client:{client-stable}' ---- +//// === Milestones and Release Candidates ==== Maven @@ -89,6 +90,7 @@ repositories { } } ---- +//// === Snapshots From 46dfbb459977a711ceaf34bd950af67c6861fa29 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 Mar 2023 01:02:25 +0000 Subject: [PATCH 1701/2114] Bump logback-classic from 1.2.11 to 1.2.12 Bumps [logback-classic](https://github.com/qos-ch/logback) from 1.2.11 to 1.2.12. - [Release notes](https://github.com/qos-ch/logback/releases) - [Commits](https://github.com/qos-ch/logback/compare/v_1.2.11...v_1.2.12) --- updated-dependencies: - dependency-name: ch.qos.logback:logback-classic dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1c19d299f1..05e0fceeea 100644 --- a/pom.xml +++ b/pom.xml @@ -59,7 +59,7 @@ 1.10.5 1.24.0 2.14.1 - 1.2.11 + 1.2.12 5.9.2 5.2.0 3.24.2 From 197f5acf6ec1b6eb2146a7ba9dda8bc2f38ce39c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Mar 2023 01:38:43 +0000 Subject: [PATCH 1702/2114] Bump maven-resources-plugin from 3.3.0 to 3.3.1 Bumps [maven-resources-plugin](https://github.com/apache/maven-resources-plugin) from 3.3.0 to 3.3.1. - [Release notes](https://github.com/apache/maven-resources-plugin/releases) - [Commits](https://github.com/apache/maven-resources-plugin/compare/maven-resources-plugin-3.3.0...maven-resources-plugin-3.3.1) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-resources-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 05e0fceeea..14fc25c5d1 100644 --- a/pom.xml +++ b/pom.xml @@ -71,7 +71,7 @@ 3.5.0 3.0.0 2.15.0 - 3.3.0 + 3.3.1 3.2.1 2.1.1 2.4.21 From cfb0097b774f418357992b11bc3185e2f6a6869d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 4 Apr 2023 09:59:23 +0200 Subject: [PATCH 1703/2114] Test against Java 20 (stable) Remove Java 19 (no longer supported). --- .github/workflows/test-supported-java-versions-5.x.yml | 2 +- .github/workflows/test-supported-java-versions-main.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-supported-java-versions-5.x.yml b/.github/workflows/test-supported-java-versions-5.x.yml index 6ff4ee2322..d99378e3ab 100644 --- a/.github/workflows/test-supported-java-versions-5.x.yml +++ b/.github/workflows/test-supported-java-versions-5.x.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-22.04 strategy: matrix: - java: [ '8', '11', '17', '19', '20-ea', '21-ea' ] + java: [ '8', '11', '17', '20', '21-ea' ] name: Test against Java ${{ matrix.java }} steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/test-supported-java-versions-main.yml b/.github/workflows/test-supported-java-versions-main.yml index ffccc7a516..e9c984af12 100644 --- a/.github/workflows/test-supported-java-versions-main.yml +++ b/.github/workflows/test-supported-java-versions-main.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-22.04 strategy: matrix: - java: [ '8', '11', '17', '19', '20-ea', '21-ea' ] + java: [ '8', '11', '17', '20', '21-ea' ] name: Test against Java ${{ matrix.java }} steps: - uses: actions/checkout@v3 From 8dfeb3761954a086cb7c9c333d6d91ce25985b69 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Apr 2023 01:15:29 +0000 Subject: [PATCH 1704/2114] Bump opentelemetry.version from 1.24.0 to 1.25.0 Bumps `opentelemetry.version` from 1.24.0 to 1.25.0. Updates `opentelemetry-api` from 1.24.0 to 1.25.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-java/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-java/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-java/compare/v1.24.0...v1.25.0) Updates `opentelemetry-sdk-testing` from 1.24.0 to 1.25.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-java/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-java/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-java/compare/v1.24.0...v1.25.0) --- updated-dependencies: - dependency-name: io.opentelemetry:opentelemetry-api dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: io.opentelemetry:opentelemetry-sdk-testing dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 14fc25c5d1..8086270b5b 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,7 @@ 1.7.36 4.2.18 1.10.5 - 1.24.0 + 1.25.0 2.14.1 1.2.12 5.9.2 From 3b3a08d7930f5161d4cc70842276ad80718480c0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Apr 2023 01:01:09 +0000 Subject: [PATCH 1705/2114] Bump micrometer-core from 1.10.5 to 1.10.6 Bumps [micrometer-core](https://github.com/micrometer-metrics/micrometer) from 1.10.5 to 1.10.6. - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.10.5...v1.10.6) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8086270b5b..0abe7a4c4c 100644 --- a/pom.xml +++ b/pom.xml @@ -56,7 +56,7 @@ 1.7.36 4.2.18 - 1.10.5 + 1.10.6 1.25.0 2.14.1 1.2.12 From 0a872829ede82122c37df135fdba29714b508f4c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Apr 2023 01:09:11 +0000 Subject: [PATCH 1706/2114] Bump mockito-core from 5.2.0 to 5.3.0 Bumps [mockito-core](https://github.com/mockito/mockito) from 5.2.0 to 5.3.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.2.0...v5.3.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0abe7a4c4c..0a3e308094 100644 --- a/pom.xml +++ b/pom.xml @@ -61,7 +61,7 @@ 2.14.1 1.2.12 5.9.2 - 5.2.0 + 5.3.0 3.24.2 9.4.51.v20230217 1.70 From 1a6b14f1dc9dc0cbd92147b46a248ff660880c52 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Apr 2023 01:13:09 +0000 Subject: [PATCH 1707/2114] Bump mockito-core from 5.3.0 to 5.3.1 Bumps [mockito-core](https://github.com/mockito/mockito) from 5.3.0 to 5.3.1. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.3.0...v5.3.1) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0a3e308094..8a0bc59fda 100644 --- a/pom.xml +++ b/pom.xml @@ -61,7 +61,7 @@ 2.14.1 1.2.12 5.9.2 - 5.3.0 + 5.3.1 3.24.2 9.4.51.v20230217 1.70 From b467a2aae82434b8668ebe19831998a47516e8de Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Apr 2023 01:13:18 +0000 Subject: [PATCH 1708/2114] Bump jackson-databind from 2.14.1 to 2.15.0 Bumps [jackson-databind](https://github.com/FasterXML/jackson) from 2.14.1 to 2.15.0. - [Release notes](https://github.com/FasterXML/jackson/releases) - [Commits](https://github.com/FasterXML/jackson/commits) --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-databind dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0a3e308094..94ef768ec5 100644 --- a/pom.xml +++ b/pom.xml @@ -58,7 +58,7 @@ 4.2.18 1.10.6 1.25.0 - 2.14.1 + 2.15.0 1.2.12 5.9.2 5.3.0 From 582fbc2267f7581a1237eae671127594559463d6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 27 Apr 2023 01:01:09 +0000 Subject: [PATCH 1709/2114] Bump junit-bom from 5.9.2 to 5.9.3 Bumps [junit-bom](https://github.com/junit-team/junit5) from 5.9.2 to 5.9.3. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.9.2...r5.9.3) --- updated-dependencies: - dependency-name: org.junit:junit-bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7f27ea526d..686c923a1d 100644 --- a/pom.xml +++ b/pom.xml @@ -60,7 +60,7 @@ 1.25.0 2.15.0 1.2.12 - 5.9.2 + 5.9.3 5.3.1 3.24.2 9.4.51.v20230217 From 01f77dce549645c0f25da4d9779d6eb2977000be Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 May 2023 01:08:21 +0000 Subject: [PATCH 1710/2114] Bump opentelemetry.version from 1.25.0 to 1.26.0 Bumps `opentelemetry.version` from 1.25.0 to 1.26.0. Updates `opentelemetry-api` from 1.25.0 to 1.26.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-java/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-java/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-java/compare/v1.25.0...v1.26.0) Updates `opentelemetry-sdk-testing` from 1.25.0 to 1.26.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-java/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-java/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-java/compare/v1.25.0...v1.26.0) --- updated-dependencies: - dependency-name: io.opentelemetry:opentelemetry-api dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: io.opentelemetry:opentelemetry-sdk-testing dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 686c923a1d..a8171e5067 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,7 @@ 1.7.36 4.2.18 1.10.6 - 1.25.0 + 1.26.0 2.15.0 1.2.12 5.9.3 From f9b317c463fe877f1a887c97293b922e515f37bd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 May 2023 01:08:54 +0000 Subject: [PATCH 1711/2114] Bump maven-gpg-plugin from 3.0.1 to 3.1.0 Bumps [maven-gpg-plugin](https://github.com/apache/maven-gpg-plugin) from 3.0.1 to 3.1.0. - [Commits](https://github.com/apache/maven-gpg-plugin/compare/maven-gpg-plugin-3.0.1...maven-gpg-plugin-3.1.0) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-gpg-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 686c923a1d..24d5fb7e1f 100644 --- a/pom.xml +++ b/pom.xml @@ -80,7 +80,7 @@ 3.11.0 3.0.0 3.0.0 - 3.0.1 + 3.1.0 3.3.0 5.1.8 0.0.6 From 3567a47c74da3b02bb1bdbcebc576e0af804fa3c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 May 2023 05:34:37 +0000 Subject: [PATCH 1712/2114] Bump maven-failsafe-plugin from 3.0.0 to 3.1.0 Bumps [maven-failsafe-plugin](https://github.com/apache/maven-surefire) from 3.0.0 to 3.1.0. - [Release notes](https://github.com/apache/maven-surefire/releases) - [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.0.0...surefire-3.1.0) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-failsafe-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 24d5fb7e1f..160321c121 100644 --- a/pom.xml +++ b/pom.xml @@ -79,7 +79,7 @@ 3.3.0 3.11.0 3.0.0 - 3.0.0 + 3.1.0 3.1.0 3.3.0 5.1.8 From 3448b5fe91876b2a01a8ae3e7f10d45bf8d00cef Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 May 2023 11:15:04 +0000 Subject: [PATCH 1713/2114] Bump maven-surefire-plugin from 3.0.0 to 3.1.0 Bumps [maven-surefire-plugin](https://github.com/apache/maven-surefire) from 3.0.0 to 3.1.0. - [Release notes](https://github.com/apache/maven-surefire/releases) - [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.0.0...surefire-3.1.0) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-surefire-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6928d3c7ac..59c58603ee 100644 --- a/pom.xml +++ b/pom.xml @@ -78,7 +78,7 @@ 1.7 3.3.0 3.11.0 - 3.0.0 + 3.1.0 3.1.0 3.1.0 3.3.0 From f5db971f95cc0294850b64ac62287a4b76dce0be Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 10 May 2023 01:15:29 +0000 Subject: [PATCH 1714/2114] Bump micrometer-core from 1.10.6 to 1.11.0 Bumps [micrometer-core](https://github.com/micrometer-metrics/micrometer) from 1.10.6 to 1.11.0. - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.10.6...v1.11.0) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 59c58603ee..6149e3e492 100644 --- a/pom.xml +++ b/pom.xml @@ -56,7 +56,7 @@ 1.7.36 4.2.18 - 1.10.6 + 1.11.0 1.26.0 2.15.0 1.2.12 From 3e69a9e44534b9ed0d43e19af5301d0ddaec2e15 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 12 May 2023 01:01:12 +0000 Subject: [PATCH 1715/2114] Bump build-helper-maven-plugin from 3.3.0 to 3.4.0 Bumps [build-helper-maven-plugin](https://github.com/mojohaus/build-helper-maven-plugin) from 3.3.0 to 3.4.0. - [Release notes](https://github.com/mojohaus/build-helper-maven-plugin/releases) - [Commits](https://github.com/mojohaus/build-helper-maven-plugin/compare/build-helper-maven-plugin-3.3.0...3.4.0) --- updated-dependencies: - dependency-name: org.codehaus.mojo:build-helper-maven-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6149e3e492..663a5e06de 100644 --- a/pom.xml +++ b/pom.xml @@ -76,7 +76,7 @@ 2.1.1 2.4.21 1.7 - 3.3.0 + 3.4.0 3.11.0 3.1.0 3.1.0 From 75a94f6374d3ca9ec45322dcfe82df5576a1efd5 Mon Sep 17 00:00:00 2001 From: Johannes Hahn Date: Mon, 15 May 2023 17:55:24 +0200 Subject: [PATCH 1716/2114] make RpcClient implement java.io.Closeable --- src/main/java/com/rabbitmq/client/RpcClient.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/RpcClient.java b/src/main/java/com/rabbitmq/client/RpcClient.java index 17b9d3259f..7f052d015f 100644 --- a/src/main/java/com/rabbitmq/client/RpcClient.java +++ b/src/main/java/com/rabbitmq/client/RpcClient.java @@ -18,6 +18,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.Closeable; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.EOFException; @@ -44,7 +45,7 @@ * It simply provides a mechanism for sending a message to an exchange with a given routing key, * and waiting for a response. */ -public class RpcClient { +public class RpcClient implements Closeable { private static final Logger LOGGER = LoggerFactory.getLogger(RpcClient.class); @@ -151,10 +152,13 @@ public void checkConsumer() throws IOException { * Public API - cancels the consumer, thus deleting the temporary queue, and marks the RpcClient as closed. * @throws IOException if an error is encountered */ + @Override public void close() throws IOException { if (_consumer != null) { - _channel.basicCancel(_consumer.getConsumerTag()); + final String consumerTag = _consumer.getConsumerTag(); + // set it null before calling basicCancel to make this method idempotent in case of IOException _consumer = null; + _channel.basicCancel(consumerTag); } } From 22530174398460ef8bd87d431c8ec28aeea8df7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 16 May 2023 10:37:04 +0200 Subject: [PATCH 1717/2114] Use atomic boolean to track state of RpcClient Instead of using the consumer property. Avoids race conditions during closing. References #1033 --- .../java/com/rabbitmq/client/RpcClient.java | 29 +++++++++---------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/RpcClient.java b/src/main/java/com/rabbitmq/client/RpcClient.java index 7f052d015f..e391db54f7 100644 --- a/src/main/java/com/rabbitmq/client/RpcClient.java +++ b/src/main/java/com/rabbitmq/client/RpcClient.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -13,12 +13,10 @@ // If you have any questions regarding licensing, please contact us at // info@rabbitmq.com. - package com.rabbitmq.client; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; -import java.io.Closeable; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.EOFException; @@ -28,6 +26,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Function; import java.util.function.Supplier; @@ -45,7 +44,7 @@ * It simply provides a mechanism for sending a message to an exchange with a given routing key, * and waiting for a response. */ -public class RpcClient implements Closeable { +public class RpcClient implements AutoCloseable { private static final Logger LOGGER = LoggerFactory.getLogger(RpcClient.class); @@ -63,6 +62,8 @@ public class RpcClient implements Closeable { protected final static int NO_TIMEOUT = -1; /** Whether to publish RPC requests with the mandatory flag or not. */ private final boolean _useMandatory; + /** closed flag */ + private final AtomicBoolean closed = new AtomicBoolean(false); public final static Function DEFAULT_REPLY_HANDLER = reply -> { if (reply instanceof ShutdownSignalException) { @@ -96,7 +97,7 @@ public class RpcClient implements Closeable { private String lastCorrelationId = "0"; /** Consumer attached to our reply queue */ - private DefaultConsumer _consumer; + private final DefaultConsumer _consumer; /** * Construct a {@link RpcClient} with the passed-in {@link RpcClientParams}. @@ -142,8 +143,8 @@ public RpcClient(RpcClientParams params) throws * Private API - ensures the RpcClient is correctly open. * @throws IOException if an error is encountered */ - public void checkConsumer() throws IOException { - if (_consumer == null) { + private void checkNotClosed() throws IOException { + if (this.closed.get()) { throw new EOFException("RpcClient is closed"); } } @@ -154,11 +155,8 @@ public void checkConsumer() throws IOException { */ @Override public void close() throws IOException { - if (_consumer != null) { - final String consumerTag = _consumer.getConsumerTag(); - // set it null before calling basicCancel to make this method idempotent in case of IOException - _consumer = null; - _channel.basicCancel(consumerTag); + if (this.closed.compareAndSet(false, true)) { + _channel.basicCancel(_consumer.getConsumerTag()); } } @@ -176,7 +174,7 @@ public void handleShutdownSignal(String consumerTag, for (Entry> entry : _continuationMap.entrySet()) { entry.getValue().set(signal); } - _consumer = null; + closed.set(true); } } @@ -184,8 +182,7 @@ public void handleShutdownSignal(String consumerTag, public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, - byte[] body) - throws IOException { + byte[] body) { synchronized (_continuationMap) { String replyId = properties.getCorrelationId(); BlockingCell blocker =_continuationMap.remove(replyId); @@ -216,7 +213,7 @@ public Response doCall(AMQP.BasicProperties props, byte[] message) public Response doCall(AMQP.BasicProperties props, byte[] message, int timeout) throws IOException, ShutdownSignalException, TimeoutException { - checkConsumer(); + checkNotClosed(); BlockingCell k = new BlockingCell(); String replyId; synchronized (_continuationMap) { From 88a006eb96ee40a3ab27aee761d12123b48af68f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 May 2023 01:00:53 +0000 Subject: [PATCH 1718/2114] Bump jackson-databind from 2.15.0 to 2.15.1 Bumps [jackson-databind](https://github.com/FasterXML/jackson) from 2.15.0 to 2.15.1. - [Commits](https://github.com/FasterXML/jackson/commits) --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-databind dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 663a5e06de..67b6bb685f 100644 --- a/pom.xml +++ b/pom.xml @@ -58,7 +58,7 @@ 4.2.18 1.11.0 1.26.0 - 2.15.0 + 2.15.1 1.2.12 5.9.3 5.3.1 From 8f9bdb40de1b6d6340378355971625f482f68e2f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 19 May 2023 01:01:39 +0000 Subject: [PATCH 1719/2114] Bump maven-bundle-plugin from 5.1.8 to 5.1.9 Bumps maven-bundle-plugin from 5.1.8 to 5.1.9. --- updated-dependencies: - dependency-name: org.apache.felix:maven-bundle-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 67b6bb685f..d7241b8098 100644 --- a/pom.xml +++ b/pom.xml @@ -82,7 +82,7 @@ 3.1.0 3.1.0 3.3.0 - 5.1.8 + 5.1.9 0.0.6 1.6.13 1.11 From 8ea72545931d585b565d70e18b32f7f22b24b147 Mon Sep 17 00:00:00 2001 From: Ennio Kerber <> Date: Sat, 20 May 2023 23:40:45 +0200 Subject: [PATCH 1720/2114] feat(ConnectionFactory): Change setters to fluent API for easier configuration --- .../rabbitmq/client/ConnectionFactory.java | 159 ++++++++++++------ .../client/test/ConnectionFactoryTest.java | 115 ++++++++++++- .../test/PropertyFileInitialisationTest.java | 4 +- 3 files changed, 218 insertions(+), 60 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index c140c0bdeb..4fe7c9c57c 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -25,8 +25,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.Map.Entry; -import java.util.function.BiConsumer; import javax.net.SocketFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; @@ -38,7 +36,9 @@ import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.util.*; +import java.util.Map.Entry; import java.util.concurrent.*; +import java.util.function.BiConsumer; import java.util.function.Predicate; import static java.util.concurrent.TimeUnit.MINUTES; @@ -209,8 +209,9 @@ public String getHost() { } /** @param host the default host to use for connections */ - public void setHost(String host) { + public ConnectionFactory setHost(String host) { this.host = host; + return this; } public static int portOrDefault(int port, boolean ssl) { @@ -228,8 +229,9 @@ public int getPort() { * Set the target port. * @param port the default port to use for connections */ - public void setPort(int port) { + public ConnectionFactory setPort(int port) { this.port = port; + return this; } /** @@ -244,11 +246,12 @@ public String getUsername() { * Set the user name. * @param username the AMQP user name to use when connecting to the broker */ - public void setUsername(String username) { + public ConnectionFactory setUsername(String username) { this.credentialsProvider = new DefaultCredentialsProvider( username, this.credentialsProvider.getPassword() ); + return this; } /** @@ -263,11 +266,12 @@ public String getPassword() { * Set the password. * @param password the password to use when connecting to the broker */ - public void setPassword(String password) { + public ConnectionFactory setPassword(String password) { this.credentialsProvider = new DefaultCredentialsProvider( this.credentialsProvider.getUsername(), password ); + return this; } /** @@ -277,8 +281,9 @@ public void setPassword(String password) { * @see com.rabbitmq.client.impl.DefaultCredentialsProvider * @since 4.5.0 */ - public void setCredentialsProvider(CredentialsProvider credentialsProvider) { + public ConnectionFactory setCredentialsProvider(CredentialsProvider credentialsProvider) { this.credentialsProvider = credentialsProvider; + return this; } /** @@ -293,8 +298,9 @@ public String getVirtualHost() { * Set the virtual host. * @param virtualHost the virtual host to use when connecting to the broker */ - public void setVirtualHost(String virtualHost) { + public ConnectionFactory setVirtualHost(String virtualHost) { this.virtualHost = virtualHost; + return this; } @@ -305,7 +311,7 @@ public void setVirtualHost(String virtualHost) { * is left unchanged. * @param uri is the AMQP URI containing the data */ - public void setUri(URI uri) + public ConnectionFactory setUri(URI uri) throws URISyntaxException, NoSuchAlgorithmException, KeyManagementException { if ("amqp".equals(uri.getScheme().toLowerCase())) { @@ -360,6 +366,7 @@ public void setUri(URI uri) if (rawQuery != null && rawQuery.length() > 0) { setQuery(rawQuery); } + return this; } /** @@ -372,10 +379,11 @@ public void setUri(URI uri) * hostname are not permitted. * @param uriString is the AMQP URI containing the data */ - public void setUri(String uriString) + public ConnectionFactory setUri(String uriString) throws URISyntaxException, NoSuchAlgorithmException, KeyManagementException { setUri(new URI(uriString)); + return this; } private static String uriDecode(String s) { @@ -426,7 +434,7 @@ private static String uriDecode(String s) { * https://www.rabbitmq.com/uri-query-parameters.html * @param rawQuery is the string containing the raw query parameters part from a URI */ - private void setQuery(String rawQuery) { + private ConnectionFactory setQuery(String rawQuery) { Map parameters = new HashMap<>(); // parsing the query parameters try { @@ -452,6 +460,7 @@ private void setQuery(String rawQuery) { processUriQueryParameter(entry.getKey(), entry.getValue()); } } + return this; } /** @@ -480,11 +489,12 @@ public int getRequestedChannelMax() { * * @param requestedChannelMax initially requested maximum channel number; zero for unlimited */ - public void setRequestedChannelMax(int requestedChannelMax) { + public ConnectionFactory setRequestedChannelMax(int requestedChannelMax) { if (requestedChannelMax < 0 || requestedChannelMax > MAX_UNSIGNED_SHORT) { throw new IllegalArgumentException("Requested channel max must be between 0 and " + MAX_UNSIGNED_SHORT); } this.requestedChannelMax = requestedChannelMax; + return this; } /** @@ -499,8 +509,9 @@ public int getRequestedFrameMax() { * Set the requested maximum frame size * @param requestedFrameMax initially requested maximum frame size, in octets; zero for unlimited */ - public void setRequestedFrameMax(int requestedFrameMax) { + public ConnectionFactory setRequestedFrameMax(int requestedFrameMax) { this.requestedFrameMax = requestedFrameMax; + return this; } /** @@ -515,11 +526,12 @@ public int getRequestedHeartbeat() { * Set the TCP connection timeout. * @param timeout connection TCP establishment timeout in milliseconds; zero for infinite */ - public void setConnectionTimeout(int timeout) { + public ConnectionFactory setConnectionTimeout(int timeout) { if(timeout < 0) { throw new IllegalArgumentException("TCP connection timeout cannot be negative"); } this.connectionTimeout = timeout; + return this; } /** @@ -542,11 +554,12 @@ public int getHandshakeTimeout() { * Set the AMQP0-9-1 protocol handshake timeout. * @param timeout the AMQP0-9-1 protocol handshake timeout, in milliseconds */ - public void setHandshakeTimeout(int timeout) { + public ConnectionFactory setHandshakeTimeout(int timeout) { if(timeout < 0) { throw new IllegalArgumentException("handshake timeout cannot be negative"); } this.handshakeTimeout = timeout; + return this; } /** @@ -557,8 +570,9 @@ public void setHandshakeTimeout(int timeout) { * the Consumer's handleShutdownSignal() invocation) will be lost. * @param shutdownTimeout shutdown timeout in milliseconds; zero for infinite; default 10000 */ - public void setShutdownTimeout(int shutdownTimeout) { + public ConnectionFactory setShutdownTimeout(int shutdownTimeout) { this.shutdownTimeout = shutdownTimeout; + return this; } /** @@ -579,11 +593,12 @@ public int getShutdownTimeout() { * @param requestedHeartbeat the initially requested heartbeat timeout, in seconds; zero for none * @see RabbitMQ Heartbeats Guide */ - public void setRequestedHeartbeat(int requestedHeartbeat) { + public ConnectionFactory setRequestedHeartbeat(int requestedHeartbeat) { if (requestedHeartbeat < 0 || requestedHeartbeat > MAX_UNSIGNED_SHORT) { throw new IllegalArgumentException("Requested heartbeat must be between 0 and " + MAX_UNSIGNED_SHORT); } this.requestedHeartbeat = requestedHeartbeat; + return this; } /** @@ -605,8 +620,9 @@ public Map getClientProperties() { * @param clientProperties the map of extra client properties * @see #getClientProperties */ - public void setClientProperties(Map clientProperties) { - _clientProperties = clientProperties; + public ConnectionFactory setClientProperties(Map clientProperties) { + this._clientProperties = clientProperties; + return this; } /** @@ -623,8 +639,9 @@ public SaslConfig getSaslConfig() { * @param saslConfig * @see com.rabbitmq.client.SaslConfig */ - public void setSaslConfig(SaslConfig saslConfig) { + public ConnectionFactory setSaslConfig(SaslConfig saslConfig) { this.saslConfig = saslConfig; + return this; } /** @@ -642,8 +659,9 @@ public SocketFactory getSocketFactory() { * NIO, as the NIO API doesn't use the SocketFactory API. * @see #useSslProtocol */ - public void setSocketFactory(SocketFactory factory) { + public ConnectionFactory setSocketFactory(SocketFactory factory) { this.socketFactory = factory; + return this; } /** @@ -662,8 +680,9 @@ public SocketConfigurator getSocketConfigurator() { * * @param socketConfigurator the configurator to use */ - public void setSocketConfigurator(SocketConfigurator socketConfigurator) { + public ConnectionFactory setSocketConfigurator(SocketConfigurator socketConfigurator) { this.socketConf = socketConfigurator; + return this; } /** @@ -677,8 +696,9 @@ public void setSocketConfigurator(SocketConfigurator socketConfigurator) { * @param executor executor service to be used for * consumer operation */ - public void setSharedExecutor(ExecutorService executor) { + public ConnectionFactory setSharedExecutor(ExecutorService executor) { this.sharedExecutor = executor; + return this; } /** @@ -691,8 +711,9 @@ public void setSharedExecutor(ExecutorService executor) { * @param executor executor service to be used for * connection shutdown */ - public void setShutdownExecutor(ExecutorService executor) { + public ConnectionFactory setShutdownExecutor(ExecutorService executor) { this.shutdownExecutor = executor; + return this; } /** @@ -704,8 +725,9 @@ public void setShutdownExecutor(ExecutorService executor) { * * @param executor executor service to be used to send heartbeat */ - public void setHeartbeatExecutor(ScheduledExecutorService executor) { + public ConnectionFactory setHeartbeatExecutor(ScheduledExecutorService executor) { this.heartbeatExecutor = executor; + return this; } /** @@ -720,8 +742,9 @@ public ThreadFactory getThreadFactory() { * Set the thread factory used to instantiate new threads. * @see ThreadFactory */ - public void setThreadFactory(ThreadFactory threadFactory) { + public ConnectionFactory setThreadFactory(ThreadFactory threadFactory) { this.threadFactory = threadFactory; + return this; } /** @@ -737,11 +760,12 @@ public ExceptionHandler getExceptionHandler() { * Set the exception handler to use for newly created connections. * @see com.rabbitmq.client.ExceptionHandler */ - public void setExceptionHandler(ExceptionHandler exceptionHandler) { + public ConnectionFactory setExceptionHandler(ExceptionHandler exceptionHandler) { if (exceptionHandler == null) { throw new IllegalArgumentException("exception handler cannot be null!"); } this.exceptionHandler = exceptionHandler; + return this; } public boolean isSSL(){ @@ -758,10 +782,10 @@ public boolean isSSL(){ * not recommended to use in production as it provides no protection * against man-in-the-middle attacks. Prefer {@link #useSslProtocol(SSLContext)}. */ - public void useSslProtocol() + public ConnectionFactory useSslProtocol() throws NoSuchAlgorithmException, KeyManagementException { - useSslProtocol(computeDefaultTlsProtocol(SSLContext.getDefault().getSupportedSSLParameters().getProtocols())); + return useSslProtocol(computeDefaultTlsProtocol(SSLContext.getDefault().getSupportedSSLParameters().getProtocols())); } /** @@ -780,10 +804,10 @@ public void useSslProtocol() * Use {@link #setSslContextFactory(SslContextFactory)} for more flexibility. * @see #setSslContextFactory(SslContextFactory) */ - public void useSslProtocol(String protocol) + public ConnectionFactory useSslProtocol(String protocol) throws NoSuchAlgorithmException, KeyManagementException { - useSslProtocol(protocol, new TrustEverythingTrustManager()); + return useSslProtocol(protocol, new TrustEverythingTrustManager()); } /** @@ -800,12 +824,12 @@ public void useSslProtocol(String protocol) * @see #setSslContextFactory(SslContextFactory) * @see #useSslProtocol(SSLContext) */ - public void useSslProtocol(String protocol, TrustManager trustManager) + public ConnectionFactory useSslProtocol(String protocol, TrustManager trustManager) throws NoSuchAlgorithmException, KeyManagementException { SSLContext c = SSLContext.getInstance(protocol); c.init(null, new TrustManager[] { trustManager }, null); - useSslProtocol(c); + return useSslProtocol(c); } /** @@ -820,9 +844,10 @@ public void useSslProtocol(String protocol, TrustManager trustManager) * @param context An initialized SSLContext * @see #setSslContextFactory(SslContextFactory) */ - public void useSslProtocol(SSLContext context) { + public ConnectionFactory useSslProtocol(SSLContext context) { this.sslContextFactory = name -> context; setSocketFactory(context.getSocketFactory()); + return this; } /** @@ -844,9 +869,10 @@ public void useSslProtocol(SSLContext context) { * @see ConnectionFactory#useSslProtocol(String, TrustManager) * @since 5.4.0 */ - public void enableHostnameVerification() { + public ConnectionFactory enableHostnameVerification() { enableHostnameVerificationForNio(); enableHostnameVerificationForBlockingIo(); + return this; } protected void enableHostnameVerificationForNio() { @@ -890,8 +916,9 @@ public boolean isAutomaticRecoveryEnabled() { * @param automaticRecovery if true, enables connection recovery * @see Automatic Recovery */ - public void setAutomaticRecoveryEnabled(boolean automaticRecovery) { + public ConnectionFactory setAutomaticRecoveryEnabled(boolean automaticRecovery) { this.automaticRecovery = automaticRecovery; + return this; } /** @@ -908,8 +935,9 @@ public boolean isTopologyRecoveryEnabled() { * @param topologyRecovery if true, enables topology recovery * @see Automatic Recovery */ - public void setTopologyRecoveryEnabled(boolean topologyRecovery) { + public ConnectionFactory setTopologyRecoveryEnabled(boolean topologyRecovery) { this.topologyRecovery = topologyRecovery; + return this; } /** @@ -929,12 +957,14 @@ public ExecutorService getTopologyRecoveryExecutor() { * @param topologyRecoveryExecutor thread pool executor * @since 4.7.0 */ - public void setTopologyRecoveryExecutor(final ExecutorService topologyRecoveryExecutor) { + public ConnectionFactory setTopologyRecoveryExecutor(final ExecutorService topologyRecoveryExecutor) { this.topologyRecoveryExecutor = topologyRecoveryExecutor; + return this; } - public void setMetricsCollector(MetricsCollector metricsCollector) { + public ConnectionFactory setMetricsCollector(MetricsCollector metricsCollector) { this.metricsCollector = metricsCollector; + return this; } public MetricsCollector getMetricsCollector() { @@ -956,8 +986,9 @@ public MetricsCollector getMetricsCollector() { * @see #setCredentialsProvider(CredentialsProvider) * @see DefaultCredentialsRefreshService */ - public void setCredentialsRefreshService(CredentialsRefreshService credentialsRefreshService) { + public ConnectionFactory setCredentialsRefreshService(CredentialsRefreshService credentialsRefreshService) { this.credentialsRefreshService = credentialsRefreshService; + return this; } protected synchronized FrameHandlerFactory createFrameHandlerFactory() throws IOException { @@ -1451,8 +1482,9 @@ public long getNetworkRecoveryInterval() { * @param networkRecoveryInterval how long will automatic recovery wait before attempting to reconnect, in ms * @see RecoveryDelayHandler */ - public void setNetworkRecoveryInterval(int networkRecoveryInterval) { + public ConnectionFactory setNetworkRecoveryInterval(int networkRecoveryInterval) { this.networkRecoveryInterval = networkRecoveryInterval; + return this; } /** @@ -1462,8 +1494,9 @@ public void setNetworkRecoveryInterval(int networkRecoveryInterval) { * @param networkRecoveryInterval how long will automatic recovery wait before attempting to reconnect, in ms * @see RecoveryDelayHandler */ - public void setNetworkRecoveryInterval(long networkRecoveryInterval) { + public ConnectionFactory setNetworkRecoveryInterval(long networkRecoveryInterval) { this.networkRecoveryInterval = networkRecoveryInterval; + return this; } /** @@ -1480,8 +1513,9 @@ public RecoveryDelayHandler getRecoveryDelayHandler() { * @param recoveryDelayHandler the recovery delay handler * @since 4.3.0 */ - public void setRecoveryDelayHandler(final RecoveryDelayHandler recoveryDelayHandler) { + public ConnectionFactory setRecoveryDelayHandler(final RecoveryDelayHandler recoveryDelayHandler) { this.recoveryDelayHandler = recoveryDelayHandler; + return this; } /** @@ -1491,8 +1525,9 @@ public void setRecoveryDelayHandler(final RecoveryDelayHandler recoveryDelayHand * @param nioParams * @see NioParams */ - public void setNioParams(NioParams nioParams) { + public ConnectionFactory setNioParams(NioParams nioParams) { this.nioParams = nioParams; + return this; } /** @@ -1519,8 +1554,9 @@ public NioParams getNioParams() { * @see java.nio.channels.SocketChannel * @see java.nio.channels.Selector */ - public void useNio() { + public ConnectionFactory useNio() { this.nio = true; + return this; } /** @@ -1528,8 +1564,9 @@ public void useNio() { * With blocking IO, each connection creates its own thread * to read data from the server. */ - public void useBlockingIo() { + public ConnectionFactory useBlockingIo() { this.nio = false; + return this; } /** @@ -1537,11 +1574,12 @@ public void useBlockingIo() { * Default is 10 minutes. 0 means no timeout. * @param channelRpcTimeout */ - public void setChannelRpcTimeout(int channelRpcTimeout) { + public ConnectionFactory setChannelRpcTimeout(int channelRpcTimeout) { if(channelRpcTimeout < 0) { throw new IllegalArgumentException("Timeout cannot be less than 0"); } this.channelRpcTimeout = channelRpcTimeout; + return this; } /** @@ -1564,8 +1602,9 @@ public int getChannelRpcTimeout() { * @see #useSslProtocol(SSLContext) * @since 5.0.0 */ - public void setSslContextFactory(SslContextFactory sslContextFactory) { + public ConnectionFactory setSslContextFactory(SslContextFactory sslContextFactory) { this.sslContextFactory = sslContextFactory; + return this; } /** @@ -1575,8 +1614,9 @@ public void setSslContextFactory(SslContextFactory sslContextFactory) { * Default is false. * @param channelShouldCheckRpcResponseType */ - public void setChannelShouldCheckRpcResponseType(boolean channelShouldCheckRpcResponseType) { + public ConnectionFactory setChannelShouldCheckRpcResponseType(boolean channelShouldCheckRpcResponseType) { this.channelShouldCheckRpcResponseType = channelShouldCheckRpcResponseType; + return this; } public boolean isChannelShouldCheckRpcResponseType() { @@ -1598,8 +1638,9 @@ public boolean isChannelShouldCheckRpcResponseType() { * @param workPoolTimeout timeout in ms * @since 4.5.0 */ - public void setWorkPoolTimeout(int workPoolTimeout) { + public ConnectionFactory setWorkPoolTimeout(int workPoolTimeout) { this.workPoolTimeout = workPoolTimeout; + return this; } public int getWorkPoolTimeout() { @@ -1615,8 +1656,9 @@ public int getWorkPoolTimeout() { * @param errorOnWriteListener the listener * @since 4.5.0 */ - public void setErrorOnWriteListener(ErrorOnWriteListener errorOnWriteListener) { + public ConnectionFactory setErrorOnWriteListener(ErrorOnWriteListener errorOnWriteListener) { this.errorOnWriteListener = errorOnWriteListener; + return this; } /** @@ -1624,8 +1666,9 @@ public void setErrorOnWriteListener(ErrorOnWriteListener errorOnWriteListener) { * * @since 4.8.0 */ - public void setTopologyRecoveryFilter(TopologyRecoveryFilter topologyRecoveryFilter) { + public ConnectionFactory setTopologyRecoveryFilter(TopologyRecoveryFilter topologyRecoveryFilter) { this.topologyRecoveryFilter = topologyRecoveryFilter; + return this; } /** @@ -1634,8 +1677,9 @@ public void setTopologyRecoveryFilter(TopologyRecoveryFilter topologyRecoveryFil * * @param connectionRecoveryTriggeringCondition */ - public void setConnectionRecoveryTriggeringCondition(Predicate connectionRecoveryTriggeringCondition) { + public ConnectionFactory setConnectionRecoveryTriggeringCondition(Predicate connectionRecoveryTriggeringCondition) { this.connectionRecoveryTriggeringCondition = connectionRecoveryTriggeringCondition; + return this; } /** @@ -1645,8 +1689,9 @@ public void setConnectionRecoveryTriggeringCondition(Predicate call, boolean expectException) { } + @Test + public void shouldBeConfigurableUsingFluentAPI() throws Exception { + /* GIVEN */ + Map clientProperties = Map.of(); + SaslConfig saslConfig = mock(SaslConfig.class); + ConnectionFactory connectionFactory = new ConnectionFactory(); + SocketFactory socketFactory = mock(SocketFactory.class); + SocketConfigurator socketConfigurator = mock(SocketConfigurator.class); + ExecutorService executorService = mock(ExecutorService.class); + ScheduledExecutorService scheduledExecutorService = mock(ScheduledExecutorService.class); + ThreadFactory threadFactory = mock(ThreadFactory.class); + ExceptionHandler exceptionHandler = mock(ExceptionHandler.class); + MetricsCollector metricsCollector = mock(MetricsCollector.class); + CredentialsRefreshService credentialsRefreshService = mock(CredentialsRefreshService.class); + RecoveryDelayHandler recoveryDelayHandler = mock(RecoveryDelayHandler.class); + NioParams nioParams = mock(NioParams.class); + SslContextFactory sslContextFactory = mock(SslContextFactory.class); + TopologyRecoveryFilter topologyRecoveryFilter = mock(TopologyRecoveryFilter.class); + Predicate connectionRecoveryTriggeringCondition = (ShutdownSignalException) -> true; + RetryHandler retryHandler = mock(RetryHandler.class); + RecoveredQueueNameSupplier recoveredQueueNameSupplier = mock(RecoveredQueueNameSupplier.class); + + /* WHEN */ + connectionFactory + .setHost("rabbitmq") + .setPort(5672) + .setUsername("guest") + .setPassword("guest") + .setVirtualHost("/") + .setRequestedChannelMax(1) + .setRequestedFrameMax(2) + .setRequestedHeartbeat(3) + .setConnectionTimeout(4) + .setHandshakeTimeout(5) + .setShutdownTimeout(6) + .setClientProperties(clientProperties) + .setSaslConfig(saslConfig) + .setSocketFactory(socketFactory) + .setSocketConfigurator(socketConfigurator) + .setSharedExecutor(executorService) + .setShutdownExecutor(executorService) + .setHeartbeatExecutor(scheduledExecutorService) + .setThreadFactory(threadFactory) + .setExceptionHandler(exceptionHandler) + .setAutomaticRecoveryEnabled(true) + .setTopologyRecoveryEnabled(true) + .setTopologyRecoveryExecutor(executorService) + .setMetricsCollector(metricsCollector) + .setCredentialsRefreshService(credentialsRefreshService) + .setNetworkRecoveryInterval(7) + .setRecoveryDelayHandler(recoveryDelayHandler) + .setNioParams(nioParams) + .useNio() + .useBlockingIo() + .setChannelRpcTimeout(8) + .setSslContextFactory(sslContextFactory) + .setChannelShouldCheckRpcResponseType(true) + .setWorkPoolTimeout(9) + .setTopologyRecoveryFilter(topologyRecoveryFilter) + .setConnectionRecoveryTriggeringCondition(connectionRecoveryTriggeringCondition) + .setTopologyRecoveryRetryHandler(retryHandler) + .setRecoveredQueueNameSupplier(recoveredQueueNameSupplier); + + /* THEN */ + assertThat(connectionFactory.getHost()).isEqualTo("rabbitmq"); + assertThat(connectionFactory.getPort()).isEqualTo(5672); + assertThat(connectionFactory.getUsername()).isEqualTo("guest"); + assertThat(connectionFactory.getPassword()).isEqualTo("guest"); + assertThat(connectionFactory.getVirtualHost()).isEqualTo("/"); + assertThat(connectionFactory.getRequestedChannelMax()).isEqualTo(1); + assertThat(connectionFactory.getRequestedFrameMax()).isEqualTo(2); + assertThat(connectionFactory.getRequestedHeartbeat()).isEqualTo(3); + assertThat(connectionFactory.getConnectionTimeout()).isEqualTo(4); + assertThat(connectionFactory.getHandshakeTimeout()).isEqualTo(5); + assertThat(connectionFactory.getShutdownTimeout()).isEqualTo(6); + assertThat(connectionFactory.getClientProperties()).isEqualTo(clientProperties); + assertThat(connectionFactory.getSaslConfig()).isEqualTo(saslConfig); + assertThat(connectionFactory.getSocketFactory()).isEqualTo(socketFactory); + assertThat(connectionFactory.getSocketConfigurator()).isEqualTo(socketConfigurator); + assertThat(connectionFactory.isAutomaticRecoveryEnabled()).isEqualTo(true); + assertThat(connectionFactory.isTopologyRecoveryEnabled()).isEqualTo(true); + assertThat(connectionFactory.getMetricsCollector()).isEqualTo(metricsCollector); + assertThat(connectionFactory.getNetworkRecoveryInterval()).isEqualTo(7); + assertThat(connectionFactory.getRecoveryDelayHandler()).isEqualTo(recoveryDelayHandler); + assertThat(connectionFactory.getNioParams()).isEqualTo(nioParams); + assertThat(connectionFactory.getChannelRpcTimeout()).isEqualTo(8); + assertThat(connectionFactory.isChannelShouldCheckRpcResponseType()).isEqualTo(true); + assertThat(connectionFactory.getWorkPoolTimeout()).isEqualTo(9); + assertThat(connectionFactory.isSSL()).isEqualTo(true); + + /* Now test cross-cutting setters that override properties set by other setters */ + CredentialsProvider credentialsProvider = mock(CredentialsProvider.class); + when(credentialsProvider.getUsername()).thenReturn("admin"); + when(credentialsProvider.getPassword()).thenReturn("admin"); + connectionFactory + .setCredentialsProvider(credentialsProvider) + .setUri("amqp://host:5671") + .useSslProtocol("TLSv1.2"); + assertThat(connectionFactory.getHost()).isEqualTo("host"); + assertThat(connectionFactory.getPort()).isEqualTo(5671); + assertThat(connectionFactory.getUsername()).isEqualTo("admin"); + assertThat(connectionFactory.getPassword()).isEqualTo("admin"); + assertThat(connectionFactory.isSSL()).isEqualTo(true); + } + } diff --git a/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java b/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java index 24d3f808d8..d0d52ab556 100644 --- a/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java +++ b/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java @@ -205,9 +205,9 @@ public void tlsSslContextSetIfTlsEnabled() { AtomicBoolean sslProtocolSet = new AtomicBoolean(false); ConnectionFactory connectionFactory = new ConnectionFactory() { @Override - public void useSslProtocol(SSLContext context) { + public ConnectionFactory useSslProtocol(SSLContext context) { sslProtocolSet.set(true); - super.useSslProtocol(context); + return super.useSslProtocol(context); } }; ConnectionFactoryConfigurator.load( From ca3a42a5e866fdba8f38eabae2c423a19378189e Mon Sep 17 00:00:00 2001 From: Ennio Kerber <> Date: Sun, 21 May 2023 00:03:59 +0200 Subject: [PATCH 1721/2114] test(ConnectionFactory): Update several existing tests to use the new fluent API to configure ConnectionFactory instances --- .../client/test/ConnectionFactoryTest.java | 3 +- .../com/rabbitmq/client/test/JavaNioTest.java | 62 ++++++++-------- .../client/test/SslContextFactoryTest.java | 72 ++++++++----------- 3 files changed, 63 insertions(+), 74 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java b/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java index 03ff074b66..276b480132 100644 --- a/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java +++ b/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java @@ -25,6 +25,7 @@ import javax.net.SocketFactory; import java.io.IOException; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Queue; @@ -203,7 +204,7 @@ public TestConfig(int value, Consumer call, boolean expectException) { @Test public void shouldBeConfigurableUsingFluentAPI() throws Exception { /* GIVEN */ - Map clientProperties = Map.of(); + Map clientProperties = new HashMap<>(); SaslConfig saslConfig = mock(SaslConfig.class); ConnectionFactory connectionFactory = new ConnectionFactory(); SocketFactory socketFactory = mock(SocketFactory.class); diff --git a/src/test/java/com/rabbitmq/client/test/JavaNioTest.java b/src/test/java/com/rabbitmq/client/test/JavaNioTest.java index 925c31ed55..cdc095e40c 100644 --- a/src/test/java/com/rabbitmq/client/test/JavaNioTest.java +++ b/src/test/java/com/rabbitmq/client/test/JavaNioTest.java @@ -30,8 +30,8 @@ public class JavaNioTest { @BeforeEach public void init() throws Exception { - ConnectionFactory connectionFactory = new ConnectionFactory(); - connectionFactory.useNio(); + ConnectionFactory connectionFactory = new ConnectionFactory() + .useNio(); testConnection = connectionFactory.newConnection(); } @@ -46,8 +46,8 @@ public void tearDown() throws Exception { @Test public void connection() throws Exception { CountDownLatch latch = new CountDownLatch(1); - ConnectionFactory connectionFactory = new ConnectionFactory(); - connectionFactory.useNio(); + ConnectionFactory connectionFactory = new ConnectionFactory() + .useNio(); Connection connection = null; try { connection = basicGetBasicConsume(connectionFactory, "nio.queue", latch); @@ -61,9 +61,9 @@ public void connection() throws Exception { @Test public void twoConnections() throws IOException, TimeoutException, InterruptedException { CountDownLatch latch = new CountDownLatch(2); - ConnectionFactory connectionFactory = new ConnectionFactory(); - connectionFactory.useNio(); - connectionFactory.setNioParams(new NioParams().setNbIoThreads(4)); + ConnectionFactory connectionFactory = new ConnectionFactory() + .useNio() + .setNioParams(new NioParams().setNbIoThreads(4)); Connection connection1 = null; Connection connection2 = null; try { @@ -82,8 +82,8 @@ public void twoConnections() throws IOException, TimeoutException, InterruptedEx public void twoConnectionsWithNioExecutor() throws IOException, TimeoutException, InterruptedException { CountDownLatch latch = new CountDownLatch(2); ExecutorService nioExecutor = Executors.newFixedThreadPool(5); - ConnectionFactory connectionFactory = new ConnectionFactory(); - connectionFactory.useNio(); + ConnectionFactory connectionFactory = new ConnectionFactory() + .useNio(); Connection connection1 = null; Connection connection2 = null; try { @@ -101,8 +101,8 @@ public void twoConnectionsWithNioExecutor() throws IOException, TimeoutException @Test public void shutdownListenerCalled() throws IOException, TimeoutException, InterruptedException { - ConnectionFactory connectionFactory = new ConnectionFactory(); - connectionFactory.useNio(); + ConnectionFactory connectionFactory = new ConnectionFactory() + .useNio(); Connection connection = connectionFactory.newConnection(); try { final CountDownLatch latch = new CountDownLatch(1); @@ -122,8 +122,8 @@ public void shutdownCompleted(ShutdownSignalException cause) { @Test public void nioLoopCleaning() throws Exception { - ConnectionFactory connectionFactory = new ConnectionFactory(); - connectionFactory.useNio(); + ConnectionFactory connectionFactory = new ConnectionFactory() + .useNio(); for (int i = 0; i < 10; i++) { Connection connection = connectionFactory.newConnection(); connection.abort(); @@ -139,20 +139,20 @@ public void messageSize() throws Exception { @Test public void byteBufferFactory() throws Exception { - ConnectionFactory cf = new ConnectionFactory(); - cf.useNio(); + ConnectionFactory connectionFactory = new ConnectionFactory() + .useNio(); int baseCapacity = 32768; NioParams nioParams = new NioParams(); nioParams.setReadByteBufferSize(baseCapacity / 2); nioParams.setWriteByteBufferSize(baseCapacity / 4); List byteBuffers = new CopyOnWriteArrayList<>(); - cf.setNioParams(nioParams.setByteBufferFactory(new DefaultByteBufferFactory(capacity -> { + connectionFactory.setNioParams(nioParams.setByteBufferFactory(new DefaultByteBufferFactory(capacity -> { ByteBuffer bb = ByteBuffer.allocate(capacity); byteBuffers.add(bb); return bb; }))); - try (Connection c = cf.newConnection()) { + try (Connection c = connectionFactory.newConnection()) { sendAndVerifyMessage(c, 100); } @@ -165,27 +165,27 @@ public void byteBufferFactory() throws Exception { @Test public void directByteBuffers() throws Exception { - ConnectionFactory cf = new ConnectionFactory(); - cf.useNio(); - cf.setNioParams(new NioParams().setByteBufferFactory(new DefaultByteBufferFactory(capacity -> ByteBuffer.allocateDirect(capacity)))); - try (Connection c = cf.newConnection()) { + ConnectionFactory connectionFactory = new ConnectionFactory() + .useNio() + .setNioParams(new NioParams().setByteBufferFactory(new DefaultByteBufferFactory(capacity -> ByteBuffer.allocateDirect(capacity)))); + try (Connection c = connectionFactory.newConnection()) { sendAndVerifyMessage(c, 100); } } @Test public void customWriteQueue() throws Exception { - ConnectionFactory cf = new ConnectionFactory(); - cf.useNio(); AtomicInteger count = new AtomicInteger(0); - cf.setNioParams(new NioParams().setWriteQueueFactory(ctx -> { - count.incrementAndGet(); - return new BlockingQueueNioQueue( - new LinkedBlockingQueue<>(ctx.getNioParams().getWriteQueueCapacity()), - ctx.getNioParams().getWriteEnqueuingTimeoutInMs() - ); - })); - try (Connection c = cf.newConnection()) { + ConnectionFactory connectionFactory = new ConnectionFactory() + .useNio() + .setNioParams(new NioParams().setWriteQueueFactory(ctx -> { + count.incrementAndGet(); + return new BlockingQueueNioQueue( + new LinkedBlockingQueue<>(ctx.getNioParams().getWriteQueueCapacity()), + ctx.getNioParams().getWriteEnqueuingTimeoutInMs() + ); + })); + try (Connection c = connectionFactory.newConnection()) { sendAndVerifyMessage(c, 100); } assertEquals(1, count.get()); diff --git a/src/test/java/com/rabbitmq/client/test/SslContextFactoryTest.java b/src/test/java/com/rabbitmq/client/test/SslContextFactoryTest.java index 69a3eee1e8..af4e206977 100644 --- a/src/test/java/com/rabbitmq/client/test/SslContextFactoryTest.java +++ b/src/test/java/com/rabbitmq/client/test/SslContextFactoryTest.java @@ -40,30 +40,22 @@ public class SslContextFactoryTest { @Test public void setSslContextFactory() throws Exception { - doTestSetSslContextFactory(() -> { - ConnectionFactory connectionFactory = new ConnectionFactory(); - connectionFactory.useBlockingIo(); - connectionFactory.setAutomaticRecoveryEnabled(true); - return connectionFactory; - }); - doTestSetSslContextFactory(() -> { - ConnectionFactory connectionFactory = new ConnectionFactory(); - connectionFactory.useNio(); - connectionFactory.setAutomaticRecoveryEnabled(true); - return connectionFactory; - }); - doTestSetSslContextFactory(() -> { - ConnectionFactory connectionFactory = new ConnectionFactory(); - connectionFactory.useBlockingIo(); - connectionFactory.setAutomaticRecoveryEnabled(false); - return connectionFactory; - }); - doTestSetSslContextFactory(() -> { - ConnectionFactory connectionFactory = new ConnectionFactory(); - connectionFactory.useNio(); - connectionFactory.setAutomaticRecoveryEnabled(false); - return connectionFactory; - }); + doTestSetSslContextFactory(() -> new ConnectionFactory() + .useBlockingIo() + .setAutomaticRecoveryEnabled(true) + ); + doTestSetSslContextFactory(() -> new ConnectionFactory() + .useNio() + .setAutomaticRecoveryEnabled(true) + ); + doTestSetSslContextFactory(() -> new ConnectionFactory() + .useBlockingIo() + .setAutomaticRecoveryEnabled(false) + ); + doTestSetSslContextFactory(() -> new ConnectionFactory() + .useNio() + .setAutomaticRecoveryEnabled(false) + ); } private void doTestSetSslContextFactory(Supplier supplier) throws Exception { @@ -82,31 +74,27 @@ private void doTestSetSslContextFactory(Supplier supplier) th } @Test public void socketFactoryTakesPrecedenceOverSslContextFactoryWithBlockingIo() throws Exception { - doTestSocketFactoryTakesPrecedenceOverSslContextFactoryWithBlockingIo(() -> { - ConnectionFactory connectionFactory = new ConnectionFactory(); - connectionFactory.useBlockingIo(); - connectionFactory.setAutomaticRecoveryEnabled(true); - return connectionFactory; - }); - doTestSocketFactoryTakesPrecedenceOverSslContextFactoryWithBlockingIo(() -> { - ConnectionFactory connectionFactory = new ConnectionFactory(); - connectionFactory.useBlockingIo(); - connectionFactory.setAutomaticRecoveryEnabled(false); - return connectionFactory; - }); + doTestSocketFactoryTakesPrecedenceOverSslContextFactoryWithBlockingIo(() -> new ConnectionFactory() + .useBlockingIo() + .setAutomaticRecoveryEnabled(true) + ); + doTestSocketFactoryTakesPrecedenceOverSslContextFactoryWithBlockingIo(() -> new ConnectionFactory() + .useBlockingIo() + .setAutomaticRecoveryEnabled(false) + ); } private void doTestSocketFactoryTakesPrecedenceOverSslContextFactoryWithBlockingIo( Supplier supplier ) throws Exception { - ConnectionFactory connectionFactory = supplier.get(); - connectionFactory.useBlockingIo(); SslContextFactory sslContextFactory = sslContextFactory(); - connectionFactory.setSslContextFactory(sslContextFactory); - SSLContext contextAcceptAll = sslContextFactory.create("connection01"); - connectionFactory.setSocketFactory(contextAcceptAll.getSocketFactory()); - + ConnectionFactory connectionFactory = supplier.get(); + connectionFactory + .useBlockingIo() + .setSslContextFactory(sslContextFactory) + .setSocketFactory(contextAcceptAll.getSocketFactory()); + Connection connection = connectionFactory.newConnection("connection01"); TestUtils.close(connection); connection = connectionFactory.newConnection("connection02"); From c3fc4163eeef26f8c3a3b65e491a5824270ea500 Mon Sep 17 00:00:00 2001 From: Ennio Kerber <> Date: Sun, 21 May 2023 16:51:32 +0200 Subject: [PATCH 1722/2114] feat(Channel): Remove checked exception from interface Channel.abort(...) as it should silently discard any exceptions --- .../java/com/rabbitmq/client/Channel.java | 4 +- .../com/rabbitmq/client/impl/ChannelN.java | 8 +--- .../impl/recovery/AutorecoveringChannel.java | 34 +++++++------ .../recovery/AutorecoveringChannelTest.java | 48 +++++++++++++++++++ 4 files changed, 71 insertions(+), 23 deletions(-) create mode 100644 src/test/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannelTest.java diff --git a/src/main/java/com/rabbitmq/client/Channel.java b/src/main/java/com/rabbitmq/client/Channel.java index 5ab9123c12..6e72cb2fd9 100644 --- a/src/main/java/com/rabbitmq/client/Channel.java +++ b/src/main/java/com/rabbitmq/client/Channel.java @@ -89,7 +89,7 @@ public interface Channel extends ShutdownNotifier, AutoCloseable { * Forces the channel to close and waits for the close operation to complete. * Any encountered exceptions in the close operation are silently discarded. */ - void abort() throws IOException; + void abort(); /** * Abort this channel. @@ -97,7 +97,7 @@ public interface Channel extends ShutdownNotifier, AutoCloseable { * Forces the channel to close and waits for the close operation to complete. * Any encountered exceptions in the close operation are silently discarded. */ - void abort(int closeCode, String closeMessage) throws IOException; + void abort(int closeCode, String closeMessage); /** * Add a {@link ReturnListener}. diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java index 428224a4bc..b922b53da0 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelN.java @@ -545,7 +545,6 @@ public void close(int closeCode, String closeMessage) /** Public API - {@inheritDoc} */ @Override public void abort() - throws IOException { abort(AMQP.REPLY_SUCCESS, "OK"); } @@ -553,14 +552,11 @@ public void abort() /** Public API - {@inheritDoc} */ @Override public void abort(int closeCode, String closeMessage) - throws IOException { try { close(closeCode, closeMessage, true, null, true); - } catch (IOException _e) { - /* ignored */ - } catch (TimeoutException _e) { - /* ignored */ + } catch (IOException | TimeoutException _e) { + // abort() shall silently discard any exceptions } } diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java index cfba283dd2..0771e21fbb 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java @@ -80,31 +80,35 @@ public void close(int closeCode, String closeMessage) throws IOException, Timeou } @Override - public void abort() throws IOException { - try { - executeAndClean(() -> delegate.abort()); - } catch (TimeoutException e) { - // abort() ignores exceptions - } + public void abort() { + this.delegate.abort(); + this.clean(); } @Override - public void abort(int closeCode, String closeMessage) throws IOException { - try { - executeAndClean(() -> delegate.abort(closeCode, closeMessage)); - } catch (TimeoutException e) { - // abort() ignores exceptions + public void abort(int closeCode, String closeMessage) { + this.delegate.abort(closeCode, closeMessage != null ? closeMessage : ""); + this.clean(); + } + + /** + * Cleans up the channel in the following way: + *

+ * Removes every recorded consumer of the channel and finally unregisters the channel from + * the underlying connection to not process any further traffic. + */ + private void clean() { + for (String consumerTag : Utility.copy(consumerTags)) { + this.deleteRecordedConsumer(consumerTag); } + this.connection.unregisterChannel(this); } private void executeAndClean(IoTimeoutExceptionRunnable callback) throws IOException, TimeoutException { try { callback.run(); } finally { - for (String consumerTag : Utility.copy(consumerTags)) { - this.deleteRecordedConsumer(consumerTag); - } - this.connection.unregisterChannel(this); + this.clean(); } } diff --git a/src/test/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannelTest.java b/src/test/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannelTest.java new file mode 100644 index 0000000000..bd72f31e47 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannelTest.java @@ -0,0 +1,48 @@ +package com.rabbitmq.client.impl.recovery; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +public final class AutorecoveringChannelTest { + + private AutorecoveringChannel channel; + + @Mock + private AutorecoveringConnection autorecoveringConnection; + + @Mock + private RecoveryAwareChannelN recoveryAwareChannelN; + + @BeforeEach + void setup() { + MockitoAnnotations.openMocks(this); + this.channel = new AutorecoveringChannel(autorecoveringConnection, recoveryAwareChannelN); + } + + @Test + void abort() { + this.channel.abort(); + verify(recoveryAwareChannelN, times(1)).abort(); + } + + @Test + void abortWithDetails() { + int closeCode = 1; + String closeMessage = "reason"; + this.channel.abort(closeCode, closeMessage); + verify(recoveryAwareChannelN, times(1)).abort(closeCode, closeMessage); + } + + @Test + void abortWithDetailsCloseMessageNull() { + int closeCode = 1; + this.channel.abort(closeCode, null); + verify(recoveryAwareChannelN, times(1)).abort(closeCode, ""); + } + +} From 86ead969863ac026bdeff2846f5046a139b68238 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 May 2023 01:33:20 +0000 Subject: [PATCH 1723/2114] Bump maven-source-plugin from 3.2.1 to 3.3.0 Bumps [maven-source-plugin](https://github.com/apache/maven-source-plugin) from 3.2.1 to 3.3.0. - [Commits](https://github.com/apache/maven-source-plugin/compare/maven-source-plugin-3.2.1...maven-source-plugin-3.3.0) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-source-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d7241b8098..eac0aeb8b7 100644 --- a/pom.xml +++ b/pom.xml @@ -72,7 +72,7 @@ 3.0.0 2.15.0 3.3.1 - 3.2.1 + 3.3.0 2.1.1 2.4.21 1.7 From 70466dd7f493423eaea166e98b14e9d636dd1015 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 31 May 2023 01:01:54 +0000 Subject: [PATCH 1724/2114] Bump jackson-databind from 2.15.1 to 2.15.2 Bumps [jackson-databind](https://github.com/FasterXML/jackson) from 2.15.1 to 2.15.2. - [Commits](https://github.com/FasterXML/jackson/commits) --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-databind dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index eac0aeb8b7..98f1604d4d 100644 --- a/pom.xml +++ b/pom.xml @@ -58,7 +58,7 @@ 4.2.18 1.11.0 1.26.0 - 2.15.1 + 2.15.2 1.2.12 5.9.3 5.3.1 From c6cc7ac1197c74c4331c2e996735a0d3437ba455 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 2 Jun 2023 01:00:32 +0000 Subject: [PATCH 1725/2114] Bump metrics-core from 4.2.18 to 4.2.19 Bumps [metrics-core](https://github.com/dropwizard/metrics) from 4.2.18 to 4.2.19. - [Release notes](https://github.com/dropwizard/metrics/releases) - [Commits](https://github.com/dropwizard/metrics/compare/v4.2.18...v4.2.19) --- updated-dependencies: - dependency-name: io.dropwizard.metrics:metrics-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 98f1604d4d..20691a1bc8 100644 --- a/pom.xml +++ b/pom.xml @@ -55,7 +55,7 @@ UTF-8 1.7.36 - 4.2.18 + 4.2.19 1.11.0 1.26.0 2.15.2 From 472f77d7190798dc2705068fc2d45c05cdaf6904 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 Jun 2023 01:27:39 +0000 Subject: [PATCH 1726/2114] Bump maven-release-plugin from 3.0.0 to 3.0.1 Bumps [maven-release-plugin](https://github.com/apache/maven-release) from 3.0.0 to 3.0.1. - [Release notes](https://github.com/apache/maven-release/releases) - [Commits](https://github.com/apache/maven-release/compare/maven-release-3.0.0...maven-release-3.0.1) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-release-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 20691a1bc8..52e1d9d61f 100644 --- a/pom.xml +++ b/pom.xml @@ -69,7 +69,7 @@ 2.10.1 3.5.0 - 3.0.0 + 3.0.1 2.15.0 3.3.1 3.3.0 From 00ad6eb4fc32edb21ee8d55ea5f7743623af762b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 5 Jun 2023 14:54:26 +0200 Subject: [PATCH 1727/2114] Use RabbitMQ 3.12 in CI --- .github/workflows/test-native-image.yml | 3 --- .github/workflows/test-rabbitmq-alphas.yml | 2 +- .github/workflows/test-supported-java-versions-5.x.yml | 3 --- .github/workflows/test-supported-java-versions-main.yml | 3 --- .github/workflows/test.yml | 5 +---- ci/start-broker.sh | 2 +- ci/start-cluster.sh | 2 +- 7 files changed, 4 insertions(+), 16 deletions(-) diff --git a/.github/workflows/test-native-image.yml b/.github/workflows/test-native-image.yml index e92fe19b11..3d43fab487 100644 --- a/.github/workflows/test-native-image.yml +++ b/.github/workflows/test-native-image.yml @@ -5,9 +5,6 @@ on: - cron: '0 4 ? * SUN,THU' workflow_dispatch: -env: - RABBITMQ_IMAGE: 'rabbitmq:3.11' - jobs: build: runs-on: ubuntu-22.04 diff --git a/.github/workflows/test-rabbitmq-alphas.yml b/.github/workflows/test-rabbitmq-alphas.yml index 05688d479a..d589bf4809 100644 --- a/.github/workflows/test-rabbitmq-alphas.yml +++ b/.github/workflows/test-rabbitmq-alphas.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-22.04 strategy: matrix: - rabbitmq-image: [ 'pivotalrabbitmq/rabbitmq:v3.11.x-otp-max-bazel', 'pivotalrabbitmq/rabbitmq:v3.12.x-otp-max-bazel' ] + rabbitmq-image: [ 'pivotalrabbitmq/rabbitmq:v3.12.x-otp-max-bazel', 'pivotalrabbitmq/rabbitmq:main-otp-max-bazel' ] name: Test against ${{ matrix.rabbitmq-image }} steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/test-supported-java-versions-5.x.yml b/.github/workflows/test-supported-java-versions-5.x.yml index d99378e3ab..487cbad97f 100644 --- a/.github/workflows/test-supported-java-versions-5.x.yml +++ b/.github/workflows/test-supported-java-versions-5.x.yml @@ -5,9 +5,6 @@ on: - cron: '0 4 ? * SUN,THU' workflow_dispatch: -env: - RABBITMQ_IMAGE: 'rabbitmq:3.11' - jobs: build: runs-on: ubuntu-22.04 diff --git a/.github/workflows/test-supported-java-versions-main.yml b/.github/workflows/test-supported-java-versions-main.yml index e9c984af12..c3b2f78301 100644 --- a/.github/workflows/test-supported-java-versions-main.yml +++ b/.github/workflows/test-supported-java-versions-main.yml @@ -5,9 +5,6 @@ on: - cron: '0 4 ? * SUN,THU' workflow_dispatch: -env: - RABBITMQ_IMAGE: 'rabbitmq:3.11' - jobs: build: runs-on: ubuntu-22.04 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4ebf82081d..98b5d1026f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,4 +1,4 @@ -name: Test against RabbitMQ 3.11 stable +name: Test against RabbitMQ 3.12 stable on: pull_request: @@ -9,9 +9,6 @@ on: - main workflow_dispatch: -env: - RABBITMQ_IMAGE: 'rabbitmq:3.11' - jobs: build: runs-on: ubuntu-22.04 diff --git a/ci/start-broker.sh b/ci/start-broker.sh index c178e63784..8ad81bb837 100755 --- a/ci/start-broker.sh +++ b/ci/start-broker.sh @@ -2,7 +2,7 @@ LOCAL_SCRIPT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -RABBITMQ_IMAGE=${RABBITMQ_IMAGE:-rabbitmq:3.11} +RABBITMQ_IMAGE=${RABBITMQ_IMAGE:-rabbitmq:3.12} wait_for_message() { while ! docker logs "$1" | grep -q "$2"; diff --git a/ci/start-cluster.sh b/ci/start-cluster.sh index c1dbac0786..f855daaf93 100755 --- a/ci/start-cluster.sh +++ b/ci/start-cluster.sh @@ -2,7 +2,7 @@ LOCAL_SCRIPT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -RABBITMQ_IMAGE=${RABBITMQ_IMAGE:-rabbitmq:3.11} +RABBITMQ_IMAGE=${RABBITMQ_IMAGE:-rabbitmq:3.12} wait_for_message() { while ! docker logs "$1" | grep -q "$2"; From a89c2b68d1a453b04c0183667437e6a99868c024 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 7 Jun 2023 01:01:13 +0000 Subject: [PATCH 1728/2114] Bump versions-maven-plugin from 2.15.0 to 2.16.0 Bumps [versions-maven-plugin](https://github.com/mojohaus/versions) from 2.15.0 to 2.16.0. - [Release notes](https://github.com/mojohaus/versions/releases) - [Changelog](https://github.com/mojohaus/versions/blob/master/ReleaseNotes.md) - [Commits](https://github.com/mojohaus/versions/compare/2.15.0...2.16.0) --- updated-dependencies: - dependency-name: org.codehaus.mojo:versions-maven-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 52e1d9d61f..8e419b88a9 100644 --- a/pom.xml +++ b/pom.xml @@ -70,7 +70,7 @@ 3.5.0 3.0.1 - 2.15.0 + 2.16.0 3.3.1 3.3.0 2.1.1 From b5dcc074a2d779cfd0a3490fa1a7959a0bbdf969 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 7 Jun 2023 01:01:27 +0000 Subject: [PATCH 1729/2114] Bump maven-failsafe-plugin from 3.1.0 to 3.1.2 Bumps [maven-failsafe-plugin](https://github.com/apache/maven-surefire) from 3.1.0 to 3.1.2. - [Release notes](https://github.com/apache/maven-surefire/releases) - [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.1.0...surefire-3.1.2) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-failsafe-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 52e1d9d61f..3059dda615 100644 --- a/pom.xml +++ b/pom.xml @@ -79,7 +79,7 @@ 3.4.0 3.11.0 3.1.0 - 3.1.0 + 3.1.2 3.1.0 3.3.0 5.1.9 From a9e2c3258c957a1ea27a7c2b9719493b459ea162 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 7 Jun 2023 05:55:51 +0000 Subject: [PATCH 1730/2114] Bump maven-surefire-plugin from 3.1.0 to 3.1.2 Bumps [maven-surefire-plugin](https://github.com/apache/maven-surefire) from 3.1.0 to 3.1.2. - [Release notes](https://github.com/apache/maven-surefire/releases) - [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.1.0...surefire-3.1.2) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-surefire-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3059dda615..14d5083a89 100644 --- a/pom.xml +++ b/pom.xml @@ -78,7 +78,7 @@ 1.7 3.4.0 3.11.0 - 3.1.0 + 3.1.2 3.1.2 3.1.0 3.3.0 From 7253c941d96a8057c6b32f3ff45d3e1c7fac0164 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Faria?= Date: Thu, 8 Jun 2023 19:47:08 +0100 Subject: [PATCH 1731/2114] Do not confirmSelect more than once per channel In order to avoid unnecessary blocking RPC calls and conform to best practices, the Channel now checks if it is already activated confirm mode before sending a confirm.select RPC call. If confirm mode is already activated, calling confirmSelect() again returns immediately without sending an RPC call. Closes #1056 --- .../com/rabbitmq/client/impl/ChannelN.java | 11 ++++++- .../rabbitmq/client/test/ChannelNTest.java | 31 +++++++++++++++++-- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java index b922b53da0..57a15d62fe 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelN.java @@ -82,6 +82,9 @@ public class ChannelN extends AMQChannel implements com.rabbitmq.client.Channel private final SortedSet unconfirmedSet = Collections.synchronizedSortedSet(new TreeSet()); + /** Whether the confirm select method has been successfully activated */ + private boolean confirmSelectActivated = false; + /** Whether any nacks have been received since the last waitForConfirms(). */ private volatile boolean onlyAcksReceived = true; @@ -1553,10 +1556,16 @@ public Tx.RollbackOk txRollback() public Confirm.SelectOk confirmSelect() throws IOException { + if (confirmSelectActivated) { + return new Confirm.SelectOk(); + } + if (nextPublishSeqNo == 0) nextPublishSeqNo = 1; - return (Confirm.SelectOk) + Confirm.SelectOk result = (Confirm.SelectOk) exnWrappingRpc(new Confirm.Select(false)).getMethod(); + confirmSelectActivated = true; + return result; } /** Public API - {@inheritDoc} */ diff --git a/src/test/java/com/rabbitmq/client/test/ChannelNTest.java b/src/test/java/com/rabbitmq/client/test/ChannelNTest.java index 76d44c816e..461f5d712e 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelNTest.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelNTest.java @@ -15,17 +15,20 @@ package com.rabbitmq.client.test; +import com.rabbitmq.client.Command; import com.rabbitmq.client.Method; +import com.rabbitmq.client.TrafficListener; import com.rabbitmq.client.impl.*; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mockito; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; +import java.io.IOException; +import java.util.concurrent.*; import java.util.stream.Stream; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertNotNull; public class ChannelNTest { @@ -81,6 +84,30 @@ public TestConfig(int value, Consumer call) { .forEach(config -> assertThatThrownBy(() -> config.call.apply(config.value)).isInstanceOf(IllegalArgumentException.class)); } + @Test + public void confirmSelectOnlySendsRPCCallOnce() throws Exception { + AMQConnection connection = Mockito.mock(AMQConnection.class); + TrafficListener trafficListener = Mockito.mock(TrafficListener.class); + + Mockito.when(connection.getTrafficListener()).thenReturn(trafficListener); + + ChannelN channel = new ChannelN(connection, 1, consumerWorkService); + + Future future = executorService.submit(() -> { + try { + return channel.confirmSelect(); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + + channel.handleCompleteInboundCommand(new AMQCommand(new AMQImpl.Confirm.SelectOk())); + + assertNotNull(future.get(1, TimeUnit.SECONDS)); + assertNotNull(channel.confirmSelect()); + Mockito.verify(trafficListener, Mockito.times(1)).write(Mockito.any(Command.class)); + } + interface Consumer { void apply(int value) throws Exception; From f5c26a7975b22a8b73cbde98be9b8cb63c233275 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Faria?= Date: Fri, 9 Jun 2023 10:05:47 +0100 Subject: [PATCH 1732/2114] Fix flaky test --- .../com/rabbitmq/client/test/ChannelNTest.java | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/ChannelNTest.java b/src/test/java/com/rabbitmq/client/test/ChannelNTest.java index 461f5d712e..24b6d1e941 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelNTest.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelNTest.java @@ -24,8 +24,8 @@ import org.junit.jupiter.api.Test; import org.mockito.Mockito; -import java.io.IOException; -import java.util.concurrent.*; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.stream.Stream; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -93,17 +93,16 @@ public void confirmSelectOnlySendsRPCCallOnce() throws Exception { ChannelN channel = new ChannelN(connection, 1, consumerWorkService); - Future future = executorService.submit(() -> { + new Thread(() -> { try { - return channel.confirmSelect(); - } catch (IOException e) { + Thread.sleep(15); + channel.handleCompleteInboundCommand(new AMQCommand(new AMQImpl.Confirm.SelectOk())); + } catch (Exception e) { throw new RuntimeException(e); } - }); + }).start(); - channel.handleCompleteInboundCommand(new AMQCommand(new AMQImpl.Confirm.SelectOk())); - - assertNotNull(future.get(1, TimeUnit.SECONDS)); + assertNotNull(channel.confirmSelect()); assertNotNull(channel.confirmSelect()); Mockito.verify(trafficListener, Mockito.times(1)).write(Mockito.any(Command.class)); } From 9fd6fa20f62b5bf71d986be4bea94d20c970f615 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Jun 2023 01:25:13 +0000 Subject: [PATCH 1733/2114] Bump opentelemetry.version from 1.26.0 to 1.27.0 Bumps `opentelemetry.version` from 1.26.0 to 1.27.0. Updates `opentelemetry-api` from 1.26.0 to 1.27.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-java/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-java/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-java/compare/v1.26.0...v1.27.0) Updates `opentelemetry-sdk-testing` from 1.26.0 to 1.27.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-java/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-java/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-java/compare/v1.26.0...v1.27.0) --- updated-dependencies: - dependency-name: io.opentelemetry:opentelemetry-api dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: io.opentelemetry:opentelemetry-sdk-testing dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 90d41267aa..5b4943cabf 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,7 @@ 1.7.36 4.2.19 1.11.0 - 1.26.0 + 1.27.0 2.15.2 1.2.12 5.9.3 From 4f5822c8d5e114e6ebd66b11f273abd860235507 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Jun 2023 01:00:51 +0000 Subject: [PATCH 1734/2114] Bump micrometer-core from 1.11.0 to 1.11.1 Bumps [micrometer-core](https://github.com/micrometer-metrics/micrometer) from 1.11.0 to 1.11.1. - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.11.0...v1.11.1) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5b4943cabf..1bfa04d8d1 100644 --- a/pom.xml +++ b/pom.xml @@ -56,7 +56,7 @@ 1.7.36 4.2.19 - 1.11.0 + 1.11.1 1.27.0 2.15.2 1.2.12 From 9ed45fde52224ec74fc523321efdf9a157d5cfca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 15 Jun 2023 10:14:02 +0200 Subject: [PATCH 1735/2114] Add max inbound message size to ConnectionFactory To avoid OOM with a very large message. The default value is 64 MiB. Fixes #1062 --- .../rabbitmq/client/ConnectionFactory.java | 33 ++++++- .../com/rabbitmq/client/impl/AMQChannel.java | 9 +- .../com/rabbitmq/client/impl/AMQCommand.java | 24 ++++- .../rabbitmq/client/impl/AMQConnection.java | 7 ++ .../impl/AbstractFrameHandlerFactory.java | 20 +++- .../client/impl/CommandAssembler.java | 20 +++- .../client/impl/ConnectionParams.java | 12 ++- .../java/com/rabbitmq/client/impl/Frame.java | 11 ++- .../client/impl/SocketFrameHandler.java | 12 ++- .../impl/SocketFrameHandlerFactory.java | 12 ++- .../client/impl/nio/FrameBuilder.java | 15 ++- .../nio/SocketChannelFrameHandlerFactory.java | 11 ++- .../nio/SocketChannelFrameHandlerState.java | 11 ++- .../impl/nio/SslEngineFrameBuilder.java | 8 +- .../client/test/FrameBuilderTest.java | 8 +- .../test/MaxInboundMessageSizeTest.java | 97 +++++++++++++++++++ .../com/rabbitmq/client/test/TestUtils.java | 20 +++- 17 files changed, 282 insertions(+), 48 deletions(-) create mode 100644 src/test/java/com/rabbitmq/client/test/MaxInboundMessageSizeTest.java diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 4fe7c9c57c..edbd8c4196 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -203,6 +203,13 @@ public class ConnectionFactory implements Cloneable { private CredentialsRefreshService credentialsRefreshService; + /** + * Maximum body size of inbound (received) messages in bytes. + * + *

Default value is 67,108,864 (64 MiB). + */ + private int maxInboundMessageBodySize = 1_048_576 * 64; + /** @return the default host to use for connections */ public String getHost() { return host; @@ -997,11 +1004,15 @@ protected synchronized FrameHandlerFactory createFrameHandlerFactory() throws IO if(this.nioParams.getNioExecutor() == null && this.nioParams.getThreadFactory() == null) { this.nioParams.setThreadFactory(getThreadFactory()); } - this.frameHandlerFactory = new SocketChannelFrameHandlerFactory(connectionTimeout, nioParams, isSSL(), sslContextFactory); + this.frameHandlerFactory = new SocketChannelFrameHandlerFactory( + connectionTimeout, nioParams, isSSL(), sslContextFactory, + this.maxInboundMessageBodySize); } return this.frameHandlerFactory; } else { - return new SocketFrameHandlerFactory(connectionTimeout, socketFactory, socketConf, isSSL(), this.shutdownExecutor, sslContextFactory); + return new SocketFrameHandlerFactory(connectionTimeout, socketFactory, + socketConf, isSSL(), this.shutdownExecutor, sslContextFactory, + this.maxInboundMessageBodySize); } } @@ -1300,6 +1311,7 @@ public ConnectionParams params(ExecutorService consumerWorkServiceExecutor) { result.setRecoveredQueueNameSupplier(recoveredQueueNameSupplier); result.setTrafficListener(trafficListener); result.setCredentialsRefreshService(credentialsRefreshService); + result.setMaxInboundMessageBodySize(maxInboundMessageBodySize); return result; } @@ -1590,6 +1602,21 @@ public int getChannelRpcTimeout() { return channelRpcTimeout; } + /** + * Maximum body size of inbound (received) messages in bytes. + * + *

Default value is 67,108,864 (64 MiB). + * + * @param maxInboundMessageBodySize the maximum size of inbound messages + */ + public void setMaxInboundMessageBodySize(int maxInboundMessageBodySize) { + if (maxInboundMessageBodySize <= 0) { + throw new IllegalArgumentException("Max inbound message body size must be greater than 0: " + + maxInboundMessageBodySize); + } + this.maxInboundMessageBodySize = maxInboundMessageBodySize; + } + /** * The factory to create SSL contexts. * This provides more flexibility to create {@link SSLContext}s diff --git a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java index 60e756de4b..83a2e3433c 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -62,7 +62,7 @@ public abstract class AMQChannel extends ShutdownNotifierComponent { private final int _channelNumber; /** Command being assembled */ - private AMQCommand _command = new AMQCommand(); + private AMQCommand _command; /** The current outstanding RPC request, if any. (Could become a queue in future.) */ private RpcWrapper _activeRpc = null; @@ -76,6 +76,7 @@ public abstract class AMQChannel extends ShutdownNotifierComponent { private final boolean _checkRpcResponseType; private final TrafficListener _trafficListener; + private final int maxInboundMessageBodySize; /** * Construct a channel on the given connection, with the given channel number. @@ -91,6 +92,8 @@ public AMQChannel(AMQConnection connection, int channelNumber) { this._rpcTimeout = connection.getChannelRpcTimeout(); this._checkRpcResponseType = connection.willCheckRpcResponseType(); this._trafficListener = connection.getTrafficListener(); + this.maxInboundMessageBodySize = connection.getMaxInboundMessageBodySize(); + this._command = new AMQCommand(this.maxInboundMessageBodySize); } /** @@ -110,7 +113,7 @@ public int getChannelNumber() { void handleFrame(Frame frame) throws IOException { AMQCommand command = _command; if (command.handleFrame(frame)) { // a complete command has rolled off the assembly line - _command = new AMQCommand(); // prepare for the next one + _command = new AMQCommand(this.maxInboundMessageBodySize); // prepare for the next one handleCompleteInboundCommand(command); } } diff --git a/src/main/java/com/rabbitmq/client/impl/AMQCommand.java b/src/main/java/com/rabbitmq/client/impl/AMQCommand.java index b8cb3c97dd..a761e5cce6 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQCommand.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQCommand.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -44,9 +44,13 @@ public class AMQCommand implements Command { /** The assembler for this command - synchronised on - contains all the state */ private final CommandAssembler assembler; + AMQCommand(int maxBodyLength) { + this(null, null, null, maxBodyLength); + } + /** Construct a command ready to fill in by reading frames */ public AMQCommand() { - this(null, null, null); + this(null, null, null, Integer.MAX_VALUE); } /** @@ -54,7 +58,7 @@ public AMQCommand() { * @param method the wrapped method */ public AMQCommand(com.rabbitmq.client.Method method) { - this(method, null, null); + this(method, null, null, Integer.MAX_VALUE); } /** @@ -64,7 +68,19 @@ public AMQCommand(com.rabbitmq.client.Method method) { * @param body the message body data */ public AMQCommand(com.rabbitmq.client.Method method, AMQContentHeader contentHeader, byte[] body) { - this.assembler = new CommandAssembler((Method) method, contentHeader, body); + this.assembler = new CommandAssembler((Method) method, contentHeader, body, Integer.MAX_VALUE); + } + + /** + * Construct a command with a specified method, header and body. + * @param method the wrapped method + * @param contentHeader the wrapped content header + * @param body the message body data + * @param maxBodyLength the maximum size for an inbound message body + */ + public AMQCommand(com.rabbitmq.client.Method method, AMQContentHeader contentHeader, byte[] body, + int maxBodyLength) { + this.assembler = new CommandAssembler((Method) method, contentHeader, body, maxBodyLength); } /** Public API - {@inheritDoc} */ diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index 79ab385c15..3528d9c806 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -157,6 +157,7 @@ public static Map defaultClientProperties() { private volatile ChannelManager _channelManager; /** Saved server properties field from connection.start */ private volatile Map _serverProperties; + private final int maxInboundMessageBodySize; /** * Protected API - respond, in the main I/O loop thread, to a ShutdownSignal. @@ -244,6 +245,7 @@ public AMQConnection(ConnectionParams params, FrameHandler frameHandler, Metrics this.credentialsRefreshService = params.getCredentialsRefreshService(); + this._channel0 = createChannel0(); this._channelManager = null; @@ -257,6 +259,7 @@ public AMQConnection(ConnectionParams params, FrameHandler frameHandler, Metrics this.errorOnWriteListener = params.getErrorOnWriteListener() != null ? params.getErrorOnWriteListener() : (connection, exception) -> { throw exception; }; // we just propagate the exception for non-recoverable connections this.workPoolTimeout = params.getWorkPoolTimeout(); + this.maxInboundMessageBodySize = params.getMaxInboundMessageBodySize(); } AMQChannel createChannel0() { @@ -1191,4 +1194,8 @@ public boolean willCheckRpcResponseType() { public TrafficListener getTrafficListener() { return trafficListener; } + + int getMaxInboundMessageBodySize() { + return maxInboundMessageBodySize; + } } diff --git a/src/main/java/com/rabbitmq/client/impl/AbstractFrameHandlerFactory.java b/src/main/java/com/rabbitmq/client/impl/AbstractFrameHandlerFactory.java index 32eb46712f..61f4c51325 100644 --- a/src/main/java/com/rabbitmq/client/impl/AbstractFrameHandlerFactory.java +++ b/src/main/java/com/rabbitmq/client/impl/AbstractFrameHandlerFactory.java @@ -1,3 +1,18 @@ +// Copyright (c) 2016-2023 VMware, Inc. or its affiliates. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + package com.rabbitmq.client.impl; import com.rabbitmq.client.SocketConfigurator; @@ -10,10 +25,13 @@ public abstract class AbstractFrameHandlerFactory implements FrameHandlerFactory protected final int connectionTimeout; protected final SocketConfigurator configurator; protected final boolean ssl; + protected final int maxInboundMessageBodySize; - protected AbstractFrameHandlerFactory(int connectionTimeout, SocketConfigurator configurator, boolean ssl) { + protected AbstractFrameHandlerFactory(int connectionTimeout, SocketConfigurator configurator, + boolean ssl, int maxInboundMessageBodySize) { this.connectionTimeout = connectionTimeout; this.configurator = configurator; this.ssl = ssl; + this.maxInboundMessageBodySize = maxInboundMessageBodySize; } } diff --git a/src/main/java/com/rabbitmq/client/impl/CommandAssembler.java b/src/main/java/com/rabbitmq/client/impl/CommandAssembler.java index d44df8d5c9..1b6e7f9e1d 100644 --- a/src/main/java/com/rabbitmq/client/impl/CommandAssembler.java +++ b/src/main/java/com/rabbitmq/client/impl/CommandAssembler.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -21,6 +21,7 @@ import com.rabbitmq.client.AMQP; import com.rabbitmq.client.UnexpectedFrameError; +import static java.lang.String.format; /** * Class responsible for piecing together a command from a series of {@link Frame}s. @@ -52,12 +53,16 @@ private enum CAState { /** No bytes of content body not yet accumulated */ private long remainingBodyBytes; - public CommandAssembler(Method method, AMQContentHeader contentHeader, byte[] body) { + private final int maxBodyLength; + + public CommandAssembler(Method method, AMQContentHeader contentHeader, byte[] body, + int maxBodyLength) { this.method = method; this.contentHeader = contentHeader; - this.bodyN = new ArrayList(2); + this.bodyN = new ArrayList<>(2); this.bodyLength = 0; this.remainingBodyBytes = 0; + this.maxBodyLength = maxBodyLength; appendBodyFragment(body); if (method == null) { this.state = CAState.EXPECTING_METHOD; @@ -99,7 +104,14 @@ private void consumeMethodFrame(Frame f) throws IOException { private void consumeHeaderFrame(Frame f) throws IOException { if (f.getType() == AMQP.FRAME_HEADER) { this.contentHeader = AMQImpl.readContentHeaderFrom(f.getInputStream()); - this.remainingBodyBytes = this.contentHeader.getBodySize(); + long bodySize = this.contentHeader.getBodySize(); + if (bodySize >= this.maxBodyLength) { + throw new IllegalStateException(format( + "Message body is too large (%d), maximum size is %d", + bodySize, this.maxBodyLength + )); + } + this.remainingBodyBytes = bodySize; updateContentBodyState(); } else { throw new UnexpectedFrameError(f, AMQP.FRAME_HEADER); diff --git a/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java b/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java index b7e6f3dd68..add7cc6398 100644 --- a/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java +++ b/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -63,6 +63,8 @@ public class ConnectionParams { private CredentialsRefreshService credentialsRefreshService; + private int maxInboundMessageBodySize; + public ConnectionParams() {} public CredentialsProvider getCredentialsProvider() { @@ -296,4 +298,12 @@ public void setCredentialsRefreshService(CredentialsRefreshService credentialsRe public CredentialsRefreshService getCredentialsRefreshService() { return credentialsRefreshService; } + + public int getMaxInboundMessageBodySize() { + return maxInboundMessageBodySize; + } + + public void setMaxInboundMessageBodySize(int maxInboundMessageBodySize) { + this.maxInboundMessageBodySize = maxInboundMessageBodySize; + } } diff --git a/src/main/java/com/rabbitmq/client/impl/Frame.java b/src/main/java/com/rabbitmq/client/impl/Frame.java index 74043c175c..045051aa92 100644 --- a/src/main/java/com/rabbitmq/client/impl/Frame.java +++ b/src/main/java/com/rabbitmq/client/impl/Frame.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2022 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -25,6 +25,7 @@ import java.util.Date; import java.util.List; import java.util.Map; +import static java.lang.String.format; /** * Represents an AMQP wire-protocol frame, with frame type, channel number, and payload bytes. @@ -81,7 +82,7 @@ public static Frame fromBodyFragment(int channelNumber, byte[] body, int offset, * * @return a new Frame if we read a frame successfully, otherwise null */ - public static Frame readFrom(DataInputStream is) throws IOException { + public static Frame readFrom(DataInputStream is, int maxPayloadSize) throws IOException { int type; int channel; @@ -107,6 +108,12 @@ public static Frame readFrom(DataInputStream is) throws IOException { channel = is.readUnsignedShort(); int payloadSize = is.readInt(); + if (payloadSize >= maxPayloadSize) { + throw new IllegalStateException(format( + "Frame body is too large (%d), maximum size is %d", + payloadSize, maxPayloadSize + )); + } byte[] payload = new byte[payloadSize]; is.readFully(payload); diff --git a/src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java b/src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java index 6efd6f83f9..5048100a7b 100644 --- a/src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -52,6 +52,8 @@ public class SocketFrameHandler implements FrameHandler { /** Socket's outputstream - data to the broker - synchronized on */ private final DataOutputStream _outputStream; + private final int maxInboundMessageBodySize; + /** Time to linger before closing the socket forcefully. */ public static final int SOCKET_CLOSING_TIMEOUT = 1; @@ -59,15 +61,17 @@ public class SocketFrameHandler implements FrameHandler { * @param socket the socket to use */ public SocketFrameHandler(Socket socket) throws IOException { - this(socket, null); + this(socket, null, Integer.MAX_VALUE); } /** * @param socket the socket to use */ - public SocketFrameHandler(Socket socket, ExecutorService shutdownExecutor) throws IOException { + public SocketFrameHandler(Socket socket, ExecutorService shutdownExecutor, + int maxInboundMessageBodySize) throws IOException { _socket = socket; _shutdownExecutor = shutdownExecutor; + this.maxInboundMessageBodySize = maxInboundMessageBodySize; _inputStream = new DataInputStream(new BufferedInputStream(socket.getInputStream())); _outputStream = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream())); @@ -181,7 +185,7 @@ public void initialize(AMQConnection connection) { @Override public Frame readFrame() throws IOException { synchronized (_inputStream) { - return Frame.readFrom(_inputStream); + return Frame.readFrom(_inputStream, this.maxInboundMessageBodySize); } } diff --git a/src/main/java/com/rabbitmq/client/impl/SocketFrameHandlerFactory.java b/src/main/java/com/rabbitmq/client/impl/SocketFrameHandlerFactory.java index d3fdfa9e25..40818c46ba 100644 --- a/src/main/java/com/rabbitmq/client/impl/SocketFrameHandlerFactory.java +++ b/src/main/java/com/rabbitmq/client/impl/SocketFrameHandlerFactory.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -38,12 +38,14 @@ public SocketFrameHandlerFactory(int connectionTimeout, SocketFactory socketFact public SocketFrameHandlerFactory(int connectionTimeout, SocketFactory socketFactory, SocketConfigurator configurator, boolean ssl, ExecutorService shutdownExecutor) { - this(connectionTimeout, socketFactory, configurator, ssl, shutdownExecutor, null); + this(connectionTimeout, socketFactory, configurator, ssl, shutdownExecutor, null, + Integer.MAX_VALUE); } public SocketFrameHandlerFactory(int connectionTimeout, SocketFactory socketFactory, SocketConfigurator configurator, - boolean ssl, ExecutorService shutdownExecutor, SslContextFactory sslContextFactory) { - super(connectionTimeout, configurator, ssl); + boolean ssl, ExecutorService shutdownExecutor, SslContextFactory sslContextFactory, + int maxInboundMessageBodySize) { + super(connectionTimeout, configurator, ssl, maxInboundMessageBodySize); this.socketFactory = socketFactory; this.shutdownExecutor = shutdownExecutor; this.sslContextFactory = sslContextFactory; @@ -79,7 +81,7 @@ protected Socket createSocket(String connectionName) throws IOException { public FrameHandler create(Socket sock) throws IOException { - return new SocketFrameHandler(sock, this.shutdownExecutor); + return new SocketFrameHandler(sock, this.shutdownExecutor, this.maxInboundMessageBodySize); } private static void quietTrySocketClose(Socket socket) { diff --git a/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java b/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java index 29dba1df54..d43228b970 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -23,6 +23,7 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.ReadableByteChannel; +import static java.lang.String.format; /** * Class to create AMQP frames from a {@link ReadableByteChannel}. @@ -43,6 +44,7 @@ public class FrameBuilder { protected final ReadableByteChannel channel; protected final ByteBuffer applicationBuffer; + private final int maxPayloadSize; // to store the bytes of the outstanding data // 3 byte-long because the longest we read is an unsigned int // (not need to store the latest byte) @@ -52,9 +54,10 @@ public class FrameBuilder { private byte[] framePayload; private int bytesRead = 0; - public FrameBuilder(ReadableByteChannel channel, ByteBuffer buffer) { + public FrameBuilder(ReadableByteChannel channel, ByteBuffer buffer, int maxPayloadSize) { this.channel = channel; this.applicationBuffer = buffer; + this.maxPayloadSize = maxPayloadSize; } /** @@ -65,7 +68,7 @@ public FrameBuilder(ReadableByteChannel channel, ByteBuffer buffer) { * * @return a complete frame or null if a frame couldn't have been fully built * @throws IOException - * @see Frame#readFrom(DataInputStream) + * @see Frame#readFrom(DataInputStream, int) */ public Frame readFrame() throws IOException { while (somethingToRead()) { @@ -93,6 +96,12 @@ public Frame readFrame() throws IOException { } else if (bytesRead == 6) { // payload size 4/4 int framePayloadSize = (frameBuffer[0] << 24) + (frameBuffer[1] << 16) + (frameBuffer[2] << 8) + readFromBuffer(); + if (framePayloadSize >= maxPayloadSize) { + throw new IllegalStateException(format( + "Frame body is too large (%d), maximum size is %d", + framePayloadSize, maxPayloadSize + )); + } framePayload = new byte[framePayloadSize]; } else if (bytesRead >= PAYLOAD_OFFSET && bytesRead < framePayload.length + PAYLOAD_OFFSET) { framePayload[bytesRead - PAYLOAD_OFFSET] = (byte) readFromBuffer(); diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java index 2cab2066c3..ed0a4f20f8 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2022 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -58,8 +58,10 @@ public class SocketChannelFrameHandlerFactory extends AbstractFrameHandlerFactor private final List nioLoopContexts; - public SocketChannelFrameHandlerFactory(int connectionTimeout, NioParams nioParams, boolean ssl, SslContextFactory sslContextFactory) { - super(connectionTimeout, null, ssl); + public SocketChannelFrameHandlerFactory(int connectionTimeout, NioParams nioParams, boolean ssl, + SslContextFactory sslContextFactory, + int maxInboundMessageBodySize) { + super(connectionTimeout, null, ssl, maxInboundMessageBodySize); this.nioParams = new NioParams(nioParams); this.sslContextFactory = sslContextFactory; this.nioLoopContexts = new ArrayList<>(this.nioParams.getNbIoThreads()); @@ -134,7 +136,8 @@ public FrameHandler create(Address addr, String connectionName) throws IOExcepti channel, nioLoopContext, nioParams, - sslEngine + sslEngine, + this.maxInboundMessageBodySize ); state.startReading(); SocketChannelFrameHandler frameHandler = new SocketChannelFrameHandler(state); diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java index 4f1e4dc885..b1a391fd65 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -71,7 +71,9 @@ public class SocketChannelFrameHandlerState { final FrameBuilder frameBuilder; - public SocketChannelFrameHandlerState(SocketChannel channel, NioLoopContext nioLoopsState, NioParams nioParams, SSLEngine sslEngine) { + public SocketChannelFrameHandlerState(SocketChannel channel, NioLoopContext nioLoopsState, + NioParams nioParams, SSLEngine sslEngine, + int maxFramePayloadSize) { this.channel = channel; this.readSelectorState = nioLoopsState.readSelectorState; this.writeSelectorState = nioLoopsState.writeSelectorState; @@ -94,7 +96,7 @@ public SocketChannelFrameHandlerState(SocketChannel channel, NioLoopContext nioL new ByteBufferOutputStream(channel, plainOut) ); - this.frameBuilder = new FrameBuilder(channel, plainIn); + this.frameBuilder = new FrameBuilder(channel, plainIn, maxFramePayloadSize); } else { this.ssl = true; @@ -106,7 +108,8 @@ public SocketChannelFrameHandlerState(SocketChannel channel, NioLoopContext nioL this.outputStream = new DataOutputStream( new SslEngineByteBufferOutputStream(sslEngine, plainOut, cipherOut, channel) ); - this.frameBuilder = new SslEngineFrameBuilder(sslEngine, plainIn, cipherIn, channel); + this.frameBuilder = new SslEngineFrameBuilder(sslEngine, plainIn, + cipherIn, channel, maxFramePayloadSize); } } diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineFrameBuilder.java b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineFrameBuilder.java index 8b6ecaf8ab..48072988c2 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineFrameBuilder.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineFrameBuilder.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -35,8 +35,10 @@ public class SslEngineFrameBuilder extends FrameBuilder { private boolean isUnderflowHandlingEnabled = false; - public SslEngineFrameBuilder(SSLEngine sslEngine, ByteBuffer plainIn, ByteBuffer cipherIn, ReadableByteChannel channel) { - super(channel, plainIn); + public SslEngineFrameBuilder(SSLEngine sslEngine, ByteBuffer plainIn, + ByteBuffer cipherIn, ReadableByteChannel channel, + int maxPayloadSize) { + super(channel, plainIn, maxPayloadSize); this.sslEngine = sslEngine; this.cipherBuffer = cipherIn; } diff --git a/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java b/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java index db10bd696b..311aabdef0 100644 --- a/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java +++ b/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java @@ -59,7 +59,7 @@ void tearDown() throws Exception { @Test public void buildFrameInOneGo() throws IOException { buffer = ByteBuffer.wrap(new byte[] { 1, 0, 0, 0, 0, 0, 3, 1, 2, 3, end() }); - builder = new FrameBuilder(channel, buffer); + builder = new FrameBuilder(channel, buffer, Integer.MAX_VALUE); Frame frame = builder.readFrame(); assertThat(frame).isNotNull(); assertThat(frame.getType()).isEqualTo(1); @@ -78,7 +78,7 @@ public void buildFramesInOneGo() throws IOException { } } buffer = ByteBuffer.wrap(frames); - builder = new FrameBuilder(channel, buffer); + builder = new FrameBuilder(channel, buffer, Integer.MAX_VALUE); int frameCount = 0; Frame frame; while ((frame = builder.readFrame()) != null) { @@ -94,7 +94,7 @@ public void buildFramesInOneGo() throws IOException { @Test public void buildFrameInSeveralCalls() throws IOException { buffer = ByteBuffer.wrap(new byte[] { 1, 0, 0, 0, 0, 0, 3, 1, 2 }); - builder = new FrameBuilder(channel, buffer); + builder = new FrameBuilder(channel, buffer, Integer.MAX_VALUE); Frame frame = builder.readFrame(); assertThat(frame).isNull(); @@ -131,7 +131,7 @@ public void protocolMismatchHeader() throws IOException { }; for (int i = 0; i < buffers.length; i++) { - builder = new FrameBuilder(channel, buffers[i]); + builder = new FrameBuilder(channel, buffers[i], Integer.MAX_VALUE); try { builder.readFrame(); fail("protocol header not correct, exception should have been thrown"); diff --git a/src/test/java/com/rabbitmq/client/test/MaxInboundMessageSizeTest.java b/src/test/java/com/rabbitmq/client/test/MaxInboundMessageSizeTest.java new file mode 100644 index 0000000000..da534d9c5f --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/MaxInboundMessageSizeTest.java @@ -0,0 +1,97 @@ +// Copyright (c) 2023 VMware, Inc. or its affiliates. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.test; + +import static com.rabbitmq.client.test.TestUtils.LatchConditions.completed; +import static org.assertj.core.api.Assertions.assertThat; + +import com.rabbitmq.client.*; +import java.io.IOException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicReference; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +public class MaxInboundMessageSizeTest extends BrokerTestCase { + + String q; + + private static void safeClose(Connection c) { + try { + c.close(); + } catch (Exception e) { + // OK + } + } + + @Override + protected void createResources() throws IOException, TimeoutException { + q = generateQueueName(); + declareTransientQueue(q); + super.createResources(); + } + + @CsvSource({ + "20000,5000,true", + "20000,100000,true", + "20000,5000,false", + "20000,100000,false", + }) + @ParameterizedTest + void maxInboundMessageSizeMustBeEnforced(int maxMessageSize, int frameMax, boolean basicGet) + throws Exception { + ConnectionFactory cf = newConnectionFactory(); + cf.setMaxInboundMessageBodySize(maxMessageSize); + cf.setRequestedFrameMax(frameMax); + Connection c = cf.newConnection(); + try { + Channel ch = c.createChannel(); + ch.confirmSelect(); + byte[] body = new byte[maxMessageSize * 2]; + ch.basicPublish("", q, null, body); + ch.waitForConfirmsOrDie(); + AtomicReference exception = new AtomicReference<>(); + CountDownLatch errorLatch = new CountDownLatch(1); + ch.addShutdownListener( + cause -> { + exception.set(cause.getCause()); + errorLatch.countDown(); + }); + if (basicGet) { + try { + ch.basicGet(q, true); + } catch (Exception e) { + // OK for basicGet + } + } else { + ch.basicConsume(q, new DefaultConsumer(ch)); + } + assertThat(errorLatch).is(completed()); + assertThat(exception.get()) + .isInstanceOf(IllegalStateException.class) + .hasMessageContaining("Message body is too large"); + } finally { + safeClose(c); + } + } + + @Override + protected void releaseResources() throws IOException { + deleteQueue(q); + super.releaseResources(); + } +} diff --git a/src/test/java/com/rabbitmq/client/test/TestUtils.java b/src/test/java/com/rabbitmq/client/test/TestUtils.java index cbb2885f22..ec495bcb83 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtils.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtils.java @@ -26,11 +26,11 @@ import java.lang.annotation.Target; import java.util.function.Function; import org.assertj.core.api.Assertions; +import org.assertj.core.api.Condition; import org.junit.jupiter.api.extension.ConditionEvaluationResult; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.ExtensionContext.Namespace; -import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; @@ -47,8 +47,6 @@ public class TestUtils { - private static final Logger LOGGER = LoggerFactory.getLogger(TestUtils.class); - public static final boolean USE_NIO = System.getProperty("use.nio") != null; public static ConnectionFactory connectionFactory() { @@ -303,6 +301,22 @@ public interface CallableFunction { } + public static class LatchConditions { + + static Condition completed() { + return new Condition<>( + countDownLatch-> { + try { + return countDownLatch.await(10, TimeUnit.SECONDS); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + }, + "Latch did not complete in 10 seconds"); + } + + } + public static boolean basicGetBasicConsume(Connection connection, String queue, final CountDownLatch latch, int msgSize) throws Exception { Channel channel = connection.createChannel(); From 5982cd1eb307004fe53353a01da03332aa342eb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 15 Jun 2023 11:49:56 +0200 Subject: [PATCH 1736/2114] Tweak error message References #1062 --- src/main/java/com/rabbitmq/client/impl/CommandAssembler.java | 4 +++- src/main/java/com/rabbitmq/client/impl/Frame.java | 4 +++- src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/CommandAssembler.java b/src/main/java/com/rabbitmq/client/impl/CommandAssembler.java index 1b6e7f9e1d..3d6ee17fda 100644 --- a/src/main/java/com/rabbitmq/client/impl/CommandAssembler.java +++ b/src/main/java/com/rabbitmq/client/impl/CommandAssembler.java @@ -107,7 +107,9 @@ private void consumeHeaderFrame(Frame f) throws IOException { long bodySize = this.contentHeader.getBodySize(); if (bodySize >= this.maxBodyLength) { throw new IllegalStateException(format( - "Message body is too large (%d), maximum size is %d", + "Message body is too large (%d), maximum configured size is %d. " + + "See ConnectionFactory#setMaxInboundMessageBodySize " + + "if you need to increase the limit.", bodySize, this.maxBodyLength )); } diff --git a/src/main/java/com/rabbitmq/client/impl/Frame.java b/src/main/java/com/rabbitmq/client/impl/Frame.java index 045051aa92..8c14f8f9f2 100644 --- a/src/main/java/com/rabbitmq/client/impl/Frame.java +++ b/src/main/java/com/rabbitmq/client/impl/Frame.java @@ -110,7 +110,9 @@ public static Frame readFrom(DataInputStream is, int maxPayloadSize) throws IOEx int payloadSize = is.readInt(); if (payloadSize >= maxPayloadSize) { throw new IllegalStateException(format( - "Frame body is too large (%d), maximum size is %d", + "Frame body is too large (%d), maximum configured size is %d. " + + "See ConnectionFactory#setMaxInboundMessageBodySize " + + "if you need to increase the limit.", payloadSize, maxPayloadSize )); } diff --git a/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java b/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java index d43228b970..cd708cad9a 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java @@ -98,7 +98,9 @@ public Frame readFrame() throws IOException { int framePayloadSize = (frameBuffer[0] << 24) + (frameBuffer[1] << 16) + (frameBuffer[2] << 8) + readFromBuffer(); if (framePayloadSize >= maxPayloadSize) { throw new IllegalStateException(format( - "Frame body is too large (%d), maximum size is %d", + "Frame body is too large (%d), maximum configured size is %d. " + + "See ConnectionFactory#setMaxInboundMessageBodySize " + + "if you need to increase the limit.", framePayloadSize, maxPayloadSize )); } From f1348a529f188c73d33a95064322b39ffe0b17d0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 Jun 2023 01:37:54 +0000 Subject: [PATCH 1737/2114] Bump mockito-core from 5.3.1 to 5.4.0 Bumps [mockito-core](https://github.com/mockito/mockito) from 5.3.1 to 5.4.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.3.1...v5.4.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1bfa04d8d1..957a9a12fa 100644 --- a/pom.xml +++ b/pom.xml @@ -61,7 +61,7 @@ 2.15.2 1.2.12 5.9.3 - 5.3.1 + 5.4.0 3.24.2 9.4.51.v20230217 1.70 From b65db946ee4694ef7f45c65d3bd9be1861a8a022 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 19 Jun 2023 11:18:13 +0200 Subject: [PATCH 1738/2114] Use 5.18.0 in readme --- README.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.adoc b/README.adoc index a3944d22fd..f416d157bf 100644 --- a/README.adoc +++ b/README.adoc @@ -1,6 +1,6 @@ -:client-stable: 5.17.0 +:client-stable: 5.18.0 :client-rc: 5.17.0.RC2 -:client-snapshot: 5.18.0-SNAPSHOT +:client-snapshot: 5.19.0-SNAPSHOT = RabbitMQ Java Client From 984956ea1920c4dd831c977f2d50837fbd143aaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 29 Jun 2023 12:05:11 +0200 Subject: [PATCH 1739/2114] Re-activate dependabot --- .github/dependabot.yml | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index c89ceb86a4..132df97b38 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -15,19 +15,19 @@ updates: versions: [ "[2.0,)" ] - dependency-name: "ch.qos.logback:logback-classic" versions: [ "[1.3,)" ] - # - package-ecosystem: "maven" - # directory: "/" - # schedule: - # interval: "daily" - # open-pull-requests-limit: 20 - # target-branch: "5.x.x-stable" - # ignore: - # - dependency-name: "org.eclipse.jetty:jetty-servlet" - # versions: ["[10.0,)"] - # - dependency-name: "org.slf4j:slf4j-api" - # versions: [ "[2.0,)" ] - # - dependency-name: "ch.qos.logback:logback-classic" - # versions: [ "[1.3,)" ] + - package-ecosystem: "maven" + directory: "/" + schedule: + interval: "daily" + open-pull-requests-limit: 20 + target-branch: "5.x.x-stable" + ignore: + - dependency-name: "org.eclipse.jetty:jetty-servlet" + versions: ["[10.0,)"] + - dependency-name: "org.slf4j:slf4j-api" + versions: [ "[2.0,)" ] + - dependency-name: "ch.qos.logback:logback-classic" + versions: [ "[1.3,)" ] - package-ecosystem: "github-actions" directory: "/" schedule: From 1e0aaeee941cd614f716e58396578ef34ae72a2c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Jul 2023 00:29:30 +0000 Subject: [PATCH 1740/2114] Bump opentelemetry.version from 1.27.0 to 1.28.0 Bumps `opentelemetry.version` from 1.27.0 to 1.28.0. Updates `opentelemetry-api` from 1.27.0 to 1.28.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-java/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-java/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-java/compare/v1.27.0...v1.28.0) Updates `opentelemetry-sdk-testing` from 1.27.0 to 1.28.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-java/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-java/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-java/compare/v1.27.0...v1.28.0) --- updated-dependencies: - dependency-name: io.opentelemetry:opentelemetry-api dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: io.opentelemetry:opentelemetry-sdk-testing dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 957a9a12fa..12830859c7 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,7 @@ 1.7.36 4.2.19 1.11.1 - 1.27.0 + 1.28.0 2.15.2 1.2.12 5.9.3 From 8db500ffdefd3644d20ac074edbb6e8bb267efa8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Jul 2023 00:55:53 +0000 Subject: [PATCH 1741/2114] Bump micrometer-core from 1.11.1 to 1.11.2 Bumps [micrometer-core](https://github.com/micrometer-metrics/micrometer) from 1.11.1 to 1.11.2. - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.11.1...v1.11.2) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 12830859c7..f8a333a6c6 100644 --- a/pom.xml +++ b/pom.xml @@ -56,7 +56,7 @@ 1.7.36 4.2.19 - 1.11.1 + 1.11.2 1.28.0 2.15.2 1.2.12 From fd04179a1ee34092a21d9aec1242b7d6bfb35ffd Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Wed, 19 Apr 2023 15:12:40 +0200 Subject: [PATCH 1742/2114] WIP on Micrometer Observation --- pom.xml | 17 +- .../com/rabbitmq/client/MetricsCollector.java | 71 ++++++++ .../com/rabbitmq/client/impl/ChannelN.java | 17 +- ...icrometerConsumeObservationConvention.java | 65 ++++++++ ...icrometerPublishObservationConvention.java | 65 ++++++++ .../client/impl/MicrometerConsumeContext.java | 69 ++++++++ ...icrometerConsumeObservationConvention.java | 34 ++++ .../impl/MicrometerMetricsCollector.java | 122 ++++++++++++++ .../client/impl/MicrometerPublishContext.java | 59 +++++++ ...icrometerPublishObservationConvention.java | 36 ++++ ...meterRabbitMqObservationDocumentation.java | 157 ++++++++++++++++++ .../test/functional/FunctionalTestSuite.java | 1 + .../test/functional/MicrometerMetrics.java | 144 ++++++++++++++++ 13 files changed, 848 insertions(+), 9 deletions(-) create mode 100644 src/main/java/com/rabbitmq/client/impl/DefaultMicrometerConsumeObservationConvention.java create mode 100644 src/main/java/com/rabbitmq/client/impl/DefaultMicrometerPublishObservationConvention.java create mode 100644 src/main/java/com/rabbitmq/client/impl/MicrometerConsumeContext.java create mode 100644 src/main/java/com/rabbitmq/client/impl/MicrometerConsumeObservationConvention.java create mode 100644 src/main/java/com/rabbitmq/client/impl/MicrometerPublishContext.java create mode 100644 src/main/java/com/rabbitmq/client/impl/MicrometerPublishObservationConvention.java create mode 100644 src/main/java/com/rabbitmq/client/impl/MicrometerRabbitMqObservationDocumentation.java create mode 100644 src/test/java/com/rabbitmq/client/test/functional/MicrometerMetrics.java diff --git a/pom.xml b/pom.xml index f8a333a6c6..f3dc64e781 100644 --- a/pom.xml +++ b/pom.xml @@ -56,8 +56,9 @@ 1.7.36 4.2.19 - 1.11.2 - 1.28.0 + 1.11.1 + 1.27.0 + 1.1.4 2.15.2 1.2.12 5.9.3 @@ -791,6 +792,11 @@ ${gson.version} test + + io.micrometer + micrometer-tracing-integration-test + test + @@ -804,6 +810,13 @@ pom import + + io.micrometer + micrometer-tracing-bom + ${micrometer-tracing.version} + pom + import + diff --git a/src/main/java/com/rabbitmq/client/MetricsCollector.java b/src/main/java/com/rabbitmq/client/MetricsCollector.java index 0ce3642522..286bd23040 100644 --- a/src/main/java/com/rabbitmq/client/MetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/MetricsCollector.java @@ -15,6 +15,12 @@ package com.rabbitmq.client; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +import com.rabbitmq.client.impl.AMQCommand; + /** * Interface to gather execution data of the client. * Note transactions are not supported: they deal with @@ -64,6 +70,71 @@ default void basicPublishUnrouted(Channel channel) { void basicConsume(Channel channel, String consumerTag, boolean autoAck); + default Consumer basicPreConsume(Channel channel, String consumerTag, boolean autoAck, AMQCommand amqCommand, Consumer callback) { + return callback; + } + void basicCancel(Channel channel, String consumerTag); + default void basicPrePublish(Channel channel, long deliveryTag, PublishArguments publishArguments) { + + } + + default void basicPublishFailure(Channel channel, Exception exception, PublishArguments publishArguments) { + basicPublishFailure(channel, exception); + } + + default void basicPublish(Channel channel, long deliveryTag, PublishArguments publishArguments) { + basicPublish(channel, deliveryTag); + } + + class PublishArguments { + private AMQP.Basic.Publish publish; + + private AMQP.BasicProperties props; + + private byte[] body; + + private final Map headers = new HashMap<>(); + + private final Map context = new HashMap<>(); + + public PublishArguments(AMQP.Basic.Publish publish, AMQP.BasicProperties props, byte[] body) { + this.publish = Objects.requireNonNull(publish); + this.props = Objects.requireNonNull(props); + this.body = Objects.requireNonNull(body); + } + + public AMQP.Basic.Publish getPublish() { + return publish; + } + + public AMQP.BasicProperties getProps() { + return props; + } + + public byte[] getBody() { + return body; + } + + public void setPublish(AMQP.Basic.Publish publish) { + this.publish = publish; + } + + public void setProps(AMQP.BasicProperties props) { + this.props = props; + } + + public void setBody(byte[] body) { + this.body = body; + } + + public Map getContext() { + return context; + } + + public Map getHeaders() { + return headers; + } + } } diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java index 57a15d62fe..c41c807df7 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelN.java @@ -700,20 +700,22 @@ public void basicPublish(String exchange, String routingKey, if (props == null) { props = MessageProperties.MINIMAL_BASIC; } - AMQCommand command = new AMQCommand( - new Basic.Publish.Builder() + AMQP.Basic.Publish publish = new Basic.Publish.Builder() .exchange(exchange) .routingKey(routingKey) .mandatory(mandatory) .immediate(immediate) - .build(), props, body); + .build(); + MetricsCollector.PublishArguments args = new MetricsCollector.PublishArguments(publish, props, body); try { + metricsCollector.basicPrePublish(this, deliveryTag, args); + AMQCommand command = new AMQCommand(args.getPublish(), args.getProps(), args.getBody()); transmit(command); } catch (IOException | AlreadyClosedException e) { - metricsCollector.basicPublishFailure(this, e); + metricsCollector.basicPublishFailure(this, e, args); throw e; } - metricsCollector.basicPublish(this, deliveryTag); + metricsCollector.basicPublish(this, deliveryTag, args); } /** Public API - {@inheritDoc} */ @@ -1358,12 +1360,13 @@ public String basicConsume(String queue, final boolean autoAck, String consumerT @Override public String transformReply(AMQCommand replyCommand) { String actualConsumerTag = ((Basic.ConsumeOk) replyCommand.getMethod()).getConsumerTag(); - _consumers.put(actualConsumerTag, callback); + Consumer wrappedCallback = metricsCollector.basicPreConsume(ChannelN.this, actualConsumerTag, autoAck, replyCommand, callback); + _consumers.put(actualConsumerTag, wrappedCallback); // need to register consumer in stats before it actually starts consuming metricsCollector.basicConsume(ChannelN.this, actualConsumerTag, autoAck); - dispatcher.handleConsumeOk(callback, actualConsumerTag); + dispatcher.handleConsumeOk(wrappedCallback, actualConsumerTag); return actualConsumerTag; } }; diff --git a/src/main/java/com/rabbitmq/client/impl/DefaultMicrometerConsumeObservationConvention.java b/src/main/java/com/rabbitmq/client/impl/DefaultMicrometerConsumeObservationConvention.java new file mode 100644 index 0000000000..c346009d17 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/DefaultMicrometerConsumeObservationConvention.java @@ -0,0 +1,65 @@ +/* + * Copyright 2022 VMware, Inc. + * + * Licensed 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 + * + * https://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 com.rabbitmq.client.impl; + +import com.rabbitmq.client.impl.MicrometerRabbitMqObservationDocumentation.HighCardinalityTags; +import com.rabbitmq.client.impl.MicrometerRabbitMqObservationDocumentation.LowCardinalityTags; +import io.micrometer.common.KeyValues; +import io.micrometer.common.util.StringUtils; + +/** + * Default implementation of {@link MicrometerConsumeObservationConvention}. + * + * @since 6.0.0 + * @see MicrometerConsumeObservationConvention + */ +public class DefaultMicrometerConsumeObservationConvention implements MicrometerConsumeObservationConvention { + + /** + * Singleton instance of this convention. + */ + public static final DefaultMicrometerConsumeObservationConvention INSTANCE = new DefaultMicrometerConsumeObservationConvention(); + + // There is no need to instantiate this class multiple times, but it may be extended, + // hence protected visibility. + protected DefaultMicrometerConsumeObservationConvention() { + } + + @Override + public String getName() { + return "rabbit.consume"; // TODO: How should we call this + } + + @Override + public String getContextualName(MicrometerConsumeContext context) { + return destination(context.getEnvelope().getRoutingKey()) + " consume"; + } + + private String destination(String destination) { + return StringUtils.isNotBlank(destination) ? destination : "(anonymous)"; + } + + @Override + public KeyValues getLowCardinalityKeyValues(MicrometerConsumeContext context) { + return KeyValues.of(LowCardinalityTags.MESSAGING_OPERATION.withValue("publish"), LowCardinalityTags.MESSAGING_SYSTEM.withValue("rabbitmq")); + } + + @Override + public KeyValues getHighCardinalityKeyValues(MicrometerConsumeContext context) { + return KeyValues.of(HighCardinalityTags.MESSAGING_ROUTING_KEY.withValue(context.getEnvelope().getRoutingKey()), HighCardinalityTags.MESSAGING_DESTINATION_NAME.withValue(context.getEnvelope().getExchange())); + } + +} diff --git a/src/main/java/com/rabbitmq/client/impl/DefaultMicrometerPublishObservationConvention.java b/src/main/java/com/rabbitmq/client/impl/DefaultMicrometerPublishObservationConvention.java new file mode 100644 index 0000000000..4dc04e2d4a --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/DefaultMicrometerPublishObservationConvention.java @@ -0,0 +1,65 @@ +/* + * Copyright 2022 VMware, Inc. + * + * Licensed 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 + * + * https://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 com.rabbitmq.client.impl; + +import com.rabbitmq.client.impl.MicrometerRabbitMqObservationDocumentation.HighCardinalityTags; +import com.rabbitmq.client.impl.MicrometerRabbitMqObservationDocumentation.LowCardinalityTags; +import io.micrometer.common.KeyValues; +import io.micrometer.common.util.StringUtils; + +/** + * Default implementation of {@link MicrometerPublishObservationConvention}. + * + * @since 6.0.0 + * @see MicrometerRabbitMqObservationDocumentation + */ +public class DefaultMicrometerPublishObservationConvention implements MicrometerPublishObservationConvention { + + /** + * Singleton instance of this convention. + */ + public static final DefaultMicrometerPublishObservationConvention INSTANCE = new DefaultMicrometerPublishObservationConvention(); + + // There is no need to instantiate this class multiple times, but it may be extended, + // hence protected visibility. + protected DefaultMicrometerPublishObservationConvention() { + } + + @Override + public String getName() { + return "rabbit.publish"; // TODO: How should we call this + } + + @Override + public String getContextualName(MicrometerPublishContext context) { + return destination(context.getPublishArguments().getPublish().getRoutingKey()) + " publish"; + } + + private String destination(String destination) { + return StringUtils.isNotBlank(destination) ? destination : "(anonymous)"; + } + + @Override + public KeyValues getLowCardinalityKeyValues(MicrometerPublishContext context) { + return KeyValues.of(LowCardinalityTags.MESSAGING_OPERATION.withValue("publish"), LowCardinalityTags.MESSAGING_SYSTEM.withValue("rabbitmq")); + } + + @Override + public KeyValues getHighCardinalityKeyValues(MicrometerPublishContext context) { + return KeyValues.of(HighCardinalityTags.MESSAGING_ROUTING_KEY.withValue(context.getPublishArguments().getPublish().getRoutingKey()), HighCardinalityTags.MESSAGING_DESTINATION_NAME.withValue(context.getPublishArguments().getPublish().getExchange())); + } + +} diff --git a/src/main/java/com/rabbitmq/client/impl/MicrometerConsumeContext.java b/src/main/java/com/rabbitmq/client/impl/MicrometerConsumeContext.java new file mode 100644 index 0000000000..c141c2eb32 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/MicrometerConsumeContext.java @@ -0,0 +1,69 @@ +/* + * Copyright 2022 VMware, Inc. + * + * Licensed 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 + * + * https://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 com.rabbitmq.client.impl; + +import java.util.Objects; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Envelope; +import io.micrometer.observation.transport.ReceiverContext; + +/** + * {@link io.micrometer.observation.Observation.Context} for use with RabbitMQ client + * {@link io.micrometer.observation.Observation} instrumentation. + * + * @since 6.0.0 + */ +public class MicrometerConsumeContext extends ReceiverContext { + + private final String consumerTag; + private final Envelope envelope; + + private final AMQP.BasicProperties properties; + + private final byte[] body; + + public MicrometerConsumeContext(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) { + super((props, key) -> { + Object result = Objects.requireNonNull(props).getHeaders().get(key); + if (result == null) { + return null; + } + return String.valueOf(result); + }); + this.consumerTag = consumerTag; + this.envelope = envelope; + this.properties = properties; + this.body = body; + setCarrier(properties); + } + + public String getConsumerTag() { + return consumerTag; + } + + public Envelope getEnvelope() { + return envelope; + } + + public AMQP.BasicProperties getProperties() { + return properties; + } + + public byte[] getBody() { + return body; + } +} diff --git a/src/main/java/com/rabbitmq/client/impl/MicrometerConsumeObservationConvention.java b/src/main/java/com/rabbitmq/client/impl/MicrometerConsumeObservationConvention.java new file mode 100644 index 0000000000..01dd6612af --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/MicrometerConsumeObservationConvention.java @@ -0,0 +1,34 @@ +/* + * Copyright 2022 VMware, Inc. + * + * Licensed 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 + * + * https://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 com.rabbitmq.client.impl; + +import io.micrometer.observation.Observation; +import io.micrometer.observation.ObservationConvention; + +/** + * {@link ObservationConvention} for RabbitMQ client instrumentation. + * + * @since 6.0.0 + * @see DefaultMicrometerPublishObservationConvention + */ +public interface MicrometerConsumeObservationConvention extends ObservationConvention { + + @Override + default boolean supportsContext(Observation.Context context) { + return context instanceof MicrometerConsumeContext; + } + +} diff --git a/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java index 9d8cd5bd1e..1ca1bcb23a 100644 --- a/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java @@ -15,14 +15,22 @@ package com.rabbitmq.client.impl; +import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; +import com.rabbitmq.client.Consumer; +import com.rabbitmq.client.Envelope; import com.rabbitmq.client.MetricsCollector; +import com.rabbitmq.client.ShutdownSignalException; +import io.micrometer.common.lang.Nullable; import io.micrometer.core.instrument.Counter; import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.Tag; import io.micrometer.core.instrument.Tags; +import io.micrometer.observation.Observation; +import io.micrometer.observation.ObservationRegistry; +import java.io.IOException; import java.util.Collections; import java.util.concurrent.atomic.AtomicLong; import java.util.function.Function; @@ -43,6 +51,8 @@ */ public class MicrometerMetricsCollector extends AbstractMetricsCollector { + private static final String MICROMETER_OBSERVATION_KEY = "micrometer.observation"; + private final AtomicLong connections; private final AtomicLong channels; @@ -63,6 +73,12 @@ public class MicrometerMetricsCollector extends AbstractMetricsCollector { private final Counter rejectedMessages; + private MicrometerPublishObservationConvention publishObservationConvention; + + private MicrometerConsumeObservationConvention consumeObservationConvention; + + private ObservationRegistry observationRegistry = ObservationRegistry.NOOP; + public MicrometerMetricsCollector(MeterRegistry registry) { this(registry, "rabbitmq"); } @@ -152,6 +168,53 @@ protected void markPublishedMessageUnrouted() { unroutedPublishedMessages.increment(); } + @Override + public void basicPrePublish(Channel channel, long deliveryTag, PublishArguments publishArguments) { + if (observationRegistry.isNoop()) { + return; + } + // TODO: Is this for fire and forget or request reply too? If r-r then we have to have 2 contexts + MicrometerPublishContext micrometerPublishContext = new MicrometerPublishContext(publishArguments); + Observation observation = MicrometerRabbitMqObservationDocumentation.PUBLISH_OBSERVATION.observation(this.publishObservationConvention, DefaultMicrometerPublishObservationConvention.INSTANCE, () -> micrometerPublishContext, observationRegistry); + publishArguments.getContext().put(MICROMETER_OBSERVATION_KEY, observation.start()); + publishArguments.setProps(micrometerPublishContext.getPropertiesBuilder().build()); + } + + @Override + public void basicPublishFailure(Channel channel, Exception exception, PublishArguments publishArguments) { + if (observationRegistry.isNoop()) { + super.basicPublishFailure(channel, exception); // TODO: Do we want both the observation and the metrics? + return; + } + Observation observation = getObservation(publishArguments); + if (observation == null) { + return; + } + observation.error(exception); + } + + @Override + public void basicPublish(Channel channel, long deliveryTag, PublishArguments publishArguments) { + if (observationRegistry.isNoop()) { + super.basicPublish(channel, deliveryTag); // TODO: Do we want both the observation and the metrics? + return; + } + Observation observation = getObservation(publishArguments); + if (observation == null) { + return; + } + observation.stop(); + } + + @Override + public Consumer basicPreConsume(Channel channel, String consumerTag, boolean autoAck, AMQCommand amqCommand, Consumer callback) { + return new ObservationConsumer(callback, observationRegistry, consumeObservationConvention); + } + + private static Observation getObservation(PublishArguments publishArguments) { + return (Observation) publishArguments.getContext().get(MICROMETER_OBSERVATION_KEY); + } + public AtomicLong getConnections() { return connections; } @@ -192,6 +255,18 @@ public Counter getRejectedMessages() { return rejectedMessages; } + public void setPublishObservationConvention(MicrometerPublishObservationConvention publishObservationConvention) { + this.publishObservationConvention = publishObservationConvention; + } + + public void setConsumeObservationConvention(MicrometerConsumeObservationConvention consumeObservationConvention) { + this.consumeObservationConvention = consumeObservationConvention; + } + + public void setObservationRegistry(ObservationRegistry observationRegistry) { + this.observationRegistry = observationRegistry; + } + public enum Metrics { CONNECTIONS { @Override @@ -258,4 +333,51 @@ Object create(MeterRegistry registry, String prefix, Iterable tags) { } + private static class ObservationConsumer implements Consumer { + + private final Consumer delegate; + + private final ObservationRegistry observationRegistry; + + private final MicrometerConsumeObservationConvention observationConvention; + + ObservationConsumer(Consumer delegate, ObservationRegistry observationRegistry, @Nullable MicrometerConsumeObservationConvention observationConvention) { + this.delegate = delegate; + this.observationRegistry = observationRegistry; + this.observationConvention = observationConvention; + } + + @Override + public void handleConsumeOk(String consumerTag) { + delegate.handleConsumeOk(consumerTag); + } + + @Override + public void handleCancelOk(String consumerTag) { + delegate.handleCancelOk(consumerTag); + } + + @Override + public void handleCancel(String consumerTag) throws IOException { + delegate.handleCancel(consumerTag); + } + + @Override + public void handleShutdownSignal(String consumerTag, ShutdownSignalException sig) { + delegate.handleShutdownSignal(consumerTag, sig); + } + + @Override + public void handleRecoverOk(String consumerTag) { + delegate.handleRecoverOk(consumerTag); + } + + @Override + public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { + MicrometerConsumeContext context = new MicrometerConsumeContext(consumerTag, envelope, properties, body); + Observation observation = MicrometerRabbitMqObservationDocumentation.CONSUME_OBSERVATION.observation(observationConvention, DefaultMicrometerConsumeObservationConvention.INSTANCE, () -> context, observationRegistry); + observation.observeChecked(() -> delegate.handleDelivery(consumerTag, envelope, properties, body)); + } + } + } diff --git a/src/main/java/com/rabbitmq/client/impl/MicrometerPublishContext.java b/src/main/java/com/rabbitmq/client/impl/MicrometerPublishContext.java new file mode 100644 index 0000000000..72b1e83c01 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/MicrometerPublishContext.java @@ -0,0 +1,59 @@ +/* + * Copyright 2022 VMware, Inc. + * + * Licensed 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 + * + * https://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 com.rabbitmq.client.impl; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.MetricsCollector; +import io.micrometer.observation.transport.SenderContext; + +/** + * {@link io.micrometer.observation.Observation.Context} for use with RabbitMQ client + * {@link io.micrometer.observation.Observation} instrumentation. + * + * @since 6.0.0 + */ +public class MicrometerPublishContext extends SenderContext { + + private final MetricsCollector.PublishArguments publishArguments; + + private final AMQP.BasicProperties.Builder builder; + + public MicrometerPublishContext(MetricsCollector.PublishArguments publishArguments) { + super((basicProperties, key, value) -> { + Map headers = publishArguments.getHeaders(); + headers.put(key, value); + Objects.requireNonNull(basicProperties, "Properties must not be null").headers(headers); + }); + this.publishArguments = publishArguments; + this.builder = publishArguments.getProps().builder(); + if (publishArguments.getProps().getHeaders() == null) { + this.builder.headers(new HashMap<>()); + } + setCarrier(this.builder); + } + + public MetricsCollector.PublishArguments getPublishArguments() { + return publishArguments; + } + + public AMQP.BasicProperties.Builder getPropertiesBuilder() { + return builder; + } +} diff --git a/src/main/java/com/rabbitmq/client/impl/MicrometerPublishObservationConvention.java b/src/main/java/com/rabbitmq/client/impl/MicrometerPublishObservationConvention.java new file mode 100644 index 0000000000..8ccb64375f --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/MicrometerPublishObservationConvention.java @@ -0,0 +1,36 @@ +/* + * Copyright 2022 VMware, Inc. + * + * Licensed 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 + * + * https://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 com.rabbitmq.client.impl; + +import io.micrometer.core.instrument.binder.httpcomponents.ApacheHttpClientContext; +import io.micrometer.core.instrument.binder.httpcomponents.DefaultApacheHttpClientObservationConvention; +import io.micrometer.observation.Observation; +import io.micrometer.observation.ObservationConvention; + +/** + * {@link ObservationConvention} for RabbitMQ client instrumentation. + * + * @since 6.0.0 + * @see DefaultMicrometerPublishObservationConvention + */ +public interface MicrometerPublishObservationConvention extends ObservationConvention { + + @Override + default boolean supportsContext(Observation.Context context) { + return context instanceof MicrometerPublishContext; + } + +} diff --git a/src/main/java/com/rabbitmq/client/impl/MicrometerRabbitMqObservationDocumentation.java b/src/main/java/com/rabbitmq/client/impl/MicrometerRabbitMqObservationDocumentation.java new file mode 100644 index 0000000000..63c2a38541 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/impl/MicrometerRabbitMqObservationDocumentation.java @@ -0,0 +1,157 @@ +/* + * Copyright 2022 VMware, Inc. + * + * Licensed 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 + * + * https://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 com.rabbitmq.client.impl; + +import io.micrometer.common.docs.KeyName; +import io.micrometer.observation.Observation; +import io.micrometer.observation.ObservationConvention; +import io.micrometer.observation.docs.ObservationDocumentation; + +/** + * {@link ObservationDocumentation} for RabbitMQ Clients. + * + * @since 6.0.0 + */ +public enum MicrometerRabbitMqObservationDocumentation implements ObservationDocumentation { + + /** + * Observation for Rabbit Client publishers. + */ + PUBLISH_OBSERVATION { + + @Override + public Class> getDefaultConvention() { + return DefaultMicrometerPublishObservationConvention.class; + } + + @Override + public KeyName[] getLowCardinalityKeyNames() { + return LowCardinalityTags.values(); + } + + }, + + /** + * Observation for Rabbit Client consumers. + */ + CONSUME_OBSERVATION { + + @Override + public Class> getDefaultConvention() { + return DefaultMicrometerConsumeObservationConvention.class; + } + + @Override + public KeyName[] getLowCardinalityKeyNames() { + return LowCardinalityTags.values(); + } + + }; + + // SPAN NAME + // + // topic with spaces process + // (anonymous) publish ((anonymous) being a stable identifier for an unnamed destination) + // (anonymous) receive ((anonymous) being a stable identifier for an unnamed destination) + + // LOW CARDINALITY + // messaging.system = rabbitmq + // messaging.operation = publish + + // HIGH CARDINALITY + + // messaging.rabbitmq.destination.routing_key + // messaging.destination.anonymous + // messaging.destination.name + // messaging.destination.template + // messaging.destination.temporary + // messaging.batch.message_count + // messaging.message.conversation_id + // messaging.message.id + // messaging.message.payload_compressed_size_bytes + // messaging.message.payload_size_bytes + + // net.peer.name + // net.protocol.name + // net.protocol.version + // net.sock.family + // net.sock.peer.addr + // net.sock.peer.name + // net.sock.peer.port + + /** + * Low cardinality tags. + */ + public enum LowCardinalityTags implements KeyName { + + /** + * A string identifying the messaging system. + */ + MESSAGING_SYSTEM { + + @Override + public String asString() { + return "messaging.system"; + } + + }, + + /** + * A string identifying the kind of messaging operation. + */ + MESSAGING_OPERATION { + + @Override + public String asString() { + return "messaging.operation"; + } + + } + + } + + /** + * High cardinality tags. + */ + public enum HighCardinalityTags implements KeyName { + + /** + * The message destination name. + */ + MESSAGING_DESTINATION_NAME { + + @Override + public String asString() { + return "messaging.destination.name"; + } + + }, + + /** + * RabbitMQ message routing key. + */ + MESSAGING_ROUTING_KEY { + + @Override + public String asString() { + return "messaging.rabbitmq.destination.routing_key"; + } + + } + + } + +} diff --git a/src/test/java/com/rabbitmq/client/test/functional/FunctionalTestSuite.java b/src/test/java/com/rabbitmq/client/test/functional/FunctionalTestSuite.java index bbf06691e1..eb1ac8d3aa 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/FunctionalTestSuite.java +++ b/src/test/java/com/rabbitmq/client/test/functional/FunctionalTestSuite.java @@ -76,6 +76,7 @@ Nack.class, ExceptionMessages.class, Metrics.class, + MicrometerMetrics.class, TopologyRecoveryFiltering.class, TopologyRecoveryRetry.class }) diff --git a/src/test/java/com/rabbitmq/client/test/functional/MicrometerMetrics.java b/src/test/java/com/rabbitmq/client/test/functional/MicrometerMetrics.java new file mode 100644 index 0000000000..1cb0b240f9 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/functional/MicrometerMetrics.java @@ -0,0 +1,144 @@ +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.test.functional; + +import java.io.IOException; +import java.time.Duration; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.DefaultConsumer; +import com.rabbitmq.client.Envelope; +import com.rabbitmq.client.impl.MicrometerMetricsCollector; +import com.rabbitmq.client.test.BrokerTestCase; +import com.rabbitmq.client.test.TestUtils; +import io.micrometer.tracing.Span; +import io.micrometer.tracing.Tracer; +import io.micrometer.tracing.test.SampleTestRunner; +import org.junit.jupiter.api.Nested; + +import static com.rabbitmq.client.test.TestUtils.waitAtMost; +import static org.assertj.core.api.Assertions.assertThat; + +public class MicrometerMetrics extends BrokerTestCase { + + static final String QUEUE = "metrics.queue"; + + @Override + protected void createResources() throws IOException { + channel.queueDeclare(QUEUE, true, false, false, null); + } + + @Override + protected void releaseResources() throws IOException { + channel.queueDelete(QUEUE); + } + + + @Nested + class IntegrationTest extends SampleTestRunner { + + @Override + public TracingSetup[] getTracingSetup() { + return new TracingSetup[] { TracingSetup.IN_MEMORY_BRAVE, TracingSetup.ZIPKIN_BRAVE }; + } + + @Override + public SampleTestRunnerConsumer yourCode() throws Exception { + return (buildingBlocks, meterRegistry) -> { + ConnectionFactory connectionFactory = createConnectionFactory(); + MicrometerMetricsCollector collector = new MicrometerMetricsCollector(meterRegistry); + collector.setObservationRegistry(getObservationRegistry()); + connectionFactory.setMetricsCollector(collector); + Connection connection1 = null; + try { + connection1 = connectionFactory.newConnection(); + Channel channel = connection1.createChannel(); + + sendMessage(channel); + + TestingConsumer testingConsumer = new TestingConsumer(channel, buildingBlocks.getTracer(), buildingBlocks.getTracer().currentSpan()); + channel.basicConsume(QUEUE, true, testingConsumer); + waitAtMost(timeout(), () -> testingConsumer.executed); + waitAtMost(timeout(), () -> testingConsumer.assertionsPassed); + getMeterRegistry().get("rabbit.publish") + .tag("messaging.operation", "publish") + .tag("messaging.system", "rabbitmq") + .timer(); + getMeterRegistry().get("rabbit.consume") + .tag("messaging.operation", "publish") + .tag("messaging.system", "rabbitmq") + .timer(); + } finally { + safeClose(connection1); + } + }; + } + } + + private Duration timeout() { + return Duration.ofSeconds(10); + } + + private static ConnectionFactory createConnectionFactory() { + ConnectionFactory connectionFactory = TestUtils.connectionFactory(); + connectionFactory.setAutomaticRecoveryEnabled(false); + return connectionFactory; + } + + private void safeClose(Connection connection) { + if(connection != null) { + try { + connection.abort(); + } catch (Exception e) { + // OK + } + } + } + + private void sendMessage(Channel channel) throws IOException { + channel.basicPublish("", QUEUE, null, "msg".getBytes("UTF-8")); + } + + static class TestingConsumer extends DefaultConsumer { + + volatile boolean executed; + + volatile boolean assertionsPassed; + + private final Tracer tracer; + + private final Span rootSpan; + + public TestingConsumer(Channel channel, Tracer tracer, Span rootSpan) { + super(channel); + this.tracer = tracer; + this.rootSpan = rootSpan; + } + + @Override + public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { + executed = true; + assertThat(tracer.currentSpan()).as("Span must be put in scope").isNotNull(); + assertThat(tracer.currentSpan().context().traceId()).as("Trace id must be propagated").isEqualTo(rootSpan.context().traceId()); + System.out.println("Current span [" + tracer.currentSpan() + "]"); + assertionsPassed = true; + } + } + +} From 590aa06f6be2da6cbf21ee5ae4fb09e8a132e4b0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Apr 2023 01:13:18 +0000 Subject: [PATCH 1743/2114] Bump jackson-databind from 2.14.1 to 2.15.0 Bumps [jackson-databind](https://github.com/FasterXML/jackson) from 2.14.1 to 2.15.0. - [Release notes](https://github.com/FasterXML/jackson/releases) - [Commits](https://github.com/FasterXML/jackson/commits) --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-databind dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f3dc64e781..b26ad1763e 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,8 @@ 1.7.36 4.2.19 1.11.1 - 1.27.0 + 1.1.4 + 1.28.0 1.1.4 2.15.2 1.2.12 From 0bd5372b78a85e54545036c1fa25b29e5da0ce2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 2 May 2023 17:34:58 +0200 Subject: [PATCH 1744/2114] Introduce ObservationCollector --- .../rabbitmq/client/ConnectionFactory.java | 16 +- .../com/rabbitmq/client/MetricsCollector.java | 73 +------- .../rabbitmq/client/impl/AMQConnection.java | 12 +- .../rabbitmq/client/impl/ChannelManager.java | 14 +- .../com/rabbitmq/client/impl/ChannelN.java | 26 +-- ...icrometerConsumeObservationConvention.java | 65 ------- ...icrometerPublishObservationConvention.java | 65 ------- .../client/impl/MicrometerConsumeContext.java | 69 -------- ...icrometerConsumeObservationConvention.java | 34 ---- .../impl/MicrometerMetricsCollector.java | 124 +------------ .../client/impl/MicrometerPublishContext.java | 59 ------- ...icrometerPublishObservationConvention.java | 36 ---- ...meterRabbitMqObservationDocumentation.java | 157 ----------------- .../recovery/AutorecoveringConnection.java | 13 +- .../recovery/RecoveryAwareAMQConnection.java | 13 +- .../RecoveryAwareAMQConnectionFactory.java | 17 +- .../recovery/RecoveryAwareChannelManager.java | 14 +- .../impl/recovery/RecoveryAwareChannelN.java | 12 +- .../observation/NoOpObservationCollector.java | 34 ++++ .../observation/ObservationCollector.java | 39 +++++ .../micrometer/ConsumeContext.java | 53 ++++++ .../ConsumeObservationConvention.java | 33 ++++ .../DefaultConsumeObservationConvention.java | 68 ++++++++ .../DefaultPublishObservationConvention.java | 68 ++++++++ .../MicrometerObservationCollector.java | 162 +++++++++++++++++ ...MicrometerObservationCollectorBuilder.java | 72 ++++++++ .../micrometer/PublishContext.java | 46 +++++ .../PublishObservationConvention.java | 33 ++++ .../RabbitMqObservationDocumentation.java | 134 ++++++++++++++ .../AMQConnectionRefreshCredentialsTest.java | 3 +- .../test/functional/FunctionalTestSuite.java | 2 +- .../test/functional/MicrometerMetrics.java | 144 --------------- ...MicrometerObservationCollectorMetrics.java | 164 ++++++++++++++++++ 33 files changed, 1006 insertions(+), 868 deletions(-) delete mode 100644 src/main/java/com/rabbitmq/client/impl/DefaultMicrometerConsumeObservationConvention.java delete mode 100644 src/main/java/com/rabbitmq/client/impl/DefaultMicrometerPublishObservationConvention.java delete mode 100644 src/main/java/com/rabbitmq/client/impl/MicrometerConsumeContext.java delete mode 100644 src/main/java/com/rabbitmq/client/impl/MicrometerConsumeObservationConvention.java delete mode 100644 src/main/java/com/rabbitmq/client/impl/MicrometerPublishContext.java delete mode 100644 src/main/java/com/rabbitmq/client/impl/MicrometerPublishObservationConvention.java delete mode 100644 src/main/java/com/rabbitmq/client/impl/MicrometerRabbitMqObservationDocumentation.java create mode 100644 src/main/java/com/rabbitmq/client/observation/NoOpObservationCollector.java create mode 100644 src/main/java/com/rabbitmq/client/observation/ObservationCollector.java create mode 100644 src/main/java/com/rabbitmq/client/observation/micrometer/ConsumeContext.java create mode 100644 src/main/java/com/rabbitmq/client/observation/micrometer/ConsumeObservationConvention.java create mode 100644 src/main/java/com/rabbitmq/client/observation/micrometer/DefaultConsumeObservationConvention.java create mode 100644 src/main/java/com/rabbitmq/client/observation/micrometer/DefaultPublishObservationConvention.java create mode 100644 src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java create mode 100644 src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollectorBuilder.java create mode 100644 src/main/java/com/rabbitmq/client/observation/micrometer/PublishContext.java create mode 100644 src/main/java/com/rabbitmq/client/observation/micrometer/PublishObservationConvention.java create mode 100644 src/main/java/com/rabbitmq/client/observation/micrometer/RabbitMqObservationDocumentation.java delete mode 100644 src/test/java/com/rabbitmq/client/test/functional/MicrometerMetrics.java create mode 100644 src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index edbd8c4196..34b4eb0d66 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -22,6 +22,7 @@ import com.rabbitmq.client.impl.recovery.RecoveredQueueNameSupplier; import com.rabbitmq.client.impl.recovery.RetryHandler; import com.rabbitmq.client.impl.recovery.TopologyRecoveryFilter; +import com.rabbitmq.client.observation.ObservationCollector; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -138,6 +139,7 @@ public class ConnectionFactory implements Cloneable { private RecoveryDelayHandler recoveryDelayHandler; private MetricsCollector metricsCollector; + private ObservationCollector observationCollector = ObservationCollector.NO_OP; private boolean nio = false; private FrameHandlerFactory frameHandlerFactory; @@ -978,6 +980,15 @@ public MetricsCollector getMetricsCollector() { return metricsCollector; } + /** + * + * @since 5.18.0 + * @param observationCollector + */ + public void setObservationCollector(ObservationCollector observationCollector) { + this.observationCollector = observationCollector; + } + /** * Set a {@link CredentialsRefreshService} instance to handle credentials refresh if appropriate. *

@@ -1249,7 +1260,8 @@ public Connection newConnection(ExecutorService executor, AddressResolver addres // see com.rabbitmq.client.impl.recovery.RecoveryAwareAMQConnectionFactory#newConnection // No Sonar: no need to close this resource because we're the one that creates it // and hands it over to the user - AutorecoveringConnection conn = new AutorecoveringConnection(params, fhFactory, addressResolver, metricsCollector); //NOSONAR + AutorecoveringConnection conn = new AutorecoveringConnection( + params, fhFactory, addressResolver, metricsCollector, observationCollector); //NOSONAR conn.init(); return conn; @@ -1316,7 +1328,7 @@ public ConnectionParams params(ExecutorService consumerWorkServiceExecutor) { } protected AMQConnection createConnection(ConnectionParams params, FrameHandler frameHandler, MetricsCollector metricsCollector) { - return new AMQConnection(params, frameHandler, metricsCollector); + return new AMQConnection(params, frameHandler, metricsCollector, observationCollector); } /** diff --git a/src/main/java/com/rabbitmq/client/MetricsCollector.java b/src/main/java/com/rabbitmq/client/MetricsCollector.java index 286bd23040..a83bc8783c 100644 --- a/src/main/java/com/rabbitmq/client/MetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/MetricsCollector.java @@ -15,12 +15,6 @@ package com.rabbitmq.client; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; - -import com.rabbitmq.client.impl.AMQCommand; - /** * Interface to gather execution data of the client. * Note transactions are not supported: they deal with @@ -70,71 +64,6 @@ default void basicPublishUnrouted(Channel channel) { void basicConsume(Channel channel, String consumerTag, boolean autoAck); - default Consumer basicPreConsume(Channel channel, String consumerTag, boolean autoAck, AMQCommand amqCommand, Consumer callback) { - return callback; - } - void basicCancel(Channel channel, String consumerTag); - default void basicPrePublish(Channel channel, long deliveryTag, PublishArguments publishArguments) { - - } - - default void basicPublishFailure(Channel channel, Exception exception, PublishArguments publishArguments) { - basicPublishFailure(channel, exception); - } - - default void basicPublish(Channel channel, long deliveryTag, PublishArguments publishArguments) { - basicPublish(channel, deliveryTag); - } - - class PublishArguments { - private AMQP.Basic.Publish publish; - - private AMQP.BasicProperties props; - - private byte[] body; - - private final Map headers = new HashMap<>(); - - private final Map context = new HashMap<>(); - - public PublishArguments(AMQP.Basic.Publish publish, AMQP.BasicProperties props, byte[] body) { - this.publish = Objects.requireNonNull(publish); - this.props = Objects.requireNonNull(props); - this.body = Objects.requireNonNull(body); - } - - public AMQP.Basic.Publish getPublish() { - return publish; - } - - public AMQP.BasicProperties getProps() { - return props; - } - - public byte[] getBody() { - return body; - } - - public void setPublish(AMQP.Basic.Publish publish) { - this.publish = publish; - } - - public void setProps(AMQP.BasicProperties props) { - this.props = props; - } - - public void setBody(byte[] body) { - this.body = body; - } - - public Map getContext() { - return context; - } - - public Map getHeaders() { - return headers; - } - } -} +} \ No newline at end of file diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index 3528d9c806..031374a544 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -19,6 +19,7 @@ import com.rabbitmq.client.*; import com.rabbitmq.client.impl.AMQChannel.BlockingRpcContinuation; import com.rabbitmq.client.impl.recovery.RecoveryCanBeginListener; +import com.rabbitmq.client.observation.ObservationCollector; import com.rabbitmq.utility.BlockingCell; import com.rabbitmq.utility.Utility; import org.slf4j.Logger; @@ -140,6 +141,7 @@ public static Map defaultClientProperties() { private final CredentialsProvider credentialsProvider; private final Collection blockedListeners = new CopyOnWriteArrayList<>(); protected final MetricsCollector metricsCollector; + protected final ObservationCollector observationCollector; private final int channelRpcTimeout; private final boolean channelShouldCheckRpcResponseType; private final TrafficListener trafficListener; @@ -210,13 +212,14 @@ public Map getServerProperties() { } public AMQConnection(ConnectionParams params, FrameHandler frameHandler) { - this(params, frameHandler, new NoOpMetricsCollector()); + this(params, frameHandler, new NoOpMetricsCollector(), ObservationCollector.NO_OP); } /** Construct a new connection * @param params parameters for it */ - public AMQConnection(ConnectionParams params, FrameHandler frameHandler, MetricsCollector metricsCollector) + public AMQConnection(ConnectionParams params, FrameHandler frameHandler, + MetricsCollector metricsCollector, ObservationCollector observationCollector) { checkPreconditions(); this.credentialsProvider = params.getCredentialsProvider(); @@ -255,6 +258,7 @@ public AMQConnection(ConnectionParams params, FrameHandler frameHandler, Metrics this._inConnectionNegotiation = true; // we start out waiting for the first protocol response this.metricsCollector = metricsCollector; + this.observationCollector = observationCollector; this.errorOnWriteListener = params.getErrorOnWriteListener() != null ? params.getErrorOnWriteListener() : (connection, exception) -> { throw exception; }; // we just propagate the exception for non-recoverable connections @@ -475,7 +479,9 @@ public void start() } protected ChannelManager instantiateChannelManager(int channelMax, ThreadFactory threadFactory) { - ChannelManager result = new ChannelManager(this._workService, channelMax, threadFactory, this.metricsCollector); + ChannelManager result = new ChannelManager( + this._workService, channelMax, threadFactory, + this.metricsCollector, this.observationCollector); configureChannelManager(result); return result; } diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelManager.java b/src/main/java/com/rabbitmq/client/impl/ChannelManager.java index fb0490eade..29c814ac41 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelManager.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelManager.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -19,6 +19,7 @@ import com.rabbitmq.client.MetricsCollector; import com.rabbitmq.client.NoOpMetricsCollector; import com.rabbitmq.client.ShutdownSignalException; +import com.rabbitmq.client.observation.ObservationCollector; import com.rabbitmq.utility.IntAllocator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -55,6 +56,7 @@ public class ChannelManager { private int channelShutdownTimeout = (int) ((ConnectionFactory.DEFAULT_HEARTBEAT * AMQConnection.CHANNEL_SHUTDOWN_TIMEOUT_MULTIPLIER) * 1000); protected final MetricsCollector metricsCollector; + protected final ObservationCollector observationCollector; public int getChannelMax(){ return _channelMax; @@ -65,11 +67,13 @@ public ChannelManager(ConsumerWorkService workService, int channelMax) { } public ChannelManager(ConsumerWorkService workService, int channelMax, ThreadFactory threadFactory) { - this(workService, channelMax, threadFactory, new NoOpMetricsCollector()); + this(workService, channelMax, threadFactory, + new NoOpMetricsCollector(), ObservationCollector.NO_OP); } - public ChannelManager(ConsumerWorkService workService, int channelMax, ThreadFactory threadFactory, MetricsCollector metricsCollector) { + public ChannelManager(ConsumerWorkService workService, int channelMax, ThreadFactory threadFactory, + MetricsCollector metricsCollector, ObservationCollector observationCollector) { if (channelMax < 0) throw new IllegalArgumentException("create ChannelManager: 'channelMax' must be greater or equal to 0."); if (channelMax == 0) { @@ -83,6 +87,7 @@ public ChannelManager(ConsumerWorkService workService, int channelMax, ThreadFac this.workService = workService; this.threadFactory = threadFactory; this.metricsCollector = metricsCollector; + this.observationCollector = observationCollector; } /** @@ -214,7 +219,8 @@ private ChannelN addNewChannel(AMQConnection connection, int channelNumber) { } protected ChannelN instantiateChannel(AMQConnection connection, int channelNumber, ConsumerWorkService workService) { - return new ChannelN(connection, channelNumber, workService, this.metricsCollector); + return new ChannelN(connection, channelNumber, workService, + this.metricsCollector, this.observationCollector); } /** diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java index c41c807df7..1769bc8da4 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelN.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -22,6 +22,7 @@ import com.rabbitmq.client.impl.AMQImpl.Channel; import com.rabbitmq.client.impl.AMQImpl.Queue; import com.rabbitmq.client.impl.AMQImpl.*; +import com.rabbitmq.client.observation.ObservationCollector; import com.rabbitmq.utility.Utility; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -89,6 +90,7 @@ public class ChannelN extends AMQChannel implements com.rabbitmq.client.Channel private volatile boolean onlyAcksReceived = true; protected final MetricsCollector metricsCollector; + private final ObservationCollector observationCollector; /** * Construct a new channel on the given connection with the given @@ -101,7 +103,8 @@ public class ChannelN extends AMQChannel implements com.rabbitmq.client.Channel */ public ChannelN(AMQConnection connection, int channelNumber, ConsumerWorkService workService) { - this(connection, channelNumber, workService, new NoOpMetricsCollector()); + this(connection, channelNumber, workService, + new NoOpMetricsCollector(), ObservationCollector.NO_OP); } /** @@ -115,10 +118,12 @@ public ChannelN(AMQConnection connection, int channelNumber, * @param metricsCollector service for managing metrics */ public ChannelN(AMQConnection connection, int channelNumber, - ConsumerWorkService workService, MetricsCollector metricsCollector) { + ConsumerWorkService workService, + MetricsCollector metricsCollector, ObservationCollector observationCollector) { super(connection, channelNumber); this.dispatcher = new ConsumerDispatcher(connection, this, workService); this.metricsCollector = metricsCollector; + this.observationCollector = observationCollector; } /** @@ -706,16 +711,17 @@ public void basicPublish(String exchange, String routingKey, .mandatory(mandatory) .immediate(immediate) .build(); - MetricsCollector.PublishArguments args = new MetricsCollector.PublishArguments(publish, props, body); try { - metricsCollector.basicPrePublish(this, deliveryTag, args); - AMQCommand command = new AMQCommand(args.getPublish(), args.getProps(), args.getBody()); - transmit(command); + ObservationCollector.PublishCall publishCall = properties -> { + AMQCommand command = new AMQCommand(publish, properties, body); + transmit(command); + }; + observationCollector.publish(publishCall, publish, props); } catch (IOException | AlreadyClosedException e) { - metricsCollector.basicPublishFailure(this, e, args); + metricsCollector.basicPublishFailure(this, e); throw e; } - metricsCollector.basicPublish(this, deliveryTag, args); + metricsCollector.basicPublish(this, deliveryTag); } /** Public API - {@inheritDoc} */ @@ -1360,7 +1366,7 @@ public String basicConsume(String queue, final boolean autoAck, String consumerT @Override public String transformReply(AMQCommand replyCommand) { String actualConsumerTag = ((Basic.ConsumeOk) replyCommand.getMethod()).getConsumerTag(); - Consumer wrappedCallback = metricsCollector.basicPreConsume(ChannelN.this, actualConsumerTag, autoAck, replyCommand, callback); + Consumer wrappedCallback = observationCollector.basicConsume(callback); _consumers.put(actualConsumerTag, wrappedCallback); // need to register consumer in stats before it actually starts consuming diff --git a/src/main/java/com/rabbitmq/client/impl/DefaultMicrometerConsumeObservationConvention.java b/src/main/java/com/rabbitmq/client/impl/DefaultMicrometerConsumeObservationConvention.java deleted file mode 100644 index c346009d17..0000000000 --- a/src/main/java/com/rabbitmq/client/impl/DefaultMicrometerConsumeObservationConvention.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2022 VMware, Inc. - * - * Licensed 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 - * - * https://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 com.rabbitmq.client.impl; - -import com.rabbitmq.client.impl.MicrometerRabbitMqObservationDocumentation.HighCardinalityTags; -import com.rabbitmq.client.impl.MicrometerRabbitMqObservationDocumentation.LowCardinalityTags; -import io.micrometer.common.KeyValues; -import io.micrometer.common.util.StringUtils; - -/** - * Default implementation of {@link MicrometerConsumeObservationConvention}. - * - * @since 6.0.0 - * @see MicrometerConsumeObservationConvention - */ -public class DefaultMicrometerConsumeObservationConvention implements MicrometerConsumeObservationConvention { - - /** - * Singleton instance of this convention. - */ - public static final DefaultMicrometerConsumeObservationConvention INSTANCE = new DefaultMicrometerConsumeObservationConvention(); - - // There is no need to instantiate this class multiple times, but it may be extended, - // hence protected visibility. - protected DefaultMicrometerConsumeObservationConvention() { - } - - @Override - public String getName() { - return "rabbit.consume"; // TODO: How should we call this - } - - @Override - public String getContextualName(MicrometerConsumeContext context) { - return destination(context.getEnvelope().getRoutingKey()) + " consume"; - } - - private String destination(String destination) { - return StringUtils.isNotBlank(destination) ? destination : "(anonymous)"; - } - - @Override - public KeyValues getLowCardinalityKeyValues(MicrometerConsumeContext context) { - return KeyValues.of(LowCardinalityTags.MESSAGING_OPERATION.withValue("publish"), LowCardinalityTags.MESSAGING_SYSTEM.withValue("rabbitmq")); - } - - @Override - public KeyValues getHighCardinalityKeyValues(MicrometerConsumeContext context) { - return KeyValues.of(HighCardinalityTags.MESSAGING_ROUTING_KEY.withValue(context.getEnvelope().getRoutingKey()), HighCardinalityTags.MESSAGING_DESTINATION_NAME.withValue(context.getEnvelope().getExchange())); - } - -} diff --git a/src/main/java/com/rabbitmq/client/impl/DefaultMicrometerPublishObservationConvention.java b/src/main/java/com/rabbitmq/client/impl/DefaultMicrometerPublishObservationConvention.java deleted file mode 100644 index 4dc04e2d4a..0000000000 --- a/src/main/java/com/rabbitmq/client/impl/DefaultMicrometerPublishObservationConvention.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2022 VMware, Inc. - * - * Licensed 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 - * - * https://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 com.rabbitmq.client.impl; - -import com.rabbitmq.client.impl.MicrometerRabbitMqObservationDocumentation.HighCardinalityTags; -import com.rabbitmq.client.impl.MicrometerRabbitMqObservationDocumentation.LowCardinalityTags; -import io.micrometer.common.KeyValues; -import io.micrometer.common.util.StringUtils; - -/** - * Default implementation of {@link MicrometerPublishObservationConvention}. - * - * @since 6.0.0 - * @see MicrometerRabbitMqObservationDocumentation - */ -public class DefaultMicrometerPublishObservationConvention implements MicrometerPublishObservationConvention { - - /** - * Singleton instance of this convention. - */ - public static final DefaultMicrometerPublishObservationConvention INSTANCE = new DefaultMicrometerPublishObservationConvention(); - - // There is no need to instantiate this class multiple times, but it may be extended, - // hence protected visibility. - protected DefaultMicrometerPublishObservationConvention() { - } - - @Override - public String getName() { - return "rabbit.publish"; // TODO: How should we call this - } - - @Override - public String getContextualName(MicrometerPublishContext context) { - return destination(context.getPublishArguments().getPublish().getRoutingKey()) + " publish"; - } - - private String destination(String destination) { - return StringUtils.isNotBlank(destination) ? destination : "(anonymous)"; - } - - @Override - public KeyValues getLowCardinalityKeyValues(MicrometerPublishContext context) { - return KeyValues.of(LowCardinalityTags.MESSAGING_OPERATION.withValue("publish"), LowCardinalityTags.MESSAGING_SYSTEM.withValue("rabbitmq")); - } - - @Override - public KeyValues getHighCardinalityKeyValues(MicrometerPublishContext context) { - return KeyValues.of(HighCardinalityTags.MESSAGING_ROUTING_KEY.withValue(context.getPublishArguments().getPublish().getRoutingKey()), HighCardinalityTags.MESSAGING_DESTINATION_NAME.withValue(context.getPublishArguments().getPublish().getExchange())); - } - -} diff --git a/src/main/java/com/rabbitmq/client/impl/MicrometerConsumeContext.java b/src/main/java/com/rabbitmq/client/impl/MicrometerConsumeContext.java deleted file mode 100644 index c141c2eb32..0000000000 --- a/src/main/java/com/rabbitmq/client/impl/MicrometerConsumeContext.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2022 VMware, Inc. - * - * Licensed 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 - * - * https://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 com.rabbitmq.client.impl; - -import java.util.Objects; - -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.Envelope; -import io.micrometer.observation.transport.ReceiverContext; - -/** - * {@link io.micrometer.observation.Observation.Context} for use with RabbitMQ client - * {@link io.micrometer.observation.Observation} instrumentation. - * - * @since 6.0.0 - */ -public class MicrometerConsumeContext extends ReceiverContext { - - private final String consumerTag; - private final Envelope envelope; - - private final AMQP.BasicProperties properties; - - private final byte[] body; - - public MicrometerConsumeContext(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) { - super((props, key) -> { - Object result = Objects.requireNonNull(props).getHeaders().get(key); - if (result == null) { - return null; - } - return String.valueOf(result); - }); - this.consumerTag = consumerTag; - this.envelope = envelope; - this.properties = properties; - this.body = body; - setCarrier(properties); - } - - public String getConsumerTag() { - return consumerTag; - } - - public Envelope getEnvelope() { - return envelope; - } - - public AMQP.BasicProperties getProperties() { - return properties; - } - - public byte[] getBody() { - return body; - } -} diff --git a/src/main/java/com/rabbitmq/client/impl/MicrometerConsumeObservationConvention.java b/src/main/java/com/rabbitmq/client/impl/MicrometerConsumeObservationConvention.java deleted file mode 100644 index 01dd6612af..0000000000 --- a/src/main/java/com/rabbitmq/client/impl/MicrometerConsumeObservationConvention.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2022 VMware, Inc. - * - * Licensed 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 - * - * https://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 com.rabbitmq.client.impl; - -import io.micrometer.observation.Observation; -import io.micrometer.observation.ObservationConvention; - -/** - * {@link ObservationConvention} for RabbitMQ client instrumentation. - * - * @since 6.0.0 - * @see DefaultMicrometerPublishObservationConvention - */ -public interface MicrometerConsumeObservationConvention extends ObservationConvention { - - @Override - default boolean supportsContext(Observation.Context context) { - return context instanceof MicrometerConsumeContext; - } - -} diff --git a/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java index 1ca1bcb23a..1be16536ae 100644 --- a/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java @@ -15,22 +15,14 @@ package com.rabbitmq.client.impl; -import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; -import com.rabbitmq.client.Consumer; -import com.rabbitmq.client.Envelope; import com.rabbitmq.client.MetricsCollector; -import com.rabbitmq.client.ShutdownSignalException; -import io.micrometer.common.lang.Nullable; import io.micrometer.core.instrument.Counter; import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.Tag; import io.micrometer.core.instrument.Tags; -import io.micrometer.observation.Observation; -import io.micrometer.observation.ObservationRegistry; -import java.io.IOException; import java.util.Collections; import java.util.concurrent.atomic.AtomicLong; import java.util.function.Function; @@ -51,8 +43,6 @@ */ public class MicrometerMetricsCollector extends AbstractMetricsCollector { - private static final String MICROMETER_OBSERVATION_KEY = "micrometer.observation"; - private final AtomicLong connections; private final AtomicLong channels; @@ -73,12 +63,6 @@ public class MicrometerMetricsCollector extends AbstractMetricsCollector { private final Counter rejectedMessages; - private MicrometerPublishObservationConvention publishObservationConvention; - - private MicrometerConsumeObservationConvention consumeObservationConvention; - - private ObservationRegistry observationRegistry = ObservationRegistry.NOOP; - public MicrometerMetricsCollector(MeterRegistry registry) { this(registry, "rabbitmq"); } @@ -168,53 +152,6 @@ protected void markPublishedMessageUnrouted() { unroutedPublishedMessages.increment(); } - @Override - public void basicPrePublish(Channel channel, long deliveryTag, PublishArguments publishArguments) { - if (observationRegistry.isNoop()) { - return; - } - // TODO: Is this for fire and forget or request reply too? If r-r then we have to have 2 contexts - MicrometerPublishContext micrometerPublishContext = new MicrometerPublishContext(publishArguments); - Observation observation = MicrometerRabbitMqObservationDocumentation.PUBLISH_OBSERVATION.observation(this.publishObservationConvention, DefaultMicrometerPublishObservationConvention.INSTANCE, () -> micrometerPublishContext, observationRegistry); - publishArguments.getContext().put(MICROMETER_OBSERVATION_KEY, observation.start()); - publishArguments.setProps(micrometerPublishContext.getPropertiesBuilder().build()); - } - - @Override - public void basicPublishFailure(Channel channel, Exception exception, PublishArguments publishArguments) { - if (observationRegistry.isNoop()) { - super.basicPublishFailure(channel, exception); // TODO: Do we want both the observation and the metrics? - return; - } - Observation observation = getObservation(publishArguments); - if (observation == null) { - return; - } - observation.error(exception); - } - - @Override - public void basicPublish(Channel channel, long deliveryTag, PublishArguments publishArguments) { - if (observationRegistry.isNoop()) { - super.basicPublish(channel, deliveryTag); // TODO: Do we want both the observation and the metrics? - return; - } - Observation observation = getObservation(publishArguments); - if (observation == null) { - return; - } - observation.stop(); - } - - @Override - public Consumer basicPreConsume(Channel channel, String consumerTag, boolean autoAck, AMQCommand amqCommand, Consumer callback) { - return new ObservationConsumer(callback, observationRegistry, consumeObservationConvention); - } - - private static Observation getObservation(PublishArguments publishArguments) { - return (Observation) publishArguments.getContext().get(MICROMETER_OBSERVATION_KEY); - } - public AtomicLong getConnections() { return connections; } @@ -255,18 +192,6 @@ public Counter getRejectedMessages() { return rejectedMessages; } - public void setPublishObservationConvention(MicrometerPublishObservationConvention publishObservationConvention) { - this.publishObservationConvention = publishObservationConvention; - } - - public void setConsumeObservationConvention(MicrometerConsumeObservationConvention consumeObservationConvention) { - this.consumeObservationConvention = consumeObservationConvention; - } - - public void setObservationRegistry(ObservationRegistry observationRegistry) { - this.observationRegistry = observationRegistry; - } - public enum Metrics { CONNECTIONS { @Override @@ -333,51 +258,4 @@ Object create(MeterRegistry registry, String prefix, Iterable tags) { } - private static class ObservationConsumer implements Consumer { - - private final Consumer delegate; - - private final ObservationRegistry observationRegistry; - - private final MicrometerConsumeObservationConvention observationConvention; - - ObservationConsumer(Consumer delegate, ObservationRegistry observationRegistry, @Nullable MicrometerConsumeObservationConvention observationConvention) { - this.delegate = delegate; - this.observationRegistry = observationRegistry; - this.observationConvention = observationConvention; - } - - @Override - public void handleConsumeOk(String consumerTag) { - delegate.handleConsumeOk(consumerTag); - } - - @Override - public void handleCancelOk(String consumerTag) { - delegate.handleCancelOk(consumerTag); - } - - @Override - public void handleCancel(String consumerTag) throws IOException { - delegate.handleCancel(consumerTag); - } - - @Override - public void handleShutdownSignal(String consumerTag, ShutdownSignalException sig) { - delegate.handleShutdownSignal(consumerTag, sig); - } - - @Override - public void handleRecoverOk(String consumerTag) { - delegate.handleRecoverOk(consumerTag); - } - - @Override - public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { - MicrometerConsumeContext context = new MicrometerConsumeContext(consumerTag, envelope, properties, body); - Observation observation = MicrometerRabbitMqObservationDocumentation.CONSUME_OBSERVATION.observation(observationConvention, DefaultMicrometerConsumeObservationConvention.INSTANCE, () -> context, observationRegistry); - observation.observeChecked(() -> delegate.handleDelivery(consumerTag, envelope, properties, body)); - } - } - -} +} \ No newline at end of file diff --git a/src/main/java/com/rabbitmq/client/impl/MicrometerPublishContext.java b/src/main/java/com/rabbitmq/client/impl/MicrometerPublishContext.java deleted file mode 100644 index 72b1e83c01..0000000000 --- a/src/main/java/com/rabbitmq/client/impl/MicrometerPublishContext.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2022 VMware, Inc. - * - * Licensed 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 - * - * https://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 com.rabbitmq.client.impl; - -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; - -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.MetricsCollector; -import io.micrometer.observation.transport.SenderContext; - -/** - * {@link io.micrometer.observation.Observation.Context} for use with RabbitMQ client - * {@link io.micrometer.observation.Observation} instrumentation. - * - * @since 6.0.0 - */ -public class MicrometerPublishContext extends SenderContext { - - private final MetricsCollector.PublishArguments publishArguments; - - private final AMQP.BasicProperties.Builder builder; - - public MicrometerPublishContext(MetricsCollector.PublishArguments publishArguments) { - super((basicProperties, key, value) -> { - Map headers = publishArguments.getHeaders(); - headers.put(key, value); - Objects.requireNonNull(basicProperties, "Properties must not be null").headers(headers); - }); - this.publishArguments = publishArguments; - this.builder = publishArguments.getProps().builder(); - if (publishArguments.getProps().getHeaders() == null) { - this.builder.headers(new HashMap<>()); - } - setCarrier(this.builder); - } - - public MetricsCollector.PublishArguments getPublishArguments() { - return publishArguments; - } - - public AMQP.BasicProperties.Builder getPropertiesBuilder() { - return builder; - } -} diff --git a/src/main/java/com/rabbitmq/client/impl/MicrometerPublishObservationConvention.java b/src/main/java/com/rabbitmq/client/impl/MicrometerPublishObservationConvention.java deleted file mode 100644 index 8ccb64375f..0000000000 --- a/src/main/java/com/rabbitmq/client/impl/MicrometerPublishObservationConvention.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2022 VMware, Inc. - * - * Licensed 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 - * - * https://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 com.rabbitmq.client.impl; - -import io.micrometer.core.instrument.binder.httpcomponents.ApacheHttpClientContext; -import io.micrometer.core.instrument.binder.httpcomponents.DefaultApacheHttpClientObservationConvention; -import io.micrometer.observation.Observation; -import io.micrometer.observation.ObservationConvention; - -/** - * {@link ObservationConvention} for RabbitMQ client instrumentation. - * - * @since 6.0.0 - * @see DefaultMicrometerPublishObservationConvention - */ -public interface MicrometerPublishObservationConvention extends ObservationConvention { - - @Override - default boolean supportsContext(Observation.Context context) { - return context instanceof MicrometerPublishContext; - } - -} diff --git a/src/main/java/com/rabbitmq/client/impl/MicrometerRabbitMqObservationDocumentation.java b/src/main/java/com/rabbitmq/client/impl/MicrometerRabbitMqObservationDocumentation.java deleted file mode 100644 index 63c2a38541..0000000000 --- a/src/main/java/com/rabbitmq/client/impl/MicrometerRabbitMqObservationDocumentation.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright 2022 VMware, Inc. - * - * Licensed 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 - * - * https://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 com.rabbitmq.client.impl; - -import io.micrometer.common.docs.KeyName; -import io.micrometer.observation.Observation; -import io.micrometer.observation.ObservationConvention; -import io.micrometer.observation.docs.ObservationDocumentation; - -/** - * {@link ObservationDocumentation} for RabbitMQ Clients. - * - * @since 6.0.0 - */ -public enum MicrometerRabbitMqObservationDocumentation implements ObservationDocumentation { - - /** - * Observation for Rabbit Client publishers. - */ - PUBLISH_OBSERVATION { - - @Override - public Class> getDefaultConvention() { - return DefaultMicrometerPublishObservationConvention.class; - } - - @Override - public KeyName[] getLowCardinalityKeyNames() { - return LowCardinalityTags.values(); - } - - }, - - /** - * Observation for Rabbit Client consumers. - */ - CONSUME_OBSERVATION { - - @Override - public Class> getDefaultConvention() { - return DefaultMicrometerConsumeObservationConvention.class; - } - - @Override - public KeyName[] getLowCardinalityKeyNames() { - return LowCardinalityTags.values(); - } - - }; - - // SPAN NAME - // - // topic with spaces process - // (anonymous) publish ((anonymous) being a stable identifier for an unnamed destination) - // (anonymous) receive ((anonymous) being a stable identifier for an unnamed destination) - - // LOW CARDINALITY - // messaging.system = rabbitmq - // messaging.operation = publish - - // HIGH CARDINALITY - - // messaging.rabbitmq.destination.routing_key - // messaging.destination.anonymous - // messaging.destination.name - // messaging.destination.template - // messaging.destination.temporary - // messaging.batch.message_count - // messaging.message.conversation_id - // messaging.message.id - // messaging.message.payload_compressed_size_bytes - // messaging.message.payload_size_bytes - - // net.peer.name - // net.protocol.name - // net.protocol.version - // net.sock.family - // net.sock.peer.addr - // net.sock.peer.name - // net.sock.peer.port - - /** - * Low cardinality tags. - */ - public enum LowCardinalityTags implements KeyName { - - /** - * A string identifying the messaging system. - */ - MESSAGING_SYSTEM { - - @Override - public String asString() { - return "messaging.system"; - } - - }, - - /** - * A string identifying the kind of messaging operation. - */ - MESSAGING_OPERATION { - - @Override - public String asString() { - return "messaging.operation"; - } - - } - - } - - /** - * High cardinality tags. - */ - public enum HighCardinalityTags implements KeyName { - - /** - * The message destination name. - */ - MESSAGING_DESTINATION_NAME { - - @Override - public String asString() { - return "messaging.destination.name"; - } - - }, - - /** - * RabbitMQ message routing key. - */ - MESSAGING_ROUTING_KEY { - - @Override - public String asString() { - return "messaging.rabbitmq.destination.routing_key"; - } - - } - - } - -} diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index 7f0e3048b9..261b2058fa 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -20,6 +20,7 @@ import com.rabbitmq.client.impl.ConnectionParams; import com.rabbitmq.client.impl.FrameHandlerFactory; import com.rabbitmq.client.impl.NetworkConnection; +import com.rabbitmq.client.observation.ObservationCollector; import com.rabbitmq.utility.Utility; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -103,11 +104,15 @@ public AutorecoveringConnection(ConnectionParams params, FrameHandlerFactory f, } public AutorecoveringConnection(ConnectionParams params, FrameHandlerFactory f, AddressResolver addressResolver) { - this(params, f, addressResolver, new NoOpMetricsCollector()); + this(params, f, addressResolver, new NoOpMetricsCollector(), ObservationCollector.NO_OP); } - public AutorecoveringConnection(ConnectionParams params, FrameHandlerFactory f, AddressResolver addressResolver, MetricsCollector metricsCollector) { - this.cf = new RecoveryAwareAMQConnectionFactory(params, f, addressResolver, metricsCollector); + public AutorecoveringConnection(ConnectionParams params, FrameHandlerFactory f, AddressResolver addressResolver, + MetricsCollector metricsCollector, ObservationCollector observationCollector) { + this.cf = new RecoveryAwareAMQConnectionFactory( + params, f, addressResolver, + metricsCollector, observationCollector + ); this.params = params; this.connectionRecoveryTriggeringCondition = params.getConnectionRecoveryTriggeringCondition() == null ? diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnection.java index 251f0aaaa1..7060407363 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -19,6 +19,7 @@ import com.rabbitmq.client.impl.AMQConnection; import com.rabbitmq.client.impl.ConnectionParams; import com.rabbitmq.client.impl.FrameHandler; +import com.rabbitmq.client.observation.ObservationCollector; import java.util.concurrent.ThreadFactory; @@ -28,8 +29,9 @@ */ public class RecoveryAwareAMQConnection extends AMQConnection { - public RecoveryAwareAMQConnection(ConnectionParams params, FrameHandler handler, MetricsCollector metricsCollector) { - super(params, handler, metricsCollector); + public RecoveryAwareAMQConnection(ConnectionParams params, FrameHandler handler, + MetricsCollector metricsCollector, ObservationCollector observationCollector) { + super(params, handler, metricsCollector, observationCollector); } public RecoveryAwareAMQConnection(ConnectionParams params, FrameHandler handler) { @@ -38,8 +40,9 @@ public RecoveryAwareAMQConnection(ConnectionParams params, FrameHandler handler) @Override protected RecoveryAwareChannelManager instantiateChannelManager(int channelMax, ThreadFactory threadFactory) { - RecoveryAwareChannelManager recoveryAwareChannelManager = new RecoveryAwareChannelManager(super._workService, channelMax, threadFactory, - this.metricsCollector); + RecoveryAwareChannelManager recoveryAwareChannelManager = new RecoveryAwareChannelManager( + super._workService, channelMax, threadFactory, + this.metricsCollector, this.observationCollector); configureChannelManager(recoveryAwareChannelManager); return recoveryAwareChannelManager; } diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java index 0dc677363f..535330c24e 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -19,6 +19,7 @@ import com.rabbitmq.client.impl.ConnectionParams; import com.rabbitmq.client.impl.FrameHandler; import com.rabbitmq.client.impl.FrameHandlerFactory; +import com.rabbitmq.client.observation.ObservationCollector; import java.io.IOException; import java.util.ArrayList; @@ -32,20 +33,25 @@ public class RecoveryAwareAMQConnectionFactory { private final FrameHandlerFactory factory; private final AddressResolver addressResolver; private final MetricsCollector metricsCollector; + private final ObservationCollector observationCollector; public RecoveryAwareAMQConnectionFactory(ConnectionParams params, FrameHandlerFactory factory, List

addrs) { - this(params, factory, new ListAddressResolver(addrs), new NoOpMetricsCollector()); + this(params, factory, new ListAddressResolver(addrs), new NoOpMetricsCollector(), + ObservationCollector.NO_OP); } public RecoveryAwareAMQConnectionFactory(ConnectionParams params, FrameHandlerFactory factory, AddressResolver addressResolver) { - this(params, factory, addressResolver, new NoOpMetricsCollector()); + this(params, factory, addressResolver, new NoOpMetricsCollector(), + ObservationCollector.NO_OP); } - public RecoveryAwareAMQConnectionFactory(ConnectionParams params, FrameHandlerFactory factory, AddressResolver addressResolver, MetricsCollector metricsCollector) { + public RecoveryAwareAMQConnectionFactory(ConnectionParams params, FrameHandlerFactory factory, AddressResolver addressResolver, + MetricsCollector metricsCollector, ObservationCollector observationCollector) { this.params = params; this.factory = factory; this.addressResolver = addressResolver; this.metricsCollector = metricsCollector; + this.observationCollector = observationCollector; } /** @@ -83,7 +89,8 @@ public RecoveryAwareAMQConnection newConnection() throws IOException, TimeoutExc } protected RecoveryAwareAMQConnection createConnection(ConnectionParams params, FrameHandler handler, MetricsCollector metricsCollector) { - return new RecoveryAwareAMQConnection(params, handler, metricsCollector); + return new RecoveryAwareAMQConnection(params, handler, metricsCollector, + this.observationCollector); } private String connectionName() { diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelManager.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelManager.java index d8aa7123cb..d4208d340b 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelManager.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelManager.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -21,6 +21,7 @@ import com.rabbitmq.client.impl.ChannelManager; import com.rabbitmq.client.impl.ChannelN; import com.rabbitmq.client.impl.ConsumerWorkService; +import com.rabbitmq.client.observation.ObservationCollector; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; @@ -34,15 +35,18 @@ public RecoveryAwareChannelManager(ConsumerWorkService workService, int channelM } public RecoveryAwareChannelManager(ConsumerWorkService workService, int channelMax, ThreadFactory threadFactory) { - super(workService, channelMax, threadFactory, new NoOpMetricsCollector()); + super(workService, channelMax, threadFactory, new NoOpMetricsCollector(), ObservationCollector.NO_OP); } - public RecoveryAwareChannelManager(ConsumerWorkService workService, int channelMax, ThreadFactory threadFactory, MetricsCollector metricsCollector) { - super(workService, channelMax, threadFactory, metricsCollector); + public RecoveryAwareChannelManager(ConsumerWorkService workService, int channelMax, + ThreadFactory threadFactory, MetricsCollector metricsCollector, + ObservationCollector observationCollector) { + super(workService, channelMax, threadFactory, metricsCollector, observationCollector); } @Override protected ChannelN instantiateChannel(AMQConnection connection, int channelNumber, ConsumerWorkService workService) { - return new RecoveryAwareChannelN(connection, channelNumber, workService, this.metricsCollector); + return new RecoveryAwareChannelN(connection, channelNumber, workService, + this.metricsCollector, this.observationCollector); } } diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java index 82ae4cc283..628c802c65 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -23,6 +23,7 @@ import com.rabbitmq.client.impl.ChannelN; import com.rabbitmq.client.impl.ConsumerWorkService; import com.rabbitmq.client.impl.AMQImpl.Basic; +import com.rabbitmq.client.observation.ObservationCollector; import java.io.IOException; @@ -56,7 +57,8 @@ public class RecoveryAwareChannelN extends ChannelN { * @param workService service for managing this channel's consumer callbacks */ public RecoveryAwareChannelN(AMQConnection connection, int channelNumber, ConsumerWorkService workService) { - this(connection, channelNumber, workService, new NoOpMetricsCollector()); + this(connection, channelNumber, workService, new NoOpMetricsCollector(), + ObservationCollector.NO_OP); } /** @@ -69,8 +71,10 @@ public RecoveryAwareChannelN(AMQConnection connection, int channelNumber, Consum * @param workService service for managing this channel's consumer callbacks * @param metricsCollector service for managing metrics */ - public RecoveryAwareChannelN(AMQConnection connection, int channelNumber, ConsumerWorkService workService, MetricsCollector metricsCollector) { - super(connection, channelNumber, workService, metricsCollector); + public RecoveryAwareChannelN(AMQConnection connection, int channelNumber, ConsumerWorkService workService, + MetricsCollector metricsCollector, ObservationCollector observationCollector) { + super(connection, channelNumber, workService, + metricsCollector, observationCollector); } @Override diff --git a/src/main/java/com/rabbitmq/client/observation/NoOpObservationCollector.java b/src/main/java/com/rabbitmq/client/observation/NoOpObservationCollector.java new file mode 100644 index 0000000000..338a4a0480 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/observation/NoOpObservationCollector.java @@ -0,0 +1,34 @@ +// Copyright (c) 2023 VMware, Inc. or its affiliates. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.observation; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Consumer; +import java.io.IOException; + +final class NoOpObservationCollector implements ObservationCollector { + + @Override + public void publish(PublishCall call, AMQP.Basic.Publish publish, AMQP.BasicProperties properties) + throws IOException { + call.publish(properties); + } + + @Override + public Consumer basicConsume(Consumer consumer) { + return consumer; + } +} diff --git a/src/main/java/com/rabbitmq/client/observation/ObservationCollector.java b/src/main/java/com/rabbitmq/client/observation/ObservationCollector.java new file mode 100644 index 0000000000..1196df818c --- /dev/null +++ b/src/main/java/com/rabbitmq/client/observation/ObservationCollector.java @@ -0,0 +1,39 @@ +// Copyright (c) 2023 VMware, Inc. or its affiliates. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.observation; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Consumer; +import java.io.IOException; + +/** + * + * @since 5.18.0 + */ +public interface ObservationCollector { + + ObservationCollector NO_OP = new NoOpObservationCollector(); + + void publish(PublishCall call, AMQP.Basic.Publish publish, AMQP.BasicProperties properties) + throws IOException; + + Consumer basicConsume(Consumer consumer); + + interface PublishCall { + + void publish(AMQP.BasicProperties properties) throws IOException; + } +} diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/ConsumeContext.java b/src/main/java/com/rabbitmq/client/observation/micrometer/ConsumeContext.java new file mode 100644 index 0000000000..c1f33f2dc2 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/ConsumeContext.java @@ -0,0 +1,53 @@ +// Copyright (c) 2023 VMware, Inc. or its affiliates. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.observation.micrometer; + +import io.micrometer.observation.transport.ReceiverContext; +import java.util.Map; + +/** + * {@link io.micrometer.observation.Observation.Context} for use with RabbitMQ client {@link + * io.micrometer.observation.Observation} instrumentation. + * + * @since 5.18.0 + */ +public class ConsumeContext extends ReceiverContext> { + + private final String exchange; + private final String routingKey; + + ConsumeContext(String exchange, String routingKey, Map headers) { + super( + (hdrs, key) -> { + Object result = hdrs.get(key); + if (result == null) { + return null; + } + return String.valueOf(result); + }); + this.exchange = exchange; + this.routingKey = routingKey; + setCarrier(headers); + } + + public String getExchange() { + return exchange; + } + + public String getRoutingKey() { + return routingKey; + } +} diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/ConsumeObservationConvention.java b/src/main/java/com/rabbitmq/client/observation/micrometer/ConsumeObservationConvention.java new file mode 100644 index 0000000000..38ce2aa333 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/ConsumeObservationConvention.java @@ -0,0 +1,33 @@ +// Copyright (c) 2023 VMware, Inc. or its affiliates. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.observation.micrometer; + +import io.micrometer.observation.Observation; +import io.micrometer.observation.ObservationConvention; + +/** + * {@link ObservationConvention} for RabbitMQ client instrumentation. + * + * @since 5.18.0 + * @see DefaultPublishObservationConvention + */ +public interface ConsumeObservationConvention extends ObservationConvention { + + @Override + default boolean supportsContext(Observation.Context context) { + return context instanceof ConsumeContext; + } +} diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultConsumeObservationConvention.java b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultConsumeObservationConvention.java new file mode 100644 index 0000000000..50fcad31a0 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultConsumeObservationConvention.java @@ -0,0 +1,68 @@ +// Copyright (c) 2023 VMware, Inc. or its affiliates. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.observation.micrometer; + +import com.rabbitmq.client.observation.micrometer.RabbitMqObservationDocumentation.HighCardinalityTags; +import com.rabbitmq.client.observation.micrometer.RabbitMqObservationDocumentation.LowCardinalityTags; +import io.micrometer.common.KeyValues; +import io.micrometer.common.util.StringUtils; + +/** + * Default implementation of {@link ConsumeObservationConvention}. + * + * @since 5.18.0 + * @see ConsumeObservationConvention + */ +public class DefaultConsumeObservationConvention implements ConsumeObservationConvention { + + private final String name; + + public DefaultConsumeObservationConvention() { + this("rabbitmq.consume"); + } + + public DefaultConsumeObservationConvention(String name) { + this.name = name; + } + + @Override + public String getName() { + return name; + } + + @Override + public String getContextualName(ConsumeContext context) { + return destination(context.getRoutingKey()) + " consume"; + } + + private String destination(String destination) { + return StringUtils.isNotBlank(destination) ? destination : "(anonymous)"; + } + + @Override + public KeyValues getLowCardinalityKeyValues(ConsumeContext context) { + return KeyValues.of( + LowCardinalityTags.MESSAGING_OPERATION.withValue("publish"), + LowCardinalityTags.MESSAGING_SYSTEM.withValue("rabbitmq")); + } + + @Override + public KeyValues getHighCardinalityKeyValues(ConsumeContext context) { + return KeyValues.of( + HighCardinalityTags.MESSAGING_ROUTING_KEY.withValue(context.getRoutingKey()), + HighCardinalityTags.MESSAGING_DESTINATION_NAME.withValue(context.getExchange())); + } +} diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultPublishObservationConvention.java b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultPublishObservationConvention.java new file mode 100644 index 0000000000..cc60a39ebd --- /dev/null +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultPublishObservationConvention.java @@ -0,0 +1,68 @@ +// Copyright (c) 2023 VMware, Inc. or its affiliates. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.observation.micrometer; + +import com.rabbitmq.client.observation.micrometer.RabbitMqObservationDocumentation.HighCardinalityTags; +import com.rabbitmq.client.observation.micrometer.RabbitMqObservationDocumentation.LowCardinalityTags; +import io.micrometer.common.KeyValues; +import io.micrometer.common.util.StringUtils; + +/** + * Default implementation of {@link PublishObservationConvention}. + * + * @since 5.18.0 + * @see RabbitMqObservationDocumentation + */ +public class DefaultPublishObservationConvention implements PublishObservationConvention { + + private final String name; + + public DefaultPublishObservationConvention() { + this("rabbitmq.publish"); + } + + public DefaultPublishObservationConvention(String name) { + this.name = name; + } + + @Override + public String getName() { + return name; + } + + @Override + public String getContextualName(PublishContext context) { + return destination(context.getRoutingKey()) + " publish"; + } + + private String destination(String destination) { + return StringUtils.isNotBlank(destination) ? destination : "(anonymous)"; + } + + @Override + public KeyValues getLowCardinalityKeyValues(PublishContext context) { + return KeyValues.of( + LowCardinalityTags.MESSAGING_OPERATION.withValue("publish"), + LowCardinalityTags.MESSAGING_SYSTEM.withValue("rabbitmq")); + } + + @Override + public KeyValues getHighCardinalityKeyValues(PublishContext context) { + return KeyValues.of( + HighCardinalityTags.MESSAGING_ROUTING_KEY.withValue(context.getRoutingKey()), + HighCardinalityTags.MESSAGING_DESTINATION_NAME.withValue(context.getExchange())); + } +} diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java b/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java new file mode 100644 index 0000000000..83b17913fb --- /dev/null +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java @@ -0,0 +1,162 @@ +// Copyright (c) 2023 VMware, Inc. or its affiliates. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.observation.micrometer; + +import com.rabbitmq.client.*; +import com.rabbitmq.client.observation.ObservationCollector; +import io.micrometer.observation.Observation; +import io.micrometer.observation.ObservationRegistry; +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +class MicrometerObservationCollector implements ObservationCollector { + + private final ObservationRegistry registry; + + private final PublishObservationConvention customPublishConvention, defaultPublishConvention; + private final ConsumeObservationConvention customConsumeConvention, defaultConsumeConvention; + + MicrometerObservationCollector( + ObservationRegistry registry, + PublishObservationConvention customPublishConvention, + PublishObservationConvention defaultPublishConvention, + ConsumeObservationConvention customConsumeConvention, + ConsumeObservationConvention defaultConsumeConvention) { + this.registry = registry; + this.customPublishConvention = customPublishConvention; + this.defaultPublishConvention = defaultPublishConvention; + this.customConsumeConvention = customConsumeConvention; + this.defaultConsumeConvention = defaultConsumeConvention; + } + + @Override + public void publish(PublishCall call, AMQP.Basic.Publish publish, AMQP.BasicProperties properties) + throws IOException { + // TODO: Is this for fire and forget or request reply too? If r-r then we have to have 2 + // contexts + Map headers; + if (properties.getHeaders() == null) { + headers = new HashMap<>(); + } else { + headers = new HashMap<>(properties.getHeaders()); + } + PublishContext micrometerPublishContext = + new PublishContext(publish.getExchange(), publish.getRoutingKey(), headers); + AMQP.BasicProperties.Builder builder = properties.builder(); + builder.headers(headers); + // TODO give possibility to create the publish observation + // the custom convention is already a property, the default convention could be a property as + // well. + // the name (in default convention) could also be set in a simple way, from the base + // configuration + // no need to give access to the other 2 parameters + Observation observation = + RabbitMqObservationDocumentation.PUBLISH_OBSERVATION.observation( + this.customPublishConvention, + this.defaultPublishConvention, + () -> micrometerPublishContext, + registry); + observation.start(); + try { + call.publish(builder.build()); + } catch (IOException | AlreadyClosedException e) { + observation.error(e); + throw e; + } + observation.stop(); + } + + @Override + public Consumer basicConsume(Consumer consumer) { + return new ObservationConsumer( + consumer, this.registry, this.customConsumeConvention, this.defaultConsumeConvention); + } + + private static class ObservationConsumer implements Consumer { + + private final Consumer delegate; + + private final ObservationRegistry observationRegistry; + + private final ConsumeObservationConvention customConsumeConvention, defaultConsumeConvention; + + private ObservationConsumer( + Consumer delegate, + ObservationRegistry observationRegistry, + ConsumeObservationConvention customConsumeConvention, + ConsumeObservationConvention defaultConsumeConvention) { + this.delegate = delegate; + this.observationRegistry = observationRegistry; + this.customConsumeConvention = customConsumeConvention; + this.defaultConsumeConvention = defaultConsumeConvention; + } + + @Override + public void handleConsumeOk(String consumerTag) { + delegate.handleConsumeOk(consumerTag); + } + + @Override + public void handleCancelOk(String consumerTag) { + delegate.handleCancelOk(consumerTag); + } + + @Override + public void handleCancel(String consumerTag) throws IOException { + delegate.handleCancel(consumerTag); + } + + @Override + public void handleShutdownSignal(String consumerTag, ShutdownSignalException sig) { + delegate.handleShutdownSignal(consumerTag, sig); + } + + @Override + public void handleRecoverOk(String consumerTag) { + delegate.handleRecoverOk(consumerTag); + } + + @Override + public void handleDelivery( + String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) + throws IOException { + Map headers; + if (properties == null || properties.getHeaders() == null) { + headers = Collections.emptyMap(); + } else { + headers = properties.getHeaders(); + } + ConsumeContext context = + new ConsumeContext(envelope.getExchange(), envelope.getRoutingKey(), headers); + // TODO give possibility to create the consume observation + // the custom convention is already a property, the default convention could be a property as + // well. + // the name (in default convention) could also be set in a simple way, from the base + // configuration + // no need to give access to the other 2 parameters + Observation observation = + RabbitMqObservationDocumentation.CONSUME_OBSERVATION.observation( + customConsumeConvention, + defaultConsumeConvention, + () -> context, + observationRegistry); + observation.observeChecked( + () -> delegate.handleDelivery(consumerTag, envelope, properties, body)); + } + } +} diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollectorBuilder.java b/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollectorBuilder.java new file mode 100644 index 0000000000..fa78587066 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollectorBuilder.java @@ -0,0 +1,72 @@ +// Copyright (c) 2023 VMware, Inc. or its affiliates. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.observation.micrometer; + +import com.rabbitmq.client.observation.ObservationCollector; +import io.micrometer.observation.ObservationRegistry; + +/** + * @since 5.18.0 + */ +public class MicrometerObservationCollectorBuilder { + + private ObservationRegistry registry = ObservationRegistry.NOOP; + private PublishObservationConvention customPublishObservationConvention; + private PublishObservationConvention defaultPublishObservationConvention = + new DefaultPublishObservationConvention(); + private ConsumeObservationConvention customConsumeObservationConvention; + private ConsumeObservationConvention defaultConsumeObservationConvention = + new DefaultConsumeObservationConvention(); + + public MicrometerObservationCollectorBuilder registry(ObservationRegistry registry) { + this.registry = registry; + return this; + } + + public MicrometerObservationCollectorBuilder customPublishObservationConvention( + PublishObservationConvention customPublishObservationConvention) { + this.customPublishObservationConvention = customPublishObservationConvention; + return this; + } + + public MicrometerObservationCollectorBuilder defaultPublishObservationConvention( + PublishObservationConvention defaultPublishObservationConvention) { + this.defaultPublishObservationConvention = defaultPublishObservationConvention; + return this; + } + + public MicrometerObservationCollectorBuilder customConsumeObservationConvention( + ConsumeObservationConvention customConsumeObservationConvention) { + this.customConsumeObservationConvention = customConsumeObservationConvention; + return this; + } + + public MicrometerObservationCollectorBuilder defaultConsumeObservationConvention( + ConsumeObservationConvention defaultConsumeObservationConvention) { + this.defaultConsumeObservationConvention = defaultConsumeObservationConvention; + return this; + } + + public ObservationCollector build() { + return new MicrometerObservationCollector( + this.registry, + this.customPublishObservationConvention, + this.defaultPublishObservationConvention, + this.customConsumeObservationConvention, + this.defaultConsumeObservationConvention + ); + } +} diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/PublishContext.java b/src/main/java/com/rabbitmq/client/observation/micrometer/PublishContext.java new file mode 100644 index 0000000000..558fb71936 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/PublishContext.java @@ -0,0 +1,46 @@ +// Copyright (c) 2023 VMware, Inc. or its affiliates. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.observation.micrometer; + +import io.micrometer.observation.transport.SenderContext; +import java.util.Map; + +/** + * {@link io.micrometer.observation.Observation.Context} for use with RabbitMQ client {@link + * io.micrometer.observation.Observation} instrumentation. + * + * @since 5.18.0 + */ +public class PublishContext extends SenderContext> { + + private final String exchange; + private final String routingKey; + + PublishContext(String exchange, String routingKey, Map headers) { + super((hdrs, key, value) -> hdrs.put(key, value)); + this.exchange = exchange; + this.routingKey = routingKey; + setCarrier(headers); + } + + public String getExchange() { + return this.exchange; + } + + public String getRoutingKey() { + return this.routingKey; + } +} diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/PublishObservationConvention.java b/src/main/java/com/rabbitmq/client/observation/micrometer/PublishObservationConvention.java new file mode 100644 index 0000000000..699921ba6f --- /dev/null +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/PublishObservationConvention.java @@ -0,0 +1,33 @@ +// Copyright (c) 2023 VMware, Inc. or its affiliates. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.observation.micrometer; + +import io.micrometer.observation.Observation; +import io.micrometer.observation.ObservationConvention; + +/** + * {@link ObservationConvention} for RabbitMQ client instrumentation. + * + * @since 5.18.0 + * @see DefaultPublishObservationConvention + */ +public interface PublishObservationConvention extends ObservationConvention { + + @Override + default boolean supportsContext(Observation.Context context) { + return context instanceof PublishContext; + } +} diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/RabbitMqObservationDocumentation.java b/src/main/java/com/rabbitmq/client/observation/micrometer/RabbitMqObservationDocumentation.java new file mode 100644 index 0000000000..80d121b349 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/RabbitMqObservationDocumentation.java @@ -0,0 +1,134 @@ +// Copyright (c) 2023 VMware, Inc. or its affiliates. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.observation.micrometer; + +import io.micrometer.common.docs.KeyName; +import io.micrometer.observation.Observation; +import io.micrometer.observation.ObservationConvention; +import io.micrometer.observation.docs.ObservationDocumentation; + +/** + * {@link ObservationDocumentation} for RabbitMQ Clients. + * + * @since 5.18.0 + */ +public enum RabbitMqObservationDocumentation implements ObservationDocumentation { + + /** Observation for Rabbit Client publishers. */ + PUBLISH_OBSERVATION { + + @Override + public Class> + getDefaultConvention() { + return DefaultPublishObservationConvention.class; + } + + @Override + public KeyName[] getLowCardinalityKeyNames() { + return LowCardinalityTags.values(); + } + }, + + /** Observation for Rabbit Client consumers. */ + CONSUME_OBSERVATION { + + @Override + public Class> + getDefaultConvention() { + return DefaultConsumeObservationConvention.class; + } + + @Override + public KeyName[] getLowCardinalityKeyNames() { + return LowCardinalityTags.values(); + } + }; + + // SPAN NAME + // + // topic with spaces process + // (anonymous) publish ((anonymous) being a stable identifier for an unnamed destination) + // (anonymous) receive ((anonymous) being a stable identifier for an unnamed destination) + + // LOW CARDINALITY + // messaging.system = rabbitmq + // messaging.operation = publish + + // HIGH CARDINALITY + + // messaging.rabbitmq.destination.routing_key + // messaging.destination.anonymous + // messaging.destination.name + // messaging.destination.template + // messaging.destination.temporary + // messaging.batch.message_count + // messaging.message.conversation_id + // messaging.message.id + // messaging.message.payload_compressed_size_bytes + // messaging.message.payload_size_bytes + + // net.peer.name + // net.protocol.name + // net.protocol.version + // net.sock.family + // net.sock.peer.addr + // net.sock.peer.name + // net.sock.peer.port + + /** Low cardinality tags. */ + public enum LowCardinalityTags implements KeyName { + + /** A string identifying the messaging system. */ + MESSAGING_SYSTEM { + + @Override + public String asString() { + return "messaging.system"; + } + }, + + /** A string identifying the kind of messaging operation. */ + MESSAGING_OPERATION { + + @Override + public String asString() { + return "messaging.operation"; + } + } + } + + /** High cardinality tags. */ + public enum HighCardinalityTags implements KeyName { + + /** The message destination name. */ + MESSAGING_DESTINATION_NAME { + + @Override + public String asString() { + return "messaging.destination.name"; + } + }, + + /** RabbitMQ message routing key. */ + MESSAGING_ROUTING_KEY { + + @Override + public String asString() { + return "messaging.rabbitmq.destination.routing_key"; + } + } + } +} diff --git a/src/test/java/com/rabbitmq/client/impl/AMQConnectionRefreshCredentialsTest.java b/src/test/java/com/rabbitmq/client/impl/AMQConnectionRefreshCredentialsTest.java index a5fce8a561..96d40cc4cf 100644 --- a/src/test/java/com/rabbitmq/client/impl/AMQConnectionRefreshCredentialsTest.java +++ b/src/test/java/com/rabbitmq/client/impl/AMQConnectionRefreshCredentialsTest.java @@ -17,6 +17,7 @@ import com.rabbitmq.client.Method; import com.rabbitmq.client.*; +import com.rabbitmq.client.observation.ObservationCollector; import com.rabbitmq.client.test.TestUtils; import com.rabbitmq.client.test.TestUtils.BrokerVersion; import com.rabbitmq.client.test.TestUtils.BrokerVersionAtLeast; @@ -64,7 +65,7 @@ private static ConnectionFactory connectionFactoryThatSendsGarbageAfterUpdateSec ConnectionFactory cf = new ConnectionFactory() { @Override protected AMQConnection createConnection(ConnectionParams params, FrameHandler frameHandler, MetricsCollector metricsCollector) { - return new AMQConnection(params, frameHandler, metricsCollector) { + return new AMQConnection(params, frameHandler, metricsCollector, ObservationCollector.NO_OP) { @Override AMQChannel createChannel0() { diff --git a/src/test/java/com/rabbitmq/client/test/functional/FunctionalTestSuite.java b/src/test/java/com/rabbitmq/client/test/functional/FunctionalTestSuite.java index eb1ac8d3aa..ec06db3553 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/FunctionalTestSuite.java +++ b/src/test/java/com/rabbitmq/client/test/functional/FunctionalTestSuite.java @@ -76,7 +76,7 @@ Nack.class, ExceptionMessages.class, Metrics.class, - MicrometerMetrics.class, + MicrometerObservationCollectorMetrics.class, TopologyRecoveryFiltering.class, TopologyRecoveryRetry.class }) diff --git a/src/test/java/com/rabbitmq/client/test/functional/MicrometerMetrics.java b/src/test/java/com/rabbitmq/client/test/functional/MicrometerMetrics.java deleted file mode 100644 index 1cb0b240f9..0000000000 --- a/src/test/java/com/rabbitmq/client/test/functional/MicrometerMetrics.java +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - -package com.rabbitmq.client.test.functional; - -import java.io.IOException; -import java.time.Duration; - -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.ConnectionFactory; -import com.rabbitmq.client.DefaultConsumer; -import com.rabbitmq.client.Envelope; -import com.rabbitmq.client.impl.MicrometerMetricsCollector; -import com.rabbitmq.client.test.BrokerTestCase; -import com.rabbitmq.client.test.TestUtils; -import io.micrometer.tracing.Span; -import io.micrometer.tracing.Tracer; -import io.micrometer.tracing.test.SampleTestRunner; -import org.junit.jupiter.api.Nested; - -import static com.rabbitmq.client.test.TestUtils.waitAtMost; -import static org.assertj.core.api.Assertions.assertThat; - -public class MicrometerMetrics extends BrokerTestCase { - - static final String QUEUE = "metrics.queue"; - - @Override - protected void createResources() throws IOException { - channel.queueDeclare(QUEUE, true, false, false, null); - } - - @Override - protected void releaseResources() throws IOException { - channel.queueDelete(QUEUE); - } - - - @Nested - class IntegrationTest extends SampleTestRunner { - - @Override - public TracingSetup[] getTracingSetup() { - return new TracingSetup[] { TracingSetup.IN_MEMORY_BRAVE, TracingSetup.ZIPKIN_BRAVE }; - } - - @Override - public SampleTestRunnerConsumer yourCode() throws Exception { - return (buildingBlocks, meterRegistry) -> { - ConnectionFactory connectionFactory = createConnectionFactory(); - MicrometerMetricsCollector collector = new MicrometerMetricsCollector(meterRegistry); - collector.setObservationRegistry(getObservationRegistry()); - connectionFactory.setMetricsCollector(collector); - Connection connection1 = null; - try { - connection1 = connectionFactory.newConnection(); - Channel channel = connection1.createChannel(); - - sendMessage(channel); - - TestingConsumer testingConsumer = new TestingConsumer(channel, buildingBlocks.getTracer(), buildingBlocks.getTracer().currentSpan()); - channel.basicConsume(QUEUE, true, testingConsumer); - waitAtMost(timeout(), () -> testingConsumer.executed); - waitAtMost(timeout(), () -> testingConsumer.assertionsPassed); - getMeterRegistry().get("rabbit.publish") - .tag("messaging.operation", "publish") - .tag("messaging.system", "rabbitmq") - .timer(); - getMeterRegistry().get("rabbit.consume") - .tag("messaging.operation", "publish") - .tag("messaging.system", "rabbitmq") - .timer(); - } finally { - safeClose(connection1); - } - }; - } - } - - private Duration timeout() { - return Duration.ofSeconds(10); - } - - private static ConnectionFactory createConnectionFactory() { - ConnectionFactory connectionFactory = TestUtils.connectionFactory(); - connectionFactory.setAutomaticRecoveryEnabled(false); - return connectionFactory; - } - - private void safeClose(Connection connection) { - if(connection != null) { - try { - connection.abort(); - } catch (Exception e) { - // OK - } - } - } - - private void sendMessage(Channel channel) throws IOException { - channel.basicPublish("", QUEUE, null, "msg".getBytes("UTF-8")); - } - - static class TestingConsumer extends DefaultConsumer { - - volatile boolean executed; - - volatile boolean assertionsPassed; - - private final Tracer tracer; - - private final Span rootSpan; - - public TestingConsumer(Channel channel, Tracer tracer, Span rootSpan) { - super(channel); - this.tracer = tracer; - this.rootSpan = rootSpan; - } - - @Override - public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { - executed = true; - assertThat(tracer.currentSpan()).as("Span must be put in scope").isNotNull(); - assertThat(tracer.currentSpan().context().traceId()).as("Trace id must be propagated").isEqualTo(rootSpan.context().traceId()); - System.out.println("Current span [" + tracer.currentSpan() + "]"); - assertionsPassed = true; - } - } - -} diff --git a/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java b/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java new file mode 100644 index 0000000000..b216863fcc --- /dev/null +++ b/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java @@ -0,0 +1,164 @@ +// Copyright (c) 2023 VMware, Inc. or its affiliates. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.test.functional; + +import static com.rabbitmq.client.test.TestUtils.waitAtMost; +import static org.assertj.core.api.Assertions.assertThat; + +import com.rabbitmq.client.*; +import com.rabbitmq.client.observation.ObservationCollector; +import com.rabbitmq.client.observation.micrometer.MicrometerObservationCollectorBuilder; +import com.rabbitmq.client.test.BrokerTestCase; +import com.rabbitmq.client.test.TestUtils; +import io.micrometer.tracing.Span; +import io.micrometer.tracing.Tracer; +import io.micrometer.tracing.test.SampleTestRunner; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +public class MicrometerObservationCollectorMetrics extends BrokerTestCase { + + static final String QUEUE = "metrics.queue"; + + private static ConnectionFactory createConnectionFactory() { + ConnectionFactory connectionFactory = TestUtils.connectionFactory(); + connectionFactory.setAutomaticRecoveryEnabled(true); + return connectionFactory; + } + + private static Consumer consumer(DeliverCallback callback) { + return new Consumer() { + @Override + public void handleConsumeOk(String consumerTag) {} + + @Override + public void handleCancelOk(String consumerTag) {} + + @Override + public void handleCancel(String consumerTag) throws IOException {} + + @Override + public void handleShutdownSignal(String consumerTag, ShutdownSignalException sig) {} + + @Override + public void handleRecoverOk(String consumerTag) {} + + @Override + public void handleDelivery( + String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) + throws IOException { + callback.handle(consumerTag, new Delivery(envelope, properties, body)); + } + }; + } + + @Override + protected void createResources() throws IOException { + channel.queueDeclare(QUEUE, true, false, false, null); + } + + @Override + protected void releaseResources() throws IOException { + channel.queueDelete(QUEUE); + } + + private Duration timeout() { + return Duration.ofSeconds(10); + } + + private void safeClose(Connection connection) { + if (connection != null) { + try { + connection.abort(); + } catch (Exception e) { + // OK + } + } + } + + private void sendMessage(Channel channel) throws IOException { + channel.basicPublish("", QUEUE, null, "msg".getBytes(StandardCharsets.UTF_8)); + } + + @Nested + class IntegrationTest extends SampleTestRunner { + + @Override + public TracingSetup[] getTracingSetup() { + return new TracingSetup[] {TracingSetup.IN_MEMORY_BRAVE, TracingSetup.ZIPKIN_BRAVE}; + } + + @Test + void test() {} + + @Override + public SampleTestRunnerConsumer yourCode() { + return (buildingBlocks, meterRegistry) -> { + ConnectionFactory connectionFactory = createConnectionFactory(); + ObservationCollector collector = + new MicrometerObservationCollectorBuilder().registry(getObservationRegistry()).build(); + connectionFactory.setObservationCollector(collector); + Connection publishConnection = null, consumeConnection = null; + try { + publishConnection = connectionFactory.newConnection(); + Channel channel = publishConnection.createChannel(); + + sendMessage(channel); + + Tracer tracer = buildingBlocks.getTracer(); + Span rootSpan = buildingBlocks.getTracer().currentSpan(); + CountDownLatch consumeLatch = new CountDownLatch(1); + Consumer consumer = + consumer( + (consumerTag, message) -> { + assertThat(tracer.currentSpan()).as("Span must be put in scope").isNotNull(); + assertThat(tracer.currentSpan().context().traceId()) + .as("Trace id must be propagated") + .isEqualTo(rootSpan.context().traceId()); + System.out.println("Current span [" + tracer.currentSpan() + "]"); + consumeLatch.countDown(); + }); + + consumeConnection = connectionFactory.newConnection(); + channel = consumeConnection.createChannel(); + channel.basicConsume(QUEUE, true, consumer); + + assertThat(consumeLatch.await(10, TimeUnit.SECONDS)).isTrue(); + waitAtMost(() -> getMeterRegistry().find("rabbitmq.publish").timer() != null && + getMeterRegistry().find("rabbitmq.consume").timer() != null); + getMeterRegistry() + .get("rabbitmq.publish") + .tag("messaging.operation", "publish") + .tag("messaging.system", "rabbitmq") + .timer(); + getMeterRegistry() + .get("rabbitmq.consume") + .tag("messaging.operation", "publish") + .tag("messaging.system", "rabbitmq") + .timer(); + } finally { + safeClose(publishConnection); + safeClose(consumeConnection); + } + }; + } + } +} From 4ff96ec1963b37ab3ead90cde62f08ed4c876914 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 3 May 2023 09:48:40 +0200 Subject: [PATCH 1745/2114] Test "non-observable" consumed message does not fail If observation is enabled. --- .../DefaultConsumeObservationConvention.java | 2 +- ...MicrometerObservationCollectorMetrics.java | 83 ++++++++++++++----- 2 files changed, 61 insertions(+), 24 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultConsumeObservationConvention.java b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultConsumeObservationConvention.java index 50fcad31a0..aad7386d1b 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultConsumeObservationConvention.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultConsumeObservationConvention.java @@ -55,7 +55,7 @@ private String destination(String destination) { @Override public KeyValues getLowCardinalityKeyValues(ConsumeContext context) { return KeyValues.of( - LowCardinalityTags.MESSAGING_OPERATION.withValue("publish"), + LowCardinalityTags.MESSAGING_OPERATION.withValue("consume"), LowCardinalityTags.MESSAGING_SYSTEM.withValue("rabbitmq")); } diff --git a/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java b/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java index b216863fcc..ba86b6dc99 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java +++ b/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java @@ -23,24 +23,34 @@ import com.rabbitmq.client.observation.micrometer.MicrometerObservationCollectorBuilder; import com.rabbitmq.client.test.BrokerTestCase; import com.rabbitmq.client.test.TestUtils; +import io.micrometer.observation.ObservationRegistry; import io.micrometer.tracing.Span; import io.micrometer.tracing.Tracer; import io.micrometer.tracing.test.SampleTestRunner; import java.io.IOException; import java.nio.charset.StandardCharsets; -import java.time.Duration; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; public class MicrometerObservationCollectorMetrics extends BrokerTestCase { static final String QUEUE = "metrics.queue"; private static ConnectionFactory createConnectionFactory() { + return createConnectionFactory(null); + } + + private static ConnectionFactory createConnectionFactory( + ObservationRegistry observationRegistry) { ConnectionFactory connectionFactory = TestUtils.connectionFactory(); connectionFactory.setAutomaticRecoveryEnabled(true); + if (observationRegistry != null) { + ObservationCollector collector = + new MicrometerObservationCollectorBuilder().registry(observationRegistry).build(); + connectionFactory.setObservationCollector(collector); + } return connectionFactory; } @@ -53,7 +63,7 @@ public void handleConsumeOk(String consumerTag) {} public void handleCancelOk(String consumerTag) {} @Override - public void handleCancel(String consumerTag) throws IOException {} + public void handleCancel(String consumerTag) {} @Override public void handleShutdownSignal(String consumerTag, ShutdownSignalException sig) {} @@ -80,10 +90,6 @@ protected void releaseResources() throws IOException { channel.queueDelete(QUEUE); } - private Duration timeout() { - return Duration.ofSeconds(10); - } - private void safeClose(Connection connection) { if (connection != null) { try { @@ -98,24 +104,21 @@ private void sendMessage(Channel channel) throws IOException { channel.basicPublish("", QUEUE, null, "msg".getBytes(StandardCharsets.UTF_8)); } - @Nested - class IntegrationTest extends SampleTestRunner { + private abstract static class IntegrationTest extends SampleTestRunner { @Override public TracingSetup[] getTracingSetup() { return new TracingSetup[] {TracingSetup.IN_MEMORY_BRAVE, TracingSetup.ZIPKIN_BRAVE}; } + } - @Test - void test() {} + @Nested + class PublishConsume extends IntegrationTest { @Override public SampleTestRunnerConsumer yourCode() { return (buildingBlocks, meterRegistry) -> { - ConnectionFactory connectionFactory = createConnectionFactory(); - ObservationCollector collector = - new MicrometerObservationCollectorBuilder().registry(getObservationRegistry()).build(); - connectionFactory.setObservationCollector(collector); + ConnectionFactory connectionFactory = createConnectionFactory(getObservationRegistry()); Connection publishConnection = null, consumeConnection = null; try { publishConnection = connectionFactory.newConnection(); @@ -125,15 +128,12 @@ public SampleTestRunnerConsumer yourCode() { Tracer tracer = buildingBlocks.getTracer(); Span rootSpan = buildingBlocks.getTracer().currentSpan(); + AtomicReference consumeSpan = new AtomicReference<>(); CountDownLatch consumeLatch = new CountDownLatch(1); Consumer consumer = consumer( (consumerTag, message) -> { - assertThat(tracer.currentSpan()).as("Span must be put in scope").isNotNull(); - assertThat(tracer.currentSpan().context().traceId()) - .as("Trace id must be propagated") - .isEqualTo(rootSpan.context().traceId()); - System.out.println("Current span [" + tracer.currentSpan() + "]"); + consumeSpan.set(tracer.currentSpan()); consumeLatch.countDown(); }); @@ -142,8 +142,14 @@ public SampleTestRunnerConsumer yourCode() { channel.basicConsume(QUEUE, true, consumer); assertThat(consumeLatch.await(10, TimeUnit.SECONDS)).isTrue(); - waitAtMost(() -> getMeterRegistry().find("rabbitmq.publish").timer() != null && - getMeterRegistry().find("rabbitmq.consume").timer() != null); + assertThat(consumeSpan.get()).as("Span must be put in scope").isNotNull(); + assertThat(consumeSpan.get().context().traceId()) + .as("Trace id must be propagated") + .isEqualTo(rootSpan.context().traceId()); + waitAtMost( + () -> + getMeterRegistry().find("rabbitmq.publish").timer() != null + && getMeterRegistry().find("rabbitmq.consume").timer() != null); getMeterRegistry() .get("rabbitmq.publish") .tag("messaging.operation", "publish") @@ -151,7 +157,7 @@ public SampleTestRunnerConsumer yourCode() { .timer(); getMeterRegistry() .get("rabbitmq.consume") - .tag("messaging.operation", "publish") + .tag("messaging.operation", "consume") .tag("messaging.system", "rabbitmq") .timer(); } finally { @@ -161,4 +167,35 @@ public SampleTestRunnerConsumer yourCode() { }; } } + + @Nested + class ConsumeWithoutObservationShouldNotFail extends IntegrationTest { + + @Override + public SampleTestRunnerConsumer yourCode() { + return (buildingBlocks, meterRegistry) -> { + ConnectionFactory publishCf = createConnectionFactory(); + ConnectionFactory consumeCf = createConnectionFactory(getObservationRegistry()); + Connection publishConnection = null, consumeConnection = null; + try { + publishConnection = publishCf.newConnection(); + Channel channel = publishConnection.createChannel(); + + sendMessage(channel); + + CountDownLatch consumeLatch = new CountDownLatch(1); + Consumer consumer = consumer((consumerTag, message) -> consumeLatch.countDown()); + + consumeConnection = consumeCf.newConnection(); + channel = consumeConnection.createChannel(); + channel.basicConsume(QUEUE, true, consumer); + + assertThat(consumeLatch.await(10, TimeUnit.SECONDS)).isTrue(); + } finally { + safeClose(publishConnection); + safeClose(consumeConnection); + } + }; + } + } } From a24b47f74d7e8caca926ad925419ad07e348ff7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 3 May 2023 10:05:42 +0200 Subject: [PATCH 1746/2114] Add queue and consumer tag to ObservationCollector#basicConsume Could be used for tag values. --- src/main/java/com/rabbitmq/client/impl/ChannelN.java | 2 +- .../rabbitmq/client/observation/NoOpObservationCollector.java | 2 +- .../com/rabbitmq/client/observation/ObservationCollector.java | 2 +- .../observation/micrometer/MicrometerObservationCollector.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java index 1769bc8da4..f31615b760 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelN.java @@ -1366,7 +1366,7 @@ public String basicConsume(String queue, final boolean autoAck, String consumerT @Override public String transformReply(AMQCommand replyCommand) { String actualConsumerTag = ((Basic.ConsumeOk) replyCommand.getMethod()).getConsumerTag(); - Consumer wrappedCallback = observationCollector.basicConsume(callback); + Consumer wrappedCallback = observationCollector.basicConsume(queue, consumerTag, callback); _consumers.put(actualConsumerTag, wrappedCallback); // need to register consumer in stats before it actually starts consuming diff --git a/src/main/java/com/rabbitmq/client/observation/NoOpObservationCollector.java b/src/main/java/com/rabbitmq/client/observation/NoOpObservationCollector.java index 338a4a0480..00d765e2e6 100644 --- a/src/main/java/com/rabbitmq/client/observation/NoOpObservationCollector.java +++ b/src/main/java/com/rabbitmq/client/observation/NoOpObservationCollector.java @@ -28,7 +28,7 @@ public void publish(PublishCall call, AMQP.Basic.Publish publish, AMQP.BasicProp } @Override - public Consumer basicConsume(Consumer consumer) { + public Consumer basicConsume(String queue, String consumerTag, Consumer consumer) { return consumer; } } diff --git a/src/main/java/com/rabbitmq/client/observation/ObservationCollector.java b/src/main/java/com/rabbitmq/client/observation/ObservationCollector.java index 1196df818c..5d0c2d0020 100644 --- a/src/main/java/com/rabbitmq/client/observation/ObservationCollector.java +++ b/src/main/java/com/rabbitmq/client/observation/ObservationCollector.java @@ -30,7 +30,7 @@ public interface ObservationCollector { void publish(PublishCall call, AMQP.Basic.Publish publish, AMQP.BasicProperties properties) throws IOException; - Consumer basicConsume(Consumer consumer); + Consumer basicConsume(String queue, String consumerTag, Consumer consumer); interface PublishCall { diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java b/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java index 83b17913fb..27016943a9 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java @@ -82,7 +82,7 @@ public void publish(PublishCall call, AMQP.Basic.Publish publish, AMQP.BasicProp } @Override - public Consumer basicConsume(Consumer consumer) { + public Consumer basicConsume(String queue, String consumerTag, Consumer consumer) { return new ObservationConsumer( consumer, this.registry, this.customConsumeConvention, this.defaultConsumeConvention); } From 73f7ab893b94cc29842559afca990c3d97e64e39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 4 May 2023 15:46:25 +0200 Subject: [PATCH 1747/2114] Update observation tag names Based on the OpenTelemetry attributes. https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/messaging.md --- .../micrometer/ConsumeContext.java | 15 ++++------ .../DefaultConsumeObservationConvention.java | 7 ++--- .../DefaultPublishObservationConvention.java | 4 +-- .../MicrometerObservationCollector.java | 6 +++- .../RabbitMqObservationDocumentation.java | 11 +++++++- ...MicrometerObservationCollectorMetrics.java | 28 ++++++++----------- 6 files changed, 37 insertions(+), 34 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/ConsumeContext.java b/src/main/java/com/rabbitmq/client/observation/micrometer/ConsumeContext.java index c1f33f2dc2..d265e2c02c 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/ConsumeContext.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/ConsumeContext.java @@ -26,10 +26,9 @@ */ public class ConsumeContext extends ReceiverContext> { - private final String exchange; - private final String routingKey; + private final String queue; - ConsumeContext(String exchange, String routingKey, Map headers) { + ConsumeContext(String queue, Map headers) { super( (hdrs, key) -> { Object result = hdrs.get(key); @@ -38,16 +37,12 @@ public class ConsumeContext extends ReceiverContext> { } return String.valueOf(result); }); - this.exchange = exchange; - this.routingKey = routingKey; + this.queue = queue; setCarrier(headers); } - public String getExchange() { - return exchange; + public String getQueue() { + return queue; } - public String getRoutingKey() { - return routingKey; - } } diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultConsumeObservationConvention.java b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultConsumeObservationConvention.java index aad7386d1b..5e5bc4a30c 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultConsumeObservationConvention.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultConsumeObservationConvention.java @@ -45,10 +45,10 @@ public String getName() { @Override public String getContextualName(ConsumeContext context) { - return destination(context.getRoutingKey()) + " consume"; + return source(context.getQueue()) + " consume"; } - private String destination(String destination) { + private String source(String destination) { return StringUtils.isNotBlank(destination) ? destination : "(anonymous)"; } @@ -62,7 +62,6 @@ public KeyValues getLowCardinalityKeyValues(ConsumeContext context) { @Override public KeyValues getHighCardinalityKeyValues(ConsumeContext context) { return KeyValues.of( - HighCardinalityTags.MESSAGING_ROUTING_KEY.withValue(context.getRoutingKey()), - HighCardinalityTags.MESSAGING_DESTINATION_NAME.withValue(context.getExchange())); + HighCardinalityTags.MESSAGING_SOURCE_NAME.withValue(context.getQueue())); } } diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultPublishObservationConvention.java b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultPublishObservationConvention.java index cc60a39ebd..24bd9776bd 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultPublishObservationConvention.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultPublishObservationConvention.java @@ -49,7 +49,7 @@ public String getContextualName(PublishContext context) { } private String destination(String destination) { - return StringUtils.isNotBlank(destination) ? destination : "(anonymous)"; + return StringUtils.isNotBlank(destination) ? destination : "amq.default"; } @Override @@ -63,6 +63,6 @@ public KeyValues getLowCardinalityKeyValues(PublishContext context) { public KeyValues getHighCardinalityKeyValues(PublishContext context) { return KeyValues.of( HighCardinalityTags.MESSAGING_ROUTING_KEY.withValue(context.getRoutingKey()), - HighCardinalityTags.MESSAGING_DESTINATION_NAME.withValue(context.getExchange())); + HighCardinalityTags.MESSAGING_DESTINATION_NAME.withValue(destination(context.getExchange()))); } } diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java b/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java index 27016943a9..7839548bc1 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java @@ -84,11 +84,13 @@ public void publish(PublishCall call, AMQP.Basic.Publish publish, AMQP.BasicProp @Override public Consumer basicConsume(String queue, String consumerTag, Consumer consumer) { return new ObservationConsumer( + queue, consumer, this.registry, this.customConsumeConvention, this.defaultConsumeConvention); } private static class ObservationConsumer implements Consumer { + private final String queue; private final Consumer delegate; private final ObservationRegistry observationRegistry; @@ -96,10 +98,12 @@ private static class ObservationConsumer implements Consumer { private final ConsumeObservationConvention customConsumeConvention, defaultConsumeConvention; private ObservationConsumer( + String queue, Consumer delegate, ObservationRegistry observationRegistry, ConsumeObservationConvention customConsumeConvention, ConsumeObservationConvention defaultConsumeConvention) { + this.queue = queue; this.delegate = delegate; this.observationRegistry = observationRegistry; this.customConsumeConvention = customConsumeConvention; @@ -142,7 +146,7 @@ public void handleDelivery( headers = properties.getHeaders(); } ConsumeContext context = - new ConsumeContext(envelope.getExchange(), envelope.getRoutingKey(), headers); + new ConsumeContext(queue, headers); // TODO give possibility to create the consume observation // the custom convention is already a property, the default convention could be a property as // well. diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/RabbitMqObservationDocumentation.java b/src/main/java/com/rabbitmq/client/observation/micrometer/RabbitMqObservationDocumentation.java index 80d121b349..9dc51f0495 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/RabbitMqObservationDocumentation.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/RabbitMqObservationDocumentation.java @@ -129,6 +129,15 @@ public String asString() { public String asString() { return "messaging.rabbitmq.destination.routing_key"; } - } + }, + + /** The message destination name. */ + MESSAGING_SOURCE_NAME { + + @Override + public String asString() { + return "messaging.source.name"; + } + }, } } diff --git a/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java b/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java index ba86b6dc99..3a6d429129 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java +++ b/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java @@ -24,14 +24,13 @@ import com.rabbitmq.client.test.BrokerTestCase; import com.rabbitmq.client.test.TestUtils; import io.micrometer.observation.ObservationRegistry; -import io.micrometer.tracing.Span; -import io.micrometer.tracing.Tracer; import io.micrometer.tracing.test.SampleTestRunner; +import io.micrometer.tracing.test.simple.SpanAssert; +import io.micrometer.tracing.test.simple.SpansAssert; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; import org.junit.jupiter.api.Nested; public class MicrometerObservationCollectorMetrics extends BrokerTestCase { @@ -126,26 +125,23 @@ public SampleTestRunnerConsumer yourCode() { sendMessage(channel); - Tracer tracer = buildingBlocks.getTracer(); - Span rootSpan = buildingBlocks.getTracer().currentSpan(); - AtomicReference consumeSpan = new AtomicReference<>(); CountDownLatch consumeLatch = new CountDownLatch(1); - Consumer consumer = - consumer( - (consumerTag, message) -> { - consumeSpan.set(tracer.currentSpan()); - consumeLatch.countDown(); - }); + Consumer consumer = consumer((consumerTag, message) -> consumeLatch.countDown()); consumeConnection = connectionFactory.newConnection(); channel = consumeConnection.createChannel(); channel.basicConsume(QUEUE, true, consumer); assertThat(consumeLatch.await(10, TimeUnit.SECONDS)).isTrue(); - assertThat(consumeSpan.get()).as("Span must be put in scope").isNotNull(); - assertThat(consumeSpan.get().context().traceId()) - .as("Trace id must be propagated") - .isEqualTo(rootSpan.context().traceId()); + waitAtMost(() -> buildingBlocks.getFinishedSpans().size() == 2); + SpansAssert.assertThat(buildingBlocks.getFinishedSpans()).haveSameTraceId().hasSize(2); + SpanAssert.assertThat(buildingBlocks.getFinishedSpans().get(0)) + .hasNameEqualTo("metrics.queue publish") + .hasTag("messaging.rabbitmq.destination.routing_key", "metrics.queue") + .hasTag("messaging.destination.name", "amq.default"); + SpanAssert.assertThat(buildingBlocks.getFinishedSpans().get(1)) + .hasNameEqualTo("metrics.queue consume") + .hasTag("messaging.source.name", "metrics.queue"); waitAtMost( () -> getMeterRegistry().find("rabbitmq.publish").timer() != null From b3251b5902c5c895e7d4468973b3516edede5b5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 5 May 2023 16:41:28 +0200 Subject: [PATCH 1748/2114] Use OpenTelemetry guidelines for observation attributes For Micrometer Observation collector implementation. This is based on what the OTel Java agent exports. The guidelines for attributes may change, but that is a good starting point for now. https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/messaging.md --- .../com/rabbitmq/client/impl/AMQChannel.java | 8 +++++ .../rabbitmq/client/impl/AMQConnection.java | 32 +++++++++++++++++++ .../com/rabbitmq/client/impl/ChannelN.java | 2 +- .../observation/NoOpObservationCollector.java | 7 +++- .../observation/ObservationCollector.java | 15 +++++++-- .../micrometer/ConsumeContext.java | 21 +++++++++++- .../DefaultConsumeObservationConvention.java | 10 +++++- .../DefaultPublishObservationConvention.java | 12 +++++-- .../MicrometerObservationCollector.java | 9 ++++-- .../micrometer/PublishContext.java | 17 +++++++++- .../RabbitMqObservationDocumentation.java | 22 +++++++++++++ ...MicrometerObservationCollectorMetrics.java | 13 ++++++-- 12 files changed, 152 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java index 83a2e3433c..06c92a416e 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java @@ -23,6 +23,7 @@ import com.rabbitmq.client.AMQP.Queue; import com.rabbitmq.client.AMQP.Tx; import com.rabbitmq.client.Method; +import com.rabbitmq.client.observation.ObservationCollector; import com.rabbitmq.utility.BlockingValueOrException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -78,6 +79,8 @@ public abstract class AMQChannel extends ShutdownNotifierComponent { private final TrafficListener _trafficListener; private final int maxInboundMessageBodySize; + private final ObservationCollector.ConnectionInfo connectionInfo; + /** * Construct a channel on the given connection, with the given channel number. * @param connection the underlying connection for this channel @@ -94,6 +97,7 @@ public AMQChannel(AMQConnection connection, int channelNumber) { this._trafficListener = connection.getTrafficListener(); this.maxInboundMessageBodySize = connection.getMaxInboundMessageBodySize(); this._command = new AMQCommand(this.maxInboundMessageBodySize); + this.connectionInfo = connection.connectionInfo(); } /** @@ -584,4 +588,8 @@ public AMQCommand transformReply(AMQCommand command) { return command; } } + + protected ObservationCollector.ConnectionInfo connectionInfo() { + return this.connectionInfo; + } } diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index 031374a544..1ce083af30 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -69,6 +69,7 @@ public class AMQConnection extends ShutdownNotifierComponent implements Connecti private final int workPoolTimeout; private final AtomicBoolean finalShutdownStarted = new AtomicBoolean(false); + private volatile ObservationCollector.ConnectionInfo connectionInfo; /** * Retrieve a copy of the default table of client properties that @@ -429,6 +430,11 @@ public void start() setHeartbeat(negotiatedHeartbeat); + this.connectionInfo = new DefaultConnectionInfo( + this._frameHandler.getAddress().getHostAddress(), + this._frameHandler.getPort() + ); + _channel0.transmit(new AMQP.Connection.TuneOk.Builder() .channelMax(negotiatedChannelMax) .frameMax(frameMax) @@ -1204,4 +1210,30 @@ public TrafficListener getTrafficListener() { int getMaxInboundMessageBodySize() { return maxInboundMessageBodySize; } + + private static class DefaultConnectionInfo implements ObservationCollector.ConnectionInfo { + + private final String peerAddress; + private final int peerPort; + + private DefaultConnectionInfo(String peerAddress, int peerPort) { + this.peerAddress = peerAddress; + this.peerPort = peerPort; + } + + @Override + public String getPeerAddress() { + return peerAddress; + } + + @Override + public int getPeerPort() { + return this.peerPort; + } + + } + + ObservationCollector.ConnectionInfo connectionInfo() { + return this.connectionInfo; + } } diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java index f31615b760..d463fde943 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelN.java @@ -716,7 +716,7 @@ public void basicPublish(String exchange, String routingKey, AMQCommand command = new AMQCommand(publish, properties, body); transmit(command); }; - observationCollector.publish(publishCall, publish, props); + observationCollector.publish(publishCall, publish, props, body, this.connectionInfo()); } catch (IOException | AlreadyClosedException e) { metricsCollector.basicPublishFailure(this, e); throw e; diff --git a/src/main/java/com/rabbitmq/client/observation/NoOpObservationCollector.java b/src/main/java/com/rabbitmq/client/observation/NoOpObservationCollector.java index 00d765e2e6..783d6769ea 100644 --- a/src/main/java/com/rabbitmq/client/observation/NoOpObservationCollector.java +++ b/src/main/java/com/rabbitmq/client/observation/NoOpObservationCollector.java @@ -22,7 +22,12 @@ final class NoOpObservationCollector implements ObservationCollector { @Override - public void publish(PublishCall call, AMQP.Basic.Publish publish, AMQP.BasicProperties properties) + public void publish( + PublishCall call, + AMQP.Basic.Publish publish, + AMQP.BasicProperties properties, + byte[] body, + ConnectionInfo connectionInfo) throws IOException { call.publish(properties); } diff --git a/src/main/java/com/rabbitmq/client/observation/ObservationCollector.java b/src/main/java/com/rabbitmq/client/observation/ObservationCollector.java index 5d0c2d0020..fe88d5c355 100644 --- a/src/main/java/com/rabbitmq/client/observation/ObservationCollector.java +++ b/src/main/java/com/rabbitmq/client/observation/ObservationCollector.java @@ -20,14 +20,18 @@ import java.io.IOException; /** - * * @since 5.18.0 */ public interface ObservationCollector { ObservationCollector NO_OP = new NoOpObservationCollector(); - void publish(PublishCall call, AMQP.Basic.Publish publish, AMQP.BasicProperties properties) + void publish( + PublishCall call, + AMQP.Basic.Publish publish, + AMQP.BasicProperties properties, + byte[] body, + ConnectionInfo connectionInfo) throws IOException; Consumer basicConsume(String queue, String consumerTag, Consumer consumer); @@ -36,4 +40,11 @@ interface PublishCall { void publish(AMQP.BasicProperties properties) throws IOException; } + + interface ConnectionInfo { + + String getPeerAddress(); + + int getPeerPort(); + } } diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/ConsumeContext.java b/src/main/java/com/rabbitmq/client/observation/micrometer/ConsumeContext.java index d265e2c02c..f7cbb53d96 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/ConsumeContext.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/ConsumeContext.java @@ -26,9 +26,13 @@ */ public class ConsumeContext extends ReceiverContext> { + private final String exchange; + private final String routingKey; + private final int payloadSizeBytes; private final String queue; - ConsumeContext(String queue, Map headers) { + ConsumeContext(String exchange, String routingKey, String queue, Map headers, + int payloadSizeBytes) { super( (hdrs, key) -> { Object result = hdrs.get(key); @@ -37,10 +41,25 @@ public class ConsumeContext extends ReceiverContext> { } return String.valueOf(result); }); + this.exchange = exchange; + this.routingKey = routingKey; + this.payloadSizeBytes = payloadSizeBytes; this.queue = queue; setCarrier(headers); } + public String getExchange() { + return this.exchange; + } + + public String getRoutingKey() { + return this.routingKey; + } + + public int getPayloadSizeBytes() { + return this.payloadSizeBytes; + } + public String getQueue() { return queue; } diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultConsumeObservationConvention.java b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultConsumeObservationConvention.java index 5e5bc4a30c..6b8401d807 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultConsumeObservationConvention.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultConsumeObservationConvention.java @@ -48,6 +48,10 @@ public String getContextualName(ConsumeContext context) { return source(context.getQueue()) + " consume"; } + private String exchange(String destination) { + return StringUtils.isNotBlank(destination) ? destination : "amq.default"; + } + private String source(String destination) { return StringUtils.isNotBlank(destination) ? destination : "(anonymous)"; } @@ -62,6 +66,10 @@ public KeyValues getLowCardinalityKeyValues(ConsumeContext context) { @Override public KeyValues getHighCardinalityKeyValues(ConsumeContext context) { return KeyValues.of( - HighCardinalityTags.MESSAGING_SOURCE_NAME.withValue(context.getQueue())); + HighCardinalityTags.MESSAGING_ROUTING_KEY.withValue(context.getRoutingKey()), + HighCardinalityTags.MESSAGING_DESTINATION_NAME.withValue(exchange(context.getExchange())), + HighCardinalityTags.MESSAGING_SOURCE_NAME.withValue(context.getQueue()), + HighCardinalityTags.MESSAGING_MESSAGE_PAYLOAD_SIZE_BYTES.withValue( + String.valueOf(context.getPayloadSizeBytes()))); } } diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultPublishObservationConvention.java b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultPublishObservationConvention.java index 24bd9776bd..5610ac77bb 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultPublishObservationConvention.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultPublishObservationConvention.java @@ -45,10 +45,10 @@ public String getName() { @Override public String getContextualName(PublishContext context) { - return destination(context.getRoutingKey()) + " publish"; + return exchange(context.getRoutingKey()) + " publish"; } - private String destination(String destination) { + private String exchange(String destination) { return StringUtils.isNotBlank(destination) ? destination : "amq.default"; } @@ -63,6 +63,12 @@ public KeyValues getLowCardinalityKeyValues(PublishContext context) { public KeyValues getHighCardinalityKeyValues(PublishContext context) { return KeyValues.of( HighCardinalityTags.MESSAGING_ROUTING_KEY.withValue(context.getRoutingKey()), - HighCardinalityTags.MESSAGING_DESTINATION_NAME.withValue(destination(context.getExchange()))); + HighCardinalityTags.MESSAGING_DESTINATION_NAME.withValue(exchange(context.getExchange())), + HighCardinalityTags.MESSAGING_MESSAGE_PAYLOAD_SIZE_BYTES.withValue( + String.valueOf(context.getPayloadSizeBytes())), + HighCardinalityTags.NET_SOCK_PEER_ADDR.withValue( + context.getConnectionInfo().getPeerAddress()), + HighCardinalityTags.NET_SOCK_PEER_PORT.withValue( + String.valueOf(context.getConnectionInfo().getPeerPort()))); } } diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java b/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java index 7839548bc1..fa42721255 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java @@ -45,7 +45,8 @@ class MicrometerObservationCollector implements ObservationCollector { } @Override - public void publish(PublishCall call, AMQP.Basic.Publish publish, AMQP.BasicProperties properties) + public void publish(PublishCall call, AMQP.Basic.Publish publish, AMQP.BasicProperties properties, + byte [] body, ConnectionInfo connectionInfo) throws IOException { // TODO: Is this for fire and forget or request reply too? If r-r then we have to have 2 // contexts @@ -56,7 +57,9 @@ public void publish(PublishCall call, AMQP.Basic.Publish publish, AMQP.BasicProp headers = new HashMap<>(properties.getHeaders()); } PublishContext micrometerPublishContext = - new PublishContext(publish.getExchange(), publish.getRoutingKey(), headers); + new PublishContext(publish.getExchange(), publish.getRoutingKey(), headers, + body == null ? 0 : body.length, + connectionInfo); AMQP.BasicProperties.Builder builder = properties.builder(); builder.headers(headers); // TODO give possibility to create the publish observation @@ -146,7 +149,7 @@ public void handleDelivery( headers = properties.getHeaders(); } ConsumeContext context = - new ConsumeContext(queue, headers); + new ConsumeContext(envelope.getExchange(), envelope.getRoutingKey(), queue, headers, body == null ? 0 : body.length); // TODO give possibility to create the consume observation // the custom convention is already a property, the default convention could be a property as // well. diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/PublishContext.java b/src/main/java/com/rabbitmq/client/observation/micrometer/PublishContext.java index 558fb71936..d5c450279d 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/PublishContext.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/PublishContext.java @@ -15,6 +15,7 @@ package com.rabbitmq.client.observation.micrometer; +import com.rabbitmq.client.observation.ObservationCollector; import io.micrometer.observation.transport.SenderContext; import java.util.Map; @@ -28,11 +29,17 @@ public class PublishContext extends SenderContext> { private final String exchange; private final String routingKey; + private final int payloadSizeBytes; + private final ObservationCollector.ConnectionInfo connectionInfo; - PublishContext(String exchange, String routingKey, Map headers) { + PublishContext( + String exchange, String routingKey, Map headers, int payloadSizeBytes, + ObservationCollector.ConnectionInfo connectionInfo) { super((hdrs, key, value) -> hdrs.put(key, value)); this.exchange = exchange; this.routingKey = routingKey; + this.payloadSizeBytes = payloadSizeBytes; + this.connectionInfo = connectionInfo; setCarrier(headers); } @@ -43,4 +50,12 @@ public String getExchange() { public String getRoutingKey() { return this.routingKey; } + + public int getPayloadSizeBytes() { + return this.payloadSizeBytes; + } + + public ObservationCollector.ConnectionInfo getConnectionInfo() { + return this.connectionInfo; + } } diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/RabbitMqObservationDocumentation.java b/src/main/java/com/rabbitmq/client/observation/micrometer/RabbitMqObservationDocumentation.java index 9dc51f0495..2b4be9008f 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/RabbitMqObservationDocumentation.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/RabbitMqObservationDocumentation.java @@ -139,5 +139,27 @@ public String asString() { return "messaging.source.name"; } }, + + MESSAGING_MESSAGE_PAYLOAD_SIZE_BYTES { + + @Override + public String asString() { + return "messaging.message.payload_size_bytes"; + } + }, + + NET_SOCK_PEER_PORT { + @Override + public String asString() { + return "net.sock.peer.port"; + } + }, + + NET_SOCK_PEER_ADDR { + @Override + public String asString() { + return "net.sock.peer.addr"; + } + } } } diff --git a/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java b/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java index 3a6d429129..4955611b12 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java +++ b/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java @@ -36,6 +36,7 @@ public class MicrometerObservationCollectorMetrics extends BrokerTestCase { static final String QUEUE = "metrics.queue"; + private static final byte[] PAYLOAD = "msg".getBytes(StandardCharsets.UTF_8); private static ConnectionFactory createConnectionFactory() { return createConnectionFactory(null); @@ -100,7 +101,7 @@ private void safeClose(Connection connection) { } private void sendMessage(Channel channel) throws IOException { - channel.basicPublish("", QUEUE, null, "msg".getBytes(StandardCharsets.UTF_8)); + channel.basicPublish("", QUEUE, null, PAYLOAD); } private abstract static class IntegrationTest extends SampleTestRunner { @@ -138,10 +139,16 @@ public SampleTestRunnerConsumer yourCode() { SpanAssert.assertThat(buildingBlocks.getFinishedSpans().get(0)) .hasNameEqualTo("metrics.queue publish") .hasTag("messaging.rabbitmq.destination.routing_key", "metrics.queue") - .hasTag("messaging.destination.name", "amq.default"); + .hasTag("messaging.destination.name", "amq.default") + .hasTag("messaging.message.payload_size_bytes", String.valueOf(PAYLOAD.length)) + .hasTagWithKey("net.sock.peer.addr") + .hasTag("net.sock.peer.port", "5672"); SpanAssert.assertThat(buildingBlocks.getFinishedSpans().get(1)) .hasNameEqualTo("metrics.queue consume") - .hasTag("messaging.source.name", "metrics.queue"); + .hasTag("messaging.rabbitmq.destination.routing_key", "metrics.queue") + .hasTag("messaging.destination.name", "amq.default") + .hasTag("messaging.source.name", "metrics.queue") + .hasTag("messaging.message.payload_size_bytes", String.valueOf(PAYLOAD.length)); waitAtMost( () -> getMeterRegistry().find("rabbitmq.publish").timer() != null From 7752e1288e8bf2d601b04c60ef5add1ad3a8d818 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 16 May 2023 10:23:35 +0200 Subject: [PATCH 1749/2114] Add protocol and version to observation attributes --- .../DefaultPublishObservationConvention.java | 4 +++- .../RabbitMqObservationDocumentation.java | 18 +++++++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultPublishObservationConvention.java b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultPublishObservationConvention.java index 5610ac77bb..3880eec4ff 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultPublishObservationConvention.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultPublishObservationConvention.java @@ -56,7 +56,9 @@ private String exchange(String destination) { public KeyValues getLowCardinalityKeyValues(PublishContext context) { return KeyValues.of( LowCardinalityTags.MESSAGING_OPERATION.withValue("publish"), - LowCardinalityTags.MESSAGING_SYSTEM.withValue("rabbitmq")); + LowCardinalityTags.MESSAGING_SYSTEM.withValue("rabbitmq"), + LowCardinalityTags.NET_PROTOCOL_NAME.withValue("amqp"), + LowCardinalityTags.NET_PROTOCOL_VERSION.withValue("0.9.1")); } @Override diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/RabbitMqObservationDocumentation.java b/src/main/java/com/rabbitmq/client/observation/micrometer/RabbitMqObservationDocumentation.java index 2b4be9008f..be0f98d6dd 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/RabbitMqObservationDocumentation.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/RabbitMqObservationDocumentation.java @@ -107,7 +107,23 @@ public String asString() { public String asString() { return "messaging.operation"; } - } + }, + + NET_PROTOCOL_NAME { + + @Override + public String asString() { + return "net.protocol.name"; + } + }, + + NET_PROTOCOL_VERSION { + + @Override + public String asString() { + return "net.protocol.version"; + } + }, } /** High cardinality tags. */ From fef51f29dcf274a615f1a239ef5e278c19279086 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 17 May 2023 16:01:41 +0200 Subject: [PATCH 1750/2114] Instrument basic.get --- pom.xml | 40 +++++++- .../com/rabbitmq/client/impl/ChannelN.java | 42 +++++---- .../observation/NoOpObservationCollector.java | 7 +- .../observation/ObservationCollector.java | 56 ++++++++++- ... DefaultDeliverObservationConvention.java} | 25 +++-- .../DefaultPublishObservationConvention.java | 2 - ...onsumeContext.java => DeliverContext.java} | 12 ++- ...java => DeliverObservationConvention.java} | 6 +- .../MicrometerObservationCollector.java | 92 +++++++++++++------ ...MicrometerObservationCollectorBuilder.java | 50 ++++++---- .../micrometer/PublishContext.java | 6 +- .../PublishObservationConvention.java | 2 - .../RabbitMqObservationDocumentation.java | 22 +++-- ...MicrometerObservationCollectorMetrics.java | 76 +++++++++++++-- 14 files changed, 330 insertions(+), 108 deletions(-) rename src/main/java/com/rabbitmq/client/observation/micrometer/{DefaultConsumeObservationConvention.java => DefaultDeliverObservationConvention.java} (76%) rename src/main/java/com/rabbitmq/client/observation/micrometer/{ConsumeContext.java => DeliverContext.java} (89%) rename src/main/java/com/rabbitmq/client/observation/micrometer/{ConsumeObservationConvention.java => DeliverObservationConvention.java} (85%) diff --git a/pom.xml b/pom.xml index b26ad1763e..d538058323 100644 --- a/pom.xml +++ b/pom.xml @@ -54,6 +54,7 @@ UTF-8 UTF-8 + true 1.7.36 4.2.19 1.11.1 @@ -89,7 +90,8 @@ 1.6.13 1.11 1.3 - + 2.35.0 + 1.17.0 + + // Copyright (c) $YEAR VMware, Inc. or its affiliates. All rights reserved. + // + // This software, the RabbitMQ Java client library, is triple-licensed under the + // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 + // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see + // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, + // please see LICENSE-APACHE2. + // + // This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, + // either express or implied. See the LICENSE file for specific language governing + // rights and limitations of this software. + // + // If you have any questions regarding licensing, please contact us at + // info@rabbitmq.com. + + + + + diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java index d463fde943..b3f8ed5427 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelN.java @@ -1164,26 +1164,28 @@ public GetResponse basicGet(String queue, boolean autoAck) .queue(queue) .noAck(autoAck) .build()); - Method method = replyCommand.getMethod(); - - if (method instanceof Basic.GetOk) { - Basic.GetOk getOk = (Basic.GetOk)method; - Envelope envelope = new Envelope(getOk.getDeliveryTag(), - getOk.getRedelivered(), - getOk.getExchange(), - getOk.getRoutingKey()); - BasicProperties props = (BasicProperties)replyCommand.getContentHeader(); - byte[] body = replyCommand.getContentBody(); - int messageCount = getOk.getMessageCount(); - - metricsCollector.consumedMessage(this, getOk.getDeliveryTag(), autoAck); - - return new GetResponse(envelope, props, body, messageCount); - } else if (method instanceof Basic.GetEmpty) { - return null; - } else { - throw new UnexpectedMethodError(method); - } + return this.observationCollector.basicGet(() -> { + Method method = replyCommand.getMethod(); + + if (method instanceof Basic.GetOk) { + Basic.GetOk getOk = (Basic.GetOk)method; + Envelope envelope = new Envelope(getOk.getDeliveryTag(), + getOk.getRedelivered(), + getOk.getExchange(), + getOk.getRoutingKey()); + BasicProperties props = (BasicProperties)replyCommand.getContentHeader(); + byte[] body = replyCommand.getContentBody(); + int messageCount = getOk.getMessageCount(); + + metricsCollector.consumedMessage(this, getOk.getDeliveryTag(), autoAck); + + return new GetResponse(envelope, props, body, messageCount); + } else if (method instanceof Basic.GetEmpty) { + return null; + } else { + throw new UnexpectedMethodError(method); + } + }, queue); } /** Public API - {@inheritDoc} */ diff --git a/src/main/java/com/rabbitmq/client/observation/NoOpObservationCollector.java b/src/main/java/com/rabbitmq/client/observation/NoOpObservationCollector.java index 783d6769ea..76ddd82a70 100644 --- a/src/main/java/com/rabbitmq/client/observation/NoOpObservationCollector.java +++ b/src/main/java/com/rabbitmq/client/observation/NoOpObservationCollector.java @@ -12,11 +12,11 @@ // // If you have any questions regarding licensing, please contact us at // info@rabbitmq.com. - package com.rabbitmq.client.observation; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Consumer; +import com.rabbitmq.client.GetResponse; import java.io.IOException; final class NoOpObservationCollector implements ObservationCollector { @@ -36,4 +36,9 @@ public void publish( public Consumer basicConsume(String queue, String consumerTag, Consumer consumer) { return consumer; } + + @Override + public GetResponse basicGet(BasicGetCall call, String queue) { + return call.get(); + } } diff --git a/src/main/java/com/rabbitmq/client/observation/ObservationCollector.java b/src/main/java/com/rabbitmq/client/observation/ObservationCollector.java index fe88d5c355..bc10f8d684 100644 --- a/src/main/java/com/rabbitmq/client/observation/ObservationCollector.java +++ b/src/main/java/com/rabbitmq/client/observation/ObservationCollector.java @@ -12,20 +12,43 @@ // // If you have any questions regarding licensing, please contact us at // info@rabbitmq.com. - package com.rabbitmq.client.observation; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Consumer; +import com.rabbitmq.client.GetResponse; import java.io.IOException; /** + * API to instrument operations in the AMQP client. The supported operations are publishing, + * asynchronous delivery, and synchronous delivery (basic.get). + * + *

Implementations can gather information and send it to tracing backends. This allows e.g. + * following the processing steps of a given message through different systems. + * + *

This is considered an SPI and is susceptible to change at any time. + * * @since 5.18.0 + * @see com.rabbitmq.client.ConnectionFactory#setObservationCollector( ObservationCollector) */ public interface ObservationCollector { ObservationCollector NO_OP = new NoOpObservationCollector(); + /** + * Decorate message publishing. + * + *

Implementations are expected to call {@link PublishCall#publish( PublishCall, + * AMQP.Basic.Publish, AMQP.BasicProperties, byte[], ConnectionInfo)} to make sure the message is + * actually sent. + * + * @param call + * @param publish + * @param properties + * @param body + * @param connectionInfo + * @throws IOException + */ void publish( PublishCall call, AMQP.Basic.Publish publish, @@ -34,13 +57,44 @@ void publish( ConnectionInfo connectionInfo) throws IOException; + /** + * Decorate consumer registration. + * + *

Implementations are expected to decorate the appropriate {@link Consumer} callbacks. The + * original {@link Consumer} behavior should not be changed though. + * + * @param queue + * @param consumerTag + * @param consumer + * @return + */ Consumer basicConsume(String queue, String consumerTag, Consumer consumer); + /** + * Decorate message polling with basic.get. + * + *

Implementations are expected to {@link BasicGetCall#basicGet( BasicGetCall, String)} and + * return the same result. + * + * @param call + * @param queue + * @return + */ + GetResponse basicGet(BasicGetCall call, String queue); + + /** Underlying publishing call. */ interface PublishCall { void publish(AMQP.BasicProperties properties) throws IOException; } + /** Underlying basic.get call. */ + interface BasicGetCall { + + GetResponse get(); + } + + /** Connection information. */ interface ConnectionInfo { String getPeerAddress(); diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultConsumeObservationConvention.java b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultDeliverObservationConvention.java similarity index 76% rename from src/main/java/com/rabbitmq/client/observation/micrometer/DefaultConsumeObservationConvention.java rename to src/main/java/com/rabbitmq/client/observation/micrometer/DefaultDeliverObservationConvention.java index 6b8401d807..88821b7120 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultConsumeObservationConvention.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultDeliverObservationConvention.java @@ -12,7 +12,6 @@ // // If you have any questions regarding licensing, please contact us at // info@rabbitmq.com. - package com.rabbitmq.client.observation.micrometer; import com.rabbitmq.client.observation.micrometer.RabbitMqObservationDocumentation.HighCardinalityTags; @@ -21,21 +20,19 @@ import io.micrometer.common.util.StringUtils; /** - * Default implementation of {@link ConsumeObservationConvention}. + * Default implementation of {@link DeliverObservationConvention}. * * @since 5.18.0 - * @see ConsumeObservationConvention + * @see DeliverObservationConvention */ -public class DefaultConsumeObservationConvention implements ConsumeObservationConvention { +public class DefaultDeliverObservationConvention implements DeliverObservationConvention { private final String name; + private final String operation; - public DefaultConsumeObservationConvention() { - this("rabbitmq.consume"); - } - - public DefaultConsumeObservationConvention(String name) { + public DefaultDeliverObservationConvention(String name, String operation) { this.name = name; + this.operation = operation; } @Override @@ -44,8 +41,8 @@ public String getName() { } @Override - public String getContextualName(ConsumeContext context) { - return source(context.getQueue()) + " consume"; + public String getContextualName(DeliverContext context) { + return source(context.getQueue()) + " " + operation; } private String exchange(String destination) { @@ -57,14 +54,14 @@ private String source(String destination) { } @Override - public KeyValues getLowCardinalityKeyValues(ConsumeContext context) { + public KeyValues getLowCardinalityKeyValues(DeliverContext context) { return KeyValues.of( - LowCardinalityTags.MESSAGING_OPERATION.withValue("consume"), + LowCardinalityTags.MESSAGING_OPERATION.withValue(this.operation), LowCardinalityTags.MESSAGING_SYSTEM.withValue("rabbitmq")); } @Override - public KeyValues getHighCardinalityKeyValues(ConsumeContext context) { + public KeyValues getHighCardinalityKeyValues(DeliverContext context) { return KeyValues.of( HighCardinalityTags.MESSAGING_ROUTING_KEY.withValue(context.getRoutingKey()), HighCardinalityTags.MESSAGING_DESTINATION_NAME.withValue(exchange(context.getExchange())), diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultPublishObservationConvention.java b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultPublishObservationConvention.java index 3880eec4ff..84c450fdda 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultPublishObservationConvention.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultPublishObservationConvention.java @@ -12,7 +12,6 @@ // // If you have any questions regarding licensing, please contact us at // info@rabbitmq.com. - package com.rabbitmq.client.observation.micrometer; import com.rabbitmq.client.observation.micrometer.RabbitMqObservationDocumentation.HighCardinalityTags; @@ -24,7 +23,6 @@ * Default implementation of {@link PublishObservationConvention}. * * @since 5.18.0 - * @see RabbitMqObservationDocumentation */ public class DefaultPublishObservationConvention implements PublishObservationConvention { diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/ConsumeContext.java b/src/main/java/com/rabbitmq/client/observation/micrometer/DeliverContext.java similarity index 89% rename from src/main/java/com/rabbitmq/client/observation/micrometer/ConsumeContext.java rename to src/main/java/com/rabbitmq/client/observation/micrometer/DeliverContext.java index f7cbb53d96..86f2eb1468 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/ConsumeContext.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/DeliverContext.java @@ -12,7 +12,6 @@ // // If you have any questions regarding licensing, please contact us at // info@rabbitmq.com. - package com.rabbitmq.client.observation.micrometer; import io.micrometer.observation.transport.ReceiverContext; @@ -24,15 +23,19 @@ * * @since 5.18.0 */ -public class ConsumeContext extends ReceiverContext> { +public class DeliverContext extends ReceiverContext> { private final String exchange; private final String routingKey; private final int payloadSizeBytes; private final String queue; - ConsumeContext(String exchange, String routingKey, String queue, Map headers, - int payloadSizeBytes) { + DeliverContext( + String exchange, + String routingKey, + String queue, + Map headers, + int payloadSizeBytes) { super( (hdrs, key) -> { Object result = hdrs.get(key); @@ -63,5 +66,4 @@ public int getPayloadSizeBytes() { public String getQueue() { return queue; } - } diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/ConsumeObservationConvention.java b/src/main/java/com/rabbitmq/client/observation/micrometer/DeliverObservationConvention.java similarity index 85% rename from src/main/java/com/rabbitmq/client/observation/micrometer/ConsumeObservationConvention.java rename to src/main/java/com/rabbitmq/client/observation/micrometer/DeliverObservationConvention.java index 38ce2aa333..c34ec4094f 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/ConsumeObservationConvention.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/DeliverObservationConvention.java @@ -12,7 +12,6 @@ // // If you have any questions regarding licensing, please contact us at // info@rabbitmq.com. - package com.rabbitmq.client.observation.micrometer; import io.micrometer.observation.Observation; @@ -22,12 +21,11 @@ * {@link ObservationConvention} for RabbitMQ client instrumentation. * * @since 5.18.0 - * @see DefaultPublishObservationConvention */ -public interface ConsumeObservationConvention extends ObservationConvention { +public interface DeliverObservationConvention extends ObservationConvention { @Override default boolean supportsContext(Observation.Context context) { - return context instanceof ConsumeContext; + return context instanceof DeliverContext; } } diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java b/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java index fa42721255..2060cff0e1 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java @@ -12,7 +12,6 @@ // // If you have any questions regarding licensing, please contact us at // info@rabbitmq.com. - package com.rabbitmq.client.observation.micrometer; import com.rabbitmq.client.*; @@ -29,24 +28,33 @@ class MicrometerObservationCollector implements ObservationCollector { private final ObservationRegistry registry; private final PublishObservationConvention customPublishConvention, defaultPublishConvention; - private final ConsumeObservationConvention customConsumeConvention, defaultConsumeConvention; + private final DeliverObservationConvention customProcessConvention, defaultProcessConvention; + private final DeliverObservationConvention customReceiveConvention, defaultReceiveConvention; MicrometerObservationCollector( ObservationRegistry registry, PublishObservationConvention customPublishConvention, PublishObservationConvention defaultPublishConvention, - ConsumeObservationConvention customConsumeConvention, - ConsumeObservationConvention defaultConsumeConvention) { + DeliverObservationConvention customProcessConvention, + DeliverObservationConvention defaultProcessConvention, + DeliverObservationConvention customReceiveConvention, + DeliverObservationConvention defaultReceiveConvention) { this.registry = registry; this.customPublishConvention = customPublishConvention; this.defaultPublishConvention = defaultPublishConvention; - this.customConsumeConvention = customConsumeConvention; - this.defaultConsumeConvention = defaultConsumeConvention; + this.customProcessConvention = customProcessConvention; + this.defaultProcessConvention = defaultProcessConvention; + this.customReceiveConvention = customReceiveConvention; + this.defaultReceiveConvention = defaultReceiveConvention; } @Override - public void publish(PublishCall call, AMQP.Basic.Publish publish, AMQP.BasicProperties properties, - byte [] body, ConnectionInfo connectionInfo) + public void publish( + PublishCall call, + AMQP.Basic.Publish publish, + AMQP.BasicProperties properties, + byte[] body, + ConnectionInfo connectionInfo) throws IOException { // TODO: Is this for fire and forget or request reply too? If r-r then we have to have 2 // contexts @@ -57,17 +65,14 @@ public void publish(PublishCall call, AMQP.Basic.Publish publish, AMQP.BasicProp headers = new HashMap<>(properties.getHeaders()); } PublishContext micrometerPublishContext = - new PublishContext(publish.getExchange(), publish.getRoutingKey(), headers, + new PublishContext( + publish.getExchange(), + publish.getRoutingKey(), + headers, body == null ? 0 : body.length, connectionInfo); AMQP.BasicProperties.Builder builder = properties.builder(); builder.headers(headers); - // TODO give possibility to create the publish observation - // the custom convention is already a property, the default convention could be a property as - // well. - // the name (in default convention) could also be set in a simple way, from the base - // configuration - // no need to give access to the other 2 parameters Observation observation = RabbitMqObservationDocumentation.PUBLISH_OBSERVATION.observation( this.customPublishConvention, @@ -88,7 +93,39 @@ public void publish(PublishCall call, AMQP.Basic.Publish publish, AMQP.BasicProp public Consumer basicConsume(String queue, String consumerTag, Consumer consumer) { return new ObservationConsumer( queue, - consumer, this.registry, this.customConsumeConvention, this.defaultConsumeConvention); + consumer, + this.registry, + this.customProcessConvention, + this.defaultProcessConvention); + } + + @Override + public GetResponse basicGet(BasicGetCall call, String queue) { + Observation parentObservation = Observation.start("rabbitmq.receive", registry); + try { + GetResponse response = call.get(); + if (response != null) { + DeliverContext context = + new DeliverContext( + response.getEnvelope().getExchange(), + response.getEnvelope().getRoutingKey(), + queue, + response.getProps().getHeaders(), + response.getBody() == null ? 0 : response.getBody().length); + Observation observation = + RabbitMqObservationDocumentation.RECEIVE_OBSERVATION.observation( + customReceiveConvention, defaultReceiveConvention, () -> context, registry); + observation.parentObservation(parentObservation); + observation.start(); + observation.stop(); + } + return response; + } catch (RuntimeException e) { + parentObservation.error(e); + throw e; + } finally { + parentObservation.stop(); + } } private static class ObservationConsumer implements Consumer { @@ -98,14 +135,14 @@ private static class ObservationConsumer implements Consumer { private final ObservationRegistry observationRegistry; - private final ConsumeObservationConvention customConsumeConvention, defaultConsumeConvention; + private final DeliverObservationConvention customConsumeConvention, defaultConsumeConvention; private ObservationConsumer( String queue, Consumer delegate, ObservationRegistry observationRegistry, - ConsumeObservationConvention customConsumeConvention, - ConsumeObservationConvention defaultConsumeConvention) { + DeliverObservationConvention customConsumeConvention, + DeliverObservationConvention defaultConsumeConvention) { this.queue = queue; this.delegate = delegate; this.observationRegistry = observationRegistry; @@ -148,16 +185,15 @@ public void handleDelivery( } else { headers = properties.getHeaders(); } - ConsumeContext context = - new ConsumeContext(envelope.getExchange(), envelope.getRoutingKey(), queue, headers, body == null ? 0 : body.length); - // TODO give possibility to create the consume observation - // the custom convention is already a property, the default convention could be a property as - // well. - // the name (in default convention) could also be set in a simple way, from the base - // configuration - // no need to give access to the other 2 parameters + DeliverContext context = + new DeliverContext( + envelope.getExchange(), + envelope.getRoutingKey(), + queue, + headers, + body == null ? 0 : body.length); Observation observation = - RabbitMqObservationDocumentation.CONSUME_OBSERVATION.observation( + RabbitMqObservationDocumentation.PROCESS_OBSERVATION.observation( customConsumeConvention, defaultConsumeConvention, () -> context, diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollectorBuilder.java b/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollectorBuilder.java index fa78587066..10e80556d4 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollectorBuilder.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollectorBuilder.java @@ -12,13 +12,15 @@ // // If you have any questions regarding licensing, please contact us at // info@rabbitmq.com. - package com.rabbitmq.client.observation.micrometer; import com.rabbitmq.client.observation.ObservationCollector; import io.micrometer.observation.ObservationRegistry; /** + * Builder to configure and create Micrometer + * Observation implementation of {@link ObservationCollector}. + * * @since 5.18.0 */ public class MicrometerObservationCollectorBuilder { @@ -27,9 +29,12 @@ public class MicrometerObservationCollectorBuilder { private PublishObservationConvention customPublishObservationConvention; private PublishObservationConvention defaultPublishObservationConvention = new DefaultPublishObservationConvention(); - private ConsumeObservationConvention customConsumeObservationConvention; - private ConsumeObservationConvention defaultConsumeObservationConvention = - new DefaultConsumeObservationConvention(); + private DeliverObservationConvention customProcessObservationConvention; + private DeliverObservationConvention defaultProcessObservationConvention = + new DefaultDeliverObservationConvention("rabbitmq.process", "process"); + private DeliverObservationConvention customReceiveObservationConvention; + private DeliverObservationConvention defaultReceiveObservationConvention = + new DefaultDeliverObservationConvention("rabbitmq.receive", "receive"); public MicrometerObservationCollectorBuilder registry(ObservationRegistry registry) { this.registry = registry; @@ -48,25 +53,38 @@ public MicrometerObservationCollectorBuilder defaultPublishObservationConvention return this; } - public MicrometerObservationCollectorBuilder customConsumeObservationConvention( - ConsumeObservationConvention customConsumeObservationConvention) { - this.customConsumeObservationConvention = customConsumeObservationConvention; + public MicrometerObservationCollectorBuilder customProcessObservationConvention( + DeliverObservationConvention customConsumeObservationConvention) { + this.customProcessObservationConvention = customConsumeObservationConvention; + return this; + } + + public MicrometerObservationCollectorBuilder defaultProcessObservationConvention( + DeliverObservationConvention defaultConsumeObservationConvention) { + this.defaultProcessObservationConvention = defaultConsumeObservationConvention; + return this; + } + + public MicrometerObservationCollectorBuilder customReceiveObservationConvention( + DeliverObservationConvention customReceiveObservationConvention) { + this.customReceiveObservationConvention = customReceiveObservationConvention; return this; } - public MicrometerObservationCollectorBuilder defaultConsumeObservationConvention( - ConsumeObservationConvention defaultConsumeObservationConvention) { - this.defaultConsumeObservationConvention = defaultConsumeObservationConvention; + public MicrometerObservationCollectorBuilder defaultReceiveObservationConvention( + DeliverObservationConvention defaultReceiveObservationConvention) { + this.defaultReceiveObservationConvention = defaultReceiveObservationConvention; return this; } public ObservationCollector build() { return new MicrometerObservationCollector( - this.registry, - this.customPublishObservationConvention, - this.defaultPublishObservationConvention, - this.customConsumeObservationConvention, - this.defaultConsumeObservationConvention - ); + this.registry, + this.customPublishObservationConvention, + this.defaultPublishObservationConvention, + this.customProcessObservationConvention, + this.defaultProcessObservationConvention, + this.customReceiveObservationConvention, + this.defaultReceiveObservationConvention); } } diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/PublishContext.java b/src/main/java/com/rabbitmq/client/observation/micrometer/PublishContext.java index d5c450279d..a559b0b526 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/PublishContext.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/PublishContext.java @@ -12,7 +12,6 @@ // // If you have any questions regarding licensing, please contact us at // info@rabbitmq.com. - package com.rabbitmq.client.observation.micrometer; import com.rabbitmq.client.observation.ObservationCollector; @@ -33,7 +32,10 @@ public class PublishContext extends SenderContext> { private final ObservationCollector.ConnectionInfo connectionInfo; PublishContext( - String exchange, String routingKey, Map headers, int payloadSizeBytes, + String exchange, + String routingKey, + Map headers, + int payloadSizeBytes, ObservationCollector.ConnectionInfo connectionInfo) { super((hdrs, key, value) -> hdrs.put(key, value)); this.exchange = exchange; diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/PublishObservationConvention.java b/src/main/java/com/rabbitmq/client/observation/micrometer/PublishObservationConvention.java index 699921ba6f..8b9aeaf03f 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/PublishObservationConvention.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/PublishObservationConvention.java @@ -12,7 +12,6 @@ // // If you have any questions regarding licensing, please contact us at // info@rabbitmq.com. - package com.rabbitmq.client.observation.micrometer; import io.micrometer.observation.Observation; @@ -22,7 +21,6 @@ * {@link ObservationConvention} for RabbitMQ client instrumentation. * * @since 5.18.0 - * @see DefaultPublishObservationConvention */ public interface PublishObservationConvention extends ObservationConvention { diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/RabbitMqObservationDocumentation.java b/src/main/java/com/rabbitmq/client/observation/micrometer/RabbitMqObservationDocumentation.java index be0f98d6dd..f6563a1b2e 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/RabbitMqObservationDocumentation.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/RabbitMqObservationDocumentation.java @@ -12,7 +12,6 @@ // // If you have any questions regarding licensing, please contact us at // info@rabbitmq.com. - package com.rabbitmq.client.observation.micrometer; import io.micrometer.common.docs.KeyName; @@ -26,8 +25,6 @@ * @since 5.18.0 */ public enum RabbitMqObservationDocumentation implements ObservationDocumentation { - - /** Observation for Rabbit Client publishers. */ PUBLISH_OBSERVATION { @Override @@ -42,13 +39,26 @@ public KeyName[] getLowCardinalityKeyNames() { } }, - /** Observation for Rabbit Client consumers. */ - CONSUME_OBSERVATION { + PROCESS_OBSERVATION { + + @Override + public Class> + getDefaultConvention() { + return DefaultDeliverObservationConvention.class; + } + + @Override + public KeyName[] getLowCardinalityKeyNames() { + return LowCardinalityTags.values(); + } + }, + + RECEIVE_OBSERVATION { @Override public Class> getDefaultConvention() { - return DefaultConsumeObservationConvention.class; + return DefaultDeliverObservationConvention.class; } @Override diff --git a/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java b/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java index 4955611b12..0af4d3ecfd 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java +++ b/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java @@ -12,7 +12,6 @@ // // If you have any questions regarding licensing, please contact us at // info@rabbitmq.com. - package com.rabbitmq.client.test.functional; import static com.rabbitmq.client.test.TestUtils.waitAtMost; @@ -29,8 +28,10 @@ import io.micrometer.tracing.test.simple.SpansAssert; import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.util.Objects; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; import org.junit.jupiter.api.Nested; public class MicrometerObservationCollectorMetrics extends BrokerTestCase { @@ -142,9 +143,72 @@ public SampleTestRunnerConsumer yourCode() { .hasTag("messaging.destination.name", "amq.default") .hasTag("messaging.message.payload_size_bytes", String.valueOf(PAYLOAD.length)) .hasTagWithKey("net.sock.peer.addr") - .hasTag("net.sock.peer.port", "5672"); + .hasTag("net.sock.peer.port", "5672") + .hasTag("net.protocol.name", "amqp") + .hasTag("net.protocol.version", "0.9.1"); + SpanAssert.assertThat(buildingBlocks.getFinishedSpans().get(1)) + .hasNameEqualTo("metrics.queue process") + .hasTag("messaging.rabbitmq.destination.routing_key", "metrics.queue") + .hasTag("messaging.destination.name", "amq.default") + .hasTag("messaging.source.name", "metrics.queue") + .hasTag("messaging.message.payload_size_bytes", String.valueOf(PAYLOAD.length)); + waitAtMost( + () -> + getMeterRegistry().find("rabbitmq.publish").timer() != null + && getMeterRegistry().find("rabbitmq.process").timer() != null); + getMeterRegistry() + .get("rabbitmq.publish") + .tag("messaging.operation", "publish") + .tag("messaging.system", "rabbitmq") + .timer(); + getMeterRegistry() + .get("rabbitmq.process") + .tag("messaging.operation", "process") + .tag("messaging.system", "rabbitmq") + .timer(); + } finally { + safeClose(publishConnection); + safeClose(consumeConnection); + } + }; + } + } + + @Nested + class PublishBasicGet extends IntegrationTest { + + @Override + public SampleTestRunnerConsumer yourCode() { + return (buildingBlocks, meterRegistry) -> { + ConnectionFactory connectionFactory = createConnectionFactory(getObservationRegistry()); + Connection publishConnection = null, consumeConnection = null; + try { + publishConnection = connectionFactory.newConnection(); + Channel channel = publishConnection.createChannel(); + + sendMessage(channel); + + consumeConnection = connectionFactory.newConnection(); + Channel basicGetChannel = consumeConnection.createChannel(); + waitAtMost(() -> basicGetChannel.basicGet(QUEUE, true) != null); + + waitAtMost(() -> buildingBlocks.getFinishedSpans().size() >= 3); + System.out.println( + buildingBlocks.getFinishedSpans().stream() + .map(Objects::toString) + .collect(Collectors.joining("\n"))); + SpansAssert.assertThat(buildingBlocks.getFinishedSpans()).haveSameTraceId(); + SpanAssert.assertThat(buildingBlocks.getFinishedSpans().get(0)) + .hasNameEqualTo("metrics.queue publish") + .hasTag("messaging.rabbitmq.destination.routing_key", "metrics.queue") + .hasTag("messaging.destination.name", "amq.default") + .hasTag("messaging.message.payload_size_bytes", String.valueOf(PAYLOAD.length)) + .hasTagWithKey("net.sock.peer.addr") + .hasTag("net.sock.peer.port", "5672") + .hasTag("net.protocol.name", "amqp") + .hasTag("net.protocol.version", "0.9.1"); SpanAssert.assertThat(buildingBlocks.getFinishedSpans().get(1)) - .hasNameEqualTo("metrics.queue consume") + .hasNameEqualTo("metrics.queue receive") .hasTag("messaging.rabbitmq.destination.routing_key", "metrics.queue") .hasTag("messaging.destination.name", "amq.default") .hasTag("messaging.source.name", "metrics.queue") @@ -152,15 +216,15 @@ public SampleTestRunnerConsumer yourCode() { waitAtMost( () -> getMeterRegistry().find("rabbitmq.publish").timer() != null - && getMeterRegistry().find("rabbitmq.consume").timer() != null); + && getMeterRegistry().find("rabbitmq.receive").timer() != null); getMeterRegistry() .get("rabbitmq.publish") .tag("messaging.operation", "publish") .tag("messaging.system", "rabbitmq") .timer(); getMeterRegistry() - .get("rabbitmq.consume") - .tag("messaging.operation", "consume") + .get("rabbitmq.receive") + .tag("messaging.operation", "receive") .tag("messaging.system", "rabbitmq") .timer(); } finally { From 5c03a2ab69ee9897415916728e110ae132a1ffa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 17 May 2023 16:40:38 +0200 Subject: [PATCH 1751/2114] Make sure headers are not null --- .../micrometer/MicrometerObservationCollector.java | 11 +++++++++-- .../MicrometerObservationCollectorMetrics.java | 1 - 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java b/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java index 2060cff0e1..26f00de845 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java @@ -85,8 +85,9 @@ public void publish( } catch (IOException | AlreadyClosedException e) { observation.error(e); throw e; + } finally { + observation.stop(); } - observation.stop(); } @Override @@ -105,12 +106,18 @@ public GetResponse basicGet(BasicGetCall call, String queue) { try { GetResponse response = call.get(); if (response != null) { + Map headers; + if (response.getProps() == null || response.getProps().getHeaders() == null) { + headers = Collections.emptyMap(); + } else { + headers = response.getProps().getHeaders(); + } DeliverContext context = new DeliverContext( response.getEnvelope().getExchange(), response.getEnvelope().getRoutingKey(), queue, - response.getProps().getHeaders(), + headers, response.getBody() == null ? 0 : response.getBody().length); Observation observation = RabbitMqObservationDocumentation.RECEIVE_OBSERVATION.observation( diff --git a/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java b/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java index 0af4d3ecfd..9c11d8d098 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java +++ b/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java @@ -191,7 +191,6 @@ public SampleTestRunnerConsumer yourCode() { consumeConnection = connectionFactory.newConnection(); Channel basicGetChannel = consumeConnection.createChannel(); waitAtMost(() -> basicGetChannel.basicGet(QUEUE, true) != null); - waitAtMost(() -> buildingBlocks.getFinishedSpans().size() >= 3); System.out.println( buildingBlocks.getFinishedSpans().stream() From c854a0a7679136ef568526c72f9aa8fc2b3cf332 Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Mon, 22 May 2023 16:15:08 +0200 Subject: [PATCH 1752/2114] Wrapping call in observe(...) and nulling sender Due to the fact that in the tests we have both the producer and the consumer and they have the same parent, the zipkin graph looks bizarre. With these changes we're changing the test sending code to simulate sending a message from a different service that will result in a creation of a new trace identifier. Due to this we will have 2 sets of trace ids created, one for sending and one for polling. Sending: null_observation -> send -> receive message Polling: test_span -> receive (very short) --- .../DefaultDeliverObservationConvention.java | 1 + .../MicrometerObservationCollector.java | 27 +++++--------- ...MicrometerObservationCollectorMetrics.java | 37 +++++++++++++++++-- 3 files changed, 44 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultDeliverObservationConvention.java b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultDeliverObservationConvention.java index 88821b7120..71a9ccfce6 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultDeliverObservationConvention.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultDeliverObservationConvention.java @@ -35,6 +35,7 @@ public DefaultDeliverObservationConvention(String name, String operation) { this.operation = operation; } + // TODO: If the name is not fixed we won't be able to parse it to automatically document the name @Override public String getName() { return name; diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java b/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java index 26f00de845..43083e9bb1 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java @@ -102,8 +102,7 @@ public Consumer basicConsume(String queue, String consumerTag, Consumer consumer @Override public GetResponse basicGet(BasicGetCall call, String queue) { - Observation parentObservation = Observation.start("rabbitmq.receive", registry); - try { + return Observation.createNotStarted("rabbitmq.receive", registry).observe(() -> { GetResponse response = call.get(); if (response != null) { Map headers; @@ -113,26 +112,20 @@ public GetResponse basicGet(BasicGetCall call, String queue) { headers = response.getProps().getHeaders(); } DeliverContext context = - new DeliverContext( - response.getEnvelope().getExchange(), - response.getEnvelope().getRoutingKey(), - queue, - headers, - response.getBody() == null ? 0 : response.getBody().length); + new DeliverContext( + response.getEnvelope().getExchange(), + response.getEnvelope().getRoutingKey(), + queue, + headers, + response.getBody() == null ? 0 : response.getBody().length); Observation observation = - RabbitMqObservationDocumentation.RECEIVE_OBSERVATION.observation( - customReceiveConvention, defaultReceiveConvention, () -> context, registry); - observation.parentObservation(parentObservation); + RabbitMqObservationDocumentation.RECEIVE_OBSERVATION.observation( + customReceiveConvention, defaultReceiveConvention, () -> context, registry); observation.start(); observation.stop(); } return response; - } catch (RuntimeException e) { - parentObservation.error(e); - throw e; - } finally { - parentObservation.stop(); - } + }); } private static class ObservationConsumer implements Consumer { diff --git a/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java b/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java index 9c11d8d098..5f9538c4ab 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java +++ b/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java @@ -22,16 +22,25 @@ import com.rabbitmq.client.observation.micrometer.MicrometerObservationCollectorBuilder; import com.rabbitmq.client.test.BrokerTestCase; import com.rabbitmq.client.test.TestUtils; +import io.micrometer.observation.Observation; import io.micrometer.observation.ObservationRegistry; +import io.micrometer.tracing.Tracer; +import io.micrometer.tracing.exporter.FinishedSpan; import io.micrometer.tracing.test.SampleTestRunner; import io.micrometer.tracing.test.simple.SpanAssert; import io.micrometer.tracing.test.simple.SpansAssert; import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.util.Collection; +import java.util.Comparator; +import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; + +import org.assertj.core.api.BDDAssertions; import org.junit.jupiter.api.Nested; public class MicrometerObservationCollectorMetrics extends BrokerTestCase { @@ -111,6 +120,17 @@ private abstract static class IntegrationTest extends SampleTestRunner { public TracingSetup[] getTracingSetup() { return new TracingSetup[] {TracingSetup.IN_MEMORY_BRAVE, TracingSetup.ZIPKIN_BRAVE}; } + + void runWithNullingObservation(ObservationRegistry registry, Tracer tracer, Observation.CheckedRunnable runnable) { + Observation noParentObservation = Observation.createNotStarted("null_observation", registry); + noParentObservation.parentObservation(null); + try (Tracer.SpanInScope ws = tracer.withSpan(null)) { + noParentObservation.observeChecked(runnable); + } + catch (Throwable e) { + throw new RuntimeException(e); + } + } } @Nested @@ -186,7 +206,7 @@ public SampleTestRunnerConsumer yourCode() { publishConnection = connectionFactory.newConnection(); Channel channel = publishConnection.createChannel(); - sendMessage(channel); + runWithNullingObservation(getObservationRegistry(), buildingBlocks.getTracer(), () -> sendMessage(channel)); consumeConnection = connectionFactory.newConnection(); Channel basicGetChannel = consumeConnection.createChannel(); @@ -196,8 +216,14 @@ public SampleTestRunnerConsumer yourCode() { buildingBlocks.getFinishedSpans().stream() .map(Objects::toString) .collect(Collectors.joining("\n"))); - SpansAssert.assertThat(buildingBlocks.getFinishedSpans()).haveSameTraceId(); - SpanAssert.assertThat(buildingBlocks.getFinishedSpans().get(0)) + Map> finishedSpans = buildingBlocks.getFinishedSpans().stream() + .collect(Collectors.groupingBy(FinishedSpan::getTraceId)); + BDDAssertions.then(finishedSpans).as("One trace id for sending, one for polling").hasSize(2); + Collection> spans = finishedSpans.values(); + List sendAndReceiveSpans = spans.stream().filter(f -> f.size() == 3).findFirst().orElseThrow(() -> new AssertionError("null_observation (fake nulling observation) -> produce -> consume")); + sendAndReceiveSpans.sort(Comparator.comparing(FinishedSpan::getStartTimestamp)); + SpanAssert.assertThat(sendAndReceiveSpans.get(0)).hasNameEqualTo("null_observation"); + SpanAssert.assertThat(sendAndReceiveSpans.get(1)) .hasNameEqualTo("metrics.queue publish") .hasTag("messaging.rabbitmq.destination.routing_key", "metrics.queue") .hasTag("messaging.destination.name", "amq.default") @@ -206,12 +232,15 @@ public SampleTestRunnerConsumer yourCode() { .hasTag("net.sock.peer.port", "5672") .hasTag("net.protocol.name", "amqp") .hasTag("net.protocol.version", "0.9.1"); - SpanAssert.assertThat(buildingBlocks.getFinishedSpans().get(1)) + SpanAssert.assertThat(sendAndReceiveSpans.get(2)) .hasNameEqualTo("metrics.queue receive") .hasTag("messaging.rabbitmq.destination.routing_key", "metrics.queue") .hasTag("messaging.destination.name", "amq.default") .hasTag("messaging.source.name", "metrics.queue") .hasTag("messaging.message.payload_size_bytes", String.valueOf(PAYLOAD.length)); + List pollingSpans = spans.stream().filter(f -> f.size() == 1).findFirst().orElseThrow(() -> new AssertionError("rabbitmq.receive (child of test span)")); + SpanAssert.assertThat(pollingSpans.get(0)) + .hasNameEqualTo("rabbitmq.receive"); waitAtMost( () -> getMeterRegistry().find("rabbitmq.publish").timer() != null From 946d30a1042a40964034eb3e647cf8cacbda34ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 23 Jun 2023 11:25:16 +0200 Subject: [PATCH 1753/2114] Finalize Micrometer Observation integration --- pom.xml | 11 +--- .../rabbitmq/client/ConnectionFactory.java | 16 +++--- .../observation/ObservationCollector.java | 3 +- .../DefaultDeliverObservationConvention.java | 2 +- .../DefaultPublishObservationConvention.java | 2 +- .../micrometer/DeliverContext.java | 2 +- .../DeliverObservationConvention.java | 2 +- .../MicrometerObservationCollector.java | 43 +++++++++------- ...MicrometerObservationCollectorBuilder.java | 2 +- .../micrometer/PublishContext.java | 2 +- .../PublishObservationConvention.java | 2 +- .../RabbitMqObservationDocumentation.java | 2 +- ...MicrometerObservationCollectorMetrics.java | 50 ++++++++----------- 13 files changed, 68 insertions(+), 71 deletions(-) diff --git a/pom.xml b/pom.xml index d538058323..7be2b6a42e 100644 --- a/pom.xml +++ b/pom.xml @@ -60,12 +60,12 @@ 1.11.1 1.1.4 1.28.0 - 1.1.4 2.15.2 1.2.12 5.9.3 5.4.0 3.24.2 + 1.1.2 9.4.51.v20230217 1.70 0.10 @@ -798,12 +798,12 @@ io.micrometer micrometer-tracing-integration-test + ${micrometer-tracing-test.version} test - @@ -813,13 +813,6 @@ pom import - - io.micrometer - micrometer-tracing-bom - ${micrometer-tracing.version} - pom - import - diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 34b4eb0d66..12fc5014c9 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -53,7 +53,6 @@ */ public class ConnectionFactory implements Cloneable { - private static final Logger LOGGER = LoggerFactory.getLogger(ConnectionFactory.class); private static final int MAX_UNSIGNED_SHORT = 65535; /** Default user name */ @@ -980,12 +979,15 @@ public MetricsCollector getMetricsCollector() { return metricsCollector; } - /** - * - * @since 5.18.0 - * @param observationCollector - */ - public void setObservationCollector(ObservationCollector observationCollector) { + /** + * Set observation collector. + * + * @param observationCollector the collector instance + * @since 5.19.0 + * @see ObservationCollector + * @see com.rabbitmq.client.observation.micrometer.MicrometerObservationCollectorBuilder + */ + public void setObservationCollector(ObservationCollector observationCollector) { this.observationCollector = observationCollector; } diff --git a/src/main/java/com/rabbitmq/client/observation/ObservationCollector.java b/src/main/java/com/rabbitmq/client/observation/ObservationCollector.java index bc10f8d684..e542d34387 100644 --- a/src/main/java/com/rabbitmq/client/observation/ObservationCollector.java +++ b/src/main/java/com/rabbitmq/client/observation/ObservationCollector.java @@ -28,8 +28,9 @@ * *

This is considered an SPI and is susceptible to change at any time. * - * @since 5.18.0 + * @since 5.19.0 * @see com.rabbitmq.client.ConnectionFactory#setObservationCollector( ObservationCollector) + * @see com.rabbitmq.client.observation.micrometer.MicrometerObservationCollectorBuilder */ public interface ObservationCollector { diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultDeliverObservationConvention.java b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultDeliverObservationConvention.java index 71a9ccfce6..12b12e4b0f 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultDeliverObservationConvention.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultDeliverObservationConvention.java @@ -22,7 +22,7 @@ /** * Default implementation of {@link DeliverObservationConvention}. * - * @since 5.18.0 + * @since 5.19.0 * @see DeliverObservationConvention */ public class DefaultDeliverObservationConvention implements DeliverObservationConvention { diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultPublishObservationConvention.java b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultPublishObservationConvention.java index 84c450fdda..019e32367f 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultPublishObservationConvention.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultPublishObservationConvention.java @@ -22,7 +22,7 @@ /** * Default implementation of {@link PublishObservationConvention}. * - * @since 5.18.0 + * @since 5.19.0 */ public class DefaultPublishObservationConvention implements PublishObservationConvention { diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/DeliverContext.java b/src/main/java/com/rabbitmq/client/observation/micrometer/DeliverContext.java index 86f2eb1468..2209d7897c 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/DeliverContext.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/DeliverContext.java @@ -21,7 +21,7 @@ * {@link io.micrometer.observation.Observation.Context} for use with RabbitMQ client {@link * io.micrometer.observation.Observation} instrumentation. * - * @since 5.18.0 + * @since 5.19.0 */ public class DeliverContext extends ReceiverContext> { diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/DeliverObservationConvention.java b/src/main/java/com/rabbitmq/client/observation/micrometer/DeliverObservationConvention.java index c34ec4094f..ba10eca747 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/DeliverObservationConvention.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/DeliverObservationConvention.java @@ -20,7 +20,7 @@ /** * {@link ObservationConvention} for RabbitMQ client instrumentation. * - * @since 5.18.0 + * @since 5.19.0 */ public interface DeliverObservationConvention extends ObservationConvention { diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java b/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java index 43083e9bb1..cea17f70a1 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java @@ -102,30 +102,37 @@ public Consumer basicConsume(String queue, String consumerTag, Consumer consumer @Override public GetResponse basicGet(BasicGetCall call, String queue) { - return Observation.createNotStarted("rabbitmq.receive", registry).observe(() -> { - GetResponse response = call.get(); - if (response != null) { - Map headers; - if (response.getProps() == null || response.getProps().getHeaders() == null) { - headers = Collections.emptyMap(); - } else { - headers = response.getProps().getHeaders(); - } - DeliverContext context = - new DeliverContext( + return Observation.createNotStarted("rabbitmq.receive", registry) + .observe( + () -> { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + GetResponse response = call.get(); + if (response != null) { + Map headers; + if (response.getProps() == null || response.getProps().getHeaders() == null) { + headers = Collections.emptyMap(); + } else { + headers = response.getProps().getHeaders(); + } + DeliverContext context = + new DeliverContext( response.getEnvelope().getExchange(), response.getEnvelope().getRoutingKey(), queue, headers, response.getBody() == null ? 0 : response.getBody().length); - Observation observation = - RabbitMqObservationDocumentation.RECEIVE_OBSERVATION.observation( + Observation observation = + RabbitMqObservationDocumentation.RECEIVE_OBSERVATION.observation( customReceiveConvention, defaultReceiveConvention, () -> context, registry); - observation.start(); - observation.stop(); - } - return response; - }); + observation.start(); + observation.stop(); + } + return response; + }); } private static class ObservationConsumer implements Consumer { diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollectorBuilder.java b/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollectorBuilder.java index 10e80556d4..464ec2aa15 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollectorBuilder.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollectorBuilder.java @@ -21,7 +21,7 @@ * Builder to configure and create Micrometer * Observation implementation of {@link ObservationCollector}. * - * @since 5.18.0 + * @since 5.19.0 */ public class MicrometerObservationCollectorBuilder { diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/PublishContext.java b/src/main/java/com/rabbitmq/client/observation/micrometer/PublishContext.java index a559b0b526..51b3e06be4 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/PublishContext.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/PublishContext.java @@ -22,7 +22,7 @@ * {@link io.micrometer.observation.Observation.Context} for use with RabbitMQ client {@link * io.micrometer.observation.Observation} instrumentation. * - * @since 5.18.0 + * @since 5.19.0 */ public class PublishContext extends SenderContext> { diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/PublishObservationConvention.java b/src/main/java/com/rabbitmq/client/observation/micrometer/PublishObservationConvention.java index 8b9aeaf03f..f6fce73ff2 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/PublishObservationConvention.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/PublishObservationConvention.java @@ -20,7 +20,7 @@ /** * {@link ObservationConvention} for RabbitMQ client instrumentation. * - * @since 5.18.0 + * @since 5.19.0 */ public interface PublishObservationConvention extends ObservationConvention { diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/RabbitMqObservationDocumentation.java b/src/main/java/com/rabbitmq/client/observation/micrometer/RabbitMqObservationDocumentation.java index f6563a1b2e..3ce9af4647 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/RabbitMqObservationDocumentation.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/RabbitMqObservationDocumentation.java @@ -22,7 +22,7 @@ /** * {@link ObservationDocumentation} for RabbitMQ Clients. * - * @since 5.18.0 + * @since 5.19.0 */ public enum RabbitMqObservationDocumentation implements ObservationDocumentation { PUBLISH_OBSERVATION { diff --git a/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java b/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java index 5f9538c4ab..cfc6a01d5c 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java +++ b/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java @@ -22,9 +22,8 @@ import com.rabbitmq.client.observation.micrometer.MicrometerObservationCollectorBuilder; import com.rabbitmq.client.test.BrokerTestCase; import com.rabbitmq.client.test.TestUtils; -import io.micrometer.observation.Observation; +import io.micrometer.observation.NullObservation; import io.micrometer.observation.ObservationRegistry; -import io.micrometer.tracing.Tracer; import io.micrometer.tracing.exporter.FinishedSpan; import io.micrometer.tracing.test.SampleTestRunner; import io.micrometer.tracing.test.simple.SpanAssert; @@ -35,11 +34,9 @@ import java.util.Comparator; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; - import org.assertj.core.api.BDDAssertions; import org.junit.jupiter.api.Nested; @@ -120,17 +117,6 @@ private abstract static class IntegrationTest extends SampleTestRunner { public TracingSetup[] getTracingSetup() { return new TracingSetup[] {TracingSetup.IN_MEMORY_BRAVE, TracingSetup.ZIPKIN_BRAVE}; } - - void runWithNullingObservation(ObservationRegistry registry, Tracer tracer, Observation.CheckedRunnable runnable) { - Observation noParentObservation = Observation.createNotStarted("null_observation", registry); - noParentObservation.parentObservation(null); - try (Tracer.SpanInScope ws = tracer.withSpan(null)) { - noParentObservation.observeChecked(runnable); - } - catch (Throwable e) { - throw new RuntimeException(e); - } - } } @Nested @@ -206,24 +192,29 @@ public SampleTestRunnerConsumer yourCode() { publishConnection = connectionFactory.newConnection(); Channel channel = publishConnection.createChannel(); - runWithNullingObservation(getObservationRegistry(), buildingBlocks.getTracer(), () -> sendMessage(channel)); + new NullObservation(getObservationRegistry()).observeChecked(() -> sendMessage(channel)); consumeConnection = connectionFactory.newConnection(); Channel basicGetChannel = consumeConnection.createChannel(); waitAtMost(() -> basicGetChannel.basicGet(QUEUE, true) != null); waitAtMost(() -> buildingBlocks.getFinishedSpans().size() >= 3); - System.out.println( + Map> finishedSpans = buildingBlocks.getFinishedSpans().stream() - .map(Objects::toString) - .collect(Collectors.joining("\n"))); - Map> finishedSpans = buildingBlocks.getFinishedSpans().stream() .collect(Collectors.groupingBy(FinishedSpan::getTraceId)); - BDDAssertions.then(finishedSpans).as("One trace id for sending, one for polling").hasSize(2); + BDDAssertions.then(finishedSpans) + .as("One trace id for sending, one for polling") + .hasSize(2); Collection> spans = finishedSpans.values(); - List sendAndReceiveSpans = spans.stream().filter(f -> f.size() == 3).findFirst().orElseThrow(() -> new AssertionError("null_observation (fake nulling observation) -> produce -> consume")); + List sendAndReceiveSpans = + spans.stream() + .filter(f -> f.size() == 2) + .findFirst() + .orElseThrow( + () -> + new AssertionError( + "null_observation (fake nulling observation) -> produce -> consume")); sendAndReceiveSpans.sort(Comparator.comparing(FinishedSpan::getStartTimestamp)); - SpanAssert.assertThat(sendAndReceiveSpans.get(0)).hasNameEqualTo("null_observation"); - SpanAssert.assertThat(sendAndReceiveSpans.get(1)) + SpanAssert.assertThat(sendAndReceiveSpans.get(0)) .hasNameEqualTo("metrics.queue publish") .hasTag("messaging.rabbitmq.destination.routing_key", "metrics.queue") .hasTag("messaging.destination.name", "amq.default") @@ -232,15 +223,18 @@ public SampleTestRunnerConsumer yourCode() { .hasTag("net.sock.peer.port", "5672") .hasTag("net.protocol.name", "amqp") .hasTag("net.protocol.version", "0.9.1"); - SpanAssert.assertThat(sendAndReceiveSpans.get(2)) + SpanAssert.assertThat(sendAndReceiveSpans.get(1)) .hasNameEqualTo("metrics.queue receive") .hasTag("messaging.rabbitmq.destination.routing_key", "metrics.queue") .hasTag("messaging.destination.name", "amq.default") .hasTag("messaging.source.name", "metrics.queue") .hasTag("messaging.message.payload_size_bytes", String.valueOf(PAYLOAD.length)); - List pollingSpans = spans.stream().filter(f -> f.size() == 1).findFirst().orElseThrow(() -> new AssertionError("rabbitmq.receive (child of test span)")); - SpanAssert.assertThat(pollingSpans.get(0)) - .hasNameEqualTo("rabbitmq.receive"); + List pollingSpans = + spans.stream() + .filter(f -> f.size() == 1) + .findFirst() + .orElseThrow(() -> new AssertionError("rabbitmq.receive (child of test span)")); + SpanAssert.assertThat(pollingSpans.get(0)).hasNameEqualTo("rabbitmq.receive"); waitAtMost( () -> getMeterRegistry().find("rabbitmq.publish").timer() != null From 25855cf6fb745d29bdc51cc26696b4c246c428ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 23 Jun 2023 16:28:47 +0200 Subject: [PATCH 1754/2114] Add tags to receive observation --- .../micrometer/MicrometerObservationCollector.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java b/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java index cea17f70a1..fa487b2f1d 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java @@ -16,6 +16,7 @@ import com.rabbitmq.client.*; import com.rabbitmq.client.observation.ObservationCollector; +import io.micrometer.common.KeyValues; import io.micrometer.observation.Observation; import io.micrometer.observation.ObservationRegistry; import java.io.IOException; @@ -56,8 +57,6 @@ public void publish( byte[] body, ConnectionInfo connectionInfo) throws IOException { - // TODO: Is this for fire and forget or request reply too? If r-r then we have to have 2 - // contexts Map headers; if (properties.getHeaders() == null) { headers = new HashMap<>(); @@ -103,13 +102,14 @@ public Consumer basicConsume(String queue, String consumerTag, Consumer consumer @Override public GetResponse basicGet(BasicGetCall call, String queue) { return Observation.createNotStarted("rabbitmq.receive", registry) + .highCardinalityKeyValues( + KeyValues.of( + RabbitMqObservationDocumentation.LowCardinalityTags.MESSAGING_OPERATION.withValue( + "receive"), + RabbitMqObservationDocumentation.LowCardinalityTags.MESSAGING_SYSTEM.withValue( + "rabbitmq"))) .observe( () -> { - try { - Thread.sleep(100); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } GetResponse response = call.get(); if (response != null) { Map headers; From d0193543e00b91489c3f86a5be5f7524f5870c42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 26 Jun 2023 11:20:25 +0200 Subject: [PATCH 1755/2114] Add observation documentation generation --- generate-observation-documentation.sh | 6 +++ .../DefaultDeliverObservationConvention.java | 12 +----- .../DefaultProcessObservationConvention.java | 27 +++++++++++++ .../DefaultReceiveObservationConvention.java | 27 +++++++++++++ ...MicrometerObservationCollectorBuilder.java | 4 +- .../RabbitMqObservationDocumentation.java | 40 ++++--------------- 6 files changed, 71 insertions(+), 45 deletions(-) create mode 100755 generate-observation-documentation.sh create mode 100644 src/main/java/com/rabbitmq/client/observation/micrometer/DefaultProcessObservationConvention.java create mode 100644 src/main/java/com/rabbitmq/client/observation/micrometer/DefaultReceiveObservationConvention.java diff --git a/generate-observation-documentation.sh b/generate-observation-documentation.sh new file mode 100755 index 0000000000..be0e4815bb --- /dev/null +++ b/generate-observation-documentation.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +./mvnw -q -P '!setup-test-cluster' test-compile exec:java \ + -Dexec.mainClass=io.micrometer.docs.DocsGeneratorCommand \ + -Dexec.classpathScope="test" \ + -Dexec.args='src/main/java/com/rabbitmq/client/observation/micrometer .* target/micrometer-observation-docs' \ No newline at end of file diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultDeliverObservationConvention.java b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultDeliverObservationConvention.java index 12b12e4b0f..55a17e5d8a 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultDeliverObservationConvention.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultDeliverObservationConvention.java @@ -25,22 +25,14 @@ * @since 5.19.0 * @see DeliverObservationConvention */ -public class DefaultDeliverObservationConvention implements DeliverObservationConvention { +abstract class DefaultDeliverObservationConvention implements DeliverObservationConvention { - private final String name; private final String operation; - public DefaultDeliverObservationConvention(String name, String operation) { - this.name = name; + public DefaultDeliverObservationConvention(String operation) { this.operation = operation; } - // TODO: If the name is not fixed we won't be able to parse it to automatically document the name - @Override - public String getName() { - return name; - } - @Override public String getContextualName(DeliverContext context) { return source(context.getQueue()) + " " + operation; diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultProcessObservationConvention.java b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultProcessObservationConvention.java new file mode 100644 index 0000000000..b7233adfae --- /dev/null +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultProcessObservationConvention.java @@ -0,0 +1,27 @@ +// Copyright (c) 2023 VMware, Inc. or its affiliates. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. +package com.rabbitmq.client.observation.micrometer; + +public class DefaultProcessObservationConvention extends DefaultDeliverObservationConvention { + + public DefaultProcessObservationConvention(String operation) { + super(operation); + } + + @Override + public String getName() { + return "rabbitmq.process"; + } +} diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultReceiveObservationConvention.java b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultReceiveObservationConvention.java new file mode 100644 index 0000000000..7a4bd0317b --- /dev/null +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultReceiveObservationConvention.java @@ -0,0 +1,27 @@ +// Copyright (c) 2023 VMware, Inc. or its affiliates. All rights reserved. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. +package com.rabbitmq.client.observation.micrometer; + +public class DefaultReceiveObservationConvention extends DefaultDeliverObservationConvention { + + public DefaultReceiveObservationConvention(String operation) { + super(operation); + } + + @Override + public String getName() { + return "rabbitmq.receive"; + } +} diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollectorBuilder.java b/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollectorBuilder.java index 464ec2aa15..d808e249b5 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollectorBuilder.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollectorBuilder.java @@ -31,10 +31,10 @@ public class MicrometerObservationCollectorBuilder { new DefaultPublishObservationConvention(); private DeliverObservationConvention customProcessObservationConvention; private DeliverObservationConvention defaultProcessObservationConvention = - new DefaultDeliverObservationConvention("rabbitmq.process", "process"); + new DefaultProcessObservationConvention("process"); private DeliverObservationConvention customReceiveObservationConvention; private DeliverObservationConvention defaultReceiveObservationConvention = - new DefaultDeliverObservationConvention("rabbitmq.receive", "receive"); + new DefaultReceiveObservationConvention("receive"); public MicrometerObservationCollectorBuilder registry(ObservationRegistry registry) { this.registry = registry; diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/RabbitMqObservationDocumentation.java b/src/main/java/com/rabbitmq/client/observation/micrometer/RabbitMqObservationDocumentation.java index 3ce9af4647..1b169d838f 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/RabbitMqObservationDocumentation.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/RabbitMqObservationDocumentation.java @@ -25,6 +25,7 @@ * @since 5.19.0 */ public enum RabbitMqObservationDocumentation implements ObservationDocumentation { + /** Observation for publishing a message. */ PUBLISH_OBSERVATION { @Override @@ -39,12 +40,13 @@ public KeyName[] getLowCardinalityKeyNames() { } }, + /** Observation for processing a message. */ PROCESS_OBSERVATION { @Override public Class> getDefaultConvention() { - return DefaultDeliverObservationConvention.class; + return DefaultProcessObservationConvention.class; } @Override @@ -53,12 +55,13 @@ public KeyName[] getLowCardinalityKeyNames() { } }, + /** Observation for polling for a message with basic.get. */ RECEIVE_OBSERVATION { @Override public Class> getDefaultConvention() { - return DefaultDeliverObservationConvention.class; + return DefaultReceiveObservationConvention.class; } @Override @@ -67,37 +70,6 @@ public KeyName[] getLowCardinalityKeyNames() { } }; - // SPAN NAME - // - // topic with spaces process - // (anonymous) publish ((anonymous) being a stable identifier for an unnamed destination) - // (anonymous) receive ((anonymous) being a stable identifier for an unnamed destination) - - // LOW CARDINALITY - // messaging.system = rabbitmq - // messaging.operation = publish - - // HIGH CARDINALITY - - // messaging.rabbitmq.destination.routing_key - // messaging.destination.anonymous - // messaging.destination.name - // messaging.destination.template - // messaging.destination.temporary - // messaging.batch.message_count - // messaging.message.conversation_id - // messaging.message.id - // messaging.message.payload_compressed_size_bytes - // messaging.message.payload_size_bytes - - // net.peer.name - // net.protocol.name - // net.protocol.version - // net.sock.family - // net.sock.peer.addr - // net.sock.peer.name - // net.sock.peer.port - /** Low cardinality tags. */ public enum LowCardinalityTags implements KeyName { @@ -119,6 +91,7 @@ public String asString() { } }, + /** A string identifying the protocol (AMQP). */ NET_PROTOCOL_NAME { @Override @@ -127,6 +100,7 @@ public String asString() { } }, + /** A string identifying the protocol version (0.9.1). */ NET_PROTOCOL_VERSION { @Override From 0a45f101d3a4fffb4e0612df5bc0663268986391 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Tue, 27 Jun 2023 10:42:24 +0200 Subject: [PATCH 1756/2114] Declare Micrometer documentation generation dependency --- pom.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pom.xml b/pom.xml index 7be2b6a42e..07f44f4c53 100644 --- a/pom.xml +++ b/pom.xml @@ -66,6 +66,7 @@ 5.4.0 3.24.2 1.1.2 + 1.0.2 9.4.51.v20230217 1.70 0.10 @@ -801,6 +802,12 @@ ${micrometer-tracing-test.version} test + + io.micrometer + micrometer-docs-generator + ${micrometer-docs-generator.version} + test + From afb39ff21d73204810dd9e3038fa13a4b6fc356a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 12 Jul 2023 10:59:27 +0200 Subject: [PATCH 1757/2114] Bump Micrometer to 1.11.2 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 07f44f4c53..90813fd466 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,7 @@ true 1.7.36 4.2.19 - 1.11.1 + 1.11.2 1.1.4 1.28.0 2.15.2 From ac8c721e58dbc0901bc13321ab5b1f7e8e1971e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 12 Jul 2023 17:40:23 +0200 Subject: [PATCH 1758/2114] Add flag to keep observation open --- .../MicrometerObservationCollector.java | 11 +- ...MicrometerObservationCollectorBuilder.java | 10 +- ...MicrometerObservationCollectorMetrics.java | 110 +++++++++++++++++- 3 files changed, 125 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java b/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java index fa487b2f1d..6534db522b 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java @@ -31,6 +31,7 @@ class MicrometerObservationCollector implements ObservationCollector { private final PublishObservationConvention customPublishConvention, defaultPublishConvention; private final DeliverObservationConvention customProcessConvention, defaultProcessConvention; private final DeliverObservationConvention customReceiveConvention, defaultReceiveConvention; + private final boolean keepObservationOpenOnBasicGet; MicrometerObservationCollector( ObservationRegistry registry, @@ -39,7 +40,8 @@ class MicrometerObservationCollector implements ObservationCollector { DeliverObservationConvention customProcessConvention, DeliverObservationConvention defaultProcessConvention, DeliverObservationConvention customReceiveConvention, - DeliverObservationConvention defaultReceiveConvention) { + DeliverObservationConvention defaultReceiveConvention, + boolean keepObservationOpenOnBasicGet) { this.registry = registry; this.customPublishConvention = customPublishConvention; this.defaultPublishConvention = defaultPublishConvention; @@ -47,6 +49,7 @@ class MicrometerObservationCollector implements ObservationCollector { this.defaultProcessConvention = defaultProcessConvention; this.customReceiveConvention = customReceiveConvention; this.defaultReceiveConvention = defaultReceiveConvention; + this.keepObservationOpenOnBasicGet = keepObservationOpenOnBasicGet; } @Override @@ -129,7 +132,11 @@ public GetResponse basicGet(BasicGetCall call, String queue) { RabbitMqObservationDocumentation.RECEIVE_OBSERVATION.observation( customReceiveConvention, defaultReceiveConvention, () -> context, registry); observation.start(); - observation.stop(); + if (this.keepObservationOpenOnBasicGet) { + observation.openScope(); + } else { + observation.stop(); + } } return response; }); diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollectorBuilder.java b/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollectorBuilder.java index d808e249b5..5fe73254f6 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollectorBuilder.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollectorBuilder.java @@ -35,6 +35,7 @@ public class MicrometerObservationCollectorBuilder { private DeliverObservationConvention customReceiveObservationConvention; private DeliverObservationConvention defaultReceiveObservationConvention = new DefaultReceiveObservationConvention("receive"); + private boolean keepObservationOpenOnBasicGet = false; public MicrometerObservationCollectorBuilder registry(ObservationRegistry registry) { this.registry = registry; @@ -77,6 +78,12 @@ public MicrometerObservationCollectorBuilder defaultReceiveObservationConvention return this; } + public MicrometerObservationCollectorBuilder keepObservationOpenOnBasicGet( + boolean keepObservationOpenOnBasicGet) { + this.keepObservationOpenOnBasicGet = keepObservationOpenOnBasicGet; + return this; + } + public ObservationCollector build() { return new MicrometerObservationCollector( this.registry, @@ -85,6 +92,7 @@ public ObservationCollector build() { this.customProcessObservationConvention, this.defaultProcessObservationConvention, this.customReceiveObservationConvention, - this.defaultReceiveObservationConvention); + this.defaultReceiveObservationConvention, + keepObservationOpenOnBasicGet); } } diff --git a/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java b/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java index cfc6a01d5c..884b924629 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java +++ b/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java @@ -23,6 +23,7 @@ import com.rabbitmq.client.test.BrokerTestCase; import com.rabbitmq.client.test.TestUtils; import io.micrometer.observation.NullObservation; +import io.micrometer.observation.Observation; import io.micrometer.observation.ObservationRegistry; import io.micrometer.tracing.exporter.FinishedSpan; import io.micrometer.tracing.test.SampleTestRunner; @@ -51,11 +52,19 @@ private static ConnectionFactory createConnectionFactory() { private static ConnectionFactory createConnectionFactory( ObservationRegistry observationRegistry) { + return createConnectionFactory(false, observationRegistry); + } + + private static ConnectionFactory createConnectionFactory( + boolean keepObservationOpenOnBasicGet, ObservationRegistry observationRegistry) { ConnectionFactory connectionFactory = TestUtils.connectionFactory(); connectionFactory.setAutomaticRecoveryEnabled(true); if (observationRegistry != null) { ObservationCollector collector = - new MicrometerObservationCollectorBuilder().registry(observationRegistry).build(); + new MicrometerObservationCollectorBuilder() + .keepObservationOpenOnBasicGet(keepObservationOpenOnBasicGet) + .registry(observationRegistry) + .build(); connectionFactory.setObservationCollector(collector); } return connectionFactory; @@ -186,18 +195,113 @@ class PublishBasicGet extends IntegrationTest { @Override public SampleTestRunnerConsumer yourCode() { return (buildingBlocks, meterRegistry) -> { - ConnectionFactory connectionFactory = createConnectionFactory(getObservationRegistry()); + ObservationRegistry observationRegistry = getObservationRegistry(); + ConnectionFactory connectionFactory = createConnectionFactory(observationRegistry); + Connection publishConnection = null, consumeConnection = null; + try { + publishConnection = connectionFactory.newConnection(); + Channel channel = publishConnection.createChannel(); + + new NullObservation(observationRegistry).observeChecked(() -> sendMessage(channel)); + + consumeConnection = connectionFactory.newConnection(); + Channel basicGetChannel = consumeConnection.createChannel(); + waitAtMost(() -> basicGetChannel.basicGet(QUEUE, true) != null); + waitAtMost(() -> buildingBlocks.getFinishedSpans().size() >= 3); + buildingBlocks + .getFinishedSpans() + .forEach( + s -> { + System.out.println(s.getName() + " " + s.getTraceId()); + }); + Map> finishedSpans = + buildingBlocks.getFinishedSpans().stream() + .collect(Collectors.groupingBy(FinishedSpan::getTraceId)); + BDDAssertions.then(finishedSpans) + .as("One trace id for sending, one for polling") + .hasSize(2); + Collection> spans = finishedSpans.values(); + List sendAndReceiveSpans = + spans.stream() + .filter(f -> f.size() == 2) + .findFirst() + .orElseThrow( + () -> + new AssertionError( + "null_observation (fake nulling observation) -> produce -> consume")); + sendAndReceiveSpans.sort(Comparator.comparing(FinishedSpan::getStartTimestamp)); + SpanAssert.assertThat(sendAndReceiveSpans.get(0)) + .hasNameEqualTo("metrics.queue publish") + .hasTag("messaging.rabbitmq.destination.routing_key", "metrics.queue") + .hasTag("messaging.destination.name", "amq.default") + .hasTag("messaging.message.payload_size_bytes", String.valueOf(PAYLOAD.length)) + .hasTagWithKey("net.sock.peer.addr") + .hasTag("net.sock.peer.port", "5672") + .hasTag("net.protocol.name", "amqp") + .hasTag("net.protocol.version", "0.9.1"); + SpanAssert.assertThat(sendAndReceiveSpans.get(1)) + .hasNameEqualTo("metrics.queue receive") + .hasTag("messaging.rabbitmq.destination.routing_key", "metrics.queue") + .hasTag("messaging.destination.name", "amq.default") + .hasTag("messaging.source.name", "metrics.queue") + .hasTag("messaging.message.payload_size_bytes", String.valueOf(PAYLOAD.length)); + List pollingSpans = + spans.stream() + .filter(f -> f.size() == 1) + .findFirst() + .orElseThrow(() -> new AssertionError("rabbitmq.receive (child of test span)")); + SpanAssert.assertThat(pollingSpans.get(0)).hasNameEqualTo("rabbitmq.receive"); + waitAtMost( + () -> + getMeterRegistry().find("rabbitmq.publish").timer() != null + && getMeterRegistry().find("rabbitmq.receive").timer() != null); + getMeterRegistry() + .get("rabbitmq.publish") + .tag("messaging.operation", "publish") + .tag("messaging.system", "rabbitmq") + .timer(); + getMeterRegistry() + .get("rabbitmq.receive") + .tag("messaging.operation", "receive") + .tag("messaging.system", "rabbitmq") + .timer(); + } finally { + safeClose(publishConnection); + safeClose(consumeConnection); + } + }; + } + } + +// @Nested + class PublishBasicGetKeepObservationOpen extends IntegrationTest { + + @Override + public SampleTestRunnerConsumer yourCode() { + return (buildingBlocks, meterRegistry) -> { + ObservationRegistry observationRegistry = getObservationRegistry(); + ConnectionFactory connectionFactory = createConnectionFactory(true, observationRegistry); Connection publishConnection = null, consumeConnection = null; try { publishConnection = connectionFactory.newConnection(); Channel channel = publishConnection.createChannel(); - new NullObservation(getObservationRegistry()).observeChecked(() -> sendMessage(channel)); + new NullObservation(observationRegistry).observeChecked(() -> sendMessage(channel)); consumeConnection = connectionFactory.newConnection(); Channel basicGetChannel = consumeConnection.createChannel(); waitAtMost(() -> basicGetChannel.basicGet(QUEUE, true) != null); + Observation.Scope scope = observationRegistry.getCurrentObservationScope(); + assertThat(scope).isNotNull(); + scope.close(); + scope.getCurrentObservation().stop(); waitAtMost(() -> buildingBlocks.getFinishedSpans().size() >= 3); + buildingBlocks + .getFinishedSpans() + .forEach( + s -> { + System.out.println(s.getName() + " " + s.getTraceId()); + }); Map> finishedSpans = buildingBlocks.getFinishedSpans().stream() .collect(Collectors.groupingBy(FinishedSpan::getTraceId)); From bc2a9963c9cf59430ce9ad5b5bbd0326ec77d484 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 13 Jul 2023 11:18:57 +0200 Subject: [PATCH 1759/2114] Use 2 distinct observations for basic.get This way it is possible to keep the second observation for the application processing of the message. The observation will have to be closed by the application in this case. --- .../MicrometerObservationCollector.java | 83 +++++++++++-------- ...MicrometerObservationCollectorMetrics.java | 21 ++--- 2 files changed, 53 insertions(+), 51 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java b/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java index 6534db522b..cd0b1ca500 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java @@ -104,42 +104,53 @@ public Consumer basicConsume(String queue, String consumerTag, Consumer consumer @Override public GetResponse basicGet(BasicGetCall call, String queue) { - return Observation.createNotStarted("rabbitmq.receive", registry) - .highCardinalityKeyValues( - KeyValues.of( - RabbitMqObservationDocumentation.LowCardinalityTags.MESSAGING_OPERATION.withValue( - "receive"), - RabbitMqObservationDocumentation.LowCardinalityTags.MESSAGING_SYSTEM.withValue( - "rabbitmq"))) - .observe( - () -> { - GetResponse response = call.get(); - if (response != null) { - Map headers; - if (response.getProps() == null || response.getProps().getHeaders() == null) { - headers = Collections.emptyMap(); - } else { - headers = response.getProps().getHeaders(); - } - DeliverContext context = - new DeliverContext( - response.getEnvelope().getExchange(), - response.getEnvelope().getRoutingKey(), - queue, - headers, - response.getBody() == null ? 0 : response.getBody().length); - Observation observation = - RabbitMqObservationDocumentation.RECEIVE_OBSERVATION.observation( - customReceiveConvention, defaultReceiveConvention, () -> context, registry); - observation.start(); - if (this.keepObservationOpenOnBasicGet) { - observation.openScope(); - } else { - observation.stop(); - } - } - return response; - }); + Observation observation = + Observation.createNotStarted("rabbitmq.receive", registry) + .highCardinalityKeyValues( + KeyValues.of( + RabbitMqObservationDocumentation.LowCardinalityTags.MESSAGING_OPERATION + .withValue("receive"), + RabbitMqObservationDocumentation.LowCardinalityTags.MESSAGING_SYSTEM.withValue( + "rabbitmq"))) + .start(); + boolean stopped = false; + try { + GetResponse response = call.get(); + if (response != null) { + observation.stop(); + stopped = true; + Map headers; + if (response.getProps() == null || response.getProps().getHeaders() == null) { + headers = Collections.emptyMap(); + } else { + headers = response.getProps().getHeaders(); + } + DeliverContext context = + new DeliverContext( + response.getEnvelope().getExchange(), + response.getEnvelope().getRoutingKey(), + queue, + headers, + response.getBody() == null ? 0 : response.getBody().length); + Observation receiveObservation = + RabbitMqObservationDocumentation.RECEIVE_OBSERVATION.observation( + customReceiveConvention, defaultReceiveConvention, () -> context, registry); + receiveObservation.start(); + if (this.keepObservationOpenOnBasicGet) { + receiveObservation.openScope(); + } else { + receiveObservation.stop(); + } + } + return response; + } catch (RuntimeException e) { + observation.error(e); + throw e; + } finally { + if (!stopped) { + observation.stop(); + } + } } private static class ObservationConsumer implements Consumer { diff --git a/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java b/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java index 884b924629..048ada0916 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java +++ b/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java @@ -208,12 +208,7 @@ public SampleTestRunnerConsumer yourCode() { Channel basicGetChannel = consumeConnection.createChannel(); waitAtMost(() -> basicGetChannel.basicGet(QUEUE, true) != null); waitAtMost(() -> buildingBlocks.getFinishedSpans().size() >= 3); - buildingBlocks - .getFinishedSpans() - .forEach( - s -> { - System.out.println(s.getName() + " " + s.getTraceId()); - }); + Map> finishedSpans = buildingBlocks.getFinishedSpans().stream() .collect(Collectors.groupingBy(FinishedSpan::getTraceId)); @@ -273,7 +268,7 @@ public SampleTestRunnerConsumer yourCode() { } } -// @Nested + @Nested class PublishBasicGetKeepObservationOpen extends IntegrationTest { @Override @@ -293,15 +288,11 @@ public SampleTestRunnerConsumer yourCode() { waitAtMost(() -> basicGetChannel.basicGet(QUEUE, true) != null); Observation.Scope scope = observationRegistry.getCurrentObservationScope(); assertThat(scope).isNotNull(); + // creating a dummy span to make sure it's wrapped into the receive one + buildingBlocks.getTracer().nextSpan().name("foobar").start().end(); scope.close(); scope.getCurrentObservation().stop(); - waitAtMost(() -> buildingBlocks.getFinishedSpans().size() >= 3); - buildingBlocks - .getFinishedSpans() - .forEach( - s -> { - System.out.println(s.getName() + " " + s.getTraceId()); - }); + waitAtMost(() -> buildingBlocks.getFinishedSpans().size() >= 3 + 1); Map> finishedSpans = buildingBlocks.getFinishedSpans().stream() .collect(Collectors.groupingBy(FinishedSpan::getTraceId)); @@ -311,7 +302,7 @@ public SampleTestRunnerConsumer yourCode() { Collection> spans = finishedSpans.values(); List sendAndReceiveSpans = spans.stream() - .filter(f -> f.size() == 2) + .filter(f -> f.size() == 2 + 1) .findFirst() .orElseThrow( () -> From 0f57d516e3b2ab1e6f77ddbbdca809840e5422c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 13 Jul 2023 12:24:03 +0200 Subject: [PATCH 1760/2114] Add Javadoc for Micrometer observability --- ...MicrometerObservationCollectorBuilder.java | 115 ++++++++++++++++-- ...MicrometerObservationCollectorMetrics.java | 4 +- 2 files changed, 108 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollectorBuilder.java b/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollectorBuilder.java index 5fe73254f6..0e3f36ba9a 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollectorBuilder.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollectorBuilder.java @@ -15,7 +15,9 @@ package com.rabbitmq.client.observation.micrometer; import com.rabbitmq.client.observation.ObservationCollector; +import io.micrometer.observation.ObservationConvention; import io.micrometer.observation.ObservationRegistry; +import java.util.function.Supplier; /** * Builder to configure and create Micrometer @@ -35,52 +37,147 @@ public class MicrometerObservationCollectorBuilder { private DeliverObservationConvention customReceiveObservationConvention; private DeliverObservationConvention defaultReceiveObservationConvention = new DefaultReceiveObservationConvention("receive"); - private boolean keepObservationOpenOnBasicGet = false; + private boolean keepObservationStartedOnBasicGet = false; + /** + * Set the {@link ObservationRegistry} to use. + * + * @param registry the registry + * @return this builder instance + */ public MicrometerObservationCollectorBuilder registry(ObservationRegistry registry) { this.registry = registry; return this; } + /** + * Custom convention for basic.publish. + * + *

If not null, it will override any pre-configured conventions. + * + * @param customPublishObservationConvention the convention + * @return this builder instance + * @see io.micrometer.observation.docs.ObservationDocumentation#observation(ObservationConvention, + * ObservationConvention, Supplier, ObservationRegistry) + */ public MicrometerObservationCollectorBuilder customPublishObservationConvention( PublishObservationConvention customPublishObservationConvention) { this.customPublishObservationConvention = customPublishObservationConvention; return this; } + /** + * Default convention for basic.publish. + * + *

It will be picked if there was neither custom convention nor a pre-configured one via {@link + * ObservationRegistry}. + * + * @param defaultPublishObservationConvention the convention + * @return this builder instance + * @see io.micrometer.observation.docs.ObservationDocumentation#observation(ObservationConvention, + * ObservationConvention, Supplier, ObservationRegistry) + */ public MicrometerObservationCollectorBuilder defaultPublishObservationConvention( PublishObservationConvention defaultPublishObservationConvention) { this.defaultPublishObservationConvention = defaultPublishObservationConvention; return this; } + /** + * Custom convention for basic.deliver. + * + *

If not null, it will override any pre-configured conventions. + * + * @param customProcessObservationConvention the convention + * @return this builder instance + * @see io.micrometer.observation.docs.ObservationDocumentation#observation(ObservationConvention, + * ObservationConvention, Supplier, ObservationRegistry) + */ public MicrometerObservationCollectorBuilder customProcessObservationConvention( - DeliverObservationConvention customConsumeObservationConvention) { - this.customProcessObservationConvention = customConsumeObservationConvention; + DeliverObservationConvention customProcessObservationConvention) { + this.customProcessObservationConvention = customProcessObservationConvention; return this; } + /** + * Default convention for basic.delivery. + * + *

It will be picked if there was neither custom convention nor a pre-configured one via {@link + * ObservationRegistry}. + * + * @param defaultProcessObservationConvention the convention + * @return this builder instance + * @see io.micrometer.observation.docs.ObservationDocumentation#observation(ObservationConvention, + * ObservationConvention, Supplier, ObservationRegistry) + */ public MicrometerObservationCollectorBuilder defaultProcessObservationConvention( - DeliverObservationConvention defaultConsumeObservationConvention) { - this.defaultProcessObservationConvention = defaultConsumeObservationConvention; + DeliverObservationConvention defaultProcessObservationConvention) { + this.defaultProcessObservationConvention = defaultProcessObservationConvention; return this; } + /** + * Custom convention for basic.get. + * + *

If not null, it will override any pre-configured conventions. + * + * @param customReceiveObservationConvention the convention + * @return this builder instance + * @see io.micrometer.observation.docs.ObservationDocumentation#observation(ObservationConvention, + * ObservationConvention, Supplier, ObservationRegistry) + */ public MicrometerObservationCollectorBuilder customReceiveObservationConvention( DeliverObservationConvention customReceiveObservationConvention) { this.customReceiveObservationConvention = customReceiveObservationConvention; return this; } + /** + * Default convention for basic.get. + * + *

It will be picked if there was neither custom convention nor a pre-configured one via {@link + * ObservationRegistry}. + * + * @param defaultReceiveObservationConvention the convention + * @return this builder instance + * @see io.micrometer.observation.docs.ObservationDocumentation#observation(ObservationConvention, + * ObservationConvention, Supplier, ObservationRegistry) + */ public MicrometerObservationCollectorBuilder defaultReceiveObservationConvention( DeliverObservationConvention defaultReceiveObservationConvention) { this.defaultReceiveObservationConvention = defaultReceiveObservationConvention; return this; } - public MicrometerObservationCollectorBuilder keepObservationOpenOnBasicGet( - boolean keepObservationOpenOnBasicGet) { - this.keepObservationOpenOnBasicGet = keepObservationOpenOnBasicGet; + /** + * Whether to keep the basic.get observation started or not. + * + *

The {@link MicrometerObservationCollector} starts and stops the observation immediately + * after the message reception. This way the observation can have all the context from the + * received message but has a very short duration. This is the default behavior. + * + *

By setting this flag to true the collector does not stop the observation and + * opens a scope. The processing of the message can then be included in the observation. + * + *

This is then the responsibility of the developer to retrieve the observation and stop it to + * avoid memory leaks. Here is an example: + * + *

+   * GetResponse response = channel.basicGet(queue, true);
+   * // process the message...
+   * // stop the observation
+   * Observation.Scope scope = observationRegistry.getCurrentObservationScope();
+   * scope.close();
+   * scope.getCurrentObservation().stop();
+ * + * Default is false, that is stopping the observation immediately. + * + * @param keepObservationStartedOnBasicGet whether to keep the observation started or not + * @return this builder instance + */ + public MicrometerObservationCollectorBuilder keepObservationStartedOnBasicGet( + boolean keepObservationStartedOnBasicGet) { + this.keepObservationStartedOnBasicGet = keepObservationStartedOnBasicGet; return this; } @@ -93,6 +190,6 @@ public ObservationCollector build() { this.defaultProcessObservationConvention, this.customReceiveObservationConvention, this.defaultReceiveObservationConvention, - keepObservationOpenOnBasicGet); + keepObservationStartedOnBasicGet); } } diff --git a/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java b/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java index 048ada0916..40dde8609e 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java +++ b/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java @@ -56,13 +56,13 @@ private static ConnectionFactory createConnectionFactory( } private static ConnectionFactory createConnectionFactory( - boolean keepObservationOpenOnBasicGet, ObservationRegistry observationRegistry) { + boolean keepObservationStartedOnBasicGet, ObservationRegistry observationRegistry) { ConnectionFactory connectionFactory = TestUtils.connectionFactory(); connectionFactory.setAutomaticRecoveryEnabled(true); if (observationRegistry != null) { ObservationCollector collector = new MicrometerObservationCollectorBuilder() - .keepObservationOpenOnBasicGet(keepObservationOpenOnBasicGet) + .keepObservationStartedOnBasicGet(keepObservationStartedOnBasicGet) .registry(observationRegistry) .build(); connectionFactory.setObservationCollector(collector); From ee87b27d05b431231ac71e61a097f2c8975c2f73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 13 Jul 2023 14:52:01 +0200 Subject: [PATCH 1761/2114] Complete Micrometer observation Javadoc --- ...MicrometerObservationCollectorBuilder.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollectorBuilder.java b/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollectorBuilder.java index 0e3f36ba9a..1a15a7e762 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollectorBuilder.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollectorBuilder.java @@ -42,6 +42,8 @@ public class MicrometerObservationCollectorBuilder { /** * Set the {@link ObservationRegistry} to use. * + *

Default is {@link ObservationRegistry#NOOP}. + * * @param registry the registry * @return this builder instance */ @@ -55,6 +57,8 @@ public MicrometerObservationCollectorBuilder registry(ObservationRegistry regist * *

If not null, it will override any pre-configured conventions. * + *

Default is null. + * * @param customPublishObservationConvention the convention * @return this builder instance * @see io.micrometer.observation.docs.ObservationDocumentation#observation(ObservationConvention, @@ -72,6 +76,8 @@ public MicrometerObservationCollectorBuilder customPublishObservationConvention( *

It will be picked if there was neither custom convention nor a pre-configured one via {@link * ObservationRegistry}. * + *

Default is {@link DefaultPublishObservationConvention}. + * * @param defaultPublishObservationConvention the convention * @return this builder instance * @see io.micrometer.observation.docs.ObservationDocumentation#observation(ObservationConvention, @@ -88,6 +94,8 @@ public MicrometerObservationCollectorBuilder defaultPublishObservationConvention * *

If not null, it will override any pre-configured conventions. * + *

Default is null. + * * @param customProcessObservationConvention the convention * @return this builder instance * @see io.micrometer.observation.docs.ObservationDocumentation#observation(ObservationConvention, @@ -105,6 +113,8 @@ public MicrometerObservationCollectorBuilder customProcessObservationConvention( *

It will be picked if there was neither custom convention nor a pre-configured one via {@link * ObservationRegistry}. * + *

Default is DefaultProcessObservationConvention("process"). + * * @param defaultProcessObservationConvention the convention * @return this builder instance * @see io.micrometer.observation.docs.ObservationDocumentation#observation(ObservationConvention, @@ -121,6 +131,8 @@ public MicrometerObservationCollectorBuilder defaultProcessObservationConvention * *

If not null, it will override any pre-configured conventions. * + *

Default is null. + * * @param customReceiveObservationConvention the convention * @return this builder instance * @see io.micrometer.observation.docs.ObservationDocumentation#observation(ObservationConvention, @@ -138,6 +150,8 @@ public MicrometerObservationCollectorBuilder customReceiveObservationConvention( *

It will be picked if there was neither custom convention nor a pre-configured one via {@link * ObservationRegistry}. * + *

Default is DefaultReceiveObservationConvention("receive"). + * * @param defaultReceiveObservationConvention the convention * @return this builder instance * @see io.micrometer.observation.docs.ObservationDocumentation#observation(ObservationConvention, @@ -181,6 +195,11 @@ public MicrometerObservationCollectorBuilder keepObservationStartedOnBasicGet( return this; } + /** + * Create the Micrometer {@link ObservationCollector}. + * + * @return the Micrometer observation collector + */ public ObservationCollector build() { return new MicrometerObservationCollector( this.registry, From 085c2ec7533b1a2a373cea78eeede89140fe4726 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 18 Jul 2023 00:19:28 +0000 Subject: [PATCH 1762/2114] Bump micrometer-tracing-integration-test from 1.1.2 to 1.1.3 Bumps [micrometer-tracing-integration-test](https://github.com/micrometer-metrics/tracing) from 1.1.2 to 1.1.3. - [Release notes](https://github.com/micrometer-metrics/tracing/releases) - [Commits](https://github.com/micrometer-metrics/tracing/compare/v1.1.2...v1.1.3) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-tracing-integration-test dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 90813fd466..a6721f0533 100644 --- a/pom.xml +++ b/pom.xml @@ -65,7 +65,7 @@ 5.9.3 5.4.0 3.24.2 - 1.1.2 + 1.1.3 1.0.2 9.4.51.v20230217 1.70 From 47134a8d0263f9505420e2f184ce8709725ccf22 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 18 Jul 2023 00:19:38 +0000 Subject: [PATCH 1763/2114] Bump spotless-maven-plugin from 2.35.0 to 2.38.0 Bumps [spotless-maven-plugin](https://github.com/diffplug/spotless) from 2.35.0 to 2.38.0. - [Changelog](https://github.com/diffplug/spotless/blob/main/CHANGES.md) - [Commits](https://github.com/diffplug/spotless/compare/lib/2.35.0...lib/2.38.0) --- updated-dependencies: - dependency-name: com.diffplug.spotless:spotless-maven-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 90813fd466..eb6631075f 100644 --- a/pom.xml +++ b/pom.xml @@ -91,7 +91,7 @@ 1.6.13 1.11 1.3 - 2.35.0 + 2.38.0 1.17.0 - -Djdk.net.URLClassPath.disableClassPathURLCheck=true + ${test-arguments} @@ -473,13 +480,10 @@ ${maven.failsafe.plugin.version} + true true - - -Djdk.net.URLClassPath.disableClassPathURLCheck=true + ${test-arguments} From 2d917702684f7a77e4cb6df120f672bde799b8ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 21 Sep 2023 09:16:19 +0200 Subject: [PATCH 1796/2114] Use Java 21 in GraalVM native test --- .github/workflows/test-native-image.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-native-image.yml b/.github/workflows/test-native-image.yml index 8ccb14a400..43cb3dd196 100644 --- a/.github/workflows/test-native-image.yml +++ b/.github/workflows/test-native-image.yml @@ -29,7 +29,7 @@ jobs: uses: graalvm/setup-graalvm@v1 with: version: 'latest' - java-version: '17' + java-version: '21' components: 'native-image' cache: 'maven' - name: Start broker From 39ee7ba53c8bfce24f777c70dedd0d317036191b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 21 Sep 2023 09:27:26 +0200 Subject: [PATCH 1797/2114] Remove native-image component Already installed. --- .github/workflows/test-native-image.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/test-native-image.yml b/.github/workflows/test-native-image.yml index 43cb3dd196..f64f6c0248 100644 --- a/.github/workflows/test-native-image.yml +++ b/.github/workflows/test-native-image.yml @@ -30,7 +30,6 @@ jobs: with: version: 'latest' java-version: '21' - components: 'native-image' cache: 'maven' - name: Start broker run: ci/start-broker.sh From 7df862bbe5e751e093f0c4858bd12a431b489885 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 21 Sep 2023 09:27:52 +0200 Subject: [PATCH 1798/2114] Bump Maven to 3.9.4 --- .mvn/wrapper/maven-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index 6d3a56651d..ac184013fc 100644 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -14,5 +14,5 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.3/apache-maven-3.9.3-bin.zip +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.4/apache-maven-3.9.4-bin.zip wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar From 7a0de3e457c3ac5144b812f778d8cb2ec30839ef Mon Sep 17 00:00:00 2001 From: "Rogelio J. Baucells" Date: Fri, 22 Sep 2023 19:01:20 -0400 Subject: [PATCH 1799/2114] Replaced synchronized() by ReentrantLock (cherry picked from commit d061fe39b9431832981dfbd80cfaf684c3450465) Conflicts: src/main/java/com/rabbitmq/client/impl/AMQChannel.java --- .../com/rabbitmq/client/impl/AMQChannel.java | 86 ++++++++++++++----- .../com/rabbitmq/client/impl/AMQCommand.java | 12 ++- .../com/rabbitmq/client/impl/ChannelN.java | 28 ++++-- .../client/impl/SocketFrameHandler.java | 23 ++++- 4 files changed, 115 insertions(+), 34 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java index 06c92a416e..14359a7e4e 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java @@ -31,6 +31,8 @@ import java.io.IOException; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeoutException; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; import java.util.function.Supplier; /** @@ -54,7 +56,8 @@ public abstract class AMQChannel extends ShutdownNotifierComponent { * so that clients can themselves use the channel to synchronize * on. */ - final Object _channelMutex = new Object(); + protected final ReentrantLock _channelMutex = new ReentrantLock(); + protected final Condition _channelMutexCondition = _channelMutex.newCondition(); /** The connection this channel is associated with. */ private final AMQConnection _connection; @@ -189,7 +192,8 @@ public void handleCompleteInboundCommand(AMQCommand command) throws IOException // so it must be a response to an earlier RPC. if (_checkRpcResponseType) { - synchronized (_channelMutex) { + _channelMutex.lock(); + try { // check if this reply command is intended for the current waiting request before calling nextOutstandingRpc() if (_activeRpc != null && !_activeRpc.canHandleReply(command)) { // this reply command is not intended for the current waiting request @@ -197,6 +201,8 @@ public void handleCompleteInboundCommand(AMQCommand command) throws IOException // Throw this reply command away so we don't stop the current request from waiting for its reply return; } + } finally { + _channelMutex.unlock(); } } final RpcWrapper nextOutstandingRpc = nextOutstandingRpc(); @@ -218,11 +224,12 @@ private void enqueueAsyncRpc(Method method, CompletableFuture future) { } private void doEnqueueRpc(Supplier rpcWrapperSupplier) { - synchronized (_channelMutex) { + _channelMutex.lock(); + try { boolean waitClearedInterruptStatus = false; while (_activeRpc != null) { try { - _channelMutex.wait(); + _channelMutexCondition.await(); } catch (InterruptedException e) { //NOSONAR waitClearedInterruptStatus = true; // No Sonar: we re-interrupt the thread later @@ -232,23 +239,31 @@ private void doEnqueueRpc(Supplier rpcWrapperSupplier) { Thread.currentThread().interrupt(); } _activeRpc = rpcWrapperSupplier.get(); + } finally { + _channelMutex.unlock(); } } boolean isOutstandingRpc() { - synchronized (_channelMutex) { + _channelMutex.lock(); + try { return (_activeRpc != null); + } finally { + _channelMutex.unlock(); } } public RpcWrapper nextOutstandingRpc() { - synchronized (_channelMutex) { + _channelMutex.lock(); + try { RpcWrapper result = _activeRpc; _activeRpc = null; - _channelMutex.notifyAll(); + _channelMutexCondition.signalAll(); return result; + } finally { + _channelMutex.unlock(); } } @@ -342,36 +357,48 @@ private AMQCommand privateRpc(Method m, int timeout) public void rpc(Method m, RpcContinuation k) throws IOException { - synchronized (_channelMutex) { + _channelMutex.lock(); + try { ensureIsOpen(); quiescingRpc(m, k); + } finally { + _channelMutex.unlock(); } } void quiescingRpc(Method m, RpcContinuation k) throws IOException { - synchronized (_channelMutex) { + _channelMutex.lock(); + try { enqueueRpc(k); quiescingTransmit(m); + } finally { + _channelMutex.unlock(); } } private void asyncRpc(Method m, CompletableFuture future) throws IOException { - synchronized (_channelMutex) { + _channelMutex.lock(); + try { ensureIsOpen(); quiescingAsyncRpc(m, future); + } finally { + _channelMutex.unlock(); } } private void quiescingAsyncRpc(Method m, CompletableFuture future) throws IOException { - synchronized (_channelMutex) { + _channelMutex.lock(); + try { enqueueAsyncRpc(m, future); quiescingTransmit(m); + } finally { + _channelMutex.unlock(); } } @@ -400,13 +427,16 @@ public void processShutdownSignal(ShutdownSignalException signal, boolean ignoreClosed, boolean notifyRpc) { try { - synchronized (_channelMutex) { + _channelMutex.lock(); + try { if (!setShutdownCauseIfOpen(signal)) { if (!ignoreClosed) throw new AlreadyClosedException(getCloseReason()); } - _channelMutex.notifyAll(); + _channelMutexCondition.signalAll(); + } finally { + _channelMutex.unlock(); } } finally { if (notifyRpc) @@ -421,31 +451,41 @@ void notifyOutstandingRpc(ShutdownSignalException signal) { } } - protected void transmit(Method m) throws IOException { - synchronized (_channelMutex) { + public void transmit(Method m) throws IOException { + _channelMutex.lock(); + try { transmit(new AMQCommand(m)); + } finally { + _channelMutex.unlock(); } } - void transmit(AMQCommand c) throws IOException { - synchronized (_channelMutex) { + public void transmit(AMQCommand c) throws IOException { + _channelMutex.lock(); + try { ensureIsOpen(); quiescingTransmit(c); + } finally { + _channelMutex.unlock(); } } - void quiescingTransmit(Method m) throws IOException { - synchronized (_channelMutex) { + public void quiescingTransmit(Method m) throws IOException { + _channelMutex.lock(); + try { quiescingTransmit(new AMQCommand(m)); + } finally { + _channelMutex.unlock(); } } - private void quiescingTransmit(AMQCommand c) throws IOException { - synchronized (_channelMutex) { + public void quiescingTransmit(AMQCommand c) throws IOException { + _channelMutex.lock(); + try { if (c.getMethod().hasContent()) { while (_blockContent) { try { - _channelMutex.wait(); + _channelMutexCondition.await(); } catch (InterruptedException ignored) { Thread.currentThread().interrupt(); } @@ -458,6 +498,8 @@ private void quiescingTransmit(AMQCommand c) throws IOException { } this._trafficListener.write(c); c.transmit(this); + } finally { + _channelMutex.unlock(); } } diff --git a/src/main/java/com/rabbitmq/client/impl/AMQCommand.java b/src/main/java/com/rabbitmq/client/impl/AMQCommand.java index a761e5cce6..8ee99c9701 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQCommand.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQCommand.java @@ -18,6 +18,7 @@ import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; +import java.util.concurrent.locks.ReentrantLock; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Command; @@ -43,6 +44,7 @@ public class AMQCommand implements Command { /** The assembler for this command - synchronised on - contains all the state */ private final CommandAssembler assembler; + private final ReentrantLock assemblerLock = new ReentrantLock(); AMQCommand(int maxBodyLength) { this(null, null, null, maxBodyLength); @@ -115,7 +117,8 @@ public void transmit(AMQChannel channel) throws IOException { int channelNumber = channel.getChannelNumber(); AMQConnection connection = channel.getConnection(); - synchronized (assembler) { + assemblerLock.lock(); + try { Method m = this.assembler.getMethod(); if (m.hasContent()) { byte[] body = this.assembler.getContentBody(); @@ -145,6 +148,8 @@ public void transmit(AMQChannel channel) throws IOException { } else { connection.writeFrame(m.toFrame(channelNumber)); } + } finally { + assemblerLock.unlock(); } connection.flush(); @@ -155,7 +160,8 @@ public void transmit(AMQChannel channel) throws IOException { } public String toString(boolean suppressBody){ - synchronized (assembler) { + assemblerLock.lock(); + try { return new StringBuilder() .append('{') .append(this.assembler.getMethod()) @@ -165,6 +171,8 @@ public String toString(boolean suppressBody){ .append(contentBodyStringBuilder( this.assembler.getContentBody(), suppressBody)) .append('}').toString(); + } finally { + assemblerLock.unlock(); } } diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java index b3f8ed5427..b719f1702f 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelN.java @@ -361,10 +361,13 @@ private void releaseChannel() { return true; } else if (method instanceof Channel.Flow) { Channel.Flow channelFlow = (Channel.Flow) method; - synchronized (_channelMutex) { + _channelMutex.lock(); + try { _blockContent = !channelFlow.getActive(); transmit(new Channel.FlowOk(!_blockContent)); - _channelMutex.notifyAll(); + _channelMutexCondition.signalAll(); + } finally { + _channelMutex.unlock(); } return true; } else if (method instanceof Basic.Ack) { @@ -524,7 +527,8 @@ private void asyncShutdown(Command command) throws IOException { false, command.getMethod(), this); - synchronized (_channelMutex) { + _channelMutex.lock(); + try { try { processShutdownSignal(signal, true, false); quiescingTransmit(new Channel.CloseOk()); @@ -533,6 +537,9 @@ private void asyncShutdown(Command command) throws IOException { notifyOutstandingRpc(signal); } } + finally { + _channelMutex.unlock(); + } notifyListeners(); } @@ -608,9 +615,12 @@ public AMQCommand transformReply(AMQCommand command) { try { // Synchronize the block below to avoid race conditions in case // connection wants to send Connection-CloseOK - synchronized (_channelMutex) { + _channelMutex.lock(); + try { startProcessShutdownSignal(signal, !initiatedByApplication, true); quiescingRpc(reason, k); + } finally { + _channelMutex.unlock(); } // Now that we're in quiescing state, channel.close was sent and @@ -1602,16 +1612,22 @@ public CompletableFuture asyncCompletableRpc(Method method) throws IOEx @Override public void enqueueRpc(RpcContinuation k) { - synchronized (_channelMutex) { + _channelMutex.lock(); + try { super.enqueueRpc(k); dispatcher.setUnlimited(true); + } finally { + _channelMutex.unlock(); } } @Override protected void markRpcFinished() { - synchronized (_channelMutex) { + _channelMutex.lock(); + try { dispatcher.setUnlimited(false); + } finally { + _channelMutex.unlock(); } } diff --git a/src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java b/src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java index 5048100a7b..607f4c4112 100644 --- a/src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java @@ -29,6 +29,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.ReentrantLock; /** * A socket-based frame handler. @@ -48,9 +49,11 @@ public class SocketFrameHandler implements FrameHandler { /** Socket's inputstream - data from the broker - synchronized on */ private final DataInputStream _inputStream; + private final ReentrantLock _inputStreamLock = new ReentrantLock(); /** Socket's outputstream - data to the broker - synchronized on */ private final DataOutputStream _outputStream; + private final ReentrantLock _outputStreamLock = new ReentrantLock(); private final int maxInboundMessageBodySize; @@ -127,7 +130,8 @@ public int getTimeout() * @see #sendHeader() */ public void sendHeader(int major, int minor) throws IOException { - synchronized (_outputStream) { + _outputStreamLock.lock(); + try { _outputStream.write("AMQP".getBytes("US-ASCII")); _outputStream.write(1); _outputStream.write(1); @@ -139,6 +143,8 @@ public void sendHeader(int major, int minor) throws IOException { LOGGER.error("TLS connection failed: {}", e.getMessage()); throw e; } + } finally { + _outputStreamLock.unlock(); } } @@ -154,7 +160,8 @@ public void sendHeader(int major, int minor) throws IOException { * @see #sendHeader() */ public void sendHeader(int major, int minor, int revision) throws IOException { - synchronized (_outputStream) { + _outputStreamLock.lock(); + try { _outputStream.write("AMQP".getBytes("US-ASCII")); _outputStream.write(0); _outputStream.write(major); @@ -166,6 +173,8 @@ public void sendHeader(int major, int minor, int revision) throws IOException { LOGGER.error("TLS connection failed: {}", e.getMessage()); throw e; } + } finally { + _outputStreamLock.unlock(); } } @@ -184,15 +193,21 @@ public void initialize(AMQConnection connection) { @Override public Frame readFrame() throws IOException { - synchronized (_inputStream) { + _inputStreamLock.lock(); + try { return Frame.readFrom(_inputStream, this.maxInboundMessageBodySize); + } finally { + _inputStreamLock.unlock(); } } @Override public void writeFrame(Frame frame) throws IOException { - synchronized (_outputStream) { + _outputStreamLock.lock(); + try { frame.writeTo(_outputStream); + } finally { + _outputStreamLock.unlock(); } } From c393749d966cb187228a7520859e9bf7504378e0 Mon Sep 17 00:00:00 2001 From: "Rogelio J. Baucells" Date: Fri, 22 Sep 2023 19:25:56 -0400 Subject: [PATCH 1800/2114] renamed Mutex => Lock (cherry picked from commit 8e855a34f620f3b5a9d0ca0f5ecced42c94769e0) --- .../com/rabbitmq/client/impl/AMQChannel.java | 64 +++++++++---------- .../com/rabbitmq/client/impl/ChannelN.java | 22 +++---- 2 files changed, 43 insertions(+), 43 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java index 14359a7e4e..f982be0f63 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java @@ -56,8 +56,8 @@ public abstract class AMQChannel extends ShutdownNotifierComponent { * so that clients can themselves use the channel to synchronize * on. */ - protected final ReentrantLock _channelMutex = new ReentrantLock(); - protected final Condition _channelMutexCondition = _channelMutex.newCondition(); + protected final ReentrantLock _channelLock = new ReentrantLock(); + protected final Condition _channelLockCondition = _channelLock.newCondition(); /** The connection this channel is associated with. */ private final AMQConnection _connection; @@ -192,7 +192,7 @@ public void handleCompleteInboundCommand(AMQCommand command) throws IOException // so it must be a response to an earlier RPC. if (_checkRpcResponseType) { - _channelMutex.lock(); + _channelLock.lock(); try { // check if this reply command is intended for the current waiting request before calling nextOutstandingRpc() if (_activeRpc != null && !_activeRpc.canHandleReply(command)) { @@ -202,7 +202,7 @@ public void handleCompleteInboundCommand(AMQCommand command) throws IOException return; } } finally { - _channelMutex.unlock(); + _channelLock.unlock(); } } final RpcWrapper nextOutstandingRpc = nextOutstandingRpc(); @@ -224,12 +224,12 @@ private void enqueueAsyncRpc(Method method, CompletableFuture future) { } private void doEnqueueRpc(Supplier rpcWrapperSupplier) { - _channelMutex.lock(); + _channelLock.lock(); try { boolean waitClearedInterruptStatus = false; while (_activeRpc != null) { try { - _channelMutexCondition.await(); + _channelLockCondition.await(); } catch (InterruptedException e) { //NOSONAR waitClearedInterruptStatus = true; // No Sonar: we re-interrupt the thread later @@ -240,30 +240,30 @@ private void doEnqueueRpc(Supplier rpcWrapperSupplier) { } _activeRpc = rpcWrapperSupplier.get(); } finally { - _channelMutex.unlock(); + _channelLock.unlock(); } } boolean isOutstandingRpc() { - _channelMutex.lock(); + _channelLock.lock(); try { return (_activeRpc != null); } finally { - _channelMutex.unlock(); + _channelLock.unlock(); } } public RpcWrapper nextOutstandingRpc() { - _channelMutex.lock(); + _channelLock.lock(); try { RpcWrapper result = _activeRpc; _activeRpc = null; - _channelMutexCondition.signalAll(); + _channelLockCondition.signalAll(); return result; } finally { - _channelMutex.unlock(); + _channelLock.unlock(); } } @@ -357,48 +357,48 @@ private AMQCommand privateRpc(Method m, int timeout) public void rpc(Method m, RpcContinuation k) throws IOException { - _channelMutex.lock(); + _channelLock.lock(); try { ensureIsOpen(); quiescingRpc(m, k); } finally { - _channelMutex.unlock(); + _channelLock.unlock(); } } void quiescingRpc(Method m, RpcContinuation k) throws IOException { - _channelMutex.lock(); + _channelLock.lock(); try { enqueueRpc(k); quiescingTransmit(m); } finally { - _channelMutex.unlock(); + _channelLock.unlock(); } } private void asyncRpc(Method m, CompletableFuture future) throws IOException { - _channelMutex.lock(); + _channelLock.lock(); try { ensureIsOpen(); quiescingAsyncRpc(m, future); } finally { - _channelMutex.unlock(); + _channelLock.unlock(); } } private void quiescingAsyncRpc(Method m, CompletableFuture future) throws IOException { - _channelMutex.lock(); + _channelLock.lock(); try { enqueueAsyncRpc(m, future); quiescingTransmit(m); } finally { - _channelMutex.unlock(); + _channelLock.unlock(); } } @@ -427,16 +427,16 @@ public void processShutdownSignal(ShutdownSignalException signal, boolean ignoreClosed, boolean notifyRpc) { try { - _channelMutex.lock(); + _channelLock.lock(); try { if (!setShutdownCauseIfOpen(signal)) { if (!ignoreClosed) throw new AlreadyClosedException(getCloseReason()); } - _channelMutexCondition.signalAll(); + _channelLockCondition.signalAll(); } finally { - _channelMutex.unlock(); + _channelLock.unlock(); } } finally { if (notifyRpc) @@ -452,40 +452,40 @@ void notifyOutstandingRpc(ShutdownSignalException signal) { } public void transmit(Method m) throws IOException { - _channelMutex.lock(); + _channelLock.lock(); try { transmit(new AMQCommand(m)); } finally { - _channelMutex.unlock(); + _channelLock.unlock(); } } public void transmit(AMQCommand c) throws IOException { - _channelMutex.lock(); + _channelLock.lock(); try { ensureIsOpen(); quiescingTransmit(c); } finally { - _channelMutex.unlock(); + _channelLock.unlock(); } } public void quiescingTransmit(Method m) throws IOException { - _channelMutex.lock(); + _channelLock.lock(); try { quiescingTransmit(new AMQCommand(m)); } finally { - _channelMutex.unlock(); + _channelLock.unlock(); } } public void quiescingTransmit(AMQCommand c) throws IOException { - _channelMutex.lock(); + _channelLock.lock(); try { if (c.getMethod().hasContent()) { while (_blockContent) { try { - _channelMutexCondition.await(); + _channelLockCondition.await(); } catch (InterruptedException ignored) { Thread.currentThread().interrupt(); } @@ -499,7 +499,7 @@ public void quiescingTransmit(AMQCommand c) throws IOException { this._trafficListener.write(c); c.transmit(this); } finally { - _channelMutex.unlock(); + _channelLock.unlock(); } } diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java index b719f1702f..8b66273714 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelN.java @@ -361,13 +361,13 @@ private void releaseChannel() { return true; } else if (method instanceof Channel.Flow) { Channel.Flow channelFlow = (Channel.Flow) method; - _channelMutex.lock(); + _channelLock.lock(); try { _blockContent = !channelFlow.getActive(); transmit(new Channel.FlowOk(!_blockContent)); - _channelMutexCondition.signalAll(); + _channelLockCondition.signalAll(); } finally { - _channelMutex.unlock(); + _channelLock.unlock(); } return true; } else if (method instanceof Basic.Ack) { @@ -527,7 +527,7 @@ private void asyncShutdown(Command command) throws IOException { false, command.getMethod(), this); - _channelMutex.lock(); + _channelLock.lock(); try { try { processShutdownSignal(signal, true, false); @@ -538,7 +538,7 @@ private void asyncShutdown(Command command) throws IOException { } } finally { - _channelMutex.unlock(); + _channelLock.unlock(); } notifyListeners(); } @@ -615,12 +615,12 @@ public AMQCommand transformReply(AMQCommand command) { try { // Synchronize the block below to avoid race conditions in case // connection wants to send Connection-CloseOK - _channelMutex.lock(); + _channelLock.lock(); try { startProcessShutdownSignal(signal, !initiatedByApplication, true); quiescingRpc(reason, k); } finally { - _channelMutex.unlock(); + _channelLock.unlock(); } // Now that we're in quiescing state, channel.close was sent and @@ -1612,22 +1612,22 @@ public CompletableFuture asyncCompletableRpc(Method method) throws IOEx @Override public void enqueueRpc(RpcContinuation k) { - _channelMutex.lock(); + _channelLock.lock(); try { super.enqueueRpc(k); dispatcher.setUnlimited(true); } finally { - _channelMutex.unlock(); + _channelLock.unlock(); } } @Override protected void markRpcFinished() { - _channelMutex.lock(); + _channelLock.lock(); try { dispatcher.setUnlimited(false); } finally { - _channelMutex.unlock(); + _channelLock.unlock(); } } From d39d9b421b79b2a8e812a2c94679e0028c219ca9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 25 Sep 2023 09:21:24 +0200 Subject: [PATCH 1801/2114] Use Lock interface to declare properties Not ReentrantLock. References #1119 (cherry picked from commit 3f72657e8875f99740992d42625eba8558c858c6) --- src/main/java/com/rabbitmq/client/impl/AMQChannel.java | 3 ++- src/main/java/com/rabbitmq/client/impl/AMQCommand.java | 3 ++- .../java/com/rabbitmq/client/impl/SocketFrameHandler.java | 5 +++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java index f982be0f63..2e070320c2 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java @@ -32,6 +32,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeoutException; import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.function.Supplier; @@ -56,7 +57,7 @@ public abstract class AMQChannel extends ShutdownNotifierComponent { * so that clients can themselves use the channel to synchronize * on. */ - protected final ReentrantLock _channelLock = new ReentrantLock(); + protected final Lock _channelLock = new ReentrantLock(); protected final Condition _channelLockCondition = _channelLock.newCondition(); /** The connection this channel is associated with. */ diff --git a/src/main/java/com/rabbitmq/client/impl/AMQCommand.java b/src/main/java/com/rabbitmq/client/impl/AMQCommand.java index 8ee99c9701..aa4df765fb 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQCommand.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQCommand.java @@ -18,6 +18,7 @@ import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; +import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import com.rabbitmq.client.AMQP; @@ -44,7 +45,7 @@ public class AMQCommand implements Command { /** The assembler for this command - synchronised on - contains all the state */ private final CommandAssembler assembler; - private final ReentrantLock assemblerLock = new ReentrantLock(); + private final Lock assemblerLock = new ReentrantLock(); AMQCommand(int maxBodyLength) { this(null, null, null, maxBodyLength); diff --git a/src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java b/src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java index 607f4c4112..3e4e0a7078 100644 --- a/src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java @@ -29,6 +29,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** @@ -49,11 +50,11 @@ public class SocketFrameHandler implements FrameHandler { /** Socket's inputstream - data from the broker - synchronized on */ private final DataInputStream _inputStream; - private final ReentrantLock _inputStreamLock = new ReentrantLock(); + private final Lock _inputStreamLock = new ReentrantLock(); /** Socket's outputstream - data to the broker - synchronized on */ private final DataOutputStream _outputStream; - private final ReentrantLock _outputStreamLock = new ReentrantLock(); + private final Lock _outputStreamLock = new ReentrantLock(); private final int maxInboundMessageBodySize; From 39731cf32d65e01f42fff9836161fbd9f56a74e9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 27 Sep 2023 00:41:35 +0000 Subject: [PATCH 1802/2114] Bump io.dropwizard.metrics:metrics-core from 4.2.19 to 4.2.20 Bumps [io.dropwizard.metrics:metrics-core](https://github.com/dropwizard/metrics) from 4.2.19 to 4.2.20. - [Release notes](https://github.com/dropwizard/metrics/releases) - [Commits](https://github.com/dropwizard/metrics/compare/v4.2.19...v4.2.20) --- updated-dependencies: - dependency-name: io.dropwizard.metrics:metrics-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index db7ae1fd12..a036d9f2cd 100644 --- a/pom.xml +++ b/pom.xml @@ -56,7 +56,7 @@ true 1.7.36 - 4.2.19 + 4.2.20 1.11.4 1.1.4 1.30.1 From d0300754c4749603841de266e93ba85443dcc133 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 27 Sep 2023 17:10:29 +0200 Subject: [PATCH 1803/2114] Use 5.19.0 in readme --- README.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.adoc b/README.adoc index f416d157bf..25355e4643 100644 --- a/README.adoc +++ b/README.adoc @@ -1,6 +1,6 @@ -:client-stable: 5.18.0 +:client-stable: 5.19.0 :client-rc: 5.17.0.RC2 -:client-snapshot: 5.19.0-SNAPSHOT +:client-snapshot: 5.20.0-SNAPSHOT = RabbitMQ Java Client From 992a5e847c02957baace2ac12796ecd0413cbda1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 29 Sep 2023 00:44:27 +0000 Subject: [PATCH 1804/2114] Bump com.diffplug.spotless:spotless-maven-plugin from 2.39.0 to 2.40.0 Bumps [com.diffplug.spotless:spotless-maven-plugin](https://github.com/diffplug/spotless) from 2.39.0 to 2.40.0. - [Changelog](https://github.com/diffplug/spotless/blob/main/CHANGES.md) - [Commits](https://github.com/diffplug/spotless/compare/lib/2.39.0...lib/2.40.0) --- updated-dependencies: - dependency-name: com.diffplug.spotless:spotless-maven-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a036d9f2cd..271aa83419 100644 --- a/pom.xml +++ b/pom.xml @@ -91,7 +91,7 @@ 1.6.13 1.11 1.4 - 2.39.0 + 2.40.0 1.17.0 - // Copyright (c) $YEAR VMware, Inc. or its affiliates. All rights reserved. + // Copyright (c) $YEAR Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/Address.java b/src/main/java/com/rabbitmq/client/Address.java index d86c040ba5..643e3a3582 100644 --- a/src/main/java/com/rabbitmq/client/Address.java +++ b/src/main/java/com/rabbitmq/client/Address.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/AddressResolver.java b/src/main/java/com/rabbitmq/client/AddressResolver.java index 4a90a8e014..992b687dab 100644 --- a/src/main/java/com/rabbitmq/client/AddressResolver.java +++ b/src/main/java/com/rabbitmq/client/AddressResolver.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/AlreadyClosedException.java b/src/main/java/com/rabbitmq/client/AlreadyClosedException.java index 69a000847e..5cf3da56f8 100644 --- a/src/main/java/com/rabbitmq/client/AlreadyClosedException.java +++ b/src/main/java/com/rabbitmq/client/AlreadyClosedException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/AuthenticationFailureException.java b/src/main/java/com/rabbitmq/client/AuthenticationFailureException.java index 56f26561ca..2001e7d94e 100644 --- a/src/main/java/com/rabbitmq/client/AuthenticationFailureException.java +++ b/src/main/java/com/rabbitmq/client/AuthenticationFailureException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/BasicProperties.java b/src/main/java/com/rabbitmq/client/BasicProperties.java index 9a0b953698..8cfbf98b6d 100644 --- a/src/main/java/com/rabbitmq/client/BasicProperties.java +++ b/src/main/java/com/rabbitmq/client/BasicProperties.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/BlockedCallback.java b/src/main/java/com/rabbitmq/client/BlockedCallback.java index d9e22fbe88..bf0607b8e9 100644 --- a/src/main/java/com/rabbitmq/client/BlockedCallback.java +++ b/src/main/java/com/rabbitmq/client/BlockedCallback.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2017-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/BlockedListener.java b/src/main/java/com/rabbitmq/client/BlockedListener.java index 521f8d19cd..aa040a473c 100644 --- a/src/main/java/com/rabbitmq/client/BlockedListener.java +++ b/src/main/java/com/rabbitmq/client/BlockedListener.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/CancelCallback.java b/src/main/java/com/rabbitmq/client/CancelCallback.java index 419f34a4bd..1b3433032d 100644 --- a/src/main/java/com/rabbitmq/client/CancelCallback.java +++ b/src/main/java/com/rabbitmq/client/CancelCallback.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2017-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/Channel.java b/src/main/java/com/rabbitmq/client/Channel.java index 6e72cb2fd9..f5b5eab7f1 100644 --- a/src/main/java/com/rabbitmq/client/Channel.java +++ b/src/main/java/com/rabbitmq/client/Channel.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/Command.java b/src/main/java/com/rabbitmq/client/Command.java index dad5c6aa64..24c113dd0b 100644 --- a/src/main/java/com/rabbitmq/client/Command.java +++ b/src/main/java/com/rabbitmq/client/Command.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ConfirmCallback.java b/src/main/java/com/rabbitmq/client/ConfirmCallback.java index e02355f957..cd0e8fe597 100644 --- a/src/main/java/com/rabbitmq/client/ConfirmCallback.java +++ b/src/main/java/com/rabbitmq/client/ConfirmCallback.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2017-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ConfirmListener.java b/src/main/java/com/rabbitmq/client/ConfirmListener.java index 50f25ad2c3..489018bb32 100644 --- a/src/main/java/com/rabbitmq/client/ConfirmListener.java +++ b/src/main/java/com/rabbitmq/client/ConfirmListener.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/Connection.java b/src/main/java/com/rabbitmq/client/Connection.java index 5004ac9372..dbfb99f8e8 100644 --- a/src/main/java/com/rabbitmq/client/Connection.java +++ b/src/main/java/com/rabbitmq/client/Connection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactory.java b/src/main/java/com/rabbitmq/client/ConnectionFactory.java index 639c89d357..dc7ea88c72 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactory.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java b/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java index 66f4a3742d..12ebcadbbc 100644 --- a/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java +++ b/src/main/java/com/rabbitmq/client/ConnectionFactoryConfigurator.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2017-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/Consumer.java b/src/main/java/com/rabbitmq/client/Consumer.java index cb57e9d956..7604ecb60f 100644 --- a/src/main/java/com/rabbitmq/client/Consumer.java +++ b/src/main/java/com/rabbitmq/client/Consumer.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ConsumerCancelledException.java b/src/main/java/com/rabbitmq/client/ConsumerCancelledException.java index 44495fceb4..ce6c966292 100644 --- a/src/main/java/com/rabbitmq/client/ConsumerCancelledException.java +++ b/src/main/java/com/rabbitmq/client/ConsumerCancelledException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ConsumerShutdownSignalCallback.java b/src/main/java/com/rabbitmq/client/ConsumerShutdownSignalCallback.java index 0fe41694a4..c6a23a4bdb 100644 --- a/src/main/java/com/rabbitmq/client/ConsumerShutdownSignalCallback.java +++ b/src/main/java/com/rabbitmq/client/ConsumerShutdownSignalCallback.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2017-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ContentHeader.java b/src/main/java/com/rabbitmq/client/ContentHeader.java index ff3f0f0a1e..d6b89c18e0 100644 --- a/src/main/java/com/rabbitmq/client/ContentHeader.java +++ b/src/main/java/com/rabbitmq/client/ContentHeader.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/DefaultConsumer.java b/src/main/java/com/rabbitmq/client/DefaultConsumer.java index b2b4644b3c..18c180117c 100644 --- a/src/main/java/com/rabbitmq/client/DefaultConsumer.java +++ b/src/main/java/com/rabbitmq/client/DefaultConsumer.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/DefaultSaslConfig.java b/src/main/java/com/rabbitmq/client/DefaultSaslConfig.java index 0e4de02da1..226605cd3c 100644 --- a/src/main/java/com/rabbitmq/client/DefaultSaslConfig.java +++ b/src/main/java/com/rabbitmq/client/DefaultSaslConfig.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/DefaultSocketChannelConfigurator.java b/src/main/java/com/rabbitmq/client/DefaultSocketChannelConfigurator.java index 470bd6f940..45d423b75f 100644 --- a/src/main/java/com/rabbitmq/client/DefaultSocketChannelConfigurator.java +++ b/src/main/java/com/rabbitmq/client/DefaultSocketChannelConfigurator.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/DefaultSocketConfigurator.java b/src/main/java/com/rabbitmq/client/DefaultSocketConfigurator.java index 57732f45c3..4543dff3c3 100644 --- a/src/main/java/com/rabbitmq/client/DefaultSocketConfigurator.java +++ b/src/main/java/com/rabbitmq/client/DefaultSocketConfigurator.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/DeliverCallback.java b/src/main/java/com/rabbitmq/client/DeliverCallback.java index 4760c7be1a..1d0ab0a3a3 100644 --- a/src/main/java/com/rabbitmq/client/DeliverCallback.java +++ b/src/main/java/com/rabbitmq/client/DeliverCallback.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2017-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/Delivery.java b/src/main/java/com/rabbitmq/client/Delivery.java index 91c36ffa3d..ecc53525c6 100644 --- a/src/main/java/com/rabbitmq/client/Delivery.java +++ b/src/main/java/com/rabbitmq/client/Delivery.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2017-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/DnsRecordIpAddressResolver.java b/src/main/java/com/rabbitmq/client/DnsRecordIpAddressResolver.java index 9c5d0dc69f..3e7f180fc8 100644 --- a/src/main/java/com/rabbitmq/client/DnsRecordIpAddressResolver.java +++ b/src/main/java/com/rabbitmq/client/DnsRecordIpAddressResolver.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/DnsSrvRecordAddressResolver.java b/src/main/java/com/rabbitmq/client/DnsSrvRecordAddressResolver.java index 5c340c3347..38a9a8d14c 100644 --- a/src/main/java/com/rabbitmq/client/DnsSrvRecordAddressResolver.java +++ b/src/main/java/com/rabbitmq/client/DnsSrvRecordAddressResolver.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/Envelope.java b/src/main/java/com/rabbitmq/client/Envelope.java index d8164f050d..7e798ea8bf 100644 --- a/src/main/java/com/rabbitmq/client/Envelope.java +++ b/src/main/java/com/rabbitmq/client/Envelope.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ExceptionHandler.java b/src/main/java/com/rabbitmq/client/ExceptionHandler.java index 90c982d11e..66f8cca08b 100644 --- a/src/main/java/com/rabbitmq/client/ExceptionHandler.java +++ b/src/main/java/com/rabbitmq/client/ExceptionHandler.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/GetResponse.java b/src/main/java/com/rabbitmq/client/GetResponse.java index 83ea3bc991..0f91ff4125 100644 --- a/src/main/java/com/rabbitmq/client/GetResponse.java +++ b/src/main/java/com/rabbitmq/client/GetResponse.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/JDKSaslConfig.java b/src/main/java/com/rabbitmq/client/JDKSaslConfig.java index e39beb2eec..5d8fcd3cb5 100644 --- a/src/main/java/com/rabbitmq/client/JDKSaslConfig.java +++ b/src/main/java/com/rabbitmq/client/JDKSaslConfig.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ListAddressResolver.java b/src/main/java/com/rabbitmq/client/ListAddressResolver.java index e04eaa4431..9aedb472ec 100644 --- a/src/main/java/com/rabbitmq/client/ListAddressResolver.java +++ b/src/main/java/com/rabbitmq/client/ListAddressResolver.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/LongString.java b/src/main/java/com/rabbitmq/client/LongString.java index 3b091b98fc..6cfcfd7ab4 100644 --- a/src/main/java/com/rabbitmq/client/LongString.java +++ b/src/main/java/com/rabbitmq/client/LongString.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/MalformedFrameException.java b/src/main/java/com/rabbitmq/client/MalformedFrameException.java index a05dc95928..c8df470ebf 100644 --- a/src/main/java/com/rabbitmq/client/MalformedFrameException.java +++ b/src/main/java/com/rabbitmq/client/MalformedFrameException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/MapRpcServer.java b/src/main/java/com/rabbitmq/client/MapRpcServer.java index 5a65fe3126..4a90244589 100644 --- a/src/main/java/com/rabbitmq/client/MapRpcServer.java +++ b/src/main/java/com/rabbitmq/client/MapRpcServer.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/MessageProperties.java b/src/main/java/com/rabbitmq/client/MessageProperties.java index bd7b6cd71c..ab2810ca21 100644 --- a/src/main/java/com/rabbitmq/client/MessageProperties.java +++ b/src/main/java/com/rabbitmq/client/MessageProperties.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/Method.java b/src/main/java/com/rabbitmq/client/Method.java index d6aa573ce0..06783c71af 100644 --- a/src/main/java/com/rabbitmq/client/Method.java +++ b/src/main/java/com/rabbitmq/client/Method.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/MetricsCollector.java b/src/main/java/com/rabbitmq/client/MetricsCollector.java index a83bc8783c..d6905c38f8 100644 --- a/src/main/java/com/rabbitmq/client/MetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/MetricsCollector.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/MissedHeartbeatException.java b/src/main/java/com/rabbitmq/client/MissedHeartbeatException.java index ef3bf5335d..6da9407614 100644 --- a/src/main/java/com/rabbitmq/client/MissedHeartbeatException.java +++ b/src/main/java/com/rabbitmq/client/MissedHeartbeatException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java b/src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java index f744de5ddb..cb65674e33 100644 --- a/src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/NoOpMetricsCollector.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/PossibleAuthenticationFailureException.java b/src/main/java/com/rabbitmq/client/PossibleAuthenticationFailureException.java index 9c8876d8e4..4281f57656 100644 --- a/src/main/java/com/rabbitmq/client/PossibleAuthenticationFailureException.java +++ b/src/main/java/com/rabbitmq/client/PossibleAuthenticationFailureException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ProtocolVersionMismatchException.java b/src/main/java/com/rabbitmq/client/ProtocolVersionMismatchException.java index e15e5873e3..8f91a992f7 100644 --- a/src/main/java/com/rabbitmq/client/ProtocolVersionMismatchException.java +++ b/src/main/java/com/rabbitmq/client/ProtocolVersionMismatchException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/Recoverable.java b/src/main/java/com/rabbitmq/client/Recoverable.java index 30d68992ba..9e651aa12c 100644 --- a/src/main/java/com/rabbitmq/client/Recoverable.java +++ b/src/main/java/com/rabbitmq/client/Recoverable.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/RecoveryDelayHandler.java b/src/main/java/com/rabbitmq/client/RecoveryDelayHandler.java index 84a2d577e7..d55153a52e 100644 --- a/src/main/java/com/rabbitmq/client/RecoveryDelayHandler.java +++ b/src/main/java/com/rabbitmq/client/RecoveryDelayHandler.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/RecoveryListener.java b/src/main/java/com/rabbitmq/client/RecoveryListener.java index 4caf77e323..cfec1058a5 100644 --- a/src/main/java/com/rabbitmq/client/RecoveryListener.java +++ b/src/main/java/com/rabbitmq/client/RecoveryListener.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/Return.java b/src/main/java/com/rabbitmq/client/Return.java index d25532b773..0992a89ea2 100644 --- a/src/main/java/com/rabbitmq/client/Return.java +++ b/src/main/java/com/rabbitmq/client/Return.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ReturnCallback.java b/src/main/java/com/rabbitmq/client/ReturnCallback.java index efa3ad6065..89f8e4cbb1 100644 --- a/src/main/java/com/rabbitmq/client/ReturnCallback.java +++ b/src/main/java/com/rabbitmq/client/ReturnCallback.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2017-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ReturnListener.java b/src/main/java/com/rabbitmq/client/ReturnListener.java index 5f45f84ef4..d138b17450 100644 --- a/src/main/java/com/rabbitmq/client/ReturnListener.java +++ b/src/main/java/com/rabbitmq/client/ReturnListener.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/RpcClient.java b/src/main/java/com/rabbitmq/client/RpcClient.java index e391db54f7..f47d185b89 100644 --- a/src/main/java/com/rabbitmq/client/RpcClient.java +++ b/src/main/java/com/rabbitmq/client/RpcClient.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/RpcClientParams.java b/src/main/java/com/rabbitmq/client/RpcClientParams.java index 190792250f..ef5d346e77 100644 --- a/src/main/java/com/rabbitmq/client/RpcClientParams.java +++ b/src/main/java/com/rabbitmq/client/RpcClientParams.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/RpcServer.java b/src/main/java/com/rabbitmq/client/RpcServer.java index 426c8d749f..05b6294cd0 100644 --- a/src/main/java/com/rabbitmq/client/RpcServer.java +++ b/src/main/java/com/rabbitmq/client/RpcServer.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/SaslConfig.java b/src/main/java/com/rabbitmq/client/SaslConfig.java index 5042f2c16f..119cfb6072 100644 --- a/src/main/java/com/rabbitmq/client/SaslConfig.java +++ b/src/main/java/com/rabbitmq/client/SaslConfig.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/SaslMechanism.java b/src/main/java/com/rabbitmq/client/SaslMechanism.java index 9a11b5a27f..eda4567ebf 100644 --- a/src/main/java/com/rabbitmq/client/SaslMechanism.java +++ b/src/main/java/com/rabbitmq/client/SaslMechanism.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ShutdownListener.java b/src/main/java/com/rabbitmq/client/ShutdownListener.java index 9775e454b0..ae7424fbcc 100644 --- a/src/main/java/com/rabbitmq/client/ShutdownListener.java +++ b/src/main/java/com/rabbitmq/client/ShutdownListener.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ShutdownNotifier.java b/src/main/java/com/rabbitmq/client/ShutdownNotifier.java index 9c1e3e8bfc..da8aaedfb3 100644 --- a/src/main/java/com/rabbitmq/client/ShutdownNotifier.java +++ b/src/main/java/com/rabbitmq/client/ShutdownNotifier.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/ShutdownSignalException.java b/src/main/java/com/rabbitmq/client/ShutdownSignalException.java index 24be455978..29c2f917bc 100644 --- a/src/main/java/com/rabbitmq/client/ShutdownSignalException.java +++ b/src/main/java/com/rabbitmq/client/ShutdownSignalException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/SocketChannelConfigurator.java b/src/main/java/com/rabbitmq/client/SocketChannelConfigurator.java index 4571e707f9..ffbb919c56 100644 --- a/src/main/java/com/rabbitmq/client/SocketChannelConfigurator.java +++ b/src/main/java/com/rabbitmq/client/SocketChannelConfigurator.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/SocketChannelConfigurators.java b/src/main/java/com/rabbitmq/client/SocketChannelConfigurators.java index 711af1cf58..95d96c4fad 100644 --- a/src/main/java/com/rabbitmq/client/SocketChannelConfigurators.java +++ b/src/main/java/com/rabbitmq/client/SocketChannelConfigurators.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2018-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/SocketConfigurator.java b/src/main/java/com/rabbitmq/client/SocketConfigurator.java index 151f572461..17e63978ac 100644 --- a/src/main/java/com/rabbitmq/client/SocketConfigurator.java +++ b/src/main/java/com/rabbitmq/client/SocketConfigurator.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/SocketConfigurators.java b/src/main/java/com/rabbitmq/client/SocketConfigurators.java index 08220dfb67..944d9a4611 100644 --- a/src/main/java/com/rabbitmq/client/SocketConfigurators.java +++ b/src/main/java/com/rabbitmq/client/SocketConfigurators.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2018-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/SslContextFactory.java b/src/main/java/com/rabbitmq/client/SslContextFactory.java index 0b285a9bf9..c012111970 100644 --- a/src/main/java/com/rabbitmq/client/SslContextFactory.java +++ b/src/main/java/com/rabbitmq/client/SslContextFactory.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2017-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/SslEngineConfigurator.java b/src/main/java/com/rabbitmq/client/SslEngineConfigurator.java index 0ed04182f3..78b2b2eae9 100644 --- a/src/main/java/com/rabbitmq/client/SslEngineConfigurator.java +++ b/src/main/java/com/rabbitmq/client/SslEngineConfigurator.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2017-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/SslEngineConfigurators.java b/src/main/java/com/rabbitmq/client/SslEngineConfigurators.java index 6e8ca36589..929fd507d4 100644 --- a/src/main/java/com/rabbitmq/client/SslEngineConfigurators.java +++ b/src/main/java/com/rabbitmq/client/SslEngineConfigurators.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2018-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/StringRpcServer.java b/src/main/java/com/rabbitmq/client/StringRpcServer.java index d437cb28b4..8cb00307b1 100644 --- a/src/main/java/com/rabbitmq/client/StringRpcServer.java +++ b/src/main/java/com/rabbitmq/client/StringRpcServer.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/TopologyRecoveryException.java b/src/main/java/com/rabbitmq/client/TopologyRecoveryException.java index 77b305c2e3..7b0a06975d 100644 --- a/src/main/java/com/rabbitmq/client/TopologyRecoveryException.java +++ b/src/main/java/com/rabbitmq/client/TopologyRecoveryException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/TrustEverythingTrustManager.java b/src/main/java/com/rabbitmq/client/TrustEverythingTrustManager.java index e7913d048e..cd558c705c 100644 --- a/src/main/java/com/rabbitmq/client/TrustEverythingTrustManager.java +++ b/src/main/java/com/rabbitmq/client/TrustEverythingTrustManager.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/UnblockedCallback.java b/src/main/java/com/rabbitmq/client/UnblockedCallback.java index 6d79423922..4421ba0d81 100644 --- a/src/main/java/com/rabbitmq/client/UnblockedCallback.java +++ b/src/main/java/com/rabbitmq/client/UnblockedCallback.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2017-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/UnexpectedFrameError.java b/src/main/java/com/rabbitmq/client/UnexpectedFrameError.java index e15e449e5b..dedf0fb8fd 100644 --- a/src/main/java/com/rabbitmq/client/UnexpectedFrameError.java +++ b/src/main/java/com/rabbitmq/client/UnexpectedFrameError.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/UnexpectedMethodError.java b/src/main/java/com/rabbitmq/client/UnexpectedMethodError.java index f5cde49379..94219d296b 100644 --- a/src/main/java/com/rabbitmq/client/UnexpectedMethodError.java +++ b/src/main/java/com/rabbitmq/client/UnexpectedMethodError.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/UnknownClassOrMethodId.java b/src/main/java/com/rabbitmq/client/UnknownClassOrMethodId.java index 3ad973a7b6..e4e8f39ec6 100644 --- a/src/main/java/com/rabbitmq/client/UnknownClassOrMethodId.java +++ b/src/main/java/com/rabbitmq/client/UnknownClassOrMethodId.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/UnroutableRpcRequestException.java b/src/main/java/com/rabbitmq/client/UnroutableRpcRequestException.java index 1a2877e14a..870e8847ae 100644 --- a/src/main/java/com/rabbitmq/client/UnroutableRpcRequestException.java +++ b/src/main/java/com/rabbitmq/client/UnroutableRpcRequestException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/AMQBasicProperties.java b/src/main/java/com/rabbitmq/client/impl/AMQBasicProperties.java index 54f312f06a..8e6a6ba3b5 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQBasicProperties.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQBasicProperties.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java index 2e070320c2..7c42388d0e 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQChannel.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/AMQCommand.java b/src/main/java/com/rabbitmq/client/impl/AMQCommand.java index aa4df765fb..be48296143 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQCommand.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQCommand.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index 3dfdf7be51..bb207dcecc 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -35,7 +35,7 @@ import java.util.concurrent.atomic.AtomicBoolean; final class Copyright { - final static String COPYRIGHT="Copyright (c) 2007-2021 VMware, Inc. or its affiliates."; + final static String COPYRIGHT="Copyright (c) 2007-2023 Broadcom Inc. and/or its subsidiaries."; final static String LICENSE="Licensed under the MPL. See https://www.rabbitmq.com/"; } diff --git a/src/main/java/com/rabbitmq/client/impl/AMQContentHeader.java b/src/main/java/com/rabbitmq/client/impl/AMQContentHeader.java index e3bf4a479f..7a8311f4cf 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQContentHeader.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQContentHeader.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/AbstractFrameHandlerFactory.java b/src/main/java/com/rabbitmq/client/impl/AbstractFrameHandlerFactory.java index 61f4c51325..576d4490cf 100644 --- a/src/main/java/com/rabbitmq/client/impl/AbstractFrameHandlerFactory.java +++ b/src/main/java/com/rabbitmq/client/impl/AbstractFrameHandlerFactory.java @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2016-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java index 0d8f8e2939..ca3132f1ab 100644 --- a/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/AbstractMetricsCollector.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/CRDemoMechanism.java b/src/main/java/com/rabbitmq/client/impl/CRDemoMechanism.java index 85f0d47cc4..c68fd2cdb1 100644 --- a/src/main/java/com/rabbitmq/client/impl/CRDemoMechanism.java +++ b/src/main/java/com/rabbitmq/client/impl/CRDemoMechanism.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelManager.java b/src/main/java/com/rabbitmq/client/impl/ChannelManager.java index 29c814ac41..15720db304 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelManager.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelManager.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java index 8b66273714..8b24f5e43a 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelN.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ClientVersion.java b/src/main/java/com/rabbitmq/client/impl/ClientVersion.java index 9fd29d86f9..d02296036a 100644 --- a/src/main/java/com/rabbitmq/client/impl/ClientVersion.java +++ b/src/main/java/com/rabbitmq/client/impl/ClientVersion.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/CommandAssembler.java b/src/main/java/com/rabbitmq/client/impl/CommandAssembler.java index 3d6ee17fda..6fda4471b4 100644 --- a/src/main/java/com/rabbitmq/client/impl/CommandAssembler.java +++ b/src/main/java/com/rabbitmq/client/impl/CommandAssembler.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/CompletableFutureRpcWrapper.java b/src/main/java/com/rabbitmq/client/impl/CompletableFutureRpcWrapper.java index 2157e15d71..a91876e59d 100644 --- a/src/main/java/com/rabbitmq/client/impl/CompletableFutureRpcWrapper.java +++ b/src/main/java/com/rabbitmq/client/impl/CompletableFutureRpcWrapper.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2017-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java b/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java index add7cc6398..d16de00b8a 100644 --- a/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java +++ b/src/main/java/com/rabbitmq/client/impl/ConnectionParams.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ConsumerDispatcher.java b/src/main/java/com/rabbitmq/client/impl/ConsumerDispatcher.java index fec98710fe..0111902156 100644 --- a/src/main/java/com/rabbitmq/client/impl/ConsumerDispatcher.java +++ b/src/main/java/com/rabbitmq/client/impl/ConsumerDispatcher.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ConsumerWorkService.java b/src/main/java/com/rabbitmq/client/impl/ConsumerWorkService.java index 656f68cae7..9c63f2a773 100644 --- a/src/main/java/com/rabbitmq/client/impl/ConsumerWorkService.java +++ b/src/main/java/com/rabbitmq/client/impl/ConsumerWorkService.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2022 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java b/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java index 115c3ef520..7279ad19fd 100644 --- a/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java +++ b/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyReader.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java b/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java index 029329a13d..93653b0ee2 100644 --- a/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java +++ b/src/main/java/com/rabbitmq/client/impl/ContentHeaderPropertyWriter.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java index 19b159df78..e39ffc56f7 100644 --- a/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/CredentialsProvider.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2018-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/CredentialsRefreshService.java b/src/main/java/com/rabbitmq/client/impl/CredentialsRefreshService.java index a490a61a5b..0cb94e22d7 100644 --- a/src/main/java/com/rabbitmq/client/impl/CredentialsRefreshService.java +++ b/src/main/java/com/rabbitmq/client/impl/CredentialsRefreshService.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2019-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java index eaf8a90c0c..7704f2ddac 100644 --- a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsProvider.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2018-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java index 4f5968fcc9..7e4c4224fd 100644 --- a/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java +++ b/src/main/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshService.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2019-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/DefaultExceptionHandler.java b/src/main/java/com/rabbitmq/client/impl/DefaultExceptionHandler.java index f521a37c14..4d091e4e93 100644 --- a/src/main/java/com/rabbitmq/client/impl/DefaultExceptionHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/DefaultExceptionHandler.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/Environment.java b/src/main/java/com/rabbitmq/client/impl/Environment.java index 2676311322..7ed33bb543 100644 --- a/src/main/java/com/rabbitmq/client/impl/Environment.java +++ b/src/main/java/com/rabbitmq/client/impl/Environment.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ErrorOnWriteListener.java b/src/main/java/com/rabbitmq/client/impl/ErrorOnWriteListener.java index dd9de0ce1c..0e9246f18a 100644 --- a/src/main/java/com/rabbitmq/client/impl/ErrorOnWriteListener.java +++ b/src/main/java/com/rabbitmq/client/impl/ErrorOnWriteListener.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2018-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ExternalMechanism.java b/src/main/java/com/rabbitmq/client/impl/ExternalMechanism.java index e50a0c17c7..961a510cd2 100644 --- a/src/main/java/com/rabbitmq/client/impl/ExternalMechanism.java +++ b/src/main/java/com/rabbitmq/client/impl/ExternalMechanism.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ForgivingExceptionHandler.java b/src/main/java/com/rabbitmq/client/impl/ForgivingExceptionHandler.java index 1c99f0a390..308acd26cb 100644 --- a/src/main/java/com/rabbitmq/client/impl/ForgivingExceptionHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/ForgivingExceptionHandler.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/Frame.java b/src/main/java/com/rabbitmq/client/impl/Frame.java index 8c14f8f9f2..c2d6afe0ee 100644 --- a/src/main/java/com/rabbitmq/client/impl/Frame.java +++ b/src/main/java/com/rabbitmq/client/impl/Frame.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/FrameHandler.java b/src/main/java/com/rabbitmq/client/impl/FrameHandler.java index 8d49352cb5..0e3cf71819 100644 --- a/src/main/java/com/rabbitmq/client/impl/FrameHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/FrameHandler.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/HeartbeatSender.java b/src/main/java/com/rabbitmq/client/impl/HeartbeatSender.java index d682317fe3..3d28d6ee21 100644 --- a/src/main/java/com/rabbitmq/client/impl/HeartbeatSender.java +++ b/src/main/java/com/rabbitmq/client/impl/HeartbeatSender.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/LongStringHelper.java b/src/main/java/com/rabbitmq/client/impl/LongStringHelper.java index 0a824db6de..6198d6c59d 100644 --- a/src/main/java/com/rabbitmq/client/impl/LongStringHelper.java +++ b/src/main/java/com/rabbitmq/client/impl/LongStringHelper.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/Method.java b/src/main/java/com/rabbitmq/client/impl/Method.java index 73b0e5e0d5..b108e56aa9 100644 --- a/src/main/java/com/rabbitmq/client/impl/Method.java +++ b/src/main/java/com/rabbitmq/client/impl/Method.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/MethodArgumentReader.java b/src/main/java/com/rabbitmq/client/impl/MethodArgumentReader.java index e5c3f437ee..b4bfbff5eb 100644 --- a/src/main/java/com/rabbitmq/client/impl/MethodArgumentReader.java +++ b/src/main/java/com/rabbitmq/client/impl/MethodArgumentReader.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/MethodArgumentWriter.java b/src/main/java/com/rabbitmq/client/impl/MethodArgumentWriter.java index 53fdfcfcfd..ea99933389 100644 --- a/src/main/java/com/rabbitmq/client/impl/MethodArgumentWriter.java +++ b/src/main/java/com/rabbitmq/client/impl/MethodArgumentWriter.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java index 1be16536ae..7cbf73c9a9 100644 --- a/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/MicrometerMetricsCollector.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/NetworkConnection.java b/src/main/java/com/rabbitmq/client/impl/NetworkConnection.java index 03ca1d2201..d955ae82cf 100644 --- a/src/main/java/com/rabbitmq/client/impl/NetworkConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/NetworkConnection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java index d69c1c9778..43c3b392c3 100644 --- a/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProvider.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2019-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/OAuthTokenManagementException.java b/src/main/java/com/rabbitmq/client/impl/OAuthTokenManagementException.java index d3419189cb..595b74dd19 100644 --- a/src/main/java/com/rabbitmq/client/impl/OAuthTokenManagementException.java +++ b/src/main/java/com/rabbitmq/client/impl/OAuthTokenManagementException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2019-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/OpenTelemetryMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/OpenTelemetryMetricsCollector.java index 685865d5a6..d3cc4067da 100644 --- a/src/main/java/com/rabbitmq/client/impl/OpenTelemetryMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/OpenTelemetryMetricsCollector.java @@ -1,4 +1,4 @@ -// Copyright (c) 2022 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/PlainMechanism.java b/src/main/java/com/rabbitmq/client/impl/PlainMechanism.java index 75651d74b0..923e8cb722 100644 --- a/src/main/java/com/rabbitmq/client/impl/PlainMechanism.java +++ b/src/main/java/com/rabbitmq/client/impl/PlainMechanism.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProvider.java b/src/main/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProvider.java index cd8f855b01..dc091550d5 100644 --- a/src/main/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProvider.java +++ b/src/main/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProvider.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2019-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/RpcContinuationRpcWrapper.java b/src/main/java/com/rabbitmq/client/impl/RpcContinuationRpcWrapper.java index 71d60a4690..b5f202237c 100644 --- a/src/main/java/com/rabbitmq/client/impl/RpcContinuationRpcWrapper.java +++ b/src/main/java/com/rabbitmq/client/impl/RpcContinuationRpcWrapper.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2017-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/RpcWrapper.java b/src/main/java/com/rabbitmq/client/impl/RpcWrapper.java index 8d81258ffc..009ac45fe7 100644 --- a/src/main/java/com/rabbitmq/client/impl/RpcWrapper.java +++ b/src/main/java/com/rabbitmq/client/impl/RpcWrapper.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2017-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/SetQueue.java b/src/main/java/com/rabbitmq/client/impl/SetQueue.java index 6a5dc8db12..11bc1de95d 100644 --- a/src/main/java/com/rabbitmq/client/impl/SetQueue.java +++ b/src/main/java/com/rabbitmq/client/impl/SetQueue.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ShutdownNotifierComponent.java b/src/main/java/com/rabbitmq/client/impl/ShutdownNotifierComponent.java index e4ec15836b..ab7de52c40 100644 --- a/src/main/java/com/rabbitmq/client/impl/ShutdownNotifierComponent.java +++ b/src/main/java/com/rabbitmq/client/impl/ShutdownNotifierComponent.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java b/src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java index 3e4e0a7078..7df8b7c3b7 100644 --- a/src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/SocketFrameHandlerFactory.java b/src/main/java/com/rabbitmq/client/impl/SocketFrameHandlerFactory.java index 40818c46ba..b48374f9bc 100644 --- a/src/main/java/com/rabbitmq/client/impl/SocketFrameHandlerFactory.java +++ b/src/main/java/com/rabbitmq/client/impl/SocketFrameHandlerFactory.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java b/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java index 07e7780817..a4ddfc24f4 100644 --- a/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java +++ b/src/main/java/com/rabbitmq/client/impl/StandardMetricsCollector.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/StrictExceptionHandler.java b/src/main/java/com/rabbitmq/client/impl/StrictExceptionHandler.java index 62f37d72b4..7fc1f37821 100644 --- a/src/main/java/com/rabbitmq/client/impl/StrictExceptionHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/StrictExceptionHandler.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/TlsUtils.java b/src/main/java/com/rabbitmq/client/impl/TlsUtils.java index aa103607ec..45a5ecfde5 100644 --- a/src/main/java/com/rabbitmq/client/impl/TlsUtils.java +++ b/src/main/java/com/rabbitmq/client/impl/TlsUtils.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2019-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/TruncatedInputStream.java b/src/main/java/com/rabbitmq/client/impl/TruncatedInputStream.java index dd35c3f2e6..ba3e756e0f 100644 --- a/src/main/java/com/rabbitmq/client/impl/TruncatedInputStream.java +++ b/src/main/java/com/rabbitmq/client/impl/TruncatedInputStream.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/UnknownChannelException.java b/src/main/java/com/rabbitmq/client/impl/UnknownChannelException.java index ff59b907cf..a7c2331b80 100644 --- a/src/main/java/com/rabbitmq/client/impl/UnknownChannelException.java +++ b/src/main/java/com/rabbitmq/client/impl/UnknownChannelException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/UpdateSecretExtension.java b/src/main/java/com/rabbitmq/client/impl/UpdateSecretExtension.java index 3028a886ab..ff5e7bfeed 100644 --- a/src/main/java/com/rabbitmq/client/impl/UpdateSecretExtension.java +++ b/src/main/java/com/rabbitmq/client/impl/UpdateSecretExtension.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2019-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/Utils.java b/src/main/java/com/rabbitmq/client/impl/Utils.java index d3e3412ee4..c306647e34 100644 --- a/src/main/java/com/rabbitmq/client/impl/Utils.java +++ b/src/main/java/com/rabbitmq/client/impl/Utils.java @@ -1,4 +1,4 @@ -// Copyright (c) 2022 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ValueReader.java b/src/main/java/com/rabbitmq/client/impl/ValueReader.java index ed7f41284c..77329505b5 100644 --- a/src/main/java/com/rabbitmq/client/impl/ValueReader.java +++ b/src/main/java/com/rabbitmq/client/impl/ValueReader.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/ValueWriter.java b/src/main/java/com/rabbitmq/client/impl/ValueWriter.java index c167fc0475..f8e599ef32 100644 --- a/src/main/java/com/rabbitmq/client/impl/ValueWriter.java +++ b/src/main/java/com/rabbitmq/client/impl/ValueWriter.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java b/src/main/java/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java index 60dbe04bb4..a239239868 100644 --- a/src/main/java/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java +++ b/src/main/java/com/rabbitmq/client/impl/VariableLinkedBlockingQueue.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -14,8 +14,9 @@ // info@rabbitmq.com. /* - * Modifications Copyright 2015-2020 VMware, Inc. or its affiliates. and licenced as per - * the rest of the RabbitMQ Java client. + * Modifications Copyright 2015-2023 Broadcom. All Rights Reserved. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * Licenced as per the rest of the RabbitMQ Java client. */ /* diff --git a/src/main/java/com/rabbitmq/client/impl/Version.java b/src/main/java/com/rabbitmq/client/impl/Version.java index 3e64d51702..ea93eba885 100644 --- a/src/main/java/com/rabbitmq/client/impl/Version.java +++ b/src/main/java/com/rabbitmq/client/impl/Version.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/WorkPool.java b/src/main/java/com/rabbitmq/client/impl/WorkPool.java index e4d7dc8cfe..870df03b15 100644 --- a/src/main/java/com/rabbitmq/client/impl/WorkPool.java +++ b/src/main/java/com/rabbitmq/client/impl/WorkPool.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/WorkPoolFullException.java b/src/main/java/com/rabbitmq/client/impl/WorkPoolFullException.java index 68e7175f1a..8b753b747d 100644 --- a/src/main/java/com/rabbitmq/client/impl/WorkPoolFullException.java +++ b/src/main/java/com/rabbitmq/client/impl/WorkPoolFullException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2018-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/ByteBufferOutputStream.java b/src/main/java/com/rabbitmq/client/impl/nio/ByteBufferOutputStream.java index e8ed5ff841..62ce2b4671 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/ByteBufferOutputStream.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/ByteBufferOutputStream.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java b/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java index cd708cad9a..7f47f6d919 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/FrameBuilder.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/FrameWriteRequest.java b/src/main/java/com/rabbitmq/client/impl/nio/FrameWriteRequest.java index d291a0d3f4..edd255a40b 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/FrameWriteRequest.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/FrameWriteRequest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/HeaderWriteRequest.java b/src/main/java/com/rabbitmq/client/impl/nio/HeaderWriteRequest.java index 558f35e025..68c9f6e894 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/HeaderWriteRequest.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/HeaderWriteRequest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioHelper.java b/src/main/java/com/rabbitmq/client/impl/nio/NioHelper.java index ab8a49b71b..8c09857493 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioHelper.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioHelper.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java b/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java index b143429ea7..ea9351e410 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioLoop.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioLoopContext.java b/src/main/java/com/rabbitmq/client/impl/nio/NioLoopContext.java index 55412e0908..3d9e76975a 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioLoopContext.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioLoopContext.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java b/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java index 049fbb33ba..d4fce8a3d7 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SelectorHolder.java b/src/main/java/com/rabbitmq/client/impl/nio/SelectorHolder.java index 97b64b2be1..9f1168efbf 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SelectorHolder.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SelectorHolder.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandler.java b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandler.java index c17c5e9579..93eea9cd60 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandler.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java index ed0a4f20f8..3e7e55e94a 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerFactory.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java index b1a391fd65..f8566fb876 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelFrameHandlerState.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelRegistration.java b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelRegistration.java index 2c9d3f0d03..feff419fff 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelRegistration.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SocketChannelRegistration.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferOutputStream.java b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferOutputStream.java index c861ad6e77..24488578e1 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferOutputStream.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineByteBufferOutputStream.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineFrameBuilder.java b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineFrameBuilder.java index 48072988c2..bdf898dd3b 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineFrameBuilder.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineFrameBuilder.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java index b7a535da87..d9a5b17105 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2022 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/nio/WriteRequest.java b/src/main/java/com/rabbitmq/client/impl/nio/WriteRequest.java index c61731e18b..2af3c483ee 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/WriteRequest.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/WriteRequest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java index 0771e21fbb..c394887c91 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringChannel.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java index 261b2058fa..4cc697c760 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/AutorecoveringConnection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/BackoffPolicy.java b/src/main/java/com/rabbitmq/client/impl/recovery/BackoffPolicy.java index 08498683ab..036bf43b63 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/BackoffPolicy.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/BackoffPolicy.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2018-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/ConsumerRecoveryListener.java b/src/main/java/com/rabbitmq/client/impl/recovery/ConsumerRecoveryListener.java index 8c87d86090..696944f8df 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/ConsumerRecoveryListener.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/ConsumerRecoveryListener.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java b/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java index 2e2890c05b..2e834c075d 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/DefaultRetryHandler.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2018-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/QueueRecoveryListener.java b/src/main/java/com/rabbitmq/client/impl/recovery/QueueRecoveryListener.java index 66f7f9248f..b9ee8003ab 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/QueueRecoveryListener.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/QueueRecoveryListener.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedBinding.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedBinding.java index 0ddf4e3bcf..2d1f50fda3 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedBinding.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedBinding.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedConsumer.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedConsumer.java index 3b0d5009d5..16e4ba078c 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedConsumer.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedConsumer.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedEntity.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedEntity.java index a56f58b88a..2f30a313dc 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedEntity.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedEntity.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchange.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchange.java index aaedcbbf58..9a493aebfd 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchange.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchange.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchangeBinding.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchangeBinding.java index d128b59bf0..6b967164d7 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchangeBinding.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedExchangeBinding.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedNamedEntity.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedNamedEntity.java index 7b5a86a8f9..3d69ac75f2 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedNamedEntity.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedNamedEntity.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java index b41ecdc302..a4cd98eec9 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueue.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java index 37bbb14fe5..1a1b506385 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecordedQueueBinding.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnection.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnection.java index 7060407363..afba2483b5 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java index 535330c24e..bfefdb3a28 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareAMQConnectionFactory.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelManager.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelManager.java index d4208d340b..a79b2dfdb5 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelManager.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelManager.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java index 628c802c65..ccfa59be00 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryAwareChannelN.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryCanBeginListener.java b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryCanBeginListener.java index cb5eae86fb..004537956d 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryCanBeginListener.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RecoveryCanBeginListener.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RetryContext.java b/src/main/java/com/rabbitmq/client/impl/recovery/RetryContext.java index 6640a7e7c1..f9b10a840f 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RetryContext.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RetryContext.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2018-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RetryHandler.java b/src/main/java/com/rabbitmq/client/impl/recovery/RetryHandler.java index a5eac40fab..d840b88a04 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RetryHandler.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RetryHandler.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2018-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/RetryResult.java b/src/main/java/com/rabbitmq/client/impl/recovery/RetryResult.java index df1d6ae1df..9250c74f7f 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/RetryResult.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/RetryResult.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2018-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryFilter.java b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryFilter.java index 602b5452f5..02364510a1 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryFilter.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryFilter.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2018-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryHandlerBuilder.java b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryHandlerBuilder.java index b8dfdff7bc..170620547e 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryHandlerBuilder.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryHandlerBuilder.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2018-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java index c452b07f71..d17e2f9809 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/TopologyRecoveryRetryLogic.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2018-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/impl/recovery/Utils.java b/src/main/java/com/rabbitmq/client/impl/recovery/Utils.java index 569f9da73a..1e74020077 100644 --- a/src/main/java/com/rabbitmq/client/impl/recovery/Utils.java +++ b/src/main/java/com/rabbitmq/client/impl/recovery/Utils.java @@ -1,4 +1,4 @@ -// Copyright (c) 2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/observation/NoOpObservationCollector.java b/src/main/java/com/rabbitmq/client/observation/NoOpObservationCollector.java index 76ddd82a70..7b37cd32a0 100644 --- a/src/main/java/com/rabbitmq/client/observation/NoOpObservationCollector.java +++ b/src/main/java/com/rabbitmq/client/observation/NoOpObservationCollector.java @@ -1,4 +1,4 @@ -// Copyright (c) 2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/observation/ObservationCollector.java b/src/main/java/com/rabbitmq/client/observation/ObservationCollector.java index e542d34387..04c452f8fe 100644 --- a/src/main/java/com/rabbitmq/client/observation/ObservationCollector.java +++ b/src/main/java/com/rabbitmq/client/observation/ObservationCollector.java @@ -1,4 +1,4 @@ -// Copyright (c) 2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultDeliverObservationConvention.java b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultDeliverObservationConvention.java index 1bfa512b86..d32f9be01c 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultDeliverObservationConvention.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultDeliverObservationConvention.java @@ -1,4 +1,4 @@ -// Copyright (c) 2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultProcessObservationConvention.java b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultProcessObservationConvention.java index b7233adfae..45201f9ea4 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultProcessObservationConvention.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultProcessObservationConvention.java @@ -1,4 +1,4 @@ -// Copyright (c) 2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultPublishObservationConvention.java b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultPublishObservationConvention.java index 019e32367f..199b3df1e0 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultPublishObservationConvention.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultPublishObservationConvention.java @@ -1,4 +1,4 @@ -// Copyright (c) 2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultReceiveObservationConvention.java b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultReceiveObservationConvention.java index 7a4bd0317b..e1928b8ee5 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultReceiveObservationConvention.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultReceiveObservationConvention.java @@ -1,4 +1,4 @@ -// Copyright (c) 2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/DeliverContext.java b/src/main/java/com/rabbitmq/client/observation/micrometer/DeliverContext.java index 2209d7897c..e838d302e5 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/DeliverContext.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/DeliverContext.java @@ -1,4 +1,4 @@ -// Copyright (c) 2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/DeliverObservationConvention.java b/src/main/java/com/rabbitmq/client/observation/micrometer/DeliverObservationConvention.java index ba10eca747..d57f035fd5 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/DeliverObservationConvention.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/DeliverObservationConvention.java @@ -1,4 +1,4 @@ -// Copyright (c) 2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java b/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java index cd0b1ca500..74a2071dc7 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java @@ -1,4 +1,4 @@ -// Copyright (c) 2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollectorBuilder.java b/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollectorBuilder.java index 1a15a7e762..9e775d108f 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollectorBuilder.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollectorBuilder.java @@ -1,4 +1,4 @@ -// Copyright (c) 2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/PublishContext.java b/src/main/java/com/rabbitmq/client/observation/micrometer/PublishContext.java index 51b3e06be4..146e8ee058 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/PublishContext.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/PublishContext.java @@ -1,4 +1,4 @@ -// Copyright (c) 2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/PublishObservationConvention.java b/src/main/java/com/rabbitmq/client/observation/micrometer/PublishObservationConvention.java index f6fce73ff2..8f8fc60e89 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/PublishObservationConvention.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/PublishObservationConvention.java @@ -1,4 +1,4 @@ -// Copyright (c) 2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/RabbitMqObservationDocumentation.java b/src/main/java/com/rabbitmq/client/observation/micrometer/RabbitMqObservationDocumentation.java index 1b169d838f..d88d7033c6 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/RabbitMqObservationDocumentation.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/RabbitMqObservationDocumentation.java @@ -1,4 +1,4 @@ -// Copyright (c) 2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/tools/json/JSONUtil.java b/src/main/java/com/rabbitmq/tools/json/JSONUtil.java index 55c2b695ed..a00903a50f 100644 --- a/src/main/java/com/rabbitmq/tools/json/JSONUtil.java +++ b/src/main/java/com/rabbitmq/tools/json/JSONUtil.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java index 81a1f26b5b..7eae103d7d 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JacksonJsonRpcMapper.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2018-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java index 76d2ef31df..851836196f 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcClient.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java index d167d0318e..c2f7dfee2a 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java index 980428612b..b8fc8061d4 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMapper.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2018-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMappingException.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMappingException.java index fc998b1b02..6876e538f6 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMappingException.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcMappingException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2018-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java index a37e957718..e627f4448f 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/JsonRpcServer.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/ParameterDescription.java b/src/main/java/com/rabbitmq/tools/jsonrpc/ParameterDescription.java index cc58516b1c..61fbfbaf63 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/ParameterDescription.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/ParameterDescription.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java b/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java index 431d4e6e13..be465e2659 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/ProcedureDescription.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java b/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java index 8986cc24e2..7711eb838b 100644 --- a/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java +++ b/src/main/java/com/rabbitmq/tools/jsonrpc/ServiceDescription.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/utility/BlockingCell.java b/src/main/java/com/rabbitmq/utility/BlockingCell.java index f9c588b7cf..0792ebde71 100644 --- a/src/main/java/com/rabbitmq/utility/BlockingCell.java +++ b/src/main/java/com/rabbitmq/utility/BlockingCell.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/utility/BlockingValueOrException.java b/src/main/java/com/rabbitmq/utility/BlockingValueOrException.java index 5946ccbb4d..41f93249dd 100644 --- a/src/main/java/com/rabbitmq/utility/BlockingValueOrException.java +++ b/src/main/java/com/rabbitmq/utility/BlockingValueOrException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/utility/IntAllocator.java b/src/main/java/com/rabbitmq/utility/IntAllocator.java index 88d9f3efb8..5fe44419dc 100644 --- a/src/main/java/com/rabbitmq/utility/IntAllocator.java +++ b/src/main/java/com/rabbitmq/utility/IntAllocator.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/utility/SensibleClone.java b/src/main/java/com/rabbitmq/utility/SensibleClone.java index 78e68cb6a5..cf02ac9c8a 100644 --- a/src/main/java/com/rabbitmq/utility/SensibleClone.java +++ b/src/main/java/com/rabbitmq/utility/SensibleClone.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/utility/Utility.java b/src/main/java/com/rabbitmq/utility/Utility.java index db709a7ff8..5a07326571 100644 --- a/src/main/java/com/rabbitmq/utility/Utility.java +++ b/src/main/java/com/rabbitmq/utility/Utility.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/utility/ValueOrException.java b/src/main/java/com/rabbitmq/utility/ValueOrException.java index 93cb1fe563..a8adbefff4 100644 --- a/src/main/java/com/rabbitmq/utility/ValueOrException.java +++ b/src/main/java/com/rabbitmq/utility/ValueOrException.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/AbstractJsonRpcTest.java b/src/test/java/com/rabbitmq/client/AbstractJsonRpcTest.java index ec9fbd2f39..6172a8f208 100644 --- a/src/test/java/com/rabbitmq/client/AbstractJsonRpcTest.java +++ b/src/test/java/com/rabbitmq/client/AbstractJsonRpcTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2018-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/AmqpClientTestExtension.java b/src/test/java/com/rabbitmq/client/AmqpClientTestExtension.java index 07e27a6838..ee4456f536 100644 --- a/src/test/java/com/rabbitmq/client/AmqpClientTestExtension.java +++ b/src/test/java/com/rabbitmq/client/AmqpClientTestExtension.java @@ -1,4 +1,4 @@ -// Copyright (c) 2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/JacksonJsonRpcTest.java b/src/test/java/com/rabbitmq/client/JacksonJsonRpcTest.java index f926061f94..c8e8ebc829 100644 --- a/src/test/java/com/rabbitmq/client/JacksonJsonRpcTest.java +++ b/src/test/java/com/rabbitmq/client/JacksonJsonRpcTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2018-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/QueueingConsumer.java b/src/test/java/com/rabbitmq/client/QueueingConsumer.java index 9ecddaa67b..c018b1989b 100644 --- a/src/test/java/com/rabbitmq/client/QueueingConsumer.java +++ b/src/test/java/com/rabbitmq/client/QueueingConsumer.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/impl/AMQConnectionRefreshCredentialsTest.java b/src/test/java/com/rabbitmq/client/impl/AMQConnectionRefreshCredentialsTest.java index 96d40cc4cf..d99a8434d6 100644 --- a/src/test/java/com/rabbitmq/client/impl/AMQConnectionRefreshCredentialsTest.java +++ b/src/test/java/com/rabbitmq/client/impl/AMQConnectionRefreshCredentialsTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2019-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java b/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java index 2ad3681c52..e52a6d98c3 100644 --- a/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java +++ b/src/test/java/com/rabbitmq/client/impl/DefaultCredentialsRefreshServiceTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2019-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java b/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java index f717cbcf27..6d210f3a8f 100644 --- a/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java +++ b/src/test/java/com/rabbitmq/client/impl/OAuth2ClientCredentialsGrantCredentialsProviderTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2019-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProviderTest.java b/src/test/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProviderTest.java index dfed27341d..8da70a0034 100644 --- a/src/test/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProviderTest.java +++ b/src/test/java/com/rabbitmq/client/impl/RefreshProtectedCredentialsProviderTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2019-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java b/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java index 54a9acfe55..e402c1f868 100644 --- a/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java +++ b/src/test/java/com/rabbitmq/client/impl/ValueWriterTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2019-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java b/src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java index 54a49da485..19d874ced6 100644 --- a/src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java +++ b/src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/AMQBuilderApiTest.java b/src/test/java/com/rabbitmq/client/test/AMQBuilderApiTest.java index a4b54c9fa7..c2a1d40149 100644 --- a/src/test/java/com/rabbitmq/client/test/AMQBuilderApiTest.java +++ b/src/test/java/com/rabbitmq/client/test/AMQBuilderApiTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/AMQChannelTest.java b/src/test/java/com/rabbitmq/client/test/AMQChannelTest.java index 091e1b14c2..91112cce64 100644 --- a/src/test/java/com/rabbitmq/client/test/AMQChannelTest.java +++ b/src/test/java/com/rabbitmq/client/test/AMQChannelTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java b/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java index de50c74542..16f861086b 100644 --- a/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java +++ b/src/test/java/com/rabbitmq/client/test/AMQConnectionTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/AddressTest.java b/src/test/java/com/rabbitmq/client/test/AddressTest.java index bc9e860e8b..d8101c63c8 100644 --- a/src/test/java/com/rabbitmq/client/test/AddressTest.java +++ b/src/test/java/com/rabbitmq/client/test/AddressTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2018-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java b/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java index 5e41dfed3b..1f417ec5a7 100644 --- a/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java +++ b/src/test/java/com/rabbitmq/client/test/AmqpUriTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/BlockedConnectionTest.java b/src/test/java/com/rabbitmq/client/test/BlockedConnectionTest.java index f8748ed27e..d3ceb146fc 100644 --- a/src/test/java/com/rabbitmq/client/test/BlockedConnectionTest.java +++ b/src/test/java/com/rabbitmq/client/test/BlockedConnectionTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/BlockingCellTest.java b/src/test/java/com/rabbitmq/client/test/BlockingCellTest.java index 03334570a6..a66ae1e0c0 100644 --- a/src/test/java/com/rabbitmq/client/test/BlockingCellTest.java +++ b/src/test/java/com/rabbitmq/client/test/BlockingCellTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java b/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java index 069ee4dd98..1b941314a8 100644 --- a/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java +++ b/src/test/java/com/rabbitmq/client/test/BrokenFramesTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java index ed975b0e5f..d7d176a359 100644 --- a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java +++ b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/Bug20004Test.java b/src/test/java/com/rabbitmq/client/test/Bug20004Test.java index a62598165b..5807be06f3 100644 --- a/src/test/java/com/rabbitmq/client/test/Bug20004Test.java +++ b/src/test/java/com/rabbitmq/client/test/Bug20004Test.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ChannelAsyncCompletableFutureTest.java b/src/test/java/com/rabbitmq/client/test/ChannelAsyncCompletableFutureTest.java index b3e5592dd4..1e46bb2a89 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelAsyncCompletableFutureTest.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelAsyncCompletableFutureTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2017-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ChannelNTest.java b/src/test/java/com/rabbitmq/client/test/ChannelNTest.java index 24b6d1e941..92cbf355db 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelNTest.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelNTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2019-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ChannelNumberAllocationTests.java b/src/test/java/com/rabbitmq/client/test/ChannelNumberAllocationTests.java index 76ecd0abda..28c28552f5 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelNumberAllocationTests.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelNumberAllocationTests.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java b/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java index d2f3aafcba..bc7c31b135 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ClientTestSuite.java b/src/test/java/com/rabbitmq/client/test/ClientTestSuite.java index 2162103e0f..cc515be623 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientTestSuite.java +++ b/src/test/java/com/rabbitmq/client/test/ClientTestSuite.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ClientVersionTest.java b/src/test/java/com/rabbitmq/client/test/ClientVersionTest.java index 3b66ec34fa..d782e050cf 100644 --- a/src/test/java/com/rabbitmq/client/test/ClientVersionTest.java +++ b/src/test/java/com/rabbitmq/client/test/ClientVersionTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2017-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ClonePropertiesTest.java b/src/test/java/com/rabbitmq/client/test/ClonePropertiesTest.java index 0ba413e9e8..af1702bc48 100644 --- a/src/test/java/com/rabbitmq/client/test/ClonePropertiesTest.java +++ b/src/test/java/com/rabbitmq/client/test/ClonePropertiesTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/CloseInMainLoop.java b/src/test/java/com/rabbitmq/client/test/CloseInMainLoop.java index b340f472c4..186df461a9 100644 --- a/src/test/java/com/rabbitmq/client/test/CloseInMainLoop.java +++ b/src/test/java/com/rabbitmq/client/test/CloseInMainLoop.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ConfirmBase.java b/src/test/java/com/rabbitmq/client/test/ConfirmBase.java index 425965b17a..1a82fd9c0a 100644 --- a/src/test/java/com/rabbitmq/client/test/ConfirmBase.java +++ b/src/test/java/com/rabbitmq/client/test/ConfirmBase.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java b/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java index 279ecbffe7..f3eee0aaa5 100644 --- a/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java +++ b/src/test/java/com/rabbitmq/client/test/ConnectionFactoryTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ConnectionTest.java b/src/test/java/com/rabbitmq/client/test/ConnectionTest.java index e7233d6e86..19a0bceb49 100644 --- a/src/test/java/com/rabbitmq/client/test/ConnectionTest.java +++ b/src/test/java/com/rabbitmq/client/test/ConnectionTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2018-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/DefaultRetryHandlerTest.java b/src/test/java/com/rabbitmq/client/test/DefaultRetryHandlerTest.java index 363c7285c8..ca3f40a8b3 100644 --- a/src/test/java/com/rabbitmq/client/test/DefaultRetryHandlerTest.java +++ b/src/test/java/com/rabbitmq/client/test/DefaultRetryHandlerTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2018-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/DnsSrvRecordAddressResolverTest.java b/src/test/java/com/rabbitmq/client/test/DnsSrvRecordAddressResolverTest.java index 839fb16fe4..ca9d67aec5 100644 --- a/src/test/java/com/rabbitmq/client/test/DnsSrvRecordAddressResolverTest.java +++ b/src/test/java/com/rabbitmq/client/test/DnsSrvRecordAddressResolverTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java b/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java index 311aabdef0..ba81589aee 100644 --- a/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java +++ b/src/test/java/com/rabbitmq/client/test/FrameBuilderTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/GeneratedClassesTest.java b/src/test/java/com/rabbitmq/client/test/GeneratedClassesTest.java index d8b139e7d7..c67ad3abae 100644 --- a/src/test/java/com/rabbitmq/client/test/GeneratedClassesTest.java +++ b/src/test/java/com/rabbitmq/client/test/GeneratedClassesTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2018-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/LambdaCallbackTest.java b/src/test/java/com/rabbitmq/client/test/LambdaCallbackTest.java index 68390b0631..1fb6c2e826 100644 --- a/src/test/java/com/rabbitmq/client/test/LambdaCallbackTest.java +++ b/src/test/java/com/rabbitmq/client/test/LambdaCallbackTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2017-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/LongStringTest.java b/src/test/java/com/rabbitmq/client/test/LongStringTest.java index 82c6053116..505544ce20 100644 --- a/src/test/java/com/rabbitmq/client/test/LongStringTest.java +++ b/src/test/java/com/rabbitmq/client/test/LongStringTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/MaxInboundMessageSizeTest.java b/src/test/java/com/rabbitmq/client/test/MaxInboundMessageSizeTest.java index da534d9c5f..a3577b957e 100644 --- a/src/test/java/com/rabbitmq/client/test/MaxInboundMessageSizeTest.java +++ b/src/test/java/com/rabbitmq/client/test/MaxInboundMessageSizeTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java b/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java index 8404a25d03..611b412929 100644 --- a/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java +++ b/src/test/java/com/rabbitmq/client/test/MetricsCollectorTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/MicrometerMetricsCollectorTest.java b/src/test/java/com/rabbitmq/client/test/MicrometerMetricsCollectorTest.java index 16c7fc12df..b55aff2486 100644 --- a/src/test/java/com/rabbitmq/client/test/MicrometerMetricsCollectorTest.java +++ b/src/test/java/com/rabbitmq/client/test/MicrometerMetricsCollectorTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2018-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/MultiThreadedChannel.java b/src/test/java/com/rabbitmq/client/test/MultiThreadedChannel.java index 7893ab056b..f7d185e44b 100644 --- a/src/test/java/com/rabbitmq/client/test/MultiThreadedChannel.java +++ b/src/test/java/com/rabbitmq/client/test/MultiThreadedChannel.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/NioDeadlockOnConnectionClosing.java b/src/test/java/com/rabbitmq/client/test/NioDeadlockOnConnectionClosing.java index 9ca7dd156a..1e97ac746e 100644 --- a/src/test/java/com/rabbitmq/client/test/NioDeadlockOnConnectionClosing.java +++ b/src/test/java/com/rabbitmq/client/test/NioDeadlockOnConnectionClosing.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java b/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java index ea0bf72c74..2b0c934cf1 100644 --- a/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java +++ b/src/test/java/com/rabbitmq/client/test/NoAutoRecoveryWhenTcpWindowIsFullTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2018-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java b/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java index d0d52ab556..233f03ae8a 100644 --- a/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java +++ b/src/test/java/com/rabbitmq/client/test/PropertyFileInitialisationTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/QueueingConsumerTests.java b/src/test/java/com/rabbitmq/client/test/QueueingConsumerTests.java index 4a4793952f..d5fa0bbf89 100644 --- a/src/test/java/com/rabbitmq/client/test/QueueingConsumerTests.java +++ b/src/test/java/com/rabbitmq/client/test/QueueingConsumerTests.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/RecoveryAwareAMQConnectionFactoryTest.java b/src/test/java/com/rabbitmq/client/test/RecoveryAwareAMQConnectionFactoryTest.java index 2b40553778..2355ea2310 100644 --- a/src/test/java/com/rabbitmq/client/test/RecoveryAwareAMQConnectionFactoryTest.java +++ b/src/test/java/com/rabbitmq/client/test/RecoveryAwareAMQConnectionFactoryTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/RecoveryDelayHandlerTest.java b/src/test/java/com/rabbitmq/client/test/RecoveryDelayHandlerTest.java index 035b96191d..5d060effff 100644 --- a/src/test/java/com/rabbitmq/client/test/RecoveryDelayHandlerTest.java +++ b/src/test/java/com/rabbitmq/client/test/RecoveryDelayHandlerTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java b/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java index 8e32dbc6c3..a9901702ba 100644 --- a/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java +++ b/src/test/java/com/rabbitmq/client/test/RefreshCredentialsTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2019-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/RpcTest.java b/src/test/java/com/rabbitmq/client/test/RpcTest.java index 5d95d0d448..f600709d19 100644 --- a/src/test/java/com/rabbitmq/client/test/RpcTest.java +++ b/src/test/java/com/rabbitmq/client/test/RpcTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2017-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/RpcTopologyRecordingTest.java b/src/test/java/com/rabbitmq/client/test/RpcTopologyRecordingTest.java index 249eeb3f1b..6b8828c807 100644 --- a/src/test/java/com/rabbitmq/client/test/RpcTopologyRecordingTest.java +++ b/src/test/java/com/rabbitmq/client/test/RpcTopologyRecordingTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2018-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java b/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java index 0e8317b987..1e7a2526ec 100644 --- a/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java +++ b/src/test/java/com/rabbitmq/client/test/SharedThreadPoolTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/SslContextFactoryTest.java b/src/test/java/com/rabbitmq/client/test/SslContextFactoryTest.java index af4e206977..9becbe7a32 100644 --- a/src/test/java/com/rabbitmq/client/test/SslContextFactoryTest.java +++ b/src/test/java/com/rabbitmq/client/test/SslContextFactoryTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/StrictExceptionHandlerTest.java b/src/test/java/com/rabbitmq/client/test/StrictExceptionHandlerTest.java index c2a3f28aa9..e51c1d42a0 100644 --- a/src/test/java/com/rabbitmq/client/test/StrictExceptionHandlerTest.java +++ b/src/test/java/com/rabbitmq/client/test/StrictExceptionHandlerTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2018-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/TableTest.java b/src/test/java/com/rabbitmq/client/test/TableTest.java index be808fa262..8e7652960f 100644 --- a/src/test/java/com/rabbitmq/client/test/TableTest.java +++ b/src/test/java/com/rabbitmq/client/test/TableTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/TestUtils.java b/src/test/java/com/rabbitmq/client/test/TestUtils.java index ef63abc1b5..f6ab6282c3 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtils.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtils.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/TestUtilsTest.java b/src/test/java/com/rabbitmq/client/test/TestUtilsTest.java index 897296938d..296930ad1c 100644 --- a/src/test/java/com/rabbitmq/client/test/TestUtilsTest.java +++ b/src/test/java/com/rabbitmq/client/test/TestUtilsTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2017-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/TlsUtilsTest.java b/src/test/java/com/rabbitmq/client/test/TlsUtilsTest.java index 51a1b691e1..6fccaffd1f 100644 --- a/src/test/java/com/rabbitmq/client/test/TlsUtilsTest.java +++ b/src/test/java/com/rabbitmq/client/test/TlsUtilsTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2019-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/TrafficListenerTest.java b/src/test/java/com/rabbitmq/client/test/TrafficListenerTest.java index db8d021194..77225c3403 100644 --- a/src/test/java/com/rabbitmq/client/test/TrafficListenerTest.java +++ b/src/test/java/com/rabbitmq/client/test/TrafficListenerTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2018-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/TruncatedInputStreamTest.java b/src/test/java/com/rabbitmq/client/test/TruncatedInputStreamTest.java index 5d4a9d1273..4362ffa406 100644 --- a/src/test/java/com/rabbitmq/client/test/TruncatedInputStreamTest.java +++ b/src/test/java/com/rabbitmq/client/test/TruncatedInputStreamTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ValueOrExceptionTest.java b/src/test/java/com/rabbitmq/client/test/ValueOrExceptionTest.java index ac9a38b767..4536c1759f 100644 --- a/src/test/java/com/rabbitmq/client/test/ValueOrExceptionTest.java +++ b/src/test/java/com/rabbitmq/client/test/ValueOrExceptionTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/AbstractRejectTest.java b/src/test/java/com/rabbitmq/client/test/functional/AbstractRejectTest.java index 82b8b78035..2e4ae9b5b6 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/AbstractRejectTest.java +++ b/src/test/java/com/rabbitmq/client/test/functional/AbstractRejectTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/AlternateExchange.java b/src/test/java/com/rabbitmq/client/test/functional/AlternateExchange.java index 816d9f70f5..5ed6561757 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/AlternateExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/AlternateExchange.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/BasicGet.java b/src/test/java/com/rabbitmq/client/test/functional/BasicGet.java index 0956e8cc35..e8929be413 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/BasicGet.java +++ b/src/test/java/com/rabbitmq/client/test/functional/BasicGet.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java b/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java index a478748a7d..6e23ce0233 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java +++ b/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycle.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycleBase.java b/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycleBase.java index c3b7995c27..9314c3566a 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycleBase.java +++ b/src/test/java/com/rabbitmq/client/test/functional/BindingLifecycleBase.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java b/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java index b65d2ad740..e11e63514d 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java +++ b/src/test/java/com/rabbitmq/client/test/functional/CcRoutes.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java b/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java index 2580ed0daf..c55e64a8ca 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ClusteredTestBase.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/Confirm.java b/src/test/java/com/rabbitmq/client/test/functional/Confirm.java index 0dbf5950c8..7a374623db 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Confirm.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Confirm.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionOpen.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionOpen.java index 646f9e054d..44e4dba063 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionOpen.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionOpen.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java index 0f9ff4a055..8dfb268ae5 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java b/src/test/java/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java index 7d8631a100..e7f32dedbe 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConsumerCancelNotification.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConsumerCount.java b/src/test/java/com/rabbitmq/client/test/functional/ConsumerCount.java index eca4b57c48..f6f89fbfeb 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConsumerCount.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConsumerCount.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConsumerPriorities.java b/src/test/java/com/rabbitmq/client/test/functional/ConsumerPriorities.java index db0ebc1212..af52b6101c 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConsumerPriorities.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConsumerPriorities.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java index d0e8bee231..86ddf898e1 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DeadLetterExchange.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/DefaultExchange.java b/src/test/java/com/rabbitmq/client/test/functional/DefaultExchange.java index 72c2793f9b..42de69e827 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DefaultExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DefaultExchange.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/DirectReplyTo.java b/src/test/java/com/rabbitmq/client/test/functional/DirectReplyTo.java index 84911f447c..34e1d39043 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DirectReplyTo.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DirectReplyTo.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/DoubleDeletion.java b/src/test/java/com/rabbitmq/client/test/functional/DoubleDeletion.java index c28bab794c..cb7a66f3ee 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DoubleDeletion.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DoubleDeletion.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/DurableOnTransient.java b/src/test/java/com/rabbitmq/client/test/functional/DurableOnTransient.java index 3732ff55ac..06c788da12 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DurableOnTransient.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DurableOnTransient.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExceptionHandling.java b/src/test/java/com/rabbitmq/client/test/functional/ExceptionHandling.java index 700a6dda52..2ac07f2341 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExceptionHandling.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExceptionHandling.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExceptionMessages.java b/src/test/java/com/rabbitmq/client/test/functional/ExceptionMessages.java index 672db4dfa8..a7957afbc9 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExceptionMessages.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExceptionMessages.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java index b6976ee873..12900c448e 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeclare.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java index 299d95567f..dfe6fac6d8 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeleteIfUnused.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeletePredeclared.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeletePredeclared.java index 4229c888ed..86234cf02e 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeletePredeclared.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeDeletePredeclared.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java index cfeed037d4..7966cf2d3f 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeEquivalenceBase.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java index 3416b334d6..ff55b0024a 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindings.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java b/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java index a6f01e20c4..6a3b191cf7 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ExchangeExchangeBindingsAutoDelete.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java b/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java index bafceed32d..4ca81aebc6 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java +++ b/src/test/java/com/rabbitmq/client/test/functional/FrameMax.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/FunctionalTestSuite.java b/src/test/java/com/rabbitmq/client/test/functional/FunctionalTestSuite.java index ec06db3553..650e9f2333 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/FunctionalTestSuite.java +++ b/src/test/java/com/rabbitmq/client/test/functional/FunctionalTestSuite.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java b/src/test/java/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java index 49b0779c8c..c0c1fc0007 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java +++ b/src/test/java/com/rabbitmq/client/test/functional/HeadersExchangeValidation.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java b/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java index 002c60b487..9a327e2ff8 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Heartbeat.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/InternalExchange.java b/src/test/java/com/rabbitmq/client/test/functional/InternalExchange.java index 12bfc7c76d..b9eb3554c9 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/InternalExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/InternalExchange.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/InvalidAcks.java b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcks.java index 08dc083f6f..3041412e9f 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/InvalidAcks.java +++ b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcks.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksBase.java b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksBase.java index f24e848c63..1c8b6aad21 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksBase.java +++ b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksBase.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksTx.java b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksTx.java index 2df62e23ed..e02e8baca3 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksTx.java +++ b/src/test/java/com/rabbitmq/client/test/functional/InvalidAcksTx.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/MessageCount.java b/src/test/java/com/rabbitmq/client/test/functional/MessageCount.java index 8ccef02846..8b0c062d29 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/MessageCount.java +++ b/src/test/java/com/rabbitmq/client/test/functional/MessageCount.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java index 95e47cb9f9..cc6790c0e2 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Metrics.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Metrics.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java b/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java index 36de057b90..c1cd52a2f4 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java +++ b/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java @@ -1,4 +1,4 @@ -// Copyright (c) 2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/Nack.java b/src/test/java/com/rabbitmq/client/test/functional/Nack.java index 6bd47e6067..1ec01c2e91 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Nack.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Nack.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java b/src/test/java/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java index f93f8f591b..7c02a13010 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java +++ b/src/test/java/com/rabbitmq/client/test/functional/NoRequeueOnCancel.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/Nowait.java b/src/test/java/com/rabbitmq/client/test/functional/Nowait.java index b795f02482..ef460f228b 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Nowait.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Nowait.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java b/src/test/java/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java index 51149c613f..83e0191538 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java +++ b/src/test/java/com/rabbitmq/client/test/functional/PerConsumerPrefetch.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/PerMessageTTL.java b/src/test/java/com/rabbitmq/client/test/functional/PerMessageTTL.java index 2b6bb3ed99..0f029a3e72 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/PerMessageTTL.java +++ b/src/test/java/com/rabbitmq/client/test/functional/PerMessageTTL.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/PerQueueTTL.java b/src/test/java/com/rabbitmq/client/test/functional/PerQueueTTL.java index 177a67cd58..a7c273d63f 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/PerQueueTTL.java +++ b/src/test/java/com/rabbitmq/client/test/functional/PerQueueTTL.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java b/src/test/java/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java index e835b42c0f..a2aae0a866 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java +++ b/src/test/java/com/rabbitmq/client/test/functional/PerQueueVsPerMessageTTL.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/Policies.java b/src/test/java/com/rabbitmq/client/test/functional/Policies.java index 602e2b57c4..016bc35320 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Policies.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Policies.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/QosTests.java b/src/test/java/com/rabbitmq/client/test/functional/QosTests.java index b14d5526c3..88a0438ab2 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QosTests.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QosTests.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/QueueExclusivity.java b/src/test/java/com/rabbitmq/client/test/functional/QueueExclusivity.java index 83df293a10..bf0c0a02c4 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QueueExclusivity.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QueueExclusivity.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/QueueLease.java b/src/test/java/com/rabbitmq/client/test/functional/QueueLease.java index 46a31f8b3e..0a17992fdf 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QueueLease.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QueueLease.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java b/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java index ceedb520ad..95646fc1e4 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QueueLifecycle.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/QueueSizeLimit.java b/src/test/java/com/rabbitmq/client/test/functional/QueueSizeLimit.java index c0c9350173..247b441aaf 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/QueueSizeLimit.java +++ b/src/test/java/com/rabbitmq/client/test/functional/QueueSizeLimit.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/Recover.java b/src/test/java/com/rabbitmq/client/test/functional/Recover.java index a83c75c9ca..ec606c28e5 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Recover.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Recover.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/Reject.java b/src/test/java/com/rabbitmq/client/test/functional/Reject.java index b8abaf0779..b680e92583 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Reject.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Reject.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java index 250b74acf0..58f01861d5 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java +++ b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnChannelClose.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/RequeueOnClose.java b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnClose.java index 7fee64f715..76696a0a1c 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/RequeueOnClose.java +++ b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnClose.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java index 126c1bd71a..9cc984e59c 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java +++ b/src/test/java/com/rabbitmq/client/test/functional/RequeueOnConnectionClose.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/Routing.java b/src/test/java/com/rabbitmq/client/test/functional/Routing.java index eb04306b8c..de201bc739 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Routing.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Routing.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/SaslMechanisms.java b/src/test/java/com/rabbitmq/client/test/functional/SaslMechanisms.java index c40718f732..193a53a8cb 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/SaslMechanisms.java +++ b/src/test/java/com/rabbitmq/client/test/functional/SaslMechanisms.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/TTLHandling.java b/src/test/java/com/rabbitmq/client/test/functional/TTLHandling.java index 8d50b7e059..8f08c0bbd8 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/TTLHandling.java +++ b/src/test/java/com/rabbitmq/client/test/functional/TTLHandling.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/Tables.java b/src/test/java/com/rabbitmq/client/test/functional/Tables.java index a1e405c7f8..0360b68690 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Tables.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Tables.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java index 1af68242b4..8edd432a67 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java +++ b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryFiltering.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2018-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java index 91a777ad1b..f27cc03872 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java +++ b/src/test/java/com/rabbitmq/client/test/functional/TopologyRecoveryRetry.java @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2018-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/Transactions.java b/src/test/java/com/rabbitmq/client/test/functional/Transactions.java index 1de0cc56ce..8c2c382439 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Transactions.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Transactions.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java b/src/test/java/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java index 08e0b8fbac..08510bc856 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java +++ b/src/test/java/com/rabbitmq/client/test/functional/UnbindAutoDeleteExchange.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java b/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java index d97d520f0f..d39893273a 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java +++ b/src/test/java/com/rabbitmq/client/test/functional/UnexpectedFrames.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/UserIDHeader.java b/src/test/java/com/rabbitmq/client/test/functional/UserIDHeader.java index 1f0383fbde..35a1a391af 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/UserIDHeader.java +++ b/src/test/java/com/rabbitmq/client/test/functional/UserIDHeader.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java b/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java index e304a71db6..d0296d8552 100644 --- a/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java +++ b/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java b/src/test/java/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java index a978d06a48..e7b8f775a0 100644 --- a/src/test/java/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java +++ b/src/test/java/com/rabbitmq/client/test/server/AlternateExchangeEquivalence.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java b/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java index a80b12387d..cc8be03e08 100644 --- a/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/server/BlockedConnection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/Bug19219Test.java b/src/test/java/com/rabbitmq/client/test/server/Bug19219Test.java index 2506ef075a..3bdb8113d2 100644 --- a/src/test/java/com/rabbitmq/client/test/server/Bug19219Test.java +++ b/src/test/java/com/rabbitmq/client/test/server/Bug19219Test.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java b/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java index a008c5b44d..41dff0f2d4 100644 --- a/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java +++ b/src/test/java/com/rabbitmq/client/test/server/ChannelLimitNegotiation.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java b/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java index f280408fa8..3b754c88e2 100644 --- a/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java +++ b/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java b/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java index 0b5d19d529..7627b50c2f 100644 --- a/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java +++ b/src/test/java/com/rabbitmq/client/test/server/DurableBindingLifecycle.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java b/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java index db5d63ef7a..31e2b898ec 100644 --- a/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java +++ b/src/test/java/com/rabbitmq/client/test/server/EffectVisibilityCrossNodeTest.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java b/src/test/java/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java index 6671be803c..6d0dba8886 100644 --- a/src/test/java/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java +++ b/src/test/java/com/rabbitmq/client/test/server/ExclusiveQueueDurability.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/Firehose.java b/src/test/java/com/rabbitmq/client/test/server/Firehose.java index 63389b5384..062f66b2c7 100644 --- a/src/test/java/com/rabbitmq/client/test/server/Firehose.java +++ b/src/test/java/com/rabbitmq/client/test/server/Firehose.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/HaTestSuite.java b/src/test/java/com/rabbitmq/client/test/server/HaTestSuite.java index 12f88c6612..edd51680ae 100644 --- a/src/test/java/com/rabbitmq/client/test/server/HaTestSuite.java +++ b/src/test/java/com/rabbitmq/client/test/server/HaTestSuite.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/LastHaTestSuite.java b/src/test/java/com/rabbitmq/client/test/server/LastHaTestSuite.java index 12aa495ae0..b42262feb6 100644 --- a/src/test/java/com/rabbitmq/client/test/server/LastHaTestSuite.java +++ b/src/test/java/com/rabbitmq/client/test/server/LastHaTestSuite.java @@ -1,4 +1,4 @@ -// Copyright (c) 2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/LoopbackUsers.java b/src/test/java/com/rabbitmq/client/test/server/LoopbackUsers.java index e758b65c9e..813e4d23f5 100644 --- a/src/test/java/com/rabbitmq/client/test/server/LoopbackUsers.java +++ b/src/test/java/com/rabbitmq/client/test/server/LoopbackUsers.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java b/src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java index d6be4534de..db87bbfb99 100644 --- a/src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java +++ b/src/test/java/com/rabbitmq/client/test/server/MemoryAlarms.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java b/src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java index c17ef018c9..791e7e0082 100644 --- a/src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/Permissions.java b/src/test/java/com/rabbitmq/client/test/server/Permissions.java index 2204f9c9ce..bf3edccaf0 100644 --- a/src/test/java/com/rabbitmq/client/test/server/Permissions.java +++ b/src/test/java/com/rabbitmq/client/test/server/Permissions.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/PersistenceGuarantees.java b/src/test/java/com/rabbitmq/client/test/server/PersistenceGuarantees.java index e0547ca786..126130f54d 100644 --- a/src/test/java/com/rabbitmq/client/test/server/PersistenceGuarantees.java +++ b/src/test/java/com/rabbitmq/client/test/server/PersistenceGuarantees.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/PriorityQueues.java b/src/test/java/com/rabbitmq/client/test/server/PriorityQueues.java index 1fba1684d7..ff6ce04e3a 100644 --- a/src/test/java/com/rabbitmq/client/test/server/PriorityQueues.java +++ b/src/test/java/com/rabbitmq/client/test/server/PriorityQueues.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/ServerTestSuite.java b/src/test/java/com/rabbitmq/client/test/server/ServerTestSuite.java index c850a31faf..64a1499eb0 100644 --- a/src/test/java/com/rabbitmq/client/test/server/ServerTestSuite.java +++ b/src/test/java/com/rabbitmq/client/test/server/ServerTestSuite.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/Shutdown.java b/src/test/java/com/rabbitmq/client/test/server/Shutdown.java index 9e861bdc9e..9d731853a0 100644 --- a/src/test/java/com/rabbitmq/client/test/server/Shutdown.java +++ b/src/test/java/com/rabbitmq/client/test/server/Shutdown.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/TopicPermissions.java b/src/test/java/com/rabbitmq/client/test/server/TopicPermissions.java index d48f6ea952..0af9ae9aca 100644 --- a/src/test/java/com/rabbitmq/client/test/server/TopicPermissions.java +++ b/src/test/java/com/rabbitmq/client/test/server/TopicPermissions.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java b/src/test/java/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java index d0898f0210..9d23040fe9 100644 --- a/src/test/java/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java +++ b/src/test/java/com/rabbitmq/client/test/server/XDeathHeaderGrowth.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java index 748bb9f883..ca71ea4c0f 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/BadVerifiedConnection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java b/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java index 1a03a02420..a09f1debdd 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/ConnectionFactoryDefaultTlsVersion.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java index f8febe4614..efdfcb57d6 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java index 768795fe65..a5ef9372bf 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/NioTlsUnverifiedConnection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ssl/SslTestSuite.java b/src/test/java/com/rabbitmq/client/test/ssl/SslTestSuite.java index 05160db0f9..868b1e26bb 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/SslTestSuite.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/SslTestSuite.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java b/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java index 1558eeda71..0369927d4b 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/TlsConnectionLogging.java @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2019-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ssl/TlsTestUtils.java b/src/test/java/com/rabbitmq/client/test/ssl/TlsTestUtils.java index 51702c4a6e..65815d4222 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/TlsTestUtils.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/TlsTestUtils.java @@ -1,4 +1,4 @@ -// Copyright (c) 2021 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java index 5a0af90463..3cf2a15b79 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/UnverifiedConnection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java b/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java index 32ac3a2ca9..24f9482dc8 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/VerifiedConnection.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/tools/Host.java b/src/test/java/com/rabbitmq/tools/Host.java index 8e950cb27e..96cf6b0dac 100644 --- a/src/test/java/com/rabbitmq/tools/Host.java +++ b/src/test/java/com/rabbitmq/tools/Host.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/utility/IntAllocatorTests.java b/src/test/java/com/rabbitmq/utility/IntAllocatorTests.java index 5e468a60e3..fb8800ecd3 100644 --- a/src/test/java/com/rabbitmq/utility/IntAllocatorTests.java +++ b/src/test/java/com/rabbitmq/utility/IntAllocatorTests.java @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 VMware, Inc. or its affiliates. All rights reserved. +// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 From 8e9197e1b74a7ccc6f72f6edbf2c8290b2126541 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Thu, 23 Nov 2023 09:13:26 +0100 Subject: [PATCH 1829/2114] Copyright update --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index eb90cd20fc..33bbc8f7c3 100644 --- a/pom.xml +++ b/pom.xml @@ -33,7 +33,7 @@ info@rabbitmq.com Team RabbitMQ - Broadcom Inc. and/or its subsidiaries + Broadcom Inc. and its subsidiaries https://rabbitmq.com @@ -46,7 +46,7 @@ - Broadcom Inc. and/or its subsidiaries + Broadcom Inc. and its subsidiaries https://www.rabbitmq.com From 00ef564ed9bff4652b8b4c266591fd25a2746699 Mon Sep 17 00:00:00 2001 From: Johannes Hahn Date: Sat, 25 Nov 2023 13:55:38 +0100 Subject: [PATCH 1830/2114] cleanup ReturnListener in close() --- src/main/java/com/rabbitmq/client/RpcClient.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/RpcClient.java b/src/main/java/com/rabbitmq/client/RpcClient.java index f47d185b89..eb49764e32 100644 --- a/src/main/java/com/rabbitmq/client/RpcClient.java +++ b/src/main/java/com/rabbitmq/client/RpcClient.java @@ -93,6 +93,7 @@ public class RpcClient implements AutoCloseable { * @since 5.9.0 */ private final Supplier _correlationIdSupplier; + private final ReturnListener _returnListener; private String lastCorrelationId = "0"; @@ -123,7 +124,7 @@ public RpcClient(RpcClientParams params) throws _consumer = setupConsumer(); if (_useMandatory) { - this._channel.addReturnListener(returnMessage -> { + this._returnListener = this._channel.addReturnListener(returnMessage -> { synchronized (_continuationMap) { String replyId = returnMessage.getProperties().getCorrelationId(); BlockingCell blocker = _continuationMap.remove(replyId); @@ -136,6 +137,8 @@ public RpcClient(RpcClientParams params) throws } } }); + } else { + this._returnListener = null; } } @@ -157,6 +160,7 @@ private void checkNotClosed() throws IOException { public void close() throws IOException { if (this.closed.compareAndSet(false, true)) { _channel.basicCancel(_consumer.getConsumerTag()); + _channel.removeReturnListener(this._returnListener); } } From d838b44c6dce1cecaaded3dd67170ddc3f1e0d85 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Sat, 25 Nov 2023 09:05:05 -0500 Subject: [PATCH 1831/2114] Don't assume that return listener was set --- src/main/java/com/rabbitmq/client/RpcClient.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/RpcClient.java b/src/main/java/com/rabbitmq/client/RpcClient.java index eb49764e32..8f12664050 100644 --- a/src/main/java/com/rabbitmq/client/RpcClient.java +++ b/src/main/java/com/rabbitmq/client/RpcClient.java @@ -160,7 +160,9 @@ private void checkNotClosed() throws IOException { public void close() throws IOException { if (this.closed.compareAndSet(false, true)) { _channel.basicCancel(_consumer.getConsumerTag()); - _channel.removeReturnListener(this._returnListener); + if (this._returnListener != null) { + _channel.removeReturnListener(this._returnListener); + } } } From 7c032eeea0f582d6a7fa444dc3a0465f8bf3eb72 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Nov 2023 00:37:05 +0000 Subject: [PATCH 1832/2114] Bump org.codehaus.mojo:build-helper-maven-plugin from 3.4.0 to 3.5.0 Bumps [org.codehaus.mojo:build-helper-maven-plugin](https://github.com/mojohaus/build-helper-maven-plugin) from 3.4.0 to 3.5.0. - [Release notes](https://github.com/mojohaus/build-helper-maven-plugin/releases) - [Commits](https://github.com/mojohaus/build-helper-maven-plugin/compare/3.4.0...3.5.0) --- updated-dependencies: - dependency-name: org.codehaus.mojo:build-helper-maven-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 33bbc8f7c3..9a1f1eabea 100644 --- a/pom.xml +++ b/pom.xml @@ -80,7 +80,7 @@ 2.1.1 2.4.21 1.7 - 3.4.0 + 3.5.0 3.11.0 3.2.2 3.2.2 From 96906eccc8ab256675ebbc271c17ab70a047652e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Nov 2023 00:14:57 +0000 Subject: [PATCH 1833/2114] Bump com.diffplug.spotless:spotless-maven-plugin from 2.40.0 to 2.41.0 Bumps [com.diffplug.spotless:spotless-maven-plugin](https://github.com/diffplug/spotless) from 2.40.0 to 2.41.0. - [Changelog](https://github.com/diffplug/spotless/blob/main/CHANGES.md) - [Commits](https://github.com/diffplug/spotless/compare/lib/2.40.0...lib/2.41.0) --- updated-dependencies: - dependency-name: com.diffplug.spotless:spotless-maven-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9a1f1eabea..7f5b665de3 100644 --- a/pom.xml +++ b/pom.xml @@ -91,7 +91,7 @@ 1.6.13 1.11 1.4 - 2.40.0 + 2.41.0 1.17.0 - // Copyright (c) $YEAR Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + // Copyright (c) $YEAR Broadcom. All Rights Reserved. + // The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/observation/NoOpObservationCollector.java b/src/main/java/com/rabbitmq/client/observation/NoOpObservationCollector.java index 7b37cd32a0..ae1cd7a4e0 100644 --- a/src/main/java/com/rabbitmq/client/observation/NoOpObservationCollector.java +++ b/src/main/java/com/rabbitmq/client/observation/NoOpObservationCollector.java @@ -1,4 +1,5 @@ -// Copyright (c) 2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. +// Copyright (c) 2023 Broadcom. All Rights Reserved. +// The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/observation/ObservationCollector.java b/src/main/java/com/rabbitmq/client/observation/ObservationCollector.java index 04c452f8fe..700d685064 100644 --- a/src/main/java/com/rabbitmq/client/observation/ObservationCollector.java +++ b/src/main/java/com/rabbitmq/client/observation/ObservationCollector.java @@ -1,4 +1,5 @@ -// Copyright (c) 2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. +// Copyright (c) 2023 Broadcom. All Rights Reserved. +// The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultDeliverObservationConvention.java b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultDeliverObservationConvention.java index d32f9be01c..4ff4f62774 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultDeliverObservationConvention.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultDeliverObservationConvention.java @@ -1,4 +1,5 @@ -// Copyright (c) 2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. +// Copyright (c) 2023 Broadcom. All Rights Reserved. +// The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultProcessObservationConvention.java b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultProcessObservationConvention.java index 45201f9ea4..66aa613832 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultProcessObservationConvention.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultProcessObservationConvention.java @@ -1,4 +1,5 @@ -// Copyright (c) 2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. +// Copyright (c) 2023 Broadcom. All Rights Reserved. +// The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultPublishObservationConvention.java b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultPublishObservationConvention.java index 199b3df1e0..8bb7e9b580 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultPublishObservationConvention.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultPublishObservationConvention.java @@ -1,4 +1,5 @@ -// Copyright (c) 2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. +// Copyright (c) 2023 Broadcom. All Rights Reserved. +// The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultReceiveObservationConvention.java b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultReceiveObservationConvention.java index e1928b8ee5..751f3c6e02 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultReceiveObservationConvention.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/DefaultReceiveObservationConvention.java @@ -1,4 +1,5 @@ -// Copyright (c) 2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. +// Copyright (c) 2023 Broadcom. All Rights Reserved. +// The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/DeliverContext.java b/src/main/java/com/rabbitmq/client/observation/micrometer/DeliverContext.java index e838d302e5..6e43eb6ebb 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/DeliverContext.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/DeliverContext.java @@ -1,4 +1,5 @@ -// Copyright (c) 2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. +// Copyright (c) 2023 Broadcom. All Rights Reserved. +// The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/DeliverObservationConvention.java b/src/main/java/com/rabbitmq/client/observation/micrometer/DeliverObservationConvention.java index d57f035fd5..422dafe546 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/DeliverObservationConvention.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/DeliverObservationConvention.java @@ -1,4 +1,5 @@ -// Copyright (c) 2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. +// Copyright (c) 2023 Broadcom. All Rights Reserved. +// The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java b/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java index 74a2071dc7..44e2fc4522 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollector.java @@ -1,4 +1,5 @@ -// Copyright (c) 2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. +// Copyright (c) 2023 Broadcom. All Rights Reserved. +// The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollectorBuilder.java b/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollectorBuilder.java index 9e775d108f..1cc26ceb53 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollectorBuilder.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/MicrometerObservationCollectorBuilder.java @@ -1,4 +1,5 @@ -// Copyright (c) 2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. +// Copyright (c) 2023 Broadcom. All Rights Reserved. +// The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/PublishContext.java b/src/main/java/com/rabbitmq/client/observation/micrometer/PublishContext.java index 146e8ee058..01362f7310 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/PublishContext.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/PublishContext.java @@ -1,4 +1,5 @@ -// Copyright (c) 2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. +// Copyright (c) 2023 Broadcom. All Rights Reserved. +// The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/PublishObservationConvention.java b/src/main/java/com/rabbitmq/client/observation/micrometer/PublishObservationConvention.java index 8f8fc60e89..ee81671c6c 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/PublishObservationConvention.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/PublishObservationConvention.java @@ -1,4 +1,5 @@ -// Copyright (c) 2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. +// Copyright (c) 2023 Broadcom. All Rights Reserved. +// The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/main/java/com/rabbitmq/client/observation/micrometer/RabbitMqObservationDocumentation.java b/src/main/java/com/rabbitmq/client/observation/micrometer/RabbitMqObservationDocumentation.java index d88d7033c6..9612a41d62 100644 --- a/src/main/java/com/rabbitmq/client/observation/micrometer/RabbitMqObservationDocumentation.java +++ b/src/main/java/com/rabbitmq/client/observation/micrometer/RabbitMqObservationDocumentation.java @@ -1,4 +1,5 @@ -// Copyright (c) 2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. +// Copyright (c) 2023 Broadcom. All Rights Reserved. +// The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 diff --git a/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java b/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java index c1cd52a2f4..5a6020b779 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java +++ b/src/test/java/com/rabbitmq/client/test/functional/MicrometerObservationCollectorMetrics.java @@ -1,4 +1,5 @@ -// Copyright (c) 2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. +// Copyright (c) 2023 Broadcom. All Rights Reserved. +// The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 From 1de584126e26f2be4dc54b5b0187c78ae4d66f89 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 25 Jan 2024 00:18:59 +0000 Subject: [PATCH 1870/2114] Bump io.dropwizard.metrics:metrics-core from 4.2.24 to 4.2.25 Bumps [io.dropwizard.metrics:metrics-core](https://github.com/dropwizard/metrics) from 4.2.24 to 4.2.25. - [Release notes](https://github.com/dropwizard/metrics/releases) - [Commits](https://github.com/dropwizard/metrics/compare/v4.2.24...v4.2.25) --- updated-dependencies: - dependency-name: io.dropwizard.metrics:metrics-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5463de9f4a..6c7abfd104 100644 --- a/pom.xml +++ b/pom.xml @@ -56,7 +56,7 @@ true 1.7.36 - 4.2.24 + 4.2.25 1.12.2 1.1.4 1.34.1 From d9bb38597b1c1fc4960869234b860fb93c58ea69 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 25 Jan 2024 00:19:23 +0000 Subject: [PATCH 1871/2114] Bump org.mockito:mockito-core from 5.9.0 to 5.10.0 Bumps [org.mockito:mockito-core](https://github.com/mockito/mockito) from 5.9.0 to 5.10.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.9.0...v5.10.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5463de9f4a..91ec7af20b 100644 --- a/pom.xml +++ b/pom.xml @@ -63,7 +63,7 @@ 2.16.1 1.2.13 5.10.1 - 5.9.0 + 5.10.0 3.25.1 1.2.2 1.0.2 From c32c5d252f40fa330122bfa838d9d45492ff2ce3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 25 Jan 2024 00:40:45 +0000 Subject: [PATCH 1872/2114] Bump org.assertj:assertj-core from 3.25.1 to 3.25.2 Bumps [org.assertj:assertj-core](https://github.com/assertj/assertj) from 3.25.1 to 3.25.2. - [Release notes](https://github.com/assertj/assertj/releases) - [Commits](https://github.com/assertj/assertj/compare/assertj-build-3.25.1...assertj-build-3.25.2) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5cd94e912a..3c1a3df0df 100644 --- a/pom.xml +++ b/pom.xml @@ -64,7 +64,7 @@ 1.2.13 5.10.1 5.10.0 - 3.25.1 + 3.25.2 1.2.2 1.0.2 9.4.53.v20231009 From 5bc76e441a8a64e3a4874433ba8cd21d7953ad61 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 Feb 2024 00:44:30 +0000 Subject: [PATCH 1873/2114] Bump org.junit:junit-bom from 5.10.1 to 5.10.2 Bumps [org.junit:junit-bom](https://github.com/junit-team/junit5) from 5.10.1 to 5.10.2. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.10.1...r5.10.2) --- updated-dependencies: - dependency-name: org.junit:junit-bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3c1a3df0df..2c6e844f5c 100644 --- a/pom.xml +++ b/pom.xml @@ -62,7 +62,7 @@ 1.34.1 2.16.1 1.2.13 - 5.10.1 + 5.10.2 5.10.0 3.25.2 1.2.2 From 2b61727b020fa5e74ebab38ce7e6779307e547fd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 Feb 2024 00:44:37 +0000 Subject: [PATCH 1874/2114] Bump org.assertj:assertj-core from 3.25.2 to 3.25.3 Bumps [org.assertj:assertj-core](https://github.com/assertj/assertj) from 3.25.2 to 3.25.3. - [Release notes](https://github.com/assertj/assertj/releases) - [Commits](https://github.com/assertj/assertj/compare/assertj-build-3.25.2...assertj-build-3.25.3) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3c1a3df0df..6545ed02c3 100644 --- a/pom.xml +++ b/pom.xml @@ -64,7 +64,7 @@ 1.2.13 5.10.1 5.10.0 - 3.25.2 + 3.25.3 1.2.2 1.0.2 9.4.53.v20231009 From b029fcdaf10f17546a15351881719b71f0dcdeed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 5 Feb 2024 14:18:21 +0100 Subject: [PATCH 1875/2114] Bump Bouncy Castle (test) --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index ff6ff1b445..36b4388779 100644 --- a/pom.xml +++ b/pom.xml @@ -68,7 +68,7 @@ 1.2.2 1.0.2 9.4.53.v20231009 - 1.70 + 1.77 0.10 2.10.1 @@ -778,7 +778,7 @@ org.bouncycastle - bcpkix-jdk15on + bcpkix-jdk18on ${bouncycastle.version} test From 75d6d8e4e9202b4a41943b2e010bc0c2d1bc49e5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Feb 2024 01:10:17 +0000 Subject: [PATCH 1876/2114] Bump opentelemetry.version from 1.34.1 to 1.35.0 Bumps `opentelemetry.version` from 1.34.1 to 1.35.0. Updates `io.opentelemetry:opentelemetry-api` from 1.34.1 to 1.35.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-java/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-java/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-java/compare/v1.34.1...v1.35.0) Updates `io.opentelemetry:opentelemetry-sdk-testing` from 1.34.1 to 1.35.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-java/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-java/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-java/compare/v1.34.1...v1.35.0) --- updated-dependencies: - dependency-name: io.opentelemetry:opentelemetry-api dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: io.opentelemetry:opentelemetry-sdk-testing dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 36b4388779..b0ca2ebfcd 100644 --- a/pom.xml +++ b/pom.xml @@ -59,7 +59,7 @@ 4.2.25 1.12.2 1.1.4 - 1.34.1 + 1.35.0 2.16.1 1.2.13 5.10.2 From b1de2432e0fadbaa4d2084b42873e376cf132c18 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Feb 2024 00:45:36 +0000 Subject: [PATCH 1877/2114] Bump io.micrometer:micrometer-core from 1.12.2 to 1.12.3 Bumps [io.micrometer:micrometer-core](https://github.com/micrometer-metrics/micrometer) from 1.12.2 to 1.12.3. - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.12.2...v1.12.3) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b0ca2ebfcd..aa37bdb0fe 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,7 @@ true 1.7.36 4.2.25 - 1.12.2 + 1.12.3 1.1.4 1.35.0 2.16.1 From 3020fef201d20c0f8eed179f04771ac355b90eb3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Feb 2024 00:45:45 +0000 Subject: [PATCH 1878/2114] Bump io.micrometer:micrometer-tracing-integration-test Bumps [io.micrometer:micrometer-tracing-integration-test](https://github.com/micrometer-metrics/tracing) from 1.2.2 to 1.2.3. - [Release notes](https://github.com/micrometer-metrics/tracing/releases) - [Commits](https://github.com/micrometer-metrics/tracing/compare/v1.2.2...v1.2.3) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-tracing-integration-test dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b0ca2ebfcd..7fce1e009c 100644 --- a/pom.xml +++ b/pom.xml @@ -65,7 +65,7 @@ 5.10.2 5.10.0 3.25.3 - 1.2.2 + 1.2.3 1.0.2 9.4.53.v20231009 1.77 From 37d3e8c80010c6ff83560972c29eb662544a249d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 14 Feb 2024 00:07:40 +0000 Subject: [PATCH 1879/2114] Bump org.eclipse.jetty:jetty-servlet Bumps org.eclipse.jetty:jetty-servlet from 9.4.53.v20231009 to 9.4.54.v20240208. --- updated-dependencies: - dependency-name: org.eclipse.jetty:jetty-servlet dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e94556f43a..e841369f91 100644 --- a/pom.xml +++ b/pom.xml @@ -67,7 +67,7 @@ 3.25.3 1.2.3 1.0.2 - 9.4.53.v20231009 + 9.4.54.v20240208 1.77 0.10 2.10.1 From ba8479f985cf7d36e18043ca15f0de5c4ebc7513 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 26 Feb 2024 10:16:23 +0100 Subject: [PATCH 1880/2114] Use RabbitMQ 3.13 in test suite --- .github/workflows/test-rabbitmq-alphas.yml | 2 +- ci/start-broker.sh | 2 +- ci/start-cluster.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-rabbitmq-alphas.yml b/.github/workflows/test-rabbitmq-alphas.yml index 69a71513a3..ab3351aaff 100644 --- a/.github/workflows/test-rabbitmq-alphas.yml +++ b/.github/workflows/test-rabbitmq-alphas.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-22.04 strategy: matrix: - rabbitmq-image: [ 'pivotalrabbitmq/rabbitmq:v3.12.x-otp-max-bazel', 'pivotalrabbitmq/rabbitmq:main-otp-max-bazel' ] + rabbitmq-image: [ 'pivotalrabbitmq/rabbitmq:v3.13.x-otp-max-bazel', 'pivotalrabbitmq/rabbitmq:main-otp-max-bazel' ] name: Test against ${{ matrix.rabbitmq-image }} steps: - uses: actions/checkout@v4 diff --git a/ci/start-broker.sh b/ci/start-broker.sh index f3060b49c9..746bcc56c9 100755 --- a/ci/start-broker.sh +++ b/ci/start-broker.sh @@ -2,7 +2,7 @@ LOCAL_SCRIPT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -RABBITMQ_IMAGE=${RABBITMQ_IMAGE:-rabbitmq:3.12} +RABBITMQ_IMAGE=${RABBITMQ_IMAGE:-rabbitmq:3.13} wait_for_message() { while ! docker logs "$1" | grep -q "$2"; diff --git a/ci/start-cluster.sh b/ci/start-cluster.sh index c50b70ef64..5209a1da67 100755 --- a/ci/start-cluster.sh +++ b/ci/start-cluster.sh @@ -2,7 +2,7 @@ LOCAL_SCRIPT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -RABBITMQ_IMAGE=${RABBITMQ_IMAGE:-rabbitmq:3.12} +RABBITMQ_IMAGE=${RABBITMQ_IMAGE:-rabbitmq:3.13} wait_for_message() { while ! docker logs "$1" | grep -q "$2"; From e8b84c710c9284bb685af62ed577c707c2741856 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 26 Feb 2024 10:22:58 +0100 Subject: [PATCH 1881/2114] Fix workflow name --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0fe3bf2d2b..56fd36503c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,4 +1,4 @@ -name: Test against RabbitMQ 3.12 stable +name: Test against RabbitMQ 3.13 stable on: pull_request: From 20e22b2c1fc30ebe4e9d68188e1cd8d6e4f87262 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Mar 2024 00:04:11 +0000 Subject: [PATCH 1882/2114] Bump org.mockito:mockito-core from 5.10.0 to 5.11.0 Bumps [org.mockito:mockito-core](https://github.com/mockito/mockito) from 5.10.0 to 5.11.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.10.0...v5.11.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e841369f91..b1a29f38d1 100644 --- a/pom.xml +++ b/pom.xml @@ -63,7 +63,7 @@ 2.16.1 1.2.13 5.10.2 - 5.10.0 + 5.11.0 3.25.3 1.2.3 1.0.2 From bd9ba04e435ee6196e971060cb9491f6c900d0f2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Mar 2024 01:05:09 +0000 Subject: [PATCH 1883/2114] Bump com.fasterxml.jackson.core:jackson-databind from 2.16.1 to 2.16.2 Bumps [com.fasterxml.jackson.core:jackson-databind](https://github.com/FasterXML/jackson) from 2.16.1 to 2.16.2. - [Commits](https://github.com/FasterXML/jackson/commits) --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-databind dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b1a29f38d1..591674f931 100644 --- a/pom.xml +++ b/pom.xml @@ -60,7 +60,7 @@ 1.12.3 1.1.4 1.35.0 - 2.16.1 + 2.16.2 1.2.13 5.10.2 5.11.0 From ceca13d6e2413a59200f2a66c60388012be3c386 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Mar 2024 07:42:53 +0000 Subject: [PATCH 1884/2114] Bump opentelemetry.version from 1.35.0 to 1.36.0 Bumps `opentelemetry.version` from 1.35.0 to 1.36.0. Updates `io.opentelemetry:opentelemetry-api` from 1.35.0 to 1.36.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-java/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-java/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-java/compare/v1.35.0...v1.36.0) Updates `io.opentelemetry:opentelemetry-sdk-testing` from 1.35.0 to 1.36.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-java/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-java/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-java/compare/v1.35.0...v1.36.0) --- updated-dependencies: - dependency-name: io.opentelemetry:opentelemetry-api dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: io.opentelemetry:opentelemetry-sdk-testing dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 591674f931..f7cbeab1fc 100644 --- a/pom.xml +++ b/pom.xml @@ -59,7 +59,7 @@ 4.2.25 1.12.3 1.1.4 - 1.35.0 + 1.36.0 2.16.2 1.2.13 5.10.2 From 12fef723524e4a4b3ca08993cb0bb361e2c7504f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Mar 2024 00:11:31 +0000 Subject: [PATCH 1885/2114] Bump org.apache.maven.plugins:maven-gpg-plugin from 3.1.0 to 3.2.0 Bumps [org.apache.maven.plugins:maven-gpg-plugin](https://github.com/apache/maven-gpg-plugin) from 3.1.0 to 3.2.0. - [Release notes](https://github.com/apache/maven-gpg-plugin/releases) - [Commits](https://github.com/apache/maven-gpg-plugin/compare/maven-gpg-plugin-3.1.0...maven-gpg-plugin-3.2.0) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-gpg-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f7cbeab1fc..29217ce660 100644 --- a/pom.xml +++ b/pom.xml @@ -84,7 +84,7 @@ 3.12.1 3.2.5 3.2.5 - 3.1.0 + 3.2.0 3.3.0 5.1.9 0.0.6 From 0bc2ddccf5c932bd3879764ee2878d6e9d37b9ef Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Mar 2024 00:11:51 +0000 Subject: [PATCH 1886/2114] Bump io.micrometer:micrometer-core from 1.12.3 to 1.12.4 Bumps [io.micrometer:micrometer-core](https://github.com/micrometer-metrics/micrometer) from 1.12.3 to 1.12.4. - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.12.3...v1.12.4) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f7cbeab1fc..0701c4c79c 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,7 @@ true 1.7.36 4.2.25 - 1.12.3 + 1.12.4 1.1.4 1.36.0 2.16.2 From ea63c8df544152a141ffc740ddf2e0d9f158f6d4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 Mar 2024 00:06:25 +0000 Subject: [PATCH 1887/2114] Bump com.fasterxml.jackson.core:jackson-databind from 2.16.2 to 2.17.0 Bumps [com.fasterxml.jackson.core:jackson-databind](https://github.com/FasterXML/jackson) from 2.16.2 to 2.17.0. - [Commits](https://github.com/FasterXML/jackson/commits) --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-databind dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 64319d8da9..ebe970b9d3 100644 --- a/pom.xml +++ b/pom.xml @@ -60,7 +60,7 @@ 1.12.4 1.1.4 1.36.0 - 2.16.2 + 2.17.0 1.2.13 5.10.2 5.11.0 From c26bee43aaca09afc77cf870d312422a3b4655ba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 Mar 2024 00:06:41 +0000 Subject: [PATCH 1888/2114] Bump io.micrometer:micrometer-tracing-integration-test Bumps [io.micrometer:micrometer-tracing-integration-test](https://github.com/micrometer-metrics/tracing) from 1.2.3 to 1.2.4. - [Release notes](https://github.com/micrometer-metrics/tracing/releases) - [Commits](https://github.com/micrometer-metrics/tracing/compare/v1.2.3...v1.2.4) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-tracing-integration-test dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 64319d8da9..622f6ada4e 100644 --- a/pom.xml +++ b/pom.xml @@ -65,7 +65,7 @@ 5.10.2 5.11.0 3.25.3 - 1.2.3 + 1.2.4 1.0.2 9.4.54.v20240208 1.77 From 511d58936c4f5a227b7024005ab713bfa51a1e99 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 14 Mar 2024 01:02:23 +0000 Subject: [PATCH 1889/2114] Bump org.sonarsource.scanner.maven:sonar-maven-plugin Bumps [org.sonarsource.scanner.maven:sonar-maven-plugin](https://github.com/SonarSource/sonar-scanner-maven) from 3.10.0.2594 to 3.11.0.3922. - [Release notes](https://github.com/SonarSource/sonar-scanner-maven/releases) - [Commits](https://github.com/SonarSource/sonar-scanner-maven/compare/3.10.0.2594...3.11.0.3922) --- updated-dependencies: - dependency-name: org.sonarsource.scanner.maven:sonar-maven-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index da73ad5573..ae037783a0 100644 --- a/pom.xml +++ b/pom.xml @@ -835,7 +835,7 @@ org.sonarsource.scanner.maven sonar-maven-plugin - 3.10.0.2594 + 3.11.0.3922 From e43a2c2d2665fb338bec50cece2ffaaa48649df0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Mar 2024 00:57:37 +0000 Subject: [PATCH 1890/2114] Bump org.apache.maven.plugins:maven-compiler-plugin Bumps [org.apache.maven.plugins:maven-compiler-plugin](https://github.com/apache/maven-compiler-plugin) from 3.12.1 to 3.13.0. - [Release notes](https://github.com/apache/maven-compiler-plugin/releases) - [Commits](https://github.com/apache/maven-compiler-plugin/compare/maven-compiler-plugin-3.12.1...maven-compiler-plugin-3.13.0) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-compiler-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ae037783a0..945510a986 100644 --- a/pom.xml +++ b/pom.xml @@ -81,7 +81,7 @@ 2.4.21 1.7 3.5.0 - 3.12.1 + 3.13.0 3.2.5 3.2.5 3.2.0 From 70a368f75df55567c2eed3ed741a44efc78315cc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Mar 2024 00:57:44 +0000 Subject: [PATCH 1891/2114] Bump org.apache.maven.plugins:maven-gpg-plugin from 3.2.0 to 3.2.1 Bumps [org.apache.maven.plugins:maven-gpg-plugin](https://github.com/apache/maven-gpg-plugin) from 3.2.0 to 3.2.1. - [Release notes](https://github.com/apache/maven-gpg-plugin/releases) - [Commits](https://github.com/apache/maven-gpg-plugin/compare/maven-gpg-plugin-3.2.0...maven-gpg-plugin-3.2.1) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-gpg-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ae037783a0..61056f53e0 100644 --- a/pom.xml +++ b/pom.xml @@ -84,7 +84,7 @@ 3.12.1 3.2.5 3.2.5 - 3.2.0 + 3.2.1 3.3.0 5.1.9 0.0.6 From 7571a8f12d9a430b8f3a931702a3c76e143db091 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 22 Mar 2024 09:22:47 +0100 Subject: [PATCH 1892/2114] Test against Java 22 --- .github/workflows/test-supported-java-versions-5.x.yml | 2 +- .github/workflows/test-supported-java-versions-main.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-supported-java-versions-5.x.yml b/.github/workflows/test-supported-java-versions-5.x.yml index 2e44947c94..967adb1361 100644 --- a/.github/workflows/test-supported-java-versions-5.x.yml +++ b/.github/workflows/test-supported-java-versions-5.x.yml @@ -11,7 +11,7 @@ jobs: strategy: matrix: distribution: [ 'temurin' ] - version: [ '8', '11', '17', '21', '22-ea' ] + version: [ '8', '11', '17', '21', '22' ] include: - distribution: 'semeru' version: '17' diff --git a/.github/workflows/test-supported-java-versions-main.yml b/.github/workflows/test-supported-java-versions-main.yml index ae6bf9367d..f9d7dcb068 100644 --- a/.github/workflows/test-supported-java-versions-main.yml +++ b/.github/workflows/test-supported-java-versions-main.yml @@ -11,7 +11,7 @@ jobs: strategy: matrix: distribution: [ 'temurin' ] - version: [ '8', '11', '17', '21', '22-ea' ] + version: [ '8', '11', '17', '21', '22' ] include: - distribution: 'semeru' version: '17' From b559730ac825d12c4307955e3f267c2503f877aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 22 Mar 2024 09:31:43 +0100 Subject: [PATCH 1893/2114] Update link to support timeline page --- README.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.adoc b/README.adoc index 8e638f9933..749ab55d75 100644 --- a/README.adoc +++ b/README.adoc @@ -244,7 +244,7 @@ This library uses https://semver.org/[semantic versioning]. == Support -See the https://www.rabbitmq.com/java-versions.html[RabbitMQ Java libraries support page] +See the https://www.rabbitmq.com/client-libraries/java-versions[RabbitMQ Java libraries support page] for the support timeline of this library. == License From ccc512e93a5c2e67325242def4ff1271489af2e8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 27 Mar 2024 00:17:56 +0000 Subject: [PATCH 1894/2114] Bump org.apache.maven.plugins:maven-gpg-plugin from 3.2.1 to 3.2.2 Bumps [org.apache.maven.plugins:maven-gpg-plugin](https://github.com/apache/maven-gpg-plugin) from 3.2.1 to 3.2.2. - [Release notes](https://github.com/apache/maven-gpg-plugin/releases) - [Commits](https://github.com/apache/maven-gpg-plugin/compare/maven-gpg-plugin-3.2.1...maven-gpg-plugin-3.2.2) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-gpg-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index afa89c4998..fd2d0f14b3 100644 --- a/pom.xml +++ b/pom.xml @@ -84,7 +84,7 @@ 3.13.0 3.2.5 3.2.5 - 3.2.1 + 3.2.2 3.3.0 5.1.9 0.0.6 From 0571ceb8a48e0d235f59436493d3b522828306d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 3 Apr 2024 09:17:32 +0200 Subject: [PATCH 1895/2114] Test against Java 23 ea --- .github/workflows/test-supported-java-versions-5.x.yml | 2 +- .github/workflows/test-supported-java-versions-main.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-supported-java-versions-5.x.yml b/.github/workflows/test-supported-java-versions-5.x.yml index 967adb1361..8935435005 100644 --- a/.github/workflows/test-supported-java-versions-5.x.yml +++ b/.github/workflows/test-supported-java-versions-5.x.yml @@ -11,7 +11,7 @@ jobs: strategy: matrix: distribution: [ 'temurin' ] - version: [ '8', '11', '17', '21', '22' ] + version: [ '8', '11', '17', '21', '22', '23-ea' ] include: - distribution: 'semeru' version: '17' diff --git a/.github/workflows/test-supported-java-versions-main.yml b/.github/workflows/test-supported-java-versions-main.yml index f9d7dcb068..1a901b85f7 100644 --- a/.github/workflows/test-supported-java-versions-main.yml +++ b/.github/workflows/test-supported-java-versions-main.yml @@ -11,7 +11,7 @@ jobs: strategy: matrix: distribution: [ 'temurin' ] - version: [ '8', '11', '17', '21', '22' ] + version: [ '8', '11', '17', '21', '22', '23-ea' ] include: - distribution: 'semeru' version: '17' From 7382a33b1eb115a730e10485e7c294a531bbe78c Mon Sep 17 00:00:00 2001 From: Bruno Leite Date: Wed, 3 Apr 2024 19:09:20 +0100 Subject: [PATCH 1896/2114] Fix unwrapping loop in case bytebuffer has exactly 1 handshake message In the scenario where the reading ByteBuffer only has enough bytes to unwrap one handshake message, the flow may enter a loop due to the call to ByteBuffer.clear(). That method does not actually erase any data, instead it sets the position back to 0, the limit to the capacity, and the mark is discarded. Since we are doing another unwrap attempt using the same reading ByteBuffer, the same handshake message will be read. Updating the reading ByteBuffer position instead of trying to clear it will result in a BUFFER_UNDERFLOW, which will then trigger another read from the channel (as expected). --- .../com/rabbitmq/client/impl/nio/SslEngineHelper.java | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java index d9a5b17105..442359c78b 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/SslEngineHelper.java @@ -110,6 +110,7 @@ private static SSLEngineResult.HandshakeStatus unwrap(ByteBuffer cipherIn, ByteB SSLEngineResult unwrapResult; do { int positionBeforeUnwrapping = cipherIn.position(); + LOGGER.debug("Before unwrapping cipherIn is {}, with {} remaining byte(s)", cipherIn, cipherIn.remaining()); unwrapResult = sslEngine.unwrap(cipherIn, plainIn); LOGGER.debug("SSL engine result is {} after unwrapping", unwrapResult); status = unwrapResult.getStatus(); @@ -118,14 +119,7 @@ private static SSLEngineResult.HandshakeStatus unwrap(ByteBuffer cipherIn, ByteB plainIn.clear(); if (unwrapResult.getHandshakeStatus() == NEED_TASK) { handshakeStatus = runDelegatedTasks(sslEngine); - int newPosition = positionBeforeUnwrapping + unwrapResult.bytesConsumed(); - if (newPosition == cipherIn.limit()) { - LOGGER.debug("Clearing cipherIn because all bytes have been read and unwrapped"); - cipherIn.clear(); - } else { - LOGGER.debug("Setting cipherIn position to {} (limit is {})", newPosition, cipherIn.limit()); - cipherIn.position(positionBeforeUnwrapping + unwrapResult.bytesConsumed()); - } + cipherIn.position(positionBeforeUnwrapping + unwrapResult.bytesConsumed()); } else { handshakeStatus = unwrapResult.getHandshakeStatus(); } From 7c1ceab9d11ac6899cffd1d6b476c2939af9f9bb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 Apr 2024 00:20:35 +0000 Subject: [PATCH 1897/2114] Bump org.apache.maven.plugins:maven-source-plugin from 3.3.0 to 3.3.1 Bumps [org.apache.maven.plugins:maven-source-plugin](https://github.com/apache/maven-source-plugin) from 3.3.0 to 3.3.1. - [Commits](https://github.com/apache/maven-source-plugin/compare/maven-source-plugin-3.3.0...maven-source-plugin-3.3.1) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-source-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index fd2d0f14b3..c2e2e7be56 100644 --- a/pom.xml +++ b/pom.xml @@ -76,7 +76,7 @@ 3.0.1 2.16.2 3.3.1 - 3.3.0 + 3.3.1 2.1.1 2.4.21 1.7 From 07d9bfd6abe1925170ef210411917a7ba2fb2f5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 5 Apr 2024 10:38:54 +0200 Subject: [PATCH 1898/2114] Update tag name for broker alphas No more OTP variant. --- .github/workflows/test-rabbitmq-alphas.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-rabbitmq-alphas.yml b/.github/workflows/test-rabbitmq-alphas.yml index ab3351aaff..2b3b48112d 100644 --- a/.github/workflows/test-rabbitmq-alphas.yml +++ b/.github/workflows/test-rabbitmq-alphas.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-22.04 strategy: matrix: - rabbitmq-image: [ 'pivotalrabbitmq/rabbitmq:v3.13.x-otp-max-bazel', 'pivotalrabbitmq/rabbitmq:main-otp-max-bazel' ] + rabbitmq-image: [ 'pivotalrabbitmq/rabbitmq:v3.13.x', 'pivotalrabbitmq/rabbitmq:main' ] name: Test against ${{ matrix.rabbitmq-image }} steps: - uses: actions/checkout@v4 From 8f52580370c154cbee05f765cd549d78ca55086b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Apr 2024 00:41:59 +0000 Subject: [PATCH 1899/2114] Bump org.bouncycastle:bcpkix-jdk18on from 1.77 to 1.78 Bumps [org.bouncycastle:bcpkix-jdk18on](https://github.com/bcgit/bc-java) from 1.77 to 1.78. - [Changelog](https://github.com/bcgit/bc-java/blob/main/docs/releasenotes.html) - [Commits](https://github.com/bcgit/bc-java/commits) --- updated-dependencies: - dependency-name: org.bouncycastle:bcpkix-jdk18on dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c2e2e7be56..9429b93d92 100644 --- a/pom.xml +++ b/pom.xml @@ -68,7 +68,7 @@ 1.2.4 1.0.2 9.4.54.v20240208 - 1.77 + 1.78 0.10 2.10.1 From d14d1a286d39683deaabbd16a8231f697cf2ac47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 8 Apr 2024 11:00:27 +0200 Subject: [PATCH 1900/2114] Use 5.21.0 in readme --- README.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.adoc b/README.adoc index 749ab55d75..548888f799 100644 --- a/README.adoc +++ b/README.adoc @@ -1,6 +1,6 @@ -:client-stable: 5.20.0 +:client-stable: 5.21.0 :client-rc: 5.17.0.RC2 -:client-snapshot: 5.21.0-SNAPSHOT +:client-snapshot: 5.22.0-SNAPSHOT = RabbitMQ Java Client From 03e8a0e3d6b78b0fc388db5d47439f02005db255 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Apr 2024 00:54:54 +0000 Subject: [PATCH 1901/2114] Bump opentelemetry.version from 1.36.0 to 1.37.0 Bumps `opentelemetry.version` from 1.36.0 to 1.37.0. Updates `io.opentelemetry:opentelemetry-api` from 1.36.0 to 1.37.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-java/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-java/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-java/compare/v1.36.0...v1.37.0) Updates `io.opentelemetry:opentelemetry-sdk-testing` from 1.36.0 to 1.37.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-java/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-java/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-java/compare/v1.36.0...v1.37.0) --- updated-dependencies: - dependency-name: io.opentelemetry:opentelemetry-api dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: io.opentelemetry:opentelemetry-sdk-testing dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9429b93d92..6cf2129a10 100644 --- a/pom.xml +++ b/pom.xml @@ -59,7 +59,7 @@ 4.2.25 1.12.4 1.1.4 - 1.36.0 + 1.37.0 2.17.0 1.2.13 5.10.2 From a9b72686231255404e55efb17dda2c48fe9a6442 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Apr 2024 00:55:08 +0000 Subject: [PATCH 1902/2114] Bump io.micrometer:micrometer-tracing-integration-test Bumps [io.micrometer:micrometer-tracing-integration-test](https://github.com/micrometer-metrics/tracing) from 1.2.4 to 1.2.5. - [Release notes](https://github.com/micrometer-metrics/tracing/releases) - [Commits](https://github.com/micrometer-metrics/tracing/compare/v1.2.4...v1.2.5) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-tracing-integration-test dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9429b93d92..9060bb1c56 100644 --- a/pom.xml +++ b/pom.xml @@ -65,7 +65,7 @@ 5.10.2 5.11.0 3.25.3 - 1.2.4 + 1.2.5 1.0.2 9.4.54.v20240208 1.78 From a4b8e5443130240b98f72a2d25245cfd7ac56958 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Apr 2024 00:55:14 +0000 Subject: [PATCH 1903/2114] Bump io.micrometer:micrometer-core from 1.12.4 to 1.12.5 Bumps [io.micrometer:micrometer-core](https://github.com/micrometer-metrics/micrometer) from 1.12.4 to 1.12.5. - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.12.4...v1.12.5) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9429b93d92..58ca5e96b9 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,7 @@ true 1.7.36 4.2.25 - 1.12.4 + 1.12.5 1.1.4 1.36.0 2.17.0 From f690cfce543336d33d0dbdae6ab3103bb82cddb2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 12 Apr 2024 00:26:33 +0000 Subject: [PATCH 1904/2114] Bump org.apache.maven.plugins:maven-gpg-plugin from 3.2.2 to 3.2.3 Bumps [org.apache.maven.plugins:maven-gpg-plugin](https://github.com/apache/maven-gpg-plugin) from 3.2.2 to 3.2.3. - [Release notes](https://github.com/apache/maven-gpg-plugin/releases) - [Commits](https://github.com/apache/maven-gpg-plugin/compare/maven-gpg-plugin-3.2.2...maven-gpg-plugin-3.2.3) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-gpg-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index bf72654881..0527786c67 100644 --- a/pom.xml +++ b/pom.xml @@ -84,7 +84,7 @@ 3.13.0 3.2.5 3.2.5 - 3.2.2 + 3.2.3 3.3.0 5.1.9 0.0.6 From 4ecbe92a0d2ec05fbdadc4c4def0f30ec6dc1142 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Apr 2024 00:48:35 +0000 Subject: [PATCH 1905/2114] Bump org.apache.maven.plugins:maven-jar-plugin from 3.3.0 to 3.4.0 Bumps [org.apache.maven.plugins:maven-jar-plugin](https://github.com/apache/maven-jar-plugin) from 3.3.0 to 3.4.0. - [Release notes](https://github.com/apache/maven-jar-plugin/releases) - [Commits](https://github.com/apache/maven-jar-plugin/compare/maven-jar-plugin-3.3.0...maven-jar-plugin-3.4.0) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-jar-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0527786c67..09540c5687 100644 --- a/pom.xml +++ b/pom.xml @@ -85,7 +85,7 @@ 3.2.5 3.2.5 3.2.3 - 3.3.0 + 3.4.0 5.1.9 0.0.6 1.6.13 From 8a58dc2c4e1a6a5cd57f42fb6de0f4a92e4ce359 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 19 Apr 2024 00:59:46 +0000 Subject: [PATCH 1906/2114] Bump org.bouncycastle:bcpkix-jdk18on from 1.78 to 1.78.1 Bumps [org.bouncycastle:bcpkix-jdk18on](https://github.com/bcgit/bc-java) from 1.78 to 1.78.1. - [Changelog](https://github.com/bcgit/bc-java/blob/main/docs/releasenotes.html) - [Commits](https://github.com/bcgit/bc-java/commits) --- updated-dependencies: - dependency-name: org.bouncycastle:bcpkix-jdk18on dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 09540c5687..7a86614653 100644 --- a/pom.xml +++ b/pom.xml @@ -68,7 +68,7 @@ 1.2.5 1.0.2 9.4.54.v20240208 - 1.78 + 1.78.1 0.10 2.10.1 From b078326c03af7ab7837729ace841f84b1ae78ffa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Apr 2024 00:50:06 +0000 Subject: [PATCH 1907/2114] Bump org.apache.maven.plugins:maven-gpg-plugin from 3.2.3 to 3.2.4 Bumps [org.apache.maven.plugins:maven-gpg-plugin](https://github.com/apache/maven-gpg-plugin) from 3.2.3 to 3.2.4. - [Release notes](https://github.com/apache/maven-gpg-plugin/releases) - [Commits](https://github.com/apache/maven-gpg-plugin/compare/maven-gpg-plugin-3.2.3...maven-gpg-plugin-3.2.4) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-gpg-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7a86614653..8c82e04e3d 100644 --- a/pom.xml +++ b/pom.xml @@ -84,7 +84,7 @@ 3.13.0 3.2.5 3.2.5 - 3.2.3 + 3.2.4 3.4.0 5.1.9 0.0.6 From 20fd890c076fa4a61bd3fddb4810797d740a8ddb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Apr 2024 06:48:25 +0000 Subject: [PATCH 1908/2114] Bump org.apache.maven.plugins:maven-jar-plugin from 3.4.0 to 3.4.1 Bumps [org.apache.maven.plugins:maven-jar-plugin](https://github.com/apache/maven-jar-plugin) from 3.4.0 to 3.4.1. - [Release notes](https://github.com/apache/maven-jar-plugin/releases) - [Commits](https://github.com/apache/maven-jar-plugin/compare/maven-jar-plugin-3.4.0...maven-jar-plugin-3.4.1) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-jar-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8c82e04e3d..8fe628b678 100644 --- a/pom.xml +++ b/pom.xml @@ -85,7 +85,7 @@ 3.2.5 3.2.5 3.2.4 - 3.4.0 + 3.4.1 5.1.9 0.0.6 1.6.13 From 84ac1a62cf23b3685bbf7e46c556280099dead08 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 May 2024 01:15:04 +0000 Subject: [PATCH 1909/2114] Bump com.fasterxml.jackson.core:jackson-databind from 2.17.0 to 2.17.1 Bumps [com.fasterxml.jackson.core:jackson-databind](https://github.com/FasterXML/jackson) from 2.17.0 to 2.17.1. - [Commits](https://github.com/FasterXML/jackson/commits) --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-databind dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8fe628b678..7d9335f57a 100644 --- a/pom.xml +++ b/pom.xml @@ -60,7 +60,7 @@ 1.12.5 1.1.4 1.37.0 - 2.17.0 + 2.17.1 1.2.13 5.10.2 5.11.0 From 530ae8b5a9bf94192f7364b05291670475263b98 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 May 2024 00:49:17 +0000 Subject: [PATCH 1910/2114] Bump org.mockito:mockito-core from 5.11.0 to 5.12.0 Bumps [org.mockito:mockito-core](https://github.com/mockito/mockito) from 5.11.0 to 5.12.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.11.0...v5.12.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7d9335f57a..f37a7d2b31 100644 --- a/pom.xml +++ b/pom.xml @@ -63,7 +63,7 @@ 2.17.1 1.2.13 5.10.2 - 5.11.0 + 5.12.0 3.25.3 1.2.5 1.0.2 From 45d616c279b350670e388275e250ad476b7abed6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 May 2024 00:49:30 +0000 Subject: [PATCH 1911/2114] Bump opentelemetry.version from 1.37.0 to 1.38.0 Bumps `opentelemetry.version` from 1.37.0 to 1.38.0. Updates `io.opentelemetry:opentelemetry-api` from 1.37.0 to 1.38.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-java/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-java/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-java/compare/v1.37.0...v1.38.0) Updates `io.opentelemetry:opentelemetry-sdk-testing` from 1.37.0 to 1.38.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-java/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-java/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-java/compare/v1.37.0...v1.38.0) --- updated-dependencies: - dependency-name: io.opentelemetry:opentelemetry-api dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: io.opentelemetry:opentelemetry-sdk-testing dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7d9335f57a..861d1b3a84 100644 --- a/pom.xml +++ b/pom.xml @@ -59,7 +59,7 @@ 4.2.25 1.12.5 1.1.4 - 1.37.0 + 1.38.0 2.17.1 1.2.13 5.10.2 From 73f0ab81c615e40088cae4db082f121202a16804 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 13 May 2024 08:53:15 +0200 Subject: [PATCH 1912/2114] Check write byte buffer size Fixes #1309 --- src/main/java/com/rabbitmq/client/impl/nio/NioParams.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java b/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java index d4fce8a3d7..7a7f025dc7 100644 --- a/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java +++ b/src/main/java/com/rabbitmq/client/impl/nio/NioParams.java @@ -180,7 +180,7 @@ public int getWriteByteBufferSize() { * @return this {@link NioParams} instance */ public NioParams setWriteByteBufferSize(int writeByteBufferSize) { - if (readByteBufferSize <= 0) { + if (writeByteBufferSize <= 0) { throw new IllegalArgumentException("Buffer size must be greater than 0"); } this.writeByteBufferSize = writeByteBufferSize; From 4e64ed873c17de91cb4bbbbcca0a5b200a28a3b4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 May 2024 00:14:34 +0000 Subject: [PATCH 1913/2114] Bump io.micrometer:micrometer-tracing-integration-test Bumps [io.micrometer:micrometer-tracing-integration-test](https://github.com/micrometer-metrics/tracing) from 1.2.5 to 1.3.0. - [Release notes](https://github.com/micrometer-metrics/tracing/releases) - [Commits](https://github.com/micrometer-metrics/tracing/compare/v1.2.5...v1.3.0) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-tracing-integration-test dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1288a4509f..920ac92f31 100644 --- a/pom.xml +++ b/pom.xml @@ -65,7 +65,7 @@ 5.10.2 5.12.0 3.25.3 - 1.2.5 + 1.3.0 1.0.2 9.4.54.v20240208 1.78.1 From bad2bd9fbe6894cbce12bc4bb9aaf905dc36b52d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 May 2024 00:14:39 +0000 Subject: [PATCH 1914/2114] Bump io.micrometer:micrometer-core from 1.12.5 to 1.13.0 Bumps [io.micrometer:micrometer-core](https://github.com/micrometer-metrics/micrometer) from 1.12.5 to 1.13.0. - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.12.5...v1.13.0) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1288a4509f..2861fd3581 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,7 @@ true 1.7.36 4.2.25 - 1.12.5 + 1.13.0 1.1.4 1.38.0 2.17.1 From cff9757776411cee2526df0f52089c262ca3e25b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 May 2024 01:13:48 +0000 Subject: [PATCH 1915/2114] Bump org.codehaus.mojo:build-helper-maven-plugin from 3.5.0 to 3.6.0 Bumps [org.codehaus.mojo:build-helper-maven-plugin](https://github.com/mojohaus/build-helper-maven-plugin) from 3.5.0 to 3.6.0. - [Release notes](https://github.com/mojohaus/build-helper-maven-plugin/releases) - [Commits](https://github.com/mojohaus/build-helper-maven-plugin/compare/3.5.0...3.6.0) --- updated-dependencies: - dependency-name: org.codehaus.mojo:build-helper-maven-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c496090779..9cab947ada 100644 --- a/pom.xml +++ b/pom.xml @@ -80,7 +80,7 @@ 2.1.1 2.4.21 1.7 - 3.5.0 + 3.6.0 3.13.0 3.2.5 3.2.5 From 8f5e5b6a67ddc3b02fc38c8fb46442bbbd4e8437 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 May 2024 01:13:57 +0000 Subject: [PATCH 1916/2114] Bump com.google.code.gson:gson from 2.10.1 to 2.11.0 Bumps [com.google.code.gson:gson](https://github.com/google/gson) from 2.10.1 to 2.11.0. - [Release notes](https://github.com/google/gson/releases) - [Changelog](https://github.com/google/gson/blob/main/CHANGELOG.md) - [Commits](https://github.com/google/gson/compare/gson-parent-2.10.1...gson-parent-2.11.0) --- updated-dependencies: - dependency-name: com.google.code.gson:gson dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c496090779..cd6bb795c2 100644 --- a/pom.xml +++ b/pom.xml @@ -70,7 +70,7 @@ 9.4.54.v20240208 1.78.1 0.10 - 2.10.1 + 2.11.0 3.6.3 3.0.1 From 2442c250c7d4c4b6a368e6a7bffdcb9150402c90 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 May 2024 00:39:30 +0000 Subject: [PATCH 1917/2114] Bump org.assertj:assertj-core from 3.25.3 to 3.26.0 Bumps [org.assertj:assertj-core](https://github.com/assertj/assertj) from 3.25.3 to 3.26.0. - [Release notes](https://github.com/assertj/assertj/releases) - [Commits](https://github.com/assertj/assertj/compare/assertj-build-3.25.3...assertj-build-3.26.0) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f505256c6f..3aa2ca3715 100644 --- a/pom.xml +++ b/pom.xml @@ -64,7 +64,7 @@ 1.2.13 5.10.2 5.12.0 - 3.25.3 + 3.26.0 1.3.0 1.0.2 9.4.54.v20240208 From d1246981c9e1da3bd55cea777234348d621c4aaf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 May 2024 00:28:00 +0000 Subject: [PATCH 1918/2114] Bump org.sonatype.plugins:nexus-staging-maven-plugin Bumps org.sonatype.plugins:nexus-staging-maven-plugin from 1.6.13 to 1.7.0. --- updated-dependencies: - dependency-name: org.sonatype.plugins:nexus-staging-maven-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3aa2ca3715..2769efa348 100644 --- a/pom.xml +++ b/pom.xml @@ -88,7 +88,7 @@ 3.4.1 5.1.9 0.0.6 - 1.6.13 + 1.7.0 1.11 1.4 2.43.0 From 7af3254a9727c1c373b30be22499bc5efe20093b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Jun 2024 01:05:40 +0000 Subject: [PATCH 1919/2114] Bump org.sonarsource.scanner.maven:sonar-maven-plugin Bumps [org.sonarsource.scanner.maven:sonar-maven-plugin](https://github.com/SonarSource/sonar-scanner-maven) from 3.11.0.3922 to 4.0.0.4121. - [Release notes](https://github.com/SonarSource/sonar-scanner-maven/releases) - [Commits](https://github.com/SonarSource/sonar-scanner-maven/compare/3.11.0.3922...4.0.0.4121) --- updated-dependencies: - dependency-name: org.sonarsource.scanner.maven:sonar-maven-plugin dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2769efa348..c27975616a 100644 --- a/pom.xml +++ b/pom.xml @@ -835,7 +835,7 @@ org.sonarsource.scanner.maven sonar-maven-plugin - 3.11.0.3922 + 4.0.0.4121 From 61ddafa40de147e99db89528afd1fd9b6188aa7c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Jun 2024 01:05:51 +0000 Subject: [PATCH 1920/2114] Bump org.apache.maven.plugins:maven-javadoc-plugin from 3.6.3 to 3.7.0 Bumps [org.apache.maven.plugins:maven-javadoc-plugin](https://github.com/apache/maven-javadoc-plugin) from 3.6.3 to 3.7.0. - [Release notes](https://github.com/apache/maven-javadoc-plugin/releases) - [Commits](https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.6.3...maven-javadoc-plugin-3.7.0) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-javadoc-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2769efa348..6733666e9a 100644 --- a/pom.xml +++ b/pom.xml @@ -72,7 +72,7 @@ 0.10 2.11.0 - 3.6.3 + 3.7.0 3.0.1 2.16.2 3.3.1 From 6c82ce2ac7929a5b7793acf44bdaa176d6fa9dc2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Jun 2024 00:32:54 +0000 Subject: [PATCH 1921/2114] Bump opentelemetry.version from 1.38.0 to 1.39.0 Bumps `opentelemetry.version` from 1.38.0 to 1.39.0. Updates `io.opentelemetry:opentelemetry-api` from 1.38.0 to 1.39.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-java/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-java/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-java/compare/v1.38.0...v1.39.0) Updates `io.opentelemetry:opentelemetry-sdk-testing` from 1.38.0 to 1.39.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-java/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-java/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-java/compare/v1.38.0...v1.39.0) --- updated-dependencies: - dependency-name: io.opentelemetry:opentelemetry-api dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: io.opentelemetry:opentelemetry-sdk-testing dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2ef44effe7..18d248b131 100644 --- a/pom.xml +++ b/pom.xml @@ -59,7 +59,7 @@ 4.2.25 1.13.0 1.1.4 - 1.38.0 + 1.39.0 2.17.1 1.2.13 5.10.2 From 80b4c05edcf9636d163a030c14a175833aa7f105 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Jun 2024 00:33:11 +0000 Subject: [PATCH 1922/2114] Bump io.dropwizard.metrics:metrics-core from 4.2.25 to 4.2.26 Bumps [io.dropwizard.metrics:metrics-core](https://github.com/dropwizard/metrics) from 4.2.25 to 4.2.26. - [Release notes](https://github.com/dropwizard/metrics/releases) - [Commits](https://github.com/dropwizard/metrics/compare/v4.2.25...v4.2.26) --- updated-dependencies: - dependency-name: io.dropwizard.metrics:metrics-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2ef44effe7..251e21f3f1 100644 --- a/pom.xml +++ b/pom.xml @@ -56,7 +56,7 @@ true 1.7.36 - 4.2.25 + 4.2.26 1.13.0 1.1.4 1.38.0 From fe2585a5b1b89d91a5afb7eed723ba8529aa980a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 10 Jun 2024 10:01:49 +0200 Subject: [PATCH 1923/2114] Remove use of ha-mode policy Classic mirrored queues are deprecated in RabbitMQ 3.13 and gone in RabbitMQ 4.0, so we do not test them anymore. --- .../rabbitmq/client/test/BrokerTestCase.java | 5 - .../client/test/functional/Policies.java | 6 - .../client/test/server/AbsentQueue.java | 108 ------------------ .../server/DeadLetterExchangeDurable.java | 3 - .../client/test/server/MessageRecovery.java | 21 +--- 5 files changed, 1 insertion(+), 142 deletions(-) delete mode 100644 src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java diff --git a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java index 7f7d2ed4bb..22b2042f71 100644 --- a/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java +++ b/src/test/java/com/rabbitmq/client/test/BrokerTestCase.java @@ -35,7 +35,6 @@ public class BrokerTestCase { private String brokerVersion; - private boolean ha = false; protected volatile TestInfo testInfo; @@ -343,10 +342,6 @@ private static String name(String prefix, Class testClass, String testMethodN prefix, testClass.getSimpleName(), testMethodName, uuid.substring(uuid.length() / 2)); } - protected boolean ha() { - return this.ha; - } - protected boolean beforeMessageContainers() { return versionCompare(this.brokerVersion, "3.13.0") < 0; } diff --git a/src/test/java/com/rabbitmq/client/test/functional/Policies.java b/src/test/java/com/rabbitmq/client/test/functional/Policies.java index 016bc35320..7a0f856882 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/Policies.java +++ b/src/test/java/com/rabbitmq/client/test/functional/Policies.java @@ -180,12 +180,6 @@ public class Policies extends BrokerTestCase { private final Set policies = new HashSet(); private void setPolicy(String name, String pattern, String definition) throws IOException { - // We need to override the HA policy that we use in HATests, so - // priority 1. But we still want a valid test of HA, so add the - // ha-mode definition. - if (ha()) { - definition += ",\"ha-mode\":\"all\""; - } Host.rabbitmqctl("set_policy --priority 1 " + name + " " + pattern + " {" + escapeDefinition(definition) + "}"); policies.add(name); diff --git a/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java b/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java deleted file mode 100644 index d0296d8552..0000000000 --- a/src/test/java/com/rabbitmq/client/test/server/AbsentQueue.java +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) 2007-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. -// -// This software, the RabbitMQ Java client library, is triple-licensed under the -// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 -// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see -// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, -// please see LICENSE-APACHE2. -// -// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, -// either express or implied. See the LICENSE file for specific language governing -// rights and limitations of this software. -// -// If you have any questions regarding licensing, please contact us at -// info@rabbitmq.com. - - -package com.rabbitmq.client.test.server; - -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.test.functional.ClusteredTestBase; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import java.io.IOException; -import java.util.concurrent.Callable; -import java.util.concurrent.TimeoutException; -import org.junit.jupiter.api.TestInfo; - -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.fail; - -/** - * This tests whether 'absent' queues - durable queues whose home node - * is down - are handled properly. - */ -public class AbsentQueue extends ClusteredTestBase { - - private static final String Q = "absent-queue"; - - @BeforeEach - @Override public void setUp(TestInfo info) throws IOException, TimeoutException { - super.setUp(info); - if (clusteredConnection != null) - stopSecondary(); - } - - @AfterEach - @Override public void tearDown(TestInfo info) throws IOException, TimeoutException { - if (clusteredConnection != null) - startSecondary(); - super.tearDown(info); - } - - @Override protected void createResources() throws IOException { - alternateChannel.queueDeclare(Q, true, false, false, null); - } - - @Override protected void releaseResources() throws IOException { - alternateChannel.queueDelete(Q); - } - - @Test public void notFound() throws Exception { - if (!ha()) { - // we don't care about this test in normal mode - return; - } - waitPropagationInHa(); - assertNotFound(() -> channel.queueDeclare(Q, true, false, false, null)); - assertNotFound(() -> channel.queueDeclarePassive(Q)); - assertNotFound(() -> channel.queuePurge(Q)); - assertNotFound(() -> channel.basicGet(Q, true)); - assertNotFound(() -> channel.queueBind(Q, "amq.fanout", "", null)); - } - - protected void assertNotFound(Callable t) throws Exception { - if (clusteredChannel == null) return; - try { - t.call(); - if (!ha()) fail("expected not_found"); - } catch (IOException ioe) { - assertFalse(ha()); - checkShutdownSignal(AMQP.NOT_FOUND, ioe); - channel = connection.createChannel(); - } - - } - - private void waitPropagationInHa() throws IOException, InterruptedException { - // can be necessary to wait a bit in HA mode - if (ha()) { - long waited = 0; - while(waited < 5000) { - Channel tempChannel = connection.createChannel(); - try { - tempChannel.queueDeclarePassive(Q); - break; - } catch (IOException e) { - - } - Thread.sleep(10); - waited += 10; - } - } - } - -} diff --git a/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java b/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java index 3b754c88e2..589fdcb1b6 100644 --- a/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java +++ b/src/test/java/com/rabbitmq/client/test/server/DeadLetterExchangeDurable.java @@ -50,9 +50,6 @@ protected void releaseResources() throws IOException { } @Test public void deadLetterQueueTTLExpiredWhileDown() throws Exception { - // This test is nonsensical (and often breaks) in HA mode. - if (ha()) return; - for(int x = 0; x < DeadLetterExchange.MSG_COUNT; x++) { channel.basicPublish("amq.direct", "test", MessageProperties.MINIMAL_PERSISTENT_BASIC, "test message".getBytes()); } diff --git a/src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java b/src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java index 791e7e0082..b568784533 100644 --- a/src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/server/MessageRecovery.java @@ -46,26 +46,7 @@ public class MessageRecovery extends ConfirmBase restart(); - // When testing in HA mode the message will be collected from - // a promoted slave and will have its redelivered flag - // set. But that only happens if there actually *is* a - // slave. We test that by passively declaring, and - // subsequently deleting, the secondary, non-durable queue, - // which only succeeds if the queue survived the restart, - // which in turn implies that it must have been a HA queue - // with slave(s). - // NB: this wont work when running against a single node broker - // and running the test individually outside of the HA suite - boolean expectDelivered = ha(); - try { - channel.queueDeclarePassive(Q2); - channel.queueDelete(Q2); - expectDelivered = true; - } catch (IOException e) { - checkShutdownSignal(AMQP.NOT_FOUND, e); - openChannel(); - } - assertDelivered(Q, 1, expectDelivered); + assertDelivered(Q, 1, false); channel.queueDelete(Q); channel.queueDelete(Q2); } From c8bd355f0531cded86f74366ad3c256c6de9e5df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 10 Jun 2024 10:11:46 +0200 Subject: [PATCH 1924/2114] Remove deleted test from test suite --- .../java/com/rabbitmq/client/test/server/ServerTestSuite.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/com/rabbitmq/client/test/server/ServerTestSuite.java b/src/test/java/com/rabbitmq/client/test/server/ServerTestSuite.java index 64a1499eb0..463fec3c8e 100644 --- a/src/test/java/com/rabbitmq/client/test/server/ServerTestSuite.java +++ b/src/test/java/com/rabbitmq/client/test/server/ServerTestSuite.java @@ -26,7 +26,6 @@ DeadLetterExchangeDurable.class, EffectVisibilityCrossNodeTest.class, ExclusiveQueueDurability.class, - AbsentQueue.class, AlternateExchangeEquivalence.class, MemoryAlarms.class, MessageRecovery.class, From 87c99b9112465802cb4f62423e20e227552e210f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 10 Jun 2024 10:39:14 +0200 Subject: [PATCH 1925/2114] Remove HA policy in JUnit extension --- .../client/AmqpClientTestExtension.java | 76 ++----------------- 1 file changed, 5 insertions(+), 71 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/AmqpClientTestExtension.java b/src/test/java/com/rabbitmq/client/AmqpClientTestExtension.java index ee4456f536..bd41d2a2cd 100644 --- a/src/test/java/com/rabbitmq/client/AmqpClientTestExtension.java +++ b/src/test/java/com/rabbitmq/client/AmqpClientTestExtension.java @@ -1,4 +1,4 @@ -// Copyright (c) 2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. +// Copyright (c) 2023-2024 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -21,12 +21,10 @@ import com.rabbitmq.client.test.TestUtils; import com.rabbitmq.client.test.functional.FunctionalTestSuite; import com.rabbitmq.client.test.server.HaTestSuite; -import com.rabbitmq.client.test.server.LastHaTestSuite; import com.rabbitmq.client.test.server.ServerTestSuite; import com.rabbitmq.client.test.ssl.SslTestSuite; import com.rabbitmq.tools.Host; import java.io.File; -import java.lang.reflect.Field; import java.net.Socket; import java.util.Properties; import org.junit.jupiter.api.extension.AfterEachCallback; @@ -35,8 +33,6 @@ import org.junit.jupiter.api.extension.ConditionEvaluationResult; import org.junit.jupiter.api.extension.ExecutionCondition; import org.junit.jupiter.api.extension.ExtensionContext; -import org.junit.jupiter.api.extension.ExtensionContext.Namespace; -import org.junit.jupiter.api.extension.ExtensionContext.Store; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -45,7 +41,6 @@ public class AmqpClientTestExtension implements ExecutionCondition, BeforeAllCal AfterEachCallback { private static final Logger LOGGER = LoggerFactory.getLogger(AmqpClientTestExtension.class); - private static final Namespace NAMESPACE = Namespace.create(AmqpClientTestExtension.class); static { Properties TESTS_PROPS = new Properties(System.getProperties()); @@ -66,31 +61,6 @@ public class AmqpClientTestExtension implements ExecutionCondition, BeforeAllCal } } - private static void maybeSetHaFieldValue(ExtensionContext context, boolean value) { - if (context.getTestClass().isPresent() && context.getTestInstance().isPresent()) { - try { - Field haField = findField(context.getTestClass().get(), "ha"); - if (haField != null) { - haField.setAccessible(true); - haField.set(context.getTestInstance().get(), value); - } - } catch (Exception e) { - // OK - } - } - } - - private static Field findField(Class clazz, String fieldName) { - try { - return clazz.getDeclaredField(fieldName); - } catch (NoSuchFieldException e) { - if (clazz.getSuperclass() != null) { - return findField(clazz.getSuperclass(), fieldName); - } - } - return null; - } - private static boolean isFunctionalSuite(ExtensionContext context) { return isTestSuite(context, FunctionalTestSuite.class); } @@ -107,10 +77,6 @@ private static boolean isHaSuite(ExtensionContext context) { return isTestSuite(context, HaTestSuite.class); } - private static boolean isLastHaSuite(ExtensionContext context) { - return isTestSuite(context, LastHaTestSuite.class); - } - private static boolean isTestSuite(ExtensionContext context, Class clazz) { return context.getUniqueId().contains(clazz.getName()); } @@ -162,22 +128,6 @@ private static boolean checkServerListening(String host, int port) { } } - private static Store store(ExtensionContext context) { - return context.getRoot().getStore(NAMESPACE); - } - - private static boolean hasHaSuiteStarted(ExtensionContext context) { - return "true".equals(store(context).get("ha")); - } - - private static void markHaSuiteStarted(ExtensionContext context) { - store(context).put("ha", "true"); - } - - private static void markHaSuiteFinished(ExtensionContext context) { - store(context).remove("ha"); - } - @Override public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) { // HA test suite must be checked first because it contains other test suites @@ -199,39 +149,23 @@ public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext con } @Override - public void beforeAll(ExtensionContext context) throws Exception { - if (isHaSuite(context) && !hasHaSuiteStarted(context)) { - LOGGER.info("Starting HA test suite"); - Host.rabbitmqctl("set_policy HA '.*' '{\"ha-mode\":\"all\"}'"); - markHaSuiteStarted(context); - } - if (isLastHaSuite(context)) { - LOGGER.info("HA suite done, clearing HA state"); - Host.rabbitmqctl("clear_policy HA"); - markHaSuiteFinished(context); - } + public void beforeAll(ExtensionContext context) { + } @Override public void beforeEach(ExtensionContext context) { LOGGER.info( - "Starting test: {}.{} (nio? {}, HA? {})", + "Starting test: {}.{} (nio? {})", context.getTestClass().get().getSimpleName(), context.getTestMethod().get().getName(), - TestUtils.USE_NIO, - hasHaSuiteStarted(context) + TestUtils.USE_NIO ); - if (isHaSuite(context)) { - maybeSetHaFieldValue(context, true); - } } @Override public void afterEach(ExtensionContext context) { LOGGER.info("Test finished: {}.{}", context.getTestClass().get().getSimpleName(), context.getTestMethod().get().getName()); - if (isHaSuite(context)) { - maybeSetHaFieldValue(context, false); - } } } From 092272204c0d8be6bdaaf6a63fa45e7eeb6ace12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Mon, 10 Jun 2024 11:46:29 +0200 Subject: [PATCH 1926/2114] Remove cluster startup script Not used anymore. --- .github/workflows/test-rabbitmq-alphas.yml | 4 +- .../test-supported-java-versions-5.x.yml | 4 +- .../test-supported-java-versions-main.yml | 4 +- .github/workflows/test.yml | 4 +- pom.xml | 166 ------------------ src/main/scripts/manage_test_broker.groovy | 65 ------- 6 files changed, 8 insertions(+), 239 deletions(-) delete mode 100644 src/main/scripts/manage_test_broker.groovy diff --git a/.github/workflows/test-rabbitmq-alphas.yml b/.github/workflows/test-rabbitmq-alphas.yml index 2b3b48112d..7d73c6f2c5 100644 --- a/.github/workflows/test-rabbitmq-alphas.yml +++ b/.github/workflows/test-rabbitmq-alphas.yml @@ -43,14 +43,14 @@ jobs: run: make deps - name: Test with NIO run: | - ./mvnw verify -P '!setup-test-cluster,use-nio' -Drabbitmqctl.bin=DOCKER:rabbitmq \ + ./mvnw verify -P use-nio -Drabbitmqctl.bin=DOCKER:rabbitmq \ -Dtest-broker.A.nodename=rabbit@$(hostname) -Dtest-broker.B.nodename=hare@$(hostname) \ -Dmaven.javadoc.skip=true \ -Dtest-client-cert.password= -Dtest-tls-certs.dir=rabbitmq-configuration/tls \ --no-transfer-progress - name: Test with blocking IO run: | - ./mvnw verify -P '!setup-test-cluster' -Drabbitmqctl.bin=DOCKER:rabbitmq \ + ./mvnw verify -Drabbitmqctl.bin=DOCKER:rabbitmq \ -Dtest-broker.A.nodename=rabbit@$(hostname) -Dtest-broker.B.nodename=hare@$(hostname) \ -Dmaven.javadoc.skip=true \ -Dtest-client-cert.password= -Dtest-tls-certs.dir=rabbitmq-configuration/tls \ diff --git a/.github/workflows/test-supported-java-versions-5.x.yml b/.github/workflows/test-supported-java-versions-5.x.yml index 8935435005..71ab02081c 100644 --- a/.github/workflows/test-supported-java-versions-5.x.yml +++ b/.github/workflows/test-supported-java-versions-5.x.yml @@ -43,7 +43,7 @@ jobs: run: ./mvnw --version - name: Test with NIO run: | - ./mvnw verify -P '!setup-test-cluster,use-nio' -Drabbitmqctl.bin=DOCKER:rabbitmq \ + ./mvnw verify -P use-nio -Drabbitmqctl.bin=DOCKER:rabbitmq \ -Dtest-broker.A.nodename=rabbit@$(hostname) -Dmaven.javadoc.skip=true \ -Dtest-client-cert.password= -Dtest-tls-certs.dir=rabbitmq-configuration/tls \ -Dit.test=ClientTestSuite,FunctionalTestSuite,ServerTestSuite,SslTestSuite \ @@ -51,7 +51,7 @@ jobs: -Dnet.bytebuddy.experimental=true - name: Test with blocking IO run: | - ./mvnw verify -P '!setup-test-cluster' -Drabbitmqctl.bin=DOCKER:rabbitmq \ + ./mvnw verify -Drabbitmqctl.bin=DOCKER:rabbitmq \ -Dtest-broker.A.nodename=rabbit@$(hostname) -Dmaven.javadoc.skip=true \ -Dtest-client-cert.password= -Dtest-tls-certs.dir=rabbitmq-configuration/tls \ -Dit.test=ClientTestSuite,FunctionalTestSuite,ServerTestSuite,SslTestSuite \ diff --git a/.github/workflows/test-supported-java-versions-main.yml b/.github/workflows/test-supported-java-versions-main.yml index 1a901b85f7..52e005b4ba 100644 --- a/.github/workflows/test-supported-java-versions-main.yml +++ b/.github/workflows/test-supported-java-versions-main.yml @@ -41,7 +41,7 @@ jobs: run: ./mvnw --version - name: Test with NIO run: | - ./mvnw verify -P '!setup-test-cluster,use-nio' -Drabbitmqctl.bin=DOCKER:rabbitmq \ + ./mvnw verify -P use-nio -Drabbitmqctl.bin=DOCKER:rabbitmq \ -Dtest-broker.A.nodename=rabbit@$(hostname) -Dmaven.javadoc.skip=true \ -Dtest-client-cert.password= -Dtest-tls-certs.dir=rabbitmq-configuration/tls \ -Dit.test=ClientTestSuite,FunctionalTestSuite,ServerTestSuite,SslTestSuite \ @@ -49,7 +49,7 @@ jobs: -Dnet.bytebuddy.experimental=true - name: Test with blocking IO run: | - ./mvnw verify -P '!setup-test-cluster' -Drabbitmqctl.bin=DOCKER:rabbitmq \ + ./mvnw verify -Drabbitmqctl.bin=DOCKER:rabbitmq \ -Dtest-broker.A.nodename=rabbit@$(hostname) -Dmaven.javadoc.skip=true \ -Dtest-client-cert.password= -Dtest-tls-certs.dir=rabbitmq-configuration/tls \ -Dit.test=ClientTestSuite,FunctionalTestSuite,ServerTestSuite,SslTestSuite \ diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 56fd36503c..2ed03ac805 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -41,14 +41,14 @@ jobs: run: make deps - name: Test with NIO run: | - ./mvnw verify -P '!setup-test-cluster,use-nio' -Drabbitmqctl.bin=DOCKER:rabbitmq \ + ./mvnw verify -P use-nio -Drabbitmqctl.bin=DOCKER:rabbitmq \ -Dtest-broker.A.nodename=rabbit@$(hostname) -Dtest-broker.B.nodename=hare@$(hostname) \ -Dmaven.javadoc.skip=true \ -Dtest-client-cert.password= -Dtest-tls-certs.dir=rabbitmq-configuration/tls \ --no-transfer-progress - name: Test with blocking IO run: | - ./mvnw verify -P '!setup-test-cluster' -Drabbitmqctl.bin=DOCKER:rabbitmq \ + ./mvnw verify -Drabbitmqctl.bin=DOCKER:rabbitmq \ -Dtest-broker.A.nodename=rabbit@$(hostname) -Dtest-broker.B.nodename=hare@$(hostname) \ -Dmaven.javadoc.skip=true \ -Dtest-client-cert.password= -Dtest-tls-certs.dir=rabbitmq-configuration/tls \ diff --git a/pom.xml b/pom.xml index 0e0aa7210f..7937783dac 100644 --- a/pom.xml +++ b/pom.xml @@ -107,9 +107,6 @@ "rabbitmq_codegen" is used to generate required Java source files. Its path can be specified with the ${codegen.dir} property instead. - - "rabbit" is used to automatically setup a RabbitMQ cluster for the - testsuite. --> ${basedir}/deps ${deps.dir}/rabbitmq_codegen @@ -198,169 +195,6 @@ - - - setup-test-cluster - - - !skipTests - - - - - - org.codehaus.gmaven - groovy-maven-plugin - ${groovy.maven.plugin.version} - - - org.codehaus.groovy - groovy-all - ${groovy.all.version} - - - - - - generate-test-resources - query-test-tls-certs-dir - - execute - - - - ${groovy-scripts.dir}/query_test_tls_certs_dir.groovy - - - - - - - pre-integration-test - start-test-broker-A - - execute - - - - ${test-broker.A.nodename} - ${test-broker.A.node_port} - - - ${groovy-scripts.dir}/manage_test_broker.groovy - - - - - pre-integration-test - start-test-broker-B - - execute - - - - ${test-broker.B.nodename} - ${test-broker.B.node_port} - - - ${groovy-scripts.dir}/manage_test_broker.groovy - - - - - pre-integration-test - create-test-cluster - - execute - - - - ${test-broker.B.nodename} - ${test-broker.A.nodename} - - - ${groovy-scripts.dir}/manage_test_broker.groovy - - - - - - - post-integration-test - stop-test-broker-B - - execute - - - - ${test-broker.B.nodename} - - - ${groovy-scripts.dir}/manage_test_broker.groovy - - - - - post-integration-test - stop-test-broker-A - - execute - - - - ${test-broker.A.nodename} - - - ${groovy-scripts.dir}/manage_test_broker.groovy - - - - - - - - - org.codehaus.mojo - keytool-maven-plugin - ${keytool.maven.plugin.version} - - false - - - - - - 6026DFCA @@ -185,35 +178,6 @@ - - - use-provided-test-keystores - - - ${test-tls-certs.dir}/testca/cacert.pem - - - - - - org.codehaus.mojo - keytool-maven-plugin - ${keytool.maven.plugin.version} - - false - - - - - - - - generate-test-resources - remove-old-test-keystores - - execute - - - - ${groovy-scripts.dir}/remove_old_test_keystores.groovy - - - @@ -840,47 +778,6 @@ - - - org.codehaus.mojo - keytool-maven-plugin - ${keytool.maven.plugin.version} - - true - - - - generate-test-ca-keystore - generate-test-resources - - importCertificate - - - ${test-tls-certs.dir}/testca/cacert.pem - ${test-keystore.ca} - ${test-keystore.password} - true - server1 - - - - generate-test-empty-keystore - generate-test-resources - - importCertificate - deleteAlias - - - ${test-tls-certs.dir}/testca/cacert.pem - ${test-keystore.empty} - ${test-keystore.password} - true - server1 - - - - - org.apache.maven.plugins maven-jar-plugin diff --git a/src/test/java/com/rabbitmq/client/AmqpClientTestExtension.java b/src/test/java/com/rabbitmq/client/AmqpClientTestExtension.java index 58abd3efeb..dcffa744b2 100644 --- a/src/test/java/com/rabbitmq/client/AmqpClientTestExtension.java +++ b/src/test/java/com/rabbitmq/client/AmqpClientTestExtension.java @@ -1,4 +1,5 @@ -// Copyright (c) 2023-2025 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. +// Copyright (c) 2023-2025 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom +// Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -24,9 +25,7 @@ import com.rabbitmq.client.test.server.ServerTestSuite; import com.rabbitmq.client.test.ssl.SslTestSuite; import com.rabbitmq.tools.Host; -import java.io.File; import java.net.Socket; -import java.util.Properties; import org.junit.jupiter.api.extension.AfterEachCallback; import org.junit.jupiter.api.extension.BeforeAllCallback; import org.junit.jupiter.api.extension.BeforeEachCallback; @@ -36,31 +35,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class AmqpClientTestExtension implements ExecutionCondition, BeforeAllCallback, - BeforeEachCallback, - AfterEachCallback { +public class AmqpClientTestExtension + implements ExecutionCondition, BeforeAllCallback, BeforeEachCallback, AfterEachCallback { private static final Logger LOGGER = LoggerFactory.getLogger(AmqpClientTestExtension.class); - static { - Properties TESTS_PROPS = new Properties(System.getProperties()); - String make = System.getenv("MAKE"); - if (make != null) { - TESTS_PROPS.setProperty("make.bin", make); - } - try { - TESTS_PROPS.load(Host.class.getClassLoader().getResourceAsStream("config.properties")); - } catch (Exception e) { - System.out.println( - "\"build.properties\" or \"config.properties\" not found" + - " in classpath. Please copy \"build.properties\" and" + - " \"config.properties\" into src/test/resources. Ignore" + - " this message if running with ant."); - } finally { - System.setProperties(TESTS_PROPS); - } - } - private static boolean isFunctionalSuite(ExtensionContext context) { return isTestSuite(context, FunctionalTestSuite.class); } @@ -86,8 +65,7 @@ public static boolean requiredProperties() { String rabbitmqctl = Host.rabbitmqctlCommand(); if (rabbitmqctl == null) { System.err.println( - "rabbitmqctl required; please set \"rabbitmqctl.bin\" system" + - " property"); + "rabbitmqctl required; please set \"rabbitmqctl.bin\" system" + " property"); return false; } @@ -95,20 +73,7 @@ public static boolean requiredProperties() { } public static boolean isSSLAvailable() { - String sslClientCertsDir = System.getProperty("test-client-cert.path"); - String hostname = System.getProperty("broker.hostname"); - String port = System.getProperty("broker.sslport"); - if (sslClientCertsDir == null || hostname == null || port == null) { - return false; - } - - // If certificate is present and some server is listening on port 5671 - if (new File(sslClientCertsDir).exists() && - checkServerListening(hostname, Integer.parseInt(port))) { - return true; - } else { - return false; - } + return checkServerListening("localhost", 5671); } private static boolean checkServerListening(String host, int port) { @@ -132,40 +97,42 @@ private static boolean checkServerListening(String host, int port) { public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) { // HA test suite must be checked first because it contains other test suites if (isHaSuite(context)) { - return requiredProperties() ? enabled("Required properties available") + return requiredProperties() + ? enabled("Required properties available") : disabled("Required properties not available"); } else if (isServerSuite(context)) { - return requiredProperties() ? enabled("Required properties available") + return requiredProperties() + ? enabled("Required properties available") : disabled("Required properties not available"); } else if (isFunctionalSuite(context)) { - return requiredProperties() ? enabled("Required properties available") + return requiredProperties() + ? enabled("Required properties available") : disabled("Required properties not available"); } else if (isSslSuite(context)) { - return requiredProperties() && isSSLAvailable() ? enabled( - "Required properties and TLS available") + return requiredProperties() && isSSLAvailable() + ? enabled("Required properties and TLS available") : disabled("Required properties or TLS not available"); } return enabled("ok"); } @Override - public void beforeAll(ExtensionContext context) { - - } + public void beforeAll(ExtensionContext context) {} @Override public void beforeEach(ExtensionContext context) { LOGGER.info( "Starting test: {}.{} (nio? {})", - context.getTestClass().get().getSimpleName(), context.getTestMethod().get().getName(), - TestUtils.USE_NIO - ); + context.getTestClass().get().getSimpleName(), + context.getTestMethod().get().getName(), + TestUtils.USE_NIO); } @Override public void afterEach(ExtensionContext context) { - LOGGER.info("Test finished: {}.{}", - context.getTestClass().get().getSimpleName(), context.getTestMethod().get().getName()); + LOGGER.info( + "Test finished: {}.{}", + context.getTestClass().get().getSimpleName(), + context.getTestMethod().get().getName()); } - } diff --git a/src/test/java/com/rabbitmq/client/test/functional/DurableOnTransient.java b/src/test/java/com/rabbitmq/client/test/functional/DurableOnTransient.java index f3dec6d0fe..08508a71f3 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/DurableOnTransient.java +++ b/src/test/java/com/rabbitmq/client/test/functional/DurableOnTransient.java @@ -20,7 +20,6 @@ import java.io.IOException; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import com.rabbitmq.client.GetResponse; @@ -68,7 +67,6 @@ protected void releaseResources() throws IOException { assertNotNull(basicGet()); } - @Disabled("Does not apply with Khepri (update datastore while second node is down)") @Test public void semiDurableBindingRemoval() throws IOException { if (clusteredConnection != null) { deleteExchange("x"); @@ -78,18 +76,25 @@ protected void releaseResources() throws IOException { channel.queueBind("q", "x", "k"); stopSecondary(); + boolean restarted = false; + try { + deleteExchange("x"); - deleteExchange("x"); - - startSecondary(); + startSecondary(); + restarted = true; - declareTransientTopicExchange("x"); + declareTransientTopicExchange("x"); - basicPublishVolatile("x", "k"); - assertDelivered("q", 0); + basicPublishVolatile("x", "k"); + assertDelivered("q", 0); - deleteQueue("q"); - deleteExchange("x"); + deleteQueue("q"); + deleteExchange("x"); + } finally { + if (!restarted) { + startSecondary(); + } + } } } } diff --git a/src/test/java/com/rabbitmq/client/test/ssl/TlsTestUtils.java b/src/test/java/com/rabbitmq/client/test/ssl/TlsTestUtils.java index 9fe5004107..f85829c119 100644 --- a/src/test/java/com/rabbitmq/client/test/ssl/TlsTestUtils.java +++ b/src/test/java/com/rabbitmq/client/test/ssl/TlsTestUtils.java @@ -1,4 +1,5 @@ -// Copyright (c) 2007-2025 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. +// Copyright (c) 2007-2025 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom +// Inc. and/or its subsidiaries. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 @@ -15,82 +16,38 @@ package com.rabbitmq.client.test.ssl; -import static org.junit.jupiter.api.Assertions.assertNotNull; - +import com.rabbitmq.tools.Host; import java.io.FileInputStream; +import java.net.InetAddress; +import java.net.UnknownHostException; import java.security.KeyStore; import java.security.NoSuchAlgorithmException; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.Collection; import java.util.stream.Collectors; -import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManagerFactory; class TlsTestUtils { + static final String[] PROTOCOLS = new String[] {"TLSv1.3", "TLSv1.2"}; + private TlsTestUtils() {} static SSLContext badVerifiedSslContext() throws Exception { - return verifiedSslContext(() -> getSSLContext(), emptyKeystoreCa()); + return sslContext(trustManagerFactory(clientCertificate())); } static SSLContext verifiedSslContext() throws Exception { - return verifiedSslContext(() -> getSSLContext(), keystoreCa()); - } - - static SSLContext verifiedSslContext(CallableSupplier sslContextSupplier) throws Exception { - return verifiedSslContext(sslContextSupplier, keystoreCa()); - } - - static SSLContext verifiedSslContext(CallableSupplier sslContextSupplier, String keystorePath) throws Exception { - // for local testing, run ./mvnw test-compile -Dtest-tls-certs.dir=/tmp/tls-gen/basic - // (generates the Java keystores) - assertNotNull(keystorePath); - String keystorePasswd = keystorePassword(); - assertNotNull(keystorePasswd); - char [] keystorePassword = keystorePasswd.toCharArray(); - - KeyStore tks = KeyStore.getInstance("JKS"); - tks.load(new FileInputStream(keystorePath), keystorePassword); - - TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); - tmf.init(tks); - - String p12Path = clientCertPath(); - assertNotNull(p12Path); - String p12Passwd = clientCertPassword(); - assertNotNull(p12Passwd); - KeyStore ks = KeyStore.getInstance("PKCS12"); - char [] p12Password = p12Passwd.toCharArray(); - ks.load(new FileInputStream(p12Path), p12Password); - - KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); - kmf.init(ks, p12Password); - - SSLContext c = sslContextSupplier.get(); - c.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); - return c; + return sslContext(trustManagerFactory(caCertificate())); } - static String keystoreCa() { - return System.getProperty("test-keystore.ca", "./target/ca.keystore"); - } - - static String emptyKeystoreCa() { - return System.getProperty("test-keystore.empty", "./target/empty.keystore"); - } - - static String keystorePassword() { - return System.getProperty("test-keystore.password", "bunnies"); - } - - static String clientCertPath() { - return System.getProperty("test-client-cert.path", "/tmp/tls-gen/basic/client/keycert.p12"); - } - - static String clientCertPassword() { - return System.getProperty("test-client-cert.password", ""); + static SSLContext verifiedSslContext(CallableSupplier sslContextSupplier) + throws Exception { + return sslContext(sslContextSupplier, trustManagerFactory(caCertificate())); } public static SSLContext getSSLContext() throws NoSuchAlgorithmException { @@ -112,15 +69,78 @@ public static SSLContext getSSLContext() throws NoSuchAlgorithmException { static Collection availableTlsProtocols() { try { String[] protocols = SSLContext.getDefault().getSupportedSSLParameters().getProtocols(); - return Arrays.stream(protocols).filter(p -> p.toLowerCase().startsWith("tls")).collect( - Collectors.toList()); + return Arrays.stream(protocols) + .filter(p -> p.toLowerCase().startsWith("tls")) + .collect(Collectors.toList()); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } } + static SSLContext sslContext(TrustManagerFactory trustManagerFactory) throws Exception { + return sslContext(() -> SSLContext.getInstance(PROTOCOLS[0]), trustManagerFactory); + } + + static SSLContext sslContext( + CallableSupplier sslContextSupplier, TrustManagerFactory trustManagerFactory) + throws Exception { + SSLContext sslContext = sslContextSupplier.get(); + sslContext.init( + null, trustManagerFactory == null ? null : trustManagerFactory.getTrustManagers(), null); + return sslContext; + } + + static TrustManagerFactory trustManagerFactory(Certificate certificate) throws Exception { + KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + keyStore.load(null, null); + keyStore.setCertificateEntry("some-certificate", certificate); + TrustManagerFactory trustManagerFactory = + TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + trustManagerFactory.init(keyStore); + return trustManagerFactory; + } + + static X509Certificate caCertificate() throws Exception { + return loadCertificate(caCertificateFile()); + } + + static String caCertificateFile() { + return tlsArtefactPath( + System.getProperty("ca.certificate", "./rabbitmq-configuration/tls/ca_certificate.pem")); + } + + static X509Certificate clientCertificate() throws Exception { + return loadCertificate(clientCertificateFile()); + } + + static String clientCertificateFile() { + return tlsArtefactPath( + System.getProperty( + "client.certificate", + "./rabbitmq-configuration/tls/client_" + hostname() + "_certificate.pem")); + } + + static X509Certificate loadCertificate(String file) throws Exception { + try (FileInputStream inputStream = new FileInputStream(file)) { + CertificateFactory fact = CertificateFactory.getInstance("X.509"); + return (X509Certificate) fact.generateCertificate(inputStream); + } + } + + private static String tlsArtefactPath(String in) { + return in.replace("$(hostname)", hostname()).replace("$(hostname -s)", hostname()); + } + + private static String hostname() { + try { + return InetAddress.getLocalHost().getHostName(); + } catch (UnknownHostException e) { + return Host.hostname(); + } + } + @FunctionalInterface - interface CallableSupplier { + interface CallableSupplier { T get() throws Exception; } diff --git a/src/test/java/com/rabbitmq/tools/Host.java b/src/test/java/com/rabbitmq/tools/Host.java index 11c9f0355a..ec264fa1b9 100644 --- a/src/test/java/com/rabbitmq/tools/Host.java +++ b/src/test/java/com/rabbitmq/tools/Host.java @@ -42,6 +42,14 @@ public class Host { private static final String DOCKER_PREFIX = "DOCKER:"; private static final Pattern CONNECTION_NAME_PATTERN = Pattern.compile("\"connection_name\",\"(?[a-zA-Z0-9\\-]+)?\""); + public static String hostname() { + try { + return executeCommand("hostname").output(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + public static String capture(InputStream is) throws IOException { @@ -189,17 +197,6 @@ public static void clearResourceAlarm(String source) throws IOException { rabbitmqctl("eval 'rabbit_alarm:clear_alarm({resource_limit, " + source + ", node()}).'"); } - public static ProcessState invokeMakeTarget(String command) throws IOException { - File rabbitmqctl = new File(rabbitmqctlCommand()); - return executeCommand(makeCommand() + - " -C \'" + rabbitmqDir() + "\'" + - " RABBITMQCTL=\'" + rabbitmqctl.getAbsolutePath() + "\'" + - " RABBITMQ_NODENAME=\'" + nodenameA() + "\'" + - " RABBITMQ_NODE_PORT=" + node_portA() + - " RABBITMQ_CONFIG_FILE=\'" + config_fileA() + "\'" + - " " + command); - } - public static void startRabbitOnNode() throws IOException { rabbitmqctl("start_app"); tryConnectFor(10_000); @@ -210,7 +207,7 @@ public static void stopRabbitOnNode() throws IOException { } public static void tryConnectFor(int timeoutInMs) throws IOException { - tryConnectFor(timeoutInMs, node_portA() == null ? 5672 : Integer.valueOf(node_portA())); + tryConnectFor(timeoutInMs, 5672); } public static void tryConnectFor(int timeoutInMs, int port) throws IOException { @@ -245,15 +242,6 @@ public static String nodenameA() return System.getProperty("test-broker.A.nodename"); } - public static String node_portA() - { - return System.getProperty("test-broker.A.node_port"); - } - - public static String config_fileA() - { - return System.getProperty("test-broker.A.config_file"); - } public static String nodenameB() { @@ -265,11 +253,6 @@ public static String node_portB() return System.getProperty("test-broker.B.node_port"); } - public static String config_fileB() - { - return System.getProperty("test-broker.B.config_file"); - } - public static String rabbitmqctlCommand() { String rabbitmqCtl = System.getProperty("rabbitmqctl.bin"); if (rabbitmqCtl == null) { @@ -291,11 +274,6 @@ public static boolean isOnDocker() { return rabbitmqCtl.startsWith(DOCKER_PREFIX); } - public static String rabbitmqDir() - { - return System.getProperty("rabbitmq.dir"); - } - public static void closeConnection(String pid) throws IOException { rabbitmqctl("close_connection '" + pid + "' 'Closed via rabbitmqctl'"); } diff --git a/src/test/resources/config.properties b/src/test/resources/config.properties deleted file mode 100644 index 6562e2f80e..0000000000 --- a/src/test/resources/config.properties +++ /dev/null @@ -1,3 +0,0 @@ -broker.hostname=localhost -broker.port=5672 -broker.sslport=5671 diff --git a/src/test/resources/hare@localhost.config b/src/test/resources/hare@localhost.config deleted file mode 100644 index 41667a9c70..0000000000 --- a/src/test/resources/hare@localhost.config +++ /dev/null @@ -1,15 +0,0 @@ -% vim:ft=erlang: - -[ - {rabbit, [ - {ssl_listeners, [5670]}, - {ssl_options, [ - {cacertfile, "${test-tls-certs.dir}/testca/cacert.pem"}, - {certfile, "${test-tls-certs.dir}/server/cert.pem"}, - {keyfile, "${test-tls-certs.dir}/server/key.pem"}, - {verify, verify_peer}, - {fail_if_no_peer_cert, false}, - {honor_cipher_order, true}]}, - {auth_mechanisms, ['PLAIN', 'ANONYMOUS', 'AMQPLAIN', 'EXTERNAL', 'RABBIT-CR-DEMO']} - ]} -]. diff --git a/src/test/resources/log4j2-test.properties b/src/test/resources/log4j2-test.properties deleted file mode 100644 index b7e0a68699..0000000000 --- a/src/test/resources/log4j2-test.properties +++ /dev/null @@ -1,12 +0,0 @@ -status = error -dest = err -name = PropertiesConfig - -appender.console.type = Console -appender.console.name = STDOUT -appender.console.layout.type = PatternLayout -appender.console.layout.pattern = %m%n - -logger.com.rabbitmq.level = info -rootLogger.level = error -rootLogger.appenderRef.stdout.ref = STDOUT \ No newline at end of file diff --git a/src/test/resources/rabbit@localhost.config b/src/test/resources/rabbit@localhost.config deleted file mode 100644 index 9e3b77c94d..0000000000 --- a/src/test/resources/rabbit@localhost.config +++ /dev/null @@ -1,15 +0,0 @@ -% vim:ft=erlang: - -[ - {rabbit, [ - {ssl_listeners, [5671]}, - {ssl_options, [ - {cacertfile, "${test-tls-certs.dir}/testca/cacert.pem"}, - {certfile, "${test-tls-certs.dir}/server/cert.pem"}, - {keyfile, "${test-tls-certs.dir}/server/key.pem"}, - {verify, verify_peer}, - {fail_if_no_peer_cert, false}, - {honor_cipher_order, true}]}, - {auth_mechanisms, ['PLAIN', 'ANONYMOUS', 'AMQPLAIN', 'EXTERNAL', 'RABBIT-CR-DEMO']} - ]} -]. From 5da298c3f89759040dc4465e467af4d97dcb8704 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Wed, 19 Feb 2025 14:35:16 +0100 Subject: [PATCH 2071/2114] Delete TLS-related groovy scripts --- .../scripts/query_test_tls_certs_dir.groovy | 25 ------------------- .../scripts/remove_old_test_keystores.groovy | 8 ------ 2 files changed, 33 deletions(-) delete mode 100644 src/main/scripts/query_test_tls_certs_dir.groovy delete mode 100644 src/main/scripts/remove_old_test_keystores.groovy diff --git a/src/main/scripts/query_test_tls_certs_dir.groovy b/src/main/scripts/query_test_tls_certs_dir.groovy deleted file mode 100644 index 2c86bb8c10..0000000000 --- a/src/main/scripts/query_test_tls_certs_dir.groovy +++ /dev/null @@ -1,25 +0,0 @@ -String[] command = [ - properties['make.bin'], - '-C', properties['rabbitmq.dir'], - '--no-print-directory', - 'show-test-tls-certs-dir', - "DEPS_DIR=${properties['deps.dir']}", -] - -def pb = new ProcessBuilder(command) -pb.redirectErrorStream(true) - -def process = pb.start() - -// We are only interested in the last line of output. Previous lines, if -// any, are related to the generation of the test certificates. -def whole_output = "" -process.inputStream.eachLine { - whole_output += it - project.properties['test-tls-certs.dir'] = it.trim() -} -process.waitFor() -if (process.exitValue() != 0) { - println(whole_output.trim()) - fail("Failed to query test TLS certs directory with command: ${command.join(' ')}") -} diff --git a/src/main/scripts/remove_old_test_keystores.groovy b/src/main/scripts/remove_old_test_keystores.groovy deleted file mode 100644 index e08775e4e0..0000000000 --- a/src/main/scripts/remove_old_test_keystores.groovy +++ /dev/null @@ -1,8 +0,0 @@ -def dir = new File(project.build.directory) - -// This pattern starts with `.*`. This is normally useless and even -// inefficient but the matching doesn't work without it... -def pattern = ~/.*\.keystore$/ -dir.eachFileMatch(pattern) { file -> - file.delete() -} From 46b245f3601df40444687d08c630b958d57191ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= Date: Fri, 21 Feb 2025 16:53:18 +0100 Subject: [PATCH 2072/2114] Set loopback users back to initial value after test --- .../test/functional/ConnectionRecovery.java | 2 -- .../client/test/server/LoopbackUsers.java | 22 ++++++++++++++----- src/test/java/com/rabbitmq/tools/Host.java | 4 ++-- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java index b54507d5df..4257c5a7b3 100644 --- a/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java +++ b/src/test/java/com/rabbitmq/client/test/functional/ConnectionRecovery.java @@ -23,7 +23,6 @@ import com.rabbitmq.client.test.BrokerTestCase; import com.rabbitmq.client.test.TestUtils; import com.rabbitmq.tools.Host; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import java.io.IOException; @@ -368,7 +367,6 @@ private void testClientNamedQueueRecoveryWith(String q, boolean noWait) throws I } // bug 26552 - @Disabled @Test public void clientNamedTransientAutoDeleteQueueAndBindingRecovery() throws IOException, InterruptedException, TimeoutException { String q = UUID.randomUUID().toString(); String x = "tmp-fanout"; diff --git a/src/test/java/com/rabbitmq/client/test/server/LoopbackUsers.java b/src/test/java/com/rabbitmq/client/test/server/LoopbackUsers.java index b97162c4c7..e81de3703e 100644 --- a/src/test/java/com/rabbitmq/client/test/server/LoopbackUsers.java +++ b/src/test/java/com/rabbitmq/client/test/server/LoopbackUsers.java @@ -48,14 +48,26 @@ public class LoopbackUsers { @Test public void loopback() throws IOException, TimeoutException { if (!Host.isOnDocker()) { String addr = findRealIPAddress().getHostAddress(); - assertGuestFail(addr); - Host.rabbitmqctl("eval 'application:set_env(rabbit, loopback_users, []).'"); - assertGuestSucceed(addr); - Host.rabbitmqctl("eval 'application:set_env(rabbit, loopback_users, [<<\"guest\">>]).'"); - assertGuestFail(addr); + String initialValue = getLoopbackUsers(); + try { + setLoopbackUsers("[]"); + assertGuestSucceed(addr); + setLoopbackUsers("[<<\"guest\">>]"); + assertGuestFail(addr); + } finally { + setLoopbackUsers(initialValue); + } } } + private static String getLoopbackUsers() throws IOException { + return Host.rabbitmqctl("eval '{ok, V} = application:get_env(rabbit, loopback_users), V.'").output(); + } + + private static void setLoopbackUsers(String value) throws IOException { + Host.rabbitmqctl(String.format("eval 'application:set_env(rabbit, loopback_users, %s).'", value)); + } + private void assertGuestSucceed(String addr) throws IOException, TimeoutException { succeedConnect("guest", addr); succeedConnect("guest", "localhost"); diff --git a/src/test/java/com/rabbitmq/tools/Host.java b/src/test/java/com/rabbitmq/tools/Host.java index ec264fa1b9..9adf1fc7fc 100644 --- a/src/test/java/com/rabbitmq/tools/Host.java +++ b/src/test/java/com/rabbitmq/tools/Host.java @@ -80,7 +80,7 @@ public static ProcessState executeCommand(String command) throws IOException return new ProcessState(pr, inputState, errorState); } - static class ProcessState { + public static class ProcessState { private final Process process; private final InputStreamPumpState inputState; @@ -93,7 +93,7 @@ static class ProcessState { this.errorState = errorState; } - private String output() { + public String output() { return inputState.buffer.toString(); } From 44c9dc2c86206b725aecad138e2e1a51ef18954d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= <514737+acogoluegnes@users.noreply.github.com> Date: Wed, 5 Mar 2025 11:41:04 +0100 Subject: [PATCH 2073/2114] Remove unnecessary throws --- .../com/rabbitmq/client/impl/WorkPoolTests.java | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java b/src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java index 79c876e186..d8cf881dea 100644 --- a/src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java +++ b/src/test/java/com/rabbitmq/client/impl/WorkPoolTests.java @@ -41,9 +41,8 @@ public class WorkPoolTests { /** * Test add work and remove work - * @throws Exception untested */ - @Test public void basicInOut() throws Exception { + @Test public void basicInOut() { Object one = new Object(); Object two = new Object(); @@ -70,9 +69,8 @@ public class WorkPoolTests { /** * Test add work when work in progress. - * @throws Exception untested */ - @Test public void workInWhileInProgress() throws Exception { + @Test public void workInWhileInProgress() { Object one = new Object(); Object two = new Object(); @@ -98,9 +96,8 @@ public class WorkPoolTests { /** * Test multiple work keys. - * @throws Exception untested */ - @Test public void interleavingKeys() throws Exception { + @Test public void interleavingKeys() { Object one = new Object(); Object two = new Object(); Object three = new Object(); @@ -129,9 +126,8 @@ public class WorkPoolTests { /** * Test removal of key (with work) - * @throws Exception untested */ - @Test public void unregisterKey() throws Exception { + @Test public void unregisterKey() { Object one = new Object(); Object two = new Object(); Object three = new Object(); @@ -154,9 +150,8 @@ public class WorkPoolTests { /** * Test removal of all keys (with work). - * @throws Exception untested */ - @Test public void unregisterAllKeys() throws Exception { + @Test public void unregisterAllKeys() { Object one = new Object(); Object two = new Object(); Object three = new Object(); From 9b049b4de3611c9ba859b3f8fe53454ee72c5964 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Mar 2025 00:19:47 +0000 Subject: [PATCH 2074/2114] Bump opentelemetry.version from 1.47.0 to 1.48.0 Bumps `opentelemetry.version` from 1.47.0 to 1.48.0. Updates `io.opentelemetry:opentelemetry-api` from 1.47.0 to 1.48.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-java/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-java/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-java/compare/v1.47.0...v1.48.0) Updates `io.opentelemetry:opentelemetry-sdk-testing` from 1.47.0 to 1.48.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-java/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-java/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-java/compare/v1.47.0...v1.48.0) --- updated-dependencies: - dependency-name: io.opentelemetry:opentelemetry-api dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: io.opentelemetry:opentelemetry-sdk-testing dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ada6a2309c..409485049e 100644 --- a/pom.xml +++ b/pom.xml @@ -58,7 +58,7 @@ 1.7.36 4.2.30 1.14.4 - 1.47.0 + 1.48.0 2.18.3 1.2.13 5.12.0 From c07acca18f41cc29d3b61f844d66ed5ca127838d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Mar 2025 00:14:21 +0000 Subject: [PATCH 2075/2114] Bump io.micrometer:micrometer-tracing-integration-test Bumps [io.micrometer:micrometer-tracing-integration-test](https://github.com/micrometer-metrics/tracing) from 1.4.3 to 1.4.4. - [Release notes](https://github.com/micrometer-metrics/tracing/releases) - [Commits](https://github.com/micrometer-metrics/tracing/compare/v1.4.3...v1.4.4) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-tracing-integration-test dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 409485049e..0bea703058 100644 --- a/pom.xml +++ b/pom.xml @@ -64,7 +64,7 @@ 5.12.0 5.16.0 3.27.3 - 1.4.3 + 1.4.4 1.0.4 9.4.57.v20241219 1.80 From d859941a129a69a0f4b610184a6f71ffd0350ebd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Mar 2025 00:14:31 +0000 Subject: [PATCH 2076/2114] Bump io.micrometer:micrometer-core from 1.14.4 to 1.14.5 Bumps [io.micrometer:micrometer-core](https://github.com/micrometer-metrics/micrometer) from 1.14.4 to 1.14.5. - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.14.4...v1.14.5) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 409485049e..8478879ef0 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,7 @@ true 1.7.36 4.2.30 - 1.14.4 + 1.14.5 1.48.0 2.18.3 1.2.13 From 1765236e36da063775621835db7d565daa81fbec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= <514737+acogoluegnes@users.noreply.github.com> Date: Thu, 13 Mar 2025 08:37:51 +0100 Subject: [PATCH 2077/2114] Test against RabbitMQ 4.1 alpha --- .github/workflows/test-rabbitmq-alphas.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-rabbitmq-alphas.yml b/.github/workflows/test-rabbitmq-alphas.yml index eca3f8e212..c0fe5372d1 100644 --- a/.github/workflows/test-rabbitmq-alphas.yml +++ b/.github/workflows/test-rabbitmq-alphas.yml @@ -16,7 +16,10 @@ jobs: runs-on: ubuntu-24.04 strategy: matrix: - rabbitmq-image: [ 'pivotalrabbitmq/rabbitmq:v4.0.x', 'pivotalrabbitmq/rabbitmq:main' ] + rabbitmq-image: + - pivotalrabbitmq/rabbitmq:v4.0.x-otp27 + - pivotalrabbitmq/rabbitmq:v4.1.x-otp27 + - pivotalrabbitmq/rabbitmq:main-otp27 name: Test against ${{ matrix.rabbitmq-image }} steps: - uses: actions/checkout@v4 From c907de3bfe212c92badf4671f831c4c350ffbf66 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Mar 2025 01:26:46 +0000 Subject: [PATCH 2078/2114] Bump org.mockito:mockito-core from 5.16.0 to 5.16.1 Bumps [org.mockito:mockito-core](https://github.com/mockito/mockito) from 5.16.0 to 5.16.1. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.16.0...v5.16.1) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5cabc4539d..6f5a81bfea 100644 --- a/pom.xml +++ b/pom.xml @@ -62,7 +62,7 @@ 2.18.3 1.2.13 5.12.0 - 5.16.0 + 5.16.1 3.27.3 1.4.4 1.0.4 From 83e839b392c92c2e4371659cf7e0d56c23f7a012 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Mar 2025 03:22:27 +0000 Subject: [PATCH 2079/2114] Bump org.junit:junit-bom from 5.12.0 to 5.12.1 Bumps [org.junit:junit-bom](https://github.com/junit-team/junit5) from 5.12.0 to 5.12.1. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.12.0...r5.12.1) --- updated-dependencies: - dependency-name: org.junit:junit-bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6f5a81bfea..056188bde2 100644 --- a/pom.xml +++ b/pom.xml @@ -61,7 +61,7 @@ 1.48.0 2.18.3 1.2.13 - 5.12.0 + 5.12.1 5.16.1 3.27.3 1.4.4 From 7f105b24f7af6d22a851f320c408c9172bb39f9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= <514737+acogoluegnes@users.noreply.github.com> Date: Mon, 17 Mar 2025 10:33:30 +0100 Subject: [PATCH 2080/2114] Use -R flag in cp command Compatible MacOS/Linux. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index d9041b2657..f320fd349f 100644 --- a/Makefile +++ b/Makefile @@ -26,7 +26,7 @@ $(DEPS_DIR)/rabbitmq_codegen: git clone -n --depth=1 --filter=tree:0 https://github.com/rabbitmq/rabbitmq-server.git $(DEPS_DIR)/rabbitmq-server git -C $(DEPS_DIR)/rabbitmq-server sparse-checkout set --no-cone deps/rabbitmq_codegen git -C $(DEPS_DIR)/rabbitmq-server checkout - cp -r $(DEPS_DIR)/rabbitmq-server/deps/rabbitmq_codegen "$@" + cp -R $(DEPS_DIR)/rabbitmq-server/deps/rabbitmq_codegen "$@" rm -rf $(DEPS_DIR)/rabbitmq-server tests: deps From ff05690847c9dff78ca24faf3c8be369d4e286ff Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 26 Mar 2025 01:21:15 +0000 Subject: [PATCH 2081/2114] Bump org.sonarsource.scanner.maven:sonar-maven-plugin Bumps [org.sonarsource.scanner.maven:sonar-maven-plugin](https://github.com/SonarSource/sonar-scanner-maven) from 5.0.0.4389 to 5.1.0.4751. - [Release notes](https://github.com/SonarSource/sonar-scanner-maven/releases) - [Commits](https://github.com/SonarSource/sonar-scanner-maven/compare/5.0.0.4389...5.1.0.4751) --- updated-dependencies: - dependency-name: org.sonarsource.scanner.maven:sonar-maven-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 056188bde2..51ce7d051d 100644 --- a/pom.xml +++ b/pom.xml @@ -639,7 +639,7 @@ org.sonarsource.scanner.maven sonar-maven-plugin - 5.0.0.4389 + 5.1.0.4751 From 663f32c1131e3350234460bca484eb6a976b302f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 31 Mar 2025 01:33:48 +0000 Subject: [PATCH 2082/2114] Bump org.apache.maven.plugins:maven-surefire-plugin from 3.5.2 to 3.5.3 Bumps [org.apache.maven.plugins:maven-surefire-plugin](https://github.com/apache/maven-surefire) from 3.5.2 to 3.5.3. - [Release notes](https://github.com/apache/maven-surefire/releases) - [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.5.2...surefire-3.5.3) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-surefire-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 51ce7d051d..dd63c80393 100644 --- a/pom.xml +++ b/pom.xml @@ -80,7 +80,7 @@ 2.4.21 3.6.0 3.14.0 - 3.5.2 + 3.5.3 3.8.1 3.5.2 3.2.7 From fdaec55803074f215906c5079fcc101e5e88aeea Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 31 Mar 2025 01:34:04 +0000 Subject: [PATCH 2083/2114] Bump org.apache.maven.plugins:maven-failsafe-plugin from 3.5.2 to 3.5.3 Bumps [org.apache.maven.plugins:maven-failsafe-plugin](https://github.com/apache/maven-surefire) from 3.5.2 to 3.5.3. - [Release notes](https://github.com/apache/maven-surefire/releases) - [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.5.2...surefire-3.5.3) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-failsafe-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 51ce7d051d..7b6e789923 100644 --- a/pom.xml +++ b/pom.xml @@ -82,7 +82,7 @@ 3.14.0 3.5.2 3.8.1 - 3.5.2 + 3.5.3 3.2.7 3.4.2 5.1.9 From 7b7a49a8afce8ff5048b0b0a286d0e935ce74359 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Apr 2025 00:56:57 +0000 Subject: [PATCH 2084/2114] Bump opentelemetry.version from 1.48.0 to 1.49.0 Bumps `opentelemetry.version` from 1.48.0 to 1.49.0. Updates `io.opentelemetry:opentelemetry-api` from 1.48.0 to 1.49.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-java/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-java/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-java/compare/v1.48.0...v1.49.0) Updates `io.opentelemetry:opentelemetry-sdk-testing` from 1.48.0 to 1.49.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-java/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-java/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-java/compare/v1.48.0...v1.49.0) --- updated-dependencies: - dependency-name: io.opentelemetry:opentelemetry-api dependency-version: 1.49.0 dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: io.opentelemetry:opentelemetry-sdk-testing dependency-version: 1.49.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9c9c4153b1..9780142b4c 100644 --- a/pom.xml +++ b/pom.xml @@ -58,7 +58,7 @@ 1.7.36 4.2.30 1.14.5 - 1.48.0 + 1.49.0 2.18.3 1.2.13 5.12.1 From aaab158484537e2daefb6e4b28a86921e0c8c934 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Apr 2025 00:57:07 +0000 Subject: [PATCH 2085/2114] Bump org.mockito:mockito-core from 5.16.1 to 5.17.0 Bumps [org.mockito:mockito-core](https://github.com/mockito/mockito) from 5.16.1 to 5.17.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.16.1...v5.17.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-version: 5.17.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9c9c4153b1..daa4ad3460 100644 --- a/pom.xml +++ b/pom.xml @@ -62,7 +62,7 @@ 2.18.3 1.2.13 5.12.1 - 5.16.1 + 5.17.0 3.27.3 1.4.4 1.0.4 From a23b8bab402d2f1c40c48bc83b2ab5dc70468f7a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Apr 2025 01:31:53 +0000 Subject: [PATCH 2086/2114] Bump com.diffplug.spotless:spotless-maven-plugin from 2.44.3 to 2.44.4 Bumps [com.diffplug.spotless:spotless-maven-plugin](https://github.com/diffplug/spotless) from 2.44.3 to 2.44.4. - [Release notes](https://github.com/diffplug/spotless/releases) - [Changelog](https://github.com/diffplug/spotless/blob/main/CHANGES.md) - [Commits](https://github.com/diffplug/spotless/compare/maven/2.44.3...maven/2.44.4) --- updated-dependencies: - dependency-name: com.diffplug.spotless:spotless-maven-plugin dependency-version: 2.44.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5c1174aaaa..68ee6446d8 100644 --- a/pom.xml +++ b/pom.xml @@ -90,7 +90,7 @@ 1.7.0 1.11 1.4 - 2.44.3 + 2.44.4 1.19.2

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%0DqAtT!)~2dBRQhhg76`Yq|l1<&R8{HX2_xH0;s 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 E8u7Mg~V5ani|mRYWih6ds=n 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 +p0tP^SH7!Vlp0*+ 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